Compare commits

...

56 Commits

Author SHA1 Message Date
Benjamin Otte
9271fa8bc7 a11y: Ignore deprecation warnings for ATK focus tracker 2014-01-28 19:49:22 +01:00
Benjamin Otte
d8fa2b3d03 window: Return a value from a non-void function 2014-01-28 19:49:10 +01:00
Benjamin Otte
d8aa468eec magnifier: Don't return a value from a void function 2014-01-28 19:48:52 +01:00
Carlos Garnacho
7378331a19 popover: Update child visibility when scrolling happens
If pointing_to starts falling outside of the parent scrollable allocation,
the popover will be automatically hidden, and shown back again when
pointing_to scrolls back to visibility.
2014-01-22 16:45:01 +01:00
Carlos Garnacho
8375987cce popover: Track parent scrollable adjustments
This makes sure popovers follow the relative_to widget if it is
contained within a GtkScrollable.
2014-01-22 16:43:37 +01:00
Carlos Garnacho
671875dd6e texthandle: Update child visibility of handles within scrollables
If the rect a handle points to starts falling outside of the parent
scrollable allocation, the handle will be automatically hidden, and
shown again when the rectangle is visible too.
2014-01-22 16:41:00 +01:00
Carlos Garnacho
908bae6e2d texthandle: Track parent scrollable adjustments
This makes sure texthandles follow the parent if it is contained within a
GtkScrollable.
2014-01-22 16:39:10 +01:00
Carlos Garnacho
9ee8e02d42 texthandle: ensure handles are recreated on parent hierarchy changes
This ensures the handles come out right even if the parent widget is
reparented to a different toplevel.
2014-01-22 16:37:43 +01:00
Carlos Garnacho
7cf6174709 popover: fix g-i warning 2014-01-22 16:27:44 +01:00
Carlos Garnacho
000cd7d8c5 popover: Fix documentation blurb
The grabbing behavior is no longer exclusively controlled by the caller,
mention gtk_popover_set_modal().
2014-01-22 16:26:13 +01:00
Matthias Clasen
426acda929 header bar: Make it possible to have no title
Add a custom title had the side-effect of showing the widget.
That is not right, adding children and managing their visibility
should be independent. The headerbar size allocation code also
made the assumption that a custom title is always visible.

With these changes, GtkHeaderBar should be usable in situations
where the centering functionality is not required, and it is
important to freely pack content at both ends, such as in nautilus.

https://bugzilla.gnome.org/show_bug.cgi?id=722340
2014-01-17 19:43:22 -05:00
Carlos Garnacho
0d36d5bee1 texthandle: Use GtkWindow private popover API. 2014-01-17 18:59:24 +01:00
Carlos Garnacho
96e35b1dc3 popover: use GtkWindow private popover API 2014-01-17 18:59:24 +01:00
Carlos Garnacho
beeb4e1436 window: Make popover window private 2014-01-17 18:59:24 +01:00
Carlos Garnacho
d2cbbd84f8 window: Use GList to store popover structs
When all popovers are removed on destroy(), if a popover is nested into
(eg. with relative_to within) another popover, the removal of one can
lead to the other being removed while the hashtable is being iterated,
which would lead to undefined behavior in further iterations.

Then, use a GList to store popovers, iterating can be made more resilient
on these situations, and unless on pathological cases there's not going
to be as many of those popovers as to cause performance decreases at the
times those are iterated.
2014-01-17 18:59:24 +01:00
Carlos Garnacho
f7824bdc51 textview: Set GTK_STYLE_CLASS_OSD on text selection popovers 2014-01-17 18:59:24 +01:00
Carlos Garnacho
6961a64fbd entry: Set GTK_STYLE_CLASS_OSD on text selection popovers 2014-01-17 18:59:24 +01:00
Carlos Garnacho
12f0603857 popover: Do not set GTK_STYLE_CLASS_OSD directly
That's up to the caller, popovers are by design not only meant to
have that role.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
52fe7ca9bd popover: Fix allocation of CSS margins
that was forgotten about, leaving no room for theme shadows that'd
make popovers look less flat.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
7a4655c875 popover: Flip popovers positioning on left/right on RTL.
If widgets have GTK_TEXT_DIRECTION_RTL, popovers being positioned
on GTK_POS_LEFT/RIGHT will default to appearing on the other side
too.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
fe9cfbe1d9 window: Remove popovers on dispose() before unsetting focus.
The popovers may return keyboard grabs to previous widgets, so if
called after unsetting the focus, the window may be left with a
dangling GtkWidget that would cause crash at later dispose() calls.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
2eae9dea7c entry: Improve positioning of touch selection magnifier
Always show completely above or below entry to avoid covering
content, and limit horizontal position so it doesn't overflow
to the right.
2014-01-17 18:59:23 +01:00
Matthias Clasen
d4e367756d Implement wfh functions
With only get_preferred_width and get_preferred_height implemented,
we end up calling the GtkBin height_for_width implmementation, which
knows nothing about the margins and paddings that GtkPopover needs.
As a result, a listbox added to a popover was getting cut off
at the bottom.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
c5611872ab popover: Remember last focused widget on the toplevel when a popover is shown
This is so the previously focused widget can regain focus when a modal popover
is dismissed.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
922b36e420 popover: Add a "modal" boolean property to GtkPopover
This property is TRUE by default, when a popover is modal, it
will automatically set a GTK+ grab on the popover, and grab
the keyboard focus into the popover.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
8e6fa0313b gtk-demo: Fix crash after running popovers demo
The GtkBuilder window containing the complex popover UI was left
dangling, and with a dangling pointer to its former child, causing
crashes on gtk_grab_notify() after the popover was destroyed.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
8b9efb612f popover: Fix memory management of popovers
Popovers are strange in the sense that they aren't attached to a
parent directly, they rely on the relative_to widget so the toplevel
is shared, and when they have a parent, it is the toplevel itself,
not relative_to. This also means that there are conditions where the
popover loses it's parent, so they must survive unparenting.

The previous code would be floating the last reference as soon as the
parent is gone, but it was non-obvious who'd own that reference. So
fix this situation by granting the ownership of popovers to their
relative_to widget, an extra reference may be held by the toplevel
when the popover has a parent, but the popover object will be
guaranteed to be alive as long as the parent lives.

This way, memory management of popovers is as hidden from the user
as regular widgets within containers are, users are free to call
gtk_widget_destroy() on a popover, but it'd eventually become
destructed when relative_to is.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
e67116dbb6 popover: Implement keyboard focus behavior
When a popover is focused, the focus is forwarded so the first
child what would get the focus actually gets it. Also, implement
correct focus chain, so the keyboard focus stays within the popover
when navigating with keyboard.
2014-01-17 18:59:23 +01:00
Carlos Garnacho
b3ec18dda9 texthandle: Fix arguments in ::style-updated callback 2014-01-17 18:59:23 +01:00
Carlos Garnacho
4aa457fcc9 gtkmain: Let windows handle WM-related events before delivering to the grab_widget
This makes it possible to move/resize client-side decorated windows that are
otherwise obscured by a GTK+ grab somewhere else, either a popover within the
window itself or a modal dialog above the window.
2014-01-17 18:59:22 +01:00
Carlos Garnacho
86c3c2c323 entry: Show a GtkMagnifier popover on touch selection 2014-01-17 18:54:22 +01:00
Carlos Garnacho
0db0eb77a0 texthandle: Remove relative_to API
It's unused now, GtkTextHandle uses widget coordinates.
2014-01-17 18:54:22 +01:00
Carlos Garnacho
f4dc912b7e texthandles: Use GtkWindow popovers API
This offers the same behavior, but GDK_WINDOW_TEMP windows aren't used
anymore, involving less translations from/to root coordinates, plus no
glitches in having handles snap to content as windows move.
2014-01-17 18:54:22 +01:00
Carlos Garnacho
771c6152cc window: Keep track of popover children mapped status
In order to maintain visibility of the GdkWindow that's the parent window
of the popover widget.
2014-01-17 18:54:22 +01:00
Carlos Garnacho
7a5199b11a window: Add gtk_window_get_popover_position()
A getter to complement the setter
2014-01-17 18:54:22 +01:00
Carlos Garnacho
32e49cc101 entry: Set use-underline in popover GtkToolButtons 2014-01-17 18:54:22 +01:00
Carlos Garnacho
e6667092d5 textview: Set use-underline in popover GtkToolButtons 2014-01-17 18:54:22 +01:00
Carlos Garnacho
e02a3d1dd8 textview: Use GtkMagnifier on touch selection
The magnifier renders the area covered by the finger, making it easier to follow
the text being selected.
2014-01-17 18:54:22 +01:00
Carlos Garnacho
e6dd8c9ca9 Add GtkMagnifier
This is a private widget that takes another widget on construction, and is able
to render parts of it, possibly at a different magnification level.
2014-01-17 18:54:22 +01:00
Carlos Garnacho
40557bf64d pixelcache: check whether cached surface and cairo_t scales match 2014-01-17 18:54:21 +01:00
Carlos Garnacho
bb3e912b59 gtk-demo: Add GtkPopovers demo
In this demo several widget create popovers with different complexities,
positions, and grabbing behavior.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
8a4f597379 popover: Add documentation 2014-01-17 18:54:21 +01:00
Carlos Garnacho
3ce119c47f popover: Honor GtkContainer::border-width
The border width is now set around the contained widget.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
3132921942 popover: remove GTK+ grab (if any) on unmap
If there is a GTK+ grab on the popover, ensure that it's removed when it's
unmapped. If no GTK+ grab was performed on the popover, this function will
do nothing.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
fe288b426e popover: listen harder on the widget being pointed to
Hierarchy, size allocation and widget visibility are now listened
to in order to update the popover state accordingly.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
a4c306deb4 Introduce GtkPopover
Now that the GtkBubbleWindow object has been cleaned up and made
more generic, rename it as GtkPopover and make it public.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
2bfab05858 bubblewindow: Remove popup/popdown() APIs
Those functions aren't as useful anymore, hiding/showing can be
controlled by setting the widget visibility, and grabbing can be
achieved by performing a GTK+ grab.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
173e5b5df0 entry: Avoid bubblewindow popup/popdown API
Besides setting all positioning properties at once, popup() would just
show the widget, so do that directly after just updating the position.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
a171b0e3d3 textview: Avoid bubblewindow popup/popdown API
Besides setting all positioning properties at once, popup() would just
show the widget, so do that directly after just updating the position.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
96cec1b630 bubblewindow: Point to the entire widget area by default
This way pointing_to is not fully needed, unless you're pointing
to an specific rectangle within the widget, passing NULL would unset
the region too.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
ac1a647c93 bubblewindow: check the border-radius when rendering the bubble tail. 2014-01-17 18:54:21 +01:00
Carlos Garnacho
5bb749c662 bubblewindow: Improve overflow cases
If the bubble window doesn't fit into one direction, it must
lay at the other side of the pointed_to rectangle.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
3ad4f3dec5 bubblewindow: Make it relative to GtkWidget coordinates
GdkWindows are gone now from the API, the pointed_to rectangle
is from now on relative to the widget allocation. GtkTextView
and GtkEntry were updated to adapt to this change.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
5028e55ee8 bubblewindow: Remove grab API
This is not as necessary now that bubble windows are popovers, if
a modal behavior is wanted on popover contents, a GTK+ grab on the
popover widget will suffice.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
706afc07ac bubblewindow: Turn into a GtkWindow popover
This way GtkBubbleWindows are rendered on top of all window content, without
the need of a GDK_WINDOW_TEMP window.
2014-01-17 18:54:21 +01:00
Carlos Garnacho
3b86dec4dc window: Add lowlevel popovers API
Popovers are transient floating widgets that are confined to the
window space. These have their own GdkWindow that is set on top
of the regular window contents, so they can be used for popup menu
alike UIs with custom popup/popdown/grabs behavior.
2014-01-17 18:54:21 +01:00
25 changed files with 3376 additions and 1675 deletions

View File

@@ -41,6 +41,7 @@ demos = \
panes.c \
pickers.c \
pixbufs.c \
popover.c \
printing.c \
revealer.c \
rotated_text.c \

View File

