Compare commits

...

23 Commits

Author SHA1 Message Date
Cosimo Cecchi
2992461c2a GtkBubbleWindow: use OSD style class 2013-03-05 11:38:05 -05:00
Cosimo Cecchi
7f36b9665a GtkBubbleWindow: rework how drawing is done
Use gtk_render_frame_gap(), refactoring the code fetching coordinates to
be usable by it. This allows for rounded corners in the window shape.
2013-03-05 11:36:03 -05:00
Cosimo Cecchi
314fdec2b2 GtkBubbleWindow: allocate CSS borders and paddings 2013-03-05 11:03:14 -05:00
Matthias Clasen
39d1638997 Rename property to be more neutral
Don't put toolbar in the name of the property - we may use
a different container down the road, and then this name
would be misleading.
2013-03-01 18:25:12 -05:00
Matthias Clasen
5065f87560 Really keep GtkBubbleWindow private
_-prefix the symbols to keep them from leaking out.
Also, un-doc-commentize the sources.
2013-03-01 17:54:12 -05:00
Matthias Clasen
d5607bc8df Small documentation tweak 2013-03-01 17:26:16 -05:00
Matthias Clasen
5799d6efa9 Popdown the bubble window when text view is scrolled 2013-03-01 17:20:59 -05:00
Matthias Clasen
6b6f52faf8 Allow to populate bubbles with extra content
We do this by making the ::populate-popup signals a little more
flexible. They used to just accept a GtkMenu as argument, now
they can take a menu or a toolbar. To not break the expectations
of existing callbacks, we only emit ::populate-popup with a toolbar
if the :populate-toolbar property is TRUE.
2013-03-01 17:20:58 -05:00
Matthias Clasen
c6eff1ad06 Drop GtkSelectionWindow
It is no longer used.
2013-03-01 17:20:58 -05:00
Matthias Clasen
5b88fdd683 Do without GtkSelectionWindow
Just populate a toolbar directly, in GtkEntry and GtkTextView.
2013-03-01 17:20:57 -05:00
Matthias Clasen
f9d25a040d Fix a typo 2013-03-01 17:20:57 -05:00
Carlos Garnacho
9c30f6dd64 Made GtkBubble/SelectionWindow private at the moment 2013-03-01 17:20:56 -05:00
Carlos Garnacho
5495d477e2 Use gdk_threads_add_timeout to popup the selection window
Second granularity may bite us back there
2013-03-01 17:20:56 -05:00
Matthias Clasen
18da48edf9 Fix includes
gtkbubblewindow.h was including gtk.h, which in turn included
gtkselectionwindow.h, leading to build failure.
2013-03-01 17:20:55 -05:00
Carlos Garnacho
2de4b5bd7a Don't allow individual #includes for GtkBubble/SelectionWindow 2013-03-01 17:20:54 -05:00
Carlos Garnacho
463ef2ed50 GtkBubbleWindow: Use style border color to stroke the bubble shape
This improves themeability a bit, corners are still square though...
2013-03-01 17:20:54 -05:00
Carlos Garnacho
d43bc5cdd8 textview: Use GtkSelectionWindow for touch text selection
This enables touch devices to manipulate the text selection
2013-03-01 17:20:53 -05:00
Carlos Garnacho
879bfba4cc entry: Use GtkSelectionWindow for touch text selection
This enables touch devices to manipulate the text selection
2013-03-01 17:20:53 -05:00
Carlos Garnacho
c487b5878e Add GtkSelectionWindow
This is a helper object to provide context-dependent content
edition apt for touch devices.
2013-03-01 17:20:52 -05:00
Carlos Garnacho
b1499832c0 Add GtkBubbleWindow
This popup window widget can be used for touch friendly context
menus that point to a concrete area.
2013-03-01 17:20:52 -05:00
Carlos Garnacho
fefb55c088 texthandle: Set a bigger input shape, covering the line height
Now, even if the handles being rendered are small, the handle touch
input shape will be as wide as the visible part of the rendered asset, and
high enough to cover both the handle and the height of the line where
the selection bound is.

Also, make handles have the same virtual distance to the line top/bottom
when a drag starts, so the handle doesn't jump to another line after a
too short threshold.
2013-03-01 17:20:51 -05:00
Carlos Garnacho
757386cc97 Ensure the insertion handle stays on fake events (eg from IM)
Don't set handles mode to none if the event has send_event set.
For consistency with GtkEntry, also make GtkTextView keep the
handle mode on buffer changes.
2013-03-01 17:20:51 -05:00
Carlos Garnacho
b952930639 texthandles: Keep state internally to avoid X overhead
Handles now do sync X calls less often. As visibility state
is kept, it now can move+resize+show handles at once instead
of in separated steps.
2013-03-01 17:20:50 -05:00
8 changed files with 1908 additions and 86 deletions

