Merge branch 'popovers'

This commit is contained in:
Carlos Garnacho 2014-01-22 18:42:29 +01:00
commit ce32476f32
22 changed files with 3365 additions and 1666 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

@ -7853,3 +7853,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 \
@ -490,6 +490,7 @@ gtk_private_h_sources = \
gtkkeyhash.h \
gtklabelprivate.h \
gtklockbuttonprivate.h \
gtkmagnifierprivate.h \
gtkmenubuttonprivate.h \
gtkmenuprivate.h \
gtkmenuitemprivate.h \
@ -629,7 +630,6 @@ gtk_base_c_sources = \
gtkborder.c \
gtkborderimage.c \
gtkbox.c \
gtkbubblewindow.c \
gtkbuildable.c \
gtkbuilder.c \
gtkbuilderparser.c \
@ -764,6 +764,7 @@ gtk_base_c_sources = \
gtkliststore.c \
gtklockbutton.c \
gtkmain.c \
gtkmagnifier.c \
gtkmarshalers.c \
gtkmenu.c \
gtkmenubar.c \
@ -801,6 +802,7 @@ gtk_base_c_sources = \
gtkprivatetypebuiltins.c \
gtkprogressbar.c \
gtkpixelcache.c \
gtkpopover.c \
gtkradiobutton.c \
gtkradiomenuitem.c \
gtkradiotoolbutton.c \

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)
{

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_val_if_fail (GTK_IS_MAGNIFIER (magnifier), NULL);
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)))
{

1679
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);
@ -5398,6 +5438,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)
{
@ -5405,6 +5480,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))
{
@ -5511,6 +5587,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
@ -5540,6 +5625,7 @@ gtk_window_unmap (GtkWidget *widget)
GtkWindowGeometryInfo *info;
GdkWindow *gdk_window;
GdkWindowState state;
GList *link;
if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
{
@ -5547,6 +5633,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);
@ -5676,6 +5771,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)
{
@ -5688,6 +5895,7 @@ gtk_window_realize (GtkWidget *widget)
GtkWindowPrivate *priv;
gint i;
int old_scale;
GList *link;
window = GTK_WINDOW (widget);
priv = window->priv;
@ -5926,18 +6134,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
@ -5982,6 +6209,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);
}
@ -6697,19 +6933,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
@ -7479,6 +7752,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)
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)
{
@ -7614,13 +7908,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);
}
@ -9395,11 +9710,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);
@ -9483,6 +9800,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;
}
@ -11697,3 +12027,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__ */