@@ -110,6 +110,7 @@
<file>panes.c</file>
<file>pickers.c</file>
<file>pixbufs.c</file>
<file>popover.c</file>
<file>printing.c</file>
<file>revealer.c</file>
<file>rotated_text.c</file>
@@ -133,4 +134,7 @@
<file>messages.txt</file>
<file>apple-red.png</file>
</gresource>
<gresource prefix="/popover">
<file>popover.ui</file>
</gresource>
</gresources>

185
demos/gtk-demo/popover.c Normal file
View File

@@ -0,0 +1,185 @@
/* Popovers
*
* A bubble-like window containing contextual information or options.
* GtkPopovers can be attached to any widget, and will be displayed
* within the same window, but on top of all its content.
*/
#include <gtk/gtk.h>
static void
toggle_changed_cb (GtkToggleButton *button,
GtkWidget *popover)
{
gtk_widget_set_visible (popover,
gtk_toggle_button_get_active (button));
}
static GtkWidget *
create_popover (GtkWidget *parent,
GtkWidget *child,
GtkPositionType pos)
{
GtkWidget *popover;
popover = gtk_popover_new (parent);
gtk_popover_set_position (GTK_POPOVER (popover), pos);
gtk_container_add (GTK_CONTAINER (popover), child);
gtk_container_set_border_width (GTK_CONTAINER (popover), 6);
gtk_widget_show (child);
return popover;
}
static GtkWidget *
create_complex_popover (GtkWidget *parent,
GtkPositionType pos)
{
GtkWidget *popover, *window, *content;
GtkBuilder *builder;
builder = gtk_builder_new ();
gtk_builder_add_from_resource (builder, "/popover/popover.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
content = gtk_bin_get_child (GTK_BIN (window));
g_object_ref (content);
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (content)),
content);
gtk_widget_destroy (window);
g_object_unref (builder);
popover = create_popover (parent, content, GTK_POS_BOTTOM);
g_object_unref (content);
gtk_widget_set_size_request (popover, 200, -1);
gtk_widget_set_vexpand (popover, TRUE);
gtk_widget_set_margin_start (popover, 10);
gtk_widget_set_margin_end (popover, 10);
gtk_widget_set_margin_bottom (popover, 10);
return popover;
}
static void
entry_size_allocate_cb (GtkEntry *entry,
GtkAllocation *allocation,
gpointer user_data)
{
GtkEntryIconPosition popover_pos;
GtkPopover *popover = user_data;
cairo_rectangle_int_t rect;
if (gtk_widget_is_visible (GTK_WIDGET (popover)))
{
popover_pos =
GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (entry),
"popover-icon-pos"));
gtk_entry_get_icon_area (entry, popover_pos, &rect);
gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
}
}
static void
entry_icon_press_cb (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data)
{
GtkWidget *popover = user_data;
cairo_rectangle_int_t rect;
gtk_entry_get_icon_area (entry, icon_pos, &rect);
gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
gtk_widget_show (popover);
g_object_set_data (G_OBJECT (entry), "popover-icon-pos",
GUINT_TO_POINTER (icon_pos));
}
static void
day_selected_cb (GtkCalendar *calendar,
gpointer user_data)
{
cairo_rectangle_int_t rect;
GtkAllocation allocation;
GtkWidget *popover;
GdkEvent *event;
event = gtk_get_current_event ();
if (event->type != GDK_BUTTON_PRESS)
return;
gdk_window_coords_to_parent (event->button.window,
event->button.x, event->button.y,
&event->button.x, &event->button.y);
gtk_widget_get_allocation (GTK_WIDGET (calendar), &allocation);
rect.x = event->button.x - allocation.x;
rect.y = event->button.y - allocation.y;
rect.width = rect.height = 1;
popover = create_popover (GTK_WIDGET (calendar),
gtk_entry_new (),
GTK_POS_BOTTOM);
gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
gtk_widget_show (popover);
gdk_event_free (event);
}
GtkWidget *
do_popover (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *popover, *box, *widget;
if (!window)
{
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 24);
gtk_container_set_border_width (GTK_CONTAINER (box), 24);
gtk_container_add (GTK_CONTAINER (window), box);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
widget = gtk_toggle_button_new_with_label ("Button");
popover = create_popover (widget,
gtk_label_new ("This popover does not grab input"),
GTK_POS_TOP);
gtk_popover_set_modal (GTK_POPOVER (popover), FALSE);
g_signal_connect (widget, "toggled",
G_CALLBACK (toggle_changed_cb), popover);
gtk_container_add (GTK_CONTAINER (box), widget);
widget = gtk_entry_new ();
popover = create_complex_popover (widget, GTK_POS_TOP);
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (widget),
GTK_ENTRY_ICON_PRIMARY, "edit-find");
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (widget),
GTK_ENTRY_ICON_SECONDARY, "edit-clear");
g_signal_connect (widget, "icon-press",
G_CALLBACK (entry_icon_press_cb), popover);
g_signal_connect (widget, "size-allocate",
G_CALLBACK (entry_size_allocate_cb), popover);
gtk_container_add (GTK_CONTAINER (box), widget);
widget = gtk_calendar_new ();
g_signal_connect (widget, "day-selected",
G_CALLBACK (day_selected_cb), NULL);
gtk_container_add (GTK_CONTAINER (box), widget);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show_all (window);
else
{
gtk_widget_destroy (window);
window = NULL;
}
return window;
}

103
demos/gtk-demo/popover.ui Normal file
View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.0 on Wed Nov 13 16:45:55 2013 -->
<interface>
<!-- interface-requires gtk+ 3.10 -->
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name Name -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Item 1</col>
</row>
<row>
<col id="0" translatable="yes">Item 2</col>
</row>
<row>
<col id="0" translatable="yes">Item 3</col>
</row>
<row>
<col id="0" translatable="yes">Item 4</col>
</row>
<row>
<col id="0" translatable="yes">Item 5</col>
</row>
<row>
<col id="0" translatable="yes">Item 6</col>
</row>
<row>
<col id="0" translatable="yes">Item 7</col>
</row>
<row>
<col id="0" translatable="yes">Item 8</col>
</row>
<row>
<col id="0" translatable="yes">Item 9</col>
</row>
<row>
<col id="0" translatable="yes">Item 10</col>
</row>
</data>
</object>
<object class="GtkWindow" id="window">
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find</property>
<property name="secondary_icon_name">edit-clear</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="treeview1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="model">liststore1</property>
<property name="headers_visible">False</property>
<property name="enable_search">False</property>
<property name="search_column">2</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="column1">
<child>
<object class="GtkCellRendererText" id="cellrenderer1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -190,6 +190,7 @@
<xi:include href="xml/gtkmenutoolbutton.xml" />
<xi:include href="xml/gtktoggletoolbutton.xml" />
<xi:include href="xml/gtkradiotoolbutton.xml" />
<xi:include href="xml/gtkpopover.xml" />
</chapter>
<chapter id="SelectorWidgets">

View File

@@ -7831,3 +7831,18 @@ gtk_flow_box_child_get_index
gtk_flow_box_child_is_selected
gtk_flow_box_child_changed
</SECTION>
<SECTION>
<FILE>gtkpopover</FILE>
<TITLE>GtkPopover</TITLE>
GtkPopover
gtk_popover_new
gtk_popover_set_relative_to
gtk_popover_get_relative_to
gtk_popover_set_pointing_to
gtk_popover_get_pointing_to
gtk_popover_set_position
gtk_popover_get_position
gtk_popover_set_modal
gtk_popover_get_modal
</SECTION>

View File

@@ -126,6 +126,7 @@ gtk_paned_get_type
gtk_paper_size_get_type
gtk_places_sidebar_get_type
@ENABLE_ON_X11@gtk_plug_get_type
gtk_popover_get_type
@DISABLE_ON_W32@gtk_printer_get_type
gtk_print_context_get_type
@DISABLE_ON_W32@gtk_print_job_get_type

View File

@@ -296,6 +296,7 @@ gtk_public_h_sources = \
gtkpapersize.h \
gtkplacessidebar.h \
gtkplug.h \
gtkpopover.h \
gtkprintcontext.h \
gtkprintoperation.h \
gtkprintoperationpreview.h \
@@ -411,7 +412,6 @@ gtk_private_h_sources = \
gtkbookmarksmanager.h \
gtkborderimageprivate.h \
gtkboxprivate.h \
gtkbubblewindowprivate.h \
gtkbuilderprivate.h \
gtkbuttonprivate.h \
gtkcairoblurprivate.h \
@@ -489,6 +489,7 @@ gtk_private_h_sources = \
gtkkeyhash.h \
gtklabelprivate.h \
gtklockbuttonprivate.h \
gtkmagnifierprivate.h \
gtkmenubuttonprivate.h \
gtkmenuprivate.h \
gtkmenuitemprivate.h \
@@ -628,7 +629,6 @@ gtk_base_c_sources = \
gtkborder.c \
gtkborderimage.c \
gtkbox.c \
gtkbubblewindow.c \
gtkbuildable.c \
gtkbuilder.c \
gtkbuilderparser.c \
@@ -763,6 +763,7 @@ gtk_base_c_sources = \
gtkliststore.c \
gtklockbutton.c \
gtkmain.c \
gtkmagnifier.c \
gtkmarshalers.c \
gtkmenu.c \
gtkmenubar.c \
@@ -800,6 +801,7 @@ gtk_base_c_sources = \
gtkprivatetypebuiltins.c \
gtkprogressbar.c \
gtkpixelcache.c \
gtkpopover.c \
gtkradiobutton.c \
gtkradiomenuitem.c \
gtkradiotoolbutton.c \

View File

@@ -524,9 +524,11 @@ gail_focus_notify (GtkWidget *widget)
/*
* Do not report focus on redundant object
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
if (atk_obj &&
(atk_object_get_role(atk_obj) != ATK_ROLE_REDUNDANT_OBJECT))
atk_focus_tracker_notify (atk_obj);
G_GNUC_END_IGNORE_DEPRECATIONS;
if (atk_obj && transient)
g_object_unref (atk_obj);
if (subsequent_focus_widget)
@@ -976,8 +978,10 @@ _gtk_accessibility_init (void)
initialized = TRUE;
quark_focus_object = g_quark_from_static_string ("gail-focus-object");
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
atk_focus_tracker_init (gail_focus_tracker_init);
focus_tracker_id = atk_add_focus_tracker (gail_focus_tracker);
G_GNUC_END_IGNORE_DEPRECATIONS;
_gtk_accessibility_override_atk_util ();
do_window_event_initialization ();

View File

@@ -144,6 +144,7 @@
#include <gtk/gtkpapersize.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkplacessidebar.h>
#include <gtk/gtkpopover.h>
#include <gtk/gtkprintcontext.h>
#include <gtk/gtkprintoperation.h>
#include <gtk/gtkprintoperationpreview.h>

File diff suppressed because it is too large Load Diff

View File

@@ -1,81 +0,0 @@
/* GTK - The GIMP Toolkit
* Copyright © 2013 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_BUBBLE_WINDOW_H__
#define __GTK_BUBBLE_WINDOW_H__
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_BUBBLE_WINDOW (_gtk_bubble_window_get_type ())
#define GTK_BUBBLE_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_BUBBLE_WINDOW, GtkBubbleWindow))
#define GTK_BUBBLE_WINDOW_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_BUBBLE_WINDOW, GtkBubbleWindowClass))
#define GTK_IS_BUBBLE_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_BUBBLE_WINDOW))
#define GTK_IS_BUBBLE_WINDOW_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_BUBBLE_WINDOW))
#define GTK_BUBBLE_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_BUBBLE_WINDOW, GtkBubbleWindowClass))
typedef struct _GtkBubbleWindow GtkBubbleWindow;
typedef struct _GtkBubbleWindowClass GtkBubbleWindowClass;
struct _GtkBubbleWindow
{
GtkWindow parent_instance;
/*< private >*/
gpointer priv;
};
struct _GtkBubbleWindowClass
{
GtkWindowClass parent_class;
};
GType _gtk_bubble_window_get_type (void) G_GNUC_CONST;
GtkWidget * _gtk_bubble_window_new (void);
void _gtk_bubble_window_set_relative_to (GtkBubbleWindow *window,
GdkWindow *relative_to);
GdkWindow * _gtk_bubble_window_get_relative_to (GtkBubbleWindow *window);
void _gtk_bubble_window_set_pointing_to (GtkBubbleWindow *window,
cairo_rectangle_int_t *rect);
gboolean _gtk_bubble_window_get_pointing_to (GtkBubbleWindow *window,
cairo_rectangle_int_t *rect);
void _gtk_bubble_window_set_position (GtkBubbleWindow *window,
GtkPositionType position);
GtkPositionType
_gtk_bubble_window_get_position (GtkBubbleWindow *window);
void _gtk_bubble_window_popup (GtkBubbleWindow *window,
GdkWindow *relative_to,
cairo_rectangle_int_t *pointing_to,
GtkPositionType position);
void _gtk_bubble_window_popdown (GtkBubbleWindow *window);
gboolean _gtk_bubble_window_grab (GtkBubbleWindow *window,
GdkDevice *device,
guint32 activate_time);
void _gtk_bubble_window_ungrab (GtkBubbleWindow *window);
G_END_DECLS
#endif /* __GTK_BUBBLE_WINDOW_H__ */