View File

@@ -422,6 +422,7 @@ gtk_private_h_sources = \
gtkbitmaskprivateimpl.h \
gtkborderimageprivate.h \
gtkboxprivate.h \
gtkbubblewindowprivate.h \
gtkbuilderprivate.h \
gtkbuttonprivate.h \
gtkcairoblurprivate.h \
@@ -621,6 +622,7 @@ gtk_base_c_sources = \
gtkborder.c \
gtkborderimage.c \
gtkbox.c \
gtkbubblewindow.c \
gtkbuildable.c \
gtkbuilder.c \
gtkbuilderparser.c \

1246
gtk/gtkbubblewindow.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/* 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

@@ -66,6 +66,8 @@
#include "gtkwidgetprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtktexthandleprivate.h"
#include "gtkbubblewindowprivate.h"
#include "gtktoolbar.h"
#include "a11y/gtkentryaccessible.h"
@@ -158,7 +160,10 @@ struct _GtkEntryPrivate
gchar *placeholder_text;
GtkBubbleWindow *bubble_window;
GtkTextHandle *text_handle;
GtkWidget *selection_bubble;
guint selection_bubble_timeout_id;
gfloat xalign;
@@ -218,6 +223,7 @@ struct _GtkEntryPrivate
guint truncate_multiline : 1;
guint cursor_handle_dragged : 1;
guint selection_handle_dragged : 1;
guint populate_all : 1;
};
struct _EntryIconInfo
@@ -314,7 +320,8 @@ enum {
PROP_COMPLETION,
PROP_INPUT_PURPOSE,
PROP_INPUT_HINTS,
PROP_ATTRIBUTES
PROP_ATTRIBUTES,
PROP_POPULATE_ALL
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -592,6 +599,12 @@ static void gtk_entry_handle_dragged (GtkTextHandle *h
gint x,
gint y,
GtkEntry *entry);
static void gtk_entry_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkEntry *entry);
static void gtk_entry_selection_bubble_popup_set (GtkEntry *entry);
static void gtk_entry_selection_bubble_popup_unset (GtkEntry *entry);
static void begin_change (GtkEntry *entry);
static void end_change (GtkEntry *entry);
@@ -1412,6 +1425,21 @@ gtk_entry_class_init (GtkEntryClass *class)
PANGO_TYPE_ATTR_LIST,
GTK_PARAM_READWRITE));
/** GtkEntry:populate-all:
*
* If ::populate-all is %TRUE, the #GtkEntry::populate-popup
* signal is also emitted for touch popups.
*
* Since: 3.8
*/
g_object_class_install_property (gobject_class,
PROP_POPULATE_ALL,
g_param_spec_boolean ("populate-all",
P_("Populate all"),
P_("Whether to emit ::populate-popup for touch popups"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkEntry:icon-prelight:
*
@@ -1470,13 +1498,20 @@ gtk_entry_class_init (GtkEntryClass *class)
/**
* GtkEntry::populate-popup:
* @entry: The entry on which the signal is emitted
* @menu: the menu that is being populated
* @popup: the container that is being populated
*
* The ::populate-popup signal gets emitted before showing the
* context menu of the entry.
* The ::populate-popup signal gets emitted before showing the
* context menu of the entry.
*
* If you need to add items to the context menu, connect
* to this signal and append your menuitems to the @menu.
* to this signal and append your items to the @widget, which
* will be a #GtkMenu in this case.
*
* If #GtkEntry::populate-all is %TRUE, this signal will
* also be emitted to populate touch popups. In this case,
* @widget will be a different container, e.g. a #GtkToolbar.
* The signal handler should not make assumptions about the
* type of @widget.
*/
signals[POPULATE_POPUP] =
g_signal_new (I_("populate-popup"),
@@ -1486,7 +1521,7 @@ gtk_entry_class_init (GtkEntryClass *class)
NULL, NULL,
_gtk_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
GTK_TYPE_MENU);
GTK_TYPE_WIDGET);
/* Action signals */
@@ -2228,6 +2263,10 @@ gtk_entry_set_property (GObject *object,
gtk_entry_set_attributes (entry, g_value_get_boxed (value));
break;
case PROP_POPULATE_ALL:
entry->priv->populate_all = g_value_get_boolean (value);
break;
case PROP_SCROLL_OFFSET:
case PROP_CURSOR_POSITION:
default:
@@ -2464,6 +2503,10 @@ gtk_entry_get_property (GObject *object,
g_value_set_boxed (value, priv->attrs);
break;
case PROP_POPULATE_ALL:
g_value_set_boolean (value, priv->populate_all);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2575,6 +2618,8 @@ gtk_entry_init (GtkEntry *entry)
priv->text_handle = _gtk_text_handle_new (GTK_WIDGET (entry));
g_signal_connect (priv->text_handle, "handle-dragged",
G_CALLBACK (gtk_entry_handle_dragged), entry);
g_signal_connect (priv->text_handle, "drag-finished",
G_CALLBACK (gtk_entry_handle_drag_finished), entry);
}
static void
@@ -2811,6 +2856,9 @@ gtk_entry_finalize (GObject *object)
if (priv->recompute_idle)
g_source_remove (priv->recompute_idle);
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
g_object_unref (priv->text_handle);
g_free (priv->placeholder_text);
g_free (priv->im_module);
@@ -4018,6 +4066,8 @@ gtk_entry_button_press (GtkWidget *widget,
gint sel_start, sel_end;
gint i;
gtk_entry_selection_bubble_popup_unset (entry);
for (i = 0; i < MAX_ICONS; i++)
{
icon_info = priv->icons[i];
@@ -4222,6 +4272,8 @@ gtk_entry_button_release (GtkWidget *widget,
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryPrivate *priv = entry->priv;
EntryIconInfo *icon_info = NULL;
gboolean is_touchscreen;
GdkDevice *source;
gint i;
for (i = 0; i < MAX_ICONS; i++)
@@ -4254,21 +4306,23 @@ gtk_entry_button_release (GtkWidget *widget,
if (event->window != priv->text_area || priv->button != event->button)
return FALSE;
source = gdk_event_get_source_device ((GdkEvent *) event);
is_touchscreen = (test_touchscreen ||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN);
if (priv->in_drag)
{
gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x);
GdkDevice *source;
gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
source = gdk_event_get_source_device ((GdkEvent *) event);
if (test_touchscreen ||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN)
if (is_touchscreen)
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
priv->in_drag = 0;
}
else if (is_touchscreen)
gtk_entry_selection_bubble_popup_set (entry);
priv->button = 0;
priv->device = NULL;
@@ -4492,8 +4546,12 @@ gtk_entry_key_press (GtkWidget *widget,
gtk_entry_reset_blink_time (entry);
gtk_entry_pend_cursor_blink (entry);
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
gtk_entry_selection_bubble_popup_unset (entry);
if (!event->send_event)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
if (priv->editable)
{
@@ -4588,6 +4646,7 @@ gtk_entry_focus_out (GtkWidget *widget,
GtkEntryCompletion *completion;
GdkKeymap *keymap;
gtk_entry_selection_bubble_popup_unset (entry);
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
@@ -5497,6 +5556,8 @@ gtk_entry_cut_clipboard (GtkEntry *entry)
{
gtk_widget_error_bell (GTK_WIDGET (entry));
}
gtk_entry_selection_bubble_popup_unset (entry);
}
static void
@@ -6225,6 +6286,8 @@ gtk_entry_handle_dragged (GtkTextHandle *handle,
GtkTextHandleMode mode;
gint *min, *max;
gtk_entry_selection_bubble_popup_unset (entry);
cursor_pos = priv->current_pos;
selection_bound_pos = priv->selection_bound;
mode = _gtk_text_handle_get_mode (handle);
@@ -6277,6 +6340,15 @@ gtk_entry_handle_dragged (GtkTextHandle *handle,
}
}
static void
gtk_entry_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkEntry *entry)
{
gtk_entry_selection_bubble_popup_set (entry);
}
/**
* gtk_entry_reset_im_context:
* @entry: a #GtkEntry
@@ -9217,6 +9289,151 @@ gtk_entry_popup_menu (GtkWidget *widget)
return TRUE;
}
static void
activate_bubble_cb (GtkWidget *item,
GtkEntry *entry)
{
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));
}
static void
append_bubble_action (GtkEntry *entry,
GtkWidget *toolbar,
const gchar *stock_id,
const gchar *signal,
gboolean sensitive)
{
GtkToolItem *item = gtk_tool_button_new_from_stock (stock_id);
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);
gtk_widget_show (GTK_WIDGET (item));
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
}
static void
bubble_targets_received (GtkClipboard *clipboard,
GtkSelectionData *data,
gpointer user_data)
{
GtkEntry *entry = user_data;
GtkEntryPrivate *priv = entry->priv;
cairo_rectangle_int_t rect;
GtkAllocation allocation;
gint start_x, end_x;
gboolean has_selection;
gboolean has_clipboard;
DisplayMode mode;
GtkWidget *toolbar;
has_selection = gtk_editable_get_selection_bounds (GTK_EDITABLE (entry),
NULL, NULL);
if (!has_selection && !priv->editable)
{
priv->selection_bubble_timeout_id = 0;
return;
}
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
priv->selection_bubble = _gtk_bubble_window_new ();
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);
gtk_widget_show (toolbar);
gtk_container_add (GTK_CONTAINER (priv->selection_bubble), toolbar);
has_clipboard = gtk_selection_data_targets_include_text (data);
mode = gtk_entry_get_display_mode (entry);
append_bubble_action (entry, toolbar, GTK_STOCK_CUT, "cut-clipboard",
priv->editable && has_selection && mode == DISPLAY_NORMAL);
append_bubble_action (entry, toolbar, GTK_STOCK_COPY, "copy-clipboard",
has_selection && mode == DISPLAY_NORMAL);
append_bubble_action (entry, toolbar, GTK_STOCK_PASTE, "paste-clipboard",
priv->editable && has_clipboard);
if (priv->populate_all)
g_signal_emit (entry, signals[POPULATE_POPUP], 0, toolbar);
gtk_widget_get_allocation (GTK_WIDGET (entry), &allocation);
gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &start_x, NULL);
start_x -= priv->scroll_offset;
start_x = CLAMP (start_x, 0, gdk_window_get_width (priv->text_area));
rect.y = 0;
rect.height = gdk_window_get_height (priv->text_area);
if (has_selection)
{
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;
}
else
{
rect.x = start_x;
rect.width = 0;
}
_gtk_bubble_window_popup (GTK_BUBBLE_WINDOW (priv->selection_bubble),
priv->text_area, &rect, GTK_POS_TOP);
priv->selection_bubble_timeout_id = 0;
}
static gboolean
gtk_entry_selection_bubble_popup_cb (gpointer user_data)
{
GtkEntry *entry = user_data;
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
gdk_atom_intern_static_string ("TARGETS"),
bubble_targets_received,
entry);
return G_SOURCE_REMOVE;
}
static void
gtk_entry_selection_bubble_popup_unset (GtkEntry *entry)
{
GtkEntryPrivate *priv;
priv = entry->priv;
if (priv->selection_bubble)
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
if (priv->selection_bubble_timeout_id)
{
g_source_remove (priv->selection_bubble_timeout_id);
priv->selection_bubble_timeout_id = 0;
}
}
static void
gtk_entry_selection_bubble_popup_set (GtkEntry *entry)
{
GtkEntryPrivate *priv;
priv = entry->priv;
if (priv->selection_bubble_timeout_id)
g_source_remove (priv->selection_bubble_timeout_id);
priv->selection_bubble_timeout_id =
gdk_threads_add_timeout (1000, gtk_entry_selection_bubble_popup_cb, entry);
}
static void
gtk_entry_drag_begin (GtkWidget *widget,
GdkDragContext *context)

View File

@@ -85,7 +85,7 @@ struct _GtkEntryClass
/* Hook to customize right-click popup */
void (* populate_popup) (GtkEntry *entry,
GtkMenu *menu);
GtkWidget *popup);
/* Action signals
*/

View File

@@ -46,6 +46,9 @@ struct _HandleWindow
gint dx;
gint dy;
guint dragged : 1;
guint mode_visible : 1;
guint user_visible : 1;
guint has_point : 1;
};
struct _GtkTextHandlePrivate
@@ -103,6 +106,9 @@ _gtk_text_handle_draw (GtkTextHandle *handle,
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);
gtk_style_context_save (priv->style_context);
gtk_style_context_add_class (priv->style_context,
GTK_STYLE_CLASS_CURSOR_HANDLE);
@@ -133,6 +139,7 @@ _gtk_text_handle_update_shape (GtkTextHandle *handle,
GtkTextHandlePosition pos)
{
GtkTextHandlePrivate *priv;
cairo_rectangle_int_t rect;
cairo_surface_t *surface;
cairo_region_t *region;
cairo_t *cr;
@@ -156,6 +163,15 @@ _gtk_text_handle_update_shape (GtkTextHandle *handle,
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);
@@ -275,6 +291,8 @@ gtk_text_handle_widget_event (GtkWidget *widget,
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_START)
y += height;
y += priv->windows[pos].pointing_to.height / 2;
g_signal_emit (handle, signals[HANDLE_DRAGGED], 0, pos, x, y);
}
@@ -282,13 +300,11 @@ gtk_text_handle_widget_event (GtkWidget *widget,
}
static void
_gtk_text_handle_update_window (GtkTextHandle *handle,
GtkTextHandlePosition pos)
_gtk_text_handle_update_window_state (GtkTextHandle *handle,
GtkTextHandlePosition pos)
{
GtkTextHandlePrivate *priv;
HandleWindow *handle_window;
gboolean visible;
gint x, y;
priv = handle->priv;
handle_window = &priv->windows[pos];
@@ -296,30 +312,50 @@ _gtk_text_handle_update_window (GtkTextHandle *handle,
if (!handle_window->window)
return;
/* Get current state and destroy */
visible = gdk_window_is_visible (handle_window->window);
if (visible)
if (handle_window->has_point &&
handle_window->mode_visible && handle_window->user_visible)
{
gint width;
gint x, y, width, height;
_gtk_text_handle_get_size (handle, &width, NULL);
gdk_window_get_root_coords (handle_window->window,
width / 2, 0, &x, &y);
}
x = handle_window->pointing_to.x;
y = handle_window->pointing_to.y;
_gtk_text_handle_get_size (handle, &width, &height);
gtk_widget_unregister_window (priv->parent, handle_window->window);
gdk_window_destroy (handle_window->window);
if (pos != GTK_TEXT_HANDLE_POSITION_CURSOR)
y -= height;
/* Create new window and apply old state */
handle_window->window = _gtk_text_handle_create_window (handle, pos);
height += handle_window->pointing_to.height;
x -= width / 2;
if (visible)
{
gdk_window_move_resize (handle_window->window, x, y, width, height);
gdk_window_show (handle_window->window);
_gtk_text_handle_set_position (handle, pos,
&handle_window->pointing_to);
}
else
gdk_window_hide (handle_window->window);
}
static void
_gtk_text_handle_update_window (GtkTextHandle *handle,
GtkTextHandlePosition pos,
gboolean recreate)
{
GtkTextHandlePrivate *priv;
HandleWindow *handle_window;
priv = handle->priv;
handle_window = &priv->windows[pos];
if (!handle_window->window)
return;
if (recreate)
{
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);
}
_gtk_text_handle_update_window_state (handle, pos);
}
static void
@@ -328,8 +364,15 @@ _gtk_text_handle_update_windows (GtkTextHandle *handle)
GtkTextHandlePrivate *priv = handle->priv;
gtk_style_context_invalidate (priv->style_context);
_gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START);
_gtk_text_handle_update_window (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END);
_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);
}
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
@@ -350,7 +393,7 @@ gtk_text_handle_constructed (GObject *object)
object);
priv->composited_changed_id =
g_signal_connect_swapped (priv->parent, "composited-changed",
G_CALLBACK (_gtk_text_handle_update_windows),
G_CALLBACK (_gtk_text_handle_composited_changed),
object);
priv->style_updated_id =
g_signal_connect_swapped (priv->parent, "style-updated",
@@ -577,30 +620,34 @@ _gtk_text_handle_set_mode (GtkTextHandle *handle,
if (priv->mode == mode)
return;
priv->mode = mode;
switch (mode)
{
case GTK_TEXT_HANDLE_MODE_CURSOR:
/* Only display one handle */
gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].window);
gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
priv->windows[GTK_TEXT_HANDLE_POSITION_CURSOR].mode_visible = TRUE;
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE;
break;
case GTK_TEXT_HANDLE_MODE_SELECTION:
/* Display both handles */
gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
gdk_window_show (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
case GTK_TEXT_HANDLE_MODE_SELECTION:
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = TRUE;
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = TRUE;
break;
case GTK_TEXT_HANDLE_MODE_NONE:
default:
gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
gdk_window_hide (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].mode_visible = FALSE;
priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].mode_visible = FALSE;
break;
}
priv->mode = mode;
_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);
}
GtkTextHandleMode
@@ -620,14 +667,15 @@ _gtk_text_handle_set_position (GtkTextHandle *handle,
GdkRectangle *rect)
{
GtkTextHandlePrivate *priv;
gint x, y, width, height;
HandleWindow *handle_window;
gboolean size_changed;
g_return_if_fail (GTK_IS_TEXT_HANDLE (handle));
priv = handle->priv;
pos = CLAMP (pos, GTK_TEXT_HANDLE_POSITION_CURSOR,
GTK_TEXT_HANDLE_POSITION_SELECTION_START);
handle_window = &priv->windows[pos];
if (!priv->realized)
return;
@@ -637,21 +685,20 @@ _gtk_text_handle_set_position (GtkTextHandle *handle,
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,
&x, &y);
_gtk_text_handle_get_size (handle, &width, &height);
handle_window = &priv->windows[pos];
&handle_window->pointing_to.x,
&handle_window->pointing_to.y);
if (pos == GTK_TEXT_HANDLE_POSITION_CURSOR)
y += rect->height;
else
y -= height;
_gtk_text_handle_update_window_state (handle, pos);
x -= width / 2;
gdk_window_move (handle_window->window, x, y);
handle_window->pointing_to = *rect;
if (size_changed)
_gtk_text_handle_update_shape (handle, handle_window->window, pos);
}
void
@@ -676,18 +723,11 @@ _gtk_text_handle_set_visible (GtkTextHandle *handle,
if (!window)
return;
if (!visible)
gdk_window_hide (window);
else
{
if (priv->mode == GTK_TEXT_HANDLE_MODE_NONE ||
(priv->mode == GTK_TEXT_HANDLE_MODE_CURSOR &&
pos != GTK_TEXT_HANDLE_POSITION_CURSOR))
return;
if (!gdk_window_is_visible (window))
_gtk_text_handle_update_shape (handle, window, pos);
if (!gdk_window_is_visible (window))
gdk_window_show (window);
}
priv->windows[pos].user_visible = visible;
_gtk_text_handle_update_window_state (handle, pos);
}
gboolean

