Compare commits

...

262 Commits

Author SHA1 Message Date
Carlos Garnacho 3c53063e2f viewport: set GDK_SMOOTH_SCROLL_MASK
This is so smooth scroll events are send/handled by the
parent GtkScrolledWindow if any.
2012-02-18 18:07:45 +01:00
Carlos Garnacho 7e08f94c9a treeview: set GDK_SMOOTH_SCROLL_MASK
This is so smooth scroll events are send/handled by the
parent GtkScrolledWindow if any.
2012-02-18 18:07:45 +01:00
Carlos Garnacho f549b02a09 textview: set GDK_SMOOTH_SCROLL_MASK
This is so smooth scroll events are send/handled by the
parent GtkScrolledWindow if any.
2012-02-18 18:07:44 +01:00
Carlos Garnacho 08111aea4c layout: set GDK_SMOOTH_SCROLL_MASK
This is so smooth scroll events are send/handled by the
parent GtkScrolledWindow if any.
2012-02-18 18:07:44 +01:00
Carlos Garnacho 975a3424e7 iconview: set GDK_SMOOTH_SCROLL_MASK
This is so smooth scroll events are send/handled by the
parent GtkScrolledWindow if any.
2012-02-18 18:07:44 +01:00
Michael Natterer 00eab88efc gtk: Implement smooth scrolling in scrolledwindow/range
If delta_x/y information is provided in scroll events, use it
to modify the underlying adjustment in steps proportional to
the deltas provided.

If the child widget of a scrolledwindow doesn't set
GDK_SMOOTH_SCROLL_MASK, regular scroll events will be dispatched,
and still handled by these 2 widgets.
2012-02-18 18:07:44 +01:00
Carlos Garnacho dd498d825f devicemanager,xi2: Implement smooth scrolling
XInput >= 2.1 allows for implementing smooth scrolling,
reporting the different scrolling axes as valuators.
Any change in those will be reported as GdkEventScroll
events with delta_x/y information.

the older kind of scroll events is still handled, and
emulated in devices able to provide smooth scrolling,
setting _gdk_event_set_pointer_emulated() in that case.
2012-02-18 18:07:44 +01:00
Carlos Garnacho 88a1d2584a devicemanager,x11: Initialize event->scroll.delta_x/y to 0 on core events 2012-02-18 18:07:44 +01:00
Michael Natterer acad37d372 quartz: Implement smooth scrolling
nsevent scrollingDeltaX/Y (available on OSX >= Lion) is used to
provide the smooth scrolling values. In any case, old fashioned
events are still sent, setting _gdk_event_set_pointer_emulated()
if the event contains both smooth and non-smooth values.
2012-02-18 18:07:44 +01:00
Carlos Garnacho c5ae193124 gdk: update csw event mask filter to handle smooth scroll
Events of type GDK_SCROLL will be received if the client side window
event mask has either GDK_SCROLL_MASK or GDK_SMOOTH_SCROLL_MASK.

GDK_BUTTON_PRESS_MASK has been removed from type_masks[GDK_SCROLL]
as that bit is often set for other-than-scrolling purposes, and
yet have the window receive scroll events. In GTK+, this forces
non-smooth events bubbling, even if the widgets above want smooth
events, and legitimately set GDK_[SMOOTH_]SCROLL_MASK.
2012-02-18 18:07:44 +01:00
Carlos Garnacho 535e6c5c6e gdk: Filter out either smooth or non-smooth event depending on the evmask
If a device provides both smooth and non-smooth events, the latter will be
flagged with _gdk_event_set_pointer_emulated() so the client side window
receives one or the other. If a device is only able to deliver non-smooth
events, those will be sent, so both direction/deltas may need to be handled.
2012-02-18 18:07:44 +01:00
Carlos Garnacho 251f318ff8 gdk: Add GDK_SMOOTH_SCROLL_MASK
By setting this event, a GdkWindow will receive scroll events
that provide delta values.
2012-02-18 18:07:44 +01:00
Michael Natterer 811019f261 gdk: transfer event->scroll.delta_x/y through csw 2012-02-18 18:07:44 +01:00
Carlos Garnacho aeaa762b7e gdk: deal with GDK_SMOOTH_SCROLL events as not having a direction
gdk_event_get_scroll_direction() will return FALSE on these, so
gdk_event_get_scroll_deltas() has to be used to retrieve dx/dy
2012-02-18 18:07:44 +01:00
Michael Natterer 992cfb285c gdk: Add delta_x/y to scroll events
gdk_event_get_scroll_deltas() can be used to retrieve those
values on smooth scroll events.
2012-02-18 18:07:44 +01:00
Carlos Garnacho c7327d2bc5 gdk: Add GDK_SCROLL_SMOOTH to GdkScrollDirection
This value will be used for smooth scroll events, as they'll
express the scrolling direction in terms of dx/dy.
2012-02-18 18:07:44 +01:00
Matthias Clasen 5b2be2f6f1 GdkTouchCluster Clarify doc language
'Transient' is what was meant here, not 'transitive'.
2012-02-18 18:05:00 +01:00
Matthias Clasen b51662cafa GdkCrossingMode: Remove duplicated doc entry 2012-02-18 18:05:00 +01:00
Carlos Garnacho a328313885 gtk: Release captured events down the hierarchy
Instead of releasing directly onto the target widget,
release down the hierarchy as if uncaptured.
2012-02-18 18:05:00 +01:00
Carlos Garnacho 8528385c80 touchcluster: use an array to store touch IDs
A GList doesn't make much sense for storing guints, so
now a GArray is used internally.

gdk_touch_cluster_get_touches() has changed to return an
allocated guint*, and gdk_touch_cluster_get_n_touches()
has been added too.
2012-02-18 18:05:00 +01:00
Carlos Garnacho c7eba11400 scrolledwindow: store whether the last button press was valid independently
Use a separate boolean instead of coding it up in the last button press
coordinates. This incidentally fixes 0-threshold on kinetic scrolling,
allowing the child widget to get button releases before it prematurely
gets ::grab-broken.
2012-02-18 17:48:54 +01:00
Carlos Garnacho 2cb50c9af2 scrolledwindow: Do not handle dnd-threshold=0
There's no need for it as the GtkSettings property has a lower
limit of 1.
2012-02-18 17:48:54 +01:00
Carlos Garnacho bc5e401de4 docs: Add section about multitouch and other interaction patterns
This is a ripoff of http://live.gnome.org/GTK%2B/DeviceInteractionPatterns,
with better phrasing in general, some more factual points, and multitouch
explained.
2012-02-18 17:48:54 +01:00
Carlos Garnacho fb99b5eeb4 improve docs for multitouch features 2012-02-18 17:48:53 +01:00
Carlos Garnacho d6e23b0924 gtk,gestures: Only match 0-length strokes with homologous stock ones
Avoids spurious stroke matching with fleeting touches.
2012-02-18 17:48:53 +01:00
Carlos Garnacho 42c0d95791 gtk,gestures: Handle multitouch gestures
Gestures are only compared with stock gestures with the same number
of strokes. If a gesture consists of several strokes, the first stroke
is compared (and any possible angle skew is gotten from it), and then
the other strokes are correlated and also compared.

If there's no feasible correlation of strokes, or the gestures yield
an accumulated confidence that's below the threshold, the gesture is
not considered to match.

testgestures has been also added a simple 2-finger gesture for testing.
2012-02-18 17:48:53 +01:00
Carlos Garnacho 6d7ac9e87e textview: Set background on the widget's window
The widget window is usually covered by the bin_window,
this is just necessary so the parent scrolled window
picks the right color for drawing the overshoot area.
2012-02-18 17:48:53 +01:00
Carlos Garnacho 607a1e8fc5 iconview: Set background on the widget's window
The widget window is usually covered by the bin_window,
this is just necessary so the parent scrolled window
picks the right color for drawing the overshoot area.
2012-02-18 17:48:53 +01:00
Carlos Garnacho 02eeed70bd treeview: Set background on the widget's window
The widget window is usually covered by the bin_window,
this is just necessary so the parent scrolled window
picks the right color for drawing the overshoot area.
2012-02-18 17:48:53 +01:00
Carlos Garnacho 849661a573 scrolledwindow: Use the child widget's window bg color for the overshoot area
This makes the overshoot area seamless, if the child plays along.
2012-02-18 17:48:53 +01:00
Carlos Garnacho ca84ac7a6a tests: only handle gestures on testgestures after the last stroke is lifted 2012-02-18 17:48:53 +01:00
Carlos Garnacho 8d421b2af2 gtkwidget: only emit ::gesture when the last stroke is lifted 2012-02-18 17:48:53 +01:00
Carlos Garnacho b2776581da gtk,gestures: Add gtk_gestures_interpreter_get_n_active_strokes
This call gets the number of currently active strokes, finished
strokes (i.e. those that already had a GDK_BUTTON/TOUCH_RELEASE
processed) don't count.
2012-02-18 17:48:53 +01:00
Carlos Garnacho f7eb9edb9b entry: Only allow press-and-hold on the text_area window
This avoids oddities in spinbuttons, press-and-hold shouldn't
be triggered on the buttons.
2012-02-18 17:48:53 +01:00
Carlos Garnacho fe87311f51 gtk,pah: Don't cancel a ::press-and-hold that's scheduled to be activated
There was a slight window where the operation could be cancelled, causing
an assert as the p-a-h data is NULL.
2012-02-18 17:48:52 +01:00
Carlos Garnacho c38159d4d7 gdkwindow: Add device parameter to gdk_window_create_touch_cluster()
gdk_touch_cluster_set_device() had to be called right after anyway,
so set the device directly within this call, and favor the most common
scenario where there's just 1 single multitouch device behind 1 master
device.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 075911ccfd demos: Demonstrate further features in the multitouch demo
Now that GtkButton and GtkScale are multitouch approved, it's
sufficient to enable GDK_TOUCH_MASK on them to have them deal
with multitouch devices.

The scales set rgba of the currently selected rectangle, and
the button adds more rectangles, those can be manipulated
simultaneously together with the rectangles, the only limit
is the number of touches the touchscreen hw is able to detect.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 20a5364a5f gdk: Listen to touch events by default on the native window
GDK will only receive touch events when dealing with a multitouch
device, so these must be transformed to pointer events if the
client-side window receiving the event doesn't listen to touch
events, and the touch sequence the event is from does emulate
the pointer.

If a sequence emulates pointer events, it will result in a
button-press, N motions with GDK_BUTTON1_MASK set and a
button-release event, and it will deliver crossing events
as specified by the current device grab.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 4a3037574d gdk,devicemanager: Mark touch events emulating the pointer as such 2012-02-18 17:48:52 +01:00
Carlos Garnacho fee9840d52 gdk: Only trigger motion hints machinery on motion events
Touch events have no need for it, plus the concept behind
gdk_event_request_motions() doesn't wrap around multiple
touches within a device.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 10bd4f8a72 gdk: Have touch grabs behave like the implicit grab wrt crossing events
These are equivalent to an implicit grab (with !owner_events), so
if the touch leaves or enters the grab window, the other window
won't receive the corresponding counter-event.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 1d986aa8a4 gtk,button: Handle touch events
Touch events don't generate crossing events themselves, so
do not rely on these to determine whether the button release
happened within the event window.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 33790437ce gtk,range: Don't perform a GTK+ grab
The implicit grab on priv->event_window already warrants that this
widget is the only one getting events while the button is pressed,
so don't spare the GTK+ grab here.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 239f52d543 gtk: rewrite touch events wrt the window group too
Likewise to pointer events, have touch events during a device
grab with owner_events=TRUE be delivered normally as long as
the widget pertains to the same window group.
2012-02-18 17:48:52 +01:00
Carlos Garnacho f2d71d3da5 gdk,csw: handle implicit touch grabs
If the touch sequence happens on a window with GDK_TOUCH_MASK set,
a GdkTouchGrabInfo is created to back it up. Else a device grab is
only created if the sequence emulates the pointer.

If both a device and a touch grab are present on a window, the later
of them both is obeyed, Any grab on the device happening after a
touch grab generates grab broken on all the windows an implicit
touch grab was going on, and all touches would be automatically
removed from every touch cluster.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 61e625d9a6 gdk,display: Add internal API to deal with touch implicit grabs
The necessary information about a touch implicit grab is stored in
GdkTouchGrabInfo structs, these are meant to be transient to the
touch sequence
2012-02-18 17:48:52 +01:00
Carlos Garnacho 9e3330c90b gdk,csw: Don't change window_under_pointer for pure touch events
Only touch events that emulate the pointer do change it.
2012-02-18 17:48:52 +01:00
Carlos Garnacho 108c831e23 gdk,xi2: set pointer emulated flags on events with XIPointerEmulated 2012-02-18 17:48:51 +01:00
Carlos Garnacho 77f071b5ff gdk: Add internal API to set "pointer emulated" flag on events
This flag will be used for non-pointer events that are emulated
from eg. touch events, or pointer events being emulated.
2012-02-18 17:48:51 +01:00
Carlos Garnacho fb35e29a19 gdk,xi2: Set GDK_BUTTON1_MASK on touch events
GTK+ handles both touch and pointer events through the same
event handlers, so enable this modifier on touch events to
avoid much special casing.
2012-02-18 17:48:51 +01:00
Carlos Garnacho b1f4497697 gdk,xi2: Only enable multitouch if the server reports XI2.2
This enables multitouch-enabled GTK+ to run on older X servers.
2012-02-18 17:48:51 +01:00
Carlos Garnacho 29569e6049 gdk,xi2: Update to latest XInput2.2 spec 2012-02-18 17:48:51 +01:00
Carlos Garnacho c201145d02 gtk,pah: Handle press-and-hold on touch devices 2012-02-18 17:48:51 +01:00
Carlos Garnacho eb214aae74 gdk: Add gdk_event_get_touch_area()
If given an event coming from a touch devices,
this functions will read the MT major/minor/orientation
axes and return a cairo_region_t with the touch shape.
2012-02-18 17:48:51 +01:00
Carlos Garnacho fbef4384aa gestures: Add some unit tests 2012-02-18 17:48:51 +01:00
Carlos Garnacho 88909ac9b2 gtk: Document helper GtkWidget gestures API 2012-02-18 17:48:51 +01:00
Carlos Garnacho 84d9872a26 gestures: Add API documentation 2012-02-18 17:48:51 +01:00
Carlos Garnacho 576ba1a03d gtk: Add helper API to handle gestures
Although GtkGesturesInterpreter can be used standalone, GtkWidget
deserves helper API to enable support for gestures. gestures can
be enabled/disabled, and the ::gesture signal can be used to get
the gesture ID.

The internal GtkWidget gestures interpreter is only handled by
touch events, if gestures are needed for other devices, a
standalone gestures interpreter must be used.
2012-02-18 17:48:51 +01:00
Carlos Garnacho bb448f619c tests: Add testgestures
This testcase handles all gestures offered by GtkGestureType,
and also creates and registers a custom M-shaped GtkGesture.
2012-02-18 17:48:51 +01:00
Carlos Garnacho 9827003e06 gestures: Implement gestures interpretation
The algorithm works on 2 GtkGestures, it finds out the similarity
of these by bending the user provided gesture so it equals a stock
one, the differences in areas are used to determine the level of
confidence on both gestures being similar.
2012-02-18 17:48:51 +01:00
Carlos Garnacho 14100b867c Add a gestures interpreter base implementation
This object is currently shallow, the API is defined but no gesture
interpretation is performed. Additional API is declared to create
and define gestures, which may consist of several strokes with an
offset.
2012-02-18 17:48:51 +01:00
Carlos Garnacho 5926e3cfec xi2: Use GDK_SOURCE_TOUCH for multitouch devices
Any device with XITouchValuatorClassInfo classes qualify as
multitouch now.
2012-02-18 17:48:50 +01:00
Carlos Garnacho e09d7b5456 gdk: Update touch events to latest spec 2012-02-18 17:48:50 +01:00
Carlos Garnacho c9b8f866df gtk-demo: Add multitouch demo
Pretty much ignores pointer events currently, so you're out
of luck to see anything happening at all if you don't have
a multitouch device...
2012-02-18 17:48:50 +01:00
Carlos Garnacho eea525ac89 Add multitouch-event signal and vfunc to GtkWidget 2012-02-18 17:48:50 +01:00
Carlos Garnacho 76e7a9e5b7 Add machinery to emit GdkEventMultiTouch events
These events are created from GDK_TOUCH_MOTION/PRESS/RELEASE
events, if the touch ID generating the event is within a
touch cluster, that event is stored and not pushed to the queue,
so a touch ID can only emit GDK_TOUCH_* or GDK_MULTITOUCH_* events
at the same time.
2012-02-18 17:48:50 +01:00
Carlos Garnacho 5a523e500b Define GdkEventMultiTouch and its related event types.
This event will gather all touches within a GdkTouchCluster,
including an array of the latest GDK_TOUCH_MOTION events for
the touch IDs contained in there.
2012-02-18 17:48:50 +01:00
Carlos Garnacho 33ea7850c9 Add gdk_window_[create|remove]_touch_cluster()
These are the functions to create/destroy a GdkTouchCluster,
as they are associated to GdkWindows.
2012-02-18 17:48:50 +01:00
Carlos Garnacho 9856a2faeb Introduce GdkTouchCluster
This is a per-window/device object to gather a group of touch IDs
as a single entity.
2012-02-18 17:48:50 +01:00
Carlos Garnacho a19c4b207c Add gdk_event_get_touch_id()
Just a helper function to get the touch ID from touch events, it
returns FALSE in any other case.
2012-02-18 17:48:50 +01:00
Carlos Garnacho 264739e6ad Make touch events go through csw/widget event handling.
In GtkWidget, touch events go through the same handler
than motion events, with the difference that touch_id
will have something meaningful there.

Touch events need to be explicitly selected, so if this
is enabled, the possibility of different motion streams
with different touch IDs must be handled in some way.
2012-02-18 17:48:50 +01:00
Carlos Garnacho 10b4eaa10b Handle TouchBegin/End events
These are translated into GDK_TOUCH_PRESS/RELEASE GdkEvents,
which use the GdkEventButton struct, a touch_id parameter
has been added there to cope with touches.
2012-02-18 17:48:50 +01:00
Carlos Garnacho be21cc53bc Add initial handling of TouchMotion events.
GdkDeviceManagerXI2 now handles TouchMotion and TouchMotionUnowned
events, which are translated to GDK_TOUCH_MOTION events.
2012-02-18 17:48:49 +01:00
Carlos Garnacho cda35f142f Add touch motion event type and mask.
These events' struct is the same than GdkEventMotion, which has been
added a touch_id parameter. The gdk_event_* functions have been modified
to also handle this event type.
2012-02-18 17:48:49 +01:00
Carlos Garnacho 5c98ea081e configure: Detect XInput 2.1 2012-02-18 17:48:49 +01:00
Carlos Garnacho 78866ca13d gdk,xi2: Add major/minor properties to XI2 device manager
This may be used to turn on/off the features that are added to
new XInput2 revisions.
2012-02-18 17:48:49 +01:00
Carlos Garnacho d4382300b4 gtk,range: Have slider jump to the pointer coordinates on touch devices
This widget is too narrow to make touch interaction tricky enough, so
don't add the penalty of having the slider run farther from the touch
coordinates if it happens to miss the slider.
2012-02-18 17:48:49 +01:00
Carlos Garnacho 7ef01e70f7 gtk,scrolledwindow: Ensure the view snaps back when overshooting
Instead of just stopping the acceleration source ID, check whether
it's overshooting, and let it snap back if needed after ::grab-notify
and ::button-release-event
2012-02-18 17:48:49 +01:00
Carlos Garnacho 10316b6ab2 gtk,scrolledwindow: set slower inverse acceleration on the overshoot area
This is so snapping back is more fluid and noticeable.
2012-02-18 17:48:49 +01:00
Carlos Garnacho e11d9904bc gtk,scrolledwindow: Improve initial velocity calculation
Velocity calculation has been refactored out of the captured motion events
handler, and also has more tolerance defore determining that a drag is actually
still.
2012-02-18 17:48:49 +01:00
Carlos Garnacho f1d33f76c7 gtk,menu: Don't popdown submenus on button release for touch devices
This is so submenus stay open as the parent menu item is pressed/released,
as the user would typically lift the finger in order to select a submenu
item.
2012-02-18 17:48:49 +01:00
Carlos Garnacho fe72a8192d gtk,settings: Deprecate gtk-touchscreen-mode
It's not used anywhere in GTK+ anymore.
2012-02-18 17:48:49 +01:00
Carlos Garnacho bf543ac8f4 gtk,range: Remove gtk-touchscreen-mode usage
Emulated crossing events with mode GDK_CROSSING_TOUCH_PRESS/RELEASE
already catter dinamically for the "don't prelight on touch devices"
usecase.
2012-02-18 17:48:49 +01:00
Carlos Garnacho 93f7a97f01 gtk,togglebutton: Remove gtk-touchcreen-mode usage
Emulated crossing events with mode GDK_CROSSING_TOUCH_PRESS/RELEASE
already catter dinamically for the "don't prelight on touch devices"
usecase.
2012-02-18 17:48:49 +01:00
Carlos Garnacho cc188dffa9 gtk,menushell: Remove gtk-touchscreen-mode usage
This usage in a keybinding signal is hardly related to touchscreens,
so just remove it.
2012-02-18 17:48:49 +01:00
Carlos Garnacho 33e3b9ddbb gtk,menu: Remove gtk-touchscreen-mode from scrolling code
scrolling is handled via ::captured-event dynamically, so remove
this now unused code.
2012-02-18 17:48:49 +01:00
Carlos Garnacho 8c4b0b66b8 gtk,menu: Select the first item for touch devices
This was done through gtk-touchscreen-mode, now is handled
dynamically on the current event source device.
2012-02-18 17:48:49 +01:00
Carlos Garnacho 2781c9544b gtk,menu: Implement scrolling through ::captured-event for touch devices
This makes overflown menus scrollable via direct manipulation. Once past
the threshold, the item below the pointer is unselected and scrolling
starts.
2012-02-18 17:48:48 +01:00
Carlos Garnacho 4765dde5cf gtk,menu: handle item selection for touch devices dynamically
Instead of using gtk-touchscreen-mode, the behavior changes depending
on the source device in use.
2012-02-18 17:48:48 +01:00
Carlos Garnacho 658b0e8092 gtk,textview: Pop up context menu on press-and-hold 2012-02-18 17:48:48 +01:00
Carlos Garnacho 0e5d05f8e0 gtk,textview: Also cancel DnD on ::grab-notify
If is about to start when the drag device is grabbed
somewhere else, unset drag start x/y so DnD doesn't
happen anyway.
2012-02-18 17:48:48 +01:00
Carlos Garnacho f1570c5c92 gtk,entry: Pop up menu on press-and-hold 2012-02-18 17:48:48 +01:00
Carlos Garnacho e042c53caa gtk,label: Pop up menu on press-and-hold 2012-02-18 17:48:48 +01:00
Carlos Garnacho a7b6859561 xi2: Get the effective group state by ORing the XIGroupState values 2012-02-18 17:48:48 +01:00
Carlos Garnacho 14235c9c17 gdk: Ensure that GdkPointerWindowInfo is only generated for pointers 2012-02-18 17:48:48 +01:00
Carlos Garnacho 6a6bed8e04 gtk: Only set widget under device on non-virtual crossing events
_gtk_widget_set_device_window() is suppose to make accounting of
the topmost widget under the device at each time, so avoid setting
it on virtual crossing events as the device is already in another
window.
2012-02-18 17:48:48 +01:00
Carlos Garnacho 7a07995944 gtk,scrolledwindow: remove scrollbars auto-hide
This is in a really sorry state, and scrollbars need to be
thought out for the new design anyway.
2012-02-18 17:48:48 +01:00
Carlos Garnacho 62afe5cda6 gtk,scrolledwindow: capture crossing events when dragging
Also, instead of connecting 2 more times to ::captured-event,
have it all go through a single handler.
2012-02-18 17:48:48 +01:00
Carlos Garnacho 95f6b7fa82 gtk,scrolledwindow: Add GtkKineticScrollingFlags
gtk_scrolled_window_set_kinetic_scrolling() now takes a set of flags,
GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS makes the "capture button
press and maybe replay later" vs "let button press go through, but
trust in ::grab-broken to undo things" an opt-in, by default that
flag is set, which is the most conservative approach.
2012-02-18 17:48:48 +01:00
Carlos Garnacho ae2438df90 gtk,scrolledwindow: Grab only after starting drag
This is so the grab doesn't break the implicit grab on the
child widget's window, which avoids that the button press and
release are possibly sent to different windows, and after the
grab was actually broken.
2012-02-18 17:48:47 +01:00
Carlos Garnacho fafb78e38e gdk: Generate crossing events around touch devices' press/release
Anytime a touch device interacts, the crossing events generation
will change to a touch mode where only events with mode
GDK_CROSSING_TOUCH_PRESS/RELEASE are handled, and those are sent
around button press/release. Those are virtual as the master
device may still stay on the window.

Whenever there is a switch of slave device (the user starts
using another non-touch device), a crossing event with mode
GDK_CROSSING_DEVICE_SWITCH may generated if needed, and the normal
crossing event handling is resumed.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 4068758bb8 gdk: Keep track of the last slave device used
This last slave device (stored per master) is used to fill
in the missing slave device in synthesized crossing events
not directly caused by a device event (ie. due to configure
events or grabs)
2012-02-18 17:48:47 +01:00
Carlos Garnacho bb87595220 gtk,tooltips: Use the source device instead of gtk-touchscreen-mode
This makes tooltips behavior dynamic based on the interacting device.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 001a1517da gtk,scrolledwindow: Clamp early overshooting when snapping back
Fixes the situation where overshooting in scrolled windows with a
small viewport could end up overshooting right to the opposite
side, and then back again indefinitely.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 76b285f475 gtk: Handle motion hints for ::captured-event
Request automatically more motion events in behalf of
the original widget if it listens to motion hints. So
the capturing widget doesn't need to handle such
implementation details.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 0b796299c1 gtk,scrolledwindow: capture motions until the kinetic scrolling cancellation
If the widget which events are captured listens to motion hints, there
are situations where neither the scrolled window or the child widget
request more motions.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 5d2af3e13d gtk,pah: Show a bigger press-and-hold indicator on touchscreens
On touch devices it uses a 2.5cm diameter via gdk_screen_get_width_mm()
in the hope that it'll pop out of the finger area.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 15d2f1697d gtk,scrolledwindow: Unset dragging device on ::grab-notify
The child widget may still call gtk_(device_)grab_add, which left
the scrolled window in an inconsistent state.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 460a54ce15 gtk,scrolledwindow: Rework physics behind kinetic scrolling
The maths being used didn't resemble much about velocities or
friction/deceleration, so reimplement it in terms of velocity
vectors and decelerations, measured in pixels/ms^2.

Overshooting is also handled within the deceleration effect,
turning into a constant acceleration vector in the opposite
direction so it returns elastically within the boundaries.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 3ab0ccf643 gtk,scrolledwindow: Implement overshooting
An extra GdkWindow has been added, this window is the parent
of the child widget, and is the one getting resized/moved when
overshooting.

The unclamped adjustments' values are also stored in
GtkScrolledWindowPrivate as a separate value, overshooting is
pretty specific to GtkScrolledWindow and it isn't worth to
expose API in GtkAlignment for this single purpose.

This method allows GtkScrollable children to be blissfully
unaware of overshooting, as otherwise they'd have to handle
rather odd adjustment values themselves.
2012-02-18 17:48:47 +01:00
Carlos Garnacho cebd79e7eb gtk,scrolledwindow: Add window for overshooting
This window is the child widget's parent window, and will
be the one that's moved when overshooting.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 4e321365cf scrolledwindow: Handle nested scrolled windows in kinetic scrolling
The innermost scrolled window always gets to capture the events, all
scrolled windows above it just let the event go through. Ideally
reaching a limit on the innermost scrolled window would propagate
the dragging up the hierarchy in order to keep following the touch
coords, although that'd involve rather evil hacks just to cater
for broken UIs.
2012-02-18 17:48:47 +01:00
Carlos Garnacho 1b088606f7 gtk: Add event storing/replaying to GtkWidget::captured-event
It now returns a GtkCapturedEventFlags which tells whether the
widget captured the event, and additionally whether the event
should be stored for later replay.

gtk_widget_release_captured_events() has been added too so
all stored events are released onto the widget that was initially
to receive the events.
2012-02-18 17:48:46 +01:00
Carlos Garnacho 7bf410f927 scrolledwindow: Use event times when calculating deceleration
Using g_get_current_time() isn't going to be realistic on lagging
events.
2012-02-18 17:48:46 +01:00
Carlos Garnacho 5476f09d35 scrolledwindow: bypass kinetic scrolling if no scrollbars are shown 2012-02-18 17:48:46 +01:00
Carlos Garnacho a49c9a27fb scrolledwindow: Remove priv->event_window
It looks like a leftover from pre-captured-event iterations of
the patch, it is completely unnecessary now.
2012-02-18 17:48:46 +01:00
Carlos Garnacho e5a3cf5a36 scrolledwindow: Don't use p-a-h for the "let event go through" timeout
Just use a timeout there, the press-and-hold feedback is undesirable
here.
2012-02-18 17:48:46 +01:00
Carlos Garnacho 59a0f62079 gtk,pah: Hook directly into gtk_main_do_event()
Press and hold couldn't reasonably work if nested widgets
handle ::captured-event, once the widget inits press-and-hold,
it'd better also handle possible cancellation on motion and
button release, which isn't guaranteed with ::capture-event.

Also, tentatively start press-and-hold by default on the
grab_widget, and before event capturing happens, this avoids
awkward situations like the scrolled window preventing/delaying
press-and-hold to happen on the child textview for example.
2012-02-18 17:48:46 +01:00
Carlos Garnacho fbbd6b2c2e scrolledwindow: Enable kinetic scrolling by default 2012-02-18 17:48:46 +01:00
Carlos Garnacho d77977aa62 scrolledwindow: add another shortcut to bypass event capture
When clicked again close to the previous button press location
(assuming it had ~0 movement), the scrolled window wil allow
the child to handle the events immediately.

This is so the user doesn't have to wait to the p-a-h timeout
in order to operate on the scrolledwindow child.
2012-02-18 17:48:46 +01:00
Carlos Garnacho da35350ee3 scrolledwindow: Only do kinetic scrolling on touch devices
This is sort of meaningless on pointer devices, besides it implies
a different input event handling on child widgets that's unnecessary
there.
2012-02-18 17:48:46 +01:00
Carlos Garnacho 40996af9c1 scrolledwindow: Don't crash on 0-sized motion buffer 2012-02-18 17:48:46 +01:00
Carlos Garnacho 7e29b38bd4 scrolledwindow: Set also a GTK+ grab on p-a-h scrolling
This is so the widget is ensured to receive the events
regardless of the pointer position.
2012-02-18 17:48:46 +01:00
Carlos Garnacho c1b86a5eab scrolledwindow: Add GdkDevice parameter to ::press-and-hold handler 2012-02-18 17:48:46 +01:00
Carlos Garnacho 68587c203c gtk: Handle press-and-hold for touch devices
Also, only react to the first button
2012-02-18 17:48:46 +01:00
Carlos Garnacho 80e08d1b1b gtk: Add a GdkDevice parameter to ::press-and-hold
This would be useful when popping up menus, just so we
know what device to trigger it for.
2012-02-18 17:48:46 +01:00
Carlos Garnacho 0a05318277 gtk: Clean up press-and-hold code
The press and hold animation now fully relies on style context
transitions, finishing the p-a-h operation right after it
finishes. There's also no need to connect to ::drag-begin as
::grab-notify will also tell when a grab begins.
2012-02-18 17:48:45 +01:00
Carlos Garnacho 5c187245a4 tests: Add an entry to testpressandhold
Useful for checking behavior while selecting,
starting drags, subwindows...
2012-02-18 17:48:45 +01:00
Carlos Garnacho 739059cc91 entry: Handle ::grab-notify
Store the device, and unset private fields whenever the device
is shadowed by another GTK+ grab, so popping up menus while
selecting (i.e. press-and-hold) doesn't leave it in a confused
state.
2012-02-18 17:48:45 +01:00
Carlos Garnacho 86e966b944 gtk: Do not use deprecated APIs on press-and-hold 2012-02-18 17:48:45 +01:00
Carlos Garnacho ef08d3975c tests: Update testkineticscrolling to use GtkGrid 2012-02-18 17:48:45 +01:00
Carlos Garnacho c50007b33a gtk: connect to grab-notify for press and hold
This is so press and hold is cancelled if a click actually
causes an inner widget to do a GTK+ grab.
2012-02-18 17:48:45 +01:00
Carlos Garnacho 9f20e16683 gtk: Propagate ::captured-event up the hierarchy for crossing events 2012-02-18 17:48:45 +01:00
Carlos Garnacho 4f2ce2f7b6 gtk: emit ::captured-event starting from the GTK grab widget 2012-02-18 17:48:45 +01:00
Carlos Garcia Campos a404a56254 scrolledwindow: Allow selections and drag-and-drop when kinetic scrolling is enabled
If the scrolling doesn't start after a long press, the scrolling is
cancelled and events are handled by child widget normally.
2012-02-18 17:48:45 +01:00
Carlos Garcia Campos 7a59b443ee Add GtkWidget::press-and-hold signal
Press-and-hold signal is emitted when the mouse button is pressed for a
given amount of time, specified in the new "press-and-hold-timeout"
GtkSetting. It's commonly used in mobile platforms to emulate a right
click to show a context menu. This patch is based on previous patches by
Kristian Rietveld and Danielle Madeley.

https://bugzilla.gnome.org/show_bug.cgi?id=315645
2012-02-18 17:48:45 +01:00
Carlos Garnacho 127bfd71d7 gtksettings: Set animation for press-and-hold through GtkStyleProvider
The "gtk-press-and-hold-timeout" setting has also been added, to control
its duration.
2012-02-18 17:48:45 +01:00
Carlos Garnacho 35341511b9 themingengine: Implement press-and-hold notification renderer
gtk_render_activity() uses it for the GTK_STYLE_CLASS_PRESS_AND_HOLD
style class.
2012-02-18 17:48:45 +01:00
Carlos Garcia Campos 65888ac515 scrolledwindow: Add auto-hide-scrollbars style property
To hide the scrollbars in kinetic mode when not scrolling.
2012-02-18 17:48:45 +01:00
Carlos Garcia Campos 313f51d1f8 tests: Add new test for kinetic scrolling 2012-02-18 17:48:44 +01:00
Carlos Garcia Campos 5ddf0f4e5f test: Add checkbox to enable/disable kinetic scrolling in scrolled window test 2012-02-18 17:48:44 +01:00
Carlos Garcia Campos 5e726db14e scrolledwindow: Initial kinetic scrolling support 2012-02-18 17:48:44 +01:00
Carlos Garcia Campos 705dde471f timeline: Add _gtk_timeline_get_elapsed_time()
To get the time in milliseconds since the last frame
2012-02-18 17:48:44 +01:00
Carlos Garcia Campos d83640dc34 Add GtkWidget::captured-event signal
https://bugzilla.gnome.org/show_bug.cgi?id=641836
2012-02-18 17:48:44 +01:00
Carlos Garnacho ed20c3255b gdk: Add GDK_SOURCE_TOUCH
This device source applies to touch capable devices, most
notably touchscreens.
2012-02-18 17:48:44 +01:00
Yaron Shahrabani 0a189935ad Updated Hebrew translation 2012-02-18 14:59:12 +02:00
Yaron Shahrabani 1f5681e419 Updated Hebrew translation. 2012-02-18 14:42:42 +02:00
Cosimo Cecchi 8dd4a0adf1 color-swatch: don't render our active badge if background-image is set
If the color active swatch has been set a background image from the
theme, use it as an asset, and do not draw our custom thing.
2012-02-18 09:55:45 +01:00
Cosimo Cecchi dcec8dfdde color-swatch: render a background if the swatch doesn't have a color
We still want to call into the background rendering code, to draw the
default background.
2012-02-18 09:55:45 +01:00
Cosimo Cecchi 8e85702dca color-swatch: derive directly from GtkWidget
Instead of GtkDrawingArea, since that calls in realize
gtk_style_context_set_background(). We don't want that to happen, given
that we do all the painting ourselves in _draw().
2012-02-18 09:55:45 +01:00
Chao-Hsiung Liao b58d50a0da Updated Traditional Chinese translation(Hong Kong and Taiwan) 2012-02-18 08:49:57 +08:00
Daniel Mustieles 1578585c08 Updated Spanish translation 2012-02-17 18:02:22 +01:00
Daniel Mustieles a18b3f2ed4 Updated Spanish translation 2012-02-17 17:50:13 +01:00
Cosimo Cecchi 039eb8dc04 color-editor: mark the GtkColorSwatch as not selectable 2012-02-17 17:03:15 +01:00
Cosimo Cecchi 5f0c4fc20f color-swatch: add a "selectable" property to GtkColorSwatch
We don't want e.g. the swatch in GtkColorEditor to get the select badge
when it's clicked, so make this a property (on by default).
2012-02-17 17:03:15 +01:00
Fran Diéguez 04b36dabd0 Updated Galician translations 2012-02-16 15:00:06 +01:00
Claudio Saavedra cfe65a0d6c GtkNotebook: and another fix
https://bugzilla.gnome.org/show_bug.cgi?id=669116
2012-02-16 12:33:26 +02:00
Claudio Saavedra ccf7867c35 GtkNotebook: fix one child-notify emission
Forgot to increase the counter in the for loop, doing it now.

https://bugzilla.gnome.org/show_bug.cgi?id=669116
2012-02-16 12:28:46 +02:00
Benjamin Otte bf89bc624b widget-factory: Don't crash when showing about dialog 2012-02-15 15:14:31 +01:00
Javier Jardón 392fdff8e5 docs: GtkWidget's "state-flags-changed" is a signal not a property 2012-02-15 13:43:58 +00:00
Daniel Mustieles 444f562955 Updated Spanish translation 2012-02-15 13:11:35 +01:00
Daniel Mustieles db8555ed31 Updated Spanish translation 2012-02-15 13:05:43 +01:00
Daniel Mustieles cc1b29cd67 Updated Spanish translation 2012-02-15 13:01:13 +01:00
Murray Cumming a0b4ab109d Documentation: Correct references to properties.
These should use :, not ::, though signals would use ::.
See
http://developer.gnome.org/gtk-doc-manual/unstable/documenting_syntax.html.en
and
http://developer.gnome.org/gtk-doc-manual/unstable/documenting_symbols.html.en
2012-02-15 11:43:33 +01:00
Rico Tzschichholz 87d979f498 Remove obsolete reference to gtk.css.raleigh 2012-02-15 08:03:05 +01:00
Matthias Clasen f9be52cb2f Add color and font chooser to the widget gallery 2012-02-14 23:48:36 -05:00
Matthias Clasen fae1be06cd Docs: Reorder a sections 2012-02-14 23:36:02 -05:00
Matthias Clasen e1a625aa78 GtkColorSwatch: Add accessible actions 2012-02-14 21:16:52 -05:00
Claudio Saavedra 347328adb0 GtkNotebook: emit child-notify::position on drag 'n drop reorder
https://bugzilla.gnome.org/show_bug.cgi?id=669116
2012-02-15 01:05:12 +02:00
Claudio Saavedra cb775a6a6d GtkNotebook: emit child-notify::position on page add/removal
For each page added/removed, notify all the other children changing
position.

https://bugzilla.gnome.org/show_bug.cgi?id=669116
2012-02-15 01:05:12 +02:00
Matthias Clasen 6c2b7a9441 Revert "Add a button to back to the palette"
This reverts commit 32f1a5ad83.
2012-02-14 16:39:05 -05:00
Cosimo Cecchi bef12c003c color-scale: remove Adwaita GtkColorScale trough hack
Instead of special-casing Adwaita, apply the half-width logic for themes
that have a scale slider with vertical proportions.
Also, simplify the rendering code a bit by factoring out the trough
sizing logic.
2012-02-14 16:37:05 -05:00
Cosimo Cecchi 19da38b811 colorchooser: factor out a private method to get the checkboard pattern
And use it in the color widgets.
2012-02-14 16:37:04 -05:00
Matthias Clasen 453aecd346 Improve a11y names for colors
Only read alpha if it is != 1, and read percentages also for
'unnamed' palette colors.
2012-02-14 16:37:04 -05:00
Matthias Clasen 2d57c5c374 Update TODO 2012-02-14 16:37:04 -05:00
Matthias Clasen c2426516c4 Update POTFILES 2012-02-14 16:37:04 -05:00
Matthias Clasen 18ea4825cf Mark color names as translatable 2012-02-14 16:37:04 -05:00
Matthias Clasen 1f698e4f62 GtkColorScale: fix an RTL issue
When using a horizontal scale in RTL, we need to flip the
background image to go along with the flipped scale.
2012-02-14 16:37:04 -05:00
Cosimo Cecchi 49a23acd89 test-toplevelembed: use new GtkColorChooserDialog 2012-02-14 16:37:03 -05:00
Cosimo Cecchi 80f0feda98 testgtk: use GtkColorChooserDialog instead of GtkColorSelectionDialog 2012-02-14 16:37:03 -05:00
Cosimo Cecchi 06b34b3fc1 prop-editor: don't use GtkColorButton deprecated API 2012-02-14 16:37:02 -05:00
Cosimo Cecchi 92322a63f5 gtk-demo: use the new GtkColorChooserDialog in the color demo 2012-02-14 16:37:02 -05:00
Cosimo Cecchi 5e77e1c117 colorsel: include gtkcolorutils.h
Fix the build
2012-02-14 16:37:02 -05:00
Cosimo Cecchi 6dbb4d6384 color-widget: don't use a GtkAlignment to center the color editor
We can just use a GtkBox, and set hexpand=TRUE/halign=CENTER to allocate
the editor in the middle of the box.
2012-02-14 16:37:01 -05:00
Cosimo Cecchi 988cbb6300 color-editor: don't use a GtkAlignment to layout popups
Set a margin on the contents and use a box instead.
2012-02-14 16:37:01 -05:00
Cosimo Cecchi 1cbaca6c60 color-editor: don't use an alignment to give the popup extra space 2012-02-14 16:37:01 -05:00
Cosimo Cecchi 2abe72283e color-editor: also set a row spacing in the popup tooltip 2012-02-14 16:37:01 -05:00
Cosimo Cecchi 126e941466 color-button: simplify internal children
Instead of going GtkAlignment->GtkFrame->GtkAlignment, just pack a
GtkDrawingArea inside the button, and use halign/margin properties to
get the desired layout.
2012-02-14 16:37:01 -05:00
Cosimo Cecchi 51c6e8329d color-swatch: cleanup unused property enum value 2012-02-14 16:37:01 -05:00
Matthias Clasen 91b4781ae9 Revert an accidental commit 2012-02-14 16:37:00 -05:00
Matthias Clasen 92618eb8e2 GtkColorSwatch: Use widget state instead of a custom 'selected' 2012-02-14 16:37:00 -05:00
Matthias Clasen 9cc827fcd1 A11y improvements 2012-02-14 16:37:00 -05:00
Matthias Clasen 40974b1463 GtkColorSwatch: Drop an unnecessary field 2012-02-14 16:37:00 -05:00
Matthias Clasen dc1929a9de Avoid a 10th custom color 2012-02-14 16:37:00 -05:00
Matthias Clasen 57e057df60 Fill the custom palette up some more 2012-02-14 16:37:00 -05:00
Matthias Clasen 32f1a5ad83 Add a button to back to the palette
This is just for trying this out; if it is considered good,
it will be moved into GtkColorChooserDialog
2012-02-14 16:36:59 -05:00
Matthias Clasen 1f05f94885 GtkColorChooserDialog: propagate notification for ::show-editor 2012-02-14 16:36:59 -05:00
Matthias Clasen 05e2124f24 GtkColorChooserWidget: emit notification for ::show-editor 2012-02-14 16:36:59 -05:00
Matthias Clasen 1fd311803a Document gtk_color_chooser_add_palette 2012-02-14 16:36:59 -05:00
Matthias Clasen 7f44feab19 Fix use_alpha initialization and propagation
We must set use_alpha to TRUE initially, and when passing it
down to the swatches, we must iterate over the custom box, too.
2012-02-14 16:36:59 -05:00
Matthias Clasen 3a7ed2e7bd Remove unused variables 2012-02-14 16:36:59 -05:00
Matthias Clasen bad24bc119 Consistently private headers
Add a 'private' suffix to all newly introduced private
headers.
2012-02-14 16:36:58 -05:00
Matthias Clasen 5aaeaa7b81 Fix the build
A G_BEGIN_DECLS went missing here.
2012-02-14 16:36:58 -05:00
Cosimo Cecchi bcc4186388 color-swatch: remove gtk_color_swatch_set_corner_radii()
It's unused now.
2012-02-14 16:36:58 -05:00
Cosimo Cecchi 74a53b542b color-widget: use a GtkBox for the custom section
Since we only allow a single row there, it's better to just use a
GtkBox, and use :first-child, :last-child and :only-child to style
swatches in there.
2012-02-14 16:36:58 -05:00
Cosimo Cecchi 9da3d8b7b9 color-widget: add LEFT/RIGHT/TOP/BOTTOM style classes to the swatches
As we add them to the grid, for setting theming properties.
2012-02-14 16:36:58 -05:00
Cosimo Cecchi 73944c6e81 color-editor: don't call gtk_color_swatch_set_corner_radii()
It's going away.
2012-02-14 16:36:58 -05:00
Cosimo Cecchi a9c2a586b1 color-swatch: don't hardcode list-add-symbolic as swatch icon
We have that as a property, we should use it.
2012-02-14 16:36:57 -05:00
Cosimo Cecchi 83de34882b color-swatch: allow styling the "active badge"
Instead of calling gtk_render_check() there, just render a symbolic
icon, falling back to a built-in one if the icon is not available.
Also, add a style class for the active badge on the swatch:
"color-active-badge".
2012-02-14 16:36:57 -05:00
Cosimo Cecchi 1ccedc5fa4 color-swatch: use GtkThemingBackground to draw the background
This allows e.g. for the corner radii to be styled directly from the
theme.
2012-02-14 16:36:57 -05:00
Cosimo Cecchi 33e54e45be color-swatch: add a color-light/color-dark style class for intensity
Themes might want to set different colors on the badge if the displayed
color is light or dark. Use a style class for this when we set a color
on the swatch.
2012-02-14 16:36:57 -05:00
Cosimo Cecchi 46187037a3 themingbackground: make it based on GtkStyleContext
Instead of GtkThemingEngine. This will allow for the object to be also
used from inside e.g. a _draw() method.
2012-02-14 16:36:57 -05:00
Cosimo Cecchi ae132c0a1a roundedbox: add _apply_border_radius() variations for engine/context
And make the base function just use the raw corner radii struct.
2012-02-14 16:36:56 -05:00
Cosimo Cecchi 4c61f1f663 themingengine: add a private _gtk_theming_engine_get_context()
We'll need this later.
2012-02-14 16:36:56 -05:00
Cosimo Cecchi 4e37d56d51 themingengine: move _gtk_theming_engine_set_context to private header
Where it belongs.
2012-02-14 16:36:56 -05:00
Matthias Clasen 8f201d62d9 Add API to set palettes
I'm not really convinced by this; the API is a little complicated.
May need more thought.
2012-02-14 16:36:56 -05:00
Matthias Clasen d7cff0797e Misc cleanups 2012-02-14 16:36:56 -05:00
Matthias Clasen ed5aa953d5 testcolorchooser: Add more options
Add a --edit option that brings the color chooser up in
single-color edit mode right away.
2012-02-14 16:36:56 -05:00
Matthias Clasen cb128cc6e9 Deprecate old color selection widgets
GtkColorSelectionDialog, GtkColorSelection and GtkHSV have
been superseded by the GtkColorChooser* family of widgets.
2012-02-14 16:36:55 -05:00
Matthias Clasen 23a5f7a22c Add docs 2012-02-14 16:36:55 -05:00
Matthias Clasen 03a2b338ee Small documentation tweaks in font choosers 2012-02-14 16:36:55 -05:00
Matthias Clasen c5cfb6e02b Rework the API a bit
Rename get/set_color to get/set_rgba and show_alpha to use_alpha,
to match existing GtkColorButton API and let GtkColorButton implement
GtkColorChooser.
2012-02-14 16:36:55 -05:00
Matthias Clasen 1f68d7d827 Simplify GtkColorScale private api a bit 2012-02-14 16:36:55 -05:00
Matthias Clasen 6ed16b5b41 Fix up exported symbols
Only GtkColorChooser* is public for now.
2012-02-14 16:36:54 -05:00
Matthias Clasen 43ffb8521d Add a small comments 2012-02-14 16:36:54 -05:00
Matthias Clasen 1f7cc92219 Dismiss popups on show
This ensures that the editor always comes up without popups,
even when it is reused.
2012-02-14 16:36:54 -05:00
Matthias Clasen 3f92e24cb7 Add more todos 2012-02-14 16:36:54 -05:00
Matthias Clasen cc127c64a9 Add some accessible labels 2012-02-14 16:36:54 -05:00
Matthias Clasen 327e36e360 Mark strings for translation 2012-02-14 16:36:53 -05:00
Matthias Clasen f2aaffaf07 Finishing touches
Implement popups in the editor, fix window sizing, fix RTL flipping.
GtkColorPlane is now using adjustments, and GtkColorEditor is using
adjustments as its model as well.
2012-02-14 16:36:53 -05:00
Matthias Clasen cd300835d7 Allow context menus on scale sliders
This will be used for a popup in the color chooser.
2012-02-14 16:36:53 -05:00
Matthias Clasen e56adaebea Only activate on double-click 2012-02-14 16:36:53 -05:00
Matthias Clasen dbbe4c12fa Remove an erraneous g_free call 2012-02-14 16:36:53 -05:00
Matthias Clasen 296cd814e5 Add an Adwaita hack
When the theme is Adwaita, let the thumb extend out over the
colored trough.
2012-02-14 16:36:53 -05:00
Matthias Clasen 5bd4c234fb Draw no trough for color scales 2012-02-14 16:36:52 -05:00
Matthias Clasen 4226551fff Move color scales into separate widget 2012-02-14 16:36:52 -05:00
Matthias Clasen bdb8931bda Fix a few problems with custom color replacement
We were allowing one too many custom colors in, and when one
of them was dropped, we did not update the shape of the penultimate
one.
2012-02-14 16:36:52 -05:00
Matthias Clasen 3a35895a00 Make color chooser always come up with palette 2012-02-14 16:36:52 -05:00
Matthias Clasen d3b30bff0c Show new color chooser from color button 2012-02-14 16:36:52 -05:00
Matthias Clasen 2a8d3f78e9 Use a swatch in the editor
For now, we simply make it insensitive to turn off unwanted
interactivity.
2012-02-14 16:36:51 -05:00
Matthias Clasen ff1f5de62f Don't waste memory 2012-02-14 16:36:51 -05:00
Matthias Clasen 1720e8ebf3 Preliminary color sliders 2012-02-14 16:36:51 -05:00
Matthias Clasen 8178578359 Make alpha optional 2012-02-14 16:36:51 -05:00
Matthias Clasen 8d1565df94 Show alpha in the palette as well 2012-02-14 16:36:51 -05:00
Matthias Clasen 9161119329 No popup menu on the button 2012-02-14 16:36:50 -05:00
Matthias Clasen 9b81322409 Make saving custom colors work as intended
The custom colors are now pushed over to the right as new ones
are added, and everything beyond the 9th row gets dropped.
Customized colors are added to the custom colors array.
2012-02-14 16:36:50 -05:00
Matthias Clasen e1bf3b6650 Choose a different initial color when adding custom colors
Going for pure red 'hides' the hairline at the edge of the
plane. This color makes it nicely visible.
2012-02-14 16:36:50 -05:00
Jon McCann efccf87961 Show editor when clicking custom button 2012-02-14 16:36:50 -05:00
Jon McCann 2c24e3cb6a Align label with swatches 2012-02-14 16:36:50 -05:00
Jon McCann ce8212c5a8 Add Tangoish grayscales 2012-02-14 16:36:50 -05:00
Jon McCann ea6ac7131e Use the Tango palette by default 2012-02-14 16:36:49 -05:00
Matthias Clasen e06ccb0fbb Move the plane into a separate widget 2012-02-14 16:36:49 -05:00
Matthias Clasen 021f5e0365 Initial work on a color editor
This replaces GtkHSV with a compound widget featuring
a hue slider and an sv-plane, amongst others.
2012-02-14 16:36:49 -05:00
Matthias Clasen 759765114f Add a simple color chooser test 2012-02-14 16:36:49 -05:00
Matthias Clasen 3b6e316e74 Initial cut at implementing a new color chooser
This is a partial implementation of
https://live.gnome.org/GnomeOS/Design/Whiteboards/ColorSelection
The new color editor has not been implemented yet.
2012-02-14 16:36:49 -05:00
Matthias Clasen e2bde55277 Remove leftover debug spew 2012-02-14 13:08:27 -05:00
Cosimo Cecchi abdbe207fe about-dialog: set proper spacing between columnns in credits section
Spacing ended up being really tight; add another 6px.

https://bugzilla.gnome.org/show_bug.cgi?id=668114
2012-02-14 11:26:16 -05:00
Cosimo Cecchi a04fa5300a about-dialog: don't set a margin around the license area
Make it consistent with the credits page.

https://bugzilla.gnome.org/show_bug.cgi?id=670077
2012-02-14 11:21:52 -05:00
Cosimo Cecchi 8dc9866e2a about-dialog: add a stroke around the credits area
Makes it consistent with e.g. the license page.

https://bugzilla.gnome.org/show_bug.cgi?id=670078
2012-02-14 11:19:04 -05:00
Alexander Larsson 4b200a0429 Set a bg on GtkViewport to ensure we get fast scrolling
Otherwise it will use the default alpha transparency and
not scroll efficiently.
2012-02-14 15:18:30 +01:00
Cosimo Cecchi 713c532940 treeview: don't use gtk_render_focus() for dnd indicator
There's no reason this should be a focus ring rather than an actual
frame. In the past this was probably used to get a dashed effect, but
now we even support that natively for borders.
2012-02-13 22:43:07 -05:00
Cosimo Cecchi a3b097639f treeview: set "dnd" style class when drawing drag and drop indicators
This is useful to theme the rings that appear around rows on drag and
drop.
2012-02-13 22:19:53 -05:00
153 changed files with 17854 additions and 2627 deletions
+5 -1
View File
@@ -935,7 +935,7 @@ if test "x$enable_x11_backend" = xyes; then
have_base_x_pc=true
X_PACKAGES="$X_PACKAGES x11 xext"
x_libs="`$PKG_CONFIG --libs x11 xext`"
X_CFLAGS="`$PKG_CONFIG --cflags x11 xext`"
X_CFLAGS="`$PKG_CONFIG --cflags x11 xext` -DXINPUT2_1_USE_UNSTABLE_PROTOCOL -DXINPUT2_2_USE_UNSTABLE_PROTOCOL"
# Strip out any .la files that pkg-config might give us (this happens
# with -uninstalled.pc files)
@@ -1126,6 +1126,10 @@ if test "x$enable_x11_backend" = xyes; then
AC_DEFINE(XINPUT_2, 1, [Define to 1 if XInput 2.0 is available]),
X_EXTENSIONS="$X_EXTENSIONS XInput")
gtk_save_LIBS="$LIBS"
LIBS="$LIBS -lXi"
AC_CHECK_FUNC(XIAllowTouchEvents, AC_DEFINE(XINPUT_2_2, 1, [Define to 1 if XInput 2.2 is available]))
LIBS="$gtk_save_LIBS"
else
AC_DEFINE(XINPUT_NONE, 1,
[Define to 1 if no XInput should be used])
+1
View File
@@ -29,6 +29,7 @@ demos = \
links.c \
list_store.c \
menus.c \
multitouch.c \
offscreen_window.c \
offscreen_window2.c \
overlay.c \
+4 -13
View File
@@ -36,26 +36,17 @@ change_color_callback (GtkWidget *button,
{
GtkWidget *dialog;
GtkColorSelection *colorsel;
GtkColorSelectionDialog *selection_dialog;
GtkColorChooserDialog *selection_dialog;
gint response;
dialog = gtk_color_selection_dialog_new ("Changing color");
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
selection_dialog = GTK_COLOR_SELECTION_DIALOG (dialog);
colorsel = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (selection_dialog));
gtk_color_selection_set_previous_rgba (colorsel, &color);
gtk_color_selection_set_current_rgba (colorsel, &color);
gtk_color_selection_set_has_palette (colorsel, TRUE);
dialog = gtk_color_chooser_dialog_new ("Changing color", GTK_WINDOW (window));
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response == GTK_RESPONSE_OK)
{
gtk_color_selection_get_current_rgba (colorsel, &color);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
gtk_widget_override_background_color (da, 0, &color);
}
+698
View File
@@ -0,0 +1,698 @@
/* Multitouch
*
* Demonstrates some general multitouch event handling,
* using GdkTouchCluster in order to get grouped motion
* events for the touches within a cluster. Each of the
* created rectangles has one of those GdkTouchCluster
* objects.
*
* Touch events are also enabled on additional widgets,
* enabling simultaneous touch interaction on those. Not
* all widgets are prepared for multitouch interaction,
* as there are constraints that not all widgets may
* apply to.
*/
#include <math.h>
#include <gtk/gtk.h>
#include "demo-common.h"
#define RECT_BORDER_WIDTH 6
static GtkWidget *window = NULL;
static GtkWidget *area = NULL;
static GtkWidget *red = NULL;
static GtkWidget *green = NULL;
static GtkWidget *blue = NULL;
static GtkWidget *alpha = NULL;
static GQueue *shapes = NULL;
typedef struct {
GdkTouchCluster *cluster;
GdkRGBA color;
gdouble angle;
gdouble zoom;
gdouble center_x;
gdouble center_y;
gdouble x;
gdouble y;
gdouble width;
gdouble height;
gdouble base_zoom;
gdouble base_angle;
gdouble initial_distance;
gdouble initial_angle;
GdkPoint points[4];
} ShapeInfo;
static void
calculate_rotated_point (gdouble angle,
gdouble zoom,
gdouble center_x,
gdouble center_y,
gdouble point_x,
gdouble point_y,
gdouble *ret_x,
gdouble *ret_y)
{
gdouble distance, xd, yd, ang;
if (angle == 0)
{
*ret_x = point_x;
*ret_y = point_y;
return;
}
xd = center_x - point_x;
yd = center_y - point_y;
if (xd == 0 && yd == 0)
{
*ret_x = center_x;
*ret_y = center_y;
return;
}
distance = sqrt ((xd * xd) + (yd * yd));
distance *= zoom;
ang = atan2 (xd, yd);
/* Invert angle */
ang = (2 * G_PI) - ang;
/* Shift it 270° */
ang += 3 * (G_PI / 2);
/* And constraint it to 0°-360° */
ang = fmod (ang, 2 * G_PI);
ang += angle;
*ret_x = center_x + (distance * cos (ang));
*ret_y = center_y + (distance * sin (ang));
}
static void
shape_info_allocate_input_rect (ShapeInfo *info)
{
gint width, height, i;
width = info->width;
height = info->height;
/* Top/left */
info->points[0].x = info->x - info->center_x;
info->points[0].y = info->y - info->center_y;
/* Top/right */
info->points[1].x = info->x - info->center_x + width;
info->points[1].y = info->y - info->center_y;
/* Bottom/right */
info->points[2].x = info->x - info->center_x + width;
info->points[2].y = info->y - info->center_y + height;
/* Bottom/left */
info->points[3].x = info->x - info->center_x;
info->points[3].y = info->y - info->center_y + height;
for (i = 0; i < 4; i++)
{
gdouble ret_x, ret_y;
calculate_rotated_point (info->angle,
info->zoom,
info->x,
info->y,
(gdouble) info->points[i].x,
(gdouble) info->points[i].y,
&ret_x,
&ret_y);
info->points[i].x = (gint) ret_x;
info->points[i].y = (gint) ret_y;
}
}
static void
shape_info_bounding_rect (ShapeInfo *info,
GdkRectangle *rect)
{
gint i, left, right, top, bottom;
left = top = G_MAXINT;
right = bottom = 0;
for (i = 0; i < 4; i++)
{
if (info->points[i].x < left)
left = info->points[i].x;
if (info->points[i].x > right)
right = info->points[i].x;
if (info->points[i].y < top)
top = info->points[i].y;
if (info->points[i].y > bottom)
bottom = info->points[i].y;
}
rect->x = left - 20;
rect->y = top - 20;
rect->width = right - left + 40;
rect->height = bottom - top + 40;
}
static gboolean
shape_info_point_in (ShapeInfo *info,
gint x,
gint y)
{
GdkPoint *left, *right, *top, *bottom;
gint i;
left = right = top = bottom = NULL;
for (i = 0; i < 4; i++)
{
GdkPoint *p = &info->points[i];
if (!left ||
p->x < left->x ||
(p->x == left->x && p->y > left->y))
left = p;
if (!right ||
p->x > right->x ||
(p->x == right->x && p->y < right->y))
right = p;
}
for (i = 0; i < 4; i++)
{
GdkPoint *p = &info->points[i];
if (p == left || p == right)
continue;
if (!top ||
p->y < top->y)
top = p;
if (!bottom ||
p->y > bottom->y)
bottom = p;
}
g_assert (left && right && top && bottom);
if (x < left->x ||
x > right->x ||
y < top->y ||
y > bottom->y)
return FALSE;
/* Check whether point is above the sides
* between leftmost and topmost, and
* topmost and rightmost corners.
*/
if (x <= top->x)
{
if (left->y - ((left->y - top->y) * (((gdouble) x - left->x) / (top->x - left->x))) > y)
return FALSE;
}
else
{
if (top->y + ((right->y - top->y) * (((gdouble) x - top->x) / (right->x - top->x))) > y)
return FALSE;
}
/* Check whether point is below the sides
* between leftmost and bottom, and
* bottom and rightmost corners.
*/
if (x <= bottom->x)
{
if (left->y + ((bottom->y - left->y) * (((gdouble) x - left->x) / (bottom->x - left->x))) < y)
return FALSE;
}
else
{
if (bottom->y - ((bottom->y - right->y) * (((gdouble) x - bottom->x) / (right->x - bottom->x))) < y)
return FALSE;
}
return TRUE;
}
static ShapeInfo *
shape_info_new (gdouble x,
gdouble y,
gdouble width,
gdouble height,
GdkRGBA *color)
{
ShapeInfo *info;
info = g_slice_new0 (ShapeInfo);
info->cluster = NULL;
info->color = *color;
info->x = x;
info->y = y;
info->width = width;
info->height = height;
info->angle = 0;
info->zoom = 1;
info->base_zoom = 1;
info->base_angle = 0;
info->initial_distance = 0;
info->initial_angle = 0;
shape_info_allocate_input_rect (info);
g_queue_push_tail (shapes, info);
return info;
}
static void
shape_info_free (ShapeInfo *info)
{
g_slice_free (ShapeInfo, info);
}
static void
shape_info_draw (cairo_t *cr,
ShapeInfo *info)
{
cairo_save (cr);
cairo_translate (cr,
info->points[0].x + RECT_BORDER_WIDTH / 2,
info->points[0].y + RECT_BORDER_WIDTH / 2);
cairo_scale (cr, info->zoom, info->zoom);
cairo_rotate (cr, info->angle);
cairo_rectangle (cr, 0, 0,
info->width - RECT_BORDER_WIDTH,
info->height - RECT_BORDER_WIDTH);
gdk_cairo_set_source_rgba (cr, &info->color);
cairo_fill_preserve (cr);
cairo_set_line_width (cr, RECT_BORDER_WIDTH);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_stroke (cr);
cairo_restore (cr);
}
static void
shape_update_scales (ShapeInfo *info)
{
gtk_range_set_value (GTK_RANGE (red), info->color.red);
gtk_range_set_value (GTK_RANGE (green), info->color.green);
gtk_range_set_value (GTK_RANGE (blue), info->color.blue);
gtk_range_set_value (GTK_RANGE (alpha), info->color.alpha);
}
static void
range_value_changed_cb (GtkRange *range,
gpointer user_data)
{
GtkWidget *widget;
GdkRectangle rect;
ShapeInfo *shape;
gdouble value;
widget = GTK_WIDGET (range);
shape = g_queue_peek_head (shapes);
if (!shape)
return;
value = gtk_range_get_value (range);
if (widget == red)
shape->color.red = value;
else if (widget == green)
shape->color.green = value;
else if (widget == blue)
shape->color.blue = value;
else if (widget == alpha)
shape->color.alpha = value;
shape_info_bounding_rect (shape, &rect);
gdk_window_invalidate_rect (gtk_widget_get_window (area),
&rect, FALSE);
}
static gboolean
draw_cb (GtkWidget *widget,
cairo_t *cr,
gpointer user_data)
{
GList *l;
cairo_save (cr);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
for (l = shapes->tail; l; l = l->prev)
shape_info_draw (cr, l->data);
cairo_restore (cr);
return FALSE;
}
static gboolean
button_press_cb (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
ShapeInfo *shape = NULL;
guint touch_id;
if (gdk_event_get_touch_id (event, &touch_id))
{
GList *l;
for (l = shapes->tail; l; l = l->prev)
{
ShapeInfo *info = l->data;
if (shape_info_point_in (info,
(gint) event->button.x,
(gint) event->button.y))
shape = info;
}
if (!shape)
return FALSE;
/* Put on top */
g_queue_remove (shapes, shape);
g_queue_push_head (shapes, shape);
shape_update_scales (shape);
if (!shape->cluster)
shape->cluster = gdk_window_create_touch_cluster (gtk_widget_get_window (widget),
gdk_event_get_device (event));
else if (gdk_touch_cluster_get_n_touches (shape->cluster) == 0)
{
/* Only change cluster device if there were no touches */
gdk_touch_cluster_set_device (shape->cluster,
gdk_event_get_device (event));
}
gdk_touch_cluster_add_touch (shape->cluster, touch_id);
return TRUE;
}
return FALSE;
}
static gboolean
multitouch_cb (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
ShapeInfo *info = NULL;
gboolean new_center = FALSE;
gboolean new_position = FALSE;
gdouble event_x, event_y;
cairo_region_t *region;
GdkRectangle rect;
GList *l;
for (l = shapes->head; l; l = l->next)
{
ShapeInfo *shape = l->data;
if (event->multitouch.group == shape->cluster)
{
info = shape;
break;
}
}
if (!info)
return FALSE;
shape_info_bounding_rect (info, &rect);
region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) &rect);
if (event->multitouch.n_events == 1)
{
/* Update center if we just got to
* this situation from either way */
if (event->type == GDK_MULTITOUCH_ADDED ||
event->type == GDK_MULTITOUCH_REMOVED)
new_center = TRUE;
event_x = event->multitouch.events[0]->x;
event_y = event->multitouch.events[0]->y;
new_position = TRUE;
}
else if (event->multitouch.n_events == 2)
{
gdouble distance, angle;
gdk_events_get_center ((GdkEvent *) event->multitouch.events[0],
(GdkEvent *) event->multitouch.events[1],
&event_x, &event_y);
gdk_events_get_distance ((GdkEvent *) event->multitouch.events[0],
(GdkEvent *) event->multitouch.events[1],
&distance);
gdk_events_get_angle ((GdkEvent *) event->multitouch.events[0],
(GdkEvent *) event->multitouch.events[1],
&angle);
if (event->type == GDK_MULTITOUCH_ADDED)
{
/* Second touch was just added, update base zoom/angle */
info->base_zoom = info->zoom;
info->base_angle = info->angle;
info->initial_angle = angle;
info->initial_distance = distance;
new_center = TRUE;
}
info->zoom = MAX (info->base_zoom * (distance / info->initial_distance), 1.0);
info->angle = info->base_angle + (angle - info->initial_angle);
new_position = TRUE;
}
if (new_center)
{
gdouble origin_x, origin_y;
origin_x = info->x - info->center_x;
origin_y = info->y - info->center_y;
calculate_rotated_point (- info->angle,
1 / info->zoom,
info->x - origin_x,
info->y - origin_y,
event_x - origin_x,
event_y - origin_y,
&info->center_x,
&info->center_y);
}
if (new_position)
{
info->x = event_x;
info->y = event_y;
}
shape_info_allocate_input_rect (info);
shape_info_bounding_rect (info, &rect);
cairo_region_union_rectangle (region, (cairo_rectangle_int_t *) &rect);
gdk_window_invalidate_region (gtk_widget_get_window (widget), region, FALSE);
return TRUE;
}
static void
window_destroyed_cb (GtkWidget *widget,
gpointer user_data)
{
g_queue_foreach (shapes, (GFunc) shape_info_free, NULL);
g_queue_free (shapes);
shapes = NULL;
window = NULL;
}
static void
new_rectangle_clicked_cb (GtkButton *button,
gpointer user_data)
{
GdkRectangle rect;
ShapeInfo *info;
GdkRGBA color;
color.red = color.green = color.blue = color.alpha = 0.5;
info = shape_info_new (0, 0, 100, 150, &color);
shape_info_bounding_rect (info, &rect);
gdk_window_invalidate_rect (gtk_widget_get_window (area), &rect, FALSE);
}
GtkWidget *
create_drawing_area (void)
{
area = gtk_drawing_area_new ();
gtk_widget_add_events (area,
GDK_TOUCH_MASK |
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
gtk_widget_set_size_request (area, 600, 600);
g_signal_connect (area, "draw",
G_CALLBACK (draw_cb), NULL);
g_signal_connect (area, "button-press-event",
G_CALLBACK (button_press_cb), NULL);
g_signal_connect (area, "multitouch-event",
G_CALLBACK (multitouch_cb), NULL);
return area;
}
GtkWidget *
create_scale (void)
{
GtkWidget *scale;
scale = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL, 0, 1, 0.01);
gtk_range_set_inverted (GTK_RANGE (scale), TRUE);
gtk_widget_set_vexpand (scale, TRUE);
gtk_widget_set_margin_left (scale, 15);
gtk_widget_set_margin_right (scale, 15);
gtk_widget_add_events (scale, GDK_TOUCH_MASK);
g_signal_connect (scale, "value-changed",
G_CALLBACK (range_value_changed_cb), NULL);
return scale;
}
GtkWidget *
create_window (void)
{
GtkWidget *grid, *label, *button;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Multitouch demo");
g_signal_connect (window, "destroy",
G_CALLBACK (window_destroyed_cb), NULL);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
area = create_drawing_area ();
gtk_grid_attach (GTK_GRID (grid),
area, 0, 0, 1, 3);
gtk_widget_set_hexpand (area, TRUE);
gtk_widget_set_vexpand (area, TRUE);
/* "red" label/scale */
label = gtk_label_new ("Red");
gtk_widget_set_vexpand (label, FALSE);
gtk_grid_attach (GTK_GRID (grid),
label, 1, 0, 1, 1);
red = create_scale ();
gtk_grid_attach (GTK_GRID (grid),
red, 1, 1, 1, 1);
/* "green" label/scale */
label = gtk_label_new ("Green");
gtk_widget_set_vexpand (label, FALSE);
gtk_grid_attach (GTK_GRID (grid),
label, 2, 0, 1, 1);
green = create_scale ();
gtk_grid_attach (GTK_GRID (grid),
green, 2, 1, 1, 1);
/* "blue" label/scale */
label = gtk_label_new ("Blue");
gtk_widget_set_vexpand (label, FALSE);
gtk_grid_attach (GTK_GRID (grid),
label, 3, 0, 1, 1);
blue = create_scale ();
gtk_grid_attach (GTK_GRID (grid),
blue, 3, 1, 1, 1);
/* "alpha" label/scale */
label = gtk_label_new ("Alpha");
gtk_widget_set_vexpand (label, FALSE);
gtk_grid_attach (GTK_GRID (grid),
label, 4, 0, 1, 1);
alpha = create_scale ();
gtk_grid_attach (GTK_GRID (grid),
alpha, 4, 1, 1, 1);
/* button */
button = gtk_button_new_from_stock (GTK_STOCK_NEW);
gtk_widget_add_events (button, GDK_TOUCH_MASK);
gtk_grid_attach (GTK_GRID (grid),
button, 1, 2, 4, 1);
gtk_widget_set_vexpand (button, FALSE);
g_signal_connect (button, "clicked",
G_CALLBACK (new_rectangle_clicked_cb), NULL);
gtk_widget_show_all (grid);
return window;
}
GtkWidget *
do_multitouch (GtkWidget *do_widget)
{
if (!shapes)
shapes = g_queue_new ();
if (!window)
window = create_window ();
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
{
gtk_widget_destroy (window);
window = NULL;
g_queue_foreach (shapes, (GFunc) shape_info_free, NULL);
g_queue_free (shapes);
shapes = NULL;
}
return window;
}
+2 -1
View File
@@ -42,7 +42,8 @@ show_about (GtkMenuItem *item, GtkWidget *window)
GdkPixbuf *pixbuf;
const gchar *authors[] = {
"Andrea Cimitan",
"Cosimo Cecchi"
"Cosimo Cecchi",
NULL
};
pixbuf = gdk_pixbuf_new_from_resource ("/logos/gtk-logo-256.png", NULL);
+1
View File
@@ -33,6 +33,7 @@
<xi:include href="xml/windows.xml" />
<xi:include href="xml/events.xml" />
<xi:include href="xml/event_structs.xml" />
<xi:include href="xml/touchcluster.xml" />
<xi:include href="xml/keys.xml" />
<xi:include href="xml/selections.xml" />
<xi:include href="xml/dnd.xml" />
+26
View File
@@ -781,11 +781,13 @@ gdk_event_get_root_coords
gdk_event_get_scroll_direction
gdk_event_get_state
gdk_event_get_time
gdk_event_get_touch_id
gdk_event_request_motions
gdk_events_get_angle
gdk_events_get_center
gdk_events_get_distance
gdk_event_triggers_context_menu
gdk_event_get_touch_id
<SUBSECTION>
gdk_event_handler_set
@@ -833,6 +835,7 @@ GdkEventWindowState
GdkEventSetting
GdkEventOwnerChange
GdkEventGrabBroken
GdkEventMultiTouch
<SUBSECTION>
GdkScrollDirection
@@ -860,6 +863,29 @@ gdk_event_get_type
gdk_owner_change_get_type
</SECTION>
<SECTION>
<TITLE>Multitouch</TITLE>
<FILE>touchcluster</FILE>
GdkTouchCluster
gdk_touch_cluster_add_touch
gdk_touch_cluster_remove_touch
gdk_touch_cluster_remove_all
gdk_touch_cluster_set_device
gdk_touch_cluster_get_device
gdk_touch_cluster_get_touches
<SUBSECTION>
gdk_window_create_touch_cluster
gdk_window_remove_touch_cluster
<SUBSECTION Standard>
GDK_TYPE_TOUCH_CLUSTER
<SUBSECTION Private>
gdk_touch_cluster_get_type
</SECTION>
<SECTION>
<TITLE>Cursors</TITLE>
<FILE>cursors</FILE>
+1
View File
@@ -9,5 +9,6 @@ gdk_display_manager_get_type
gdk_drag_context_get_type
gdk_keymap_get_type
gdk_screen_get_type
gdk_touch_cluster_get_type
gdk_visual_get_type
gdk_window_get_type
+4
View File
@@ -119,6 +119,7 @@ content_files = \
running.sgml \
building.sgml \
compiling.sgml \
device-interaction-patterns.xml \
drawing-model.xml \
glossary.xml \
migrating-2to3.xml \
@@ -142,6 +143,7 @@ content_files = \
overview.xml
expand_content_files = \
device-interaction-patterns.xml \
drawing-model.xml \
getting_started.xml \
glossary.xml \
@@ -287,6 +289,7 @@ HTML_IMAGES = \
$(srcdir)/images/check-button.png \
$(srcdir)/images/color-button.png \
$(srcdir)/images/colorsel.png \
$(srcdir)/images/colorchooser.png \
$(srcdir)/images/combo-box.png \
$(srcdir)/images/combo-box-entry.png \
$(srcdir)/images/entry.png \
@@ -296,6 +299,7 @@ HTML_IMAGES = \
$(srcdir)/images/filechooser.png \
$(srcdir)/images/font-button.png \
$(srcdir)/images/fontsel.png \
$(srcdir)/images/fontchooser.png \
$(srcdir)/images/frame.png \
$(srcdir)/images/icon-view.png \
$(srcdir)/images/image.png \
@@ -0,0 +1,578 @@
<?xml version="1.0"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<chapter id="gtk-device-interaction-patterns">
<title>Multitouch and other device interaction patterns</title>
<para>
Depending on the platform, GTK+ is able to handle a wide range of input
devices. Those are offered to applications in a 2-level hierarchy, with
virtual devices (or master devices) representing the visual cursors
displayed in the screen, which are each controlled by a number of physical
devices (or slave devices). Those devices can respectively be retrieved
from an input event with gdk_event_get_device() and
gdk_event_get_source_device().
</para>
<para>
In X11, GTK+ uses XInput2 for input events, which caters for a fully dynamic
device hierarchy, and support for multiple virtual pointer/keyboard pairs.
</para>
<example>
<title>Listing and modifying the device hierarchy</title>
<programlisting>
carlos@sacarino:~$ xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ Wacom ISDv4 E6 Pen stylus id=10 [slave pointer (2)]
⎜ ↳ Wacom ISDv4 E6 Finger touch id=11 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=13 [slave pointer (2)]
⎜ ↳ TPPS/2 IBM TrackPoint id=14 [slave pointer (2)]
⎜ ↳ Wacom ISDv4 E6 Pen eraser id=16 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Sleep Button id=8 [slave keyboard (3)]
↳ Integrated Camera id=9 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=12 [slave keyboard (3)]
↳ ThinkPad Extra Buttons id=15 [slave keyboard (3)]
carlos@sacarino:~$ xinput create-master eek
carlos@sacarino:~$ xinput list
...
⎡ eek pointer id=17 [master pointer (18)]
⎜ ↳ eek XTEST pointer id=19 [slave pointer (17)]
⎣ eek keyboard id=18 [master keyboard (17)]
↳ eek XTEST keyboard id=20 [slave keyboard (18)]
carlos@sacarino:~$ xinput reattach 10 17
carlos@sacarino:~$ xinput list
...
⎡ eek pointer id=17 [master pointer (18)]
⎜ ↳ Wacom ISDv4 E6 Pen stylus id=10 [slave pointer (17)]
⎜ ↳ eek XTEST pointer id=19 [slave pointer (17)]
⎣ eek keyboard id=18 [master keyboard (17)]
↳ eek XTEST keyboard id=20 [slave keyboard (18)]
</programlisting>
</example>
<para>
Anytime a virtual device is added or removed, or a physical device
is attached to another virtual device, or left floating (detached
from any virtual device), #GdkDeviceManager will emit the corresponding
#GdkDeviceManager::device-added, #GdkDeviceManager::device-removed, or
#GdkDeviceManager::device-changed signals.
</para>
<section id="gtk-device-patterns-client-pointer">
<title>The client pointer</title>
<para>
In X11, Under the presence of multiple virtual pointers, GDK and XInput2
use the "client pointer" principle to allow several legacy applications
to interact simultaneously with different virtual pointer/keyboard pairs,
it would be usually set by the window manager for a focused window, so
different application windows could operate on different client pointers.
gdk_device_manager_get_client_pointer() may be called to get the client
pointer #GdkDevice
</para>
<para>
Under the hood, X11 uses the client pointer (or its paired keyboard) to
satisfy core calls such as XGrabPointer/Keyboard, XQueryPointer and
others that have been superseded by XInput2.
</para>
<para>
In platforms without multidevice features, gdk_device_manager_get_client_pointer()
will return the only virtual pointer available.
</para>
</section>
<section id="gtk-device-patterns-simple">
<title>Simple device handling</title>
<para>
There are applications that could have little gain in knowing about
multiple devices, although there are situations where a device could
be needed (i.e. popping up a menu on the pointer coordinates).
</para>
<para>
For such applications, the client pointer may be a good enough
approximation for these operations. Under the presence of multiple
device pairs, this gives a behavior that is most similar to that
of legacy applications (i.e. gtk+2).
</para>
<example>
<title>Getting the client pointer and keyboard</title>
<programlisting>
GdkDisplay *display;
GdkDeviceManager *device_manager;
GdkDevice *client_pointer, client_keyboard;
display = gdk_display_get_default ();
device_manager = gdk_display_get_device_manager (display);
client_pointer = gdk_device_manager_get_client_pointer (device_manager);
/* Or if we need a keyboard too */
client_keyboard = gdk_device_get_associated_device (client_pointer);
</programlisting>
</example>
</section>
<section id="gtk-device-patterns-multiple-devices">
<title>Dealing with multiple devices</title>
<para>
There may be several usecases to deal with multiple devices, including,
but not limited to:
</para>
<orderedlist>
<listitem>
Retrieving advanced information from an input device: i.e. stylus pressure/tilt
in drawing applications.
</listitem>
<listitem>
Receiving events from a dedicated input device: i.e. joysticks in games.
</listitem>
<listitem>
Collaborative interfaces, handling simultaneous input from multiple users.
</listitem>
</orderedlist>
<para>
However, the patterns to make them work are very similar.
</para>
<section>
<title>Event handling</title>
<para>
Each device will emit its own event stream, this means
that you will need to check the GdkEvent you get in
your event handlers
</para>
<example>
<title>Reacting differently to devices</title>
<programlisting>
static gboolean
my_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
GdkDevice *device, *source_device;
device = gdk_event_get_device ((GdkEvent *) event);
source_device = gdk_event_get_source_device ((GdkEvent *) event);
g_print ("Motion event by '%s', coming from HW device '%s'\n",
gdk_device_get_name (device),
gdk_device_get_name (source_device));
/* Handle touch devices differently */
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
{
...
}
else
{
...
}
return TRUE;
}
</programlisting>
</example>
<para>
The mechanism above could also be used for fine grained event discarding
(i.e. so rubberband selection doesn't jump to another pointer entering
the widget for example)
</para>
<example>
<title>Reacting differently to devices</title>
<programlisting>
static gboolean
my_widget_button_press (Gtkwidget *widget,
GdkEventButton *event)
{
GET_PRIV(widget)->current_pointer = gdk_event_get_device ((GdkEvent *) event);
...
}
static gboolean
my_widget_button_release (Gtkwidget *widget,
GdkEventButton *event)
{
GET_PRIV(widget)->current_pointer = NULL;
...
}
static gboolean
my_widget_motion_notify (Gtkwidget *widget,
GdkEventMotion *event)
{
if (gdk_event_get_device (event) !=
GET_PRIV(widget)->current_pointer)
return FALSE;
...
}
</programlisting>
</example>
</section>
<section>
<title>Grabs</title>
<para>
Grabs are a mechanism to coerce a device into sending events to
a window, but with multidevice there's an other side of the coin,
how other devices are supposed to interact while the grab is in
effect.
</para>
<para>
The GdkGrabOwnership enum passed to gdk_device_grab() may be used
to block other devices' interaction. %GDK_OWNERSHIP_NONE applies
no restrictions, allowing other devices to interact, even with
the grab window. %GDK_OWNERSHIP_WINDOW blocks other devices from
interacting with the grab window, but they'll still be able to
interact with the rest of the application, whereas
%GDK_OWNERSHIP_APPLICATION will render the whole application
insensitive to input from other devices. Different devices may
have simultaneous grabs on the same or different windows.
</para>
<example>
<title>Grabbing as a result of an input event</title>
<programlisting>
gboolean
my_widget_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GdkDevice *pointer, *keyboard;
pointer = gdk_event_get_device ((GdkEvent *) event);
keyboard = gdk_device_get_associated_device (pointer);
/* Grab both keyboard/pointer, other devices will be
* unable to interact with the widget window meanwhile
*/
gdk_device_grab (pointer,
gtk_widget_get_window (widget),
GDK_OWNERSHIP_WINDOW,
...);
gdk_device_grab (keyboard,
gtk_widget_get_window (widget),
GDK_OWNERSHIP_WINDOW,
...);
return FALSE;
}
</programlisting>
</example>
<para>
For GTK+ grabs, there's only a boolean value, equivalent to
%GDK_OWNERSHIP_NONE and %GDK_OWNERSHIP_WINDOW, but the mechanism
is quite similar.
</para>
<para>
Once the device is grabbed, there may be different situations
that could break the grabs, so the widget needs to listen to
#GdkGrabBrokenEvent and the #GtkWidget::grab-notify signal to
handle these situations.
</para>
<example>
<title>Handling broken grabs</title>
<programlisting>
static gboolean
my_widget_grab_broken (GtkWidget *widget,
GdkEventGrabBroken *event)
{
MyWidgetPrivate *priv = GET_PRIV (widget);
if (gdk_event_get_device (event) == priv->grab_pointer)
{
/* Undo state */
...
priv->grab_pointer = NULL;
return TRUE;
}
return FALSE;
}
static void
my_widget_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
MyWidgetPrivate *priv = GET_PRIV (widget);
if (gtk_widget_device_is_shadowed (widget, priv->grab_device))
{
/* Device was "shadowed" by another widget's grab,
* release and undo state
*/
...
priv->grab_pointer = NULL;
}
}
</programlisting>
</example>
</section>
<section>
<title>Handling multipointer</title>
<para>
Widgets do react by default to every virtual device, although
by default they are set in a compatibility mode that makes them
behave better with multiple pointers, without necessarily
being multipointer aware.
</para>
<para>
This compatibility mode most notably disables per-device
enter/leave events, so these are stacked, and the crossing
events are only emitted when the first pointer enters the
window, and after the last pointer leaves it. This behavior
is controlled through gtk_widget_set_support_multidevice()
</para>
</section>
<section>
<title>Reading device axis values</title>
<para>
Button and motion events provide further information about
the device axes' current state. Note the device axes are
hardware and driver dependent, therefore the set of axes
is not set in stone, although there are a few more common ones.
</para>
<example>
<title>Getting to know the axes provided by a device</title>
<programlisting>
carlos@sacarino:~$ xinput list "Wacom ISDv4 E6 Pen stylus" |grep "Label"
Label: Abs X
Label: Abs Y
Label: Abs Pressure
Label: Abs Tilt X
Label: Abs Tilt Y
Label: Abs Wheel
</programlisting>
</example>
<example>
<title>Getting an axis value</title>
<programlisting>
gboolean
my_widget_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
GdkAtom *label_atom;
gdouble pressure;
label_atom = gdk_atom_intern_static_string ("Abs Pressure");
gdk_device_get_axis_value (gdk_event_get_device ((GdkEvent *) event),
event->axes, label_atom, &amp;pressure);
/* Do something with pressure */
...
return TRUE;
}
</programlisting>
</example>
<para>
All pointer devices report axes information, master and slave. to
achieve this, master pointers modify their list of axes at runtime
to reflect those of the currently routed slave, emitting
#GdkDevice::changed as the routed slave device changes.
</para>
</section>
<section>
<title>Dealing with slave (or floating) devices</title>
<para>
By default, GTK+ listens to all master devices, and typically
all slave devices will be attached to a master device. so
gdk_event_get_source_device() is the recommended way to deal
with the physical device triggering the event.
</para>
<para>
In more specialized setups, some devices could be floating
(i.e. tablets that don't route events through any virtual
pointer, but are expected to interact with drawing applications).
In that case, such specialized applications could want to interact
directly with the device. To do so, the device must be enabled,
and the widget wanting its events needs to add the event mask.
</para>
<example>
<title>Enabling events for a slave device</title>
<programlisting>
GdkDevice *device;
/* Gets the first device found with the given GdkInputSource */
device = get_device (gtk_widget_get_display (widget),
GDK_SOURCE_PEN);
gdk_device_set_mode (device, GDK_MODE_SCREEN);
gtk_widget_add_device_events (widget, device,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK);
</programlisting>
</example>
<para>
After these calls, the widget would specifically receive events
from the physical device, regardless of it being floating or
connected to a master device. In this second case, and if you
want exclusive control of the device, you can temporarily detach
the stylus device from its master by doing a GDK grab on it.
</para>
<para>
For events coming directly from slave devices, both
gdk_event_get_device() and gdk_event_get_source_device() will
return the same device of type %GDK_DEVICE_TYPE_SLAVE or
%GDK_DEVICE_TYPE_FLOATING.
</para>
<note>
This is less useful than it used to be in GTK+2/XInput1, at least
for attached slaves, as there is gdk_event_get_source_device(),
and master devices' events provide axes information.
</note>
</section>
</section>
<section id="gtk-device-patterns-multitouch-widgets">
<title>Multitouch in GTK+ widgets</title>
<para>
Since version 3.4, GTK+ offers support for multitouch devices through a new
set of events and higher level tools like #GdkTouchCluster and
#GtkGesturesInterpreter.
</para>
<para>
If the widget does not have %GDK_TOUCH_MASK set in the event mask, it will
only be allowed to interact with the touch emulating pointer events, and will
only receive pointer events.
</para>
<para>
If the widget does have %GDK_TOUCH_MASK enabled, it will be able to receive
events of type %GDK_TOUCH_PRESS, %GDK_TOUCH_RELEASE and %GDK_TOUCH_MOTION,
which will be respectively emitted through the #GtkWidget::button-press-event,
#GtkWidget::button-release-event and #GtkWidget::motion-notify-event signals.
There may be multiple, simultaneous sequences of events, those will be
recognized and referenced by their touch ID. See gdk_event_get_touch_id().
</para>
<para>
#GtkWidget<!-- -->s may create GdkTouchCluster<!-- -->s via
gdk_window_create_touch_cluster(), those may be used to group
touch events together, which are notified through #GdkEventMultitouch,
this event will be emitted in #GtkWidget<!-- -->s through the
#GtkWidget::multitouch-event signal.
</para>
<para>
Widgets may also handle gestures being performed on them,
gtk_widget_enable_gesture() and gtk_widget_disable_gesture() are
provided as a simple API, although widgets may also create a
#GtkGesturesInterpreter and feed it events directly.
</para>
</section>
<section id="gtk-device-patterns-multitouch">
<title>Multitouch across a widget hierarchy</title>
<para>
Fully touch driven applications might not want to confine multitouch
operations within a single widget, but rather offer simultaneous
interaction with multiple widgets.
</para>
<para>
GTK+ is able to provide such experience, although it does not enable
%GDK_TOUCH_MASK by default on its stock widgets. If a widget meets the
following requirements, it is ready to be used in a multitouch UI:
</para>
<orderedlist>
<listitem>
The widget handles #GtkWidget::button-press-event, #GtkWidget::button-release-event
and #GtkWidget::motion-notify-event, and does something meaningful while the button 1
is pressed. If any explicit check on the event type being %GDK_BUTTON_PRESS,
%GDK_BUTTON_RELEASE or %GDK_MOTION_NOTIFY is performed, the event types
%GDK_TOUCH_PRESS, %GDK_TOUCH_RELEASE or %GDK_TOUCH_MOTION also need to be handled.
</listitem>
<listitem>
The widget relies on the implicit grab as long as the button press/touch is active,
GDK or GTK+ grabs would break the implicit grabs other touch sequences may have on
other widgets.
</listitem>
<listitem>
The widget does not require (or opts out) keyboard interaction while a touch is
active on it. Touch interaction does not necessarily bring the keyboard focus with it.
</listitem>
<listitem>
If the widget is only meant to interact with one touch sequence at a time (i.e.
buttons), it has to be able to discern and reject operations on any later touch
sequence as long as the touch it is interacting with remains active.
</listitem>
</orderedlist>
<para>
If a widget meets those requirements, enabling %GDK_TOUCH_MASK on it will suffice
to make it handle multitouch events in a way that doesn't disrupt other touch
operations.
</para>
<example>
<title>Enabling touch events on a widget</title>
<programlisting>
gtk_widget_add_events (widget, GDK_TOUCH_MASK);
</programlisting>
</example>
<note>
Not all GTK+ stock widgets are immediately suitable for handling touch
events, there could be even design reasons on some of those which render
them unsuitable.
</note>
</section>
<section id="gtk-device-patterns-recommendations">
<title>Recommendations</title>
<orderedlist>
<listitem>
Device operations often come up as a result of input events, favor
gdk_event_get_device() and gtk_get_current_event_device() before
gdk_device_manager_get_client_pointer().
</listitem>
<listitem>
Store the devices the widget is currently interacting with, handle
GdkEventGrabBroken and #GtkWidget::grab-notify to undo/nullify these.
</listitem>
</orderedlist>
</section>
</chapter>
+13 -3
View File
@@ -68,6 +68,12 @@
<xi:include href="xml/gtkstyle.xml" />
</part>
<part id="multitouch-and-multidevice">
<title>Interacting with input devices</title>
<xi:include href="xml/device-interaction-patterns.xml" />
<xi:include href="xml/gtkgesturesinterpreter.xml" />
</part>
<part id="gtkobjects">
<title>GTK+ Widgets and Objects</title>
@@ -209,18 +215,22 @@
<chapter id="SelectorWidgets">
<title>Selectors (Color/File/Font)</title>
<xi:include href="xml/gtkcolorchooser.xml" />
<xi:include href="xml/gtkcolorbutton.xml" />
<xi:include href="xml/gtkcolorseldlg.xml" />
<xi:include href="xml/gtkcolorchooserwidget.xml" />
<xi:include href="xml/gtkcolorchooserdialog.xml" />
<xi:include href="xml/gtkcolorsel.xml" />
<xi:include href="xml/gtkcolorseldlg.xml" />
<xi:include href="xml/gtkhsv.xml" />
<xi:include href="xml/gtkfilechooser.xml" />
<xi:include href="xml/gtkfilechooserbutton.xml" />
<xi:include href="xml/gtkfilechooserdialog.xml" />
<xi:include href="xml/gtkfilechooserwidget.xml" />
<xi:include href="xml/gtkfilefilter.xml" />
<xi:include href="xml/gtkfontbutton.xml" />
<xi:include href="xml/gtkfontchooser.xml" />
<xi:include href="xml/gtkfontchooserdlg.xml" />
<xi:include href="xml/gtkfontbutton.xml" />
<xi:include href="xml/gtkfontchooserwidget.xml" />
<xi:include href="xml/gtkfontchooserdialog.xml" />
<xi:include href="xml/gtkfontsel.xml" />
<xi:include href="xml/gtkfontseldlg.xml" />
</chapter>
+113 -1
View File
@@ -1535,7 +1535,7 @@ gtk_font_chooser_widget_get_type
</SECTION>
<SECTION>
<FILE>gtkfontchooserdlg</FILE>
<FILE>gtkfontchooserdialog</FILE>
<TITLE>GtkFontChooserDialog</TITLE>
GtkFontChooserDialog
gtk_font_chooser_dialog_new
@@ -1579,6 +1579,51 @@ GtkFramePrivate
gtk_frame_get_type
</SECTION>
<SECTION>
<FILE>gtkgesturesinterpreter</FILE>
<TITLE>GtkGesturesInterpreter</TITLE>
GtkGesturesInterpreter
GtkGestureType
gtk_gestures_interpreter_new
gtk_gestures_interpreter_add_gesture
gtk_gestures_interpreter_remove_gesture
gtk_gestures_interpreter_feed_event
gtk_gestures_interpreter_finish
gtk_gestures_interpreter_get_n_active_strokes
<SUBSECTION Gestures>
GtkGestureStroke
gtk_gesture_stroke_new
gtk_gesture_stroke_copy
gtk_gesture_stroke_free
gtk_gesture_stroke_append_vector
gtk_gesture_stroke_get_n_vectors
gtk_gesture_stroke_get_vector
GtkGesture
GtkGestureFlags
gtk_gesture_new
gtk_gesture_copy
gtk_gesture_free
gtk_gesture_add_stroke
gtk_gesture_get_n_strokes
gtk_gesture_get_stroke
gtk_gesture_get_flags
gtk_gesture_register
gtk_gesture_register_static
gtk_gesture_lookup
<SUBSECTION Standard>
GTK_GESTURES_INTERPRETER
GTK_IS_GESTURES_INTERPRETER
GTK_TYPE_GESTURES_INTERPRETER
GTK_IS_GESTURES_INTERPRETER_CLASS
GTK_GESTURES_INTERPRETER_GET_CLASS
<SUBSECTION Private>
gtk_gestures_interpreter_get_type
gtk_gesture_stroke_get_type
gtk_gesture_get_type
</SECTION>
<SECTION>
<FILE>gtkhandlebox</FILE>
<TITLE>GtkHandleBox</TITLE>
@@ -2939,6 +2984,9 @@ gtk_scrolled_window_get_min_content_width
gtk_scrolled_window_set_min_content_width
gtk_scrolled_window_get_min_content_height
gtk_scrolled_window_set_min_content_height
GtkKineticScrollingFlags
gtk_scrolled_window_set_kinetic_scrolling
gtk_scrolled_window_get_kinetic_scrolling
<SUBSECTION Standard>
GTK_SCROLLED_WINDOW
@@ -5028,6 +5076,7 @@ GtkAllocation
GtkSelectionData
GtkWidgetAuxInfo
GtkWidgetHelpType
GtkCapturedEventFlags
gtk_widget_new
gtk_widget_destroy
gtk_widget_in_destruction
@@ -5213,6 +5262,7 @@ gtk_widget_get_mapped
gtk_widget_get_requisition
gtk_widget_device_is_shadowed
gtk_widget_get_modifier_mask
gtk_widget_release_captured_events
<SUBSECTION>
gtk_widget_get_path
@@ -5262,6 +5312,10 @@ gtk_widget_set_vexpand_set
gtk_widget_queue_compute_expand
gtk_widget_compute_expand
<SUBSECTION Gestures>
gtk_widget_enable_gesture
gtk_widget_disable_gesture
<SUBSECTION Standard>
GTK_WIDGET
GTK_IS_WIDGET
@@ -7298,3 +7352,61 @@ GtkOverlayClass
gtk_overlay_get_type
GtkOverlayPrivate
</SECTION>
<SECTION>
<FILE>gtkcolorchooser</FILE>
<TITLE>GtkColorChooser</TITLE>
GtkColorChooser
gtk_color_chooser_get_rgba
gtk_color_chooser_set_rgba
gtk_color_chooser_get_use_alpha
gtk_color_chooser_set_use_alpha
gtk_color_chooser_add_palette
<SUBSECTION Standard>
GTK_TYPE_COLOR_CHOOSER
GTK_COLOR_CHOOSER
GTK_IS_COLOR_CHOOSER
GTK_COLOR_CHOOSER_GET_IFACE
<SUBSECTION Private>
gtk_color_chooser_get_type
</SECTION>
<SECTION>
<FILE>gtkcolorchooserwidget</FILE>
<TITLE>GtkColorChooserWidget</TITLE>
GtkColorChooserWidget
gtk_color_chooser_widget_new
<SUBSECTION Standard>
GTK_TYPE_COLOR_CHOOSER_WIDGET
GTK_COLOR_CHOOSER_WIDGET
GTK_COLOR_CHOOSER_WIDGET_CLASS
GTK_IS_COLOR_CHOOSER_WIDGET
GTK_IS_COLOR_CHOOSER_WIDGET_CLASS
GTK_COLOR_CHOOSER_WIDGET_GET_CLASS
<SUBSECTION Private>
gtk_color_chooser_widget_get_type
GtkColorChooserWidgetPrivate
</SECTION>
<SECTION>
<FILE>gtkcolorchooserdialog</FILE>
<TITLE>GtkColorChooserDialog</TITLE>
GtkColorChooserDialog
gtk_color_chooser_dialog_new
<SUBSECTION Standard>
GTK_TYPE_COLOR_CHOOSER_DIALOG
GTK_COLOR_CHOOSER_DIALOG
GTK_COLOR_CHOOSER_DIALOG_CLASS
GTK_IS_COLOR_CHOOSER_DIALOG
GTK_IS_COLOR_CHOOSER_DIALOG_CLASS
GTK_COLOR_CHOOSER_DIALOG_GET_CLASS
<SUBSECTION Private>
GtkColorChooserDialogPrivate
gtk_color_chooser_dialog_get_type
</SECTION>
+4
View File
@@ -47,6 +47,9 @@ gtk_check_button_get_type
gtk_check_menu_item_get_type
gtk_clipboard_get_type
gtk_color_button_get_type
gtk_color_chooser_get_type
gtk_color_chooser_dialog_get_type
gtk_color_chooser_widget_get_type
gtk_color_selection_dialog_get_type
gtk_color_selection_get_type
gtk_combo_box_get_type
@@ -74,6 +77,7 @@ gtk_font_chooser_widget_get_type
gtk_font_selection_dialog_get_type
gtk_font_selection_get_type
gtk_frame_get_type
gtk_gestures_interpreter_get_type
gtk_grid_get_type
gtk_handle_box_get_type
gtk_hbox_get_type
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

+6
View File
@@ -135,4 +135,10 @@
<link linkend="GtkSwitch">
<inlinegraphic fileref="switch.png" format="PNG"></inlinegraphic>
</link>
<link linkend="GtkColorChooserDialog">
<inlinegraphic fileref="colorchooser.png" format="PNG"></inlinegraphic>
</link>
<link linkend="GtkFontChooserDialog">
<inlinegraphic fileref="fontchooser.png" format="PNG"></inlinegraphic>
</link>
</para>
+29
View File
@@ -1154,6 +1154,33 @@ create_appchooserdialog (void)
return info;
}
static WidgetInfo *
create_fontchooserdialog (void)
{
WidgetInfo *info;
GtkWidget *widget;
widget = gtk_font_chooser_dialog_new ("Font Chooser Dialog", NULL);
gtk_window_set_default_size (GTK_WINDOW (widget), 200, 300);
info = new_widget_info ("fontchooser", widget, ASIS);
info->include_decorations = TRUE;
return info;
}
static WidgetInfo *
create_colorchooserdialog (void)
{
WidgetInfo *info;
GtkWidget *widget;
widget = gtk_color_chooser_dialog_new ("Color Chooser Dialog", NULL);
info = new_widget_info ("colorchooser", widget, ASIS);
info->include_decorations = TRUE;
return info;
}
GList *
get_all_widgets (void)
{
@@ -1204,6 +1231,8 @@ get_all_widgets (void)
retval = g_list_prepend (retval, create_appchooserbutton ());
retval = g_list_prepend (retval, create_appchooserdialog ());
retval = g_list_prepend (retval, create_lockbutton ());
retval = g_list_prepend (retval, create_fontchooserdialog ());
retval = g_list_prepend (retval, create_colorchooserdialog ());
return retval;
}
+2
View File
@@ -88,6 +88,7 @@ gdk_public_h_sources = \
gdkselection.h \
gdktestutils.h \
gdkthreads.h \
gdktouchcluster.h \
gdktypes.h \
gdkvisual.h \
gdkwindow.h
@@ -130,6 +131,7 @@ gdk_c_sources = \
gdkrgba.c \
gdkscreen.c \
gdkselection.c \
gdktouchcluster.c \
gdkvisual.c \
gdkwindow.c \
gdkwindowimpl.c
+1
View File
@@ -53,6 +53,7 @@
#include <gdk/gdkselection.h>
#include <gdk/gdktestutils.h>
#include <gdk/gdkthreads.h>
#include <gdk/gdktouchcluster.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkvisual.h>
#include <gdk/gdkwindow.h>
+6
View File
@@ -168,6 +168,7 @@ gdk_event_get_scroll_direction
gdk_event_get_source_device
gdk_event_get_state
gdk_event_get_time
gdk_event_get_touch_id
gdk_event_get_type
gdk_event_handler_set
gdk_event_mask_get_type
@@ -327,6 +328,11 @@ gdk_threads_enter
gdk_threads_init
gdk_threads_leave
gdk_threads_set_lock_functions
gdk_touch_cluster_add_touch
gdk_touch_cluster_get_device
gdk_touch_cluster_get_type G_GNUC_CONST
gdk_touch_cluster_list_touches
gdk_touch_cluster_remove_touch
gdk_unicode_to_keyval
gdk_utf8_to_string_target
gdk_visibility_state_get_type
+3 -1
View File
@@ -61,6 +61,7 @@ typedef enum
* of a stylus on a graphics tablet.
* @GDK_SOURCE_CURSOR: the device is a graphics tablet "puck" or similar device.
* @GDK_SOURCE_KEYBOARD: the device is a keyboard.
* @GDK_SOURCE_TOUCH: the device is a touch capable device.
*
* An enumeration describing the type of an input device in general terms.
*/
@@ -70,7 +71,8 @@ typedef enum
GDK_SOURCE_PEN,
GDK_SOURCE_ERASER,
GDK_SOURCE_CURSOR,
GDK_SOURCE_KEYBOARD
GDK_SOURCE_KEYBOARD,
GDK_SOURCE_TOUCH
} GdkInputSource;
/**
+135 -13
View File
@@ -188,6 +188,7 @@ gdk_display_init (GdkDisplay *display)
display->double_click_time = 250;
display->double_click_distance = 5;
display->touch_implicit_grabs = g_array_new (FALSE, FALSE, sizeof (GdkTouchGrabInfo));
display->device_grabs = g_hash_table_new (NULL, NULL);
display->motion_hint_info = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_free);
@@ -236,6 +237,8 @@ gdk_display_finalize (GObject *object)
NULL);
g_hash_table_destroy (display->device_grabs);
g_array_free (display->touch_implicit_grabs, TRUE);
g_hash_table_destroy (display->motion_hint_info);
g_hash_table_destroy (display->pointers_info);
g_hash_table_destroy (display->multiple_click_info);
@@ -694,6 +697,81 @@ _gdk_display_add_device_grab (GdkDisplay *display,
return info;
}
static void
_gdk_display_break_touch_grabs (GdkDisplay *display,
GdkDevice *device,
GdkWindow *new_grab_window)
{
guint i = 0;
while (i < display->touch_implicit_grabs->len)
{
GdkTouchGrabInfo *info;
info = &g_array_index (display->touch_implicit_grabs,
GdkTouchGrabInfo, i);
if (info->device == device &&
info->window != new_grab_window)
{
generate_grab_broken_event (GDK_WINDOW (info->window),
device, TRUE, new_grab_window);
_gdk_window_finish_touch_id (info->window, device, info->touch_id);
g_array_remove_index_fast (display->touch_implicit_grabs, i);
}
else
i++;
}
}
void
_gdk_display_add_touch_grab (GdkDisplay *display,
GdkDevice *device,
guint touch_id,
GdkWindow *window,
GdkWindow *native_window,
GdkEventMask event_mask,
unsigned long serial,
guint32 time)
{
GdkTouchGrabInfo info;
info.device = device;
info.touch_id = touch_id;
info.window = g_object_ref (window);
info.native_window = g_object_ref (native_window);
info.serial = serial;
info.event_mask = event_mask;
info.time = time;
g_array_append_val (display->touch_implicit_grabs, info);
}
gboolean
_gdk_display_end_touch_grab (GdkDisplay *display,
GdkDevice *device,
guint touch_id)
{
guint i;
for (i = 0; i < display->touch_implicit_grabs->len; i++)
{
GdkTouchGrabInfo *info;
info = &g_array_index (display->touch_implicit_grabs,
GdkTouchGrabInfo, i);
if (info->device == device &&
info->touch_id == touch_id)
{
g_array_remove_index_fast (display->touch_implicit_grabs, i);
return TRUE;
}
}
return FALSE;
}
/* _gdk_synthesize_crossing_events only works inside one toplevel.
This function splits things into two calls if needed, converting the
coordinates to the right toplevel */
@@ -897,15 +975,25 @@ switch_to_pointer_grab (GdkDisplay *display,
if (grab == NULL) /* Ungrabbed, send events */
{
pointer_window = NULL;
if (new_toplevel)
{
/* Find (possibly virtual) child window */
pointer_window =
_gdk_window_find_descendant_at (new_toplevel,
x, y,
NULL, NULL);
}
/* If the source device is a touch device, do not
* propagate any enter event yet, until one is
* synthesized when needed.
*/
if (source_device &&
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
info->need_touch_press_enter = TRUE;
pointer_window = NULL;
if (new_toplevel &&
!info->need_touch_press_enter)
{
/* Find (possibly virtual) child window */
pointer_window =
_gdk_window_find_descendant_at (new_toplevel,
x, y,
NULL, NULL);
}
if (pointer_window != last_grab->window)
synthesize_crossing_events (display, device, source_device,
@@ -964,12 +1052,15 @@ _gdk_display_device_grab_update (GdkDisplay *display,
next_grab = NULL; /* Actually its not yet active */
}
if (next_grab)
_gdk_display_break_touch_grabs (display, device, next_grab->window);
if ((next_grab == NULL && current_grab->implicit_ungrab) ||
(next_grab != NULL && current_grab->window != next_grab->window))
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
(next_grab != NULL && current_grab->window != next_grab->window))
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
device,
current_grab->implicit,
next_grab? next_grab->window : NULL);
current_grab->implicit,
next_grab? next_grab->window : NULL);
/* Remove old grab */
grabs = g_list_delete_link (grabs, grabs);
@@ -1028,6 +1119,34 @@ _gdk_display_has_device_grab (GdkDisplay *display,
return NULL;
}
GdkTouchGrabInfo *
_gdk_display_has_touch_grab (GdkDisplay *display,
GdkDevice *device,
guint touch_id,
gulong serial)
{
guint i;
for (i = 0; i < display->touch_implicit_grabs->len; i++)
{
GdkTouchGrabInfo *info;
info = &g_array_index (display->touch_implicit_grabs,
GdkTouchGrabInfo, i);
if (info->device == device &&
info->touch_id == touch_id)
{
if (serial >= info->serial)
return info;
else
return NULL;
}
}
return NULL;
}
/* Returns true if last grab was ended
* If if_child is non-NULL, end the grab only if the grabbed
* window is the same as if_child or a descendant of it */
@@ -1120,6 +1239,9 @@ _gdk_display_get_pointer_info (GdkDisplay *display,
{
GdkPointerWindowInfo *info;
if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
device = gdk_device_get_associated_device (device);
if (G_UNLIKELY (!device))
return NULL;
+31
View File
@@ -60,6 +60,19 @@ typedef struct
guint implicit : 1;
} GdkDeviceGrabInfo;
/* Tracks information about a touch implicit grab on this display */
typedef struct
{
GdkDevice *device;
guint touch_id;
GdkWindow *window;
GdkWindow *native_window;
gulong serial;
guint event_mask;
guint32 time;
} GdkTouchGrabInfo;
/* Tracks information about which window and position the pointer last was in.
* This is useful when we need to synthesize events later.
* Note that we track toplevel_under_pointer using enter/leave events,
@@ -75,6 +88,8 @@ typedef struct
gdouble toplevel_x, toplevel_y;
guint32 state;
guint32 button;
GdkDevice *last_slave;
guint need_touch_press_enter : 1;
} GdkPointerWindowInfo;
typedef struct
@@ -103,6 +118,7 @@ struct _GdkDisplay
guint closed : 1; /* Whether this display has been closed */
guint ignore_core_events : 1; /* Don't send core motion and button event */
GArray *touch_implicit_grabs;
GHashTable *device_grabs;
GHashTable *motion_hint_info;
GdkDeviceManager *device_manager;
@@ -260,6 +276,21 @@ gboolean _gdk_display_end_device_grab (GdkDisplay *display
gboolean _gdk_display_check_grab_ownership (GdkDisplay *display,
GdkDevice *device,
gulong serial);
void _gdk_display_add_touch_grab (GdkDisplay *display,
GdkDevice *device,
guint touch_id,
GdkWindow *window,
GdkWindow *native_window,
GdkEventMask event_mask,
unsigned long serial_start,
guint32 time);
GdkTouchGrabInfo * _gdk_display_has_touch_grab (GdkDisplay *display,
GdkDevice *device,
guint touch_id,
gulong serial);
gboolean _gdk_display_end_touch_grab (GdkDisplay *display,
GdkDevice *device,
guint touch_id);
void _gdk_display_enable_motion_hints (GdkDisplay *display,
GdkDevice *device);
GdkPointerWindowInfo * _gdk_display_get_pointer_info (GdkDisplay *display,
+298 -5
View File
@@ -445,6 +445,7 @@ gdk_event_new (GdkEventType type)
switch (type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
new_event->motion.x = 0.;
new_event->motion.y = 0.;
new_event->motion.x_root = 0.;
@@ -454,6 +455,8 @@ gdk_event_new (GdkEventType type)
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
new_event->button.x = 0.;
new_event->button.y = 0.;
new_event->button.x_root = 0.;
@@ -464,6 +467,8 @@ gdk_event_new (GdkEventType type)
new_event->scroll.y = 0.;
new_event->scroll.x_root = 0.;
new_event->scroll.y_root = 0.;
new_event->scroll.delta_x = 0.;
new_event->scroll.delta_y = 0.;
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
@@ -487,7 +492,31 @@ gdk_event_is_allocated (const GdkEvent *event)
return FALSE;
}
void
_gdk_event_set_pointer_emulated (GdkEvent *event,
gboolean emulated)
{
if (gdk_event_is_allocated (event))
{
GdkEventPrivate *private = (GdkEventPrivate *) event;
if (emulated)
private->flags |= GDK_EVENT_POINTER_EMULATED;
else
private->flags &= ~(GDK_EVENT_POINTER_EMULATED);
}
}
gboolean
_gdk_event_get_pointer_emulated (GdkEvent *event)
{
if (gdk_event_is_allocated (event))
return (((GdkEventPrivate *) event)->flags & GDK_EVENT_POINTER_EMULATED) != 0;
return FALSE;
}
/**
* gdk_event_copy:
* @event: a #GdkEvent
@@ -558,12 +587,15 @@ gdk_event_copy (const GdkEvent *event)
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
if (event->button.axes)
new_event->button.axes = g_memdup (event->button.axes,
sizeof (gdouble) * gdk_device_get_n_axes (event->button.device));
break;
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
if (event->motion.axes)
new_event->motion.axes = g_memdup (event->motion.axes,
sizeof (gdouble) * gdk_device_get_n_axes (event->motion.device));
@@ -583,6 +615,22 @@ gdk_event_copy (const GdkEvent *event)
g_object_ref (new_event->selection.requestor);
break;
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
{
GdkEventMotion **motion_events;
guint i;
motion_events = g_new0 (GdkEventMotion*, event->multitouch.n_events);
for (i = 0; i < event->multitouch.n_events; i++)
motion_events[i] = (GdkEventMotion *) gdk_event_copy ((GdkEvent *) event->multitouch.events[i]);
new_event->multitouch.events = motion_events;
}
break;
default:
break;
}
@@ -639,6 +687,8 @@ gdk_event_free (GdkEvent *event)
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
g_free (event->button.axes);
break;
@@ -649,6 +699,7 @@ gdk_event_free (GdkEvent *event)
break;
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
g_free (event->motion.axes);
break;
@@ -668,6 +719,20 @@ gdk_event_free (GdkEvent *event)
g_object_unref (event->selection.requestor);
break;
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
if (event->multitouch.events)
{
guint i;
for (i = 0; i < event->multitouch.n_events; i++)
gdk_event_free ((GdkEvent *) event->multitouch.events[i]);
g_free (event->multitouch.events);
}
break;
default:
break;
}
@@ -696,11 +761,14 @@ gdk_event_get_time (const GdkEvent *event)
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
return event->motion.time;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
return event->button.time;
case GDK_SCROLL:
return event->scroll.time;
@@ -726,6 +794,10 @@ gdk_event_get_time (const GdkEvent *event)
case GDK_DROP_START:
case GDK_DROP_FINISHED:
return event->dnd.time;
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
return event->multitouch.time;
case GDK_CLIENT_EVENT:
case GDK_VISIBILITY_NOTIFY:
case GDK_CONFIGURE:
@@ -771,12 +843,15 @@ gdk_event_get_state (const GdkEvent *event,
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
*state = event->motion.state;
return TRUE;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
*state = event->button.state;
return TRUE;
case GDK_SCROLL:
@@ -790,6 +865,11 @@ gdk_event_get_state (const GdkEvent *event,
case GDK_LEAVE_NOTIFY:
*state = event->crossing.state;
return TRUE;
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
*state = event->multitouch.state;
return TRUE;
case GDK_PROPERTY_NOTIFY:
case GDK_VISIBILITY_NOTIFY:
case GDK_CLIENT_EVENT:
@@ -865,10 +945,13 @@ gdk_event_get_coords (const GdkEvent *event,
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
x = event->button.x;
y = event->button.y;
break;
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
x = event->motion.x;
y = event->motion.y;
break;
@@ -908,6 +991,7 @@ gdk_event_get_root_coords (const GdkEvent *event,
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
x = event->motion.x_root;
y = event->motion.y_root;
break;
@@ -919,6 +1003,8 @@ gdk_event_get_root_coords (const GdkEvent *event,
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
x = event->button.x_root;
y = event->button.y_root;
break;
@@ -1122,7 +1208,10 @@ gdk_event_get_scroll_direction (const GdkEvent *event,
switch (event->type)
{
case GDK_SCROLL:
dir = event->scroll.direction;
if (event->scroll.direction == GDK_SCROLL_SMOOTH)
fetched = FALSE;
else
dir = event->scroll.direction;
break;
default:
fetched = FALSE;
@@ -1135,6 +1224,52 @@ gdk_event_get_scroll_direction (const GdkEvent *event,
return fetched;
}
/**
* gdk_event_get_scroll_deltas:
* @event: a #GdkEvent
* @delta_x: return location for X delta
* @delta_y: return location for Y delta
*
* Retrieves the scroll deltas from a #GdkEvent
*
* Returns: %TRUE if the event contains smooth scroll information
*
* Since: 3.4
**/
gboolean
gdk_event_get_scroll_deltas (const GdkEvent *event,
gdouble *delta_x,
gdouble *delta_y)
{
gboolean fetched = TRUE;
gdouble dx = 0.0;
gdouble dy = 0.0;
switch (event->type)
{
case GDK_SCROLL:
if (event->scroll.direction == GDK_SCROLL_SMOOTH)
{
dx = event->scroll.delta_x;
dy = event->scroll.delta_y;
}
else
fetched = FALSE;
break;
default:
fetched = FALSE;
break;
}
if (delta_x)
*delta_x = dx;
if (delta_y)
*delta_y = dy;
return fetched;
}
/**
* gdk_event_get_axis:
* @event: a #GdkEvent
@@ -1162,7 +1297,8 @@ gdk_event_get_axis (const GdkEvent *event,
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
x = event->motion.x;
y = event->motion.y;
break;
@@ -1172,6 +1308,8 @@ gdk_event_get_axis (const GdkEvent *event,
break;
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
x = event->button.x;
y = event->button.y;
break;
@@ -1193,12 +1331,15 @@ gdk_event_get_axis (const GdkEvent *event,
return TRUE;
}
else if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_BUTTON_RELEASE)
event->type == GDK_BUTTON_RELEASE ||
event->type == GDK_TOUCH_PRESS ||
event->type == GDK_TOUCH_RELEASE)
{
device = event->button.device;
axes = event->button.axes;
}
else if (event->type == GDK_MOTION_NOTIFY)
else if (event->type == GDK_MOTION_NOTIFY ||
event->type == GDK_TOUCH_MOTION)
{
device = event->motion.device;
axes = event->motion.axes;
@@ -1235,12 +1376,15 @@ gdk_event_set_device (GdkEvent *event,
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
event->motion.device = device;
break;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
event->button.device = device;
break;
case GDK_SCROLL:
@@ -1250,6 +1394,10 @@ gdk_event_set_device (GdkEvent *event,
case GDK_PROXIMITY_OUT:
event->proximity.device = device;
break;
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
event->multitouch.device = device;
default:
break;
}
@@ -1282,17 +1430,24 @@ gdk_event_get_device (const GdkEvent *event)
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
return event->motion.device;
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
return event->button.device;
case GDK_SCROLL:
return event->scroll.device;
case GDK_PROXIMITY_IN:
case GDK_PROXIMITY_OUT:
return event->proximity.device;
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
return event->multitouch.device;
default:
break;
}
@@ -1301,10 +1456,13 @@ gdk_event_get_device (const GdkEvent *event)
switch (event->type)
{
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
case GDK_FOCUS_CHANGE:
@@ -1320,6 +1478,9 @@ gdk_event_get_device (const GdkEvent *event)
case GDK_GRAB_BROKEN:
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
{
GdkDisplay *display;
GdkDeviceManager *device_manager;
@@ -1686,6 +1847,138 @@ gdk_event_get_screen (const GdkEvent *event)
return NULL;
}
/**
* gdk_event_get_touch_id:
* @event: a #GdkEvent
* @touch_id: return location of the touch ID of a touch event
*
* If @event if of type %GDK_TOUCH_MOTION, %GDK_TOUCH_PRESS or
* %GDK_TOUCH_RELEASE, fills in @touch_id and returns %TRUE,
* else it returns %FALSE.
*
* Returns: %TRUE if the touch ID can be extracted from @event.
*
* Since: 3.4
**/
gboolean
gdk_event_get_touch_id (const GdkEvent *event,
guint *touch_id)
{
if (!event)
return FALSE;
if (event->type == GDK_TOUCH_MOTION)
{
if (touch_id)
*touch_id = event->motion.touch_id;
return TRUE;
}
else if (event->type == GDK_TOUCH_PRESS ||
event->type == GDK_TOUCH_RELEASE)
{
if (touch_id)
*touch_id = event->button.touch_id;
return TRUE;
}
else
{
if (touch_id)
*touch_id = 0;
return FALSE;
}
}
/**
* gdk_event_get_touch_area:
* @event: a #GdkEvent
*
* This function takes a #GdkEvent coming from a touch device
* (eg. gdk_event_get_source_device() returns a device of type
* %GDK_SOURCE_TOUCH), and returns the area covered by the touch
* as a #cairo_region_t. or %NULL if the device doesn't provide
* this information, or the touch area information couldn't be
* extracted from the event.
*
* <note><warning>Not all touch capable devices provide this
* information, so provide fallbacks to this function returning
* %NULL, even if the window receiving events is only meant
* to react to touch events.</warning></note>
*
* Returns: (transfer full): the touch region, or %NULL if unavailable
*
* Since: 3.4
**/
cairo_region_t *
gdk_event_get_touch_area (GdkEvent *event)
{
gdouble *axes, minor_axis, major_axis, orientation_axis;
GdkAtom major, minor, orientation;
GdkDevice *device;
g_return_val_if_fail (event != NULL, NULL);
device = gdk_event_get_source_device (event);
if (!device)
return NULL;
if (event->type == GDK_MOTION_NOTIFY ||
event->type == GDK_TOUCH_MOTION)
axes = event->motion.axes;
else if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_2BUTTON_PRESS ||
event->type == GDK_3BUTTON_PRESS ||
event->type == GDK_BUTTON_RELEASE)
axes = event->button.axes;
else
return NULL;
major = gdk_atom_intern_static_string ("Abs MT Touch Major");
minor = gdk_atom_intern_static_string ("Abs MT Touch Minor");
orientation = gdk_atom_intern_static_string ("Abs MT Orientation");
if (gdk_device_get_axis_value (device, axes, major, &major_axis) &&
gdk_device_get_axis_value (device, axes, minor, &minor_axis) &&
gdk_device_get_axis_value (device, axes, orientation, &orientation_axis))
{
cairo_rectangle_int_t rect;
GdkScreen *screen;
gdouble x, y;
/* FIXME: We're assuming the device is mapped to a single screen,
* could lead to stretched/shrinked shapes in multimonitor, although
* that'd be an unusual setup for touchscreens.
*/
screen = gdk_window_get_screen (event->any.window);
gdk_event_get_coords (event, &x, &y);
if (orientation_axis == 0)
{
/* Orientation is horizontal */
rect.width = (gint) gdk_screen_get_width (screen) * major_axis;
rect.height = (gint) gdk_screen_get_height (screen) * minor_axis;
}
else
{
/* Orientation is vertical */
rect.height = (gint) gdk_screen_get_height (screen) * major_axis;
rect.width = (gint) gdk_screen_get_width (screen) * minor_axis;
}
/* Something is wrong here */
if (rect.width == 0 ||
rect.height == 0)
return NULL;
rect.x = x - rect.width / 2;
rect.y = y - rect.height / 2;
return cairo_region_create_rectangle (&rect);
}
return NULL;
}
/**
* gdk_set_show_events:
* @show_events: %TRUE to output event debugging information.
+114 -5
View File
@@ -35,6 +35,7 @@
#include <gdk/gdktypes.h>
#include <gdk/gdkdnd.h>
#include <gdk/gdkdevice.h>
#include <gdk/gdktouchcluster.h>
G_BEGIN_DECLS
@@ -143,6 +144,7 @@ typedef struct _GdkEventDND GdkEventDND;
typedef struct _GdkEventWindowState GdkEventWindowState;
typedef struct _GdkEventSetting GdkEventSetting;
typedef struct _GdkEventGrabBroken GdkEventGrabBroken;
typedef struct _GdkEventMultiTouch GdkEventMultiTouch;
typedef union _GdkEvent GdkEvent;
@@ -263,6 +265,18 @@ typedef GdkFilterReturn (*GdkFilterFunc) (GdkXEvent *xevent,
* was added in 2.8.
* @GDK_DAMAGE: the content of the window has been changed. This event type
* was added in 2.14.
* @GDK_TOUCH_MOTION: A touch device has been updated. This event type was
* added in 3.4.
* @GDK_TOUCH_PRESS: A new touch stream has just started. This event type was
* added in 3.4.
* @GDK_TOUCH_RELEASE: A touch stream has finished. This event type was
* added in 3.4.
* @GDK_MULTITOUCH_ADDED: A touch ID was added to a #GdkTouchCluster. This
* event type was added in 3.4.
* @GDK_MULTITOUCH_UPDATED: A touch within a #GdkTouchCluster has been updated.
* This event type was added in 3.4.
* @GDK_MULTITOUCH_REMOVED: A touch ID was removed from a #GdkTouchCluster. This
* event type was added in 3.4.
* @GDK_EVENT_LAST: marks the end of the GdkEventType enumeration. Added in 2.18
*
* Specifies the type of the event.
@@ -310,6 +324,12 @@ typedef enum
GDK_OWNER_CHANGE = 34,
GDK_GRAB_BROKEN = 35,
GDK_DAMAGE = 36,
GDK_TOUCH_MOTION = 37,
GDK_TOUCH_PRESS = 38,
GDK_TOUCH_RELEASE = 39,
GDK_MULTITOUCH_ADDED = 40,
GDK_MULTITOUCH_UPDATED = 41,
GDK_MULTITOUCH_REMOVED = 42,
GDK_EVENT_LAST /* helper variable for decls */
} GdkEventType;
@@ -334,6 +354,8 @@ typedef enum
* @GDK_SCROLL_DOWN: the window is scrolled down.
* @GDK_SCROLL_LEFT: the window is scrolled to the left.
* @GDK_SCROLL_RIGHT: the window is scrolled to the right.
* @GDK_SCROLL_SMOOTH: the scrolling is determined by the delta values
* in #GdkEventScroll. See gdk_event_get_scroll_deltas().
*
* Specifies the direction for #GdkEventScroll.
*/
@@ -342,7 +364,8 @@ typedef enum
GDK_SCROLL_UP,
GDK_SCROLL_DOWN,
GDK_SCROLL_LEFT,
GDK_SCROLL_RIGHT
GDK_SCROLL_RIGHT,
GDK_SCROLL_SMOOTH
} GdkScrollDirection;
/**
@@ -385,6 +408,13 @@ typedef enum
* @GDK_CROSSING_GTK_UNGRAB: crossing because a GTK+ grab is deactivated.
* @GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed
* state (e.g. sensitivity).
* @GDK_CROSSING_TOUCH_PRESS: crossing because a touch device was pressed,
* this event is synthetic as the pointer might have not left the window.
* @GDK_CROSSING_TOUCH_RELEASE: crossing because a touch device was released.
* this event is synthetic as the pointer might have not left the window.
* @GDK_CROSSING_DEVICE_SWITCH: crossing because of a device switch (i.e.
* a mouse taking control of the pointer after a touch device), this event
* is synthetic as the pointer didn't leave the window.
*
* Specifies the crossing mode for #GdkEventCrossing.
*/
@@ -395,7 +425,10 @@ typedef enum
GDK_CROSSING_UNGRAB,
GDK_CROSSING_GTK_GRAB,
GDK_CROSSING_GTK_UNGRAB,
GDK_CROSSING_STATE_CHANGED
GDK_CROSSING_STATE_CHANGED,
GDK_CROSSING_TOUCH_PRESS,
GDK_CROSSING_TOUCH_RELEASE,
GDK_CROSSING_DEVICE_SWITCH
} GdkCrossingMode;
/**
@@ -552,8 +585,13 @@ struct _GdkEventVisibility
* screen.
* @y_root: the y coordinate of the pointer relative to the root of the
* screen.
* @touch_id: touch ID, only meaningful if event is of type %GDK_TOUCH_MOTION.
*
* Generated when the pointer moves.
* Generated when the pointer/touch moves.
*
* If the event has a type of %GDK_TOUCH_MOTION, this event will
* pertain to a sequence identified by gdk_event_get_touch_id().
* With multitouch devices, there may be several ongoing sequences.
*/
struct _GdkEventMotion
{
@@ -568,12 +606,63 @@ struct _GdkEventMotion
gint16 is_hint;
GdkDevice *device;
gdouble x_root, y_root;
guint touch_id;
};
/**
* GdkEventMultiTouch:
* @type: the type of the event (%GDK_MULTITOUCH_ADDED, %GDK_MULTITOUCH_UPDATED
* or %GDK_MULTITOUCH_REMOVED).
* @window: the window which received the event.
* @send_event: %TRUE if the event was sent explicitly (e.g. using
* <function>XSendEvent</function>).
* @time: the time of the event in milliseconds.
* @state: (type GdkModifierType): a bit-mask representing the state of
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
* buttons. See #GdkModifierType.
* @device: the device where the event originated.
* @group: the #GdkTouchCluster containing the touches that generated this event
* @events: an array of events of type %GDK_TOUCH_MOTION for the touches in @group
* @updated_touch_id: the touch ID that caused this event to be generated
* @n_events: the number of events in @events
* @n_updated_event: the index in @events of the event corresponding to
* @updated_touch_id, or -1 for %GDK_MULTITOUCH_REMOVED events.
*
* Used for multitouch events. The @type field will be one of
* %GDK_MULTITOUCH_ADDED, %GDK_MULTITOUCH_UPDATED or
* %GDK_MULTITOUCH_REMOVED.
*
* Multitouch events group the events from the touches in a
* #GdkTouchCluster, so one of these events is generated
* whenever a touch ID generates a new event, or a touch ID
* is added or removed.
*
* For any given touch ID, %GDK_MULTITOUCH_ADDED and
* %GDK_MULTITOUCH_REMOVED events are always paired,
* with any number of %GDK_MULTITOUCH_UPDATED
* events in between. The minimum event stream is an
* added/removed pair.
*/
struct _GdkEventMultiTouch
{
GdkEventType type;
GdkWindow *window;
gint8 send_event;
guint32 time;
guint state;
GdkDevice *device;
GdkTouchCluster *group;
GdkEventMotion **events;
guint updated_touch_id;
gint8 n_events;
gint8 n_updated_event;
};
/**
* GdkEventButton:
* @type: the type of the event (%GDK_BUTTON_PRESS, %GDK_2BUTTON_PRESS,
* %GDK_3BUTTON_PRESS or %GDK_BUTTON_RELEASE).
* %GDK_3BUTTON_PRESS, %GDK_BUTTON_RELEASE, %GDK_TOUCH_PRESS or
* %GDK_TOUCH_RELEASE).
* @window: the window which received the event.
* @send_event: %TRUE if the event was sent explicitly (e.g. using
* <function>XSendEvent</function>).
@@ -594,10 +683,13 @@ struct _GdkEventMotion
* screen.
* @y_root: the y coordinate of the pointer relative to the root of the
* screen.
* @touch_id: touch ID, only meaningful if event is of type %GDK_TOUCH_PRESS
* or %GDK_TOUCH_RELEASE.
*
* Used for button press and button release events. The
* @type field will be one of %GDK_BUTTON_PRESS,
* %GDK_2BUTTON_PRESS, %GDK_3BUTTON_PRESS, and %GDK_BUTTON_RELEASE.
* %GDK_2BUTTON_PRESS, %GDK_3BUTTON_PRESS, %GDK_BUTTON_RELEASE,
* %GDK_TOUCH_PRESS and %GDK_TOUCH_RELEASE.
*
* Double and triple-clicks result in a sequence of events being received.
* For double-clicks the order of events will be:
@@ -629,6 +721,11 @@ struct _GdkEventMotion
* For a double click to occur, the second button press must occur within
* 1/4 of a second of the first. For a triple click to occur, the third
* button press must also occur within 1/2 second of the first button press.
*
* If the event has a type of %GDK_TOUCH_PRESS or %GDK_TOUCH_RELEASE,
* this event will pertain to a sequence identified by
* gdk_event_get_touch_id(). With multitouch devices, there may be
* several ongoing sequences.
*/
struct _GdkEventButton
{
@@ -643,6 +740,7 @@ struct _GdkEventButton
guint button;
GdkDevice *device;
gdouble x_root, y_root;
guint touch_id;
};
/**
@@ -681,6 +779,8 @@ struct _GdkEventScroll
GdkScrollDirection direction;
GdkDevice *device;
gdouble x_root, y_root;
gdouble delta_x;
gdouble delta_y;
};
/**
@@ -1086,6 +1186,7 @@ union _GdkEvent
GdkEventWindowState window_state;
GdkEventSetting setting;
GdkEventGrabBroken grab_broken;
GdkEventMultiTouch multitouch;
};
GType gdk_event_get_type (void) G_GNUC_CONST;
@@ -1119,6 +1220,10 @@ gboolean gdk_event_get_keycode (const GdkEvent *event,
guint16 *keycode);
gboolean gdk_event_get_scroll_direction (const GdkEvent *event,
GdkScrollDirection *direction);
gboolean gdk_event_get_scroll_deltas (const GdkEvent *event,
gdouble *delta_x,
gdouble *delta_y);
gboolean gdk_event_get_axis (const GdkEvent *event,
GdkAxisUse axis_use,
gdouble *value);
@@ -1150,6 +1255,10 @@ void gdk_event_set_screen (GdkEvent *event,
GdkScreen *screen);
GdkScreen *gdk_event_get_screen (const GdkEvent *event);
gboolean gdk_event_get_touch_id (const GdkEvent *event,
guint *touch_id);
cairo_region_t * gdk_event_get_touch_area (GdkEvent *event);
void gdk_set_show_events (gboolean show_events);
gboolean gdk_get_show_events (void);
+20 -1
View File
@@ -150,7 +150,13 @@ typedef enum
/* Following flag is set for events on the event queue during
* translation and cleared afterwards.
*/
GDK_EVENT_PENDING = 1 << 0
GDK_EVENT_PENDING = 1 << 0,
/* The following flag is set for:
* 1) touch events emulating pointer events
* 2) pointer events being emulated by a touch sequence.
*/
GDK_EVENT_POINTER_EMULATED = 1 << 1
} GdkEventFlags;
struct _GdkEventPrivate
@@ -260,6 +266,12 @@ struct _GdkWindow
gulong device_changed_handler_id;
guint num_offscreen_children;
/* Store of latest per-touch events, keys are
* GdkDevices, values are hashtables of touchID/info
*/
GHashTable *touch_event_tracker;
GList *touch_clusters;
};
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
@@ -275,6 +287,10 @@ GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
void _gdk_event_filter_unref (GdkWindow *window,
GdkEventFilter *filter);
void _gdk_event_set_pointer_emulated (GdkEvent *event,
gboolean emulated);
gboolean _gdk_event_get_pointer_emulated (GdkEvent *event);
void _gdk_event_emit (GdkEvent *event);
GList* _gdk_event_queue_find_first (GdkDisplay *display);
void _gdk_event_queue_remove_link (GdkDisplay *display,
@@ -318,6 +334,9 @@ gboolean _gdk_window_update_viewable (GdkWindow *window);
void _gdk_window_process_updates_recurse (GdkWindow *window,
cairo_region_t *expose_region);
gboolean _gdk_window_finish_touch_id (GdkWindow *window,
GdkDevice *device,
guint touch_id);
void _gdk_screen_close (GdkScreen *screen);
+448
View File
@@ -0,0 +1,448 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2011 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gdktouchcluster.h"
#include "gdkintl.h"
/**
* SECTION:touchcluster
* @Short_description: Multitouch handling
* @Title: Multitouch
* @See_also: #GdkEventMultiTouch
*
* #GdkTouchCluster is an object that gathers touch IDs from a
* #GdkDevice, in order to send #GdkEventMultiTouch events
* whenever a touch ID that is contained in the cluster sends
* an event.
*
* #GdkTouchCluster<!-- -->s are always associated to a window,
* you need to create them through gdk_window_create_touch_cluster(),
* and free them through gdk_window_remove_touch_cluster().
*
* Touch IDs from devices can be obtained from %GDK_TOUCH_PRESS,
* %GDK_TOUCH_MOTION or %GDK_TOUCH_RELEASE events through
* gdk_event_get_touch_id(), and then be added via
* gdk_touch_cluster_add_touch(). Note that touch IDs are
* very transient, and they must be dealt with as such.
* touch IDs must not be stored after a GDK_TOUCH_RELEASE,
* and should always be retrieved from the events being
* currently received.
*
* <example>
* <title>Adding touch IDs to a cluster in a GTK+ widget</title>
* <programlisting>
* static gboolean
* widget_button_press (GtkWidget *widget,
* GdkEvent *event)
* {
* guint touch_id;
*
* if (gdk_event_get_touch_id (event, &touch_id))
* {
* /<!-- -->* It is a touch event, delegate processing
* * to the multitouch event handler
* *<!-- -->/
* gdk_touch_cluster_add_touch (priv->touch_cluster, touch_id);
* return TRUE;
* }
*
* /<!-- -->* Normal button processing *<!-- -->/
* ...
* }
* </programlisting>
* </example>
*
* Anytime a touch ID is within a cluster, no %GDK_TOUCH_PRESS,
* %GDK_TOUCH_MOTION or %GDK_TOUCH_RELEASE events will happen
* for the individual touch. The event will be available instead
* as part of the #GdkMultitouchEvent that will be emitted. This
* will hold true until gdk_touch_cluster_remove_touch() is
* called for it. Note that GTK+ will automatically take a
* touch ID out of any cluster if %GDK_TOUCH_RELEASE is gotten
* internally.
*
* <example>
* <title>Typical multitouch event handler</title>
* <programlisting>
* static gboolean
* widget_multitouch_event (GtkWidget *widget,
* GdkEvent *event)
* {
* if (event->type == GDK_MULTITOUCH_ADDED ||
* event->type == GDK_MULTITOUCH_REMOVED)
* {
* /<!-- -->* Update control mode based
* * on the current number of touches
* *<!-- -->/
* priv->control_mode = update_control_mode (event->multitouch.n_events);
* }
* else
* {
* /<!-- -->* A touch ID in the cluster has updated
* * its coordinates, update widget based on the
* * current control mode.
* *<!-- -->/
* update_view (widget, priv->control_mode,
* event->multitouch.events,
* event->multitouch.n_events);
* }
*
* return TRUE;
* }
* </programlisting>
* </example>
*/
typedef struct GdkTouchClusterPrivate GdkTouchClusterPrivate;
struct GdkTouchClusterPrivate
{
GdkDevice *device;
GArray *touches;
};
enum {
PROP_0,
PROP_DEVICE
};
enum {
TOUCH_ADDED,
TOUCH_REMOVED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0 };
static void gdk_touch_cluster_finalize (GObject *object);
static void gdk_touch_cluster_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gdk_touch_cluster_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (GdkTouchCluster, gdk_touch_cluster, G_TYPE_OBJECT)
static void
gdk_touch_cluster_class_init (GdkTouchClusterClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gdk_touch_cluster_finalize;
object_class->get_property = gdk_touch_cluster_get_property;
object_class->set_property = gdk_touch_cluster_set_property;
g_object_class_install_property (object_class,
PROP_DEVICE,
g_param_spec_object ("device",
P_("Device"),
P_("Device attached to the cluster"),
GDK_TYPE_DEVICE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
signals[TOUCH_ADDED] =
g_signal_new (g_intern_static_string ("touch-added"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GdkTouchClusterClass, touch_added),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1, G_TYPE_UINT);
signals[TOUCH_REMOVED] =
g_signal_new (g_intern_static_string ("touch-removed"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GdkTouchClusterClass, touch_removed),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1, G_TYPE_UINT);
g_type_class_add_private (object_class, sizeof (GdkTouchClusterPrivate));
}
static void
gdk_touch_cluster_init (GdkTouchCluster *cluster)
{
GdkTouchClusterPrivate *priv;
priv = cluster->priv = G_TYPE_INSTANCE_GET_PRIVATE (cluster,
GDK_TYPE_TOUCH_CLUSTER,
GdkTouchClusterPrivate);
priv->touches = g_array_new (FALSE, FALSE, sizeof (guint));
}
static void
gdk_touch_cluster_finalize (GObject *object)
{
GdkTouchClusterPrivate *priv;
priv = GDK_TOUCH_CLUSTER (object)->priv;
g_array_free (priv->touches, TRUE);
G_OBJECT_CLASS (gdk_touch_cluster_parent_class)->finalize (object);
}
static void
gdk_touch_cluster_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_DEVICE:
gdk_touch_cluster_set_device (GDK_TOUCH_CLUSTER (object),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdk_touch_cluster_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkTouchClusterPrivate *priv;
priv = GDK_TOUCH_CLUSTER (object)->priv;
switch (prop_id)
{
case PROP_DEVICE:
g_value_set_object (value, priv->device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* gdk_touch_cluster_add_touch:
* @cluster: a #GdkTouchCluster
* @touch_id: a touch ID from a touch event
*
* Adds a touch ID to @cluster, so it will generate a
* %GDK_MULTITOUCH_ADDED event, followed by %GDK_MULTITOUCH_UPDATED
* events whenever this touch ID is updated.
*
* If @touch_id already pertained to another #GdkTouchCluster, it
* will be removed from it, generating a %GDK_MULTITOUCH_REMOVED
* for that another cluster.
*
* Since: 3.4
**/
void
gdk_touch_cluster_add_touch (GdkTouchCluster *cluster,
guint touch_id)
{
GdkTouchClusterPrivate *priv;
gint i;
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
priv = cluster->priv;
for (i = 0; i < priv->touches->len; i++)
{
if (touch_id == g_array_index (priv->touches, guint, i))
return;
}
g_array_append_val (priv->touches, touch_id);
g_signal_emit (cluster, signals [TOUCH_ADDED], 0, touch_id);
}
/**
* gdk_touch_cluster_remove_touch:
* @cluster: a #GdkTouchCluster
* @touch_id: a touch ID from a touch event
*
* Removes a touch ID from @cluster, generating a %GDK_MULTITOUCH_REMOVED
* event for @cluster, and causing any further input from @touch_id
* to be reported trough %GDK_TOUCH_MOTION events.
*
* <note><para>
* Note that GTK+ automatically removes a touch ID from any cluster
* if a %GDK_TOUCH_RELEASE event is gotten internally.
* </para></note>
*
* Since: 3.4
**/
void
gdk_touch_cluster_remove_touch (GdkTouchCluster *cluster,
guint touch_id)
{
GdkTouchClusterPrivate *priv;
gint i;
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
priv = cluster->priv;
for (i = 0; i < priv->touches->len; i++)
{
if (touch_id == g_array_index (priv->touches, guint, i))
{
g_array_remove_index_fast (priv->touches, i);
g_signal_emit (cluster, signals [TOUCH_REMOVED], 0, touch_id);
return;
}
}
}
/**
* gdk_touch_cluster_remove_all:
* @cluster: a #GdkTouchCluster
*
* Removes all touch IDs from @cluster.
*
* Since: 3.4
**/
void
gdk_touch_cluster_remove_all (GdkTouchCluster *cluster)
{
GdkTouchClusterPrivate *priv;
guint touch_id;
gint i;
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
priv = cluster->priv;
for (i = priv->touches->len - 1; i >= 0; i--)
{
touch_id = g_array_index (priv->touches, guint, i);
g_signal_emit (cluster, signals [TOUCH_REMOVED], 0, touch_id);
g_array_remove_index_fast (priv->touches, i);
}
}
/**
* gdk_touch_cluster_get_touches:
* @cluster: a #GdkTouchCluster
* @length: return location for the number of touches returned
*
* Returns the list of touches as an array of @guint.
*
* Returns: (transfer full) (array zero-terminated=0 length=length) (element-type uint): A list of touch IDs.
*
* Since: 3.4
**/
guint *
gdk_touch_cluster_get_touches (GdkTouchCluster *cluster,
gint *len)
{
GdkTouchClusterPrivate *priv;
g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), NULL);
priv = cluster->priv;
if (len)
*len = (gint) priv->touches->len;
return g_memdup (priv->touches->data,
sizeof (guint) * priv->touches->len);
}
/**
* gdk_touch_cluster_get_n_touches:
* @cluster: a #GdkTouchCluster
*
* Returns the number of touches contained in @cluster.
*
* Returns: The number of touches.
*
* Since: 3.4
**/
gint
gdk_touch_cluster_get_n_touches (GdkTouchCluster *cluster)
{
GdkTouchClusterPrivate *priv;
g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), 0);
priv = cluster->priv;
return (gint) priv->touches->len;
}
/**
* gdk_touch_cluster_set_device:
* @cluster: a #GdkTouchCluster
* @device: a #GdkDevice
*
* Sets the current device associated to @cluster, all contained
* touch IDs must pertain to this device. As a consequence,
* gdk_touch_cluster_remove_all() will be called on @cluster
* if the current device changes.
*
* Since: 3.4
**/
void
gdk_touch_cluster_set_device (GdkTouchCluster *cluster,
GdkDevice *device)
{
GdkTouchClusterPrivate *priv;
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
g_return_if_fail (!device || GDK_IS_DEVICE (device));
priv = cluster->priv;
if (priv->device != device)
gdk_touch_cluster_remove_all (cluster);
priv->device = device;
}
/**
* gdk_touch_cluster_get_device:
* @cluster: a #GdkTouchCluster
*
* Returns the slave/floating device this touch cluster pertains to,
* only touch IDs from this device can be included in @cluster.
* the #GdkDevice will typically have the %GDK_SOURCE_TOUCH input source.
*
* Returns: (transfer none): The #GdkDevice generating the contained touch IDs
*
* Since: 3.4
**/
GdkDevice *
gdk_touch_cluster_get_device (GdkTouchCluster *cluster)
{
GdkTouchClusterPrivate *priv;
g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), NULL);
priv = cluster->priv;
return priv->device;
}
+71
View File
@@ -0,0 +1,71 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2011 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GDK_TOUCH_CLUSTER_H__
#define __GDK_TOUCH_CLUSTER_H__
#include <glib-object.h>
#include <gdk/gdkdevice.h>
G_BEGIN_DECLS
#define GDK_TYPE_TOUCH_CLUSTER (gdk_touch_cluster_get_type ())
#define GDK_TOUCH_CLUSTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_TOUCH_CLUSTER, GdkTouchCluster))
#define GDK_IS_TOUCH_CLUSTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_TOUCH_CLUSTER))
typedef struct _GdkTouchCluster GdkTouchCluster;
typedef struct _GdkTouchClusterClass GdkTouchClusterClass;
struct _GdkTouchCluster
{
GObject parent_instance;
gpointer priv;
};
struct _GdkTouchClusterClass
{
GObjectClass parent_class;
void (* touch_added) (GdkTouchCluster *cluster,
guint touch_id);
void (* touch_removed) (GdkTouchCluster *cluster,
guint touch_id);
gpointer padding[16];
};
GType gdk_touch_cluster_get_type (void) G_GNUC_CONST;
void gdk_touch_cluster_add_touch (GdkTouchCluster *cluster,
guint touch_id);
void gdk_touch_cluster_remove_touch (GdkTouchCluster *cluster,
guint touch_id);
void gdk_touch_cluster_remove_all (GdkTouchCluster *cluster);
guint * gdk_touch_cluster_get_touches (GdkTouchCluster *cluster,
gint *length);
gint gdk_touch_cluster_get_n_touches (GdkTouchCluster *cluster);
void gdk_touch_cluster_set_device (GdkTouchCluster *cluster,
GdkDevice *device);
GdkDevice * gdk_touch_cluster_get_device (GdkTouchCluster *cluster);
G_END_DECLS
#endif /* __GDK_TOUCH_CLUSTER_H__ */
+12 -1
View File
@@ -350,6 +350,8 @@ typedef enum
* @GDK_SUBSTRUCTURE_MASK: receive events about window configuration changes of
* child windows
* @GDK_SCROLL_MASK: receive scroll events
* @GDK_TOUCH_MASK: receive (multi)touch events
* @GDK_SMOOTH_SCROLL_MASK: receive smooth scrolling events
* @GDK_ALL_EVENTS_MASK: the combination of all the above event masks.
*
* A set of bit-flags to indicate which events a window is to receive.
@@ -365,6 +367,13 @@ typedef enum
* some of which are marked as a hint (the is_hint member is %TRUE).
* To receive more motion events after a motion hint event, the application
* needs to asks for more, by calling gdk_event_request_motions().
*
* If %GDK_TOUCH_MASK is enabled, the window will receive (multi)touch events
* from touch-enabled devices. Those will come as sequences #GdkEventMotion
* with type %GDK_TOUCH_MOTION, enclosed by 2 #GdkEventButton events with
* type %GDK_TOUCH_PRESS / %GDK_TOUCH_RELEASE. gdk_event_get_touch_id() will
* return the touch ID on those events, so different sequences may be
* distinguished.
*/
typedef enum
{
@@ -389,7 +398,9 @@ typedef enum
GDK_PROXIMITY_OUT_MASK = 1 << 19,
GDK_SUBSTRUCTURE_MASK = 1 << 20,
GDK_SCROLL_MASK = 1 << 21,
GDK_ALL_EVENTS_MASK = 0x3FFFFE
GDK_TOUCH_MASK = 1 << 22,
GDK_SMOOTH_SCROLL_MASK = 1 << 23,
GDK_ALL_EVENTS_MASK = 0x7FFFFF
} GdkEventMask;
/**
+733 -75
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -33,6 +33,7 @@
#include <gdk/gdktypes.h>
#include <gdk/gdkevents.h>
#include <gdk/gdktouchcluster.h>
G_BEGIN_DECLS
@@ -878,6 +879,12 @@ void gdk_window_set_support_multidevice (GdkWindow *window,
gboolean support_multidevice);
gboolean gdk_window_get_support_multidevice (GdkWindow *window);
/* Multitouch support */
GdkTouchCluster * gdk_window_create_touch_cluster (GdkWindow *window,
GdkDevice *device);
void gdk_window_remove_touch_cluster (GdkWindow *window,
GdkTouchCluster *cluster);
G_END_DECLS
#endif /* __GDK_WINDOW_H__ */
+48 -8
View File
@@ -870,6 +870,8 @@ fill_scroll_event (GdkWindow *window,
gint y,
gint x_root,
gint y_root,
gdouble delta_x,
gdouble delta_y,
GdkScrollDirection direction)
{
NSPoint point;
@@ -886,6 +888,8 @@ fill_scroll_event (GdkWindow *window,
event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
event->scroll.direction = direction;
event->scroll.device = _gdk_display->core_pointer;
event->scroll.delta_x = delta_x;
event->scroll.delta_y = delta_y;
}
static void
@@ -1320,28 +1324,64 @@ gdk_event_translate (GdkEvent *event,
case NSScrollWheel:
{
float dx = [nsevent deltaX];
float dy = [nsevent deltaY];
GdkScrollDirection direction;
GdkScrollDirection direction;
float dx;
float dy;
if (dy != 0)
if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
[nsevent hasPreciseScrollingDeltas])
{
dx = [nsevent scrollingDeltaX];
dy = [nsevent scrollingDeltaY];
direction = GDK_SCROLL_SMOOTH;
fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
-dx, -dy, direction);
/* Fall through for scroll buttons emulation */
}
dx = [nsevent deltaX];
dy = [nsevent deltaY];
if (dy != 0.0)
{
if (dy < 0.0)
direction = GDK_SCROLL_DOWN;
else
direction = GDK_SCROLL_UP;
fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
dy = fabs (dy);
dx = 0.0;
}
if (dx != 0)
else if (dx != 0.0)
{
if (dx < 0.0)
direction = GDK_SCROLL_RIGHT;
else
direction = GDK_SCROLL_LEFT;
fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
dx = fabs (dx);
dy = 0.0;
}
if (dx != 0.0 || dy != 0.0)
{
if ([nsevent hasPreciseScrollingDeltas])
{
GdkEvent *emulated_event;
emulated_event = gdk_event_new (GDK_SCROLL);
_gdk_event_set_pointer_emulated (emulated_event, TRUE);
fill_scroll_event (window, emulated_event, nsevent,
x, y, x_root, y_root,
dx, dy, direction);
append_event (emulated_event, TRUE);
}
else
fill_scroll_event (window, event, nsevent,
x, y, x_root, y_root,
dx, dy, direction);
}
}
break;
+2
View File
@@ -7,6 +7,8 @@ libgdkx11includedir = $(includedir)/gtk-3.0/gdk/x11
AM_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Gdk\" \
-DGDK_COMPILATION \
-DXINPUT2_2_USE_UNSTABLE_PROTOCOL \
-DXINPUT2_1_USE_UNSTABLE_PROTOCOL \
-I$(top_srcdir) \
-I$(top_srcdir)/gdk \
-I$(top_builddir)/gdk \
+130 -5
View File
@@ -35,11 +35,21 @@
#endif
typedef struct _ScrollValuator ScrollValuator;
struct _ScrollValuator
{
guint n_valuator : 4;
guint direction : 4;
gdouble last_value;
};
struct _GdkX11DeviceXI2
{
GdkDevice parent_instance;
gint device_id;
GArray *scroll_valuators;
};
struct _GdkX11DeviceXI2Class
@@ -51,6 +61,7 @@ G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
#ifdef XINPUT_2
static void gdk_x11_device_xi2_finalize (GObject *object);
static void gdk_x11_device_xi2_get_property (GObject *object,
guint prop_id,
GValue *value,
@@ -112,6 +123,7 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
object_class->finalize = gdk_x11_device_xi2_finalize;
object_class->get_property = gdk_x11_device_xi2_get_property;
object_class->set_property = gdk_x11_device_xi2_set_property;
@@ -136,6 +148,17 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
static void
gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
{
device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
}
static void
gdk_x11_device_xi2_finalize (GObject *object)
{
GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
g_array_free (device->scroll_valuators, TRUE);
G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
}
static void
@@ -388,6 +411,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
guint32 time_)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkX11DeviceManagerXI2 *device_manager_xi2;
GdkDisplay *display;
XIEventMask mask;
Window xwindow;
@@ -395,6 +419,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
gint status;
display = gdk_device_get_display (device);
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
/* FIXME: confine_to is actually unused */
@@ -409,7 +434,9 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
}
mask.deviceid = device_xi2->device_id;
mask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
event_mask,
&mask.mask_len);
#ifdef G_ENABLE_DEBUG
if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
@@ -625,10 +652,17 @@ gdk_x11_device_xi2_select_window_events (GdkDevice *device,
GdkEventMask event_mask)
{
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
GdkX11DeviceManagerXI2 *device_manager_xi2;
GdkDisplay *display;
XIEventMask evmask;
display = gdk_device_get_display (device);
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
evmask.deviceid = device_xi2->device_id;
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
event_mask,
&evmask.mask_len);
XISelectEvents (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
@@ -638,10 +672,14 @@ gdk_x11_device_xi2_select_window_events (GdkDevice *device,
}
guchar *
_gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
gint *len)
_gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
GdkEventMask event_mask,
gint *len)
{
guchar *mask;
gint minor;
g_object_get (device_manager_xi2, "minor", &minor, NULL);
*len = XIMaskLen (XI_LASTEVENT);
mask = g_new0 (guchar, *len);
@@ -690,6 +728,17 @@ _gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
XISetMask (mask, XI_FocusOut);
}
#ifdef XINPUT_2_2
/* XInput 2.2 includes multitouch support */
if (minor >= 2 &&
event_mask & GDK_TOUCH_MASK)
{
XISetMask (mask, XI_TouchBegin);
XISetMask (mask, XI_TouchUpdate);
XISetMask (mask, XI_TouchEnd);
}
#endif /* XINPUT_2_2 */
return mask;
}
@@ -742,7 +791,7 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
{
gint group;
group = group_state->base + group_state->latched + group_state->locked;
group = group_state->base | group_state->latched | group_state->locked;
/* FIXME: do we need the XKB complications for this ? */
group = CLAMP(group, 0, 3);
@@ -753,6 +802,82 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
return state;
}
void
_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
guint n_valuator,
GdkScrollDirection direction,
gdouble current_value)
{
ScrollValuator scroll;
g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
scroll.n_valuator = n_valuator;
scroll.direction = direction;
scroll.last_value = current_value;
g_array_append_val (device->scroll_valuators, scroll);
}
gboolean
_gdk_x11_device_xi2_is_scroll_valuator (GdkX11DeviceXI2 *device,
guint n_valuator,
GdkScrollDirection *direction)
{
guint i;
g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
for (i = 0; i < device->scroll_valuators->len; i++)
{
ScrollValuator *scroll;
scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
if (scroll->n_valuator == n_valuator)
{
if (*direction)
*direction = scroll->direction;
return TRUE;
}
}
return FALSE;
}
gdouble
_gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2 *device,
guint n_valuator,
gdouble valuator_value)
{
guint i;
g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), 0);
g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), 0);
for (i = 0; i < device->scroll_valuators->len; i++)
{
ScrollValuator *scroll;
scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
if (scroll->n_valuator == n_valuator)
{
gdouble delta;
delta = valuator_value - scroll->last_value;
scroll->last_value = valuator_value;
return delta;
}
}
return 0;
}
gint
_gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
{
+3
View File
@@ -471,6 +471,9 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
event->scroll.state = (GdkModifierType) xevent->xbutton.state;
event->scroll.device = device_manager->core_pointer;
event->scroll.delta_x = 0;
event->scroll.delta_y = 0;
if (!set_screen_from_root (display, event, xevent->xbutton.root))
{
return_val = FALSE;
+6
View File
@@ -54,7 +54,11 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
int major, minor;
major = 2;
#ifdef XINPUT_2_2
minor = 2;
#else
minor = 0;
#endif /* XINPUT_2_2 */
if (!_gdk_disable_multidevice &&
XIQueryVersion (xdisplay, &major, &minor) != BadRequest)
@@ -66,6 +70,8 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
device_manager_xi2 = g_object_new (GDK_TYPE_X11_DEVICE_MANAGER_XI2,
"display", display,
"opcode", opcode,
"major", major,
"minor", minor,
NULL);
return GDK_DEVICE_MANAGER (device_manager_xi2);
+266 -63
View File
@@ -29,6 +29,7 @@
#include "gdkprivate-x11.h"
#include "gdkintl.h"
#include "gdkkeysyms.h"
#include "gdkinternals.h"
#ifdef XINPUT_2
@@ -49,6 +50,8 @@ struct _GdkX11DeviceManagerXI2
GList *devices;
gint opcode;
gint major;
gint minor;
};
struct _GdkX11DeviceManagerXI2Class
@@ -96,7 +99,9 @@ static GdkWindow * gdk_x11_device_manager_xi2_get_window (GdkEventTra
enum {
PROP_0,
PROP_OPCODE
PROP_OPCODE,
PROP_MAJOR,
PROP_MINOR
};
static void
@@ -120,6 +125,20 @@ gdk_x11_device_manager_xi2_class_init (GdkX11DeviceManagerXI2Class *klass)
P_("Opcode for XInput2 requests"),
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_MAJOR,
g_param_spec_int ("major",
P_("Major"),
P_("Major version number"),
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_MINOR,
g_param_spec_int ("minor",
P_("Minor"),
P_("Minor version number"),
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
@@ -148,8 +167,10 @@ _gdk_x11_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
static void
translate_valuator_class (GdkDisplay *display,
GdkDevice *device,
XIValuatorClassInfo *info,
gint n_valuator)
Atom valuator_label,
gdouble min,
gdouble max,
gdouble resolution)
{
static gboolean initialized = FALSE;
static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
@@ -170,24 +191,19 @@ translate_valuator_class (GdkDisplay *display,
for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
{
if (label_atoms[i] == info->label)
if (label_atoms[i] == valuator_label)
{
use = i;
break;
}
}
if (info->label != None)
label = gdk_x11_xatom_to_atom_for_display (display, info->label);
if (valuator_label != None)
label = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
else
label = GDK_NONE;
_gdk_device_add_axis (device,
label,
use,
info->min,
info->max,
info->resolution);
_gdk_device_add_axis (device, label, use, min, max, resolution);
}
static void
@@ -196,7 +212,7 @@ translate_device_classes (GdkDisplay *display,
XIAnyClassInfo **classes,
guint n_classes)
{
gint i, n_valuator = 0;
gint i;
g_object_freeze_notify (G_OBJECT (device));
@@ -218,11 +234,41 @@ translate_device_classes (GdkDisplay *display,
}
break;
case XIValuatorClass:
translate_valuator_class (display, device,
(XIValuatorClassInfo *) class_info,
n_valuator);
n_valuator++;
{
XIValuatorClassInfo *valuator_info = (XIValuatorClassInfo *) class_info;
translate_valuator_class (display, device,
valuator_info->label,
valuator_info->min,
valuator_info->max,
valuator_info->resolution);
}
break;
#ifdef XINPUT_2_2
case XIScrollClass:
{
XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
XIValuatorClassInfo *scroll_valuator_info = NULL;
GdkScrollDirection direction;
gint j;
for (j = 0; j < n_classes; j++)
{
if (classes[j]->type == XIValuatorClass &&
((XIValuatorClassInfo *) classes[j])->number == scroll_info->number)
scroll_valuator_info = (XIValuatorClassInfo *) classes[j];
}
if (scroll_info->scroll_type == XIScrollTypeVertical)
direction = GDK_SCROLL_DOWN;
else
direction = GDK_SCROLL_RIGHT;
_gdk_x11_device_xi2_add_scroll_valuator (GDK_X11_DEVICE_XI2 (device),
scroll_info->number,
direction,
scroll_valuator_info->value);
}
#endif /* XINPUT_2_2 */
default:
/* Ignore */
break;
@@ -232,6 +278,27 @@ translate_device_classes (GdkDisplay *display,
g_object_thaw_notify (G_OBJECT (device));
}
static gint
count_device_touches (XIAnyClassInfo **classes,
guint n_classes)
{
#ifdef XINPUT_2_2
guint i;
for (i = 0; i < n_classes; i++)
{
XITouchClassInfo *valuator_info = (XITouchClassInfo *) classes[i];
if (valuator_info->type != XITouchClass)
continue;
return valuator_info->num_touches;
}
#endif
return 0;
}
static GdkDevice *
create_device (GdkDeviceManager *device_manager,
GdkDisplay *display,
@@ -244,6 +311,9 @@ create_device (GdkDeviceManager *device_manager,
if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
input_source = GDK_SOURCE_KEYBOARD;
else if (dev->use == XISlavePointer &&
count_device_touches (dev->classes, dev->num_classes) > 0)
input_source = GDK_SOURCE_TOUCH;
else
{
gchar *tmp_name;
@@ -254,6 +324,10 @@ create_device (GdkDeviceManager *device_manager,
input_source = GDK_SOURCE_ERASER;
else if (strstr (tmp_name, "cursor"))
input_source = GDK_SOURCE_CURSOR;
else if (strstr (tmp_name, "finger") ||
(strstr (tmp_name, "touch") &&
!strstr (tmp_name, "touchpad")))
input_source = GDK_SOURCE_TOUCH;
else if (strstr (tmp_name, "wacom") ||
strstr (tmp_name, "pen"))
input_source = GDK_SOURCE_PEN;
@@ -408,6 +482,8 @@ gdk_x11_device_manager_xi2_constructed (GObject *object)
display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
xdisplay = GDK_DISPLAY_XDISPLAY (display);
g_assert (device_manager->major == 2);
masters = g_hash_table_new (NULL, NULL);
slaves = g_hash_table_new (NULL, NULL);
@@ -533,6 +609,12 @@ gdk_x11_device_manager_xi2_set_property (GObject *object,
case PROP_OPCODE:
device_manager->opcode = g_value_get_int (value);
break;
case PROP_MAJOR:
device_manager->major = g_value_get_int (value);
break;
case PROP_MINOR:
device_manager->minor = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -554,6 +636,12 @@ gdk_x11_device_manager_xi2_get_property (GObject *object,
case PROP_OPCODE:
g_value_set_int (value, device_manager->opcode);
break;
case PROP_MAJOR:
g_value_set_int (value, device_manager->major);
break;
case PROP_MINOR:
g_value_set_int (value, device_manager->minor);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -823,6 +911,11 @@ get_event_window (GdkEventTranslator *translator,
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_Motion:
#ifdef XINPUT_2_2
case XI_TouchUpdate:
case XI_TouchBegin:
case XI_TouchEnd:
#endif /* XINPUT_2_2 */
{
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
@@ -941,6 +1034,47 @@ gdk_x11_device_manager_xi2_translate_core_event (GdkEventTranslator *translator,
return TRUE;
}
static gboolean
scroll_valuators_changed (GdkX11DeviceXI2 *device,
XIValuatorState *valuators,
gdouble *dx,
gdouble *dy)
{
gdouble has_scroll_valuators = FALSE;
GdkScrollDirection direction;
guint n_axes, i, n_val;
gdouble *vals;
n_axes = gdk_device_get_n_axes (GDK_DEVICE (device));
vals = valuators->values;
*dx = *dy = 0;
n_val = 0;
for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
{
if (!XIMaskIsSet (valuators->mask, i))
continue;
if (_gdk_x11_device_xi2_is_scroll_valuator (device, i, &direction))
{
gdouble delta;
has_scroll_valuators = TRUE;
delta = _gdk_x11_device_xi2_get_scroll_delta (device, i, vals[n_val]);
if (direction == GDK_SCROLL_UP ||
direction == GDK_SCROLL_DOWN)
*dy = delta;
else
*dx = delta;
}
n_val++;
}
return has_scroll_valuators;
}
static gboolean
gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
GdkDisplay *display,
@@ -1043,56 +1177,60 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
break;
case XI_ButtonPress:
case XI_ButtonRelease:
#ifdef XINPUT_2_2
case XI_TouchBegin:
case XI_TouchEnd:
#endif /* XINPUT_2_2 */
{
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
GdkDevice *source_device;
switch (xev->detail)
if (ev->evtype == XI_ButtonPress &&
(xev->detail >= 4 && xev->detail <= 7))
{
case 4:
case 5:
case 6:
case 7:
/* Button presses of button 4-7 are scroll events */
if (ev->evtype == XI_ButtonPress)
{
event->scroll.type = GDK_SCROLL;
/* Button presses of button 4-7 are scroll events */
event->scroll.type = GDK_SCROLL;
if (xev->detail == 4)
event->scroll.direction = GDK_SCROLL_UP;
else if (xev->detail == 5)
event->scroll.direction = GDK_SCROLL_DOWN;
else if (xev->detail == 6)
event->scroll.direction = GDK_SCROLL_LEFT;
else
event->scroll.direction = GDK_SCROLL_RIGHT;
if (xev->detail == 4)
event->scroll.direction = GDK_SCROLL_UP;
else if (xev->detail == 5)
event->scroll.direction = GDK_SCROLL_DOWN;
else if (xev->detail == 6)
event->scroll.direction = GDK_SCROLL_LEFT;
else
event->scroll.direction = GDK_SCROLL_RIGHT;
event->scroll.window = window;
event->scroll.time = xev->time;
event->scroll.x = (gdouble) xev->event_x;
event->scroll.y = (gdouble) xev->event_y;
event->scroll.x_root = (gdouble) xev->root_x;
event->scroll.y_root = (gdouble) xev->root_y;
event->scroll.window = window;
event->scroll.time = xev->time;
event->scroll.x = (gdouble) xev->event_x;
event->scroll.y = (gdouble) xev->event_y;
event->scroll.x_root = (gdouble) xev->root_x;
event->scroll.y_root = (gdouble) xev->root_y;
event->scroll.delta_x = 0;
event->scroll.delta_y = 0;
event->scroll.device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->deviceid));
event->scroll.device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->deviceid));
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
break;
}
/* Button presses of button 4-7 are scroll events, so ignore the release */
else if (ev->evtype == XI_ButtonRelease)
{
return_val = FALSE;
break;
}
/* else (XI_ButtonRelease) fall thru */
default:
event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
if (xev->flags & XIPointerEmulated)
_gdk_event_set_pointer_emulated (event, TRUE);
}
else
{
#ifdef XINPUT_2_2
if (ev->evtype == XI_TouchBegin)
event->button.type = GDK_TOUCH_PRESS;
else if (ev->evtype == XI_TouchEnd)
event->button.type = GDK_TOUCH_RELEASE;
else
#endif /* XINPUT_2_2 */
event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
event->button.window = window;
event->button.time = xev->time;
@@ -1124,9 +1262,25 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
}
event->button.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
event->button.button = xev->detail;
if (ev->evtype == XI_TouchBegin)
event->button.state |= GDK_BUTTON1_MASK;
#ifdef XINPUT_2_2
if (ev->evtype == XI_TouchBegin ||
ev->evtype == XI_TouchEnd)
{
event->button.button = 1;
event->button.touch_id = xev->detail;
}
else
#endif /* XINPUT_2_2 */
event->button.button = xev->detail;
}
if (xev->flags & (XIPointerEmulated | XITouchEmulatingPointer))
_gdk_event_set_pointer_emulated (event, TRUE);
if (return_val == FALSE)
break;
@@ -1142,11 +1296,53 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
break;
}
case XI_Motion:
#ifdef XINPUT_2_2
case XI_TouchUpdate:
#endif /* XINPUT_2_2 */
{
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
GdkDevice *source_device;
gdouble delta_x, delta_y;
event->motion.type = GDK_MOTION_NOTIFY;
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
if (scroll_valuators_changed (GDK_X11_DEVICE_XI2 (source_device),
&xev->valuators, &delta_x, &delta_y))
{
event->scroll.type = GDK_SCROLL;
event->scroll.direction = GDK_SCROLL_SMOOTH;
event->scroll.window = window;
event->scroll.time = xev->time;
event->scroll.x = (gdouble) xev->event_x;
event->scroll.y = (gdouble) xev->event_y;
event->scroll.x_root = (gdouble) xev->root_x;
event->scroll.y_root = (gdouble) xev->root_y;
event->scroll.delta_x = delta_x;
event->scroll.delta_y = delta_y;
event->scroll.device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->deviceid));
gdk_event_set_source_device (event, source_device);
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
break;
}
if (ev->evtype == XI_Motion)
{
event->motion.touch_id = 0;
event->motion.type = GDK_MOTION_NOTIFY;
}
#ifdef XINPUT_2_2
else
{
event->motion.touch_id = xev->detail;
event->motion.type = GDK_TOUCH_MOTION;
}
#endif
event->motion.window = window;
@@ -1159,12 +1355,16 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
event->motion.device = g_hash_table_lookup (device_manager->id_table,
GINT_TO_POINTER (xev->deviceid));
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
if (ev->evtype == XI_TouchUpdate)
event->motion.state |= GDK_BUTTON1_MASK;
if (xev->flags & (XIPointerEmulated | XITouchEmulatingPointer))
_gdk_event_set_pointer_emulated (event, TRUE);
/* There doesn't seem to be motion hints in XI */
event->motion.is_hint = FALSE;
@@ -1280,7 +1480,8 @@ gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
GDK_BUTTON2_MOTION_MASK |
GDK_BUTTON3_MOTION_MASK |
GDK_BUTTON_MOTION_MASK |
GDK_FOCUS_CHANGE_MASK);
GDK_FOCUS_CHANGE_MASK |
GDK_TOUCH_MASK);
}
static void
@@ -1294,7 +1495,9 @@ gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
device_manager = GDK_DEVICE_MANAGER (translator);
event_mask.deviceid = XIAllMasterDevices;
event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (evmask, &event_mask.mask_len);
event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (GDK_X11_DEVICE_MANAGER_XI2 (device_manager),
evmask,
&event_mask.mask_len);
_gdk_x11_device_manager_xi2_select_events (device_manager, window, &event_mask);
g_free (event_mask.mask);
+4 -1
View File
@@ -1579,9 +1579,12 @@ device_grab_update_callback (GdkDisplay *display,
gpointer data,
gulong serial)
{
GdkPointerWindowInfo *pointer_info;
GdkDevice *device = data;
_gdk_display_device_grab_update (display, device, NULL, serial);
pointer_info = _gdk_display_get_pointer_info (display, device);
_gdk_display_device_grab_update (display, device,
pointer_info->last_slave, serial);
}
#define XSERVER_TIME_IS_LATER(time1, time2) \
+13 -2
View File
@@ -247,8 +247,9 @@ void _gdk_x11_device_xi_translate_axes (GdkDevice *device,
#endif
#ifdef XINPUT_2
guchar * _gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
gint *len);
guchar * _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
GdkEventMask event_mask,
gint *len);
guint _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
XIButtonState *buttons_state,
XIGroupState *group_state);
@@ -256,6 +257,16 @@ gint _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device);
GdkDevice * _gdk_x11_device_manager_xi2_lookup (GdkX11DeviceManagerXI2 *device_manager_xi2,
gint device_id);
void _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
guint n_valuator,
GdkScrollDirection direction,
gdouble current_value);
gboolean _gdk_x11_device_xi2_is_scroll_valuator (GdkX11DeviceXI2 *device,
guint n_valuator,
GdkScrollDirection *direction);
gdouble _gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2 *device,
guint n_valuator,
gdouble valuator_value);
#endif
+29 -9
View File
@@ -145,6 +145,8 @@ endif
# by configure)
deprecated_h_sources = \
deprecated/gtkcolorsel.h \
deprecated/gtkcolorseldialog.h \
deprecated/gtkfontsel.h \
deprecated/gtkhandlebox.h \
deprecated/gtkhbbox.h \
@@ -153,6 +155,7 @@ deprecated_h_sources = \
deprecated/gtkhscale.h \
deprecated/gtkhscrollbar.h \
deprecated/gtkhseparator.h \
deprecated/gtkhsv.h \
deprecated/gtkstyle.h \
deprecated/gtkrc.h \
deprecated/gtktable.h \
@@ -215,8 +218,10 @@ gtk_public_h_sources = \
gtkcheckmenuitem.h \
gtkclipboard.h \
gtkcolorbutton.h \
gtkcolorsel.h \
gtkcolorseldialog.h \
gtkcolorchooser.h \
gtkcolorchooserwidget.h \
gtkcolorchooserdialog.h \
gtkcolorutils.h \
gtkcombobox.h \
gtkcomboboxtext.h \
gtkcontainer.h \
@@ -244,9 +249,9 @@ gtk_public_h_sources = \
gtkfontchooserdialog.h \
gtkfontchooserwidget.h \
gtkframe.h \
gtkgesturesinterpreter.h \
gtkgradient.h \
gtkgrid.h \
gtkhsv.h \
gtkiconfactory.h \
gtkicontheme.h \
gtkiconview.h \
@@ -410,6 +415,11 @@ gtk_private_h_sources = \
gtkbuilderprivate.h \
gtkbuttonprivate.h \
gtkcellareaboxcontextprivate.h \
gtkcolorswatchprivate.h \
gtkcoloreditorprivate.h \
gtkcolorplaneprivate.h \
gtkcolorscaleprivate.h \
gtkcolorchooserprivate.h \
gtkcontainerprivate.h \
gtkcsscomputedvaluesprivate.h \
gtkcsscustompropertyprivate.h \
@@ -506,6 +516,8 @@ gtk_private_h_sources = \
# GTK+ C sources to build the library from
deprecated_c_sources = \
deprecated/gtkcolorsel.c \
deprecated/gtkcolorseldialog.c \
deprecated/gtkfontsel.c \
deprecated/gtkhandlebox.c \
deprecated/gtkhbbox.c \
@@ -514,6 +526,7 @@ deprecated_c_sources = \
deprecated/gtkhscale.c \
deprecated/gtkhscrollbar.c \
deprecated/gtkhseparator.c \
deprecated/gtkhsv.c \
deprecated/gtkrc.c \
deprecated/gtkstyle.c \
deprecated/gtktable.c \
@@ -590,8 +603,14 @@ gtk_base_c_sources = \
gtkcheckbutton.c \
gtkcheckmenuitem.c \
gtkcolorbutton.c \
gtkcolorsel.c \
gtkcolorseldialog.c \
gtkcolorchooser.c \
gtkcolorchooserwidget.c \
gtkcolorchooserdialog.c \
gtkcoloreditor.c \
gtkcolorplane.c \
gtkcolorscale.c \
gtkcolorswatch.c \
gtkcolorutils.c \
gtkcombobox.c \
gtkcomboboxtext.c \
gtkcontainer.c \
@@ -639,9 +658,9 @@ gtk_base_c_sources = \
gtkfontchooserutils.c \
gtkfontchooserwidget.c \
gtkframe.c \
gtkgesturesinterpreter.c \
gtkgradient.c \
gtkgrid.c \
gtkhsv.c \
gtkiconcache.c \
gtkiconcachevalidator.c \
gtkiconfactory.c \
@@ -1549,7 +1568,6 @@ EXTRA_DIST += \
gtkprint-win32.h \
gtkprint-win32.c \
gtksearchenginequartz.h \
gtk.css.raleigh \
gtk.gresource.xml \
gtk-default.css \
gtk-keys.css.default \
@@ -1562,10 +1580,12 @@ EXTRA_DIST += \
gtktypebuiltins.h.template \
gtkprivatetypebuiltins.c.template \
gtkprivatetypebuiltins.h.template \
org.gtk.Settings.FileChooser.gschema.xml
org.gtk.Settings.FileChooser.gschema.xml \
org.gtk.Settings.ColorChooser.gschema.xml
gsettings_SCHEMAS = \
org.gtk.Settings.FileChooser.gschema.xml
org.gtk.Settings.FileChooser.gschema.xml \
org.gtk.Settings.ColorChooser.gschema.xml
@GSETTINGS_RULES@
+2
View File
@@ -11,6 +11,7 @@ gail_c_sources = \
gtkcellaccessible.c \
gtkcellaccessibleparent.c \
gtkcheckmenuitemaccessible.c \
gtkcolorswatchaccessible.c \
gtkcomboboxaccessible.c \
gtkcontaineraccessible.c \
gtkcontainercellaccessible.c \
@@ -59,6 +60,7 @@ gail_private_h_sources = \
gtkcellaccessible.h \
gtkcellaccessibleparent.h \
gtkcheckmenuitemaccessible.h \
gtkcolorswatchaccessible.h \
gtkcomboboxaccessible.h \
gtkcontaineraccessible.h \
gtkcontainercellaccessible.h \
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright 2012 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtkcolorswatchaccessible.h"
static void atk_action_interface_init (AtkActionIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkColorSwatchAccessible, _gtk_color_swatch_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
static void
_gtk_color_swatch_accessible_class_init (GtkColorSwatchAccessibleClass *klass)
{
}
static void
_gtk_color_swatch_accessible_init (GtkColorSwatchAccessible *scale)
{
}
static gint
gtk_color_swatch_accessible_get_n_actions (AtkAction *action)
{
return 3;
}
static const gchar *
gtk_color_swatch_accessible_get_keybinding (AtkAction *action,
gint i)
{
return NULL;
}
static const gchar *
gtk_color_swatch_accessible_get_name (AtkAction *action,
gint i)
{
switch (i)
{
case 0: return "select";
case 1: return "activate";
case 2: return "customize";
default: return NULL;
}
}
static gboolean
gtk_color_swatch_accessible_do_action (AtkAction *action,
gint i)
{
GtkWidget *widget;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
if (widget == NULL)
return FALSE;
switch (i)
{
case 0:
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
break;
case 1:
g_signal_emit_by_name (widget, "activate");
break;
case 2:
g_signal_emit_by_name (widget, "customize");
break;
default:
return FALSE;
}
return TRUE;
}
static void
atk_action_interface_init (AtkActionIface *iface)
{
iface->do_action = gtk_color_swatch_accessible_do_action;
iface->get_n_actions = gtk_color_swatch_accessible_get_n_actions;
iface->get_keybinding = gtk_color_swatch_accessible_get_keybinding;
iface->get_name = gtk_color_swatch_accessible_get_name;
}
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright 2012, Red Hat, Inc
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_COLOR_SWATCH_ACCESSIBLE_H__
#define __GTK_COLOR_SWATCH_ACCESSIBLE_H__
#include "gtkwidgetaccessible.h"
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_SWATCH_ACCESSIBLE (_gtk_color_swatch_accessible_get_type ())
#define GTK_COLOR_SWATCH_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE, GtkColorSwatchAccessible))
#define GTK_COLOR_SWATCH_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE, GtkColorSwatchAccessibleClass))
#define GTK_IS_COLOR_SWATCH_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE))
#define GTK_IS_COLOR_SWATCH_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE))
#define GTK_COLOR_SWATCH_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE, GtkColorSwatchAccessibleClass))
typedef struct _GtkColorSwatchAccessible GtkColorSwatchAccessible;
typedef struct _GtkColorSwatchAccessibleClass GtkColorSwatchAccessibleClass;
struct _GtkColorSwatchAccessible
{
GtkWidgetAccessible parent;
};
struct _GtkColorSwatchAccessibleClass
{
GtkWidgetAccessibleClass parent_class;
};
GType _gtk_color_swatch_accessible_get_type (void);
G_END_DECLS
#endif /* __GTK_COLOR_SWATCH_ACCESSIBLE_H__ */
@@ -27,6 +27,8 @@
#include "config.h"
#define GDK_DISABLE_DEPRECATION_WARNINGS
#include "gtkcolorsel.h"
#include <math.h>
@@ -37,6 +39,7 @@
#include "gtkhsv.h"
#include "gtkwindow.h"
#include "gtkselection.h"
#include "gtkcolorutils.h"
#include "gtkdnd.h"
#include "gtkdrawingarea.h"
#include "gtkframe.h"
@@ -62,7 +65,7 @@
/**
* SECTION:gtkcolorsel
* @Short_description: A widget used to select a color
* @Short_description: Deprecated widget used to select a color
* @Title: GtkColorSelection
*
* The #GtkColorSelection is a widget that is used to select
@@ -3068,7 +3071,7 @@ gtk_color_selection_palette_to_string (const GdkColor *colors,
* tries to modify the palette in a color selection.
*
* This function should save the new palette contents, and update
* the #GtkSettings::gtk-color-palette GtkSettings property so all
* the #GtkSettings:gtk-color-palette GtkSettings property so all
* GtkColorSelection widgets will be modified.
*
* Return value: the previous change palette hook (that was replaced)
@@ -89,51 +89,67 @@ struct _GtkColorSelectionClass
/* ColorSelection */
GType gtk_color_selection_get_type (void) G_GNUC_CONST;
GDK_DEPRECATED_FOR(gtk_color_chooser_widget_new)
GtkWidget *gtk_color_selection_new (void);
GDK_DEPRECATED_FOR(gtk_color_chooser_get_use_alpha)
gboolean gtk_color_selection_get_has_opacity_control (GtkColorSelection *colorsel);
GDK_DEPRECATED_FOR(gtk_color_chooser_set_use_alpha)
void gtk_color_selection_set_has_opacity_control (GtkColorSelection *colorsel,
gboolean has_opacity);
GDK_DEPRECATED
gboolean gtk_color_selection_get_has_palette (GtkColorSelection *colorsel);
GDK_DEPRECATED
void gtk_color_selection_set_has_palette (GtkColorSelection *colorsel,
gboolean has_palette);
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
void gtk_color_selection_set_current_alpha (GtkColorSelection *colorsel,
guint16 alpha);
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
guint16 gtk_color_selection_get_current_alpha (GtkColorSelection *colorsel);
GDK_DEPRECATED
void gtk_color_selection_set_previous_alpha (GtkColorSelection *colorsel,
guint16 alpha);
GDK_DEPRECATED
guint16 gtk_color_selection_get_previous_alpha (GtkColorSelection *colorsel);
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
void gtk_color_selection_set_current_rgba (GtkColorSelection *colorsel,
const GdkRGBA *rgba);
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
void gtk_color_selection_get_current_rgba (GtkColorSelection *colorsel,
GdkRGBA *rgba);
GDK_DEPRECATED
void gtk_color_selection_set_previous_rgba (GtkColorSelection *colorsel,
const GdkRGBA *rgba);
GDK_DEPRECATED
void gtk_color_selection_get_previous_rgba (GtkColorSelection *colorsel,
GdkRGBA *rgba);
GDK_DEPRECATED
gboolean gtk_color_selection_is_adjusting (GtkColorSelection *colorsel);
GDK_DEPRECATED
gboolean gtk_color_selection_palette_from_string (const gchar *str,
GdkColor **colors,
gint *n_colors);
GDK_DEPRECATED
gchar* gtk_color_selection_palette_to_string (const GdkColor *colors,
gint n_colors);
GtkColorSelectionChangePaletteWithScreenFunc gtk_color_selection_set_change_palette_with_screen_hook (GtkColorSelectionChangePaletteWithScreenFunc func);
GDK_DEPRECATED_FOR(gtk_color_selection_set_current_rgba)
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
void gtk_color_selection_set_current_color (GtkColorSelection *colorsel,
const GdkColor *color);
GDK_DEPRECATED_FOR(gtk_color_selection_get_current_rgba)
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
void gtk_color_selection_get_current_color (GtkColorSelection *colorsel,
GdkColor *color);
GDK_DEPRECATED_FOR(gtk_color_selection_set_previous_rgba)
GDK_DEPRECATED
void gtk_color_selection_set_previous_color (GtkColorSelection *colorsel,
const GdkColor *color);
GDK_DEPRECATED_FOR(gtk_color_selection_get_previous_rgba)
GDK_DEPRECATED
void gtk_color_selection_get_previous_color (GtkColorSelection *colorsel,
GdkColor *color);
@@ -24,6 +24,10 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
#define GDK_DISABLE_DEPRECATION_WARNINGS
#include <string.h>
#include <glib.h>
#include "gtkcolorseldialog.h"
@@ -36,7 +40,7 @@
/**
* SECTION:gtkcolorseldlg
* @Short_description: A standard dialog box for selecting a color
* @Short_description: Deprecated dialog box for selecting a color
* @Title: GtkColorSelectionDialog
*
* The #GtkColorSelectionDialog provides a standard dialog which
@@ -32,7 +32,7 @@
#define __GTK_COLOR_SELECTION_DIALOG_H__
#include <gtk/gtkdialog.h>
#include <gtk/gtkcolorsel.h>
#include <gtk/deprecated/gtkcolorsel.h>
G_BEGIN_DECLS
@@ -71,7 +71,9 @@ struct _GtkColorSelectionDialogClass
/* ColorSelectionDialog */
GType gtk_color_selection_dialog_get_type (void) G_GNUC_CONST;
GDK_DEPRECATED_FOR(gtk_color_chooser_dialog_new)
GtkWidget* gtk_color_selection_dialog_new (const gchar *title);
GDK_DEPRECATED_FOR(GtkColorChooser)
GtkWidget* gtk_color_selection_dialog_get_color_selection (GtkColorSelectionDialog *colorsel);
+1 -1
View File
@@ -1635,7 +1635,7 @@ gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
/**
* SECTION:gtkfontseldlg
* @Short_description: A dialog box for selecting fonts
* @Short_description: Deprecated dialog box for selecting fonts
* @Title: GtkFontSelectionDialog
* @See_also: #GtkFontSelection, #GtkDialog, #GtkFontChooserDialog
*
+1 -1
View File
@@ -49,7 +49,7 @@
* very quick and easy change. If you have derived your own classes from
* GtkHBox, you can simply change the inheritance to derive directly
* from #GtkBox. No further changes are needed, since the default
* value of the #GtkOrientable::orientation property is
* value of the #GtkOrientable:orientation property is
* %GTK_ORIENTATION_HORIZONTAL.
* If you want your code to be future-proof, the recommendation is to
* switch to #GtkGrid, since #GtkBox is going to be deprecated in favor
+5 -78
View File
@@ -31,6 +31,8 @@
#include "config.h"
#define GDK_DISABLE_DEPRECATION_WARNINGS
#include <math.h>
#include <string.h>
@@ -52,6 +54,9 @@
* intuitive way. Moving the selection around the outer ring changes the hue,
* and moving the selection point inside the inner triangle changes value and
* saturation.
*
* #GtkHSV has been deprecated together with #GtkColorSelection, where
* it was used.
*/
@@ -1454,84 +1459,6 @@ gtk_hsv_is_adjusting (GtkHSV *hsv)
return priv->mode != DRAG_NONE;
}
/**
* gtk_hsv_to_rgb:
* @h: Hue
* @s: Saturation
* @v: Value
* @r: (out): Return value for the red component
* @g: (out): Return value for the green component
* @b: (out): Return value for the blue component
*
* Converts a color from HSV space to RGB.
* Input values must be in the [0.0, 1.0] range;
* output values will be in the same range.
*
* Since: 2.14
*/
void
gtk_hsv_to_rgb (gdouble h,
gdouble s,
gdouble v,
gdouble *r,
gdouble *g,
gdouble *b)
{
g_return_if_fail (h >= 0.0 && h <= 1.0);
g_return_if_fail (s >= 0.0 && s <= 1.0);
g_return_if_fail (v >= 0.0 && v <= 1.0);
hsv_to_rgb (&h, &s, &v);
if (r)
*r = h;
if (g)
*g = s;
if (b)
*b = v;
}
/**
* gtk_rgb_to_hsv:
* @r: Red
* @g: Green
* @b: Blue
* @h: (out): Return value for the hue component
* @s: (out): Return value for the saturation component
* @v: (out): Return value for the value component
*
* Converts a color from RGB space to HSV.
* Input values must be in the [0.0, 1.0] range;
* output values will be in the same range.
*
* Since: 2.14
*/
void
gtk_rgb_to_hsv (gdouble r,
gdouble g,
gdouble b,
gdouble *h,
gdouble *s,
gdouble *v)
{
g_return_if_fail (r >= 0.0 && r <= 1.0);
g_return_if_fail (g >= 0.0 && g <= 1.0);
g_return_if_fail (b >= 0.0 && b <= 1.0);
rgb_to_hsv (&r, &g, &b);
if (h)
*h = r;
if (s)
*s = g;
if (v)
*v = b;
}
static void
gtk_hsv_move (GtkHSV *hsv,
GtkDirectionType dir)
+6 -14
View File
@@ -80,37 +80,29 @@ struct _GtkHSVClass
GType gtk_hsv_get_type (void) G_GNUC_CONST;
GDK_DEPRECATED
GtkWidget* gtk_hsv_new (void);
GDK_DEPRECATED
void gtk_hsv_set_color (GtkHSV *hsv,
double h,
double s,
double v);
GDK_DEPRECATED
void gtk_hsv_get_color (GtkHSV *hsv,
gdouble *h,
gdouble *s,
gdouble *v);
GDK_DEPRECATED
void gtk_hsv_set_metrics (GtkHSV *hsv,
gint size,
gint ring_width);
GDK_DEPRECATED
void gtk_hsv_get_metrics (GtkHSV *hsv,
gint *size,
gint *ring_width);
GDK_DEPRECATED
gboolean gtk_hsv_is_adjusting (GtkHSV *hsv);
/* Convert colors between the RGB and HSV color spaces */
void gtk_hsv_to_rgb (gdouble h,
gdouble s,
gdouble v,
gdouble *r,
gdouble *g,
gdouble *b);
void gtk_rgb_to_hsv (gdouble r,
gdouble g,
gdouble b,
gdouble *h,
gdouble *s,
gdouble *v);
G_END_DECLS
#endif /* __GTK_HSV_H__ */
+1 -1
View File
@@ -49,7 +49,7 @@
* GtkVBox has been deprecated. You can use #GtkBox instead, which is a
* very quick and easy change. If you have derived your own classes from
* GtkVBox, you can simply change the inheritance to derive directly
* from #GtkBox, and set the #GtkOrientable::orientation property to
* from #GtkBox, and set the #GtkOrientable:orientation property to
* %GTK_ORIENTATION_VERTICAL in your instance init function, with a
* call like:
* |[
+6
View File
@@ -362,3 +362,9 @@ GtkCalendar.button:hover {
border-width: 0;
padding: 2px;
}
.press-and-hold {
background-color: alpha (@bg_color, 0.5);
color: alpha (lighter (@selected_bg_color), 0.8);
border-width: 10;
}
+2 -1
View File
@@ -12,7 +12,8 @@
@define-color error_fg_color rgb (166, 38, 38);
@define-color error_bg_color rgb (237, 54, 54);
GtkWindow {
GtkWindow,
GtkViewport {
background-color: @bg_color;
}
+8 -3
View File
@@ -78,8 +78,10 @@
#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkclipboard.h>
#include <gtk/gtkcolorbutton.h>
#include <gtk/gtkcolorsel.h>
#include <gtk/gtkcolorseldialog.h>
#include <gtk/gtkcolorchooser.h>
#include <gtk/gtkcolorchooserdialog.h>
#include <gtk/gtkcolorchooserwidget.h>
#include <gtk/gtkcolorutils.h>
#include <gtk/gtkcombobox.h>
#include <gtk/gtkcomboboxtext.h>
#include <gtk/gtkcontainer.h>
@@ -107,9 +109,9 @@
#include <gtk/gtkfontchooserdialog.h>
#include <gtk/gtkfontchooserwidget.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkgesturesinterpreter.h>
#include <gtk/gtkgradient.h>
#include <gtk/gtkgrid.h>
#include <gtk/gtkhsv.h>
#include <gtk/gtkiconfactory.h>
#include <gtk/gtkicontheme.h>
#include <gtk/gtkiconview.h>
@@ -223,11 +225,14 @@
#include <gtk/gtkwidgetpath.h>
#include <gtk/gtkwindow.h>
#include <gtk/deprecated/gtkcolorsel.h>
#include <gtk/deprecated/gtkcolorseldialog.h>
#include <gtk/deprecated/gtkfontsel.h>
#include <gtk/deprecated/gtkhandlebox.h>
#include <gtk/deprecated/gtkhbbox.h>
#include <gtk/deprecated/gtkhbox.h>
#include <gtk/deprecated/gtkhpaned.h>
#include <gtk/deprecated/gtkhsv.h>
#include <gtk/deprecated/gtkhscale.h>
#include <gtk/deprecated/gtkhscrollbar.h>
#include <gtk/deprecated/gtkhseparator.h>
+9
View File
@@ -605,6 +605,15 @@ gtk_color_button_set_color
gtk_color_button_set_rgba
gtk_color_button_set_title
gtk_color_button_set_use_alpha
gtk_color_chooser_dialog_get_type
gtk_color_chooser_dialog_new
gtk_color_chooser_get_color
gtk_color_chooser_get_show_alpha
gtk_color_chooser_get_type
gtk_color_chooser_set_color
gtk_color_chooser_set_show_alpha
gtk_color_chooser_widget_get_type
gtk_color_chooser_widget_new
gtk_color_selection_dialog_get_color_selection
gtk_color_selection_dialog_get_type
gtk_color_selection_dialog_new
+2 -3
View File
@@ -2380,7 +2380,7 @@ create_credits_page (GtkAboutDialog *about)
priv->credits_page = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), page_vbox, NULL);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
@@ -2389,7 +2389,7 @@ create_credits_page (GtkAboutDialog *about)
grid = gtk_grid_new ();
gtk_container_set_border_width (GTK_CONTAINER (grid), 5);
gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
gtk_grid_set_column_spacing (GTK_GRID (grid), 2);
gtk_grid_set_column_spacing (GTK_GRID (grid), 8);
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
gtk_widget_set_valign (grid, GTK_ALIGN_START);
@@ -2455,7 +2455,6 @@ create_license_page (GtkAboutDialog *about)
priv->license_page = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), page_vbox, NULL);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_set_border_width (GTK_CONTAINER (sw), 5);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+2 -2
View File
@@ -340,9 +340,9 @@ gtk_activatable_update (GtkActivatable *activatable,
* @action: (allow-none): the related #GtkAction or %NULL
*
* This is called to update the activatable completely, this is called
* internally when the #GtkActivatable::related-action property is set
* internally when the #GtkActivatable:related-action property is set
* or unset and by the implementing class when
* #GtkActivatable::use-action-appearance changes.
* #GtkActivatable:use-action-appearance changes.
*
* Since: 2.16
**/
+2 -2
View File
@@ -45,8 +45,8 @@ typedef struct _GtkActivatableIface GtkActivatableIface;
* You must check the #GtkActivatable:use-action-appearance property only apply action
* properties that are meant to effect the appearance accordingly.
* @sync_action_properties: Called to update the activatable completely, this is called internally when
* #GtkActivatable::related-action property is set or unset and by the implementor when
* #GtkActivatable::use-action-appearance changes.<note><para>This method can be called
* #GtkActivatable:related-action property is set or unset and by the implementor when
* #GtkActivatable:use-action-appearance changes.<note><para>This method can be called
* with a %NULL action at times</para></note>
*
* Since: 2.16
+3 -3
View File
@@ -31,14 +31,14 @@
*
* Initially, a #GtkAppChooserButton selects the first application
* in its list, which will either be the most-recently used application
* or, if #GtkAppChooserButton::show-default-item is %TRUE, the
* or, if #GtkAppChooserButton:show-default-item is %TRUE, the
* default application.
*
* The list of applications shown in a #GtkAppChooserButton includes
* the recommended applications for the given content type. When
* #GtkAppChooserButton::show-default-item is set, the default application
* #GtkAppChooserButton:show-default-item is set, the default application
* is also included. To let the user chooser other applications,
* you can set the #GtkAppChooserButton::show-dialog-item property,
* you can set the #GtkAppChooserButton:show-dialog-item property,
* which allows to open a full #GtkAppChooserDialog.
*
* It is possible to add custom items to the list, using
+2 -2
View File
@@ -42,10 +42,10 @@
* same size. GtkButtonBox gives all children the same size, but it does allow
* 'outliers' to keep their own larger size. To force all children to be
* strictly the same size without exceptions, you can set the
* #GtkButtonBox::homogeneous property to %TRUE.
* #GtkButtonBox:homogeneous property to %TRUE.
*
* To excempt individual children from homogeneous sizing regardless of their
* 'outlier' status, you can set the #GtkButtonBox::non-homogeneous child
* 'outlier' status, you can set the #GtkButtonBox:non-homogeneous child
* property.
*/
+38 -2
View File
@@ -1813,7 +1813,8 @@ gtk_button_button_press (GtkWidget *widget,
GtkButton *button;
GtkButtonPrivate *priv;
if (event->type == GDK_BUTTON_PRESS)
if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_TOUCH_PRESS)
{
button = GTK_BUTTON (widget);
priv = button->priv;
@@ -1932,6 +1933,40 @@ gtk_real_button_pressed (GtkButton *button)
gtk_button_update_state (button);
}
static gboolean
touch_release_in_button (GtkButton *button)
{
GtkButtonPrivate *priv;
gint width, height;
GdkEvent *event;
gdouble x, y;
priv = button->priv;
event = gtk_get_current_event ();
if (!event)
return FALSE;
if (event->type != GDK_TOUCH_RELEASE ||
event->button.window != priv->event_window)
{
gdk_event_free (event);
return FALSE;
}
gdk_event_get_coords (event, &x, &y);
width = gdk_window_get_width (priv->event_window);
height = gdk_window_get_height (priv->event_window);
gdk_event_free (event);
if (x >= 0 && x <= width &&
y >= 0 && y <= height)
return TRUE;
return FALSE;
}
static void
gtk_real_button_released (GtkButton *button)
{
@@ -1944,7 +1979,8 @@ gtk_real_button_released (GtkButton *button)
if (priv->activate_timeout)
return;
if (priv->in_button)
if (priv->in_button ||
touch_release_in_button (button))
gtk_button_clicked (button);
gtk_button_update_state (button);
+239 -256
View File
@@ -28,18 +28,18 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#define GDK_DISABLE_DEPRECATION_WARNINGS
#include "config.h"
#include "gtkcolorbutton.h"
#include "gtkbutton.h"
#include "gtkmain.h"
#include "gtkalignment.h"
#include "gtkcolorsel.h"
#include "gtkcolorseldialog.h"
#include "gtkcolorchooser.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcolorchooserdialog.h"
#include "gtkdnd.h"
#include "gtkdrawingarea.h"
#include "gtkframe.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@@ -62,6 +62,7 @@
#define CHECK_DARK (1.0 / 3.0)
#define CHECK_LIGHT (2.0 / 3.0)
#define COLOR_SAMPLE_MARGIN 1
struct _GtkColorButtonPrivate
{
@@ -119,7 +120,7 @@ static void gtk_color_button_drag_data_get (GtkWidget *widget,
GtkSelectionData *selection_data,
guint info,
guint time,
GtkColorButton *color_button);
GtkColorButton *button);
/* target side drag signals */
static void gtk_color_button_drag_data_received (GtkWidget *widget,
@@ -129,14 +130,18 @@ static void gtk_color_button_drag_data_received (GtkWidget *widget,
GtkSelectionData *selection_data,
guint info,
guint32 time,
GtkColorButton *color_button);
GtkColorButton *button);
static guint color_button_signals[LAST_SIGNAL] = { 0 };
static const GtkTargetEntry drop_types[] = { { "application/x-color", 0, 0 } };
G_DEFINE_TYPE (GtkColorButton, gtk_color_button, GTK_TYPE_BUTTON)
static void gtk_color_button_iface_init (GtkColorChooserInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkColorButton, gtk_color_button, GTK_TYPE_BUTTON,
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
gtk_color_button_iface_init))
static void
gtk_color_button_class_init (GtkColorButtonClass *klass)
@@ -159,9 +164,9 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
/**
* GtkColorButton:use-alpha:
*
* If this property is set to %TRUE, the color swatch on the button is rendered against a
* checkerboard background to show its opacity and the opacity slider is displayed in the
* color selection dialog.
* If this property is set to %TRUE, the color swatch on the button is
* rendered against a checkerboard background to show its opacity and
* the opacity slider is displayed in the color selection dialog.
*
* Since: 2.4
*/
@@ -262,33 +267,9 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
}
static gboolean
gtk_color_button_has_alpha (GtkColorButton *color_button)
gtk_color_button_has_alpha (GtkColorButton *button)
{
return color_button->priv->use_alpha &&
color_button->priv->rgba.alpha < 1;
}
static cairo_pattern_t *
gtk_color_button_get_checkered (void)
{
/* need to respect pixman's stride being a multiple of 4 */
static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00 };
static cairo_surface_t *checkered = NULL;
cairo_pattern_t *pattern;
if (checkered == NULL)
{
checkered = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_A8,
2, 2, 4);
}
pattern = cairo_pattern_create_for_surface (checkered);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
return pattern;
return button->priv->use_alpha && button->priv->rgba.alpha < 1;
}
/* Handle exposure events for the color picker's drawing area */
@@ -297,10 +278,10 @@ gtk_color_button_draw_cb (GtkWidget *widget,
cairo_t *cr,
gpointer data)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
GtkColorButton *button = GTK_COLOR_BUTTON (data);
cairo_pattern_t *checkered;
if (gtk_color_button_has_alpha (color_button))
if (gtk_color_button_has_alpha (button))
{
cairo_set_source_rgb (cr, CHECK_DARK, CHECK_DARK, CHECK_DARK);
cairo_paint (cr);
@@ -308,23 +289,23 @@ gtk_color_button_draw_cb (GtkWidget *widget,
cairo_set_source_rgb (cr, CHECK_LIGHT, CHECK_LIGHT, CHECK_LIGHT);
cairo_scale (cr, CHECK_SIZE, CHECK_SIZE);
checkered = gtk_color_button_get_checkered ();
checkered = _gtk_color_chooser_get_checkered_pattern ();
cairo_mask (cr, checkered);
cairo_pattern_destroy (checkered);
gdk_cairo_set_source_rgba (cr, &color_button->priv->rgba);
gdk_cairo_set_source_rgba (cr, &button->priv->rgba);
}
else
{
cairo_set_source_rgb (cr,
color_button->priv->rgba.red,
color_button->priv->rgba.green,
color_button->priv->rgba.blue);
button->priv->rgba.red,
button->priv->rgba.green,
button->priv->rgba.blue);
}
cairo_paint (cr);
if (!gtk_widget_is_sensitive (GTK_WIDGET (color_button)))
if (!gtk_widget_is_sensitive (GTK_WIDGET (button)))
{
GtkStyleContext *context;
GdkRGBA color;
@@ -333,7 +314,7 @@ gtk_color_button_draw_cb (GtkWidget *widget,
gtk_style_context_get_background_color (context, GTK_STATE_FLAG_INSENSITIVE, &color);
gdk_cairo_set_source_rgba (cr, &color);
checkered = gtk_color_button_get_checkered ();
checkered = _gtk_color_chooser_get_checkered_pattern ();
cairo_mask (cr, checkered);
cairo_pattern_destroy (checkered);
}
@@ -356,7 +337,7 @@ gtk_color_button_drag_data_received (GtkWidget *widget,
GtkSelectionData *selection_data,
guint info,
guint32 time,
GtkColorButton *color_button)
GtkColorButton *button)
{
gint length;
guint16 *dropped;
@@ -378,20 +359,20 @@ gtk_color_button_drag_data_received (GtkWidget *widget,
dropped = (guint16 *) gtk_selection_data_get_data (selection_data);
color_button->priv->rgba.red = dropped[0] / 65535.;
color_button->priv->rgba.green = dropped[1] / 65535.;
color_button->priv->rgba.blue = dropped[2] / 65535.;
color_button->priv->rgba.alpha = dropped[3] / 65535.;
button->priv->rgba.red = dropped[0] / 65535.;
button->priv->rgba.green = dropped[1] / 65535.;
button->priv->rgba.blue = dropped[2] / 65535.;
button->priv->rgba.alpha = dropped[3] / 65535.;
gtk_widget_queue_draw (color_button->priv->draw_area);
gtk_widget_queue_draw (button->priv->draw_area);
g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
g_signal_emit (button, color_button_signals[COLOR_SET], 0);
g_object_freeze_notify (G_OBJECT (color_button));
g_object_notify (G_OBJECT (color_button), "color");
g_object_notify (G_OBJECT (color_button), "alpha");
g_object_notify (G_OBJECT (color_button), "rgba");
g_object_thaw_notify (G_OBJECT (color_button));
g_object_freeze_notify (G_OBJECT (button));
g_object_notify (G_OBJECT (button), "color");
g_object_notify (G_OBJECT (button), "alpha");
g_object_notify (G_OBJECT (button), "rgba");
g_object_thaw_notify (G_OBJECT (button));
}
static void
@@ -419,9 +400,9 @@ gtk_color_button_drag_begin (GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
GtkColorButton *color_button = data;
GtkColorButton *button = data;
set_color_icon (context, &color_button->priv->rgba);
set_color_icon (context, &button->priv->rgba);
}
static void
@@ -430,14 +411,14 @@ gtk_color_button_drag_data_get (GtkWidget *widget,
GtkSelectionData *selection_data,
guint info,
guint time,
GtkColorButton *color_button)
GtkColorButton *button)
{
guint16 dropped[4];
dropped[0] = (guint16) (color_button->priv->rgba.red * 65535);
dropped[1] = (guint16) (color_button->priv->rgba.green * 65535);
dropped[2] = (guint16) (color_button->priv->rgba.blue * 65535);
dropped[3] = (guint16) (color_button->priv->rgba.alpha * 65535);
dropped[0] = (guint16) (button->priv->rgba.red * 65535);
dropped[1] = (guint16) (button->priv->rgba.green * 65535);
dropped[2] = (guint16) (button->priv->rgba.blue * 65535);
dropped[3] = (guint16) (button->priv->rgba.alpha * 65535);
gtk_selection_data_set (selection_data,
gtk_selection_data_get_target (selection_data),
@@ -445,68 +426,62 @@ gtk_color_button_drag_data_get (GtkWidget *widget,
}
static void
gtk_color_button_init (GtkColorButton *color_button)
gtk_color_button_init (GtkColorButton *button)
{
GtkWidget *alignment;
GtkWidget *frame;
PangoLayout *layout;
PangoRectangle rect;
/* Create the widgets */
color_button->priv = G_TYPE_INSTANCE_GET_PRIVATE (color_button,
GTK_TYPE_COLOR_BUTTON,
GtkColorButtonPrivate);
button->priv = G_TYPE_INSTANCE_GET_PRIVATE (button,
GTK_TYPE_COLOR_BUTTON,
GtkColorButtonPrivate);
gtk_widget_push_composite_child ();
alignment = gtk_alignment_new (0.5, 0.5, 0.5, 1.0);
gtk_container_set_border_width (GTK_CONTAINER (alignment), 1);
gtk_container_add (GTK_CONTAINER (color_button), alignment);
gtk_widget_show (alignment);
button->priv->draw_area = gtk_drawing_area_new ();
g_object_set (button->priv->draw_area,
"margin-top", COLOR_SAMPLE_MARGIN,
"margin-bottom", COLOR_SAMPLE_MARGIN,
"margin-left", 16,
"margin-right", 16,
NULL);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
gtk_container_add (GTK_CONTAINER (alignment), frame);
gtk_widget_show (frame);
/* Just some widget we can hook to expose-event on */
color_button->priv->draw_area = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
layout = gtk_widget_create_pango_layout (GTK_WIDGET (color_button), "Black");
layout = gtk_widget_create_pango_layout (GTK_WIDGET (button), "Black");
pango_layout_get_pixel_extents (layout, NULL, &rect);
g_object_unref (layout);
gtk_widget_set_size_request (color_button->priv->draw_area, rect.width - 2, rect.height - 2);
g_signal_connect (color_button->priv->draw_area, "draw",
G_CALLBACK (gtk_color_button_draw_cb), color_button);
gtk_container_add (GTK_CONTAINER (frame), color_button->priv->draw_area);
gtk_widget_show (color_button->priv->draw_area);
gtk_widget_set_size_request (button->priv->draw_area,
rect.width, rect.height - 2 * COLOR_SAMPLE_MARGIN);
color_button->priv->title = g_strdup (_("Pick a Color")); /* default title */
g_signal_connect (button->priv->draw_area, "draw",
G_CALLBACK (gtk_color_button_draw_cb), button);
gtk_container_add (GTK_CONTAINER (button), button->priv->draw_area);
gtk_widget_show (button->priv->draw_area);
button->priv->title = g_strdup (_("Pick a Color")); /* default title */
/* Start with opaque black, alpha disabled */
button->priv->rgba.red = 0;
button->priv->rgba.green = 0;
button->priv->rgba.blue = 0;
button->priv->rgba.alpha = 1;
button->priv->use_alpha = FALSE;
color_button->priv->rgba.red = 0;
color_button->priv->rgba.green = 0;
color_button->priv->rgba.blue = 0;
color_button->priv->rgba.alpha = 1;
color_button->priv->use_alpha = FALSE;
gtk_drag_dest_set (GTK_WIDGET (color_button),
gtk_drag_dest_set (GTK_WIDGET (button),
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_HIGHLIGHT |
GTK_DEST_DEFAULT_DROP,
drop_types, 1, GDK_ACTION_COPY);
gtk_drag_source_set (GTK_WIDGET(color_button),
gtk_drag_source_set (GTK_WIDGET (button),
GDK_BUTTON1_MASK|GDK_BUTTON3_MASK,
drop_types, 1,
GDK_ACTION_COPY);
g_signal_connect (color_button, "drag-begin",
G_CALLBACK (gtk_color_button_drag_begin), color_button);
g_signal_connect (color_button, "drag-data-received",
G_CALLBACK (gtk_color_button_drag_data_received), color_button);
g_signal_connect (color_button, "drag-data-get",
G_CALLBACK (gtk_color_button_drag_data_get), color_button);
g_signal_connect (button, "drag-begin",
G_CALLBACK (gtk_color_button_drag_begin), button);
g_signal_connect (button, "drag-data-received",
G_CALLBACK (gtk_color_button_drag_data_received), button);
g_signal_connect (button, "drag-data-get",
G_CALLBACK (gtk_color_button_drag_data_get), button);
gtk_widget_pop_composite_child ();
}
@@ -514,14 +489,14 @@ gtk_color_button_init (GtkColorButton *color_button)
static void
gtk_color_button_finalize (GObject *object)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
GtkColorButton *button = GTK_COLOR_BUTTON (object);
if (color_button->priv->cs_dialog != NULL)
gtk_widget_destroy (color_button->priv->cs_dialog);
color_button->priv->cs_dialog = NULL;
if (button->priv->cs_dialog != NULL)
gtk_widget_destroy (button->priv->cs_dialog);
button->priv->cs_dialog = NULL;
g_free (color_button->priv->title);
color_button->priv->title = NULL;
g_free (button->priv->title);
button->priv->title = NULL;
G_OBJECT_CLASS (gtk_color_button_parent_class)->finalize (object);
}
@@ -582,296 +557,278 @@ gtk_color_button_new_with_rgba (const GdkRGBA *rgba)
return g_object_new (GTK_TYPE_COLOR_BUTTON, "rgba", rgba, NULL);
}
static void
dialog_ok_clicked (GtkWidget *widget,
gpointer data)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
GtkColorSelection *color_selection;
GtkColorSelectionDialog *selection_dialog;
selection_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
color_selection = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (selection_dialog));
gtk_color_selection_get_current_rgba (color_selection, &color_button->priv->rgba);
gtk_widget_hide (color_button->priv->cs_dialog);
gtk_widget_queue_draw (color_button->priv->draw_area);
g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
g_object_freeze_notify (G_OBJECT (color_button));
g_object_notify (G_OBJECT (color_button), "color");
g_object_notify (G_OBJECT (color_button), "alpha");
g_object_notify (G_OBJECT (color_button), "rgba");
g_object_thaw_notify (G_OBJECT (color_button));
}
static gboolean
dialog_destroy (GtkWidget *widget,
gpointer data)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
GtkColorButton *button = GTK_COLOR_BUTTON (data);
color_button->priv->cs_dialog = NULL;
button->priv->cs_dialog = NULL;
return FALSE;
}
static void
dialog_cancel_clicked (GtkWidget *widget,
gpointer data)
dialog_response (GtkDialog *dialog,
gint response,
gpointer data)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
if (response == GTK_RESPONSE_CANCEL)
gtk_widget_hide (GTK_WIDGET (dialog));
else if (response == GTK_RESPONSE_OK)
{
GtkColorButton *button = GTK_COLOR_BUTTON (data);
gtk_widget_hide (color_button->priv->cs_dialog);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog),
&button->priv->rgba);
gtk_widget_hide (GTK_WIDGET (dialog));
gtk_widget_queue_draw (button->priv->draw_area);
g_signal_emit (button, color_button_signals[COLOR_SET], 0);
g_object_freeze_notify (G_OBJECT (button));
g_object_notify (G_OBJECT (button), "color");
g_object_notify (G_OBJECT (button), "alpha");
g_object_notify (G_OBJECT (button), "rgba");
g_object_thaw_notify (G_OBJECT (button));
}
}
static void
gtk_color_button_clicked (GtkButton *button)
gtk_color_button_clicked (GtkButton *b)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (button);
GtkColorSelection *color_selection;
GtkColorSelectionDialog *color_dialog;
GtkColorButton *button = GTK_COLOR_BUTTON (b);
GtkWidget *dialog;
/* if dialog already exists, make sure it's shown and raised */
if (!color_button->priv->cs_dialog)
if (!button->priv->cs_dialog)
{
/* Create the dialog and connects its buttons */
GtkWidget *parent;
GtkWidget *ok_button, *cancel_button;
parent = gtk_widget_get_toplevel (GTK_WIDGET (color_button));
parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
color_button->priv->cs_dialog = gtk_color_selection_dialog_new (color_button->priv->title);
color_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
button->priv->cs_dialog = dialog = gtk_color_chooser_dialog_new (button->priv->title, NULL);
if (gtk_widget_is_toplevel (parent) && GTK_IS_WINDOW (parent))
{
if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (color_dialog)))
gtk_window_set_transient_for (GTK_WINDOW (color_dialog), GTK_WINDOW (parent));
if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (dialog)))
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
gtk_window_set_modal (GTK_WINDOW (color_dialog),
gtk_window_set_modal (GTK_WINDOW (dialog),
gtk_window_get_modal (GTK_WINDOW (parent)));
}
g_object_get (color_dialog,
"ok-button", &ok_button,
"cancel-button", &cancel_button,
NULL);
g_signal_connect (ok_button, "clicked",
G_CALLBACK (dialog_ok_clicked), color_button);
g_signal_connect (cancel_button, "clicked",
G_CALLBACK (dialog_cancel_clicked), color_button);
g_signal_connect (color_dialog, "destroy",
G_CALLBACK (dialog_destroy), color_button);
g_object_unref (ok_button);
g_object_unref (cancel_button);
g_signal_connect (dialog, "response",
G_CALLBACK (dialog_response), button);
g_signal_connect (dialog, "destroy",
G_CALLBACK (dialog_destroy), button);
}
color_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
color_selection = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (color_dialog));
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
button->priv->use_alpha);
gtk_color_selection_set_has_opacity_control (color_selection,
color_button->priv->use_alpha);
gtk_color_selection_set_previous_rgba (color_selection,
&color_button->priv->rgba);
gtk_color_selection_set_current_rgba (color_selection,
&color_button->priv->rgba);
gtk_window_present (GTK_WINDOW (color_button->priv->cs_dialog));
gtk_window_present (GTK_WINDOW (button->priv->cs_dialog));
}
/**
* gtk_color_button_set_color:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @color: A #GdkColor to set the current color with
*
* Sets the current color to be @color.
*
* Since: 2.4
*
* Deprecated: Use gtk_color_button_set_rgba() instead.
* Deprecated: Use gtk_color_chooser_set_rgba() instead.
*/
void
gtk_color_button_set_color (GtkColorButton *color_button,
gtk_color_button_set_color (GtkColorButton *button,
const GdkColor *color)
{
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
g_return_if_fail (color != NULL);
color_button->priv->rgba.red = color->red / 65535.;
color_button->priv->rgba.green = color->green / 65535.;
color_button->priv->rgba.blue = color->blue / 65535.;
button->priv->rgba.red = color->red / 65535.;
button->priv->rgba.green = color->green / 65535.;
button->priv->rgba.blue = color->blue / 65535.;
gtk_widget_queue_draw (color_button->priv->draw_area);
gtk_widget_queue_draw (button->priv->draw_area);
g_object_notify (G_OBJECT (color_button), "color");
g_object_notify (G_OBJECT (color_button), "rgba");
g_object_notify (G_OBJECT (button), "color");
g_object_notify (G_OBJECT (button), "rgba");
}
/**
* gtk_color_button_set_alpha:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @alpha: an integer between 0 and 65535
*
* Sets the current opacity to be @alpha.
*
* Since: 2.4
*
* Deprecated: 3.4: Use gtk_color_chooser_set_rgba() instead.
*/
void
gtk_color_button_set_alpha (GtkColorButton *color_button,
gtk_color_button_set_alpha (GtkColorButton *button,
guint16 alpha)
{
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
color_button->priv->rgba.alpha = alpha / 65535.;
button->priv->rgba.alpha = alpha / 65535.;
gtk_widget_queue_draw (color_button->priv->draw_area);
gtk_widget_queue_draw (button->priv->draw_area);
g_object_notify (G_OBJECT (color_button), "alpha");
g_object_notify (G_OBJECT (color_button), "rgba");
g_object_notify (G_OBJECT (button), "alpha");
g_object_notify (G_OBJECT (button), "rgba");
}
/**
* gtk_color_button_get_color:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @color: (out): a #GdkColor to fill in with the current color
*
* Sets @color to be the current color in the #GtkColorButton widget.
*
* Since: 2.4
*
* Deprecated: 3.4: Use gtk_color_button_get_rgba() instead.
* Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
*/
void
gtk_color_button_get_color (GtkColorButton *color_button,
gtk_color_button_get_color (GtkColorButton *button,
GdkColor *color)
{
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
color->red = (guint16) (color_button->priv->rgba.red * 65535);
color->green = (guint16) (color_button->priv->rgba.green * 65535);
color->blue = (guint16) (color_button->priv->rgba.blue * 65535);
color->red = (guint16) (button->priv->rgba.red * 65535);
color->green = (guint16) (button->priv->rgba.green * 65535);
color->blue = (guint16) (button->priv->rgba.blue * 65535);
}
/**
* gtk_color_button_get_alpha:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
*
* Returns the current alpha value.
*
* Return value: an integer between 0 and 65535
*
* Since: 2.4
*
* Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
*/
guint16
gtk_color_button_get_alpha (GtkColorButton *color_button)
gtk_color_button_get_alpha (GtkColorButton *button)
{
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), 0);
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), 0);
return (guint16) (color_button->priv->rgba.alpha * 65535);
return (guint16) (button->priv->rgba.alpha * 65535);
}
/**
* gtk_color_button_set_rgba:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @rgba: a #GdkRGBA to set the current color with
*
* Sets the current color to be @rgba.
*
* Since: 3.0
*
* Deprecated: 3.4: Use gtk_color_chooser_set_rgba() instead.
*/
void
gtk_color_button_set_rgba (GtkColorButton *color_button,
gtk_color_button_set_rgba (GtkColorButton *button,
const GdkRGBA *rgba)
{
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
g_return_if_fail (rgba != NULL);
color_button->priv->rgba = *rgba;
button->priv->rgba = *rgba;
gtk_widget_queue_draw (button->priv->draw_area);
gtk_widget_queue_draw (color_button->priv->draw_area);
g_object_notify (G_OBJECT (color_button), "color");
g_object_notify (G_OBJECT (color_button), "alpha");
g_object_notify (G_OBJECT (color_button), "rgba");
g_object_notify (G_OBJECT (button), "color");
g_object_notify (G_OBJECT (button), "alpha");
g_object_notify (G_OBJECT (button), "rgba");
}
/**
* gtk_color_button_get_rgba:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @rgba: (out): a #GdkRGBA to fill in with the current color
*
* Sets @rgba to be the current color in the #GtkColorButton widget.
*
* Since: 3.0
*
* Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
*/
void
gtk_color_button_get_rgba (GtkColorButton *color_button,
gtk_color_button_get_rgba (GtkColorButton *button,
GdkRGBA *rgba)
{
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
g_return_if_fail (rgba != NULL);
*rgba = color_button->priv->rgba;
*rgba = button->priv->rgba;
}
/**
* gtk_color_button_set_use_alpha:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @use_alpha: %TRUE if color button should use alpha channel, %FALSE if not
*
* Sets whether or not the color button should use the alpha channel.
*
* Since: 2.4
*
* Deprecated: 3.4: Use gtk_color_chooser_set_use_alpha() instead.
*/
void
gtk_color_button_set_use_alpha (GtkColorButton *color_button,
gtk_color_button_set_use_alpha (GtkColorButton *button,
gboolean use_alpha)
{
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
use_alpha = (use_alpha != FALSE);
if (color_button->priv->use_alpha != use_alpha)
if (button->priv->use_alpha != use_alpha)
{
color_button->priv->use_alpha = use_alpha;
button->priv->use_alpha = use_alpha;
gtk_widget_queue_draw (color_button->priv->draw_area);
gtk_widget_queue_draw (button->priv->draw_area);
g_object_notify (G_OBJECT (color_button), "use-alpha");
g_object_notify (G_OBJECT (button), "use-alpha");
}
}
/**
* gtk_color_button_get_use_alpha:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
*
* Does the color selection dialog use the alpha channel ?
*
* Returns: %TRUE if the color sample uses alpha channel, %FALSE if not
*
* Since: 2.4
*
* Deprecated: 3.4: Use gtk_color_chooser_get_use_alpha() instead.
*/
gboolean
gtk_color_button_get_use_alpha (GtkColorButton *color_button)
gtk_color_button_get_use_alpha (GtkColorButton *button)
{
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), FALSE);
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), FALSE);
return color_button->priv->use_alpha;
return button->priv->use_alpha;
}
/**
* gtk_color_button_set_title:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
* @title: String containing new window title
*
* Sets the title for the color selection dialog.
@@ -879,27 +836,27 @@ gtk_color_button_get_use_alpha (GtkColorButton *color_button)
* Since: 2.4
*/
void
gtk_color_button_set_title (GtkColorButton *color_button,
gtk_color_button_set_title (GtkColorButton *button,
const gchar *title)
{
gchar *old_title;
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
old_title = color_button->priv->title;
color_button->priv->title = g_strdup (title);
old_title = button->priv->title;
button->priv->title = g_strdup (title);
g_free (old_title);
if (color_button->priv->cs_dialog)
gtk_window_set_title (GTK_WINDOW (color_button->priv->cs_dialog),
color_button->priv->title);
if (button->priv->cs_dialog)
gtk_window_set_title (GTK_WINDOW (button->priv->cs_dialog),
button->priv->title);
g_object_notify (G_OBJECT (color_button), "title");
g_object_notify (G_OBJECT (button), "title");
}
/**
* gtk_color_button_get_title:
* @color_button: a #GtkColorButton
* @button: a #GtkColorButton
*
* Gets the title of the color selection dialog.
*
@@ -908,11 +865,11 @@ gtk_color_button_set_title (GtkColorButton *color_button,
* Since: 2.4
*/
const gchar *
gtk_color_button_get_title (GtkColorButton *color_button)
gtk_color_button_get_title (GtkColorButton *button)
{
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), NULL);
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), NULL);
return color_button->priv->title;
return button->priv->title;
}
static void
@@ -921,15 +878,15 @@ gtk_color_button_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
GtkColorButton *button = GTK_COLOR_BUTTON (object);
switch (param_id)
{
case PROP_USE_ALPHA:
gtk_color_button_set_use_alpha (color_button, g_value_get_boolean (value));
gtk_color_button_set_use_alpha (button, g_value_get_boolean (value));
break;
case PROP_TITLE:
gtk_color_button_set_title (color_button, g_value_get_string (value));
gtk_color_button_set_title (button, g_value_get_string (value));
break;
case PROP_COLOR:
{
@@ -943,14 +900,14 @@ gtk_color_button_set_property (GObject *object,
rgba.blue = color->blue / 65535.0;
rgba.alpha = 1.0;
gtk_color_button_set_rgba (color_button, &rgba);
gtk_color_button_set_rgba (button, &rgba);
}
break;
case PROP_ALPHA:
gtk_color_button_set_alpha (color_button, g_value_get_uint (value));
gtk_color_button_set_alpha (button, g_value_get_uint (value));
break;
case PROP_RGBA:
gtk_color_button_set_rgba (color_button, g_value_get_boxed (value));
gtk_color_button_set_rgba (button, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -964,22 +921,22 @@ gtk_color_button_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
GtkColorButton *button = GTK_COLOR_BUTTON (object);
switch (param_id)
{
case PROP_USE_ALPHA:
g_value_set_boolean (value, gtk_color_button_get_use_alpha (color_button));
g_value_set_boolean (value, gtk_color_button_get_use_alpha (button));
break;
case PROP_TITLE:
g_value_set_string (value, gtk_color_button_get_title (color_button));
g_value_set_string (value, gtk_color_button_get_title (button));
break;
case PROP_COLOR:
{
GdkColor color;
GdkRGBA rgba;
gtk_color_button_get_rgba (color_button, &rgba);
gtk_color_button_get_rgba (button, &rgba);
color.red = (guint16) (rgba.red * 65535 + 0.5);
color.green = (guint16) (rgba.green * 65535 + 0.5);
@@ -989,13 +946,13 @@ gtk_color_button_get_property (GObject *object,
}
break;
case PROP_ALPHA:
g_value_set_uint (value, gtk_color_button_get_alpha (color_button));
g_value_set_uint (value, gtk_color_button_get_alpha (button));
break;
case PROP_RGBA:
{
GdkRGBA rgba;
gtk_color_button_get_rgba (color_button, &rgba);
gtk_color_button_get_rgba (button, &rgba);
g_value_set_boxed (value, &rgba);
}
break;
@@ -1004,3 +961,29 @@ gtk_color_button_get_property (GObject *object,
break;
}
}
static void
gtk_color_button_add_palette (GtkColorChooser *chooser,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors)
{
GtkColorButton *button = GTK_COLOR_BUTTON (chooser);
if (button->priv->cs_dialog)
gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
horizontal, colors_per_line, n_colors, colors);
}
typedef void (* get_rgba) (GtkColorChooser *, GdkRGBA *);
typedef void (* set_rgba) (GtkColorChooser *, const GdkRGBA *);
static void
gtk_color_button_iface_init (GtkColorChooserInterface *iface)
{
iface->get_rgba = (get_rgba)gtk_color_button_get_rgba;
iface->set_rgba = (set_rgba)gtk_color_button_set_rgba;
iface->add_palette = gtk_color_button_add_palette;
}
+24 -19
View File
@@ -73,32 +73,37 @@ struct _GtkColorButtonClass {
};
GType gtk_color_button_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_color_button_new (void);
GtkWidget *gtk_color_button_new_with_rgba (const GdkRGBA *rgba);
void gtk_color_button_set_alpha (GtkColorButton *color_button,
guint16 alpha);
guint16 gtk_color_button_get_alpha (GtkColorButton *color_button);
void gtk_color_button_set_use_alpha (GtkColorButton *color_button,
gboolean use_alpha);
gboolean gtk_color_button_get_use_alpha (GtkColorButton *color_button);
void gtk_color_button_set_rgba (GtkColorButton *color_button,
const GdkRGBA *rgba);
void gtk_color_button_get_rgba (GtkColorButton *color_button,
GdkRGBA *rgba);
void gtk_color_button_set_title (GtkColorButton *color_button,
const gchar *title);
const gchar *gtk_color_button_get_title (GtkColorButton *color_button);
GType gtk_color_button_get_type (void) G_GNUC_CONST;
GtkWidget * gtk_color_button_new (void);
GtkWidget * gtk_color_button_new_with_rgba (const GdkRGBA *rgba);
void gtk_color_button_set_title (GtkColorButton *button,
const gchar *title);
const gchar *gtk_color_button_get_title (GtkColorButton *button);
GDK_DEPRECATED_FOR(gtk_color_button_new_with_rgba)
GtkWidget *gtk_color_button_new_with_color (const GdkColor *color);
GDK_DEPRECATED_FOR(gtk_color_button_set_rgba)
void gtk_color_button_set_color (GtkColorButton *color_button,
void gtk_color_button_set_color (GtkColorButton *button,
const GdkColor *color);
GDK_DEPRECATED_FOR(gtk_color_button_get_rgba)
void gtk_color_button_get_color (GtkColorButton *color_button,
void gtk_color_button_get_color (GtkColorButton *button,
GdkColor *color);
GDK_DEPRECATED_FOR(gtk_color_button_set_rgba)
void gtk_color_button_set_alpha (GtkColorButton *button,
guint16 alpha);
GDK_DEPRECATED_FOR(gtk_color_button_get_rgba)
guint16 gtk_color_button_get_alpha (GtkColorButton *button);
GDK_DEPRECATED_FOR(gtk_color_chooser_set_use_alpha)
void gtk_color_button_set_use_alpha (GtkColorButton *button,
gboolean use_alpha);
GDK_DEPRECATED_FOR(gtk_color_chooser_get_use_alpha)
gboolean gtk_color_button_get_use_alpha (GtkColorButton *button);
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
void gtk_color_button_set_rgba (GtkColorButton *button,
const GdkRGBA *rgba);
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
void gtk_color_button_get_rgba (GtkColorButton *button,
GdkRGBA *rgba);
G_END_DECLS
+258
View File
@@ -0,0 +1,258 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2012, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkcolorchooser.h"
#include "gtkcolorchooserprivate.h"
#include "gtkintl.h"
#include "gtktypebuiltins.h"
#include "gtkprivate.h"
/**
* SECTION:gtkcolorchooser
* @Short_description: Interface implemented by widgets for choosing colors
* @Title: GtkColorChooser
* @See_also: #GtkColorChooserDialog, #GtkColorChooserWidget, #GtkColorButton
*
* #GtkColorChooser is an interface that is implemented by widgets
* for choosing colors. Depending on the situation, colors may be
* allowed to have alpha (translucency).
*
* In GTK+, the main widgets that implement this interface are
* #GtkColorChooserWidget, #GtkColorChooserDialog and #GtkColorButton.
*
* Since: 3.4
*/
enum
{
COLOR_ACTIVATED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_INTERFACE (GtkColorChooser, gtk_color_chooser, G_TYPE_OBJECT);
static void
gtk_color_chooser_default_init (GtkColorChooserInterface *iface)
{
/**
* GtkColorChooser:rgba:
*
* The ::rgba property contains the currently selected color,
* as a #GdkRGBA struct. The property can be set to change
* the current selection programmatically.
*
* Since: 3.4
*/
g_object_interface_install_property (iface,
g_param_spec_boxed ("rgba",
P_("Color"),
P_("Current color, as a GdkRGBA"),
GDK_TYPE_RGBA,
GTK_PARAM_READWRITE));
/**
* GtkColorChooser:use-alpha:
*
* When ::use-alpha is %TRUE, colors may have alpha (translucency)
* information. When it is %FALSE, the #GdkRGBA struct obtained
* via the #GtkColorChooser:rgba property will be forced to have
* alpha == 1.
*
* Implementations are expected to show alpha by rendering the color
* over a non-uniform background (like a checkerboard pattern).
*
* Since: 3.4
*/
g_object_interface_install_property (iface,
g_param_spec_boolean ("use-alpha",
P_("Use alpha"),
P_("Whether alpha should be shown"),
TRUE,
GTK_PARAM_READWRITE));
/**
* GtkColorChooser::color-activated:
* @chooser: the object which received the signal
* @color: the color
*
* Emitted when a color is activated from the color chooser.
* This usually happens when the user clicks a color swatch,
* or a color is selected and the user presses one of the keys
* Space, Shift+Space, Return or Enter.
*
* Since: 3.4
*/
signals[COLOR_ACTIVATED] =
g_signal_new ("color-activated",
GTK_TYPE_COLOR_CHOOSER,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkColorChooserInterface, color_activated),
NULL, NULL,
NULL,
G_TYPE_NONE,
1, G_TYPE_STRING);
}
void
_gtk_color_chooser_color_activated (GtkColorChooser *chooser,
const GdkRGBA *color)
{
g_signal_emit (chooser, signals[COLOR_ACTIVATED], 0, color);
}
/**
* gtk_color_chooser_get_rgba:
* @chooser: a #GtkColorChooser
* @color: return location for the color
*
* Gets the currently-selected color.
*
* Since: 3.4
*/
void
gtk_color_chooser_get_rgba (GtkColorChooser *chooser,
GdkRGBA *color)
{
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
GTK_COLOR_CHOOSER_GET_IFACE (chooser)->get_rgba (chooser, color);
}
/**
* gtk_color_chooser_set_rgba:
* @chooser: a #GtkColorChooser
* @color: the new color
*
* Sets the color.
*/
void
gtk_color_chooser_set_rgba (GtkColorChooser *chooser,
const GdkRGBA *color)
{
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
g_return_if_fail (color != NULL);
GTK_COLOR_CHOOSER_GET_IFACE (chooser)->set_rgba (chooser, color);
}
/**
* gtk_color_chooser_get_use_alpha:
* @chooser: a #GtkColorChooser
*
* Returns whether the color chooser shows the alpha channel.
*
* Returns: %TRUE if the color chooser uses the alpha channel,
* %FALSE if not
*
* Since: 3.4
*/
gboolean
gtk_color_chooser_get_use_alpha (GtkColorChooser *chooser)
{
gboolean use_alpha;
g_return_val_if_fail (GTK_IS_COLOR_CHOOSER (chooser), TRUE);
g_object_get (chooser, "use-alpha", &use_alpha, NULL);
return use_alpha;
}
/**
* gtk_color_chooser_set_use_alpha:
* @chooser: a #GtkColorChooser
* @use_alpha: %TRUE if color chooser should use alpha channel, %FALSE if not
*
* Sets whether or not the color chooser should use the alpha channel.
*
* Since: 3.4
*/
void
gtk_color_chooser_set_use_alpha (GtkColorChooser *chooser,
gboolean use_alpha)
{
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
g_object_set (chooser, "use-alpha", use_alpha, NULL);
}
/**
* gtk_color_chooser_add_palette:
* @chooser: a #GtkColorChooser
* @horizontal: %TRUE if the palette should be displayed in rows,
* %FALSE for columns
* @colors_per_line: the number of colors to show in each row/column
* @n_colors: the total number of elements in @colors
* @colors: (array length=n_colors): the colors of the palette
*
* Adds a palette to the color chooser. If @horizontal is %TRUE,
* the colors are grouped in rows, with @colors_per_line colors
* in each row. If @horizontal is %FALSE, the colors are grouped
* in columns instead.
*
* The default color palette of #GtkColorChooserWidget has
* 27 colors, organized in columns of 3 colors. The default gray
* palette has 9 grays in a single row.
*
* The layout of the color chooser widget works best when the
* palettes have 9-10 columns.
*
* Calling this function is called for the first time has the
* side effect of removing the default color and gray palettes
* from the color chooser.
*/
void
gtk_color_chooser_add_palette (GtkColorChooser *chooser,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors)
{
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
if (GTK_COLOR_CHOOSER_GET_IFACE (chooser)->add_palette)
GTK_COLOR_CHOOSER_GET_IFACE (chooser)->add_palette (chooser, horizontal, colors_per_line, n_colors, colors);
}
cairo_pattern_t *
_gtk_color_chooser_get_checkered_pattern (void)
{
/* need to respect pixman's stride being a multiple of 4 */
static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00 };
static cairo_surface_t *checkered = NULL;
cairo_pattern_t *pattern;
if (checkered == NULL)
checkered = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_A8,
2, 2, 4);
pattern = cairo_pattern_create_for_surface (checkered);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
return pattern;
}
+82
View File
@@ -0,0 +1,82 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_CHOOSER_H__
#define __GTK_COLOR_CHOOSER_H__
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_CHOOSER (gtk_color_chooser_get_type ())
#define GTK_COLOR_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER, GtkColorChooser))
#define GTK_IS_COLOR_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER))
#define GTK_COLOR_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_COLOR_CHOOSER, GtkColorChooserInterface))
typedef struct _GtkColorChooser GtkColorChooser;
typedef struct _GtkColorChooserInterface GtkColorChooserInterface;
struct _GtkColorChooserInterface
{
GTypeInterface base_interface;
/* Methods */
void (* get_rgba) (GtkColorChooser *chooser,
GdkRGBA *color);
void (* set_rgba) (GtkColorChooser *chooser,
const GdkRGBA *color);
void (* add_palette) (GtkColorChooser *chooser,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors);
/* Signals */
void (* color_activated) (GtkColorChooser *chooser,
const GdkRGBA *color);
/* Padding */
gpointer padding[12];
};
GType gtk_color_chooser_get_type (void) G_GNUC_CONST;
void gtk_color_chooser_get_rgba (GtkColorChooser *chooser,
GdkRGBA *color);
void gtk_color_chooser_set_rgba (GtkColorChooser *chooser,
const GdkRGBA *color);
gboolean gtk_color_chooser_get_use_alpha (GtkColorChooser *chooser);
void gtk_color_chooser_set_use_alpha (GtkColorChooser *chooser,
gboolean use_alpha);
void gtk_color_chooser_add_palette (GtkColorChooser *chooser,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors);
G_END_DECLS
#endif /* __GTK_COLOR_CHOOSER_H__ */
+303
View File
@@ -0,0 +1,303 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkdialog.h"
#include "gtkstock.h"
#include "gtkbox.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcolorchooserdialog.h"
#include "gtkcolorchooserwidget.h"
/**
* SECTION:gtkcolorchooserdialog
* @Short_description: A dialog for choosing colors
* @Title: GtkColorChooserDialog
* @See_also: #GtkColorChooser, #GtkDialog
*
* The #GtkColorChooserDialog widget is a dialog for choosing
* a color. It implements the #GtkColorChooser interface.
*
* Since: 3.4
*/
struct _GtkColorChooserDialogPrivate
{
GtkWidget *chooser;
GtkWidget *select_button;
GtkWidget *cancel_button;
};
enum
{
PROP_ZERO,
PROP_RGBA,
PROP_USE_ALPHA,
PROP_SHOW_EDITOR
};
static void gtk_color_chooser_dialog_iface_init (GtkColorChooserInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkColorChooserDialog, gtk_color_chooser_dialog, GTK_TYPE_DIALOG,
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
gtk_color_chooser_dialog_iface_init))
static void
propagate_notify (GObject *o,
GParamSpec *pspec,
GtkColorChooserDialog *cc)
{
g_object_notify (G_OBJECT (cc), pspec->name);
}
static void
color_activated_cb (GtkColorChooser *chooser,
GdkRGBA *color,
GtkDialog *dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_OK);
}
static void
gtk_color_chooser_dialog_init (GtkColorChooserDialog *cc)
{
GtkColorChooserDialogPrivate *priv;
GtkDialog *dialog = GTK_DIALOG (cc);
GtkWidget *action_area, *content_area;
cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc,
GTK_TYPE_COLOR_CHOOSER_DIALOG,
GtkColorChooserDialogPrivate);
priv = cc->priv;
content_area = gtk_dialog_get_content_area (dialog);
action_area = gtk_dialog_get_action_area (dialog);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
gtk_box_set_spacing (GTK_BOX (action_area), 6);
gtk_widget_push_composite_child ();
gtk_window_set_resizable (GTK_WINDOW (cc), FALSE);
/* Create the content area */
priv->chooser = gtk_color_chooser_widget_new ();
gtk_container_set_border_width (GTK_CONTAINER (priv->chooser), 5);
gtk_widget_show (priv->chooser);
gtk_box_pack_start (GTK_BOX (content_area),
priv->chooser, TRUE, TRUE, 0);
g_signal_connect (priv->chooser, "notify::rgba",
G_CALLBACK (propagate_notify), cc);
g_signal_connect (priv->chooser, "notify::show-editor",
G_CALLBACK (propagate_notify), cc);
g_signal_connect (priv->chooser, "color-activated",
G_CALLBACK (color_activated_cb), cc);
/* Create the action area */
priv->cancel_button = gtk_dialog_add_button (dialog,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL);
priv->select_button = gtk_dialog_add_button (dialog,
_("_Select"),
GTK_RESPONSE_OK);
gtk_widget_grab_default (priv->select_button);
gtk_dialog_set_alternative_button_order (dialog,
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_window_set_title (GTK_WINDOW (cc), _("Select a Color"));
gtk_widget_pop_composite_child ();
}
static void
gtk_color_chooser_dialog_response (GtkDialog *dialog,
gint response_id)
{
if (response_id == GTK_RESPONSE_OK)
{
GdkRGBA color;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
}
g_object_set (GTK_COLOR_CHOOSER_DIALOG (dialog)->priv->chooser,
"show-editor", FALSE, NULL);
}
static void
gtk_color_chooser_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorChooserDialog *cd = GTK_COLOR_CHOOSER_DIALOG (object);
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
switch (prop_id)
{
case PROP_RGBA:
{
GdkRGBA color;
gtk_color_chooser_get_rgba (cc, &color);
g_value_set_boxed (value, &color);
}
break;
case PROP_USE_ALPHA:
g_value_set_boolean (value, gtk_color_chooser_get_use_alpha (GTK_COLOR_CHOOSER (cd->priv->chooser)));
break;
case PROP_SHOW_EDITOR:
{
gboolean show_editor;
g_object_get (cd->priv->chooser, "show-editor", &show_editor, NULL);
g_value_set_boolean (value, show_editor);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_chooser_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorChooserDialog *cd = GTK_COLOR_CHOOSER_DIALOG (object);
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
switch (prop_id)
{
case PROP_RGBA:
gtk_color_chooser_set_rgba (cc, g_value_get_boxed (value));
break;
case PROP_USE_ALPHA:
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cd->priv->chooser), g_value_get_boolean (value));
break;
case PROP_SHOW_EDITOR:
g_object_set (cd->priv->chooser,
"show-editor", g_value_get_boolean (value),
NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_chooser_dialog_class_init (GtkColorChooserDialogClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (class);
object_class->get_property = gtk_color_chooser_dialog_get_property;
object_class->set_property = gtk_color_chooser_dialog_set_property;
dialog_class->response = gtk_color_chooser_dialog_response;
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
FALSE, GTK_PARAM_READWRITE));
g_type_class_add_private (class, sizeof (GtkColorChooserDialogPrivate));
}
static void
gtk_color_chooser_dialog_get_rgba (GtkColorChooser *chooser,
GdkRGBA *color)
{
GtkColorChooserDialog *cc = GTK_COLOR_CHOOSER_DIALOG (chooser);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->priv->chooser), color);
}
static void
gtk_color_chooser_dialog_set_rgba (GtkColorChooser *chooser,
const GdkRGBA *color)
{
GtkColorChooserDialog *cc = GTK_COLOR_CHOOSER_DIALOG (chooser);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->chooser), color);
}
static void
gtk_color_chooser_dialog_add_palette (GtkColorChooser *chooser,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors)
{
GtkColorChooserDialog *cc = GTK_COLOR_CHOOSER_DIALOG (chooser);
gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (cc->priv->chooser),
horizontal, colors_per_line, n_colors, colors);
}
static void
gtk_color_chooser_dialog_iface_init (GtkColorChooserInterface *iface)
{
iface->get_rgba = gtk_color_chooser_dialog_get_rgba;
iface->set_rgba = gtk_color_chooser_dialog_set_rgba;
iface->add_palette = gtk_color_chooser_dialog_add_palette;
}
/**
* gtk_color_chooser_dialog_new:
* @title: (allow-none): Title of the dialog, or %NULL
* @parent: (allow-none): Transient parent of the dialog, or %NULL
*
* Creates a new #GtkColorChooserDialog.
*
* Return value: a new #GtkColorChooserDialog
*
* Since: 3.4
*/
GtkWidget *
gtk_color_chooser_dialog_new (const gchar *title,
GtkWindow *parent)
{
GtkColorChooserDialog *dialog;
dialog = g_object_new (GTK_TYPE_COLOR_CHOOSER_DIALOG,
"title", title,
"transient-for", parent,
NULL);
return GTK_WIDGET (dialog);
}
+68
View File
@@ -0,0 +1,68 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_CHOOSER_DIALOG_H__
#define __GTK_COLOR_CHOOSER_DIALOG_H__
#include <gtk/gtkdialog.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_CHOOSER_DIALOG (gtk_color_chooser_dialog_get_type ())
#define GTK_COLOR_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER_DIALOG, GtkColorChooserDialog))
#define GTK_COLOR_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_CHOOSER_DIALOG, GtkColorChooserDialogClass))
#define GTK_IS_COLOR_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER_DIALOG))
#define GTK_IS_COLOR_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_CHOOSER_DIALOG))
#define GTK_COLOR_CHOOSER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_CHOOSER_DIALOG, GtkColorChooserDialogClass))
typedef struct _GtkColorChooserDialog GtkColorChooserDialog;
typedef struct _GtkColorChooserDialogPrivate GtkColorChooserDialogPrivate;
typedef struct _GtkColorChooserDialogClass GtkColorChooserDialogClass;
struct _GtkColorChooserDialog
{
GtkDialog parent_instance;
/*< private >*/
GtkColorChooserDialogPrivate *priv;
};
struct _GtkColorChooserDialogClass
{
GtkDialogClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
GType gtk_color_chooser_dialog_get_type (void) G_GNUC_CONST;
GtkWidget * gtk_color_chooser_dialog_new (const gchar *title,
GtkWindow *parent);
G_END_DECLS
#endif /* __GTK_COLOR_CHOOSER_DIALOG_H__ */
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2012 Red Hat, Inc.
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_COLOR_CHOOSER_PRIVATE_H__
#define __GTK_COLOR_CHOOSER_PRIVATE_H__
#include "gtkcolorchooser.h"
G_BEGIN_DECLS
void _gtk_color_chooser_color_activated (GtkColorChooser *chooser,
const GdkRGBA *color);
cairo_pattern_t * _gtk_color_chooser_get_checkered_pattern (void);
G_END_DECLS
#endif /* ! __GTK_COLOR_CHOOSER_PRIVATE_H__ */
+803
View File
@@ -0,0 +1,803 @@
/* GTK - The GIMP Toolkit
*
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcolorchooserwidget.h"
#include "gtkcoloreditorprivate.h"
#include "gtkcolorswatchprivate.h"
#include "gtkbox.h"
#include "gtkgrid.h"
#include "gtklabel.h"
#include "gtkorientable.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtksizegroup.h"
#include <math.h>
/**
* SECTION:gtkcolorchooserwidget
* @Short_description: A widget for choosing colors
* @Title: GtkColorChooserWidget
* @See_also: #GtkColorChooserDialog
*
* The #GtkColorChooserWidget widget lets the user select a
* color. By default, the chooser presents a prefined palette
* of colors, plus a small number of settable custom colors.
* It is also possible to select a different color with the
* single-color editor. To enter the single-color editing mode,
* use the context menu of any color of the palette, or use the
* '+' button to add a new custom color.
*
* The chooser automatically remembers the last selection, as well
* as custom colors.
*
* To change the initially selected color, use gtk_color_chooser_set_rgba().
* To get the selected font use gtk_color_chooser_get_rgba().
*
* The #GtkColorChooserWidget is used in the #GtkColorChooserDialog
* to provide a dialog for selecting colors.
*
* Since: 3.4
*/
struct _GtkColorChooserWidgetPrivate
{
GtkWidget *palette;
GtkWidget *editor;
GtkSizeGroup *size_group;
GtkWidget *custom_label;
GtkWidget *custom;
GtkWidget *button;
GtkColorSwatch *current;
gboolean use_alpha;
gboolean has_default_palette;
GSettings *settings;
};
enum
{
PROP_ZERO,
PROP_RGBA,
PROP_USE_ALPHA,
PROP_SHOW_EDITOR
};
static void gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkColorChooserWidget, gtk_color_chooser_widget, GTK_TYPE_BOX,
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
gtk_color_chooser_widget_iface_init))
static void
select_swatch (GtkColorChooserWidget *cc,
GtkColorSwatch *swatch)
{
GdkRGBA color;
if (cc->priv->current == swatch)
return;
if (cc->priv->current != NULL)
gtk_widget_unset_state_flags (GTK_WIDGET (cc->priv->current), GTK_STATE_FLAG_SELECTED);
gtk_widget_set_state_flags (GTK_WIDGET (swatch), GTK_STATE_FLAG_SELECTED, FALSE);
cc->priv->current = swatch;
gtk_color_swatch_get_rgba (swatch, &color);
g_settings_set (cc->priv->settings, "selected-color", "(bdddd)",
TRUE, color.red, color.green, color.blue, color.alpha);
g_object_notify (G_OBJECT (cc), "rgba");
}
static void
swatch_activate (GtkColorSwatch *swatch,
GtkColorChooserWidget *cc)
{
GdkRGBA color;
gtk_color_swatch_get_rgba (swatch, &color);
_gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
}
static void
swatch_customize (GtkColorSwatch *swatch,
GtkColorChooserWidget *cc)
{
GdkRGBA color;
gtk_color_swatch_get_rgba (swatch, &color);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
gtk_widget_hide (cc->priv->palette);
gtk_widget_show (cc->priv->editor);
g_object_notify (G_OBJECT (cc), "show-editor");
}
static void
swatch_selected (GtkColorSwatch *swatch,
GtkStateFlags previous,
GtkColorChooserWidget *cc)
{
GtkStateFlags flags;
flags = gtk_widget_get_state_flags (GTK_WIDGET (swatch));
if ((flags & GTK_STATE_FLAG_SELECTED) != (previous & GTK_STATE_FLAG_SELECTED) &&
(flags & GTK_STATE_FLAG_SELECTED) != 0)
select_swatch (cc, swatch);
}
static void
connect_swatch_signals (GtkWidget *p,
gpointer data)
{
g_signal_connect (p, "activate", G_CALLBACK (swatch_activate), data);
g_signal_connect (p, "customize", G_CALLBACK (swatch_customize), data);
g_signal_connect (p, "state-flags-changed", G_CALLBACK (swatch_selected), data);
}
static void
button_activate (GtkColorSwatch *swatch,
GtkColorChooserWidget *cc)
{
/* somewhat random, makes the hairline nicely visible */
GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
gtk_widget_hide (cc->priv->palette);
gtk_widget_show (cc->priv->editor);
g_object_notify (G_OBJECT (cc), "show-editor");
}
static void
connect_button_signals (GtkWidget *p,
gpointer data)
{
g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
}
static void
save_custom_colors (GtkColorChooserWidget *cc)
{
GVariantBuilder builder;
GVariant *variant;
GdkRGBA color;
GList *children, *l;
GtkWidget *child;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dddd)"));
children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
for (l = g_list_nth (children, 1); l != NULL; l = l->next)
{
child = l->data;
if (gtk_color_swatch_get_rgba (GTK_COLOR_SWATCH (child), &color))
g_variant_builder_add (&builder, "(dddd)",
color.red, color.green, color.blue, color.alpha);
}
variant = g_variant_builder_end (&builder);
g_settings_set_value (cc->priv->settings, "custom-colors", variant);
g_list_free (children);
}
static void
connect_custom_signals (GtkWidget *p,
gpointer data)
{
connect_swatch_signals (p, data);
g_signal_connect_swapped (p, "notify::rgba",
G_CALLBACK (save_custom_colors), data);
}
static void
gtk_color_chooser_widget_set_use_alpha (GtkColorChooserWidget *cc,
gboolean use_alpha)
{
GList *children, *l;
GList *palettes, *p;
GtkWidget *swatch;
GtkWidget *grid;
cc->priv->use_alpha = use_alpha;
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cc->priv->editor), use_alpha);
palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
for (p = palettes; p; p = p->next)
{
grid = p->data;
if (!GTK_IS_CONTAINER (grid))
continue;
children = gtk_container_get_children (GTK_CONTAINER (grid));
for (l = children; l; l = l->next)
{
swatch = l->data;
gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (swatch), use_alpha);
}
g_list_free (children);
}
g_list_free (palettes);
gtk_widget_queue_draw (GTK_WIDGET (cc));
}
static void
gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
gboolean show_editor)
{
if (show_editor)
{
GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
if (cc->priv->current)
gtk_color_swatch_get_rgba (cc->priv->current, &color);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
}
gtk_widget_set_visible (cc->priv->editor, show_editor);
gtk_widget_set_visible (cc->priv->palette, !show_editor);
}
/* UI construction {{{1 */
static guint
scale_round (gdouble value, gdouble scale)
{
value = floor (value * scale + 0.5);
value = MAX (value, 0);
value = MIN (value, scale);
return (guint)value;
}
gchar *
accessible_color_name (GdkRGBA *color)
{
if (color->alpha < 1.0)
return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"),
scale_round (color->red, 100),
scale_round (color->green, 100),
scale_round (color->blue, 100),
scale_round (color->alpha, 100));
else
return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%"),
scale_round (color->red, 100),
scale_round (color->green, 100),
scale_round (color->blue, 100));
}
static void
add_palette (GtkColorChooserWidget *cc,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors,
const gchar **names)
{
GtkWidget *grid;
GtkWidget *p;
AtkObject *atk_obj;
gint line, pos;
gint i;
gint left, right;
grid = gtk_grid_new ();
gtk_widget_set_margin_bottom (grid, 12);
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);
left = 0;
right = colors_per_line - 1;
if (gtk_widget_get_direction (GTK_WIDGET (cc)) == GTK_TEXT_DIR_RTL)
{
i = left;
left = right;
right = i;
}
for (i = 0; i < n_colors; i++)
{
p = gtk_color_swatch_new ();
atk_obj = gtk_widget_get_accessible (p);
if (names)
{
atk_object_set_description (atk_obj,
g_dpgettext2 (GETTEXT_PACKAGE, "Color name", names[i]));
}
else
{
gchar *text, *name;
name = accessible_color_name (&colors[i]);
text = g_strdup_printf (_("Color: %s"), name);
atk_object_set_description (atk_obj, text);
g_free (text);
g_free (name);
}
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &colors[i]);
connect_swatch_signals (p, cc);
line = i / colors_per_line;
pos = i % colors_per_line;
if (horizontal)
{
if (pos == left)
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_LEFT);
else if (pos == right)
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_RIGHT);
gtk_grid_attach (GTK_GRID (grid), p, pos, line, 1, 1);
}
else
{
if (pos == 0)
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_TOP);
else if (pos == colors_per_line - 1)
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_BOTTOM);
gtk_grid_attach (GTK_GRID (grid), p, line, pos, 1, 1);
}
}
gtk_widget_show_all (grid);
}
static void
remove_default_palette (GtkColorChooserWidget *cc)
{
GList *children, *l;
GtkWidget *widget;
if (!cc->priv->has_default_palette)
return;
children = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
for (l = children; l; l = l->next)
{
widget = l->data;
if (widget == cc->priv->custom_label || widget == cc->priv->custom)
continue;
gtk_container_remove (GTK_CONTAINER (cc->priv->palette), widget);
}
g_list_free (children);
cc->priv->has_default_palette = FALSE;
}
static void
add_default_palette (GtkColorChooserWidget *cc)
{
const gchar *default_colors[9][3] = {
{ "#ef2929", "#cc0000", "#a40000" }, /* Scarlet Red */
{ "#fcaf3e", "#f57900", "#ce5c00" }, /* Orange */
{ "#fce94f", "#edd400", "#c4a000" }, /* Butter */
{ "#8ae234", "#73d216", "#4e9a06" }, /* Chameleon */
{ "#729fcf", "#3465a4", "#204a87" }, /* Sky Blue */
{ "#ad7fa8", "#75507b", "#5c3566" }, /* Plum */
{ "#e9b96e", "#c17d11", "#8f5902" }, /* Chocolate */
{ "#888a85", "#555753", "#2e3436" }, /* Aluminum 1 */
{ "#eeeeec", "#d3d7cf", "#babdb6" } /* Aluminum 2 */
};
const gchar *color_names[] = {
NC_("Color name", "Light Scarlet Red"),
NC_("Color name", "Scarlet Red"),
NC_("Color name", "Dark Scarlet Red"),
NC_("Color name", "Light Orange"),
NC_("Color name", "Orange"),
NC_("Color name", "Dark Orange"),
NC_("Color name", "Light Butter"),
NC_("Color name", "Butter"),
NC_("Color name", "Dark Butter"),
NC_("Color name", "Light Chameleon"),
NC_("Color name", "Chameleon"),
NC_("Color name", "Dark Chameleon"),
NC_("Color name", "Light Sky Blue"),
NC_("Color name", "Sky Blue"),
NC_("Color name", "Dark Sky Blue"),
NC_("Color name", "Light Plum"),
NC_("Color name", "Plum"),
NC_("Color name", "Dark Plum"),
NC_("Color name", "Light Chocolate"),
NC_("Color name", "Chocolate"),
NC_("Color name", "Dark Chocolate"),
NC_("Color name", "Light Aluminum 1"),
NC_("Color name", "Aluminum 1"),
NC_("Color name", "Dark Aluminum 1"),
NC_("Color name", "Light Aluminum 2"),
NC_("Color name", "Aluminum 2"),
NC_("Color name", "Dark Aluminum 2")
};
const gchar *default_grays[9] = {
"#000000", /* black */
"#2e3436", /* very dark gray */
"#555753", /* darker gray */
"#888a85", /* dark gray */
"#babdb6", /* medium gray */
"#d3d7cf", /* light gray */
"#eeeeec", /* lighter gray */
"#f3f3f3", /* very light gray */
"#ffffff" /* white */
};
const gchar *gray_names[] = {
NC_("Color name", "Black"),
NC_("Color name", "Very Dark Gray"),
NC_("Color name", "Darker Gray"),
NC_("Color name", "Dark Gray"),
NC_("Color name", "Medium Gray"),
NC_("Color name", "Light Gray"),
NC_("Color name", "Lighter Gray"),
NC_("Color name", "Very Light Gray"),
NC_("Color name", "White")
};
GdkRGBA colors[9*3];
gint i, j;
for (i = 0; i < 9; i++)
for (j = 0; j < 3; j++)
gdk_rgba_parse (&colors[i*3 + j], default_colors[i][j]);
add_palette (cc, FALSE, 3, 9*3, colors, color_names);
for (i = 0; i < 9; i++)
gdk_rgba_parse (&colors[i], default_grays[i]);
add_palette (cc, TRUE, 9, 9, colors, gray_names);
cc->priv->has_default_palette = TRUE;
}
static void
gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
{
GtkWidget *box;
GtkWidget *p;
GtkWidget *button;
GtkWidget *label;
gint i;
GdkRGBA color;
GVariant *variant;
GVariantIter iter;
gboolean selected;
AtkObject *atk_obj;
gchar *text, *name;
cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc, GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetPrivate);
cc->priv->use_alpha = TRUE;
gtk_orientable_set_orientation (GTK_ORIENTABLE (cc), GTK_ORIENTATION_VERTICAL);
cc->priv->palette = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (cc), cc->priv->palette);
add_default_palette (cc);
cc->priv->custom = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set (box, "margin-top", 12, NULL);
gtk_box_pack_end (GTK_BOX (cc->priv->palette), box, FALSE, TRUE, 0);
/* translators: label for the custom section in the color chooser */
cc->priv->custom_label = label = gtk_label_new (_("Custom"));
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_box_pack_end (GTK_BOX (cc->priv->palette), label, FALSE, TRUE, 0);
cc->priv->button = button = gtk_color_swatch_new ();
atk_obj = gtk_widget_get_accessible (button);
atk_object_set_role (atk_obj, ATK_ROLE_PUSH_BUTTON);
atk_object_set_description (atk_obj, _("Create custom color"));
connect_button_signals (button, cc);
gtk_color_swatch_set_icon (GTK_COLOR_SWATCH (button), "list-add-symbolic");
gtk_container_add (GTK_CONTAINER (box), button);
cc->priv->settings = g_settings_new_with_path ("org.gtk.Settings.ColorChooser",
"/org/gtk/settings/color-chooser/");
variant = g_settings_get_value (cc->priv->settings, "custom-colors");
g_variant_iter_init (&iter, variant);
i = 0;
p = NULL;
while (g_variant_iter_loop (&iter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha))
{
i++;
p = gtk_color_swatch_new ();
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &color);
gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
atk_obj = gtk_widget_get_accessible (p);
name = accessible_color_name (&color);
text = g_strdup_printf (_("Custom color %d: %s"), i, name);
atk_object_set_description (atk_obj, text);
g_free (text);
g_free (name);
connect_custom_signals (p, cc);
gtk_container_add (GTK_CONTAINER (box), p);
if (i == 8)
break;
}
g_variant_unref (variant);
cc->priv->editor = gtk_color_editor_new ();
gtk_widget_set_halign (cc->priv->editor, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (cc->priv->editor, TRUE);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add (GTK_CONTAINER (cc), box);
gtk_container_add (GTK_CONTAINER (box), cc->priv->editor);
g_settings_get (cc->priv->settings, "selected-color", "(bdddd)",
&selected,
&color.red, &color.green, &color.blue, &color.alpha);
if (selected)
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc), &color);
gtk_widget_show_all (GTK_WIDGET (cc));
gtk_widget_hide (GTK_WIDGET (cc->priv->editor));
gtk_widget_hide (GTK_WIDGET (cc));
gtk_widget_set_no_show_all (cc->priv->palette, TRUE);
gtk_widget_set_no_show_all (cc->priv->editor, TRUE);
cc->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (cc->priv->size_group, cc->priv->palette);
gtk_size_group_add_widget (cc->priv->size_group, box);
}
/* GObject implementation {{{1 */
static void
gtk_color_chooser_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorChooserWidget *cw = GTK_COLOR_CHOOSER_WIDGET (object);
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
switch (prop_id)
{
case PROP_RGBA:
{
GdkRGBA color;
gtk_color_chooser_get_rgba (cc, &color);
g_value_set_boxed (value, &color);
}
break;
case PROP_USE_ALPHA:
g_value_set_boolean (value, cw->priv->use_alpha);
break;
case PROP_SHOW_EDITOR:
g_value_set_boolean (value, gtk_widget_get_visible (cw->priv->editor));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_chooser_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
switch (prop_id)
{
case PROP_RGBA:
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc),
g_value_get_boxed (value));
break;
case PROP_USE_ALPHA:
gtk_color_chooser_widget_set_use_alpha (cc,
g_value_get_boolean (value));
break;
case PROP_SHOW_EDITOR:
gtk_color_chooser_widget_set_show_editor (cc,
g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_chooser_widget_finalize (GObject *object)
{
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
g_object_unref (cc->priv->size_group);
g_object_unref (cc->priv->settings);
G_OBJECT_CLASS (gtk_color_chooser_widget_parent_class)->finalize (object);
}
static void
gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->get_property = gtk_color_chooser_widget_get_property;
object_class->set_property = gtk_color_chooser_widget_set_property;
object_class->finalize = gtk_color_chooser_widget_finalize;
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
/**
* GtkColorChooserWidget:show-editor:
*
* The ::show-editor property is %TRUE when the color chooser
* is showing the single-color editor. It can be set to switch
* the color chooser into single-color editing mode.
*
* Since: 3.4
*/
g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
FALSE, GTK_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkColorChooserWidgetPrivate));
}
/* GtkColorChooser implementation {{{1 */
static void
gtk_color_chooser_widget_get_rgba (GtkColorChooser *chooser,
GdkRGBA *color)
{
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
if (gtk_widget_get_visible (cc->priv->editor))
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), color);
else if (cc->priv->current)
gtk_color_swatch_get_rgba (cc->priv->current, color);
else
{
color->red = 1.0;
color->green = 1.0;
color->blue = 1.0;
color->alpha = 1.0;
}
if (!cc->priv->use_alpha)
color->alpha = 1.0;
}
static void
add_custom_color (GtkColorChooserWidget *cc,
const GdkRGBA *color)
{
GtkWidget *last;
GtkWidget *p;
GList *children;
children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
if (g_list_length (children) >= 8)
{
last = g_list_last (children)->data;
gtk_widget_destroy (last);
}
g_list_free (children);
p = gtk_color_swatch_new ();
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), color);
gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
connect_custom_signals (p, cc);
gtk_container_add (GTK_CONTAINER (cc->priv->custom), p);
gtk_box_reorder_child (GTK_BOX (cc->priv->custom), p, 1);
gtk_widget_show (p);
select_swatch (cc, GTK_COLOR_SWATCH (p));
save_custom_colors (cc);
}
static void
gtk_color_chooser_widget_set_rgba (GtkColorChooser *chooser,
const GdkRGBA *color)
{
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
GList *children, *l;
GList *palettes, *p;
GtkColorSwatch *swatch;
GtkWidget *w;
GdkRGBA c;
palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
for (p = palettes; p; p = p->next)
{
w = p->data;
if (!GTK_IS_GRID (w) && !GTK_IS_BOX (w))
continue;
children = gtk_container_get_children (GTK_CONTAINER (w));
for (l = children; l; l = l->next)
{
swatch = l->data;
gtk_color_swatch_get_rgba (swatch, &c);
if (!cc->priv->use_alpha)
c.alpha = color->alpha;
if (gdk_rgba_equal (color, &c))
{
select_swatch (cc, swatch);
g_list_free (children);
return;
}
}
g_list_free (children);
}
g_list_free (palettes);
add_custom_color (cc, color);
}
static void
gtk_color_chooser_widget_add_palette (GtkColorChooser *chooser,
gboolean horizontal,
gint colors_per_line,
gint n_colors,
GdkRGBA *colors)
{
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
remove_default_palette (cc);
add_palette (cc, horizontal, colors_per_line, n_colors, colors, NULL);
}
static void
gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface)
{
iface->get_rgba = gtk_color_chooser_widget_get_rgba;
iface->set_rgba = gtk_color_chooser_widget_set_rgba;
iface->add_palette = gtk_color_chooser_widget_add_palette;
}
/* Public API {{{1 */
/**
* gtk_color_chooser_widget_new:
*
* Creates a new #GtkColorChooserWidget.
*
* Returns: a new #GtkColorChooserWidget
*
* Since: 3.4
*/
GtkWidget *
gtk_color_chooser_widget_new (void)
{
return g_object_new (GTK_TYPE_COLOR_CHOOSER_WIDGET, NULL);
}
/* vim:set foldmethod=marker: */
+71
View File
@@ -0,0 +1,71 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_CHOOSER_WIDGET_H__
#define __GTK_COLOR_CHOOSER_WIDGET_H__
#include <gtk/gtkbox.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_CHOOSER_WIDGET (gtk_color_chooser_widget_get_type ())
#define GTK_COLOR_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidget))
#define GTK_COLOR_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetClass))
#define GTK_IS_COLOR_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER_WIDGET))
#define GTK_IS_COLOR_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_CHOOSER_WIDGET))
#define GTK_COLOR_CHOOSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetClass))
typedef struct _GtkColorChooserWidget GtkColorChooserWidget;
typedef struct _GtkColorChooserWidgetPrivate GtkColorChooserWidgetPrivate;
typedef struct _GtkColorChooserWidgetClass GtkColorChooserWidgetClass;
struct _GtkColorChooserWidget
{
GtkBox parent_instance;
/*< private >*/
GtkColorChooserWidgetPrivate *priv;
};
struct _GtkColorChooserWidgetClass
{
GtkBoxClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
void (*_gtk_reserved8) (void);
};
GType gtk_color_chooser_widget_get_type (void) G_GNUC_CONST;
GtkWidget * gtk_color_chooser_widget_new (void);
G_END_DECLS
#endif /* __GTK_COLOR_CHOOSER_WIDGET_H__ */
+655
View File
@@ -0,0 +1,655 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* TODO
* - touch
* - accessible relations for popups
* - saving per-application (?)
* - better popup theming
*/
#include "config.h"
#include "gtkcoloreditorprivate.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcolorplaneprivate.h"
#include "gtkcolorscaleprivate.h"
#include "gtkcolorswatchprivate.h"
#include "gtkcolorutils.h"
#include "gtkgrid.h"
#include "gtkorientable.h"
#include "gtkentry.h"
#include "gtkoverlay.h"
#include "gtkadjustment.h"
#include "gtklabel.h"
#include "gtkspinbutton.h"
#include "gtkintl.h"
#include <math.h>
struct _GtkColorEditorPrivate
{
GtkWidget *overlay;
GtkWidget *grid;
GtkWidget *swatch;
GtkWidget *entry;
GtkWidget *h_slider;
GtkWidget *h_popup;
GtkWidget *h_entry;
GtkWidget *a_slider;
GtkWidget *a_popup;
GtkWidget *a_entry;
GtkWidget *sv_plane;
GtkWidget *sv_popup;
GtkWidget *s_entry;
GtkWidget *v_entry;
GtkWidget *current_popup;
GtkWidget *popdown_focus;
GtkAdjustment *h_adj;
GtkAdjustment *s_adj;
GtkAdjustment *v_adj;
GtkAdjustment *a_adj;
guint text_changed : 1;
guint use_alpha : 1;
};
enum
{
PROP_ZERO,
PROP_RGBA,
PROP_USE_ALPHA
};
static void gtk_color_editor_iface_init (GtkColorChooserInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkColorEditor, gtk_color_editor, GTK_TYPE_BOX,
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
gtk_color_editor_iface_init))
static guint
scale_round (gdouble value, gdouble scale)
{
value = floor (value * scale + 0.5);
value = MAX (value, 0);
value = MIN (value, scale);
return (guint)value;
}
static void
entry_set_rgba (GtkColorEditor *editor,
const GdkRGBA *color)
{
gchar *text;
text = g_strdup_printf ("#%02X%02X%02X",
scale_round (color->red, 255),
scale_round (color->green, 255),
scale_round (color->blue, 255));
gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), text);
editor->priv->text_changed = FALSE;
g_free (text);
}
static void
entry_apply (GtkWidget *entry,
GtkColorEditor *editor)
{
GdkRGBA color;
gchar *text;
if (!editor->priv->text_changed)
return;
text = gtk_editable_get_chars (GTK_EDITABLE (editor->priv->entry), 0, -1);
if (gdk_rgba_parse (&color, text))
{
color.alpha = gtk_adjustment_get_value (editor->priv->a_adj);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), &color);
}
editor->priv->text_changed = FALSE;
g_free (text);
}
static gboolean
entry_focus_out (GtkWidget *entry,
GdkEventFocus *event,
GtkColorEditor *editor)
{
entry_apply (entry, editor);
return FALSE;
}
static void
entry_text_changed (GtkWidget *entry,
GParamSpec *pspec,
GtkColorEditor *editor)
{
editor->priv->text_changed = TRUE;
}
static void
hsv_changed (GtkColorEditor *editor)
{
GdkRGBA color;
gdouble h, s, v, a;
h = gtk_adjustment_get_value (editor->priv->h_adj);
s = gtk_adjustment_get_value (editor->priv->s_adj);
v = gtk_adjustment_get_value (editor->priv->v_adj);
a = gtk_adjustment_get_value (editor->priv->a_adj);
gtk_hsv_to_rgb (h, s, v, &color.red, &color.green, &color.blue);
color.alpha = a;
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), &color);
gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), &color);
entry_set_rgba (editor, &color);
g_object_notify (G_OBJECT (editor), "rgba");
}
static void
dismiss_current_popup (GtkColorEditor *editor)
{
if (editor->priv->current_popup)
{
gtk_widget_hide (editor->priv->current_popup);
editor->priv->current_popup = NULL;
if (editor->priv->popdown_focus)
{
gtk_widget_grab_focus (editor->priv->popdown_focus);
editor->priv->popdown_focus = NULL;
}
}
}
static void
popup_edit (GtkWidget *widget,
GtkColorEditor *editor)
{
GtkWidget *popup = NULL;
GtkWidget *toplevel;
GtkWidget *focus;
if (widget == editor->priv->sv_plane)
{
popup = editor->priv->sv_popup;
focus = editor->priv->s_entry;
}
else if (widget == editor->priv->h_slider)
{
popup = editor->priv->h_popup;
focus = editor->priv->h_entry;
}
else if (widget == editor->priv->a_slider)
{
popup = editor->priv->a_popup;
focus = editor->priv->a_entry;
}
if (popup)
{
dismiss_current_popup (editor);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
editor->priv->popdown_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
editor->priv->current_popup = popup;
gtk_widget_show (popup);
gtk_widget_grab_focus (focus);
}
}
static gboolean
popup_key_press (GtkWidget *popup,
GdkEventKey *event,
GtkColorEditor *editor)
{
if (event->keyval == GDK_KEY_Escape)
{
dismiss_current_popup (editor);
return TRUE;
}
return FALSE;
}
static gboolean
get_child_position (GtkOverlay *overlay,
GtkWidget *widget,
GtkAllocation *allocation,
GtkColorEditor *editor)
{
GtkRequisition req;
GtkAllocation alloc;
gint s, e;
gtk_widget_get_preferred_size (widget, &req, NULL);
allocation->width = req.width;
allocation->height = req.height;
if (widget == editor->priv->sv_popup)
{
if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL)
allocation->x = 0;
else
allocation->x = gtk_widget_get_allocated_width (GTK_WIDGET (overlay)) - req.width;
allocation->y = req.height / 3;
}
else if (widget == editor->priv->h_popup)
{
gtk_widget_get_allocation (editor->priv->h_slider, &alloc);
gtk_range_get_slider_range (GTK_RANGE (editor->priv->h_slider), &s, &e);
if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL)
gtk_widget_translate_coordinates (editor->priv->h_slider,
gtk_widget_get_parent (editor->priv->grid),
- req.width, (s + e - req.height) / 2,
&allocation->x, &allocation->y);
else
gtk_widget_translate_coordinates (editor->priv->h_slider,
gtk_widget_get_parent (editor->priv->grid),
alloc.width, (s + e - req.height) / 2,
&allocation->x, &allocation->y);
}
else if (widget == editor->priv->a_popup)
{
gtk_widget_get_allocation (editor->priv->a_slider, &alloc);
gtk_range_get_slider_range (GTK_RANGE (editor->priv->a_slider), &s, &e);
gtk_widget_translate_coordinates (editor->priv->a_slider,
gtk_widget_get_parent (editor->priv->grid),
(s + e - req.width) / 2, - req.height,
&allocation->x, &allocation->y);
}
else
return FALSE;
allocation->x = CLAMP (allocation->x, 0, gtk_widget_get_allocated_width (GTK_WIDGET (overlay)) - req.width);
allocation->y = CLAMP (allocation->y, 0, gtk_widget_get_allocated_height (GTK_WIDGET (overlay)) - req.height);
return TRUE;
}
static void
value_changed (GtkAdjustment *a,
GtkAdjustment *as)
{
gdouble scale;
scale = gtk_adjustment_get_upper (as) / gtk_adjustment_get_upper (a);
g_signal_handlers_block_by_func (as, value_changed, a);
gtk_adjustment_set_value (as, gtk_adjustment_get_value (a) * scale);
g_signal_handlers_unblock_by_func (as, value_changed, a);
}
static GtkAdjustment *
scaled_adjustment (GtkAdjustment *a,
gdouble scale)
{
GtkAdjustment *as;
as = gtk_adjustment_new (gtk_adjustment_get_value (a) * scale,
gtk_adjustment_get_lower (a) * scale,
gtk_adjustment_get_upper (a) * scale,
gtk_adjustment_get_step_increment (a) * scale,
gtk_adjustment_get_page_increment (a) * scale,
gtk_adjustment_get_page_size (a) * scale);
g_signal_connect (a, "value-changed", G_CALLBACK (value_changed), as);
g_signal_connect (as, "value-changed", G_CALLBACK (value_changed), a);
return as;
}
static gboolean
popup_draw (GtkWidget *popup,
cairo_t *cr,
GtkColorEditor *editor)
{
GtkStyleContext *context;
gint width, height;
context = gtk_widget_get_style_context (popup);
width = gtk_widget_get_allocated_width (popup);
height = gtk_widget_get_allocated_height (popup);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_render_frame (context, cr, 0, 0, width, height);
return FALSE;
}
static GtkWidget *
create_popup (GtkColorEditor *editor,
GtkWidget *attach,
GtkWidget *contents)
{
GtkWidget *popup;
g_object_set (contents, "margin", 12, NULL);
popup = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (popup), GTK_STYLE_CLASS_TOOLTIP);
gtk_container_add (GTK_CONTAINER (popup), contents);
gtk_widget_show_all (contents);
gtk_widget_set_no_show_all (popup, TRUE);
g_signal_connect (popup, "draw", G_CALLBACK (popup_draw), editor);
gtk_overlay_add_overlay (GTK_OVERLAY (editor->priv->overlay), popup);
g_signal_connect (attach, "popup-menu", G_CALLBACK (popup_edit), editor);
return popup;
}
static void
gtk_color_editor_init (GtkColorEditor *editor)
{
GtkWidget *grid;
GtkWidget *slider;
GtkWidget *entry;
GtkWidget *swatch;
GtkAdjustment *h_adj, *s_adj, *v_adj, *a_adj;
AtkObject *atk_obj;
GdkRGBA transparent = { 0, 0, 0, 0 };
editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor,
GTK_TYPE_COLOR_EDITOR,
GtkColorEditorPrivate);
editor->priv->use_alpha = TRUE;
editor->priv->h_adj = h_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
editor->priv->s_adj = s_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
editor->priv->v_adj = v_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
editor->priv->a_adj = a_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
g_object_ref_sink (h_adj);
g_object_ref_sink (s_adj);
g_object_ref_sink (v_adj);
g_object_ref_sink (a_adj);
g_signal_connect_swapped (h_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
g_signal_connect_swapped (s_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
g_signal_connect_swapped (v_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
g_signal_connect_swapped (a_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
gtk_widget_push_composite_child ();
/* Construct the main UI */
editor->priv->swatch = swatch = gtk_color_swatch_new ();
gtk_color_swatch_set_selectable (GTK_COLOR_SWATCH (editor->priv->swatch), FALSE);
gtk_widget_set_events (swatch, gtk_widget_get_events (swatch)
& ~(GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_KEY_PRESS_MASK
| GDK_KEY_RELEASE_MASK));
gtk_widget_set_can_focus (swatch, FALSE);
editor->priv->entry = entry = gtk_entry_new ();
atk_obj = gtk_widget_get_accessible (entry);
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
atk_object_set_name (atk_obj, _("Color Name"));
g_signal_connect (entry, "activate", G_CALLBACK (entry_apply), editor);
g_signal_connect (entry, "notify::text", G_CALLBACK (entry_text_changed), editor);
g_signal_connect (entry, "focus-out-event", G_CALLBACK (entry_focus_out), editor);
editor->priv->h_slider = slider = gtk_color_scale_new (h_adj, GTK_COLOR_SCALE_HUE);
gtk_orientable_set_orientation (GTK_ORIENTABLE (slider), GTK_ORIENTATION_VERTICAL);
if (gtk_widget_get_direction (slider) == GTK_TEXT_DIR_RTL)
gtk_style_context_add_class (gtk_widget_get_style_context (slider),
GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE);
else
gtk_style_context_add_class (gtk_widget_get_style_context (slider),
GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW);
editor->priv->sv_plane = gtk_color_plane_new (h_adj, s_adj, v_adj);
gtk_widget_set_size_request (editor->priv->sv_plane, 300, 300);
editor->priv->a_slider = slider = gtk_color_scale_new (a_adj, GTK_COLOR_SCALE_ALPHA);
gtk_orientable_set_orientation (GTK_ORIENTABLE (slider), GTK_ORIENTATION_HORIZONTAL);
gtk_style_context_add_class (gtk_widget_get_style_context (slider),
GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE);
editor->priv->grid = grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
gtk_grid_attach (GTK_GRID (grid), editor->priv->swatch, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->entry, 2, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->h_slider, 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->sv_plane, 1, 1, 2, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->a_slider, 1, 2, 2, 1);
/* This extra margin is necessary so we have room to the sides
* to place the popups as desired
*/
gtk_widget_set_margin_left (grid, 30);
gtk_widget_set_margin_right (grid, 30);
editor->priv->overlay = gtk_overlay_new ();
gtk_widget_override_background_color (editor->priv->overlay, 0, &transparent);
gtk_container_add (GTK_CONTAINER (editor->priv->overlay), grid);
/* Construct the sv popup */
editor->priv->s_entry = entry = gtk_spin_button_new (scaled_adjustment (s_adj, 100), 1, 0);
atk_obj = gtk_widget_get_accessible (entry);
atk_object_set_name (atk_obj, C_("Color channel", "Saturation"));
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
editor->priv->v_entry = entry = gtk_spin_button_new (scaled_adjustment (v_adj, 100), 1, 0);
atk_obj = gtk_widget_get_accessible (entry);
atk_object_set_name (atk_obj, C_("Color channel", "Value"));
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "S")), 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->s_entry, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "V")), 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->v_entry, 1, 1, 1, 1);
editor->priv->sv_popup = create_popup (editor, editor->priv->sv_plane, grid);
/* Construct the h popup */
editor->priv->h_entry = entry = gtk_spin_button_new (scaled_adjustment (h_adj, 100), 1, 0);
atk_obj = gtk_widget_get_accessible (entry);
atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "H")), 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->h_entry, 1, 0, 1, 1);
editor->priv->h_popup = create_popup (editor, editor->priv->h_slider, grid);
/* Construct the a popup */
editor->priv->a_entry = entry = gtk_spin_button_new (scaled_adjustment (a_adj, 100), 1, 0);
atk_obj = gtk_widget_get_accessible (entry);
atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
grid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "A")), 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), editor->priv->a_entry, 1, 0, 1, 1);
editor->priv->a_popup = create_popup (editor, editor->priv->a_slider, grid);
/* Hook up popup positioning */
g_signal_connect (editor->priv->overlay, "get-child-position", G_CALLBACK (get_child_position), editor);
g_signal_connect (editor, "notify::visible", G_CALLBACK (dismiss_current_popup), NULL);
gtk_widget_show_all (editor->priv->overlay);
gtk_container_add (GTK_CONTAINER (editor), editor->priv->overlay);
gtk_widget_pop_composite_child ();
}
static void
gtk_color_editor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
switch (prop_id)
{
case PROP_RGBA:
{
GdkRGBA color;
gtk_color_chooser_get_rgba (cc, &color);
g_value_set_boxed (value, &color);
}
break;
case PROP_USE_ALPHA:
g_value_set_boolean (value, gtk_widget_get_visible (ce->priv->a_slider));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_editor_set_use_alpha (GtkColorEditor *editor,
gboolean use_alpha)
{
if (editor->priv->use_alpha != use_alpha)
{
editor->priv->use_alpha = use_alpha;
gtk_widget_set_visible (editor->priv->a_slider, use_alpha);
gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (editor->priv->swatch), use_alpha);
}
}
static void
gtk_color_editor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
switch (prop_id)
{
case PROP_RGBA:
gtk_color_chooser_set_rgba (cc, g_value_get_boxed (value));
break;
case PROP_USE_ALPHA:
gtk_color_editor_set_use_alpha (ce, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_editor_finalize (GObject *object)
{
GtkColorEditor *editor = GTK_COLOR_EDITOR (object);
g_clear_object (&editor->priv->h_adj);
g_clear_object (&editor->priv->s_adj);
g_clear_object (&editor->priv->v_adj);
g_clear_object (&editor->priv->a_adj);
G_OBJECT_CLASS (gtk_color_editor_parent_class)->finalize (object);
}
static void
gtk_color_editor_class_init (GtkColorEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_color_editor_finalize;
object_class->get_property = gtk_color_editor_get_property;
object_class->set_property = gtk_color_editor_set_property;
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
g_type_class_add_private (class, sizeof (GtkColorEditorPrivate));
}
static void
gtk_color_editor_get_rgba (GtkColorChooser *chooser,
GdkRGBA *color)
{
GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
gdouble h, s, v;
h = gtk_adjustment_get_value (editor->priv->h_adj);
s = gtk_adjustment_get_value (editor->priv->s_adj);
v = gtk_adjustment_get_value (editor->priv->v_adj);
gtk_hsv_to_rgb (h, s, v, &color->red, &color->green, &color->blue);
color->alpha = gtk_adjustment_get_value (editor->priv->a_adj);
}
static void
gtk_color_editor_set_rgba (GtkColorChooser *chooser,
const GdkRGBA *color)
{
GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
gdouble h, s, v;
gtk_rgb_to_hsv (color->red, color->green, color->blue, &h, &s, &v);
gtk_adjustment_set_value (editor->priv->h_adj, h);
gtk_adjustment_set_value (editor->priv->s_adj, s);
gtk_adjustment_set_value (editor->priv->v_adj, v);
gtk_adjustment_set_value (editor->priv->a_adj, color->alpha);
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), color);
gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), color);
entry_set_rgba (editor, color);
g_object_notify (G_OBJECT (editor), "rgba");
}
static void
gtk_color_editor_iface_init (GtkColorChooserInterface *iface)
{
iface->get_rgba = gtk_color_editor_get_rgba;
iface->set_rgba = gtk_color_editor_set_rgba;
}
GtkWidget *
gtk_color_editor_new (void)
{
return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_EDITOR, NULL);
}
+70
View File
@@ -0,0 +1,70 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_EDITOR_H__
#define __GTK_COLOR_EDITOR_H__
#include <gtk/gtkbox.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_EDITOR (gtk_color_editor_get_type ())
#define GTK_COLOR_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_EDITOR, GtkColorEditor))
#define GTK_COLOR_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_EDITOR, GtkColorEditorClass))
#define GTK_IS_COLOR_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_EDITOR))
#define GTK_IS_COLOR_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_EDITOR))
#define GTK_COLOR_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_EDITOR, GtkColorEditorClass))
typedef struct _GtkColorEditor GtkColorEditor;
typedef struct _GtkColorEditorClass GtkColorEditorClass;
typedef struct _GtkColorEditorPrivate GtkColorEditorPrivate;
struct _GtkColorEditor
{
GtkBox parent_instance;
GtkColorEditorPrivate *priv;
};
struct _GtkColorEditorClass
{
GtkBoxClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
G_GNUC_INTERNAL
GType gtk_color_editor_get_type (void) G_GNUC_CONST;
G_GNUC_INTERNAL
GtkWidget * gtk_color_editor_new (void);
G_END_DECLS
#endif /* __GTK_COLOR_EDITOR_H__ */
+449
View File
@@ -0,0 +1,449 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkcolorplaneprivate.h"
#include "gtkcolorutils.h"
#include "gtkaccessible.h"
#include "gtkintl.h"
struct _GtkColorPlanePrivate
{
GtkAdjustment *h_adj;
GtkAdjustment *s_adj;
GtkAdjustment *v_adj;
cairo_surface_t *surface;
gboolean in_drag;
};
G_DEFINE_TYPE (GtkColorPlane, gtk_color_plane, GTK_TYPE_DRAWING_AREA)
static void
sv_to_xy (GtkColorPlane *plane,
gint *x,
gint *y)
{
gdouble s, v;
gint width, height;
width = gtk_widget_get_allocated_width (GTK_WIDGET (plane));
height = gtk_widget_get_allocated_height (GTK_WIDGET (plane));
s = gtk_adjustment_get_value (plane->priv->s_adj);
v = gtk_adjustment_get_value (plane->priv->v_adj);
*x = CLAMP (width * v, 0, width - 1);
*y = CLAMP (height * (1 - s), 0, height - 1);
}
static gboolean
plane_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
gint x, y;
gint width, height;
cairo_set_source_surface (cr, plane->priv->surface, 0, 0);
cairo_paint (cr);
sv_to_xy (plane, &x, &y);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
cairo_move_to (cr, 0, y + 0.5);
cairo_line_to (cr, width, y + 0.5);
cairo_move_to (cr, x + 0.5, 0);
cairo_line_to (cr, x + 0.5, height);
if (gtk_widget_has_visible_focus (widget))
{
cairo_set_line_width (cr, 3.0);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
cairo_stroke_preserve (cr);
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
cairo_stroke (cr);
}
else
{
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8);
cairo_stroke (cr);
}
return FALSE;
}
static void
create_surface (GtkColorPlane *plane)
{
GtkWidget *widget = GTK_WIDGET (plane);
cairo_t *cr;
cairo_surface_t *surface;
gint width, height, stride;
cairo_surface_t *tmp;
guint red, green, blue;
guint32 *data, *p;
gdouble h, s, v;
gdouble r, g, b;
gdouble sf, vf;
gint x, y;
if (!gtk_widget_get_realized (widget))
return;
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
CAIRO_CONTENT_COLOR,
width, height);
if (plane->priv->surface)
cairo_surface_destroy (plane->priv->surface);
plane->priv->surface = surface;
if (width == 1 || height == 1)
return;
stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
data = g_malloc (height * stride);
h = gtk_adjustment_get_value (plane->priv->h_adj);
sf = 1.0 / (height - 1);
vf = 1.0 / (width - 1);
for (y = 0; y < height; y++)
{
s = CLAMP (1.0 - y * sf, 0.0, 1.0);
p = data + y * (stride / 4);
for (x = 0; x < width; x++)
{
v = x * vf;
gtk_hsv_to_rgb (h, s, v, &r, &g, &b);
red = CLAMP (r * 255, 0, 255);
green = CLAMP (g * 255, 0, 255);
blue = CLAMP (b * 255, 0, 255);
p[x] = (red << 16) | (green << 8) | blue;
}
}
tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
width, height, stride);
cr = cairo_create (surface);
cairo_set_source_surface (cr, tmp, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_destroy (tmp);
g_free (data);
}
static gboolean
plane_configure (GtkWidget *widget,
GdkEventConfigure *event)
{
create_surface (GTK_COLOR_PLANE (widget));
return TRUE;
}
static void
set_cross_grab (GtkWidget *widget,
GdkDevice *device,
guint32 time)
{
GdkCursor *cursor;
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (widget)),
GDK_CROSSHAIR);
gdk_device_grab (device,
gtk_widget_get_window (widget),
GDK_OWNERSHIP_NONE,
FALSE,
GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
| GDK_BUTTON_RELEASE_MASK,
cursor,
time);
g_object_unref (cursor);
}
static gboolean
plane_grab_broken (GtkWidget *widget,
GdkEventGrabBroken *event)
{
GTK_COLOR_PLANE (widget)->priv->in_drag = FALSE;
return TRUE;
}
static void
h_changed (GtkColorPlane *plane)
{
create_surface (plane);
gtk_widget_queue_draw (GTK_WIDGET (plane));
}
static void
sv_changed (GtkColorPlane *plane)
{
gtk_widget_queue_draw (GTK_WIDGET (plane));
}
static void
update_color (GtkColorPlane *plane,
gint x,
gint y)
{
GtkWidget *widget = GTK_WIDGET (plane);
gdouble s, v;
s = CLAMP (1 - y * (1.0 / gtk_widget_get_allocated_height (widget)), 0, 1);
v = CLAMP (x * (1.0 / gtk_widget_get_allocated_width (widget)), 0, 1);
gtk_adjustment_set_value (plane->priv->s_adj, s);
gtk_adjustment_set_value (plane->priv->v_adj, v);
gtk_widget_queue_draw (widget);
}
static gboolean
plane_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
if (event->button == GDK_BUTTON_SECONDARY)
{
gboolean handled;
g_signal_emit_by_name (widget, "popup-menu", &handled);
return TRUE;
}
if (plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY)
return FALSE;
plane->priv->in_drag = TRUE;
set_cross_grab (widget, gdk_event_get_device ((GdkEvent*)event), event->time);
update_color (plane, event->x, event->y);
gtk_widget_grab_focus (widget);
return TRUE;
}
static gboolean
plane_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
if (!plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY)
return FALSE;
plane->priv->in_drag = FALSE;
update_color (plane, event->x, event->y);
gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time);
return TRUE;
}
static gboolean
plane_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
if (!plane->priv->in_drag)
return FALSE;
gdk_event_request_motions (event);
update_color (plane, event->x, event->y);
return TRUE;
}
static void
sv_move (GtkColorPlane *plane,
gdouble ds,
gdouble dv)
{
gdouble s, v;
s = gtk_adjustment_get_value (plane->priv->s_adj);
v = gtk_adjustment_get_value (plane->priv->v_adj);
if (s + ds > 1)
{
if (s < 1)
s = 1;
else
goto error;
}
else if (s + ds < 0)
{
if (s > 0)
s = 0;
else
goto error;
}
else
{
s += ds;
}
if (v + dv > 1)
{
if (v < 1)
v = 1;
else
goto error;
}
else if (v + dv < 0)
{
if (v > 0)
v = 0;
else
goto error;
}
else
{
v += dv;
}
gtk_adjustment_set_value (plane->priv->s_adj, s);
gtk_adjustment_set_value (plane->priv->v_adj, v);
return;
error:
gtk_widget_error_bell (GTK_WIDGET (plane));
}
static gboolean
plane_key_press (GtkWidget *widget,
GdkEventKey *event)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
gdouble step;
if ((event->state & GDK_MOD1_MASK) != 0)
step = 0.1;
else
step = 0.01;
if (event->keyval == GDK_KEY_Up ||
event->keyval == GDK_KEY_KP_Up)
sv_move (plane, step, 0);
else if (event->keyval == GDK_KEY_Down ||
event->keyval == GDK_KEY_KP_Down)
sv_move (plane, -step, 0);
else if (event->keyval == GDK_KEY_Left ||
event->keyval == GDK_KEY_KP_Left)
sv_move (plane, 0, -step);
else if (event->keyval == GDK_KEY_Right ||
event->keyval == GDK_KEY_KP_Right)
sv_move (plane, 0, step);
else
return GTK_WIDGET_CLASS (gtk_color_plane_parent_class)->key_press_event (widget, event);
return TRUE;
}
static void
gtk_color_plane_init (GtkColorPlane *plane)
{
AtkObject *atk_obj;
plane->priv = G_TYPE_INSTANCE_GET_PRIVATE (plane,
GTK_TYPE_COLOR_PLANE,
GtkColorPlanePrivate);
gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE);
gtk_widget_set_events (GTK_WIDGET (plane), GDK_KEY_PRESS_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK);
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (plane));
if (GTK_IS_ACCESSIBLE (atk_obj))
{
atk_object_set_name (atk_obj, _("Color Plane"));
atk_object_set_role (atk_obj, ATK_ROLE_COLOR_CHOOSER);
}
}
static void
plane_finalize (GObject *object)
{
GtkColorPlane *plane = GTK_COLOR_PLANE (object);
if (plane->priv->surface)
cairo_surface_destroy (plane->priv->surface);
g_clear_object (&plane->priv->h_adj);
g_clear_object (&plane->priv->s_adj);
g_clear_object (&plane->priv->v_adj);
G_OBJECT_CLASS (gtk_color_plane_parent_class)->finalize (object);
}
static void
gtk_color_plane_class_init (GtkColorPlaneClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->finalize = plane_finalize;
widget_class->draw = plane_draw;
widget_class->configure_event = plane_configure;
widget_class->button_press_event = plane_button_press;
widget_class->button_release_event = plane_button_release;
widget_class->motion_notify_event = plane_motion_notify;
widget_class->grab_broken_event = plane_grab_broken;
widget_class->key_press_event = plane_key_press;
g_type_class_add_private (class, sizeof (GtkColorPlanePrivate));
}
GtkWidget *
gtk_color_plane_new (GtkAdjustment *h_adj,
GtkAdjustment *s_adj,
GtkAdjustment *v_adj)
{
GtkColorPlane *plane;
plane = (GtkColorPlane *) g_object_new (GTK_TYPE_COLOR_PLANE, NULL);
plane->priv->h_adj = g_object_ref_sink (h_adj);
plane->priv->s_adj = g_object_ref_sink (s_adj);
plane->priv->v_adj = g_object_ref_sink (v_adj);
g_signal_connect_swapped (h_adj, "value-changed", G_CALLBACK (h_changed), plane);
g_signal_connect_swapped (s_adj, "value-changed", G_CALLBACK (sv_changed), plane);
g_signal_connect_swapped (v_adj, "value-changed", G_CALLBACK (sv_changed), plane);
return (GtkWidget *)plane;
}
+72
View File
@@ -0,0 +1,72 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_PLANE_H__
#define __GTK_COLOR_PLANE_H__
#include <gtk/gtkdrawingarea.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_PLANE (gtk_color_plane_get_type ())
#define GTK_COLOR_PLANE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_PLANE, GtkColorPlane))
#define GTK_COLOR_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_PLANE, GtkColorPlaneClass))
#define GTK_IS_COLOR_PLANE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_PLANE))
#define GTK_IS_COLOR_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_PLANE))
#define GTK_COLOR_PLANE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_PLANE, GtkColorPlaneClass))
typedef struct _GtkColorPlane GtkColorPlane;
typedef struct _GtkColorPlaneClass GtkColorPlaneClass;
typedef struct _GtkColorPlanePrivate GtkColorPlanePrivate;
struct _GtkColorPlane
{
GtkDrawingArea parent_instance;
GtkColorPlanePrivate *priv;
};
struct _GtkColorPlaneClass
{
GtkDrawingAreaClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
G_GNUC_INTERNAL
GType gtk_color_plane_get_type (void) G_GNUC_CONST;
G_GNUC_INTERNAL
GtkWidget * gtk_color_plane_new (GtkAdjustment *h_adj,
GtkAdjustment *s_adj,
GtkAdjustment *v_adj);
G_END_DECLS
#endif /* __GTK_COLOR_PLANE_H__ */
+362
View File
@@ -0,0 +1,362 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkcolorscaleprivate.h"
#include "gtkcolorchooserprivate.h"
#include "gtkcolorutils.h"
#include "gtkorientable.h"
#include "gtkstylecontext.h"
#include "gtkaccessible.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include <math.h>
struct _GtkColorScalePrivate
{
cairo_surface_t *surface;
gint width, height;
GdkRGBA color;
GtkColorScaleType type;
};
enum
{
PROP_ZERO,
PROP_SCALE_TYPE
};
G_DEFINE_TYPE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE)
static void
gtk_color_scale_get_trough_size (GtkColorScale *scale,
gint *x_offset_out,
gint *y_offset_out,
gint *width_out,
gint *height_out)
{
GtkWidget *widget = GTK_WIDGET (scale);
gint width, height, focus_line_width, focus_padding;
gint x_offset, y_offset;
gint slider_width, slider_height;
gtk_widget_style_get (widget,
"focus-line-width", &focus_line_width,
"focus-padding", &focus_padding,
"slider-width", &slider_width,
"slider-length", &slider_height,
NULL);
width = gtk_widget_get_allocated_width (widget) - 2 * (focus_line_width + focus_padding);
height = gtk_widget_get_allocated_height (widget) - 2 * (focus_line_width + focus_padding);
x_offset = focus_line_width + focus_padding;
y_offset = focus_line_width + focus_padding;
/* if the slider has a vertical shape, draw the trough asymmetric */
if (slider_width > slider_height)
{
if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL)
{
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
x_offset += (gint) floor (slider_width / 2.0);
width = (gint) floor (slider_width / 2.0);
}
else
{
height = (gint) floor (slider_width / 2.0);
}
}
if (width_out)
*width_out = width;
if (height_out)
*height_out = height;
if (x_offset_out)
*x_offset_out = x_offset;
if (y_offset_out)
*y_offset_out = y_offset;
}
static void
create_surface (GtkColorScale *scale)
{
GtkWidget *widget = GTK_WIDGET (scale);
cairo_surface_t *surface;
gint width, height;
if (!gtk_widget_get_realized (widget))
return;
gtk_color_scale_get_trough_size (scale,
NULL, NULL,
&width, &height);
if (!scale->priv->surface ||
width != scale->priv->width ||
height != scale->priv->height)
{
surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
CAIRO_CONTENT_COLOR,
width, height);
if (scale->priv->surface)
cairo_surface_destroy (scale->priv->surface);
scale->priv->surface = surface;
scale->priv->width = width;
scale->priv->height= height;
}
else
surface = scale->priv->surface;
if (width == 1 || height == 1)
return;
if (scale->priv->type == GTK_COLOR_SCALE_HUE)
{
cairo_t *cr;
gint stride;
cairo_surface_t *tmp;
guint red, green, blue;
guint32 *data, *p;
gdouble h;
gdouble r, g, b;
gdouble f;
gint x, y;
stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
data = g_malloc (height * stride);
f = 1.0 / (height - 1);
for (y = 0; y < height; y++)
{
h = CLAMP (y * f, 0.0, 1.0);
p = data + y * (stride / 4);
for (x = 0; x < width; x++)
{
gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b);
red = CLAMP (r * 255, 0, 255);
green = CLAMP (g * 255, 0, 255);
blue = CLAMP (b * 255, 0, 255);
p[x] = (red << 16) | (green << 8) | blue;
}
}
tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
width, height, stride);
cr = cairo_create (surface);
cairo_set_source_surface (cr, tmp, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_destroy (tmp);
g_free (data);
}
else if (scale->priv->type == GTK_COLOR_SCALE_ALPHA)
{
cairo_t *cr;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
GdkRGBA *color;
cr = cairo_create (surface);
cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
cairo_paint (cr);
cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
pattern = _gtk_color_chooser_get_checkered_pattern ();
cairo_matrix_init_scale (&matrix, 0.125, 0.125);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
color = &scale->priv->color;
pattern = cairo_pattern_create_linear (0, 0, width, 0);
cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0);
cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
cairo_destroy (cr);
}
}
static gboolean
scale_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkColorScale *scale = GTK_COLOR_SCALE (widget);
gint width, height, x_offset, y_offset;
cairo_pattern_t *pattern;
create_surface (scale);
gtk_color_scale_get_trough_size (scale,
&x_offset, &y_offset,
&width, &height);
cairo_save (cr);
cairo_translate (cr, x_offset, y_offset);
cairo_rectangle (cr, 0, 0, width, height);
pattern = cairo_pattern_create_for_surface (scale->priv->surface);
if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL &&
gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
{
cairo_matrix_t matrix;
cairo_matrix_init_scale (&matrix, -1, 1);
cairo_matrix_translate (&matrix, -width, 0);
cairo_pattern_set_matrix (pattern, &matrix);
}
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
GTK_WIDGET_CLASS (gtk_color_scale_parent_class)->draw (widget, cr);
return FALSE;
}
static void
gtk_color_scale_init (GtkColorScale *scale)
{
scale->priv = G_TYPE_INSTANCE_GET_PRIVATE (scale,
GTK_TYPE_COLOR_SCALE,
GtkColorScalePrivate);
}
static void
scale_finalize (GObject *object)
{
GtkColorScale *scale = GTK_COLOR_SCALE (object);
if (scale->priv->surface)
cairo_surface_destroy (scale->priv->surface);
G_OBJECT_CLASS (gtk_color_scale_parent_class)->finalize (object);
}
static void
scale_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorScale *scale = GTK_COLOR_SCALE (object);
switch (prop_id)
{
case PROP_SCALE_TYPE:
g_value_set_int (value, scale->priv->type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
scale_set_type (GtkColorScale *scale,
GtkColorScaleType type)
{
AtkObject *atk_obj;
scale->priv->type = type;
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (scale));
if (GTK_IS_ACCESSIBLE (atk_obj))
{
if (type == GTK_COLOR_SCALE_HUE)
atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
else if (type == GTK_COLOR_SCALE_ALPHA)
atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (scale)), ATK_ROLE_COLOR_CHOOSER);
}
}
static void
scale_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorScale *scale = GTK_COLOR_SCALE (object);
switch (prop_id)
{
case PROP_SCALE_TYPE:
scale_set_type (scale, (GtkColorScaleType)g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_scale_class_init (GtkColorScaleClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->finalize = scale_finalize;
object_class->get_property = scale_get_property;
object_class->set_property = scale_set_property;
widget_class->draw = scale_draw;
g_object_class_install_property (object_class, PROP_SCALE_TYPE,
g_param_spec_int ("scale-type", P_("Scale type"), P_("Scale type"),
0, 1, 0,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (class, sizeof (GtkColorScalePrivate));
}
void
gtk_color_scale_set_rgba (GtkColorScale *scale,
const GdkRGBA *color)
{
scale->priv->color = *color;
scale->priv->width = -1; /* force surface refresh */
create_surface (scale);
gtk_widget_queue_draw (GTK_WIDGET (scale));
}
GtkWidget *
gtk_color_scale_new (GtkAdjustment *adjustment,
GtkColorScaleType type)
{
return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SCALE,
"adjustment", adjustment,
"draw-value", FALSE,
"scale-type", type,
NULL);
}
+80
View File
@@ -0,0 +1,80 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_SCALE_H__
#define __GTK_COLOR_SCALE_H__
#include <gtk/gtkscale.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_SCALE (gtk_color_scale_get_type ())
#define GTK_COLOR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_SCALE, GtkColorScale))
#define GTK_COLOR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SCALE, GtkColorScaleClass))
#define GTK_IS_COLOR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_SCALE))
#define GTK_IS_COLOR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SCALE))
#define GTK_COLOR_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_SCALE, GtkColorScaleClass))
typedef struct _GtkColorScale GtkColorScale;
typedef struct _GtkColorScaleClass GtkColorScaleClass;
typedef struct _GtkColorScalePrivate GtkColorScalePrivate;
struct _GtkColorScale
{
GtkScale parent_instance;
GtkColorScalePrivate *priv;
};
struct _GtkColorScaleClass
{
GtkScaleClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
typedef enum
{
GTK_COLOR_SCALE_HUE,
GTK_COLOR_SCALE_ALPHA
} GtkColorScaleType;
G_GNUC_INTERNAL
GType gtk_color_scale_get_type (void) G_GNUC_CONST;
G_GNUC_INTERNAL
GtkWidget * gtk_color_scale_new (GtkAdjustment *adjustment,
GtkColorScaleType type);
G_GNUC_INTERNAL
void gtk_color_scale_set_rgba (GtkColorScale *scale,
const GdkRGBA *color);
G_END_DECLS
#endif /* __GTK_COLOR_SCALE_H__ */
+775
View File
@@ -0,0 +1,775 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkcolorswatchprivate.h"
#include "gtkcolorchooserprivate.h"
#include "gtkroundedboxprivate.h"
#include "gtkthemingbackgroundprivate.h"
#include "gtkdnd.h"
#include "gtkicontheme.h"
#include "gtkmain.h"
#include "gtkmenu.h"
#include "gtkmenuitem.h"
#include "gtkmenushell.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "a11y/gtkcolorswatchaccessible.h"
struct _GtkColorSwatchPrivate
{
GdkRGBA color;
gdouble radius[4];
gchar *icon;
guint has_color : 1;
guint contains_pointer : 1;
guint use_alpha : 1;
guint selectable : 1;
};
enum
{
PROP_ZERO,
PROP_RGBA,
PROP_SELECTABLE
};
enum
{
ACTIVATE,
CUSTOMIZE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
static void
gtk_color_swatch_init (GtkColorSwatch *swatch)
{
swatch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swatch,
GTK_TYPE_COLOR_SWATCH,
GtkColorSwatchPrivate);
gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
gtk_widget_set_events (GTK_WIDGET (swatch), GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_EXPOSURE_MASK
| GDK_ENTER_NOTIFY_MASK
| GDK_LEAVE_NOTIFY_MASK);
swatch->priv->use_alpha = TRUE;
swatch->priv->selectable = TRUE;
}
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
#define ACTIVE_BADGE_RADIUS 10
static gboolean
swatch_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkColorSwatch *swatch = (GtkColorSwatch*)widget;
GtkThemingBackground background;
gdouble width, height;
GtkStyleContext *context;
GtkStateFlags state;
GtkIconTheme *theme;
GtkIconInfo *icon_info = NULL;
theme = gtk_icon_theme_get_default ();
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
cairo_save (cr);
gtk_style_context_save (context);
gtk_style_context_set_state (context, state);
_gtk_theming_background_init_from_context (&background, context,
0, 0, width, height,
GTK_JUNCTION_NONE);
if (swatch->priv->has_color)
{
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
if (swatch->priv->use_alpha)
{
cairo_save (cr);
_gtk_rounded_box_path (&background.clip_box, cr);
cairo_clip_preserve (cr);
cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
cairo_fill_preserve (cr);
pattern = _gtk_color_chooser_get_checkered_pattern ();
cairo_matrix_init_scale (&matrix, 0.125, 0.125);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_restore (cr);
background.bg_color = swatch->priv->color;
}
else
{
background.bg_color = swatch->priv->color;
background.bg_color.alpha = 1.0;
}
_gtk_theming_background_render (&background, cr);
}
else
_gtk_theming_background_render (&background, cr);
gtk_render_frame (context, cr,
0, 0, width, height);
if (gtk_widget_has_visible_focus (widget))
{
cairo_set_line_width (cr, 2);
if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5)
cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
else
cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
_gtk_rounded_box_shrink (&background.clip_box, 3, 3, 3, 3);
_gtk_rounded_box_path (&background.clip_box, cr);
cairo_stroke (cr);
}
if (swatch->priv->icon)
{
icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16,
GTK_ICON_LOOKUP_GENERIC_FALLBACK
| GTK_ICON_LOOKUP_USE_BUILTIN);
}
else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
{
GdkRGBA bg, border;
GtkBorder border_width;
GIcon *gicon;
gtk_style_context_add_class (context, "color-active-badge");
_gtk_theming_background_init_from_context (&background, context,
(width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2,
2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS,
GTK_JUNCTION_NONE);
if (_gtk_theming_background_has_background_image (&background))
{
_gtk_theming_background_render (&background, cr);
}
else
{
gtk_style_context_get_background_color (context, state, &bg);
gtk_style_context_get_border_color (context, state, &border);
gtk_style_context_get_border (context, state, &border_width);
cairo_new_sub_path (cr);
cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI);
cairo_close_path (cr);
gdk_cairo_set_source_rgba (cr, &bg);
cairo_fill_preserve (cr);
gdk_cairo_set_source_rgba (cr, &border);
cairo_set_line_width (cr, border_width.left);
cairo_stroke (cr);
gicon = g_themed_icon_new ("object-select-symbolic");
/* fallback for themes that don't have object-select-symbolic */
g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");
icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
GTK_ICON_LOOKUP_GENERIC_FALLBACK
| GTK_ICON_LOOKUP_USE_BUILTIN);
g_object_unref (gicon);
}
}
if (icon_info != NULL)
{
GdkPixbuf *pixbuf;
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context,
NULL, NULL);
if (pixbuf != NULL)
{
gtk_render_icon (context, cr, pixbuf,
(width - gdk_pixbuf_get_width (pixbuf)) / 2,
(height - gdk_pixbuf_get_height (pixbuf)) / 2);
g_object_unref (pixbuf);
}
gtk_icon_info_free (icon_info);
}
cairo_restore (cr);
gtk_style_context_restore (context);
return FALSE;
}
static void
drag_set_color_icon (GdkDragContext *context,
const GdkRGBA *color)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 48, 32);
cr = cairo_create (surface);
gdk_cairo_set_source_rgba (cr, color);
cairo_paint (cr);
cairo_surface_set_device_offset (surface, -4, -4);
gtk_drag_set_icon_surface (context, surface);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
static void
swatch_drag_begin (GtkWidget *widget,
GdkDragContext *context)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
GdkRGBA color;
gtk_color_swatch_get_rgba (swatch, &color);
drag_set_color_icon (context, &color);
}
static void
swatch_drag_data_get (GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
guint16 vals[4];
GdkRGBA color;
gtk_color_swatch_get_rgba (swatch, &color);
vals[0] = color.red * 0xffff;
vals[1] = color.green * 0xffff;
vals[2] = color.blue * 0xffff;
vals[3] = color.alpha * 0xffff;
gtk_selection_data_set (selection_data,
gdk_atom_intern_static_string ("application/x-color"),
16, (guchar *)vals, 8);
}
static void
swatch_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time)
{
gint length;
guint16 *vals;
GdkRGBA color;
length = gtk_selection_data_get_length (selection_data);
if (length < 0)
return;
/* We accept drops with the wrong format, since the KDE color
* chooser incorrectly drops application/x-color with format 8.
*/
if (length != 8)
{
g_warning ("Received invalid color data\n");
return;
}
vals = (guint16 *) gtk_selection_data_get_data (selection_data);
color.red = (gdouble)vals[0] / 0xffff;
color.green = (gdouble)vals[1] / 0xffff;
color.blue = (gdouble)vals[2] / 0xffff;
color.alpha = (gdouble)vals[3] / 0xffff;
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
}
static void
swatch_get_preferred_width (GtkWidget *widget,
gint *min,
gint *nat)
{
*min = *nat = 48;
}
static void
swatch_get_preferred_height (GtkWidget *widget,
gint *min,
gint *nat)
{
*min = *nat = 32;
}
static gboolean
swatch_key_press (GtkWidget *widget,
GdkEventKey *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
if (event->keyval == GDK_KEY_space ||
event->keyval == GDK_KEY_Return ||
event->keyval == GDK_KEY_ISO_Enter||
event->keyval == GDK_KEY_KP_Enter ||
event->keyval == GDK_KEY_KP_Space)
{
if (swatch->priv->has_color &&
swatch->priv->selectable &&
(gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0)
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
else
g_signal_emit (swatch, signals[ACTIVATE], 0);
return TRUE;
}
if (GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->key_press_event (widget, event))
return TRUE;
return FALSE;
}
static gboolean
swatch_enter_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
swatch->priv->contains_pointer = TRUE;
return FALSE;
}
static gboolean
swatch_leave_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
swatch->priv->contains_pointer = FALSE;
return FALSE;
}
static void
emit_customize (GtkColorSwatch *swatch)
{
g_signal_emit (swatch, signals[CUSTOMIZE], 0);
}
static void
popup_position_func (GtkMenu *menu,
gint *x,
gint *y,
gboolean *push_in,
gpointer user_data)
{
GtkWidget *widget;
GtkRequisition req;
gint root_x, root_y;
GdkScreen *screen;
GdkWindow *window;
GdkRectangle monitor;
gint monitor_num;
widget = GTK_WIDGET (user_data);
g_return_if_fail (gtk_widget_get_realized (widget));
window = gtk_widget_get_window (widget);
screen = gtk_widget_get_screen (widget);
monitor_num = gdk_screen_get_monitor_at_window (screen, window);
if (monitor_num < 0)
monitor_num = 0;
gtk_menu_set_monitor (menu, monitor_num);
gdk_window_get_origin (window, &root_x, &root_y);
gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
/* Put corner of menu centered on swatch */
*x = root_x + gtk_widget_get_allocated_width (widget) / 2;
*y = root_y + gtk_widget_get_allocated_height (widget) / 2;
/* Ensure sanity */
gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
*x = CLAMP (*x, monitor.x, MAX (monitor.x, monitor.width - req.width));
*y = CLAMP (*y, monitor.y, MAX (monitor.y, monitor.height - req.height));
}
static void
do_popup (GtkWidget *swatch,
GdkEventButton *event)
{
GtkWidget *menu;
GtkWidget *item;
menu = gtk_menu_new ();
item = gtk_menu_item_new_with_mnemonic (_("_Customize"));
gtk_menu_attach_to_widget (GTK_MENU (menu), swatch, NULL);
g_signal_connect_swapped (item, "activate",
G_CALLBACK (emit_customize), swatch);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show_all (item);
if (event)
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
NULL, NULL, event->button, event->time);
else
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
popup_position_func, swatch,
0, gtk_get_current_event_time ());
}
static gboolean
swatch_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
gtk_widget_grab_focus (widget);
if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
swatch->priv->has_color)
{
do_popup (widget, event);
return TRUE;
}
else if (event->type == GDK_2BUTTON_PRESS &&
event->button == GDK_BUTTON_PRIMARY)
{
g_signal_emit (swatch, signals[ACTIVATE], 0);
return TRUE;
}
return FALSE;
}
static gboolean
swatch_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
GtkStateFlags flags;
if (event->button == GDK_BUTTON_PRIMARY &&
swatch->priv->contains_pointer)
{
flags = gtk_widget_get_state_flags (widget);
if (!swatch->priv->has_color)
{
g_signal_emit (swatch, signals[ACTIVATE], 0);
return TRUE;
}
else if (swatch->priv->selectable &&
(flags & GTK_STATE_FLAG_SELECTED) == 0)
{
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
return TRUE;
}
}
return FALSE;
}
static void
swatch_realize (GtkWidget *widget)
{
GtkAllocation allocation;
GdkWindow *window;
GdkWindowAttr attributes;
gint attributes_mask;
gtk_widget_set_realized (widget, TRUE);
gtk_widget_get_allocation (widget, &allocation);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual (widget);
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
gdk_window_set_user_data (window, widget);
gtk_widget_set_window (widget, window);
}
static gboolean
swatch_popup_menu (GtkWidget *swatch)
{
do_popup (swatch, NULL);
return TRUE;
}
/* GObject implementation {{{1 */
static void
swatch_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
GdkRGBA color;
switch (prop_id)
{
case PROP_RGBA:
gtk_color_swatch_get_rgba (swatch, &color);
g_value_set_boxed (value, &color);
break;
case PROP_SELECTABLE:
g_value_set_boolean (value, gtk_color_swatch_get_selectable (swatch));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
swatch_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
switch (prop_id)
{
case PROP_RGBA:
gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
break;
case PROP_SELECTABLE:
gtk_color_swatch_set_selectable (swatch, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
swatch_finalize (GObject *object)
{
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
g_free (swatch->priv->icon);
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
}
static void
gtk_color_swatch_class_init (GtkColorSwatchClass *class)
{
GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
GObjectClass *object_class = (GObjectClass *)class;
object_class->get_property = swatch_get_property;
object_class->set_property = swatch_set_property;
object_class->finalize = swatch_finalize;
widget_class->get_preferred_width = swatch_get_preferred_width;
widget_class->get_preferred_height = swatch_get_preferred_height;
widget_class->draw = swatch_draw;
widget_class->drag_begin = swatch_drag_begin;
widget_class->drag_data_get = swatch_drag_data_get;
widget_class->drag_data_received = swatch_drag_data_received;
widget_class->key_press_event = swatch_key_press;
widget_class->popup_menu = swatch_popup_menu;
widget_class->button_press_event = swatch_button_press;
widget_class->button_release_event = swatch_button_release;
widget_class->enter_notify_event = swatch_enter_notify;
widget_class->leave_notify_event = swatch_leave_notify;
widget_class->realize = swatch_realize;
signals[ACTIVATE] =
g_signal_new ("activate",
GTK_TYPE_COLOR_SWATCH,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkColorSwatchClass, activate),
NULL, NULL, NULL, G_TYPE_NONE, 0);
signals[CUSTOMIZE] =
g_signal_new ("customize",
GTK_TYPE_COLOR_SWATCH,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkColorSwatchClass, customize),
NULL, NULL, NULL, G_TYPE_NONE, 0);
g_object_class_install_property (object_class, PROP_RGBA,
g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
GDK_TYPE_RGBA, GTK_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_SELECTABLE,
g_param_spec_boolean ("selectable", P_("Selectable"), P_("Whether the swatch is selectable"),
TRUE, GTK_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkColorSwatchPrivate));
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE);
}
/* Public API {{{1 */
GtkWidget *
gtk_color_swatch_new (void)
{
return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SWATCH, NULL);
}
static const GtkTargetEntry dnd_targets[] = {
{ "application/x-color", 0 }
};
void
gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
const GdkRGBA *color)
{
GtkStyleContext *context;
context = gtk_widget_get_style_context (GTK_WIDGET (swatch));
if (!swatch->priv->has_color)
{
gtk_drag_source_set (GTK_WIDGET (swatch),
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
dnd_targets, G_N_ELEMENTS (dnd_targets),
GDK_ACTION_COPY | GDK_ACTION_MOVE);
}
else
{
gtk_style_context_remove_class (context, "color-light");
gtk_style_context_remove_class (context, "color-dark");
}
swatch->priv->has_color = TRUE;
swatch->priv->color = *color;
if (INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) > 0.5)
gtk_style_context_add_class (context, "color-light");
else
gtk_style_context_add_class (context, "color-dark");
gtk_widget_queue_draw (GTK_WIDGET (swatch));
g_object_notify (G_OBJECT (swatch), "rgba");
}
gboolean
gtk_color_swatch_get_rgba (GtkColorSwatch *swatch,
GdkRGBA *color)
{
if (swatch->priv->has_color)
{
color->red = swatch->priv->color.red;
color->green = swatch->priv->color.green;
color->blue = swatch->priv->color.blue;
color->alpha = swatch->priv->color.alpha;
return TRUE;
}
else
{
color->red = 1.0;
color->green = 1.0;
color->blue = 1.0;
color->alpha = 1.0;
return FALSE;
}
}
void
gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
const gchar *icon)
{
swatch->priv->icon = g_strdup (icon);
gtk_widget_queue_draw (GTK_WIDGET (swatch));
}
void
gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
gboolean can_drop)
{
if (can_drop)
{
gtk_drag_dest_set (GTK_WIDGET (swatch),
GTK_DEST_DEFAULT_HIGHLIGHT |
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_DROP,
dnd_targets, G_N_ELEMENTS (dnd_targets),
GDK_ACTION_COPY);
}
else
{
gtk_drag_dest_unset (GTK_WIDGET (swatch));
}
}
void
gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
gboolean use_alpha)
{
swatch->priv->use_alpha = use_alpha;
gtk_widget_queue_draw (GTK_WIDGET (swatch));
}
void
gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
gboolean selectable)
{
if (selectable == swatch->priv->selectable)
return;
swatch->priv->selectable = selectable;
g_object_notify (G_OBJECT (swatch), "selectable");
}
gboolean
gtk_color_swatch_get_selectable (GtkColorSwatch *swatch)
{
return swatch->priv->selectable;
}
/* vim:set foldmethod=marker: */
+101
View File
@@ -0,0 +1,101 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_SWATCH_H__
#define __GTK_COLOR_SWATCH_H__
#include <gtk/gtkdrawingarea.h>
G_BEGIN_DECLS
#define GTK_TYPE_COLOR_SWATCH (gtk_color_swatch_get_type ())
#define GTK_COLOR_SWATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_SWATCH, GtkColorSwatch))
#define GTK_COLOR_SWATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SWATCH, GtkColorSwatchClass))
#define GTK_IS_COLOR_SWATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_SWATCH))
#define GTK_IS_COLOR_SWATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SWATCH))
#define GTK_COLOR_SWATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_SWATCH, GtkColorSwatchClass))
typedef struct _GtkColorSwatch GtkColorSwatch;
typedef struct _GtkColorSwatchClass GtkColorSwatchClass;
typedef struct _GtkColorSwatchPrivate GtkColorSwatchPrivate;
struct _GtkColorSwatch
{
GtkWidget parent;
/*< private >*/
GtkColorSwatchPrivate *priv;
};
struct _GtkColorSwatchClass
{
GtkWidgetClass parent_class;
void ( * activate) (GtkColorSwatch *swatch);
void ( * customize) (GtkColorSwatch *swatch);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
};
G_GNUC_INTERNAL
GType gtk_color_swatch_get_type (void) G_GNUC_CONST;
G_GNUC_INTERNAL
GtkWidget * gtk_color_swatch_new (void);
G_GNUC_INTERNAL
void gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
const GdkRGBA *color);
G_GNUC_INTERNAL
gboolean gtk_color_swatch_get_rgba (GtkColorSwatch *swatch,
GdkRGBA *color);
G_GNUC_INTERNAL
void gtk_color_swatch_set_hsva (GtkColorSwatch *swatch,
gdouble h,
gdouble s,
gdouble v,
gdouble a);
G_GNUC_INTERNAL
void gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
gboolean can_drop);
G_GNUC_INTERNAL
void gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
const gchar *icon);
G_GNUC_INTERNAL
void gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
gboolean use_alpha);
G_GNUC_INTERNAL
void gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
gboolean selectable);
G_GNUC_INTERNAL
gboolean gtk_color_swatch_get_selectable (GtkColorSwatch *swatch);
G_END_DECLS
#endif /* __GTK_COLOR_SWATCH_H__ */
+260
View File
@@ -0,0 +1,260 @@
/* Color utilities
*
* Copyright (C) 1999 The Free Software Foundation
*
* Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
* Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
* Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include "gtkcolorutils.h"
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
/* Converts from HSV to RGB */
static void
hsv_to_rgb (gdouble *h,
gdouble *s,
gdouble *v)
{
gdouble hue, saturation, value;
gdouble f, p, q, t;
if (*s == 0.0)
{
*h = *v;
*s = *v;
*v = *v; /* heh */
}
else
{
hue = *h * 6.0;
saturation = *s;
value = *v;
if (hue == 6.0)
hue = 0.0;
f = hue - (int) hue;
p = value * (1.0 - saturation);
q = value * (1.0 - saturation * f);
t = value * (1.0 - saturation * (1.0 - f));
switch ((int) hue)
{
case 0:
*h = value;
*s = t;
*v = p;
break;
case 1:
*h = q;
*s = value;
*v = p;
break;
case 2:
*h = p;
*s = value;
*v = t;
break;
case 3:
*h = p;
*s = q;
*v = value;
break;
case 4:
*h = t;
*s = p;
*v = value;
break;
case 5:
*h = value;
*s = p;
*v = q;
break;
default:
g_assert_not_reached ();
}
}
}
/* Converts from RGB to HSV */
static void
rgb_to_hsv (gdouble *r,
gdouble *g,
gdouble *b)
{
gdouble red, green, blue;
gdouble h, s, v;
gdouble min, max;
gdouble delta;
red = *r;
green = *g;
blue = *b;
h = 0.0;
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
min = blue;
}
else
{
if (green > blue)
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
v = max;
if (max != 0.0)
s = (max - min) / max;
else
s = 0.0;
if (s == 0.0)
h = 0.0;
else
{
delta = max - min;
if (red == max)
h = (green - blue) / delta;
else if (green == max)
h = 2 + (blue - red) / delta;
else if (blue == max)
h = 4 + (red - green) / delta;
h /= 6.0;
if (h < 0.0)
h += 1.0;
else if (h > 1.0)
h -= 1.0;
}
*r = h;
*g = s;
*b = v;
}
/**
* gtk_hsv_to_rgb:
* @h: Hue
* @s: Saturation
* @v: Value
* @r: (out): Return value for the red component
* @g: (out): Return value for the green component
* @b: (out): Return value for the blue component
*
* Converts a color from HSV space to RGB.
*
* Input values must be in the [0.0, 1.0] range;
* output values will be in the same range.
*
* Since: 2.14
*/
void
gtk_hsv_to_rgb (gdouble h, gdouble s, gdouble v,
gdouble *r, gdouble *g, gdouble *b)
{
g_return_if_fail (h >= 0.0 && h <= 1.0);
g_return_if_fail (s >= 0.0 && s <= 1.0);
g_return_if_fail (v >= 0.0 && v <= 1.0);
hsv_to_rgb (&h, &s, &v);
if (r)
*r = h;
if (g)
*g = s;
if (b)
*b = v;
}
/**
* gtk_rgb_to_hsv:
* @r: Red
* @g: Green
* @b: Blue
* @h: (out): Return value for the hue component
* @s: (out): Return value for the saturation component
* @v: (out): Return value for the value component
*
* Converts a color from RGB space to HSV.
*
* Input values must be in the [0.0, 1.0] range;
* output values will be in the same range.
*
* Since: 2.14
*/
void
gtk_rgb_to_hsv (gdouble r, gdouble g, gdouble b,
gdouble *h, gdouble *s, gdouble *v)
{
g_return_if_fail (r >= 0.0 && r <= 1.0);
g_return_if_fail (g >= 0.0 && g <= 1.0);
g_return_if_fail (b >= 0.0 && b <= 1.0);
rgb_to_hsv (&r, &g, &b);
if (h)
*h = r;
if (s)
*s = g;
if (v)
*v = b;
}
+50
View File
@@ -0,0 +1,50 @@
/* Color utilties
*
* Copyright (C) 1999 The Free Software Foundation
*
* Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
* Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
* Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_COLOR_UTILS_H__
#define __GTK_COLOR_UTILS_H__
#include <glib.h>
G_BEGIN_DECLS
void gtk_hsv_to_rgb (gdouble h, gdouble s, gdouble v,
gdouble *r, gdouble *g, gdouble *b);
void gtk_rgb_to_hsv (gdouble r, gdouble g, gdouble b,
gdouble *h, gdouble *s, gdouble *v);
G_END_DECLS
#endif /* __GTK_COLOR_UTILS_H__ */
+1 -1
View File
@@ -467,7 +467,7 @@ gtk_combo_box_text_prepend (GtkComboBoxText *combo_box,
*
* Inserts @text at @position in the list of strings stored in @combo_box.
* If @id is non-%NULL then it is used as the ID of the row. See
* #GtkComboBox::id-column.
* #GtkComboBox:id-column.
*
* If @position is negative then @text is appended.
*
+102 -27
View File
@@ -147,6 +147,8 @@ struct _GtkEntryPrivate
GtkShadowType shadow_type;
GtkWidget *popup_menu;
GdkDevice *device;
GdkDevice *completion_device;
GdkWindow *text_area;
@@ -481,6 +483,11 @@ static void gtk_entry_toggle_overwrite (GtkEntry *entry);
static void gtk_entry_select_all (GtkEntry *entry);
static void gtk_entry_real_activate (GtkEntry *entry);
static gboolean gtk_entry_popup_menu (GtkWidget *widget);
static gboolean gtk_entry_press_and_hold (GtkWidget *widget,
GdkDevice *device,
GtkPressAndHoldAction action,
gint x,
gint y);
static void keymap_direction_changed (GdkKeymap *keymap,
GtkEntry *entry);
@@ -544,9 +551,13 @@ static void gtk_entry_paste (GtkEntry *entry,
GdkAtom selection);
static void gtk_entry_update_primary_selection (GtkEntry *entry);
static void gtk_entry_do_popup (GtkEntry *entry,
GdkEventButton *event);
GdkDevice *device,
guint32 _time,
guint button);
static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
static void gtk_entry_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
static void gtk_entry_check_cursor_blink (GtkEntry *entry);
static void gtk_entry_pend_cursor_blink (GtkEntry *entry);
static void gtk_entry_reset_blink_time (GtkEntry *entry);
@@ -691,6 +702,7 @@ gtk_entry_class_init (GtkEntryClass *class)
widget_class->state_flags_changed = gtk_entry_state_flags_changed;
widget_class->screen_changed = gtk_entry_screen_changed;
widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
widget_class->grab_notify = gtk_entry_grab_notify;
widget_class->drag_drop = gtk_entry_drag_drop;
widget_class->drag_motion = gtk_entry_drag_motion;
@@ -700,6 +712,7 @@ gtk_entry_class_init (GtkEntryClass *class)
widget_class->drag_data_delete = gtk_entry_drag_data_delete;
widget_class->popup_menu = gtk_entry_popup_menu;
widget_class->press_and_hold = gtk_entry_press_and_hold;
class->move_cursor = gtk_entry_move_cursor;
class->insert_at_cursor = gtk_entry_insert_at_cursor;
@@ -1392,7 +1405,7 @@ gtk_entry_class_init (GtkEntryClass *class)
*
* The invisible character is used when masking entry contents (in
* \"password mode\")"). When it is not explicitly set with the
* #GtkEntry::invisible-char property, GTK+ determines the character
* #GtkEntry:invisible-char property, GTK+ determines the character
* to use from a list of possible candidates, depending on availability
* in the current font.
*
@@ -3810,7 +3823,8 @@ gtk_entry_button_press (GtkWidget *widget,
gtk_entry_reset_blink_time (entry);
priv->button = event->button;
priv->device = gdk_event_get_device ((GdkEvent *) event);
if (!gtk_widget_has_focus (widget))
{
priv->in_click = TRUE;
@@ -3822,8 +3836,10 @@ gtk_entry_button_press (GtkWidget *widget,
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
{
gtk_entry_do_popup (entry, event);
gtk_entry_do_popup (entry, event->device,
event->time, event->button);
priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
priv->device = NULL;
return TRUE;
}
@@ -4001,9 +4017,10 @@ gtk_entry_button_release (GtkWidget *widget,
priv->in_drag = 0;
}
priv->button = 0;
priv->device = NULL;
gtk_entry_update_primary_selection (entry);
return TRUE;
@@ -4112,7 +4129,8 @@ gtk_entry_motion_notify (GtkWidget *widget,
priv->in_drag = FALSE;
priv->button = 0;
priv->device = NULL;
gtk_target_list_unref (target_list);
}
}
@@ -8553,6 +8571,26 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
return TRUE;
}
static void
gtk_entry_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
GtkEntryPrivate *priv;
priv = GTK_ENTRY (widget)->priv;
if (priv->device &&
gtk_widget_device_is_shadowed (widget, priv->device))
{
/* Unset button so we don't expect
* a button release anymore
*/
priv->button = 0;
priv->device = NULL;
priv->in_drag = FALSE;
}
}
static void
append_action_signal (GtkEntry *entry,
GtkWidget *menu,
@@ -8755,15 +8793,17 @@ popup_targets_received (GtkClipboard *clipboard,
info_entry_priv->popup_menu);
if (info->device)
if (gdk_device_get_source (info->device) != GDK_SOURCE_KEYBOARD)
gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu),
info->device, NULL, NULL, NULL, NULL, NULL,
info->button, info->time);
else
{
gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL,
popup_position_func, entry,
0, gtk_get_current_event_time ());
gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu),
info->device, NULL, NULL,
popup_position_func,
entry, NULL,
0, info->time);
gtk_menu_shell_select_first (GTK_MENU_SHELL (info_entry_priv->popup_menu), FALSE);
}
}
@@ -8771,10 +8811,12 @@ popup_targets_received (GtkClipboard *clipboard,
g_object_unref (entry);
g_slice_free (PopupInfo, info);
}
static void
gtk_entry_do_popup (GtkEntry *entry,
GdkEventButton *event)
GdkDevice *device,
guint32 _time,
guint button)
{
PopupInfo *info = g_slice_new (PopupInfo);
@@ -8783,19 +8825,10 @@ gtk_entry_do_popup (GtkEntry *entry,
* we get them, then we actually pop up the menu.
*/
info->entry = g_object_ref (entry);
if (event)
{
info->button = event->button;
info->time = event->time;
info->device = event->device;
}
else
{
info->button = 0;
info->time = gtk_get_current_event_time ();
info->device = NULL;
}
info->button = button;
info->time = _time;
info->device = device;
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
gdk_atom_intern_static_string ("TARGETS"),
@@ -8806,7 +8839,49 @@ gtk_entry_do_popup (GtkEntry *entry,
static gboolean
gtk_entry_popup_menu (GtkWidget *widget)
{
gtk_entry_do_popup (GTK_ENTRY (widget), NULL);
gtk_entry_do_popup (GTK_ENTRY (widget),
gtk_get_current_event_device (),
gtk_get_current_event_time (),
0);
return TRUE;
}
static gboolean
gtk_entry_press_and_hold (GtkWidget *widget,
GdkDevice *device,
GtkPressAndHoldAction action,
gint x,
gint y)
{
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
gtk_entry_do_popup (GTK_ENTRY (widget),
device, GDK_CURRENT_TIME, 1);
else if (action == GTK_PRESS_AND_HOLD_QUERY)
{
GtkEntryPrivate *priv;
GdkDevice *source_device;
GdkEvent *event;
priv = GTK_ENTRY (widget)->priv;
event = gtk_get_current_event ();
if (!event)
return FALSE;
source_device = gdk_event_get_source_device (event);
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH ||
(event->type != GDK_BUTTON_PRESS &&
event->type != GDK_TOUCH_PRESS) ||
event->button.window != priv->text_area)
{
gdk_event_free (event);
return FALSE;
}
gdk_event_free (event);
}
return TRUE;
}
+72
View File
@@ -932,6 +932,78 @@ typedef enum {
GTK_BORDER_STYLE_RIDGE
} GtkBorderStyle;
/**
* GtkCapturedEventFlags:
* @GTK_CAPTURED_EVENT_NONE: Event goes uncaptured
* @GTK_CAPTURED_EVENT_HANDLED: The event was handled
* @GTK_CAPTURED_EVENT_STORE: Store for later propagation, see
* gtk_widget_release_captured_events()
*
* Describes how an event in the #GtkWidget::captured-event handler
* is handled.
*/
typedef enum {
GTK_CAPTURED_EVENT_NONE = 0,
GTK_CAPTURED_EVENT_HANDLED = 1 << 0,
GTK_CAPTURED_EVENT_STORE = 1 << 1
} GtkCapturedEventFlags;
/**
* GtkKineticScrollingFlags:
* @GTK_KINETIC_SCROLLING_NONE: No kinetic scrolling.
* @GTK_KINETIC_SCROLLING_ENABLED: Kinetic scrolling is enabled.
* @GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS: The first button
* press is captured by the scrolled window, and then replayed
* if the button press is meant to go to the child widget. This
* flag should be enabled if the child widget(s) perform
* non-reversible actions on #GtkWidget::button-press-event.
* If the widget does not do so, and handles
* #GtkWidget::grab-broken-event, it might be better off without
* this flag.
*
* Describes the kinetic scrolling behavior of a #GtkScrolledWindow
*/
typedef enum {
GTK_KINETIC_SCROLLING_NONE = 0,
GTK_KINETIC_SCROLLING_ENABLED = 1 << 0,
GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS = 1 << 1
} GtkKineticScrollingFlags;
/**
* GtkGestureType:
* @GTK_GESTURE_SWIPE_RIGHT: A swipe from left to right
* @GTK_GESTURE_SWIPE_LEFT: A swipe from right to left
* @GTK_GESTURE_SWIPE_UP: A swipe from bottom to top
* @GTK_GESTURE_SWIPE_DOWN: A swipe from top to bottom
* @GTK_GESTURE_CIRCULAR_CLOCKWISE: A circular clockwise movement
* @GTK_GESTURE_CIRCULAR_COUNTERCLOCKWISE: A circular counterclockwise movement
*
* Describes the stock gestures handled by GTK+.
*/
typedef enum {
GTK_GESTURE_SWIPE_RIGHT = 1,
GTK_GESTURE_SWIPE_LEFT,
GTK_GESTURE_SWIPE_UP,
GTK_GESTURE_SWIPE_DOWN,
GTK_GESTURE_CIRCULAR_CLOCKWISE,
GTK_GESTURE_CIRCULAR_COUNTERCLOCKWISE
} GtkGestureType;
/**
* GtkGestureFlags:
* @GTK_GESTURE_FLAG_NONE: Gesture is interpreted as-is.
* @GTK_GESTURE_FLAG_IGNORE_INITIAL_ORIENTATION:
* The initial orientation is ignored in comparisons,
* so the gesture doesn't have a sense of direction,
* this is useful for i.e. circular strokes.
*
* Flags accepted by gtk_gesture_new()
*/
typedef enum {
GTK_GESTURE_FLAG_NONE = 0,
GTK_GESTURE_FLAG_IGNORE_INITIAL_ORIENTATION = 1 << 1
} GtkGestureFlags;
G_END_DECLS
+3 -3
View File
@@ -46,12 +46,12 @@ struct _GtkFontChooserDialogPrivate
};
/**
* SECTION:gtkfontchooserdlg
* @Short_description: A dialog box for selecting fonts
* SECTION:gtkfontchooserdialog
* @Short_description: A dialog for selecting fonts
* @Title: GtkFontChooserDialog
* @See_also: #GtkFontChooser, #GtkDialog
*
* The #GtkFontChooserDialog widget is a dialog box for selecting a font.
* The #GtkFontChooserDialog widget is a dialog for selecting a font.
* It implements the #GtkFontChooser interface.
*
* <refsect2 id="GtkFontChooserDialog-BUILDER-UI">
+1 -1
View File
@@ -51,7 +51,7 @@
#include "gtkgrid.h"
/**
* SECTION:gtkfontchooser
* SECTION:gtkfontchooserwidget
* @Short_description: A widget for selecting fonts
* @Title: GtkFontChooserWidget
* @See_also: #GtkFontChooserDialog
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_GESTURES_INTERPRETER_H__
#define __GTK_GESTURES_INTERPRETER_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE (gtk_gesture_get_type ())
#define GTK_TYPE_GESTURE_STROKE (gtk_gesture_stroke_get_type ())
#define GTK_TYPE_GESTURES_INTERPRETER (gtk_gestures_interpreter_get_type ())
#define GTK_GESTURES_INTERPRETER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURES_INTERPRETER, GtkGesturesInterpreter))
#define GTK_GESTURES_INTERPRETER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_GESTURES_INTERPRETER, GtkGesturesInterpreterClass))
#define GTK_IS_GESTURES_INTERPRETER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURES_INTERPRETER))
#define GTK_IS_GESTURES_INTERPRETER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GTK_TYPE_GESTURES_INTERPRETER))
#define GTK_GESTURES_INTERPRETER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURES_INTERPRETER, GtkGesturesInterpreterClass))
typedef struct _GtkGestureStroke GtkGestureStroke;
typedef struct _GtkGesture GtkGesture;
typedef struct _GtkGesturesInterpreter GtkGesturesInterpreter;
typedef struct _GtkGesturesInterpreterClass GtkGesturesInterpreterClass;
struct _GtkGesturesInterpreter
{
GObject parent_object;
gpointer priv;
};
struct _GtkGesturesInterpreterClass
{
GObjectClass parent_class;
void (* events_vectorized) (GtkGesturesInterpreter *interpreter,
GtkGesture *gesture);
void (* gesture_detected) (GtkGesturesInterpreter *interpreter,
guint gesture_id,
gdouble confidence);
};
/* Gesture stroke */
GType gtk_gesture_stroke_get_type (void) G_GNUC_CONST;
GtkGestureStroke * gtk_gesture_stroke_new (void);
GtkGestureStroke * gtk_gesture_stroke_copy (const GtkGestureStroke *stroke);
void gtk_gesture_stroke_free (GtkGestureStroke *stroke);
void gtk_gesture_stroke_append_vector (GtkGestureStroke *stroke,
gdouble angle,
guint length);
guint gtk_gesture_stroke_get_n_vectors (const GtkGestureStroke *stroke);
gboolean gtk_gesture_stroke_get_vector (const GtkGestureStroke *stroke,
guint n_vector,
gdouble *angle,
guint *length,
gdouble *relative_length);
/* Gesture */
GType gtk_gesture_get_type (void) G_GNUC_CONST;
GtkGesture * gtk_gesture_new (const GtkGestureStroke *stroke,
GtkGestureFlags flags);
void gtk_gesture_add_stroke (GtkGesture *gesture,
const GtkGestureStroke *stroke,
gint dx,
gint dy);
GtkGesture * gtk_gesture_copy (const GtkGesture *gesture);
void gtk_gesture_free (GtkGesture *gesture);
GtkGestureFlags gtk_gesture_get_flags (const GtkGesture *gesture);
guint gtk_gesture_get_n_strokes (const GtkGesture *gesture);
const GtkGestureStroke * gtk_gesture_get_stroke (const GtkGesture *gesture,
guint n_stroke,
gint *dx,
gint *dy);
guint gtk_gesture_register (const GtkGesture *gesture);
guint gtk_gesture_register_static (const GtkGesture *gesture);
const GtkGesture * gtk_gesture_lookup (guint gesture_id);
/* Gestures interpreter */
GType gtk_gestures_interpreter_get_type (void) G_GNUC_CONST;
GtkGesturesInterpreter * gtk_gestures_interpreter_new (void);
gboolean gtk_gestures_interpreter_add_gesture (GtkGesturesInterpreter *interpreter,
guint gesture_id);
void gtk_gestures_interpreter_remove_gesture (GtkGesturesInterpreter *interpreter,
guint gesture_id);
guint gtk_gestures_interpreter_get_n_active_strokes (GtkGesturesInterpreter *interpreter);
gboolean gtk_gestures_interpreter_feed_event (GtkGesturesInterpreter *interpreter,
GdkEvent *event);
gboolean gtk_gestures_interpreter_finish (GtkGesturesInterpreter *interpreter,
guint *gesture_id);
G_END_DECLS
#endif /* __GTK_GESTURES_INTERPRETER_H__ */
+9 -7
View File
@@ -1285,12 +1285,13 @@ gtk_icon_view_realize (GtkWidget *widget)
attributes.width = MAX (icon_view->priv->width, allocation.width);
attributes.height = MAX (icon_view->priv->height, allocation.height);
attributes.event_mask = (GDK_EXPOSURE_MASK |
GDK_SCROLL_MASK |
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK) |
GDK_SCROLL_MASK |
GDK_SMOOTH_SCROLL_MASK |
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK) |
gtk_widget_get_events (widget);
icon_view->priv->bin_window = gdk_window_new (window,
@@ -1302,6 +1303,7 @@ gtk_icon_view_realize (GtkWidget *widget)
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
gtk_style_context_set_background (context, icon_view->priv->bin_window);
gtk_style_context_set_background (context, window);
gtk_style_context_restore (context);
gdk_window_show (icon_view->priv->bin_window);
@@ -4494,7 +4496,7 @@ gtk_icon_view_set_tooltip_query_cb (GtkWidget *widget,
* for you. @column should be set to the column in @icon_view's model
* containing the tooltip texts, or -1 to disable this feature.
*
* When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
* When enabled, #GtkWidget:has-tooltip will be set to %TRUE and
* @icon_view will connect a #GtkWidget::query-tooltip signal handler.
*
* Note that the signal handler sets the text with gtk_tooltip_set_markup(),
-1
View File
@@ -843,7 +843,6 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
if (priv->tentative_match &&
g_unichar_validate (priv->tentative_match))
{
g_print ("committing tentative match on release\n");
gtk_im_context_simple_commit_char (context, priv->tentative_match);
priv->compose_buffer[0] = 0;
+56 -13
View File
@@ -437,6 +437,11 @@ static void gtk_label_hierarchy_changed (GtkWidget *widget,
static void gtk_label_screen_changed (GtkWidget *widget,
GdkScreen *old_screen);
static gboolean gtk_label_popup_menu (GtkWidget *widget);
static gboolean gtk_label_press_and_hold (GtkWidget *widget,
GdkDevice *device,
GtkPressAndHoldAction action,
gint x,
gint y);
static void gtk_label_create_window (GtkLabel *label);
static void gtk_label_destroy_window (GtkLabel *label);
@@ -490,7 +495,9 @@ static void gtk_label_move_cursor (GtkLabel *label,
static void gtk_label_copy_clipboard (GtkLabel *label);
static void gtk_label_select_all (GtkLabel *label);
static void gtk_label_do_popup (GtkLabel *label,
GdkEventButton *event);
GdkDevice *device,
guint32 _time,
guint button);
static gint gtk_label_move_forward_word (GtkLabel *label,
gint start);
static gint gtk_label_move_backward_word (GtkLabel *label,
@@ -585,6 +592,7 @@ gtk_label_class_init (GtkLabelClass *class)
widget_class->drag_data_get = gtk_label_drag_data_get;
widget_class->grab_focus = gtk_label_grab_focus;
widget_class->popup_menu = gtk_label_popup_menu;
widget_class->press_and_hold = gtk_label_press_and_hold;
widget_class->focus = gtk_label_focus;
widget_class->get_request_mode = gtk_label_get_request_mode;
widget_class->get_preferred_width = gtk_label_get_preferred_width;
@@ -4638,7 +4646,8 @@ gtk_label_button_press (GtkWidget *widget,
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
{
info->link_clicked = 1;
gtk_label_do_popup (label, event);
gtk_label_do_popup (label, event->device,
event->time, event->button);
return TRUE;
}
else if (event->button == GDK_BUTTON_PRIMARY)
@@ -4656,7 +4665,8 @@ gtk_label_button_press (GtkWidget *widget,
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
{
gtk_label_do_popup (label, event);
gtk_label_do_popup (label, event->device,
event->time, event->button);
return TRUE;
}
@@ -4921,6 +4931,8 @@ gtk_label_motion (GtkWidget *widget,
if ((event->state & GDK_BUTTON1_MASK) == 0)
return FALSE;
gdk_event_request_motions (event);
if (info->in_drag)
{
if (gtk_drag_check_threshold (widget,
@@ -6170,14 +6182,43 @@ copy_link_activate_cb (GtkMenuItem *menu_item,
static gboolean
gtk_label_popup_menu (GtkWidget *widget)
{
gtk_label_do_popup (GTK_LABEL (widget), NULL);
gtk_label_do_popup (GTK_LABEL (widget),
gtk_get_current_event_device (),
gtk_get_current_event_time (),
0);
return TRUE;
}
static gboolean
gtk_label_press_and_hold (GtkWidget *widget,
GdkDevice *device,
GtkPressAndHoldAction action,
gint x,
gint y)
{
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
gtk_label_do_popup (GTK_LABEL (widget),
device, GDK_CURRENT_TIME, 1);
else if (action == GTK_PRESS_AND_HOLD_QUERY)
{
GdkDevice *source_device;
GdkEvent *event;
event = gtk_get_current_event ();
source_device = gdk_event_get_source_device (event);
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
return FALSE;
}
return TRUE;
}
static void
gtk_label_do_popup (GtkLabel *label,
GdkEventButton *event)
GdkDevice *device,
guint32 _time,
guint button)
{
GtkLabelPrivate *priv = label->priv;
GtkWidget *menuitem;
@@ -6199,7 +6240,7 @@ gtk_label_do_popup (GtkLabel *label,
have_selection =
priv->select_info->selection_anchor != priv->select_info->selection_end;
if (event)
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
{
if (priv->select_info->link_clicked)
link = priv->select_info->active_link;
@@ -6259,15 +6300,17 @@ gtk_label_do_popup (GtkLabel *label,
g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
if (event)
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
NULL, NULL,
event->button, event->time);
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
gtk_menu_popup_for_device (GTK_MENU (menu), device,
NULL, NULL, NULL, NULL, NULL,
button, _time);
else
{
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
popup_position_func, label,
0, gtk_get_current_event_time ());
gtk_menu_popup_for_device (GTK_MENU (menu),
device, NULL, NULL,
popup_position_func,
label, NULL,
0, _time);
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
}
}
+2 -1
View File
@@ -894,7 +894,8 @@ gtk_layout_realize (GtkWidget *widget)
attributes.y = - gtk_adjustment_get_value (priv->vadjustment);
attributes.width = MAX (priv->width, allocation.width);
attributes.height = MAX (priv->height, allocation.height);
attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK |
attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK |
GDK_SMOOTH_SCROLL_MASK |
gtk_widget_get_events (widget);
priv->bin_window = gdk_window_new (window,
+210 -83
View File
@@ -1332,11 +1332,14 @@ rewrite_event_for_window (GdkEvent *event,
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
rewrite_events_translate (event->any.window,
new_window,
&event->button.x, &event->button.y);
break;
case GDK_MOTION_NOTIFY:
case GDK_TOUCH_MOTION:
rewrite_events_translate (event->any.window,
new_window,
&event->motion.x, &event->motion.y);
@@ -1386,6 +1389,9 @@ rewrite_event_for_grabs (GdkEvent *event)
case GDK_PROXIMITY_OUT:
case GDK_KEY_PRESS:
case GDK_KEY_RELEASE:
case GDK_TOUCH_PRESS:
case GDK_TOUCH_RELEASE:
case GDK_TOUCH_MOTION:
display = gdk_window_get_display (event->any.window);
device = gdk_event_get_device (event);
@@ -1473,6 +1479,7 @@ gtk_main_do_event (GdkEvent *event)
{
GtkWidget *event_widget;
GtkWidget *grab_widget = NULL;
GtkWidget *topmost_widget = NULL;
GtkWindowGroup *window_group;
GdkEvent *rewritten_event = NULL;
GdkDevice *device;
@@ -1532,6 +1539,14 @@ gtk_main_do_event (GdkEvent *event)
if (!grab_widget)
grab_widget = gtk_window_group_get_current_grab (window_group);
/* Find out the topmost widget where captured event propagation
* should start, which is the widget holding the GTK+ grab
* if any, otherwise it's left NULL and events are emitted
* from the toplevel (or topmost parentless parent).
*/
if (grab_widget)
topmost_widget = grab_widget;
/* If the grab widget is an ancestor of the event widget
* then we send the event to the original event widget.
* This is the key to implementing modality.
@@ -1628,14 +1643,28 @@ gtk_main_do_event (GdkEvent *event)
case GDK_WINDOW_STATE:
case GDK_GRAB_BROKEN:
case GDK_DAMAGE:
gtk_widget_event (event_widget, event);
if (!_gtk_widget_captured_event (event_widget, event))
gtk_widget_event (event_widget, event);
break;
case GDK_SCROLL:
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
gtk_propagate_event (grab_widget, event);
case GDK_TOUCH_PRESS:
if ((event->type == GDK_BUTTON_PRESS ||
event->type == GDK_TOUCH_PRESS) &&
event->button.button == 1)
{
/* Handle press and hold on the grab widget before propagating up,
* so a parent capturing events doesn't delay nor prevent a child
* from doing the press-and-hold action.
*/
_gtk_widget_press_and_hold_check_start (grab_widget, &event->button);
}
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
gtk_propagate_event (grab_widget, event);
break;
case GDK_KEY_PRESS:
@@ -1684,22 +1713,43 @@ gtk_main_do_event (GdkEvent *event)
case GDK_BUTTON_RELEASE:
case GDK_PROXIMITY_IN:
case GDK_PROXIMITY_OUT:
gtk_propagate_event (grab_widget, event);
case GDK_TOUCH_MOTION:
case GDK_TOUCH_RELEASE:
case GDK_MULTITOUCH_ADDED:
case GDK_MULTITOUCH_REMOVED:
case GDK_MULTITOUCH_UPDATED:
if ((event->type == GDK_BUTTON_RELEASE ||
event->type == GDK_TOUCH_RELEASE) &&
event->button.button == 1)
_gtk_widget_press_and_hold_check_cancel (grab_widget, &event->button);
else if (event->type == GDK_MOTION_NOTIFY ||
event->type == GDK_TOUCH_MOTION)
_gtk_widget_press_and_hold_check_threshold (grab_widget,
&event->motion);
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
gtk_propagate_event (grab_widget, event);
break;
case GDK_ENTER_NOTIFY:
_gtk_widget_set_device_window (event_widget,
gdk_event_get_device (event),
event->any.window);
if (gtk_widget_is_sensitive (grab_widget))
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
_gtk_widget_set_device_window (event_widget,
gdk_event_get_device (event),
event->any.window);
if (gtk_widget_is_sensitive (grab_widget) &&
!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
gtk_widget_event (grab_widget, event);
break;
case GDK_LEAVE_NOTIFY:
_gtk_widget_set_device_window (event_widget,
gdk_event_get_device (event),
NULL);
if (gtk_widget_is_sensitive (grab_widget))
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
_gtk_widget_set_device_window (event_widget,
gdk_event_get_device (event),
NULL);
if (gtk_widget_is_sensitive (grab_widget) &&
!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
gtk_widget_event (grab_widget, event);
break;
@@ -1727,11 +1777,22 @@ gtk_main_do_event (GdkEvent *event)
|| event->type == GDK_DRAG_ENTER
|| event->type == GDK_GRAB_BROKEN
|| event->type == GDK_MOTION_NOTIFY
|| event->type == GDK_TOUCH_MOTION
|| event->type == GDK_SCROLL)
{
_gtk_tooltip_handle_event (event);
}
/* Handle gestures for touch events */
if (gdk_event_get_touch_id (event, NULL))
{
_gtk_widget_gesture_stroke (grab_widget, event);
if (event->type == GDK_BUTTON_RELEASE ||
event->type == GDK_TOUCH_RELEASE)
_gtk_widget_gesture_finish (grab_widget);
}
tmp_list = current_events;
current_events = g_list_remove_link (current_events, tmp_list);
g_list_free_1 (tmp_list);
@@ -2329,6 +2390,135 @@ gtk_get_event_widget (GdkEvent *event)
return widget;
}
static gboolean
propagate_event_up (GtkWidget *widget,
GdkEvent *event,
GtkWidget *topmost)
{
gboolean handled_event = FALSE;
/* Propagate event up the widget tree so that
* parents can see the button and motion
* events of the children.
*/
while (TRUE)
{
GtkWidget *tmp;
g_object_ref (widget);
/* Scroll events are special cased here because it
* feels wrong when scrolling a GtkViewport, say,
* to have children of the viewport eat the scroll
* event
*/
if (!gtk_widget_is_sensitive (widget))
handled_event = event->type != GDK_SCROLL;
else
handled_event = gtk_widget_event (widget, event);
tmp = gtk_widget_get_parent (widget);
g_object_unref (widget);
if (widget == topmost)
break;
widget = tmp;
if (handled_event || !widget)
break;
}
return handled_event;
}
static gboolean
propagate_event_down (GtkWidget *widget,
GdkEvent *event,
GtkWidget *topmost)
{
gint handled_event = FALSE;
GList *widgets = NULL;
GList *l;
widgets = g_list_prepend (widgets, g_object_ref (widget));
while (widget && widget != topmost)
{
widget = gtk_widget_get_parent (widget);
if (!widget)
break;
widgets = g_list_prepend (widgets, g_object_ref (widget));
if (widget == topmost)
break;
}
for (l = widgets; l && !handled_event; l = g_list_next (l))
{
widget = (GtkWidget *)l->data;
if (!gtk_widget_is_sensitive (widget))
handled_event = TRUE;
else
handled_event = _gtk_widget_captured_event (widget, event);
}
g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
return handled_event;
}
static gboolean
propagate_event (GtkWidget *widget,
GdkEvent *event,
gboolean captured,
GtkWidget *topmost)
{
gboolean handled_event = FALSE;
gboolean (* propagate_func) (GtkWidget *widget, GdkEvent *event);
propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event;
if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
{
/* Only send key events within Window widgets to the Window
* The Window widget will in turn pass the
* key event on to the currently focused widget
* for that window.
*/
GtkWidget *window;
window = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (window))
{
g_object_ref (widget);
/* If there is a grab within the window, give the grab widget
* a first crack at the key event
*/
if (widget != window && gtk_widget_has_grab (widget))
handled_event = propagate_func (widget, event);
if (!handled_event)
{
window = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (window))
{
if (gtk_widget_is_sensitive (window))
handled_event = propagate_func (window, event);
}
}
g_object_unref (widget);
return handled_event;
}
}
/* Other events get propagated up/down the widget tree */
return captured ?
propagate_event_down (widget, event, topmost) :
propagate_event_up (widget, event, topmost);
}
/**
* gtk_propagate_event:
* @widget: a #GtkWidget
@@ -2357,79 +2547,16 @@ void
gtk_propagate_event (GtkWidget *widget,
GdkEvent *event)
{
gint handled_event;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (event != NULL);
handled_event = FALSE;
g_object_ref (widget);
if ((event->type == GDK_KEY_PRESS) ||
(event->type == GDK_KEY_RELEASE))
{
/* Only send key events within Window widgets to the Window
* The Window widget will in turn pass the
* key event on to the currently focused widget
* for that window.
*/
GtkWidget *window;
window = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (window))
{
/* If there is a grab within the window, give the grab widget
* a first crack at the key event
*/
if (widget != window && gtk_widget_has_grab (widget))
handled_event = gtk_widget_event (widget, event);
if (!handled_event)
{
window = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (window))
{
if (gtk_widget_is_sensitive (window))
gtk_widget_event (window, event);
}
}
handled_event = TRUE; /* don't send to widget */
}
}
/* Other events get propagated up the widget tree
* so that parents can see the button and motion
* events of the children.
*/
if (!handled_event)
{
while (TRUE)
{
GtkWidget *tmp;
/* Scroll events are special cased here because it
* feels wrong when scrolling a GtkViewport, say,
* to have children of the viewport eat the scroll
* event
*/
if (!gtk_widget_is_sensitive (widget))
handled_event = event->type != GDK_SCROLL;
else
handled_event = gtk_widget_event (widget, event);
tmp = gtk_widget_get_parent (widget);
g_object_unref (widget);
widget = tmp;
if (!handled_event && widget)
g_object_ref (widget);
else
break;
}
}
else
g_object_unref (widget);
propagate_event (widget, event, FALSE, NULL);
}
gboolean
_gtk_propagate_captured_event (GtkWidget *widget,
GdkEvent *event,
GtkWidget *topmost)
{
return propagate_event (widget, event, TRUE, topmost);
}
+3
View File
@@ -36,6 +36,7 @@ BOOLEAN:OBJECT,BOXED,BOXED
BOOLEAN:OBJECT,OBJECT,OBJECT
BOOLEAN:OBJECT,STRING,STRING
BOOLEAN:OBJECT,ENUM
BOOLEAN:OBJECT,ENUM,INT,INT
BOOLEAN:INT
BOOLEAN:INT,INT
BOOLEAN:INT,INT,INT
@@ -47,6 +48,7 @@ BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
BOOLEAN:STRING
ENUM:ENUM
ENUM:VOID
FLAGS:BOXED
INT:POINTER
OBJECT:VOID
STRING:DOUBLE
@@ -109,6 +111,7 @@ VOID:STRING,STRING,STRING
VOID:STRING,INT,POINTER
VOID:STRING,UINT,FLAGS
VOID:STRING,UINT,FLAGS,UINT
VOID:UINT,DOUBLE
VOID:UINT,FLAGS,BOXED
VOID:UINT,UINT
VOID:UINT,STRING
+230 -276
View File
@@ -110,6 +110,7 @@
#include "gtksettings.h"
#include "gtkprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkdnd.h"
#include "gtkintl.h"
#include "gtktypebuiltins.h"
@@ -227,12 +228,14 @@ static void gtk_menu_scroll_to (GtkMenu *menu,
gint offset);
static void gtk_menu_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
static GtkCapturedEventFlags
gtk_menu_captured_event (GtkWidget *widget,
GdkEvent *event);
static void gtk_menu_stop_scrolling (GtkMenu *menu);
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
static gboolean gtk_menu_scroll_timeout (gpointer data);
static gboolean gtk_menu_scroll_timeout_initial (gpointer data);
static void gtk_menu_start_scrolling (GtkMenu *menu);
static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
GtkWidget *menu_item);
@@ -510,6 +513,7 @@ gtk_menu_class_init (GtkMenuClass *class)
widget_class->get_preferred_width = gtk_menu_get_preferred_width;
widget_class->get_preferred_height = gtk_menu_get_preferred_height;
widget_class->get_preferred_height_for_width = gtk_menu_get_preferred_height_for_width;
widget_class->captured_event = gtk_menu_captured_event;
container_class->remove = gtk_menu_remove;
container_class->get_child_property = gtk_menu_get_child_property;
@@ -1057,6 +1061,7 @@ gtk_menu_init (GtkMenu *menu)
priv->needs_destruction_ref = TRUE;
priv->monitor_num = -1;
priv->drag_start_y = -1;
context = gtk_widget_get_style_context (GTK_WIDGET (menu));
gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU);
@@ -1465,7 +1470,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
GtkMenuShell *menu_shell;
gboolean grab_keyboard;
GtkWidget *parent_toplevel;
GdkDevice *keyboard, *pointer;
GdkDevice *keyboard, *pointer, *source_device = NULL;
g_return_if_fail (GTK_IS_MENU (menu));
g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
@@ -1602,6 +1607,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
(current_event->type != GDK_ENTER_NOTIFY))
menu_shell->priv->ignore_enter = TRUE;
source_device = gdk_event_get_source_device (current_event);
gdk_event_free (current_event);
}
else
@@ -1671,17 +1677,9 @@ gtk_menu_popup_for_device (GtkMenu *menu,
gtk_menu_scroll_to (menu, priv->scroll_offset);
/* if no item is selected, select the first one */
if (!menu_shell->priv->active_menu_item)
{
gboolean touchscreen_mode;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
if (touchscreen_mode)
gtk_menu_shell_select_first (menu_shell, TRUE);
}
if (!menu_shell->priv->active_menu_item &&
source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
gtk_menu_shell_select_first (menu_shell, TRUE);
/* Once everything is set up correctly, map the toplevel */
gtk_widget_show (priv->toplevel);
@@ -3316,34 +3314,6 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
g_free (nat_heights);
}
static gboolean
gtk_menu_button_scroll (GtkMenu *menu,
GdkEventButton *event)
{
GtkMenuPrivate *priv = menu->priv;
if (priv->upper_arrow_prelight || priv->lower_arrow_prelight)
{
gboolean touchscreen_mode;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
if (touchscreen_mode)
gtk_menu_handle_scrolling (menu,
event->x_root, event->y_root,
event->type == GDK_BUTTON_PRESS,
FALSE);
return TRUE;
}
return FALSE;
}
static gboolean
pointer_in_menu_window (GtkWidget *widget,
gdouble x_root,
@@ -3380,13 +3350,16 @@ static gboolean
gtk_menu_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GdkDevice *source_device;
GtkWidget *event_widget;
GtkMenu *menu;
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
/* Don't pass down to menu shell for presses over scroll arrows
*/
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
return TRUE;
source_device = gdk_event_get_source_device ((GdkEvent *) event);
event_widget = gtk_get_event_widget ((GdkEvent *) event);
menu = GTK_MENU (widget);
/* Don't pass down to menu shell if a non-menuitem part of the menu
* was clicked. The check for the event_widget being a GtkMenuShell
@@ -3395,10 +3368,16 @@ gtk_menu_button_press (GtkWidget *widget,
* the menu or on its border are delivered relative to
* menu_shell->window.
*/
if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
if (GTK_IS_MENU_SHELL (event_widget) &&
pointer_in_menu_window (widget, event->x_root, event->y_root))
return TRUE;
if (GTK_IS_MENU_ITEM (event_widget) &&
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH &&
GTK_MENU_ITEM (event_widget)->priv->submenu != NULL &&
!gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu))
menu->priv->ignore_button_release = TRUE;
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
}
@@ -3417,11 +3396,6 @@ gtk_menu_button_release (GtkWidget *widget,
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
/* Don't pass down to menu shell for releases over scroll arrows
*/
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
return TRUE;
/* Don't pass down to menu shell if a non-menuitem part of the menu
* was clicked (see comment in button_press()).
*/
@@ -3665,10 +3639,14 @@ gtk_menu_motion_notify (GtkWidget *widget,
GtkMenu *menu;
GtkMenuShell *menu_shell;
GtkWidget *parent;
GdkDevice *source_device;
gboolean need_enter;
if (GTK_IS_MENU (widget))
source_device = gdk_event_get_source_device ((GdkEvent *) event);
if (GTK_IS_MENU (widget) &&
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
{
GtkMenuPrivate *priv = GTK_MENU(widget)->priv;
@@ -3832,90 +3810,17 @@ gtk_menu_scroll_by (GtkMenu *menu,
gtk_menu_scroll_to (menu, offset);
}
static void
gtk_menu_do_timeout_scroll (GtkMenu *menu,
gboolean touchscreen_mode)
{
GtkMenuPrivate *priv = menu->priv;
gboolean upper_visible;
gboolean lower_visible;
upper_visible = priv->upper_arrow_visible;
lower_visible = priv->lower_arrow_visible;
gtk_menu_scroll_by (menu, priv->scroll_step);
if (touchscreen_mode &&
(upper_visible != priv->upper_arrow_visible ||
lower_visible != priv->lower_arrow_visible))
{
/* We are about to hide a scroll arrow while the mouse is pressed,
* this would cause the uncovered menu item to be activated on button
* release. Therefore we need to ignore button release here
*/
GTK_MENU_SHELL (menu)->priv->ignore_enter = TRUE;
priv->ignore_button_release = TRUE;
}
}
static gboolean
gtk_menu_scroll_timeout (gpointer data)
{
GtkMenu *menu;
gboolean touchscreen_mode;
menu = GTK_MENU (data);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
gtk_menu_scroll_by (menu, menu->priv->scroll_step);
return TRUE;
}
static gboolean
gtk_menu_scroll_timeout_initial (gpointer data)
{
GtkMenu *menu;
guint timeout;
gboolean touchscreen_mode;
menu = GTK_MENU (data);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-timeout-repeat", &timeout,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
gtk_menu_remove_scroll_timeout (menu);
menu->priv->scroll_timeout =
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
return FALSE;
}
static void
gtk_menu_start_scrolling (GtkMenu *menu)
{
guint timeout;
gboolean touchscreen_mode;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-timeout-repeat", &timeout,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
menu->priv->scroll_timeout =
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu);
}
static gboolean
gtk_menu_scroll (GtkWidget *widget,
GdkEventScroll *event)
@@ -4039,14 +3944,9 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
gboolean in_arrow;
gboolean scroll_fast = FALSE;
gint top_x, top_y;
gboolean touchscreen_mode;
menu_shell = GTK_MENU_SHELL (menu);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
&top_x, &top_y);
x -= top_x;
@@ -4064,82 +3964,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
in_arrow = TRUE;
}
if (touchscreen_mode)
priv->upper_arrow_prelight = in_arrow;
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
gboolean arrow_pressed = FALSE;
if (priv->upper_arrow_visible && !priv->tearoff_active)
{
if (touchscreen_mode)
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
if (enter && in_arrow &&
(!priv->upper_arrow_prelight ||
priv->scroll_fast != scroll_fast))
{
if (enter && priv->upper_arrow_prelight)
{
if (priv->scroll_timeout == 0)
{
/* Deselect the active item so that
* any submenus are popped down
*/
gtk_menu_shell_deselect (menu_shell);
priv->upper_arrow_prelight = TRUE;
priv->scroll_fast = scroll_fast;
gtk_menu_remove_scroll_timeout (menu);
priv->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
/* Deselect the active item so that
* any submenus are popped down
*/
gtk_menu_shell_deselect (menu_shell);
if (!motion)
{
/* Only do stuff on click. */
gtk_menu_start_scrolling (menu);
arrow_pressed = TRUE;
}
}
else
{
arrow_pressed = TRUE;
}
}
else if (!enter)
{
gtk_menu_stop_scrolling (menu);
}
gtk_menu_remove_scroll_timeout (menu);
priv->scroll_step = scroll_fast
? -MENU_SCROLL_STEP2
: -MENU_SCROLL_STEP1;
priv->scroll_timeout =
gdk_threads_add_timeout (scroll_fast
? MENU_SCROLL_TIMEOUT2
: MENU_SCROLL_TIMEOUT1,
gtk_menu_scroll_timeout, menu);
}
else /* !touchscreen_mode */
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
{
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
if (enter && in_arrow &&
(!priv->upper_arrow_prelight ||
priv->scroll_fast != scroll_fast))
{
priv->upper_arrow_prelight = TRUE;
priv->scroll_fast = scroll_fast;
/* Deselect the active item so that
* any submenus are popped down
*/
gtk_menu_shell_deselect (menu_shell);
gtk_menu_remove_scroll_timeout (menu);
priv->scroll_step = scroll_fast
? -MENU_SCROLL_STEP2
: -MENU_SCROLL_STEP1;
priv->scroll_timeout =
gdk_threads_add_timeout (scroll_fast
? MENU_SCROLL_TIMEOUT2
: MENU_SCROLL_TIMEOUT1,
gtk_menu_scroll_timeout, menu);
}
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
{
gtk_menu_stop_scrolling (menu);
}
gtk_menu_stop_scrolling (menu);
}
}
/* gtk_menu_start_scrolling() might have hit the top of the
* menu, so check if the button isn't insensitive before
/* check if the button isn't insensitive before
* changing it to something else.
*/
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
@@ -4174,82 +4036,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
in_arrow = TRUE;
}
if (touchscreen_mode)
priv->lower_arrow_prelight = in_arrow;
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
gboolean arrow_pressed = FALSE;
if (priv->lower_arrow_visible && !priv->tearoff_active)
{
if (touchscreen_mode)
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
if (enter && in_arrow &&
(!priv->lower_arrow_prelight ||
priv->scroll_fast != scroll_fast))
{
if (enter && priv->lower_arrow_prelight)
{
if (priv->scroll_timeout == 0)
{
/* Deselect the active item so that
* any submenus are popped down
*/
gtk_menu_shell_deselect (menu_shell);
priv->lower_arrow_prelight = TRUE;
priv->scroll_fast = scroll_fast;
gtk_menu_remove_scroll_timeout (menu);
priv->scroll_step = MENU_SCROLL_STEP2; /* always fast */
/* Deselect the active item so that
* any submenus are popped down
*/
gtk_menu_shell_deselect (menu_shell);
if (!motion)
{
/* Only do stuff on click. */
gtk_menu_start_scrolling (menu);
arrow_pressed = TRUE;
}
}
else
{
arrow_pressed = TRUE;
}
}
else if (!enter)
{
gtk_menu_stop_scrolling (menu);
}
gtk_menu_remove_scroll_timeout (menu);
priv->scroll_step = scroll_fast
? MENU_SCROLL_STEP2
: MENU_SCROLL_STEP1;
priv->scroll_timeout =
gdk_threads_add_timeout (scroll_fast
? MENU_SCROLL_TIMEOUT2
: MENU_SCROLL_TIMEOUT1,
gtk_menu_scroll_timeout, menu);
}
else /* !touchscreen_mode */
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
{
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
if (enter && in_arrow &&
(!priv->lower_arrow_prelight ||
priv->scroll_fast != scroll_fast))
{
priv->lower_arrow_prelight = TRUE;
priv->scroll_fast = scroll_fast;
/* Deselect the active item so that
* any submenus are popped down
*/
gtk_menu_shell_deselect (menu_shell);
gtk_menu_remove_scroll_timeout (menu);
priv->scroll_step = scroll_fast
? MENU_SCROLL_STEP2
: MENU_SCROLL_STEP1;
priv->scroll_timeout =
gdk_threads_add_timeout (scroll_fast
? MENU_SCROLL_TIMEOUT2
: MENU_SCROLL_TIMEOUT1,
gtk_menu_scroll_timeout, menu);
}
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
{
gtk_menu_stop_scrolling (menu);
}
gtk_menu_stop_scrolling (menu);
}
}
/* gtk_menu_start_scrolling() might have hit the bottom of the
* menu, so check if the button isn't insensitive before
/* check if the button isn't insensitive before
* changing it to something else.
*/
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
@@ -4279,19 +4103,18 @@ gtk_menu_enter_notify (GtkWidget *widget,
{
GtkWidget *menu_item;
GtkWidget *parent;
gboolean touchscreen_mode;
GdkDevice *source_device;
if (event->mode == GDK_CROSSING_GTK_GRAB ||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
event->mode == GDK_CROSSING_STATE_CHANGED)
return TRUE;
g_object_get (gtk_widget_get_settings (widget),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
source_device = gdk_event_get_source_device ((GdkEvent *) event);
menu_item = gtk_get_event_widget ((GdkEvent*) event);
if (GTK_IS_MENU (widget))
if (GTK_IS_MENU (widget) &&
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
{
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
@@ -4300,7 +4123,8 @@ gtk_menu_enter_notify (GtkWidget *widget,
event->x_root, event->y_root, TRUE, TRUE);
}
if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item))
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH &&
GTK_IS_MENU_ITEM (menu_item))
{
GtkWidget *menu = gtk_widget_get_parent (menu_item);
@@ -4357,6 +4181,7 @@ gtk_menu_leave_notify (GtkWidget *widget,
GtkMenu *menu;
GtkMenuItem *menu_item;
GtkWidget *event_widget;
GdkDevice *source_device;
if (event->mode == GDK_CROSSING_GTK_GRAB ||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
@@ -4369,7 +4194,10 @@ gtk_menu_leave_notify (GtkWidget *widget,
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
return TRUE;
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
source_device = gdk_event_get_source_device ((GdkEvent *) event);
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
event_widget = gtk_get_event_widget ((GdkEvent*) event);
@@ -4404,6 +4232,138 @@ gtk_menu_leave_notify (GtkWidget *widget,
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event);
}
static gboolean
pointer_on_menu_widget (GtkMenu *menu,
gdouble x_root,
gdouble y_root)
{
GtkMenuPrivate *priv = menu->priv;
GtkAllocation allocation;
gint window_x, window_y;
gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation);
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
&window_x, &window_y);
if (x_root >= window_x && x_root < window_x + allocation.width &&
y_root >= window_y && y_root < window_y + allocation.height)
return TRUE;
return FALSE;
}
static GtkCapturedEventFlags
gtk_menu_captured_event (GtkWidget *widget,
GdkEvent *event)
{
GdkDevice *source_device;
GtkCapturedEventFlags flags;
GtkMenuPrivate *priv;
GtkMenu *menu;
menu = GTK_MENU (widget);
priv = menu->priv;
flags = GTK_CAPTURED_EVENT_NONE;
if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
return flags;
source_device = gdk_event_get_source_device (event);
switch (event->type)
{
case GDK_BUTTON_PRESS:
if (event->button.button == 1 &&
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH &&
pointer_on_menu_widget (menu, event->button.x_root, event->button.y_root))
{
priv->drag_start_y = event->button.y_root;
priv->initial_drag_offset = priv->scroll_offset;
priv->drag_scroll_started = FALSE;
}
else
priv->drag_start_y = -1;
priv->drag_already_pressed = TRUE;
break;
case GDK_BUTTON_RELEASE:
if (priv->drag_scroll_started)
{
flags = GTK_CAPTURED_EVENT_HANDLED;
priv->drag_scroll_started = FALSE;
priv->drag_start_y = -1;
priv->drag_already_pressed = FALSE;
}
break;
case GDK_MOTION_NOTIFY:
if (event->motion.state & GDK_BUTTON1_MASK &&
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
{
if (!priv->drag_already_pressed)
{
if (pointer_on_menu_widget (menu,
event->motion.x_root,
event->motion.y_root))
{
priv->drag_start_y = event->motion.y_root;
priv->initial_drag_offset = priv->scroll_offset;
priv->drag_scroll_started = FALSE;
}
else
priv->drag_start_y = -1;
priv->drag_already_pressed = TRUE;
}
if (priv->drag_start_y < 0 &&
!priv->drag_scroll_started)
break;
if (priv->drag_scroll_started)
{
gint offset, view_height;
GtkBorder arrow_border;
gdouble y_diff;
y_diff = event->motion.y_root - priv->drag_start_y;
offset = priv->initial_drag_offset - y_diff;
view_height = gdk_window_get_height (gtk_widget_get_window (widget));
get_arrows_border (menu, &arrow_border);
if (priv->upper_arrow_visible)
view_height -= arrow_border.top;
if (priv->lower_arrow_visible)
view_height -= arrow_border.bottom;
offset = CLAMP (offset, 0, priv->requested_height - view_height);
gtk_menu_scroll_to (menu, offset);
flags = GTK_CAPTURED_EVENT_HANDLED;
}
else if (gtk_drag_check_threshold (widget,
0, priv->drag_start_y,
0, event->motion.y_root))
{
priv->drag_scroll_started = TRUE;
flags = GTK_CAPTURED_EVENT_HANDLED;
gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
}
}
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
if (priv->drag_scroll_started)
flags = GTK_CAPTURED_EVENT_HANDLED;
break;
default:
break;
}
return flags;
}
static void
gtk_menu_stop_navigating_submenu (GtkMenu *menu)
{
@@ -4846,19 +4806,10 @@ static void
gtk_menu_stop_scrolling (GtkMenu *menu)
{
GtkMenuPrivate *priv = menu->priv;
gboolean touchscreen_mode;
gtk_menu_remove_scroll_timeout (menu);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
if (!touchscreen_mode)
{
priv->upper_arrow_prelight = FALSE;
priv->lower_arrow_prelight = FALSE;
}
priv->upper_arrow_prelight = FALSE;
priv->lower_arrow_prelight = FALSE;
}
static void
@@ -5664,7 +5615,6 @@ gtk_menu_real_move_scroll (GtkMenu *menu,
}
}
/**
* gtk_menu_set_monitor:
* @menu: a #GtkMenu
@@ -5741,11 +5691,13 @@ static void
gtk_menu_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
GtkMenu *menu;
GtkWidget *toplevel;
GtkWindowGroup *group;
GtkWidget *grab;
GdkDevice *pointer;
menu = GTK_MENU (widget);
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget));
if (!pointer ||
@@ -5762,6 +5714,8 @@ gtk_menu_grab_notify (GtkWidget *widget,
if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab))
gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
menu->priv->drag_scroll_started = FALSE;
}
/**
+12 -5
View File
@@ -1690,13 +1690,20 @@ static void
gtk_real_menu_item_select (GtkMenuItem *menu_item)
{
GtkMenuItemPrivate *priv = menu_item->priv;
gboolean touchscreen_mode;
GdkDevice *source_device = NULL;
GdkEvent *current_event;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
current_event = gtk_get_current_event ();
if (!touchscreen_mode && priv->submenu &&
if (current_event)
{
source_device = gdk_event_get_source_device (current_event);
gdk_event_free (current_event);
}
if ((!source_device ||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH) &&
priv->submenu &&
(!gtk_widget_get_mapped (priv->submenu) ||
GTK_MENU (priv->submenu)->priv->tearoff_active))
{
+5
View File
@@ -100,6 +100,8 @@ struct _GtkMenuPrivate
guint seen_item_enter : 1;
guint ignore_button_release : 1;
guint no_toggle_size : 1;
guint drag_already_pressed : 1;
guint drag_scroll_started : 1;
/* info used for the table */
guint *heights;
@@ -126,6 +128,9 @@ struct _GtkMenuPrivate
gint navigation_height;
guint navigation_timeout;
gdouble drag_start_y;
gint initial_drag_offset;
};
G_END_DECLS
+4 -32
View File
@@ -1084,13 +1084,11 @@ gtk_menu_shell_enter_notify (GtkWidget *widget,
if (!gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
{
gboolean touchscreen_mode;
GdkDevice *source_device;
g_object_get (gtk_widget_get_settings (widget),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
source_device = gdk_event_get_source_device ((GdkEvent *) event);
if (touchscreen_mode)
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
_gtk_menu_item_popup_submenu (menu_item, TRUE);
}
}
@@ -1612,45 +1610,19 @@ gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell,
GtkMenuShellPrivate *priv = menu_shell->priv;
GtkMenuShell *parent_menu_shell = NULL;
gboolean had_selection;
gboolean touchscreen_mode;
priv->in_unselectable_item = FALSE;
had_selection = priv->active_menu_item != NULL;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
if (priv->parent_menu_shell)
parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
switch (direction)
{
case GTK_MENU_DIR_PARENT:
if (touchscreen_mode &&
priv->active_menu_item &&
GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
if (parent_menu_shell)
{
/* if we are on a menu item that has an open submenu but the
* focus is not in that submenu (e.g. because it's empty or
* has only insensitive items), close that submenu instead of
* running into the code below which would close *this* menu.
*/
_gtk_menu_item_popdown_submenu (priv->active_menu_item);
_gtk_menu_shell_update_mnemonics (menu_shell);
}
else if (parent_menu_shell)
{
if (touchscreen_mode)
{
/* close menu when returning from submenu. */
_gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
_gtk_menu_shell_update_mnemonics (parent_menu_shell);
break;
}
if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
gtk_menu_shell_deselect (menu_shell);
+29 -7
View File
@@ -3185,7 +3185,7 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook)
{
if (priv->during_reorder)
{
gint old_page_num, page_num;
gint old_page_num, page_num, i;
GList *element;
element = get_drop_position (notebook);
@@ -3194,9 +3194,16 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook)
gtk_notebook_child_reordered (notebook, page);
if (priv->has_scrolled || old_page_num != page_num)
g_signal_emit (notebook,
notebook_signals[PAGE_REORDERED], 0,
page->child, page_num);
{
for (element = priv->children, i = 0; element; element = element->next, i++)
{
if (MIN (old_page_num, page_num) <= i && i <= MAX (old_page_num, page_num))
gtk_widget_child_notify (((GtkNotebookPage *) element->data)->child, "position");
}
g_signal_emit (notebook,
notebook_signals[PAGE_REORDERED], 0,
page->child, page_num);
}
priv->has_scrolled = FALSE;
priv->during_reorder = FALSE;
@@ -4097,7 +4104,7 @@ gtk_notebook_remove (GtkContainer *container,
GtkNotebook *notebook = GTK_NOTEBOOK (container);
GtkNotebookPrivate *priv = notebook->priv;
GtkNotebookPage *page;
GList *children;
GList *children, *list;
gint page_num = 0;
children = priv->children;
@@ -4117,8 +4124,15 @@ gtk_notebook_remove (GtkContainer *container,
g_object_ref (widget);
list = children->next;
gtk_notebook_real_remove (notebook, children);
while (list)
{
gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position");
list = list->next;
}
g_signal_emit (notebook,
notebook_signals[PAGE_REMOVED],
0,
@@ -4566,6 +4580,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
GtkNotebookPrivate *priv = notebook->priv;
GtkNotebookPage *page;
gint nchildren;
GList *list;
gtk_widget_freeze_child_notify (child);
@@ -4648,7 +4663,14 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
gtk_widget_child_notify (child, "tab-fill");
gtk_widget_child_notify (child, "tab-label");
gtk_widget_child_notify (child, "menu-label");
gtk_widget_child_notify (child, "position");
list = g_list_nth (priv->children, position);
while (list)
{
gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position");
list = list->next;
}
gtk_widget_thaw_child_notify (child);
/* The page-added handler might have reordered the pages, re-get the position */
@@ -8017,7 +8039,7 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
/* Move around the menu items if necessary */
gtk_notebook_child_reordered (notebook, page);
for (list = priv->children, i = 0; list; list = list->next)
for (list = priv->children, i = 0; list; list = list->next, i++)
{
if (MIN (old_pos, position) <= i && i <= MAX (old_pos, position))
gtk_widget_child_notify (((GtkNotebookPage *) list->data)->child, "position");
+3 -3
View File
@@ -37,8 +37,8 @@
*
* GtkOverlay is a container which contains a single main child, on top
* of which it can place <firstterm>overlay</firstterm> widgets. The
* position of each overlay widget is determined by its #GtkWidget::halign
* and #GtkWidget::valign properties. E.g. a widget with both alignments
* position of each overlay widget is determined by its #GtkWidget:halign
* and #GtkWidget:valign properties. E.g. a widget with both alignments
* set to %GTK_ALIGN_START will be placed at the top left corner of the
* main widget, whereas an overlay with halign set to %GTK_ALIGN_CENTER
* and valign set to %GTK_ALIGN_END will be placed a the bottom edge of
@@ -605,7 +605,7 @@ gtk_overlay_new (void)
* added with gtk_container_add().
*
* The position at which @widget is placed is determined
* from its #GtkWidget::halign and #GtkWidget::valign properties.
* from its #GtkWidget:halign and #GtkWidget:valign properties.
*
* Since: 3.2
*/

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