View File

@@ -63,8 +63,9 @@
#include "gtkwidgetprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtktexthandleprivate.h"
#include "gtkbubblewindowprivate.h"
#include "gtkpopover.h"
#include "gtktoolbar.h"
#include "gtkmagnifierprivate.h"
#include "a11y/gtkentryaccessible.h"
@@ -158,11 +159,14 @@ struct _GtkEntryPrivate
gchar *placeholder_text;
GtkBubbleWindow *bubble_window;
GtkWidget *bubble_window;
GtkTextHandle *text_handle;
GtkWidget *selection_bubble;
guint selection_bubble_timeout_id;
GtkWidget *magnifier_popover;
GtkWidget *magnifier;
gfloat xalign;
gint ascent; /* font ascent in pango units */
@@ -2665,6 +2669,18 @@ gtk_entry_init (GtkEntry *entry)
G_CALLBACK (gtk_entry_handle_dragged), entry);
g_signal_connect (priv->text_handle, "drag-finished",
G_CALLBACK (gtk_entry_handle_drag_finished), entry);
priv->magnifier = _gtk_magnifier_new (GTK_WIDGET (entry));
gtk_widget_set_size_request (priv->magnifier, 100, 60);
_gtk_magnifier_set_magnification (GTK_MAGNIFIER (priv->magnifier), 2.0);
priv->magnifier_popover = gtk_popover_new (GTK_WIDGET (entry));
gtk_style_context_add_class (gtk_widget_get_style_context (priv->magnifier_popover),
GTK_STYLE_CLASS_OSD);
gtk_popover_set_modal (GTK_POPOVER (priv->magnifier_popover), FALSE);
gtk_container_add (GTK_CONTAINER (priv->magnifier_popover),
priv->magnifier);
gtk_container_set_border_width (GTK_CONTAINER (priv->magnifier_popover), 4);
gtk_widget_show (priv->magnifier);
}
static void
@@ -2904,6 +2920,7 @@ gtk_entry_finalize (GObject *object)
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
gtk_widget_destroy (priv->magnifier_popover);
g_object_unref (priv->text_handle);
g_free (priv->placeholder_text);
g_free (priv->im_module);
@@ -3209,7 +3226,6 @@ gtk_entry_realize (GtkWidget *widget)
gtk_entry_adjust_scroll (entry);
gtk_entry_update_primary_selection (entry);
_gtk_text_handle_set_relative_to (priv->text_handle, priv->text_area);
/* If the icon positions are already setup, create their windows.
* Otherwise if they don't exist yet, then construct_icon_info()
@@ -3237,7 +3253,6 @@ gtk_entry_unrealize (GtkWidget *widget)
gtk_entry_reset_layout (entry);
gtk_im_context_set_client_window (priv->im_context, NULL);
_gtk_text_handle_set_relative_to (priv->text_handle, NULL);
clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY);
if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
@@ -4062,13 +4077,22 @@ gtk_entry_move_handle (GtkEntry *entry,
}
else
{
GtkAllocation primary, secondary;
GdkRectangle rect;
gint win_x, win_y;
rect.x = CLAMP (x, 0, gdk_window_get_width (priv->text_area));
rect.y = y;
get_icon_allocations (entry, &primary, &secondary);
gtk_entry_get_text_area_size (entry, &win_x, &win_y, NULL, NULL);
rect.x = CLAMP (x, 0, gdk_window_get_width (priv->text_area)) + win_x;
rect.y = y + win_y;
rect.width = 1;
rect.height = height;
if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
rect.x += secondary.width;
else
rect.x += primary.width;
_gtk_text_handle_set_visible (priv->text_handle, pos, TRUE);
_gtk_text_handle_set_position (priv->text_handle, pos, &rect);
}
@@ -4412,7 +4436,10 @@ gtk_entry_button_release (GtkWidget *widget,
priv->in_drag = 0;
}
else if (is_touchscreen)
gtk_entry_selection_bubble_popup_set (entry);
{
gtk_entry_selection_bubble_popup_set (entry);
gtk_widget_hide (priv->magnifier_popover);
}
priv->button = 0;
priv->device = NULL;
@@ -4435,6 +4462,36 @@ _gtk_entry_get_selected_text (GtkEntry *entry)
return text;
}
static void
gtk_entry_show_magnifier (GtkEntry *entry,
gint x,
gint y)
{
GtkAllocation allocation, primary, secondary;
cairo_rectangle_int_t rect;
GtkEntryPrivate *priv;
gtk_widget_get_allocation (GTK_WIDGET (entry), &allocation);
get_icon_allocations (entry, &primary, &secondary);
priv = entry->priv;
rect.x = CLAMP (x, 0, allocation.width - primary.width - secondary.width);
rect.width = 1;
rect.y = 0;
rect.height = allocation.height;
if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
rect.x += secondary.width;
else
rect.x += primary.width;
_gtk_magnifier_set_coords (GTK_MAGNIFIER (priv->magnifier), rect.x,
rect.y + allocation.height / 2);
gtk_popover_set_pointing_to (GTK_POPOVER (priv->magnifier_popover),
&rect);
gtk_widget_show (priv->magnifier_popover);
}
static gint
gtk_entry_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
@@ -4603,10 +4660,19 @@ gtk_entry_motion_notify (GtkWidget *widget,
/* Update touch handles' position */
if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN)
gtk_entry_update_handles (entry,
(priv->current_pos == priv->selection_bound) ?
GTK_TEXT_HANDLE_MODE_CURSOR :
GTK_TEXT_HANDLE_MODE_SELECTION);
{
gint x, y;
gtk_entry_update_handles (entry,
(priv->current_pos == priv->selection_bound) ?
GTK_TEXT_HANDLE_MODE_CURSOR :
GTK_TEXT_HANDLE_MODE_SELECTION);
gtk_entry_get_text_area_size (entry, &x, &y, NULL, NULL);
x += event->x;
y += event->y;
gtk_entry_show_magnifier (entry, x, y);
}
}
return TRUE;
@@ -6403,6 +6469,7 @@ gtk_entry_handle_dragged (GtkTextHandle *handle,
{
gint cursor_pos, selection_bound_pos, tmp_pos;
GtkEntryPrivate *priv = entry->priv;
GtkAllocation primary, secondary;
GtkTextHandleMode mode;
gint *min, *max;
@@ -6411,6 +6478,14 @@ gtk_entry_handle_dragged (GtkTextHandle *handle,
cursor_pos = priv->current_pos;
selection_bound_pos = priv->selection_bound;
mode = _gtk_text_handle_get_mode (handle);
get_icon_allocations (entry, &primary, &secondary);
if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
x -= secondary.width;
else
x -= primary.width;
tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset);
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR ||
@@ -6458,6 +6533,8 @@ gtk_entry_handle_dragged (GtkTextHandle *handle,
gtk_entry_update_handles (entry, mode);
}
gtk_entry_show_magnifier (entry, x, y);
}
static void
@@ -6466,6 +6543,7 @@ gtk_entry_handle_drag_finished (GtkTextHandle *handle,
GtkEntry *entry)
{
gtk_entry_selection_bubble_popup_set (entry);
gtk_widget_hide (entry->priv->magnifier_popover);
}
@@ -9361,7 +9439,7 @@ activate_bubble_cb (GtkWidget *item,
{
const gchar *signal = g_object_get_data (G_OBJECT (item), "gtk-signal");
g_signal_emit_by_name (entry, signal);
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (entry->priv->selection_bubble));
gtk_widget_hide (entry->priv->selection_bubble);
}
static void
@@ -9372,6 +9450,7 @@ append_bubble_action (GtkEntry *entry,
gboolean sensitive)
{
GtkToolItem *item = gtk_tool_button_new (NULL, label);
gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (item), TRUE);
g_object_set_data (G_OBJECT (item), I_("gtk-signal"), (char *)signal);
g_signal_connect (item, "clicked", G_CALLBACK (activate_bubble_cb), entry);
gtk_widget_set_sensitive (GTK_WIDGET (item), sensitive);
@@ -9387,7 +9466,7 @@ bubble_targets_received (GtkClipboard *clipboard,
GtkEntry *entry = user_data;
GtkEntryPrivate *priv = entry->priv;
cairo_rectangle_int_t rect;
GtkAllocation allocation;
GtkAllocation allocation, primary, secondary;
gint start_x, end_x;
gboolean has_selection;
gboolean has_clipboard;
@@ -9405,7 +9484,13 @@ bubble_targets_received (GtkClipboard *clipboard,
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
priv->selection_bubble = _gtk_bubble_window_new ();
priv->selection_bubble = gtk_popover_new (GTK_WIDGET (entry));
gtk_style_context_add_class (gtk_widget_get_style_context (priv->selection_bubble),
GTK_STYLE_CLASS_OSD);
gtk_popover_set_position (GTK_POPOVER (priv->selection_bubble),
GTK_POS_TOP);
gtk_popover_set_modal (GTK_POPOVER (priv->selection_bubble), FALSE);
toolbar = GTK_WIDGET (gtk_toolbar_new ());
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
@@ -9434,7 +9519,9 @@ bubble_targets_received (GtkClipboard *clipboard,
start_x -= priv->scroll_offset;
start_x = CLAMP (start_x, 0, gdk_window_get_width (priv->text_area));
rect.y = 0;
gtk_entry_get_text_area_size (entry, &rect.x, &rect.y, NULL, NULL);
get_icon_allocations (entry, &primary, &secondary);
rect.x += primary.width;
rect.height = gdk_window_get_height (priv->text_area);
if (has_selection)
@@ -9442,17 +9529,17 @@ bubble_targets_received (GtkClipboard *clipboard,
end_x = gtk_entry_get_selection_bound_location (entry) - priv->scroll_offset;
end_x = CLAMP (end_x, 0, gdk_window_get_width (priv->text_area));
rect.x = MIN (start_x, end_x);
rect.width = MAX (start_x, end_x) - rect.x;
rect.x += MIN (start_x, end_x);
rect.width = MAX (start_x, end_x) - MIN (start_x, end_x);
}
else
{
rect.x = start_x;
rect.x += start_x;
rect.width = 0;
}
_gtk_bubble_window_popup (GTK_BUBBLE_WINDOW (priv->selection_bubble),
priv->text_area, &rect, GTK_POS_TOP);
gtk_popover_set_pointing_to (GTK_POPOVER (priv->selection_bubble), &rect);
gtk_widget_show (priv->selection_bubble);
priv->selection_bubble_timeout_id = 0;
}
@@ -9477,7 +9564,7 @@ gtk_entry_selection_bubble_popup_unset (GtkEntry *entry)
priv = entry->priv;
if (priv->selection_bubble)
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
gtk_widget_hide (priv->selection_bubble);
if (priv->selection_bubble_timeout_id)
{

View File

@@ -727,8 +727,7 @@ gtk_header_bar_compute_size_for_orientation (GtkWidget *widget,
}
}
if (priv->label_box != NULL &&
gtk_widget_get_visible (priv->label_box))
if (priv->label_box != NULL)
{
gtk_widget_get_preferred_width (priv->label_sizing_box,
&child_size, &child_natural);
@@ -862,8 +861,7 @@ gtk_header_bar_compute_size_for_opposing_orientation (GtkWidget *widget,
i += 1;
}
if (priv->label_box != NULL &&
gtk_widget_get_visible (priv->label_box))
if (priv->label_box != NULL)
{
gtk_widget_get_preferred_height (priv->label_sizing_box,
&child_minimum, &child_natural);
@@ -990,14 +988,16 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
i++;
}
if (priv->custom_title)
if (priv->custom_title &&
gtk_widget_get_visible (priv->custom_title))
{
gtk_widget_get_preferred_width_for_height (priv->custom_title,
height,
&title_minimum_size,
&title_natural_size);
}
else
if (priv->label_box != NULL)
{
gtk_widget_get_preferred_width_for_height (priv->label_box,
height,
@@ -1105,9 +1105,11 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
if (direction == GTK_TEXT_DIR_RTL)
child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
if (priv->custom_title)
if (priv->custom_title != NULL &&
gtk_widget_get_visible (priv->custom_title))
gtk_widget_size_allocate (priv->custom_title, &child_allocation);
else
if (priv->label_box != NULL)
gtk_widget_size_allocate (priv->label_box, &child_allocation);
if (priv->titlebar_start_box)
@@ -1295,7 +1297,6 @@ gtk_header_bar_set_custom_title (GtkHeaderBar *bar,
gtk_widget_set_parent (priv->custom_title, GTK_WIDGET (bar));
gtk_widget_set_valign (priv->custom_title, GTK_ALIGN_CENTER);
gtk_widget_show (title_widget);
if (priv->label_box != NULL)
{

View File

@@ -3285,7 +3285,9 @@ _gtk_icon_view_set_cursor_item (GtkIconView *icon_view,
if (item_obj != NULL)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
atk_focus_tracker_notify (item_obj);
G_GNUC_END_IGNORE_DEPRECATIONS;
atk_object_notify_state_change (item_obj, ATK_STATE_FOCUSED, TRUE);
g_object_unref (item_obj);
}

269
gtk/gtkmagnifier.c Normal file
View File

@@ -0,0 +1,269 @@
/* GTK - The GIMP Toolkit
* Copyright © 2013 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtk/gtk.h"
#include "gtkmagnifierprivate.h"
#include "gtkintl.h"
enum {
PROP_INSPECTED = 1,
PROP_MAGNIFICATION
};
typedef struct _GtkMagnifierPrivate GtkMagnifierPrivate;
struct _GtkMagnifierPrivate
{
GtkWidget *inspected;
gdouble magnification;
gint x;
gint y;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkMagnifier, _gtk_magnifier,
GTK_TYPE_WIDGET)
static void
_gtk_magnifier_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
switch (param_id)
{
case PROP_INSPECTED:
_gtk_magnifier_set_inspected (GTK_MAGNIFIER (object),
g_value_get_object (value));
break;
case PROP_MAGNIFICATION:
_gtk_magnifier_set_magnification (GTK_MAGNIFIER (object),
g_value_get_double (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
}
}
static void
_gtk_magnifier_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
GtkMagnifier *magnifier;
GtkMagnifierPrivate *priv;
magnifier = GTK_MAGNIFIER (object);
priv = _gtk_magnifier_get_instance_private (magnifier);
switch (param_id)
{
case PROP_INSPECTED:
g_value_set_object (value, priv->inspected);
break;
case PROP_MAGNIFICATION:
g_value_set_double (value, priv->magnification);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
}
}
static gboolean
_gtk_magnifier_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkAllocation allocation, inspected_alloc;
GtkMagnifier *magnifier;
GtkMagnifierPrivate *priv;
gdouble x, y;
magnifier = GTK_MAGNIFIER (widget);
priv = _gtk_magnifier_get_instance_private (magnifier);
if (!gtk_widget_is_visible (priv->inspected))
return FALSE;
gtk_widget_get_allocation (widget, &allocation);
gtk_widget_get_allocation (priv->inspected, &inspected_alloc);
cairo_translate (cr, allocation.width / 2, allocation.height / 2);
x = CLAMP (priv->x, 0, inspected_alloc.width);
y = CLAMP (priv->y, 0, inspected_alloc.height);
cairo_save (cr);
cairo_scale (cr, priv->magnification, priv->magnification);
cairo_translate (cr, -x, -y);
gtk_widget_draw (priv->inspected, cr);
cairo_restore (cr);
return TRUE;
}
static void
_gtk_magnifier_class_init (GtkMagnifierClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->set_property = _gtk_magnifier_set_property;
object_class->get_property = _gtk_magnifier_get_property;
widget_class->draw = _gtk_magnifier_draw;
g_object_class_install_property (object_class,
PROP_INSPECTED,
g_param_spec_object (P_("inspected"),
P_("Inspected"),
P_("Inspected widget"),
GTK_TYPE_WIDGET,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_MAGNIFICATION,
g_param_spec_double (P_("magnification"),
P_("magnification"),
P_("magnification"),
1, G_MAXDOUBLE, 1,
G_PARAM_READWRITE));
}
static void
_gtk_magnifier_init (GtkMagnifier *magnifier)
{
GtkWidget *widget = GTK_WIDGET (magnifier);
GtkMagnifierPrivate *priv;
priv = _gtk_magnifier_get_instance_private (magnifier);
gtk_widget_set_events (widget,
gtk_widget_get_events (widget) |
GDK_EXPOSURE_MASK);
gtk_widget_set_has_window (widget, FALSE);
priv->magnification = 1;
}
GtkWidget *
_gtk_magnifier_new (GtkWidget *inspected)
{
g_return_val_if_fail (GTK_IS_WIDGET (inspected), NULL);
return g_object_new (GTK_TYPE_MAGNIFIER,
"inspected", inspected,
NULL);
}
GtkWidget *
_gtk_magnifier_get_inspected (GtkMagnifier *magnifier)
{
GtkMagnifierPrivate *priv;
g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), NULL);
priv = _gtk_magnifier_get_instance_private (magnifier);
return priv->inspected;
}
void
_gtk_magnifier_set_inspected (GtkMagnifier *magnifier,
GtkWidget *inspected)
{
GtkMagnifierPrivate *priv;
g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
priv = _gtk_magnifier_get_instance_private (magnifier);
if (priv->inspected == inspected)
return;
priv->inspected = inspected;
g_object_notify (G_OBJECT (magnifier), "inspected");
}
void
_gtk_magnifier_set_coords (GtkMagnifier *magnifier,
gdouble x,
gdouble y)
{
GtkMagnifierPrivate *priv;
g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
priv = _gtk_magnifier_get_instance_private (magnifier);
if (priv->x == x && priv->y == y)
return;
priv->x = x;
priv->y = y;
if (gtk_widget_is_visible (GTK_WIDGET (magnifier)))
gtk_widget_queue_draw (GTK_WIDGET (magnifier));
}
void
_gtk_magnifier_get_coords (GtkMagnifier *magnifier,
gdouble *x,
gdouble *y)
{
GtkMagnifierPrivate *priv;
g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
priv = _gtk_magnifier_get_instance_private (magnifier);
if (x)
*x = priv->x;
if (y)
*y = priv->y;
}
void
_gtk_magnifier_set_magnification (GtkMagnifier *magnifier,
gdouble magnification)
{
GtkMagnifierPrivate *priv;
g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
priv = _gtk_magnifier_get_instance_private (magnifier);
if (priv->magnification == magnification)
return;
priv->magnification = magnification;
g_object_notify (G_OBJECT (magnifier), "magnification");
if (gtk_widget_is_visible (GTK_WIDGET (magnifier)))
gtk_widget_queue_draw (GTK_WIDGET (magnifier));
}
gdouble
_gtk_magnifier_get_magnification (GtkMagnifier *magnifier)
{
GtkMagnifierPrivate *priv;
g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), 1);
priv = _gtk_magnifier_get_instance_private (magnifier);
return priv->magnification;
}

64
gtk/gtkmagnifierprivate.h Normal file
View File

@@ -0,0 +1,64 @@
/* GTK - The GIMP Toolkit
* Copyright © 2013 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_MAGNIFIER_H__
#define __GTK_MAGNIFIER_H__
G_BEGIN_DECLS
#define GTK_TYPE_MAGNIFIER (_gtk_magnifier_get_type ())
#define GTK_MAGNIFIER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_MAGNIFIER, GtkMagnifier))
#define GTK_MAGNIFIER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_MAGNIFIER, GtkMagnifierClass))
#define GTK_IS_MAGNIFIER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_MAGNIFIER))
#define GTK_IS_MAGNIFIER_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_MAGNIFIER))
#define GTK_MAGNIFIER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_MAGNIFIER, GtkMagnifierClass))
typedef struct _GtkMagnifier GtkMagnifier;
typedef struct _GtkMagnifierClass GtkMagnifierClass;
struct _GtkMagnifier
{
GtkWidget parent_instance;
};
struct _GtkMagnifierClass
{
GtkWidgetClass parent_class;
};
GType _gtk_magnifier_get_type (void) G_GNUC_CONST;
GtkWidget * _gtk_magnifier_new (GtkWidget *inspected);
GtkWidget * _gtk_magnifier_get_inspected (GtkMagnifier *magnifier);
void _gtk_magnifier_set_inspected (GtkMagnifier *magnifier,
GtkWidget *inspected);
void _gtk_magnifier_set_coords (GtkMagnifier *magnifier,
gdouble x,
gdouble y);
void _gtk_magnifier_get_coords (GtkMagnifier *magnifier,
gdouble *x,
gdouble *y);
void _gtk_magnifier_set_magnification (GtkMagnifier *magnifier,
gdouble magnification);
gdouble _gtk_magnifier_get_magnification (GtkMagnifier *magnifier);
G_END_DECLS
#endif /* __GTK_MAGNIFIER_H__ */

View File

@@ -1568,6 +1568,12 @@ gtk_main_do_event (GdkEvent *event)
event_widget = gtk_get_event_widget (event);
}
if (GTK_IS_WINDOW (event_widget))
{
if (_gtk_window_check_handle_wm_event (event))
return;
}
window_group = gtk_main_get_window_group (event_widget);
device = gdk_event_get_device (event);

View File

@@ -396,6 +396,19 @@ blow_cache_cb (gpointer user_data)
return G_SOURCE_REMOVE;
}
static gboolean
context_is_unscaled (cairo_t *cr)
{
cairo_matrix_t matrix;
gdouble x, y;
x = y = 1;
cairo_get_matrix (cr, &matrix);
cairo_matrix_transform_distance (&matrix, &x, &y);
return x == 1 && y == 1;
}
void
_gtk_pixel_cache_draw (GtkPixelCache *cache,
@@ -420,7 +433,7 @@ _gtk_pixel_cache_draw (GtkPixelCache *cache,
_gtk_pixel_cache_set_position (cache, view_rect, canvas_rect);
_gtk_pixel_cache_repaint (cache, draw, view_rect, canvas_rect, user_data);
if (cache->surface &&
if (cache->surface && context_is_unscaled (cr) &&
/* Don't use backing surface if rendering elsewhere */
cairo_surface_get_type (cache->surface) == cairo_surface_get_type (cairo_get_target (cr)))
{

1674
gtk/gtkpopover.c Normal file

File diff suppressed because it is too large Load Diff

84
gtk/gtkpopover.h Normal file
View File

@@ -0,0 +1,84 @@
/* GTK - The GIMP Toolkit
* Copyright © 2013 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_POPOVER_H__
#define __GTK_POPOVER_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkwindow.h>
G_BEGIN_DECLS
#define GTK_TYPE_POPOVER (gtk_popover_get_type ())
#define GTK_POPOVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_POPOVER, GtkPopover))
#define GTK_POPOVER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_POPOVER, GtkPopoverClass))
#define GTK_IS_POPOVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_POPOVER))
#define GTK_IS_POPOVER_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_POPOVER))
#define GTK_POPOVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_POPOVER, GtkPopoverClass))
typedef struct _GtkPopover GtkPopover;
typedef struct _GtkPopoverClass GtkPopoverClass;
struct _GtkPopover
{
GtkBin parent_instance;
/*< private >*/
gpointer priv;
};
struct _GtkPopoverClass
{
GtkBinClass parent_class;
};
GDK_AVAILABLE_IN_3_12
GType gtk_popover_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_12
GtkWidget * gtk_popover_new (GtkWidget *relative_to);
GDK_AVAILABLE_IN_3_12
void gtk_popover_set_relative_to (GtkPopover *popover,
GtkWidget *relative_to);
GDK_AVAILABLE_IN_3_12
GtkWidget * gtk_popover_get_relative_to (GtkPopover *popover);
GDK_AVAILABLE_IN_3_12
void gtk_popover_set_pointing_to (GtkPopover *popover,
cairo_rectangle_int_t *rect);
GDK_AVAILABLE_IN_3_12
gboolean gtk_popover_get_pointing_to (GtkPopover *popover,
cairo_rectangle_int_t *rect);
GDK_AVAILABLE_IN_3_12
void gtk_popover_set_position (GtkPopover *popover,
GtkPositionType position);
GDK_AVAILABLE_IN_3_12
GtkPositionType gtk_popover_get_position (GtkPopover *popover);
GDK_AVAILABLE_IN_3_12
void gtk_popover_set_modal (GtkPopover *popover,
gboolean modal);
GDK_AVAILABLE_IN_3_12
gboolean gtk_popover_get_modal (GtkPopover *popover);
G_END_DECLS
#endif /* __GTK_POPOVER_H__ */

View File

@@ -20,6 +20,7 @@
#include "gtktexthandleprivate.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkwindowprivate.h"
#include "gtkintl.h"
#include <gtk/gtk.h>
@@ -35,13 +36,12 @@ enum {
enum {
PROP_0,
PROP_PARENT,
PROP_RELATIVE_TO
PROP_PARENT
};
struct _HandleWindow
{
GdkWindow *window;
GtkWidget *widget;
GdkRectangle pointing_to;
gint dx;
gint dy;
@@ -55,13 +55,11 @@ struct _GtkTextHandlePrivate
{
HandleWindow windows[2];
GtkWidget *parent;
GdkWindow *relative_to;
gulong draw_signal_id;
gulong event_signal_id;
gulong style_updated_id;
gulong composited_changed_id;
guint realized : 1;
GtkScrollable *parent_scrollable;
GtkAdjustment *vadj;
GtkAdjustment *hadj;
guint hierarchy_changed_id;
guint scrollable_notify_id;
guint mode : 2;
};
@@ -69,6 +67,9 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkTextHandle, _gtk_text_handle, G_TYPE_OBJECT)
static guint signals[LAST_SIGNAL] = { 0 };
static void _gtk_text_handle_update (GtkTextHandle *handle,
GtkTextHandlePosition pos);
static void
_gtk_text_handle_get_size (GtkTextHandle *handle,
gint *width,
@@ -104,10 +105,6 @@ _gtk_text_handle_draw (GtkTextHandle *handle,
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_paint (cr);
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
cairo_translate (cr, 0, priv->windows[pos].pointing_to.height);
@@ -135,92 +132,18 @@ _gtk_text_handle_draw (GtkTextHandle *handle,
cairo_restore (cr);
}
static void
_gtk_text_handle_update_shape (GtkTextHandle *handle,
GdkWindow *window,
GtkTextHandlePosition pos)
static gint
_text_handle_pos_from_widget (GtkTextHandle *handle,
GtkWidget *widget)
{
GtkTextHandlePrivate *priv;
cairo_rectangle_int_t rect;
cairo_surface_t *surface;
cairo_region_t *region;
cairo_t *cr;
GtkTextHandlePrivate *priv = handle->priv;
priv = handle->priv;
surface =
gdk_window_create_similar_surface (window,
CAIRO_CONTENT_COLOR_ALPHA,
gdk_window_get_width (window),
gdk_window_get_height (window));
cr = cairo_create (surface);
_gtk_text_handle_draw (handle, cr, pos);
cairo_destroy (cr);
region = gdk_cairo_region_create_from_surface (surface);
if (gtk_widget_is_composited (priv->parent))
gdk_window_shape_combine_region (window, NULL, 0, 0);
if (widget == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget)
return GTK_TEXT_HANDLE_POSITION_SELECTION_START;
else if (widget == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget)
return GTK_TEXT_HANDLE_POSITION_SELECTION_END;
else
gdk_window_shape_combine_region (window, region, 0, 0);
cairo_region_get_extents (region, &rect);
cairo_region_destroy (region);
/* Preserve x/width, but extend input shape
* vertically to all window height */
rect.y = 0;
rect.height = gdk_window_get_height (window);
region = cairo_region_create_rectangle (&rect);
gdk_window_input_shape_combine_region (window, region, 0, 0);
cairo_surface_destroy (surface);
cairo_region_destroy (region);
}
static GdkWindow *
_gtk_text_handle_create_window (GtkTextHandle *handle,
GtkTextHandlePosition pos)
{
GtkTextHandlePrivate *priv;
GdkRGBA bg = { 0, 0, 0, 0 };
GdkWindowAttr attributes;
GdkWindow *window;
GdkVisual *visual;
gint mask;
priv = handle->priv;
attributes.x = 0;
attributes.y = 0;
_gtk_text_handle_get_size (handle, &attributes.width, &attributes.height);
attributes.window_type = GDK_WINDOW_TEMP;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.event_mask = (GDK_EXPOSURE_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON1_MOTION_MASK);
mask = GDK_WA_X | GDK_WA_Y;
visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (priv->parent));
if (visual)
{
attributes.visual = visual;
mask |= GDK_WA_VISUAL;
}
window = gdk_window_new (gtk_widget_get_root_window (priv->parent),
&attributes, mask);
gtk_widget_register_window (priv->parent, window);
gdk_window_set_background_rgba (window, &bg);
_gtk_text_handle_update_shape (handle, window, pos);
return window;
return -1;
}
static gboolean
@@ -228,27 +151,15 @@ gtk_text_handle_widget_draw (GtkWidget *widget,
cairo_t *cr,
GtkTextHandle *handle)
{
GtkTextHandlePrivate *priv;
GtkTextHandlePosition pos;
HandleWindow *handle_window;
gint pos;
priv = handle->priv;
pos = _text_handle_pos_from_widget (handle, widget);
if (!priv->realized)
if (pos < 0)
return FALSE;
if (gtk_cairo_should_draw_window (cr, priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window))
pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
else if (gtk_cairo_should_draw_window (cr, priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window))
pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END;
else
return FALSE;
handle_window = &priv->windows[pos];
if (gdk_window_is_visible (handle_window->window))
_gtk_text_handle_draw (handle, cr, pos);
return FALSE;
_gtk_text_handle_draw (handle, cr, pos);
return TRUE;
}
static gboolean
@@ -257,15 +168,12 @@ gtk_text_handle_widget_event (GtkWidget *widget,
GtkTextHandle *handle)
{
GtkTextHandlePrivate *priv;
GtkTextHandlePosition pos;
gint pos;
priv = handle->priv;
pos = _text_handle_pos_from_widget (handle, widget);
if (event->any.window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window)
pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
else if (event->any.window == priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window)
pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END;
else
if (pos < 0)
return FALSE;
if (event->type == GDK_BUTTON_PRESS)
@@ -277,24 +185,24 @@ gtk_text_handle_widget_event (GtkWidget *widget,
else if (event->type == GDK_BUTTON_RELEASE)
{
g_signal_emit (handle, signals[DRAG_FINISHED], 0, pos);
priv->windows[pos].dx = priv->windows[pos].dy = 0;
priv->windows[pos].dragged = FALSE;
}
else if (event->type == GDK_MOTION_NOTIFY && priv->windows[pos].dragged)
else if (event->type == GDK_MOTION_NOTIFY &&
event->motion.state & GDK_BUTTON1_MASK &&
priv->windows[pos].dragged)
{
gint x, y, width, height;
_gtk_text_handle_get_size (handle, &width, &height);
gdk_window_get_origin (priv->relative_to, &x, &y);
x = event->motion.x - priv->windows[pos].dx + (width / 2);
y = event->motion.y - priv->windows[pos].dy;
x = event->motion.x_root - priv->windows[pos].dx + (width / 2) - x;
y = event->motion.y_root - priv->windows[pos].dy - y;
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_START)
if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR)
y += height;
y += priv->windows[pos].pointing_to.height / 2;
gtk_widget_translate_coordinates (widget, priv->parent, x, y, &x, &y);
g_signal_emit (handle, signals[HANDLE_DRAGGED], 0, pos, x, y);
}
@@ -302,8 +210,84 @@ gtk_text_handle_widget_event (GtkWidget *widget,
}
static void
_gtk_text_handle_update_window_state (GtkTextHandle *handle,
GtkTextHandlePosition pos)
gtk_text_handle_widget_style_updated (GtkWidget *widget,
GtkTextHandle *handle)
{
_gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
_gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
}
static GtkWidget *
_gtk_text_handle_ensure_widget (GtkTextHandle *handle,
GtkTextHandlePosition pos)
{
GtkTextHandlePrivate *priv;
priv = handle->priv;
if (!priv->windows[pos].widget)
{
GtkWidget *widget, *window;
widget = gtk_event_box_new ();
gtk_widget_set_events (widget,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK);
g_signal_connect (widget, "draw",
G_CALLBACK (gtk_text_handle_widget_draw), handle);
g_signal_connect (widget, "event",
G_CALLBACK (gtk_text_handle_widget_event), handle);
g_signal_connect (widget, "style-updated",
G_CALLBACK (gtk_text_handle_widget_style_updated),
handle);
priv->windows[pos].widget = g_object_ref_sink (widget);
window = gtk_widget_get_ancestor (priv->parent, GTK_TYPE_WINDOW);
_gtk_window_add_popover (GTK_WINDOW (window), widget);
}
return priv->windows[pos].widget;
}
static void
_handle_update_child_visible (GtkTextHandle *handle,
GtkTextHandlePosition pos)
{
HandleWindow *handle_window;
GtkTextHandlePrivate *priv;
cairo_rectangle_int_t rect;
GtkAllocation allocation;
GtkWidget *parent;
priv = handle->priv;
handle_window = &priv->windows[pos];
if (!priv->parent_scrollable)
{
gtk_widget_set_child_visible (handle_window->widget, TRUE);
return;
}
parent = gtk_widget_get_parent (GTK_WIDGET (priv->parent_scrollable));
rect = handle_window->pointing_to;
gtk_widget_translate_coordinates (priv->parent, parent,
rect.x, rect.y, &rect.x, &rect.y);
gtk_widget_get_allocation (GTK_WIDGET (parent), &allocation);
if (rect.x < 0 || rect.x + rect.width > allocation.width ||
rect.y < 0 || rect.y + rect.height > allocation.height)
gtk_widget_set_child_visible (handle_window->widget, FALSE);
else
gtk_widget_set_child_visible (handle_window->widget, TRUE);
}
static void
_gtk_text_handle_update (GtkTextHandle *handle,
GtkTextHandlePosition pos)
{
GtkTextHandlePrivate *priv;
HandleWindow *handle_window;
@@ -311,93 +295,209 @@ _gtk_text_handle_update_window_state (GtkTextHandle *handle,
priv = handle->priv;
handle_window = &priv->windows[pos];
if (!handle_window->window)
if (!priv->parent || !gtk_widget_is_drawable (priv->parent))
return;
if (handle_window->has_point &&
handle_window->mode_visible && handle_window->user_visible)
{
gint x, y, width, height;
cairo_rectangle_int_t rect;
GtkPositionType handle_pos;
gint width, height;
GtkWidget *window;
x = handle_window->pointing_to.x;
y = handle_window->pointing_to.y;
_gtk_text_handle_ensure_widget (handle, pos);
_gtk_text_handle_get_size (handle, &width, &height);
rect.x = handle_window->pointing_to.x;
rect.y = handle_window->pointing_to.y;
rect.width = width;
rect.height = 0;
if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR)
y -= height;
_handle_update_child_visible (handle, pos);
window = gtk_widget_get_parent (handle_window->widget);
gtk_widget_translate_coordinates (priv->parent, window,
rect.x, rect.y, &rect.x, &rect.y);
if (pos == GTK_TEXT_HANDLE_POSITION_CURSOR)
handle_pos = GTK_POS_BOTTOM;
else
{
handle_pos = GTK_POS_TOP;
rect.y += handle_window->pointing_to.height;
}
height += handle_window->pointing_to.height;
x -= width / 2;
rect.x -= rect.width / 2;
gdk_window_move_resize (handle_window->window, x, y, width, height);
gdk_window_show (handle_window->window);
gtk_widget_set_size_request (handle_window->widget, width, height);
gtk_widget_show (handle_window->widget);
_gtk_window_set_popover_position (GTK_WINDOW (window),
handle_window->widget,
handle_pos, &rect);
}
else
gdk_window_hide (handle_window->window);
else if (handle_window->widget)
gtk_widget_hide (handle_window->widget);
}
static void
_gtk_text_handle_update_window (GtkTextHandle *handle,
GtkTextHandlePosition pos,
gboolean recreate)
adjustment_changed_cb (GtkAdjustment *adjustment,
GtkTextHandle *handle)
{
_gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
_gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
}
static void
_gtk_text_handle_set_scrollable (GtkTextHandle *handle,
GtkScrollable *scrollable)
{
GtkTextHandlePrivate *priv;
HandleWindow *handle_window;
priv = handle->priv;
handle_window = &priv->windows[pos];
if (!handle_window->window)
return;
if (recreate)
if (priv->parent_scrollable)
{
gtk_widget_unregister_window (priv->parent, handle_window->window);
gdk_window_destroy (handle_window->window);
handle_window->window = _gtk_text_handle_create_window (handle, pos);
if (priv->vadj)
{
g_signal_handlers_disconnect_by_data (priv->vadj, handle);
g_object_unref (priv->vadj);
priv->vadj = NULL;
}
if (priv->hadj)
{
g_signal_handlers_disconnect_by_data (priv->hadj, handle);
g_object_unref (priv->hadj);
priv->hadj = NULL;
}
}
_gtk_text_handle_update_window_state (handle, pos);
priv->parent_scrollable = scrollable;
if (scrollable)
{
priv->vadj = gtk_scrollable_get_vadjustment (scrollable);
priv->hadj = gtk_scrollable_get_hadjustment (scrollable);
if (priv->vadj)
{
g_object_ref (priv->vadj);
g_signal_connect (priv->vadj, "changed",
G_CALLBACK (adjustment_changed_cb), handle);
g_signal_connect (priv->vadj, "value-changed",
G_CALLBACK (adjustment_changed_cb), handle);
}
if (priv->hadj)
{
g_object_ref (priv->hadj);
g_signal_connect (priv->hadj, "changed",
G_CALLBACK (adjustment_changed_cb), handle);
g_signal_connect (priv->hadj, "value-changed",
G_CALLBACK (adjustment_changed_cb), handle);
}
}
}
static void
_gtk_text_handle_update_windows (GtkTextHandle *handle)
_gtk_text_handle_scrollable_notify (GObject *object,
GParamSpec *pspec,
GtkTextHandle *handle)
{
_gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, FALSE);
_gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, FALSE);
if (pspec->value_type == GTK_TYPE_ADJUSTMENT)
_gtk_text_handle_set_scrollable (handle, GTK_SCROLLABLE (object));
}
static void
_gtk_text_handle_composited_changed (GtkTextHandle *handle)
{
_gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, TRUE);
_gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, TRUE);
}
static void
gtk_text_handle_constructed (GObject *object)
_gtk_text_handle_update_scrollable (GtkTextHandle *handle,
GtkScrollable *scrollable)
{
GtkTextHandlePrivate *priv;
priv = GTK_TEXT_HANDLE (object)->priv;
g_assert (priv->parent != NULL);
priv = handle->priv;
priv->draw_signal_id =
g_signal_connect (priv->parent, "draw",
G_CALLBACK (gtk_text_handle_widget_draw),
object);
priv->event_signal_id =
g_signal_connect (priv->parent, "event",
G_CALLBACK (gtk_text_handle_widget_event),
object);
priv->composited_changed_id =
g_signal_connect_swapped (priv->parent, "composited-changed",
G_CALLBACK (_gtk_text_handle_composited_changed),
object);
priv->style_updated_id =
g_signal_connect_swapped (priv->parent, "style-updated",
G_CALLBACK (_gtk_text_handle_update_windows),
object);
if (priv->parent_scrollable == scrollable)
return;
if (priv->parent_scrollable && priv->scrollable_notify_id &&
g_signal_handler_is_connected (priv->parent_scrollable,
priv->scrollable_notify_id))
g_signal_handler_disconnect (priv->parent_scrollable,
priv->scrollable_notify_id);
_gtk_text_handle_set_scrollable (handle, scrollable);
if (priv->parent_scrollable)
priv->scrollable_notify_id =
g_signal_connect (priv->parent_scrollable, "notify",
G_CALLBACK (_gtk_text_handle_scrollable_notify),
handle);
}
static void
_gtk_text_handle_parent_hierarchy_changed (GtkWidget *widget,
GtkWindow *previous_toplevel,
GtkTextHandle *handle)
{
GtkWidget *toplevel, *scrollable;
GtkTextHandlePrivate *priv;
priv = handle->priv;
toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
if (previous_toplevel && !toplevel)
{
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget)
{
_gtk_window_remove_popover (GTK_WINDOW (previous_toplevel),
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget);
g_object_unref (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget);
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget = NULL;
}
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget)
{
_gtk_window_remove_popover (GTK_WINDOW (previous_toplevel),
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget);
g_object_unref (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget);
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget = NULL;
}
}
scrollable = gtk_widget_get_ancestor (widget, GTK_TYPE_SCROLLABLE);
_gtk_text_handle_update_scrollable (handle, GTK_SCROLLABLE (scrollable));
}
static void
_gtk_text_handle_set_parent (GtkTextHandle *handle,
GtkWidget *parent)
{
GtkTextHandlePrivate *priv;
GtkWidget *scrollable = NULL;
priv = handle->priv;
if (priv->parent == parent)
return;
if (priv->parent && priv->hierarchy_changed_id &&
g_signal_handler_is_connected (priv->parent, priv->hierarchy_changed_id))
g_signal_handler_disconnect (priv->parent, priv->hierarchy_changed_id);
priv->parent = parent;
if (parent)
{
priv->hierarchy_changed_id =
g_signal_connect (parent, "hierarchy-changed",
G_CALLBACK (_gtk_text_handle_parent_hierarchy_changed),
handle);
scrollable = gtk_widget_get_ancestor (parent, GTK_TYPE_SCROLLABLE);
}
_gtk_text_handle_update_scrollable (handle, GTK_SCROLLABLE (scrollable));
}
static void
@@ -407,34 +507,14 @@ gtk_text_handle_finalize (GObject *object)
priv = GTK_TEXT_HANDLE (object)->priv;
if (priv->relative_to)
g_object_unref (priv->relative_to);
_gtk_text_handle_set_parent (GTK_TEXT_HANDLE (object), NULL);
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window)
{
gtk_widget_unregister_window (priv->parent,
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
}
/* We sank the references, unref here */
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget)
g_object_unref (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].widget);
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window)
{
gtk_widget_unregister_window (priv->parent,
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
}
if (g_signal_handler_is_connected (priv->parent, priv->draw_signal_id))
g_signal_handler_disconnect (priv->parent, priv->draw_signal_id);
if (g_signal_handler_is_connected (priv->parent, priv->event_signal_id))
g_signal_handler_disconnect (priv->parent, priv->event_signal_id);
if (g_signal_handler_is_connected (priv->parent, priv->composited_changed_id))
g_signal_handler_disconnect (priv->parent, priv->composited_changed_id);
if (g_signal_handler_is_connected (priv->parent, priv->style_updated_id))
g_signal_handler_disconnect (priv->parent, priv->style_updated_id);
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget)
g_object_unref (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].widget);
G_OBJECT_CLASS (_gtk_text_handle_parent_class)->finalize (object);
}
@@ -445,20 +525,14 @@ gtk_text_handle_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
GtkTextHandlePrivate *priv;
GtkTextHandle *handle;
handle = GTK_TEXT_HANDLE (object);
priv = handle->priv;
switch (prop_id)
{
case PROP_PARENT:
priv->parent = g_value_get_object (value);
break;
case PROP_RELATIVE_TO:
_gtk_text_handle_set_relative_to (handle,
g_value_get_object (value));
_gtk_text_handle_set_parent (handle, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -480,9 +554,6 @@ gtk_text_handle_get_property (GObject *object,
case PROP_PARENT:
g_value_set_object (value, priv->parent);
break;
case PROP_RELATIVE_TO:
g_value_set_object (value, priv->relative_to);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -493,7 +564,6 @@ _gtk_text_handle_class_init (GtkTextHandleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = gtk_text_handle_constructed;
object_class->finalize = gtk_text_handle_finalize;
object_class->set_property = gtk_text_handle_set_property;
object_class->get_property = gtk_text_handle_get_property;
@@ -525,13 +595,6 @@ _gtk_text_handle_class_init (GtkTextHandleClass *klass)
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_RELATIVE_TO,
g_param_spec_object ("relative-to",
P_("Window"),
P_("Window the coordinates are based upon"),
GDK_TYPE_WINDOW,
GTK_PARAM_READWRITE));
}
static void
@@ -548,48 +611,6 @@ _gtk_text_handle_new (GtkWidget *parent)
NULL);
}
void
_gtk_text_handle_set_relative_to (GtkTextHandle *handle,
GdkWindow *window)
{
GtkTextHandlePrivate *priv;
g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
g_return_if_fail (!window || GDK_IS_WINDOW (window));
priv = handle->priv;
if (priv->relative_to)
{
gtk_widget_unregister_window (priv->parent,
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
gtk_widget_unregister_window (priv->parent,
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
g_object_unref (priv->relative_to);
}
if (window)
{
priv->relative_to = g_object_ref (window);
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window =
_gtk_text_handle_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window =
_gtk_text_handle_create_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
priv->realized = TRUE;
}
else
{
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window = NULL;
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window = NULL;
priv->relative_to = NULL;
priv->realized = FALSE;
}
g_object_notify (G_OBJECT (handle), "relative-to");
}
void
_gtk_text_handle_set_mode (GtkTextHandle *handle,
GtkTextHandleMode mode)
@@ -622,15 +643,8 @@ _gtk_text_handle_set_mode (GtkTextHandle *handle,
break;
}
_gtk_text_handle_update_shape (handle,
priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window,
GTK_TEXT_HANDLE_POSITION_CURSOR);
_gtk_text_handle_update_shape (handle,
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window,
GTK_TEXT_HANDLE_POSITION_SELECTION_START);
_gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
_gtk_text_handle_update_window_state (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
_gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
_gtk_text_handle_update (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
}
GtkTextHandleMode
@@ -651,7 +665,6 @@ _gtk_text_handle_set_position (GtkTextHandle *handle,
{
GtkTextHandlePrivate *priv;
HandleWindow *handle_window;
gboolean size_changed;
g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
@@ -660,28 +673,16 @@ _gtk_text_handle_set_position (GtkTextHandle *handle,
GTK_TEXT_HANDLE_POSITION_SELECTION_START);
handle_window = &priv->windows[pos];
if (!priv->realized)
return;
if (priv->mode == GTK_TEXT_HANDLE_MODE_NONE ||
(priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR &&
pos != GTK_TEXT_HANDLE_POSITION_CURSOR))
return;
size_changed = (rect->width != handle_window->pointing_to.width ||
rect->height != handle_window->pointing_to.height);
handle_window->pointing_to = *rect;
handle_window->has_point = TRUE;
gdk_window_get_root_coords (priv->relative_to,
rect->x, rect->y,
&handle_window->pointing_to.x,
&handle_window->pointing_to.y);
_gtk_text_handle_update_window_state (handle, pos);
if (size_changed)
_gtk_text_handle_update_shape (handle, handle_window->window, pos);
if (gtk_widget_is_visible (priv->parent))
_gtk_text_handle_update (handle, pos);
}
void
@@ -690,7 +691,6 @@ _gtk_text_handle_set_visible (GtkTextHandle *handle,
gboolean visible)
{
GtkTextHandlePrivate *priv;
GdkWindow *window;
g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
@@ -698,19 +698,10 @@ _gtk_text_handle_set_visible (GtkTextHandle *handle,
pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR,
GTK_TEXT_HANDLE_POSITION_SELECTION_START);
if (!priv->realized)
return;
window = priv->windows[pos].window;
if (!window)
return;
if (!gdk_window_is_visible (window))
_gtk_text_handle_update_shape (handle, window, pos);
priv->windows[pos].user_visible = visible;
_gtk_text_handle_update_window_state (handle, pos);
if (gtk_widget_is_visible (priv->parent))
_gtk_text_handle_update (handle, pos);
}
gboolean

View File

@@ -51,9 +51,10 @@
#include "gtktexthandleprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkbubblewindowprivate.h"
#include "gtkpopover.h"
#include "gtktoolbar.h"
#include "gtkpixelcacheprivate.h"
#include "gtkmagnifierprivate.h"
#include "a11y/gtktextviewaccessibleprivate.h"
@@ -140,6 +141,9 @@ struct _GtkTextViewPrivate
GtkWidget *selection_bubble;
guint selection_bubble_timeout_id;
GtkWidget *magnifier_popover;
GtkWidget *magnifier;
GtkTextWindow *text_window;
GtkTextWindow *left_window;
GtkTextWindow *right_window;
@@ -1542,6 +1546,18 @@ gtk_text_view_init (GtkTextView *text_view)
G_CALLBACK (gtk_text_view_handle_dragged), text_view);
g_signal_connect (priv->text_handle, "drag-finished",
G_CALLBACK (gtk_text_view_handle_drag_finished), text_view);
priv->magnifier = _gtk_magnifier_new (widget);
gtk_widget_set_size_request (priv->magnifier, 100, 60);
_gtk_magnifier_set_magnification (GTK_MAGNIFIER (priv->magnifier), 2.0);
priv->magnifier_popover = gtk_popover_new (widget);
gtk_style_context_add_class (gtk_widget_get_style_context (priv->magnifier_popover),
GTK_STYLE_CLASS_OSD);
gtk_popover_set_modal (GTK_POPOVER (priv->magnifier_popover), FALSE);
gtk_container_add (GTK_CONTAINER (priv->magnifier_popover),
priv->magnifier);
gtk_container_set_border_width (GTK_CONTAINER (priv->magnifier_popover), 4);
gtk_widget_show (priv->magnifier);
}
/**
@@ -3215,6 +3231,7 @@ gtk_text_view_finalize (GObject *object)
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
gtk_widget_destroy (priv->magnifier_popover);
g_object_unref (priv->text_handle);
g_object_unref (priv->im_context);
@@ -4237,8 +4254,6 @@ gtk_text_view_realize (GtkWidget *widget)
/* Ensure updating the spot location. */
gtk_text_view_update_im_spot_location (text_view);
_gtk_text_handle_set_relative_to (priv->text_handle, priv->text_window->window);
}
static void
@@ -4279,8 +4294,6 @@ gtk_text_view_unrealize (GtkWidget *widget)
if (priv->bottom_window)
text_window_unrealize (priv->bottom_window);
_gtk_text_handle_set_relative_to (priv->text_handle, NULL);
GTK_WIDGET_CLASS (gtk_text_view_parent_class)->unrealize (widget);
}
@@ -4588,6 +4601,30 @@ gtk_text_view_set_handle_position (GtkTextView *text_view,
}
}
static void
gtk_text_view_show_magnifier (GtkTextView *text_view,
gint x,
gint y)
{
cairo_rectangle_int_t rect;
GtkTextViewPrivate *priv;
GtkAllocation allocation;
gtk_widget_get_allocation (GTK_WIDGET (text_view), &allocation);
priv = text_view->priv;
x = CLAMP (x, 0, allocation.width);
y = CLAMP (y, 0, allocation.height);
rect.x = x;
rect.y = y;
rect.width = rect.height = 1;
_gtk_magnifier_set_coords (GTK_MAGNIFIER (priv->magnifier), x, y);
gtk_popover_set_pointing_to (GTK_POPOVER (priv->magnifier_popover),
&rect);
gtk_widget_show (priv->magnifier_popover);
}
static void
gtk_text_view_handle_dragged (GtkTextHandle *handle,
GtkTextHandlePosition pos,
@@ -4672,6 +4709,8 @@ gtk_text_view_handle_dragged (GtkTextHandle *handle,
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_selection_bound (buffer));
}
gtk_text_view_show_magnifier (text_view, x, y);
}
static void
@@ -4680,6 +4719,7 @@ gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
GtkTextView *text_view)
{
gtk_text_view_selection_bubble_popup_set (text_view);
gtk_widget_hide (text_view->priv->magnifier_popover);
}
static void
@@ -6948,7 +6988,10 @@ selection_motion_event_handler (GtkTextView *text_view,
g_source_set_name_by_id (text_view->priv->scroll_timeout, "[gtk+] selection_scan_timeout");
if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN)
gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_SELECTION);
{
gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_SELECTION);
gtk_text_view_show_magnifier (text_view, event->x, event->y);
}
return TRUE;
}
@@ -7068,6 +7111,8 @@ gtk_text_view_end_selection_drag (GtkTextView *text_view)
priv->grab_device);
priv->grab_device = NULL;
gtk_widget_hide (priv->magnifier_popover);
return TRUE;
}
@@ -8857,7 +8902,7 @@ activate_bubble_cb (GtkWidget *item,
{
const gchar *signal = g_object_get_data (G_OBJECT (item), "gtk-signal");
g_signal_emit_by_name (text_view, signal);
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (text_view->priv->selection_bubble));
gtk_widget_hide (text_view->priv->selection_bubble);
}
static void
@@ -8868,6 +8913,7 @@ append_bubble_action (GtkTextView *text_view,
gboolean sensitive)
{
GtkToolItem *item = gtk_tool_button_new (NULL, label);
gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (item), TRUE);
g_object_set_data (G_OBJECT (item), I_("gtk-signal"), (char *)signal);
g_signal_connect (item, "clicked", G_CALLBACK (activate_bubble_cb), text_view);
gtk_widget_set_sensitive (GTK_WIDGET (item), sensitive);
@@ -8888,7 +8934,6 @@ bubble_targets_received (GtkClipboard *clipboard,
gboolean can_insert;
GtkTextIter iter;
GtkTextIter sel_start, sel_end;
GdkWindow *window;
GtkWidget *toolbar;
has_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
@@ -8902,8 +8947,13 @@ bubble_targets_received (GtkClipboard *clipboard,
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
window = gtk_widget_get_window (GTK_WIDGET (text_view));
priv->selection_bubble = _gtk_bubble_window_new ();
priv->selection_bubble = gtk_popover_new (GTK_WIDGET (text_view));
gtk_style_context_add_class (gtk_widget_get_style_context (priv->selection_bubble),
GTK_STYLE_CLASS_OSD);
gtk_popover_set_position (GTK_POPOVER (priv->selection_bubble),
GTK_POS_TOP);
gtk_popover_set_modal (GTK_POPOVER (priv->selection_bubble), FALSE);
toolbar = GTK_WIDGET (gtk_toolbar_new ());
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
@@ -8930,8 +8980,9 @@ bubble_targets_received (GtkClipboard *clipboard,
gtk_text_view_get_selection_rect (text_view, &rect);
rect.x -= priv->xoffset;
rect.y -= priv->yoffset;
_gtk_bubble_window_popup (GTK_BUBBLE_WINDOW (priv->selection_bubble),
window, &rect, GTK_POS_TOP);
gtk_popover_set_pointing_to (GTK_POPOVER (priv->selection_bubble), &rect);
gtk_widget_show (priv->selection_bubble);
priv->selection_bubble_timeout_id = 0;
}
@@ -8957,7 +9008,7 @@ gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view)
priv = text_view->priv;
if (priv->selection_bubble)
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
gtk_widget_hide (priv->selection_bubble);
if (priv->selection_bubble_timeout_id)
{
@@ -9221,7 +9272,7 @@ text_window_scroll (GtkTextWindow *win,
if (dx != 0 || dy != 0)
{
if (priv->selection_bubble)
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
gtk_widget_hide (priv->selection_bubble);
view->priv->in_scroll = TRUE;
gdk_window_scroll (win->bin_window, dx, dy);
view->priv->in_scroll = FALSE;

View File

@@ -123,6 +123,16 @@
#define MNEMONICS_DELAY 300 /* ms */
typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo;
typedef struct _GtkWindowPopover GtkWindowPopover;
struct _GtkWindowPopover
{
GtkWidget *widget;
GdkWindow *window;
GtkPositionType pos;
cairo_rectangle_int_t rect;
gulong unmap_id;
};
struct _GtkWindowPrivate
{
@@ -137,6 +147,8 @@ struct _GtkWindowPrivate
GdkScreen *screen;
GtkApplication *application;
GList *popovers;
GdkModifierType mnemonic_modifier;
GdkWindowTypeHint gdk_type_hint;
@@ -1318,6 +1330,24 @@ gtk_window_close (GtkWindow *window)
gdk_threads_add_idle (send_delete_event, window);
}
static void
popover_destroy (GtkWindowPopover *popover)
{
if (popover->unmap_id)
{
g_signal_handler_disconnect (popover->widget, popover->unmap_id);
popover->unmap_id = 0;
}
if (popover->widget && gtk_widget_get_parent (popover->widget))
gtk_widget_unparent (popover->widget);
if (popover->window)
gdk_window_destroy (popover->window);
g_free (popover);
}
static void
gtk_window_init (GtkWindow *window)
{
@@ -2630,6 +2660,16 @@ static void
gtk_window_dispose (GObject *object)
{
GtkWindow *window = GTK_WINDOW (object);
GtkWindowPrivate *priv = window->priv;
while (priv->popovers)
{
GtkWindowPopover *popover;
popover = priv->popovers->data;
priv->popovers = g_list_remove_link (priv->popovers, priv->popovers);
popover_destroy (popover);
}
gtk_window_set_focus (window, NULL);
gtk_window_set_default (window, NULL);
@@ -5391,6 +5431,41 @@ gtk_window_hide (GtkWidget *widget)
gtk_grab_remove (widget);
}
static void
popover_unmap (GtkWidget *widget,
GtkWindowPopover *popover)
{
if (popover->window)
{
if (gtk_widget_is_visible (popover->widget))
gtk_widget_unmap (popover->widget);
gdk_window_hide (popover->window);
}
if (popover->unmap_id)
{
g_signal_handler_disconnect (widget, popover->unmap_id);
popover->unmap_id = 0;
}
}
static void
popover_map (GtkWidget *widget,
GtkWindowPopover *popover)
{
if (popover->window)
{
gdk_window_show (popover->window);
if (gtk_widget_get_visible (popover->widget))
{
gtk_widget_map (popover->widget);
popover->unmap_id = g_signal_connect (popover->widget, "unmap",
G_CALLBACK (popover_unmap), popover);
}
}
}
static void
gtk_window_map (GtkWidget *widget)
{
@@ -5398,6 +5473,7 @@ gtk_window_map (GtkWidget *widget)
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
GdkWindow *gdk_window;
GList *link;
if (!gtk_widget_is_toplevel (widget))
{
@@ -5504,6 +5580,15 @@ gtk_window_map (GtkWidget *widget)
if (priv->application)
gtk_application_handle_window_map (priv->application, window);
link = priv->popovers;
while (link)
{
GtkWindowPopover *popover = link->data;
link = link->next;
popover_map (popover->widget, popover);
}
}
static gboolean
@@ -5533,6 +5618,7 @@ gtk_window_unmap (GtkWidget *widget)
GtkWindowGeometryInfo *info;
GdkWindow *gdk_window;
GdkWindowState state;
GList *link;
if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
{
@@ -5540,6 +5626,15 @@ gtk_window_unmap (GtkWidget *widget)
return;
}
link = priv->popovers;
while (link)
{
GtkWindowPopover *popover = link->data;
link = link->next;
popover_unmap (popover->widget, popover);
}
gdk_window = gtk_widget_get_window (widget);
gtk_widget_set_mapped (widget, FALSE);
@@ -5669,6 +5764,118 @@ gtk_window_get_remembered_size (GtkWindow *window,
}
}
static void
popover_get_rect (GtkWindowPopover *popover,
GtkWindow *window,
cairo_rectangle_int_t *rect)
{
GtkAllocation win_alloc;
GtkRequisition req;
gtk_widget_get_preferred_size (popover->widget, NULL, &req);
gtk_widget_get_allocation (GTK_WIDGET (window), &win_alloc);
rect->width = req.width;
rect->height = req.height;
if (popover->pos == GTK_POS_LEFT || popover->pos == GTK_POS_RIGHT)
{
if (req.height < win_alloc.height &&
gtk_widget_get_vexpand (popover->widget))
{
rect->y = 0;
rect->height = win_alloc.height;
}
else
rect->y = CLAMP (popover->rect.y + (popover->rect.height / 2) -
(req.height / 2), 0, win_alloc.height - req.height);
if ((popover->pos == GTK_POS_LEFT) ==
(gtk_widget_get_direction (popover->widget) == GTK_TEXT_DIR_LTR))
{
rect->x = popover->rect.x - req.width;
if (rect->x > 0 && gtk_widget_get_hexpand (popover->widget))
{
rect->x = 0;
rect->width = popover->rect.x;
}
}
else
{
rect->x = popover->rect.x + popover->rect.width;
if (rect->x + rect->width < win_alloc.width &&
gtk_widget_get_hexpand (popover->widget))
rect->width = win_alloc.width - rect->x;
}
}
else if (popover->pos == GTK_POS_TOP || popover->pos == GTK_POS_BOTTOM)
{
if (req.width < win_alloc.width &&
gtk_widget_get_hexpand (popover->widget))
{
rect->x = 0;
rect->width = win_alloc.width;
}
else
rect->x = CLAMP (popover->rect.x + (popover->rect.width / 2) -
(req.width / 2), 0, win_alloc.width - req.width);
if (popover->pos == GTK_POS_TOP)
{
rect->y = popover->rect.y - req.height;
if (rect->y > 0 && gtk_widget_get_vexpand (popover->widget))
{
rect->y = 0;
rect->height = popover->rect.y;
}
}
else
{
rect->y = popover->rect.y + popover->rect.height;
if (rect->y + rect->height < win_alloc.height &&
gtk_widget_get_vexpand (popover->widget))
rect->height = win_alloc.height - rect->y;
}
}
}
static void
popover_realize (GtkWidget *widget,
GtkWindowPopover *popover,
GtkWindow *window)
{
cairo_rectangle_int_t rect;
GdkWindow *parent_window;
GdkWindowAttr attributes;
gint attributes_mask;
if (popover->window)
return;
popover_get_rect (popover, window, &rect);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.x = rect.x;
attributes.y = rect.y;
attributes.width = rect.width;
attributes.height = rect.height;
attributes.visual = gtk_widget_get_visual (widget);
attributes.event_mask = gtk_widget_get_events (popover->widget) |
GDK_EXPOSURE_MASK;
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
parent_window = gtk_widget_get_window (GTK_WIDGET (window));
popover->window =
gdk_window_new (parent_window, &attributes, attributes_mask);
gtk_widget_register_window (GTK_WIDGET (window), popover->window);
gtk_widget_set_parent_window (popover->widget, popover->window);
}
static void
gtk_window_realize (GtkWidget *widget)
{
@@ -5681,6 +5888,7 @@ gtk_window_realize (GtkWidget *widget)
GtkWindowPrivate *priv;
gint i;
int old_scale;
GList *link;
window = GTK_WINDOW (widget);
priv = window->priv;
@@ -5919,18 +6127,37 @@ gtk_window_realize (GtkWidget *widget)
if (priv->has_resize_grip)
resize_grip_create_window (window);
link = priv->popovers;
while (link)
{
GtkWindowPopover *popover = link->data;
link = link->next;
popover_realize (popover->widget, popover, window);
}
old_scale = priv->scale;
priv->scale = gtk_widget_get_scale_factor (widget);
if (old_scale != priv->scale)
_gtk_widget_scale_changed (widget);
}
static void
popover_unrealize (GtkWidget *widget,
GtkWindowPopover *popover)
{
gtk_widget_unrealize (popover->widget);
gdk_window_destroy (popover->window);
popover->window = NULL;
}
static void
gtk_window_unrealize (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
GtkWindowGeometryInfo *info;
GList *link;
gint i;
/* On unrealize, we reset the size of the window such
@@ -5975,6 +6202,15 @@ gtk_window_unrealize (GtkWidget *widget)
}
}
link = priv->popovers;
while (link)
{
GtkWindowPopover *popover = link->data;
link = link->next;
popover_unrealize (popover->widget, popover);
}
GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
}
@@ -6690,19 +6926,56 @@ _gtk_window_set_allocation (GtkWindow *window,
*allocation_out = child_allocation;
}
static void
popover_size_allocate (GtkWidget *widget,
GtkWindowPopover *popover,
GtkWindow *window)
{
cairo_rectangle_int_t rect;
if (!popover->window)
return;
popover_get_rect (popover, window, &rect);
gdk_window_move_resize (popover->window, rect.x, rect.y,
rect.width, rect.height);
rect.x = rect.y = 0;
gtk_widget_size_allocate (widget, &rect);
if (gtk_widget_is_drawable (GTK_WIDGET (window)) &&
gtk_widget_is_visible (widget))
{
if (!gdk_window_is_visible (popover->window))
gdk_window_show (popover->window);
}
else if (gdk_window_is_visible (popover->window))
gdk_window_hide (popover->window);
}
static void
gtk_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
GtkWidget *child;
GtkAllocation child_allocation;
GList *link;
_gtk_window_set_allocation (window, allocation, &child_allocation);
child = gtk_bin_get_child (GTK_BIN (window));
if (child && gtk_widget_get_visible (child))
gtk_widget_size_allocate (child, &child_allocation);
link = priv->popovers;
while (link)
{
GtkWindowPopover *popover = link->data;
link = link->next;
popover_size_allocate (popover->widget, popover, window);
}
}
static gint
@@ -7472,6 +7745,27 @@ gtk_window_button_press_event (GtkWidget *widget,
return FALSE;
}
gboolean
_gtk_window_check_handle_wm_event (GdkEvent *event)
{
GtkWidget *widget;
widget = gtk_get_event_widget (event);
if (!GTK_IS_WINDOW (widget))
return FALSE;
if (event->type == GDK_BUTTON_PRESS ||
event->type == GDK_2BUTTON_PRESS)
return gtk_window_button_press_event (widget, &event->button);
else if (event->type == GDK_BUTTON_RELEASE)
return gtk_window_button_release_event (widget, &event->button);
else if (event->type == GDK_MOTION_NOTIFY)
return gtk_window_motion_notify_event (widget, &event->motion);
else
return FALSE;
}
static void
gtk_window_real_activate_default (GtkWindow *window)
{
@@ -7607,13 +7901,34 @@ gtk_window_focus_out_event (GtkWidget *widget,
return FALSE;
}
static GtkWindowPopover *
_gtk_window_has_popover (GtkWindow *window,
GtkWidget *widget)
{
GtkWindowPrivate *priv = window->priv;
GList *link;
for (link = priv->popovers; link; link = link->next)
{
GtkWindowPopover *popover = link->data;
if (popover->widget == widget)
return popover;
}
return NULL;
}
static void
gtk_window_remove (GtkContainer *container,
GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (container);
if (widget == window->priv->title_box)
unset_titlebar (window);
else if (_gtk_window_has_popover (window, widget))
_gtk_window_remove_popover (window, widget);
else
GTK_CONTAINER_CLASS (gtk_window_parent_class)->remove (container, widget);
}
@@ -9388,11 +9703,13 @@ gtk_window_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
GtkWindowPopover *popover;
GtkStyleContext *context;
gboolean ret = FALSE;
GtkAllocation allocation;
GtkBorder window_border;
gint title_height;
GList *link;
context = gtk_widget_get_style_context (widget);
@@ -9476,6 +9793,19 @@ gtk_window_draw (GtkWidget *widget,
gtk_style_context_restore (context);
}
link = priv->popovers;
while (link)
{
popover = link->data;
link = link->next;
if (popover->window && gtk_widget_is_visible (popover->widget) &&
gtk_cairo_should_draw_window (cr, popover->window))
gtk_container_propagate_draw (GTK_CONTAINER (widget),
popover->widget, cr);
}
return ret;
}
@@ -11690,3 +12020,122 @@ _gtk_window_get_shadow_width (GtkWindow *window,
{
get_shadow_width (GTK_WIDGET (window), border);
}
void
_gtk_window_add_popover (GtkWindow *window,
GtkWidget *popover)
{
GtkWindowPrivate *priv;
GtkWindowPopover *data;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (GTK_IS_WIDGET (popover));
g_return_if_fail (gtk_widget_get_parent (popover) == NULL);
priv = window->priv;
if (_gtk_window_has_popover (window, popover))
return;
data = g_new0 (GtkWindowPopover, 1);
data->widget = popover;
priv->popovers = g_list_prepend (priv->popovers, data);
if (gtk_widget_get_realized (GTK_WIDGET (window)))
popover_realize (popover, data, window);
gtk_widget_set_parent (popover, GTK_WIDGET (window));
}
void
_gtk_window_remove_popover (GtkWindow *window,
GtkWidget *popover)
{
GtkWindowPrivate *priv;
GtkWindowPopover *data;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (GTK_IS_WIDGET (popover));
priv = window->priv;
data = _gtk_window_has_popover (window, popover);
if (!data)
return;
priv->popovers = g_list_remove (priv->popovers, data);
popover_destroy (data);
}
void
_gtk_window_set_popover_position (GtkWindow *window,
GtkWidget *popover,
GtkPositionType pos,
const cairo_rectangle_int_t *rect)
{
GtkWindowPopover *data;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (GTK_IS_WIDGET (popover));
data = _gtk_window_has_popover (window, popover);
if (!data)
{
g_warning ("Widget %s(%p) is not a popover of window %s",
gtk_widget_get_name (popover), popover,
gtk_widget_get_name (GTK_WIDGET (window)));
return;
}
else
{
if (data->pos == pos &&
memcmp (&data->rect, rect, sizeof (cairo_rectangle_int_t)) == 0)
return;
}
data->rect = *rect;
data->pos = pos;
if (gtk_widget_is_visible (popover))
{
if (!data->window)
{
popover_realize (popover, data, window);
popover_map (popover, data);
}
else
gdk_window_raise (data->window);
}
gtk_widget_queue_resize (popover);
}
void
_gtk_window_get_popover_position (GtkWindow *window,
GtkWidget *popover,
GtkPositionType *pos,
cairo_rectangle_int_t *rect)
{
GtkWindowPopover *data;
g_return_if_fail (GTK_IS_WINDOW (window));
g_return_if_fail (GTK_IS_WIDGET (popover));
data = _gtk_window_has_popover (window, popover);
if (!data)
{
g_warning ("Widget %s(%p) is not a popover of window %s",
gtk_widget_get_name (popover), popover,
gtk_widget_get_name (GTK_WIDGET (window)));
return;
}
if (pos)
*pos = data->pos;
if (rect)
*rect = data->rect;
}

View File

@@ -75,6 +75,8 @@ void _gtk_window_keys_foreach (GtkWindow *window,
GtkWindowKeysForeachFunc func,
gpointer func_data);
gboolean _gtk_window_check_handle_wm_event (GdkEvent *event);
/* --- internal (GtkAcceleratable) --- */
gboolean _gtk_window_query_nonaccels (GtkWindow *window,
guint accel_key,
@@ -91,6 +93,20 @@ void _gtk_window_get_shadow_width (GtkWindow *window,
void _gtk_window_toggle_maximized (GtkWindow *window);
/* Popovers */
void _gtk_window_add_popover (GtkWindow *window,
GtkWidget *popover);
void _gtk_window_remove_popover (GtkWindow *window,
GtkWidget *popover);
void _gtk_window_set_popover_position (GtkWindow *window,
GtkWidget *popover,
GtkPositionType pos,
const cairo_rectangle_int_t *rect);
void _gtk_window_get_popover_position (GtkWindow *window,
GtkWidget *popover,
GtkPositionType *pos,
cairo_rectangle_int_t *rect);
G_END_DECLS
#endif /* __GTK_WINDOW_PRIVATE_H__ */