View File

@@ -53,6 +53,8 @@
#include "gtktexthandleprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkbubblewindowprivate.h"
#include "gtktoolbar.h"
#include "a11y/gtktextviewaccessibleprivate.h"
@@ -136,6 +138,8 @@ struct _GtkTextViewPrivate
gulong selection_drag_handler;
GtkTextHandle *text_handle;
GtkWidget *selection_bubble;
guint selection_bubble_timeout_id;
GtkTextWindow *text_window;
GtkTextWindow *left_window;
@@ -235,6 +239,7 @@ struct _GtkTextViewPrivate
guint vscroll_policy : 1;
guint cursor_handle_dragged : 1;
guint selection_handle_dragged : 1;
guint populate_all : 1;
};
struct _GtkTextPendingScroll
@@ -289,7 +294,8 @@ enum
PROP_HSCROLL_POLICY,
PROP_VSCROLL_POLICY,
PROP_INPUT_PURPOSE,
PROP_INPUT_HINTS
PROP_INPUT_HINTS,
PROP_POPULATE_ALL
};
static void gtk_text_view_finalize (GObject *object);
@@ -511,9 +517,16 @@ static void gtk_text_view_handle_dragged (GtkTextHandle *handle,
gint x,
gint y,
GtkTextView *text_view);
static void gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextView *text_view);
static void gtk_text_view_update_handles (GtkTextView *text_view,
GtkTextHandleMode mode);
static void gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view);
static void gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view);
/* FIXME probably need the focus methods. */
typedef struct _GtkTextViewChild GtkTextViewChild;
@@ -850,6 +863,22 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
GTK_INPUT_HINT_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** GtkTextView:populate-all:
*
* If ::populate-all is %TRUE, the #GtkTextView::populate-popup
* signal is also emitted for touch popups.
*
* Since: 3.8
*/
g_object_class_install_property (gobject_class,
PROP_POPULATE_ALL,
g_param_spec_boolean ("populate-all",
P_("Populate all"),
P_("Whether to emit ::populate-popup for touch popups"),
FALSE,
GTK_PARAM_READWRITE));
/* GtkScrollable interface */
g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
@@ -1112,13 +1141,22 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
/**
* GtkTextView::populate-popup:
* @text_view: The text view on which the signal is emitted
* @menu: the menu that is being populated
* @popup: the container that is being populated
*
* The ::populate-popup signal gets emitted before showing the
* The ::populate-popup signal gets emitted before showing the
* context menu of the text view.
*
* If you need to add items to the context menu, connect
* to this signal and append your menuitems to the @menu.
* to this signal and append your items to the @popup, which
* will be a #GtkMenu in this case.
*
* If #GtkEntry::populate-toolbar is %TRUE, this signal will
* also be emitted to populate touch popups. In this case,
* @popup will be a different container, e.g. a #GtkToolbar.
*
* The signal handler should not make assumptions about the
* type of @widget, but check whether @popup is a #GtkMenu
* or #GtkToolbar or another kind of container.
*/
signals[POPULATE_POPUP] =
g_signal_new (I_("populate-popup"),
@@ -1128,7 +1166,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
NULL, NULL,
_gtk_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
GTK_TYPE_MENU);
GTK_TYPE_WIDGET);
/**
* GtkTextView::select-all:
@@ -1479,6 +1517,8 @@ gtk_text_view_init (GtkTextView *text_view)
priv->text_handle = _gtk_text_handle_new (widget);
g_signal_connect (priv->text_handle, "handle-dragged",
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);
}
/**
@@ -3137,6 +3177,9 @@ gtk_text_view_finalize (GObject *object)
if (priv->bottom_window)
text_window_free (priv->bottom_window);
if (priv->selection_bubble)
gtk_widget_destroy (priv->selection_bubble);
g_object_unref (priv->text_handle);
g_object_unref (priv->im_context);
@@ -3248,6 +3291,10 @@ gtk_text_view_set_property (GObject *object,
gtk_text_view_set_input_hints (text_view, g_value_get_flags (value));
break;
case PROP_POPULATE_ALL:
text_view->priv->populate_all = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3352,6 +3399,10 @@ gtk_text_view_get_property (GObject *object,
g_value_set_flags (value, gtk_text_view_get_input_hints (text_view));
break;
case PROP_POPULATE_ALL:
g_value_set_boolean (value, priv->populate_all);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -4509,6 +4560,7 @@ gtk_text_view_handle_dragged (GtkTextHandle *handle,
buffer = get_buffer (text_view);
mode = _gtk_text_handle_get_mode (handle);
gtk_text_view_selection_bubble_popup_unset (text_view);
gtk_text_layout_get_iter_at_pixel (priv->layout, &iter,
x + priv->xoffset,
y + priv->yoffset);
@@ -4575,6 +4627,14 @@ gtk_text_view_handle_dragged (GtkTextHandle *handle,
}
}
static void
gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextView *text_view)
{
gtk_text_view_selection_bubble_popup_set (text_view);
}
static void
gtk_text_view_update_handles (GtkTextView *text_view,
GtkTextHandleMode mode)
@@ -4755,8 +4815,11 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
gtk_text_view_reset_blink_time (text_view);
gtk_text_view_pend_cursor_blink (text_view);
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
if (!event->send_event)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
gtk_text_view_selection_bubble_popup_unset (text_view);
return retval;
}
@@ -4808,6 +4871,7 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
}
gtk_text_view_reset_blink_time (text_view);
gtk_text_view_selection_bubble_popup_unset (text_view);
#if 0
/* debug hack */
@@ -4925,9 +4989,11 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
{
GtkTextView *text_view;
GtkTextViewPrivate *priv;
GdkDevice *device;
text_view = GTK_TEXT_VIEW (widget);
priv = text_view->priv;
device = gdk_event_get_source_device ((GdkEvent *) event);
if (event->window != priv->text_window->bin_window)
return FALSE;
@@ -4941,11 +5007,15 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
}
if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget)))
return TRUE;
{
if (test_touchscreen ||
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN)
gtk_text_view_selection_bubble_popup_set (text_view);
return TRUE;
}
else if (priv->pending_place_cursor_button == event->button)
{
GtkTextHandleMode mode;
GdkDevice *device;
GtkTextIter iter;
/* Unselect everything; we clicked inside selection, but
@@ -4960,12 +5030,10 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
gtk_text_view_check_cursor_blink (text_view);
device = gdk_event_get_source_device ((GdkEvent *) event);
if (gtk_widget_is_sensitive (widget) &&
(test_touchscreen ||
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))
mode = GTK_TEXT_HANDLE_MODE_CURSOR;
mode = GTK_TEXT_HANDLE_MODE_CURSOR;
else
mode = GTK_TEXT_HANDLE_MODE_NONE;
@@ -5045,6 +5113,7 @@ gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
keymap_direction_changed,
text_view);
gtk_text_view_selection_bubble_popup_unset (text_view);
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
@@ -6326,6 +6395,7 @@ gtk_text_view_cut_clipboard (GtkTextView *text_view)
DV(g_print (G_STRLOC": scrolling onscreen\n"));
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_insert (get_buffer (text_view)));
gtk_text_view_selection_bubble_popup_unset (text_view);
}
static void
@@ -6376,7 +6446,10 @@ gtk_text_view_buffer_changed_handler (GtkTextBuffer *buffer,
gpointer data)
{
GtkTextView *text_view = data;
gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_NONE);
GtkTextViewPrivate *priv = text_view->priv;
gtk_text_view_update_handles (text_view,
_gtk_text_handle_get_mode (priv->text_handle));
}
static void
@@ -8696,6 +8769,165 @@ gtk_text_view_popup_menu (GtkWidget *widget)
return TRUE;
}
static void
gtk_text_view_get_selection_rect (GtkTextView *text_view,
cairo_rectangle_int_t *rect)
{
cairo_rectangle_int_t rect_cursor, rect_bound;
GtkTextIter cursor, bound;
GtkTextBuffer *buffer;
gint x1, y1, x2, y2;
buffer = get_buffer (text_view);
gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
gtk_text_buffer_get_insert (buffer));
gtk_text_buffer_get_iter_at_mark (buffer, &bound,
gtk_text_buffer_get_selection_bound (buffer));
gtk_text_view_get_cursor_locations (text_view, &cursor, &rect_cursor, NULL);
gtk_text_view_get_cursor_locations (text_view, &bound, &rect_bound, NULL);
x1 = MIN (rect_cursor.x, rect_bound.x);
x2 = MAX (rect_cursor.x, rect_bound.x);
y1 = MIN (rect_cursor.y, rect_bound.y);
y2 = MAX (rect_cursor.y + rect_cursor.height, rect_bound.y + rect_bound.height);
rect->x = x1;
rect->y = y1;
rect->width = x2 - x1;
rect->height = y2 - y1;
}
static void
activate_bubble_cb (GtkWidget *item,
GtkTextView *text_view)
{
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));
}
static void
append_bubble_action (GtkTextView *text_view,
GtkWidget *toolbar,
const gchar *stock_id,
const gchar *signal,
gboolean sensitive)
{
GtkToolItem *item = gtk_tool_button_new_from_stock (stock_id);
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);
gtk_widget_show (GTK_WIDGET (item));
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
}
static void
bubble_targets_received (GtkClipboard *clipboard,
GtkSelectionData *data,
gpointer user_data)
{
GtkTextView *text_view = user_data;
GtkTextViewPrivate *priv = text_view->priv;
cairo_rectangle_int_t rect;
gboolean has_selection;
gboolean has_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),
&sel_start, &sel_end);
if (!priv->editable && !has_selection)
{
priv->selection_bubble_timeout_id = 0;
return;
}
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 ();
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);
gtk_widget_show (toolbar);
gtk_container_add (GTK_CONTAINER (priv->selection_bubble), toolbar);
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
gtk_text_buffer_get_insert (get_buffer (text_view)));
can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
has_clipboard = gtk_selection_data_targets_include_text (data);
append_bubble_action (text_view, toolbar, GTK_STOCK_CUT, "cut-clipboard",
has_selection &&
range_contains_editable_text (&sel_start, &sel_end,
priv->editable));
append_bubble_action (text_view, toolbar, GTK_STOCK_COPY, "copy-clipboard",
has_selection);
append_bubble_action (text_view, toolbar, GTK_STOCK_PASTE, "paste-clipboard",
can_insert && has_clipboard);
if (priv->populate_all)
g_signal_emit (text_view, signals[POPULATE_POPUP], 0, toolbar);
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);
priv->selection_bubble_timeout_id = 0;
}
static gboolean
gtk_text_view_selection_bubble_popup_cb (gpointer user_data)
{
GtkTextView *text_view = user_data;
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
GDK_SELECTION_CLIPBOARD),
gdk_atom_intern_static_string ("TARGETS"),
bubble_targets_received,
text_view);
return G_SOURCE_REMOVE;
}
static void
gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view)
{
GtkTextViewPrivate *priv;
priv = text_view->priv;
if (priv->selection_bubble)
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
if (priv->selection_bubble_timeout_id)
{
g_source_remove (priv->selection_bubble_timeout_id);
priv->selection_bubble_timeout_id = 0;
}
}
static void
gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view)
{
GtkTextViewPrivate *priv;
priv = text_view->priv;
if (priv->selection_bubble_timeout_id)
g_source_remove (priv->selection_bubble_timeout_id);
priv->selection_bubble_timeout_id =
gdk_threads_add_timeout (1000, gtk_text_view_selection_bubble_popup_cb,
text_view);
}
/* Child GdkWindows */
@@ -8864,8 +9096,12 @@ text_window_scroll (GtkTextWindow *win,
gint dx,
gint dy)
{
GtkTextView *view = GTK_TEXT_VIEW (win->widget);
GtkTextViewPrivate *priv = view->priv;
if (dx != 0 || dy != 0)
{
_gtk_bubble_window_popdown (GTK_BUBBLE_WINDOW (priv->selection_bubble));
gdk_window_scroll (win->bin_window, dx, dy);
}
}

View File

@@ -78,7 +78,7 @@ struct _GtkTextViewClass
GtkContainerClass parent_class;
void (* populate_popup) (GtkTextView *text_view,
GtkMenu *menu);
GtkWidget *popup);
/* These are all RUN_ACTION signals for keybindings */