Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d94d6e560b | |||
| 33b160569f | |||
| fd941bd764 | |||
| 18e451da6e | |||
| 0e05d33eee | |||
| e5b2e528ca | |||
| 355a4cdc14 | |||
| d45dc8f3c3 | |||
| dd8cf478b0 | |||
| c33786446c | |||
| c4b7848aeb | |||
| 2d88021014 | |||
| 5cf832da40 | |||
| bbbc5198a3 | |||
| 2e4eaa7cfd | |||
| 07a4c8174f | |||
| 5f20868ec8 | |||
| 5d2c04b9d1 | |||
| 62c32d742e | |||
| 736438ecfb | |||
| b02c3cf4a9 | |||
| cf4b293b75 | |||
| 64534d1fc2 | |||
| 380299681a | |||
| bbe6075408 | |||
| 9615fa61a0 | |||
| 5a0ec9859e | |||
| 03d89b557a | |||
| d12924f241 | |||
| e349e46abd | |||
| 888be799d9 | |||
| 365a4f7535 | |||
| 6468ae821f | |||
| 4f04075a8f | |||
| ae058ae7ef | |||
| 7f0fe69b6e | |||
| ce879ae739 | |||
| df2bb4a92d | |||
| e45d9994a4 | |||
| 447ddb08fc | |||
| 0df96ac738 | |||
| 688d8c0796 | |||
| fb7047d212 | |||
| 1bb03e26a4 | |||
| 7df706715c | |||
| 40455db2f5 | |||
| 64ec631874 | |||
| de593da052 | |||
| a308c35112 | |||
| 412ba5cc2d | |||
| e4e11aa4a2 | |||
| e48285f759 | |||
| dcd2dba384 | |||
| 1a6a1118a4 | |||
| d6476eb99a | |||
| cdd97bbff7 | |||
| a447b2fee2 | |||
| 4af317307f | |||
| aa0c220f7d | |||
| 39966dbaf8 | |||
| fbb70becef | |||
| 388dcb4234 | |||
| e8a9fad467 | |||
| ccb7da408e | |||
| 1764558d8c | |||
| 90ee273c66 | |||
| b0b26cc2e0 | |||
| 990e049510 | |||
| 8f013f4055 |
@@ -2936,6 +2936,9 @@ gtk_scrolled_window_get_min_content_width
|
||||
gtk_scrolled_window_set_min_content_width
|
||||
gtk_scrolled_window_get_min_content_height
|
||||
gtk_scrolled_window_set_min_content_height
|
||||
GtkKineticScrollingFlags
|
||||
gtk_scrolled_window_set_kinetic_scrolling
|
||||
gtk_scrolled_window_get_kinetic_scrolling
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_SCROLLED_WINDOW
|
||||
|
||||
+3
-1
@@ -61,6 +61,7 @@ typedef enum
|
||||
* of a stylus on a graphics tablet.
|
||||
* @GDK_SOURCE_CURSOR: the device is a graphics tablet "puck" or similar device.
|
||||
* @GDK_SOURCE_KEYBOARD: the device is a keyboard.
|
||||
* @GDK_SOURCE_TOUCH: the device is a touch capable device.
|
||||
*
|
||||
* An enumeration describing the type of an input device in general terms.
|
||||
*/
|
||||
@@ -70,7 +71,8 @@ typedef enum
|
||||
GDK_SOURCE_PEN,
|
||||
GDK_SOURCE_ERASER,
|
||||
GDK_SOURCE_CURSOR,
|
||||
GDK_SOURCE_KEYBOARD
|
||||
GDK_SOURCE_KEYBOARD,
|
||||
GDK_SOURCE_TOUCH
|
||||
} GdkInputSource;
|
||||
|
||||
/**
|
||||
|
||||
+22
-9
@@ -899,15 +899,25 @@ switch_to_pointer_grab (GdkDisplay *display,
|
||||
|
||||
if (grab == NULL) /* Ungrabbed, send events */
|
||||
{
|
||||
pointer_window = NULL;
|
||||
if (new_toplevel)
|
||||
{
|
||||
/* Find (possibly virtual) child window */
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (new_toplevel,
|
||||
x, y,
|
||||
NULL, NULL);
|
||||
}
|
||||
/* If the source device is a touch device, do not
|
||||
* propagate any enter event yet, until one is
|
||||
* synthesized when needed.
|
||||
*/
|
||||
if (source_device &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
info->need_touch_press_enter = TRUE;
|
||||
|
||||
pointer_window = NULL;
|
||||
|
||||
if (new_toplevel &&
|
||||
!info->need_touch_press_enter)
|
||||
{
|
||||
/* Find (possibly virtual) child window */
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (new_toplevel,
|
||||
x, y,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
if (pointer_window != last_grab->window)
|
||||
synthesize_crossing_events (display, device, source_device,
|
||||
@@ -1122,6 +1132,9 @@ _gdk_display_get_pointer_info (GdkDisplay *display,
|
||||
{
|
||||
GdkPointerWindowInfo *info;
|
||||
|
||||
if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
device = gdk_device_get_associated_device (device);
|
||||
|
||||
if (G_UNLIKELY (!device))
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ typedef struct
|
||||
gdouble toplevel_x, toplevel_y;
|
||||
guint32 state;
|
||||
guint32 button;
|
||||
GdkDevice *last_slave;
|
||||
guint need_touch_press_enter : 1;
|
||||
} GdkPointerWindowInfo;
|
||||
|
||||
typedef struct
|
||||
|
||||
+13
-1
@@ -354,6 +354,15 @@ typedef enum
|
||||
* @GDK_CROSSING_GTK_UNGRAB: crossing because a GTK+ grab is deactivated.
|
||||
* @GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed
|
||||
* state (e.g. sensitivity).
|
||||
* @GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed
|
||||
* state (e.g. sensitivity).
|
||||
* @GDK_CROSSING_TOUCH_PRESS: crossing because a touch device was pressed,
|
||||
* this event is synthetic as the pointer might have not left the window.
|
||||
* @GDK_CROSSING_TOUCH_RELEASE: crossing because a touch device was released.
|
||||
* this event is synthetic as the pointer might have not left the window.
|
||||
* @GDK_CROSSING_DEVICE_SWITCH: crossing because of a device switch (i.e.
|
||||
* a mouse taking control of the pointer after a touch device), this event
|
||||
* is synthetic as the pointer didn't leave the window.
|
||||
*
|
||||
* Specifies the crossing mode for #GdkEventCrossing.
|
||||
*/
|
||||
@@ -364,7 +373,10 @@ typedef enum
|
||||
GDK_CROSSING_UNGRAB,
|
||||
GDK_CROSSING_GTK_GRAB,
|
||||
GDK_CROSSING_GTK_UNGRAB,
|
||||
GDK_CROSSING_STATE_CHANGED
|
||||
GDK_CROSSING_STATE_CHANGED,
|
||||
GDK_CROSSING_TOUCH_PRESS,
|
||||
GDK_CROSSING_TOUCH_RELEASE,
|
||||
GDK_CROSSING_DEVICE_SWITCH
|
||||
} GdkCrossingMode;
|
||||
|
||||
/**
|
||||
|
||||
+96
-14
@@ -8340,9 +8340,11 @@ send_crossing_event (GdkDisplay *display,
|
||||
GdkEvent *event;
|
||||
guint32 window_event_mask, type_event_mask;
|
||||
GdkDeviceGrabInfo *grab;
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
gboolean block_event = FALSE;
|
||||
|
||||
grab = _gdk_display_has_device_grab (display, device, serial);
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
|
||||
if (grab != NULL &&
|
||||
!grab->owner_events)
|
||||
@@ -8355,7 +8357,13 @@ send_crossing_event (GdkDisplay *display,
|
||||
else
|
||||
window_event_mask = window->event_mask;
|
||||
|
||||
if (type == GDK_LEAVE_NOTIFY)
|
||||
if (pointer_info->need_touch_press_enter &&
|
||||
mode != GDK_CROSSING_TOUCH_PRESS &&
|
||||
mode != GDK_CROSSING_TOUCH_RELEASE)
|
||||
{
|
||||
block_event = TRUE;
|
||||
}
|
||||
else if (type == GDK_LEAVE_NOTIFY)
|
||||
{
|
||||
type_event_mask = GDK_LEAVE_NOTIFY_MASK;
|
||||
window->devices_inside = g_list_remove (window->devices_inside, device);
|
||||
@@ -9064,7 +9072,7 @@ do_synthesize_crossing_event (gpointer data)
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
pointer_info->window_under_pointer,
|
||||
new_window_under_pointer,
|
||||
device, NULL,
|
||||
device, pointer_info->last_slave,
|
||||
GDK_CROSSING_NORMAL,
|
||||
pointer_info->toplevel_x,
|
||||
pointer_info->toplevel_y,
|
||||
@@ -9179,7 +9187,7 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
guint state;
|
||||
gdouble toplevel_x, toplevel_y;
|
||||
guint32 time_;
|
||||
gboolean non_linear;
|
||||
gboolean non_linear, need_synthetic_enter = FALSE;
|
||||
|
||||
event_window = source_event->any.window;
|
||||
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
|
||||
@@ -9199,6 +9207,13 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
|
||||
non_linear = TRUE;
|
||||
|
||||
if (pointer_info->need_touch_press_enter &&
|
||||
gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCH)
|
||||
{
|
||||
pointer_info->need_touch_press_enter = FALSE;
|
||||
need_synthetic_enter = TRUE;
|
||||
}
|
||||
|
||||
/* If we get crossing events with subwindow unexpectedly being NULL
|
||||
that means there is a native subwindow that gdk doesn't know about.
|
||||
We track these and forward them, with the correct virtual window
|
||||
@@ -9322,6 +9337,18 @@ proxy_pointer_event (GdkDisplay *display,
|
||||
gdk_window_get_device_events (event_win, device) == 0)
|
||||
return TRUE;
|
||||
|
||||
/* The last device to interact with the window was a touch device,
|
||||
* which synthesized a leave notify event, so synthesize another enter
|
||||
* notify to tell the pointer is on the window.
|
||||
*/
|
||||
if (need_synthetic_enter)
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
NULL, pointer_window,
|
||||
device, source_device,
|
||||
GDK_CROSSING_DEVICE_SWITCH,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, NULL,
|
||||
serial, FALSE);
|
||||
is_hint = FALSE;
|
||||
|
||||
if (event_win &&
|
||||
@@ -9380,6 +9407,7 @@ proxy_button_event (GdkEvent *source_event,
|
||||
GdkWindow *pointer_window;
|
||||
GdkWindow *parent;
|
||||
GdkEvent *event;
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
guint state;
|
||||
guint32 time_;
|
||||
GdkEventType type;
|
||||
@@ -9399,6 +9427,7 @@ proxy_button_event (GdkEvent *source_event,
|
||||
toplevel_window = convert_native_coords_to_toplevel (event_window,
|
||||
toplevel_x, toplevel_y,
|
||||
&toplevel_x, &toplevel_y);
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
|
||||
if (type == GDK_BUTTON_PRESS &&
|
||||
!source_event->any.send_event &&
|
||||
@@ -9451,6 +9480,30 @@ proxy_button_event (GdkEvent *source_event,
|
||||
gdk_window_get_device_events (event_win, device) == 0)
|
||||
return TRUE;
|
||||
|
||||
if (type == GDK_BUTTON_PRESS &&
|
||||
pointer_info->need_touch_press_enter)
|
||||
{
|
||||
GdkCrossingMode mode;
|
||||
|
||||
/* The last device to interact with the window was a touch device,
|
||||
* which synthesized a leave notify event, so synthesize another enter
|
||||
* notify to tell the pointer is on the window.
|
||||
*/
|
||||
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
mode = GDK_CROSSING_TOUCH_PRESS;
|
||||
else
|
||||
mode = GDK_CROSSING_DEVICE_SWITCH;
|
||||
|
||||
pointer_info->need_touch_press_enter = FALSE;
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
NULL,
|
||||
pointer_info->window_under_pointer,
|
||||
device, source_device, mode,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, source_event,
|
||||
serial, FALSE);
|
||||
}
|
||||
|
||||
event = _gdk_make_event (event_win, type, source_event, FALSE);
|
||||
|
||||
switch (type)
|
||||
@@ -9471,7 +9524,23 @@ proxy_button_event (GdkEvent *source_event,
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
if (type == GDK_BUTTON_PRESS)
|
||||
_gdk_event_button_generate (display, event);
|
||||
_gdk_event_button_generate (display, event);
|
||||
else if (type == GDK_BUTTON_RELEASE &&
|
||||
pointer_window == pointer_info->window_under_pointer &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
{
|
||||
/* Synthesize a leave notify event
|
||||
* whenever a touch device is released
|
||||
*/
|
||||
pointer_info->need_touch_press_enter = TRUE;
|
||||
_gdk_synthesize_crossing_events (display,
|
||||
pointer_window, NULL,
|
||||
device, source_device,
|
||||
GDK_CROSSING_TOUCH_RELEASE,
|
||||
toplevel_x, toplevel_y,
|
||||
state, time_, NULL,
|
||||
serial, FALSE);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case GDK_SCROLL:
|
||||
@@ -9590,6 +9659,17 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
{
|
||||
GdkInputMode mode;
|
||||
|
||||
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
||||
{
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
|
||||
if (source_device != pointer_info->last_slave &&
|
||||
gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
|
||||
pointer_info->last_slave = source_device;
|
||||
else
|
||||
source_device = pointer_info->last_slave;
|
||||
}
|
||||
|
||||
g_object_get (device, "input-mode", &mode, NULL);
|
||||
_gdk_display_device_grab_update (display, device, source_device, serial);
|
||||
|
||||
@@ -9608,8 +9688,6 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
if (!event_window)
|
||||
return;
|
||||
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
|
||||
#ifdef DEBUG_WINDOW_PRINTING
|
||||
if (event->type == GDK_KEY_PRESS &&
|
||||
(event->key.keyval == 0xa7 ||
|
||||
@@ -9694,15 +9772,19 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
/* Store last pointer window and position/state */
|
||||
old_state = pointer_info->state;
|
||||
old_button = pointer_info->button;
|
||||
if (pointer_info)
|
||||
{
|
||||
/* Store last pointer window and position/state */
|
||||
old_state = pointer_info->state;
|
||||
old_button = pointer_info->button;
|
||||
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
|
||||
pointer_info->toplevel_x = x;
|
||||
pointer_info->toplevel_y = y;
|
||||
gdk_event_get_state (event, &pointer_info->state);
|
||||
}
|
||||
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
convert_native_coords_to_toplevel (event_window, x, y, &x, &y);
|
||||
pointer_info->toplevel_x = x;
|
||||
pointer_info->toplevel_y = y;
|
||||
gdk_event_get_state (event, &pointer_info->state);
|
||||
if (event->type == GDK_BUTTON_PRESS ||
|
||||
event->type == GDK_BUTTON_RELEASE)
|
||||
pointer_info->button = event->button.button;
|
||||
|
||||
@@ -742,7 +742,7 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
|
||||
{
|
||||
gint group;
|
||||
|
||||
group = group_state->base + group_state->latched + group_state->locked;
|
||||
group = group_state->base | group_state->latched | group_state->locked;
|
||||
|
||||
/* FIXME: do we need the XKB complications for this ? */
|
||||
group = CLAMP(group, 0, 3);
|
||||
|
||||
@@ -254,6 +254,10 @@ create_device (GdkDeviceManager *device_manager,
|
||||
input_source = GDK_SOURCE_ERASER;
|
||||
else if (strstr (tmp_name, "cursor"))
|
||||
input_source = GDK_SOURCE_CURSOR;
|
||||
else if (strstr (tmp_name, "finger") ||
|
||||
(strstr (tmp_name, "touch") &&
|
||||
!strstr (tmp_name, "touchpad")))
|
||||
input_source = GDK_SOURCE_TOUCH;
|
||||
else if (strstr (tmp_name, "wacom") ||
|
||||
strstr (tmp_name, "pen"))
|
||||
input_source = GDK_SOURCE_PEN;
|
||||
|
||||
@@ -1579,9 +1579,12 @@ device_grab_update_callback (GdkDisplay *display,
|
||||
gpointer data,
|
||||
gulong serial)
|
||||
{
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
GdkDevice *device = data;
|
||||
|
||||
_gdk_display_device_grab_update (display, device, NULL, serial);
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
_gdk_display_device_grab_update (display, device,
|
||||
pointer_info->last_slave, serial);
|
||||
}
|
||||
|
||||
#define XSERVER_TIME_IS_LATER(time1, time2) \
|
||||
|
||||
@@ -3057,6 +3057,12 @@ gtk_css_provider_get_default (void)
|
||||
" border-width: 0;\n"
|
||||
" padding: 2;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
".press-and-hold {\n"
|
||||
" background-color: alpha (@bg_color, 0.5);\n"
|
||||
" color: alpha (lighter (@selected_bg_color), 0.8);\n"
|
||||
" border-width: 10;\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
|
||||
+76
-26
@@ -147,6 +147,8 @@ struct _GtkEntryPrivate
|
||||
GtkShadowType shadow_type;
|
||||
GtkWidget *popup_menu;
|
||||
|
||||
GdkDevice *device;
|
||||
|
||||
GdkDevice *completion_device;
|
||||
GdkWindow *text_area;
|
||||
|
||||
@@ -482,6 +484,11 @@ static void gtk_entry_toggle_overwrite (GtkEntry *entry);
|
||||
static void gtk_entry_select_all (GtkEntry *entry);
|
||||
static void gtk_entry_real_activate (GtkEntry *entry);
|
||||
static gboolean gtk_entry_popup_menu (GtkWidget *widget);
|
||||
static gboolean gtk_entry_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
static void keymap_direction_changed (GdkKeymap *keymap,
|
||||
GtkEntry *entry);
|
||||
@@ -545,9 +552,13 @@ static void gtk_entry_paste (GtkEntry *entry,
|
||||
GdkAtom selection);
|
||||
static void gtk_entry_update_primary_selection (GtkEntry *entry);
|
||||
static void gtk_entry_do_popup (GtkEntry *entry,
|
||||
GdkEventButton *event);
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button);
|
||||
static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget,
|
||||
gboolean group_cycling);
|
||||
static void gtk_entry_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static void gtk_entry_check_cursor_blink (GtkEntry *entry);
|
||||
static void gtk_entry_pend_cursor_blink (GtkEntry *entry);
|
||||
static void gtk_entry_reset_blink_time (GtkEntry *entry);
|
||||
@@ -692,6 +703,7 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
widget_class->state_flags_changed = gtk_entry_state_flags_changed;
|
||||
widget_class->screen_changed = gtk_entry_screen_changed;
|
||||
widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
|
||||
widget_class->grab_notify = gtk_entry_grab_notify;
|
||||
|
||||
widget_class->drag_drop = gtk_entry_drag_drop;
|
||||
widget_class->drag_motion = gtk_entry_drag_motion;
|
||||
@@ -701,6 +713,7 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
widget_class->drag_data_delete = gtk_entry_drag_data_delete;
|
||||
|
||||
widget_class->popup_menu = gtk_entry_popup_menu;
|
||||
widget_class->press_and_hold = gtk_entry_press_and_hold;
|
||||
|
||||
class->move_cursor = gtk_entry_move_cursor;
|
||||
class->insert_at_cursor = gtk_entry_insert_at_cursor;
|
||||
@@ -3771,7 +3784,8 @@ gtk_entry_button_press (GtkWidget *widget,
|
||||
gtk_entry_reset_blink_time (entry);
|
||||
|
||||
priv->button = event->button;
|
||||
|
||||
priv->device = gdk_event_get_device ((GdkEvent *) event);
|
||||
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
{
|
||||
priv->in_click = TRUE;
|
||||
@@ -3783,8 +3797,10 @@ gtk_entry_button_press (GtkWidget *widget,
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
gtk_entry_do_popup (entry, event);
|
||||
gtk_entry_do_popup (entry, event->device,
|
||||
event->time, event->button);
|
||||
priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
|
||||
priv->device = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -3962,9 +3978,10 @@ gtk_entry_button_release (GtkWidget *widget,
|
||||
|
||||
priv->in_drag = 0;
|
||||
}
|
||||
|
||||
|
||||
priv->button = 0;
|
||||
|
||||
priv->device = NULL;
|
||||
|
||||
gtk_entry_update_primary_selection (entry);
|
||||
|
||||
return TRUE;
|
||||
@@ -4073,7 +4090,8 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
|
||||
priv->in_drag = FALSE;
|
||||
priv->button = 0;
|
||||
|
||||
priv->device = NULL;
|
||||
|
||||
gtk_target_list_unref (target_list);
|
||||
}
|
||||
}
|
||||
@@ -8542,6 +8560,26 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_entry_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkEntryPrivate *priv;
|
||||
|
||||
priv = GTK_ENTRY (widget)->priv;
|
||||
|
||||
if (priv->device &&
|
||||
gtk_widget_device_is_shadowed (widget, priv->device))
|
||||
{
|
||||
/* Unset button so we don't expect
|
||||
* a button release anymore
|
||||
*/
|
||||
priv->button = 0;
|
||||
priv->device = NULL;
|
||||
priv->in_drag = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
append_action_signal (GtkEntry *entry,
|
||||
GtkWidget *menu,
|
||||
@@ -8744,15 +8782,17 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
info_entry_priv->popup_menu);
|
||||
|
||||
|
||||
if (info->device)
|
||||
if (gdk_device_get_source (info->device) != GDK_SOURCE_KEYBOARD)
|
||||
gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu),
|
||||
info->device, NULL, NULL, NULL, NULL, NULL,
|
||||
info->button, info->time);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL,
|
||||
popup_position_func, entry,
|
||||
0, gtk_get_current_event_time ());
|
||||
gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu),
|
||||
info->device, NULL, NULL,
|
||||
popup_position_func,
|
||||
entry, NULL,
|
||||
0, info->time);
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (info_entry_priv->popup_menu), FALSE);
|
||||
}
|
||||
}
|
||||
@@ -8760,10 +8800,12 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
g_object_unref (entry);
|
||||
g_slice_free (PopupInfo, info);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_entry_do_popup (GtkEntry *entry,
|
||||
GdkEventButton *event)
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button)
|
||||
{
|
||||
PopupInfo *info = g_slice_new (PopupInfo);
|
||||
|
||||
@@ -8772,19 +8814,10 @@ gtk_entry_do_popup (GtkEntry *entry,
|
||||
* we get them, then we actually pop up the menu.
|
||||
*/
|
||||
info->entry = g_object_ref (entry);
|
||||
|
||||
if (event)
|
||||
{
|
||||
info->button = event->button;
|
||||
info->time = event->time;
|
||||
info->device = event->device;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->button = 0;
|
||||
info->time = gtk_get_current_event_time ();
|
||||
info->device = NULL;
|
||||
}
|
||||
|
||||
info->button = button;
|
||||
info->time = _time;
|
||||
info->device = device;
|
||||
|
||||
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
|
||||
gdk_atom_intern_static_string ("TARGETS"),
|
||||
@@ -8795,7 +8828,24 @@ gtk_entry_do_popup (GtkEntry *entry,
|
||||
static gboolean
|
||||
gtk_entry_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_entry_do_popup (GTK_ENTRY (widget), NULL);
|
||||
gtk_entry_do_popup (GTK_ENTRY (widget),
|
||||
gtk_get_current_event_device (),
|
||||
gtk_get_current_event_time (),
|
||||
0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_entry_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
|
||||
gtk_entry_do_popup (GTK_ENTRY (widget),
|
||||
device, GDK_CURRENT_TIME, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -920,6 +920,33 @@ typedef enum {
|
||||
GTK_BORDER_STYLE_OUTSET
|
||||
} GtkBorderStyle;
|
||||
|
||||
typedef enum {
|
||||
GTK_CAPTURED_EVENT_NONE = 0,
|
||||
GTK_CAPTURED_EVENT_HANDLED = 1 << 0,
|
||||
GTK_CAPTURED_EVENT_STORE = 1 << 1
|
||||
} GtkCapturedEventFlags;
|
||||
|
||||
/**
|
||||
* GtkKineticScrollingFlags:
|
||||
* @GTK_KINETIC_SCROLLING_NONE: No kinetic scrolling.
|
||||
* @GTK_KINETIC_SCROLLING_ENABLED: Kinetic scrolling is enabled.
|
||||
* @GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS: The first button
|
||||
* press is captured by the scrolled window, and then replayed
|
||||
* if the button press is meant to go to the child widget. This
|
||||
* flag should be enabled if the child widget(s) perform
|
||||
* non-reversible actions on #GtkWidget::button-press-event.
|
||||
* If the widget does not do so, and handles
|
||||
* #GtkWidget::grab-broken-event, it might be better off without
|
||||
* this flag.
|
||||
*
|
||||
* Describes the kinetic scrolling behavior of a #GtkScrolledWindow
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_KINETIC_SCROLLING_NONE = 0,
|
||||
GTK_KINETIC_SCROLLING_ENABLED = 1 << 0,
|
||||
GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS = 1 << 1
|
||||
} GtkKineticScrollingFlags;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
|
||||
+45
-13
@@ -439,6 +439,11 @@ static void gtk_label_hierarchy_changed (GtkWidget *widget,
|
||||
static void gtk_label_screen_changed (GtkWidget *widget,
|
||||
GdkScreen *old_screen);
|
||||
static gboolean gtk_label_popup_menu (GtkWidget *widget);
|
||||
static gboolean gtk_label_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
static void gtk_label_create_window (GtkLabel *label);
|
||||
static void gtk_label_destroy_window (GtkLabel *label);
|
||||
@@ -492,7 +497,9 @@ static void gtk_label_move_cursor (GtkLabel *label,
|
||||
static void gtk_label_copy_clipboard (GtkLabel *label);
|
||||
static void gtk_label_select_all (GtkLabel *label);
|
||||
static void gtk_label_do_popup (GtkLabel *label,
|
||||
GdkEventButton *event);
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button);
|
||||
static gint gtk_label_move_forward_word (GtkLabel *label,
|
||||
gint start);
|
||||
static gint gtk_label_move_backward_word (GtkLabel *label,
|
||||
@@ -588,6 +595,7 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
widget_class->drag_data_get = gtk_label_drag_data_get;
|
||||
widget_class->grab_focus = gtk_label_grab_focus;
|
||||
widget_class->popup_menu = gtk_label_popup_menu;
|
||||
widget_class->press_and_hold = gtk_label_press_and_hold;
|
||||
widget_class->focus = gtk_label_focus;
|
||||
widget_class->get_request_mode = gtk_label_get_request_mode;
|
||||
widget_class->get_preferred_width = gtk_label_get_preferred_width;
|
||||
@@ -4625,7 +4633,8 @@ gtk_label_button_press (GtkWidget *widget,
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
info->link_clicked = 1;
|
||||
gtk_label_do_popup (label, event);
|
||||
gtk_label_do_popup (label, event->device,
|
||||
event->time, event->button);
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->button == 1)
|
||||
@@ -4643,7 +4652,8 @@ gtk_label_button_press (GtkWidget *widget,
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
gtk_label_do_popup (label, event);
|
||||
gtk_label_do_popup (label, event->device,
|
||||
event->time, event->button);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -4908,6 +4918,8 @@ gtk_label_motion (GtkWidget *widget,
|
||||
if ((event->state & GDK_BUTTON1_MASK) == 0)
|
||||
return FALSE;
|
||||
|
||||
gdk_event_request_motions (event);
|
||||
|
||||
if (info->in_drag)
|
||||
{
|
||||
if (gtk_drag_check_threshold (widget,
|
||||
@@ -6157,14 +6169,32 @@ copy_link_activate_cb (GtkMenuItem *menu_item,
|
||||
static gboolean
|
||||
gtk_label_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_label_do_popup (GTK_LABEL (widget), NULL);
|
||||
gtk_label_do_popup (GTK_LABEL (widget),
|
||||
gtk_get_current_event_device (),
|
||||
gtk_get_current_event_time (),
|
||||
0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_label_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
|
||||
gtk_label_do_popup (GTK_LABEL (widget),
|
||||
device, GDK_CURRENT_TIME, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_do_popup (GtkLabel *label,
|
||||
GdkEventButton *event)
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button)
|
||||
{
|
||||
GtkLabelPrivate *priv = label->priv;
|
||||
GtkWidget *menuitem;
|
||||
@@ -6186,7 +6216,7 @@ gtk_label_do_popup (GtkLabel *label,
|
||||
have_selection =
|
||||
priv->select_info->selection_anchor != priv->select_info->selection_end;
|
||||
|
||||
if (event)
|
||||
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
||||
{
|
||||
if (priv->select_info->link_clicked)
|
||||
link = priv->select_info->active_link;
|
||||
@@ -6246,15 +6276,17 @@ gtk_label_do_popup (GtkLabel *label,
|
||||
|
||||
g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
|
||||
|
||||
if (event)
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
||||
NULL, NULL,
|
||||
event->button, event->time);
|
||||
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
||||
gtk_menu_popup_for_device (GTK_MENU (menu), device,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
button, _time);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
||||
popup_position_func, label,
|
||||
0, gtk_get_current_event_time ());
|
||||
gtk_menu_popup_for_device (GTK_MENU (menu),
|
||||
device, NULL, NULL,
|
||||
popup_position_func,
|
||||
label, NULL,
|
||||
0, _time);
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
+187
-83
@@ -129,6 +129,9 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkwindowprivate.h"
|
||||
|
||||
static gboolean gtk_propagate_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost);
|
||||
|
||||
/* Private type definitions
|
||||
*/
|
||||
@@ -1469,6 +1472,7 @@ gtk_main_do_event (GdkEvent *event)
|
||||
{
|
||||
GtkWidget *event_widget;
|
||||
GtkWidget *grab_widget = NULL;
|
||||
GtkWidget *topmost_widget = NULL;
|
||||
GtkWindowGroup *window_group;
|
||||
GdkEvent *rewritten_event = NULL;
|
||||
GdkDevice *device;
|
||||
@@ -1528,6 +1532,14 @@ gtk_main_do_event (GdkEvent *event)
|
||||
if (!grab_widget)
|
||||
grab_widget = gtk_window_group_get_current_grab (window_group);
|
||||
|
||||
/* Find out the topmost widget where captured event propagation
|
||||
* should start, which is the widget holding the GTK+ grab
|
||||
* if any, otherwise it's left NULL and events are emitted
|
||||
* from the toplevel (or topmost parentless parent).
|
||||
*/
|
||||
if (grab_widget)
|
||||
topmost_widget = grab_widget;
|
||||
|
||||
/* If the grab widget is an ancestor of the event widget
|
||||
* then we send the event to the original event widget.
|
||||
* This is the key to implementing modality.
|
||||
@@ -1624,14 +1636,26 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_WINDOW_STATE:
|
||||
case GDK_GRAB_BROKEN:
|
||||
case GDK_DAMAGE:
|
||||
gtk_widget_event (event_widget, event);
|
||||
if (!_gtk_widget_captured_event (event_widget, event))
|
||||
gtk_widget_event (event_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_SCROLL:
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
if ((event->type == GDK_BUTTON_PRESS) &&
|
||||
event->button.button == 1)
|
||||
{
|
||||
/* Handle press and hold on the grab widget before propagating up,
|
||||
* so a parent capturing events doesn't delay nor prevent a child
|
||||
* from doing the press-and-hold action.
|
||||
*/
|
||||
_gtk_widget_press_and_hold_check_start (grab_widget, &event->button);
|
||||
}
|
||||
|
||||
if (!gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_KEY_PRESS:
|
||||
@@ -1683,22 +1707,36 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_PROXIMITY_IN:
|
||||
case GDK_PROXIMITY_OUT:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
if ((event->type == GDK_BUTTON_RELEASE) &&
|
||||
event->button.button == 1)
|
||||
_gtk_widget_press_and_hold_check_cancel (grab_widget, &event->button);
|
||||
else if (event->type == GDK_MOTION_NOTIFY)
|
||||
_gtk_widget_press_and_hold_check_threshold (grab_widget,
|
||||
&event->motion);
|
||||
|
||||
if (!gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
event->any.window);
|
||||
if (gtk_widget_is_sensitive (grab_widget))
|
||||
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
|
||||
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
event->any.window);
|
||||
if (gtk_widget_is_sensitive (grab_widget) &&
|
||||
!gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
NULL);
|
||||
if (gtk_widget_is_sensitive (grab_widget))
|
||||
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
|
||||
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
NULL);
|
||||
if (gtk_widget_is_sensitive (grab_widget) &&
|
||||
!gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
@@ -2320,6 +2358,135 @@ gtk_get_event_widget (GdkEvent *event)
|
||||
return widget;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event_up (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gboolean handled_event = FALSE;
|
||||
|
||||
/* Propagate event up the widget tree so that
|
||||
* parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
while (TRUE)
|
||||
{
|
||||
GtkWidget *tmp;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = event->type != GDK_SCROLL;
|
||||
else
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
tmp = gtk_widget_get_parent (widget);
|
||||
g_object_unref (widget);
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
|
||||
widget = tmp;
|
||||
|
||||
if (handled_event || !widget)
|
||||
break;
|
||||
}
|
||||
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event_down (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gint handled_event = FALSE;
|
||||
GList *widgets = NULL;
|
||||
GList *l;
|
||||
|
||||
widgets = g_list_prepend (widgets, g_object_ref (widget));
|
||||
while (widget && widget != topmost)
|
||||
{
|
||||
widget = gtk_widget_get_parent (widget);
|
||||
if (!widget)
|
||||
break;
|
||||
|
||||
widgets = g_list_prepend (widgets, g_object_ref (widget));
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
}
|
||||
|
||||
for (l = widgets; l && !handled_event; l = g_list_next (l))
|
||||
{
|
||||
widget = (GtkWidget *)l->data;
|
||||
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = TRUE;
|
||||
else
|
||||
handled_event = _gtk_widget_captured_event (widget, event);
|
||||
}
|
||||
g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
|
||||
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gboolean captured,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gboolean handled_event = FALSE;
|
||||
gboolean (* propagate_func) (GtkWidget *widget, GdkEvent *event);
|
||||
|
||||
propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event;
|
||||
|
||||
if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
|
||||
{
|
||||
/* Only send key events within Window widgets to the Window
|
||||
* The Window widget will in turn pass the
|
||||
* key event on to the currently focused widget
|
||||
* for that window.
|
||||
*/
|
||||
GtkWidget *window;
|
||||
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
g_object_ref (widget);
|
||||
/* If there is a grab within the window, give the grab widget
|
||||
* a first crack at the key event
|
||||
*/
|
||||
if (widget != window && gtk_widget_has_grab (widget))
|
||||
handled_event = propagate_func (widget, event);
|
||||
|
||||
if (!handled_event)
|
||||
{
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
if (gtk_widget_is_sensitive (window))
|
||||
handled_event = propagate_func (window, event);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (widget);
|
||||
return handled_event;
|
||||
}
|
||||
}
|
||||
|
||||
/* Other events get propagated up/down the widget tree */
|
||||
return captured ?
|
||||
propagate_event_down (widget, event, topmost) :
|
||||
propagate_event_up (widget, event, topmost);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_propagate_event:
|
||||
* @widget: a #GtkWidget
|
||||
@@ -2348,79 +2515,16 @@ void
|
||||
gtk_propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
gint handled_event;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (event != NULL);
|
||||
|
||||
handled_event = FALSE;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
if ((event->type == GDK_KEY_PRESS) ||
|
||||
(event->type == GDK_KEY_RELEASE))
|
||||
{
|
||||
/* Only send key events within Window widgets to the Window
|
||||
* The Window widget will in turn pass the
|
||||
* key event on to the currently focused widget
|
||||
* for that window.
|
||||
*/
|
||||
GtkWidget *window;
|
||||
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
/* If there is a grab within the window, give the grab widget
|
||||
* a first crack at the key event
|
||||
*/
|
||||
if (widget != window && gtk_widget_has_grab (widget))
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
if (!handled_event)
|
||||
{
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
if (gtk_widget_is_sensitive (window))
|
||||
gtk_widget_event (window, event);
|
||||
}
|
||||
}
|
||||
|
||||
handled_event = TRUE; /* don't send to widget */
|
||||
}
|
||||
}
|
||||
|
||||
/* Other events get propagated up the widget tree
|
||||
* so that parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
if (!handled_event)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
GtkWidget *tmp;
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = event->type != GDK_SCROLL;
|
||||
else
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
tmp = gtk_widget_get_parent (widget);
|
||||
g_object_unref (widget);
|
||||
|
||||
widget = tmp;
|
||||
|
||||
if (!handled_event && widget)
|
||||
g_object_ref (widget);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_object_unref (widget);
|
||||
propagate_event (widget, event, FALSE, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_propagate_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
return propagate_event (widget, event, TRUE, topmost);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ BOOLEAN:OBJECT,BOXED,BOXED
|
||||
BOOLEAN:OBJECT,OBJECT,OBJECT
|
||||
BOOLEAN:OBJECT,STRING,STRING
|
||||
BOOLEAN:OBJECT,ENUM
|
||||
BOOLEAN:OBJECT,ENUM,INT,INT
|
||||
BOOLEAN:INT
|
||||
BOOLEAN:INT,INT
|
||||
BOOLEAN:INT,INT,INT
|
||||
@@ -47,6 +48,7 @@ BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
|
||||
BOOLEAN:STRING
|
||||
ENUM:ENUM
|
||||
ENUM:VOID
|
||||
FLAGS:BOXED
|
||||
INT:POINTER
|
||||
OBJECT:VOID
|
||||
STRING:DOUBLE
|
||||
|
||||
+230
-276
@@ -110,6 +110,7 @@
|
||||
#include "gtksettings.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
@@ -227,12 +228,14 @@ static void gtk_menu_scroll_to (GtkMenu *menu,
|
||||
gint offset);
|
||||
static void gtk_menu_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static GtkCapturedEventFlags
|
||||
gtk_menu_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
|
||||
static void gtk_menu_stop_scrolling (GtkMenu *menu);
|
||||
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
|
||||
static gboolean gtk_menu_scroll_timeout (gpointer data);
|
||||
static gboolean gtk_menu_scroll_timeout_initial (gpointer data);
|
||||
static void gtk_menu_start_scrolling (GtkMenu *menu);
|
||||
|
||||
static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
|
||||
GtkWidget *menu_item);
|
||||
@@ -510,6 +513,7 @@ gtk_menu_class_init (GtkMenuClass *class)
|
||||
widget_class->get_preferred_width = gtk_menu_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_menu_get_preferred_height;
|
||||
widget_class->get_preferred_height_for_width = gtk_menu_get_preferred_height_for_width;
|
||||
widget_class->captured_event = gtk_menu_captured_event;
|
||||
|
||||
container_class->remove = gtk_menu_remove;
|
||||
container_class->get_child_property = gtk_menu_get_child_property;
|
||||
@@ -1057,6 +1061,7 @@ gtk_menu_init (GtkMenu *menu)
|
||||
priv->needs_destruction_ref = TRUE;
|
||||
|
||||
priv->monitor_num = -1;
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (menu));
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU);
|
||||
@@ -1462,7 +1467,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
GtkMenuShell *menu_shell;
|
||||
gboolean grab_keyboard;
|
||||
GtkWidget *parent_toplevel;
|
||||
GdkDevice *keyboard, *pointer;
|
||||
GdkDevice *keyboard, *pointer, *source_device = NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_MENU (menu));
|
||||
g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
|
||||
@@ -1599,6 +1604,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
(current_event->type != GDK_ENTER_NOTIFY))
|
||||
menu_shell->priv->ignore_enter = TRUE;
|
||||
|
||||
source_device = gdk_event_get_source_device (current_event);
|
||||
gdk_event_free (current_event);
|
||||
}
|
||||
else
|
||||
@@ -1668,17 +1674,9 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
gtk_menu_scroll_to (menu, priv->scroll_offset);
|
||||
|
||||
/* if no item is selected, select the first one */
|
||||
if (!menu_shell->priv->active_menu_item)
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (touchscreen_mode)
|
||||
gtk_menu_shell_select_first (menu_shell, TRUE);
|
||||
}
|
||||
if (!menu_shell->priv->active_menu_item &&
|
||||
source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
gtk_menu_shell_select_first (menu_shell, TRUE);
|
||||
|
||||
/* Once everything is set up correctly, map the toplevel */
|
||||
gtk_widget_show (priv->toplevel);
|
||||
@@ -3313,34 +3311,6 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
|
||||
g_free (nat_heights);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_menu_button_scroll (GtkMenu *menu,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
|
||||
if (priv->upper_arrow_prelight || priv->lower_arrow_prelight)
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (touchscreen_mode)
|
||||
gtk_menu_handle_scrolling (menu,
|
||||
event->x_root, event->y_root,
|
||||
event->type == GDK_BUTTON_PRESS,
|
||||
FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_in_menu_window (GtkWidget *widget,
|
||||
gdouble x_root,
|
||||
@@ -3377,13 +3347,16 @@ static gboolean
|
||||
gtk_menu_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GtkWidget *event_widget;
|
||||
GtkMenu *menu;
|
||||
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
|
||||
/* Don't pass down to menu shell for presses over scroll arrows
|
||||
*/
|
||||
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
|
||||
return TRUE;
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
event_widget = gtk_get_event_widget ((GdkEvent *) event);
|
||||
menu = GTK_MENU (widget);
|
||||
|
||||
/* Don't pass down to menu shell if a non-menuitem part of the menu
|
||||
* was clicked. The check for the event_widget being a GtkMenuShell
|
||||
@@ -3392,10 +3365,16 @@ gtk_menu_button_press (GtkWidget *widget,
|
||||
* the menu or on its border are delivered relative to
|
||||
* menu_shell->window.
|
||||
*/
|
||||
if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
|
||||
if (GTK_IS_MENU_SHELL (event_widget) &&
|
||||
pointer_in_menu_window (widget, event->x_root, event->y_root))
|
||||
return TRUE;
|
||||
|
||||
if (GTK_IS_MENU_ITEM (event_widget) &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH &&
|
||||
GTK_MENU_ITEM (event_widget)->priv->submenu != NULL &&
|
||||
!gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu))
|
||||
menu->priv->ignore_button_release = TRUE;
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
|
||||
}
|
||||
|
||||
@@ -3414,11 +3393,6 @@ gtk_menu_button_release (GtkWidget *widget,
|
||||
if (event->type != GDK_BUTTON_RELEASE)
|
||||
return FALSE;
|
||||
|
||||
/* Don't pass down to menu shell for releases over scroll arrows
|
||||
*/
|
||||
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
|
||||
return TRUE;
|
||||
|
||||
/* Don't pass down to menu shell if a non-menuitem part of the menu
|
||||
* was clicked (see comment in button_press()).
|
||||
*/
|
||||
@@ -3662,10 +3636,14 @@ gtk_menu_motion_notify (GtkWidget *widget,
|
||||
GtkMenu *menu;
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkWidget *parent;
|
||||
GdkDevice *source_device;
|
||||
|
||||
gboolean need_enter;
|
||||
|
||||
if (GTK_IS_MENU (widget))
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (GTK_IS_MENU (widget) &&
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
{
|
||||
GtkMenuPrivate *priv = GTK_MENU(widget)->priv;
|
||||
|
||||
@@ -3829,90 +3807,17 @@ gtk_menu_scroll_by (GtkMenu *menu,
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_do_timeout_scroll (GtkMenu *menu,
|
||||
gboolean touchscreen_mode)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
gboolean upper_visible;
|
||||
gboolean lower_visible;
|
||||
|
||||
upper_visible = priv->upper_arrow_visible;
|
||||
lower_visible = priv->lower_arrow_visible;
|
||||
|
||||
gtk_menu_scroll_by (menu, priv->scroll_step);
|
||||
|
||||
if (touchscreen_mode &&
|
||||
(upper_visible != priv->upper_arrow_visible ||
|
||||
lower_visible != priv->lower_arrow_visible))
|
||||
{
|
||||
/* We are about to hide a scroll arrow while the mouse is pressed,
|
||||
* this would cause the uncovered menu item to be activated on button
|
||||
* release. Therefore we need to ignore button release here
|
||||
*/
|
||||
GTK_MENU_SHELL (menu)->priv->ignore_enter = TRUE;
|
||||
priv->ignore_button_release = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll_timeout (gpointer data)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu = GTK_MENU (data);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
gtk_menu_scroll_by (menu, menu->priv->scroll_step);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll_timeout_initial (gpointer data)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
guint timeout;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu = GTK_MENU (data);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-timeout-repeat", &timeout,
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
|
||||
menu->priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_start_scrolling (GtkMenu *menu)
|
||||
{
|
||||
guint timeout;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-timeout-repeat", &timeout,
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
|
||||
menu->priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll (GtkWidget *widget,
|
||||
GdkEventScroll *event)
|
||||
@@ -4036,14 +3941,9 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
gboolean in_arrow;
|
||||
gboolean scroll_fast = FALSE;
|
||||
gint top_x, top_y;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu_shell = GTK_MENU_SHELL (menu);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
|
||||
&top_x, &top_y);
|
||||
x -= top_x;
|
||||
@@ -4061,82 +3961,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
in_arrow = TRUE;
|
||||
}
|
||||
|
||||
if (touchscreen_mode)
|
||||
priv->upper_arrow_prelight = in_arrow;
|
||||
|
||||
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
{
|
||||
gboolean arrow_pressed = FALSE;
|
||||
|
||||
if (priv->upper_arrow_visible && !priv->tearoff_active)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->upper_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
if (enter && priv->upper_arrow_prelight)
|
||||
{
|
||||
if (priv->scroll_timeout == 0)
|
||||
{
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
priv->upper_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
/* Only do stuff on click. */
|
||||
gtk_menu_start_scrolling (menu);
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (!enter)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? -MENU_SCROLL_STEP2
|
||||
: -MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else /* !touchscreen_mode */
|
||||
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
|
||||
{
|
||||
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->upper_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
priv->upper_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? -MENU_SCROLL_STEP2
|
||||
: -MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtk_menu_start_scrolling() might have hit the top of the
|
||||
* menu, so check if the button isn't insensitive before
|
||||
/* check if the button isn't insensitive before
|
||||
* changing it to something else.
|
||||
*/
|
||||
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
@@ -4171,82 +4033,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
in_arrow = TRUE;
|
||||
}
|
||||
|
||||
if (touchscreen_mode)
|
||||
priv->lower_arrow_prelight = in_arrow;
|
||||
|
||||
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
{
|
||||
gboolean arrow_pressed = FALSE;
|
||||
|
||||
if (priv->lower_arrow_visible && !priv->tearoff_active)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->lower_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
if (enter && priv->lower_arrow_prelight)
|
||||
{
|
||||
if (priv->scroll_timeout == 0)
|
||||
{
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
priv->lower_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = MENU_SCROLL_STEP2; /* always fast */
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
/* Only do stuff on click. */
|
||||
gtk_menu_start_scrolling (menu);
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (!enter)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? MENU_SCROLL_STEP2
|
||||
: MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else /* !touchscreen_mode */
|
||||
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
|
||||
{
|
||||
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->lower_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
priv->lower_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? MENU_SCROLL_STEP2
|
||||
: MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtk_menu_start_scrolling() might have hit the bottom of the
|
||||
* menu, so check if the button isn't insensitive before
|
||||
/* check if the button isn't insensitive before
|
||||
* changing it to something else.
|
||||
*/
|
||||
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
@@ -4276,19 +4100,18 @@ gtk_menu_enter_notify (GtkWidget *widget,
|
||||
{
|
||||
GtkWidget *menu_item;
|
||||
GtkWidget *parent;
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device;
|
||||
|
||||
if (event->mode == GDK_CROSSING_GTK_GRAB ||
|
||||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
|
||||
event->mode == GDK_CROSSING_STATE_CHANGED)
|
||||
return TRUE;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
menu_item = gtk_get_event_widget ((GdkEvent*) event);
|
||||
if (GTK_IS_MENU (widget))
|
||||
|
||||
if (GTK_IS_MENU (widget) &&
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
{
|
||||
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
|
||||
|
||||
@@ -4297,7 +4120,8 @@ gtk_menu_enter_notify (GtkWidget *widget,
|
||||
event->x_root, event->y_root, TRUE, TRUE);
|
||||
}
|
||||
|
||||
if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item))
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH &&
|
||||
GTK_IS_MENU_ITEM (menu_item))
|
||||
{
|
||||
GtkWidget *menu = gtk_widget_get_parent (menu_item);
|
||||
|
||||
@@ -4354,6 +4178,7 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
GtkMenu *menu;
|
||||
GtkMenuItem *menu_item;
|
||||
GtkWidget *event_widget;
|
||||
GdkDevice *source_device;
|
||||
|
||||
if (event->mode == GDK_CROSSING_GTK_GRAB ||
|
||||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
|
||||
@@ -4366,7 +4191,10 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
|
||||
return TRUE;
|
||||
|
||||
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
||||
|
||||
event_widget = gtk_get_event_widget ((GdkEvent*) event);
|
||||
|
||||
@@ -4401,6 +4229,138 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_on_menu_widget (GtkMenu *menu,
|
||||
gdouble x_root,
|
||||
gdouble y_root)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
GtkAllocation allocation;
|
||||
gint window_x, window_y;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation);
|
||||
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
|
||||
&window_x, &window_y);
|
||||
|
||||
if (x_root >= window_x && x_root < window_x + allocation.width &&
|
||||
y_root >= window_y && y_root < window_y + allocation.height)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkCapturedEventFlags
|
||||
gtk_menu_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GtkCapturedEventFlags flags;
|
||||
GtkMenuPrivate *priv;
|
||||
GtkMenu *menu;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
priv = menu->priv;
|
||||
flags = GTK_CAPTURED_EVENT_NONE;
|
||||
|
||||
if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
|
||||
return flags;
|
||||
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
if (event->button.button == 1 &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH &&
|
||||
pointer_on_menu_widget (menu, event->button.x_root, event->button.y_root))
|
||||
{
|
||||
priv->drag_start_y = event->button.y_root;
|
||||
priv->initial_drag_offset = priv->scroll_offset;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
else
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
priv->drag_already_pressed = TRUE;
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (priv->drag_scroll_started)
|
||||
{
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
priv->drag_start_y = -1;
|
||||
priv->drag_already_pressed = FALSE;
|
||||
}
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (event->motion.state & GDK_BUTTON1_MASK &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
{
|
||||
if (!priv->drag_already_pressed)
|
||||
{
|
||||
if (pointer_on_menu_widget (menu,
|
||||
event->motion.x_root,
|
||||
event->motion.y_root))
|
||||
{
|
||||
priv->drag_start_y = event->motion.y_root;
|
||||
priv->initial_drag_offset = priv->scroll_offset;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
else
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
priv->drag_already_pressed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->drag_start_y < 0 &&
|
||||
!priv->drag_scroll_started)
|
||||
break;
|
||||
|
||||
if (priv->drag_scroll_started)
|
||||
{
|
||||
gint offset, view_height;
|
||||
GtkBorder arrow_border;
|
||||
gdouble y_diff;
|
||||
|
||||
y_diff = event->motion.y_root - priv->drag_start_y;
|
||||
offset = priv->initial_drag_offset - y_diff;
|
||||
|
||||
view_height = gdk_window_get_height (gtk_widget_get_window (widget));
|
||||
get_arrows_border (menu, &arrow_border);
|
||||
|
||||
if (priv->upper_arrow_visible)
|
||||
view_height -= arrow_border.top;
|
||||
|
||||
if (priv->lower_arrow_visible)
|
||||
view_height -= arrow_border.bottom;
|
||||
|
||||
offset = CLAMP (offset, 0, priv->requested_height - view_height);
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
}
|
||||
else if (gtk_drag_check_threshold (widget,
|
||||
0, priv->drag_start_y,
|
||||
0, event->motion.y_root))
|
||||
{
|
||||
priv->drag_scroll_started = TRUE;
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (priv->drag_scroll_started)
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_stop_navigating_submenu (GtkMenu *menu)
|
||||
{
|
||||
@@ -4844,19 +4804,10 @@ static void
|
||||
gtk_menu_stop_scrolling (GtkMenu *menu)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (!touchscreen_mode)
|
||||
{
|
||||
priv->upper_arrow_prelight = FALSE;
|
||||
priv->lower_arrow_prelight = FALSE;
|
||||
}
|
||||
priv->upper_arrow_prelight = FALSE;
|
||||
priv->lower_arrow_prelight = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -5662,7 +5613,6 @@ gtk_menu_real_move_scroll (GtkMenu *menu,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_menu_set_monitor:
|
||||
* @menu: a #GtkMenu
|
||||
@@ -5739,11 +5689,13 @@ static void
|
||||
gtk_menu_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
GtkWidget *toplevel;
|
||||
GtkWindowGroup *group;
|
||||
GtkWidget *grab;
|
||||
GdkDevice *pointer;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget));
|
||||
|
||||
if (!pointer ||
|
||||
@@ -5760,6 +5712,8 @@ gtk_menu_grab_notify (GtkWidget *widget,
|
||||
|
||||
if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab))
|
||||
gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
|
||||
|
||||
menu->priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-5
@@ -1690,13 +1690,20 @@ static void
|
||||
gtk_real_menu_item_select (GtkMenuItem *menu_item)
|
||||
{
|
||||
GtkMenuItemPrivate *priv = menu_item->priv;
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device = NULL;
|
||||
GdkEvent *current_event;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
current_event = gtk_get_current_event ();
|
||||
|
||||
if (!touchscreen_mode && priv->submenu &&
|
||||
if (current_event)
|
||||
{
|
||||
source_device = gdk_event_get_source_device (current_event);
|
||||
gdk_event_free (current_event);
|
||||
}
|
||||
|
||||
if ((!source_device ||
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH) &&
|
||||
priv->submenu &&
|
||||
(!gtk_widget_get_mapped (priv->submenu) ||
|
||||
GTK_MENU (priv->submenu)->priv->tearoff_active))
|
||||
{
|
||||
|
||||
@@ -100,6 +100,8 @@ struct _GtkMenuPrivate
|
||||
guint seen_item_enter : 1;
|
||||
guint ignore_button_release : 1;
|
||||
guint no_toggle_size : 1;
|
||||
guint drag_already_pressed : 1;
|
||||
guint drag_scroll_started : 1;
|
||||
|
||||
/* info used for the table */
|
||||
guint *heights;
|
||||
@@ -126,6 +128,9 @@ struct _GtkMenuPrivate
|
||||
gint navigation_height;
|
||||
|
||||
guint navigation_timeout;
|
||||
|
||||
gdouble drag_start_y;
|
||||
gint initial_drag_offset;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
+4
-32
@@ -1084,13 +1084,11 @@ gtk_menu_shell_enter_notify (GtkWidget *widget,
|
||||
|
||||
if (!gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (touchscreen_mode)
|
||||
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
_gtk_menu_item_popup_submenu (menu_item, TRUE);
|
||||
}
|
||||
}
|
||||
@@ -1612,45 +1610,19 @@ gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell,
|
||||
GtkMenuShellPrivate *priv = menu_shell->priv;
|
||||
GtkMenuShell *parent_menu_shell = NULL;
|
||||
gboolean had_selection;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
priv->in_unselectable_item = FALSE;
|
||||
|
||||
had_selection = priv->active_menu_item != NULL;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (priv->parent_menu_shell)
|
||||
parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_MENU_DIR_PARENT:
|
||||
if (touchscreen_mode &&
|
||||
priv->active_menu_item &&
|
||||
GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
|
||||
gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
|
||||
if (parent_menu_shell)
|
||||
{
|
||||
/* if we are on a menu item that has an open submenu but the
|
||||
* focus is not in that submenu (e.g. because it's empty or
|
||||
* has only insensitive items), close that submenu instead of
|
||||
* running into the code below which would close *this* menu.
|
||||
*/
|
||||
_gtk_menu_item_popdown_submenu (priv->active_menu_item);
|
||||
_gtk_menu_shell_update_mnemonics (menu_shell);
|
||||
}
|
||||
else if (parent_menu_shell)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
{
|
||||
/* close menu when returning from submenu. */
|
||||
_gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
|
||||
_gtk_menu_shell_update_mnemonics (parent_menu_shell);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
|
||||
GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "gdk/gdk.h"
|
||||
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkenums.h"
|
||||
|
||||
|
||||
#if !defined G_OS_WIN32 && !(defined GDK_WINDOWING_QUARTZ && defined QUARTZ_RELOCATION)
|
||||
@@ -159,6 +160,22 @@ _gtk_single_string_accumulator (GSignalInvocationHint *ihint,
|
||||
return continue_emission;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_captured_enum_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer dummy)
|
||||
{
|
||||
gboolean continue_emission;
|
||||
GtkCapturedEventFlags flags;
|
||||
|
||||
flags = g_value_get_flags (handler_return);
|
||||
g_value_set_flags (return_accu, flags);
|
||||
continue_emission = (flags & GTK_CAPTURED_EVENT_HANDLED) == 0;
|
||||
|
||||
return continue_emission;
|
||||
}
|
||||
|
||||
GdkModifierType
|
||||
_gtk_replace_virtual_modifiers (GdkKeymap *keymap,
|
||||
GdkModifierType modifiers)
|
||||
|
||||
@@ -59,6 +59,10 @@ gboolean _gtk_single_string_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer dummy);
|
||||
gboolean _gtk_captured_enum_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer dummy);
|
||||
|
||||
GdkModifierType _gtk_replace_virtual_modifiers (GdkKeymap *keymap,
|
||||
GdkModifierType modifiers);
|
||||
|
||||
+16
-15
@@ -2005,14 +2005,10 @@ gtk_range_draw (GtkWidget *widget,
|
||||
GtkStateFlags state = 0;
|
||||
gint focus_line_width = 0;
|
||||
gint focus_padding = 0;
|
||||
gboolean touchscreen;
|
||||
gboolean draw_trough = TRUE;
|
||||
GtkStyleContext *context;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen,
|
||||
NULL);
|
||||
|
||||
if (GTK_IS_SCALE (widget) &&
|
||||
gtk_adjustment_get_upper (priv->adjustment) == gtk_adjustment_get_lower (priv->adjustment))
|
||||
@@ -2282,7 +2278,7 @@ gtk_range_draw (GtkWidget *widget,
|
||||
|
||||
if (!sensitive)
|
||||
state = GTK_STATE_FLAG_INSENSITIVE;
|
||||
else if (!touchscreen && priv->mouse_location == MOUSE_SLIDER)
|
||||
else if (priv->mouse_location == MOUSE_SLIDER)
|
||||
state = GTK_STATE_FLAG_PRELIGHT;
|
||||
|
||||
if (priv->grab_location == MOUSE_SLIDER)
|
||||
@@ -2314,25 +2310,25 @@ gtk_range_draw (GtkWidget *widget,
|
||||
draw_stepper (range, STEPPER_A, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
|
||||
priv->grab_location == MOUSE_STEPPER_A,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_A);
|
||||
priv->mouse_location == MOUSE_STEPPER_A);
|
||||
|
||||
if (priv->has_stepper_b)
|
||||
draw_stepper (range, STEPPER_B, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
|
||||
priv->grab_location == MOUSE_STEPPER_B,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_B);
|
||||
priv->mouse_location == MOUSE_STEPPER_B);
|
||||
|
||||
if (priv->has_stepper_c)
|
||||
draw_stepper (range, STEPPER_C, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
|
||||
priv->grab_location == MOUSE_STEPPER_C,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_C);
|
||||
priv->mouse_location == MOUSE_STEPPER_C);
|
||||
|
||||
if (priv->has_stepper_d)
|
||||
draw_stepper (range, STEPPER_D, cr,
|
||||
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
|
||||
priv->grab_location == MOUSE_STEPPER_D,
|
||||
!touchscreen && priv->mouse_location == MOUSE_STEPPER_D);
|
||||
priv->mouse_location == MOUSE_STEPPER_D);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2533,7 +2529,8 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
{
|
||||
GtkRange *range = GTK_RANGE (widget);
|
||||
GtkRangePrivate *priv = range->priv;
|
||||
GdkDevice *device;
|
||||
GdkDevice *device, *source_device;
|
||||
GdkInputSource source;
|
||||
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
@@ -2543,13 +2540,17 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
return FALSE;
|
||||
|
||||
device = gdk_event_get_device ((GdkEvent *) event);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
source = gdk_device_get_source (source_device);
|
||||
|
||||
priv->mouse_x = event->x;
|
||||
priv->mouse_y = event->y;
|
||||
|
||||
if (gtk_range_update_mouse_location (range))
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
if (priv->mouse_location == MOUSE_TROUGH &&
|
||||
if (source != GDK_SOURCE_TOUCH &&
|
||||
priv->mouse_location == MOUSE_TROUGH &&
|
||||
event->button == 1)
|
||||
{
|
||||
/* button 1 steps by page increment, as with button 2 on a stepper
|
||||
@@ -2598,17 +2599,17 @@ gtk_range_button_press (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
else if ((priv->mouse_location == MOUSE_TROUGH &&
|
||||
event->button == 2) ||
|
||||
(source == GDK_SOURCE_TOUCH || event->button == 2)) ||
|
||||
priv->mouse_location == MOUSE_SLIDER)
|
||||
{
|
||||
gboolean need_value_update = FALSE;
|
||||
|
||||
/* Any button can be used to drag the slider, but you can start
|
||||
* dragging the slider with a trough click using button 2;
|
||||
* On button 2 press, we warp the slider to mouse position,
|
||||
* then begin the slider drag.
|
||||
* On button 2 press and touch devices, we warp the slider to
|
||||
* mouse position, then begin the slider drag.
|
||||
*/
|
||||
if (event->button == 2)
|
||||
if (event->button == 2 || source == GDK_SOURCE_TOUCH)
|
||||
{
|
||||
gdouble slider_low_value, slider_high_value, new_value;
|
||||
|
||||
|
||||
+1013
-13
File diff suppressed because it is too large
Load Diff
@@ -117,6 +117,9 @@ void gtk_scrolled_window_set_min_content_width (GtkScrolledWindow *sc
|
||||
gint gtk_scrolled_window_get_min_content_height (GtkScrolledWindow *scrolled_window);
|
||||
void gtk_scrolled_window_set_min_content_height (GtkScrolledWindow *scrolled_window,
|
||||
gint height);
|
||||
void gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
|
||||
GtkKineticScrollingFlags flags);
|
||||
GtkKineticScrollingFlags gtk_scrolled_window_get_kinetic_scrolling (GtkScrolledWindow *scrolled_window);
|
||||
|
||||
gint _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window);
|
||||
|
||||
|
||||
+56
-5
@@ -33,6 +33,7 @@
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkcssproviderprivate.h"
|
||||
#include "gtksymboliccolor.h"
|
||||
#include "gtkanimationdescription.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkversion.h"
|
||||
|
||||
@@ -96,9 +97,10 @@
|
||||
*/
|
||||
|
||||
|
||||
#define DEFAULT_TIMEOUT_INITIAL 200
|
||||
#define DEFAULT_TIMEOUT_REPEAT 20
|
||||
#define DEFAULT_TIMEOUT_EXPAND 500
|
||||
#define DEFAULT_TIMEOUT_INITIAL 200
|
||||
#define DEFAULT_TIMEOUT_REPEAT 20
|
||||
#define DEFAULT_TIMEOUT_EXPAND 500
|
||||
#define DEFAULT_TIMEOUT_PRESS_AND_HOLD 800
|
||||
|
||||
typedef struct _GtkSettingsPropertyValue GtkSettingsPropertyValue;
|
||||
typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate;
|
||||
@@ -206,7 +208,8 @@ enum {
|
||||
PROP_IM_PREEDIT_STYLE,
|
||||
PROP_IM_STATUS_STYLE,
|
||||
PROP_SHELL_SHOWS_APP_MENU,
|
||||
PROP_SHELL_SHOWS_MENUBAR
|
||||
PROP_SHELL_SHOWS_MENUBAR,
|
||||
PROP_PRESS_AND_HOLD_TIMEOUT
|
||||
};
|
||||
|
||||
/* --- prototypes --- */
|
||||
@@ -697,13 +700,16 @@ gtk_settings_class_init (GtkSettingsClass *class)
|
||||
* functionality.
|
||||
*
|
||||
* Since: 2.10
|
||||
*
|
||||
* Deprecated: 3.4. Generally the behavior touchscreen input should be
|
||||
* performed dynamically based on gdk_event_get_source_device().
|
||||
*/
|
||||
result = settings_install_property_parser (class,
|
||||
g_param_spec_boolean ("gtk-touchscreen-mode",
|
||||
P_("Enable Touchscreen Mode"),
|
||||
P_("When TRUE, there are no motion notify events delivered on this screen"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE),
|
||||
GTK_PARAM_READWRITE | G_PARAM_DEPRECATED),
|
||||
NULL);
|
||||
|
||||
g_assert (result == PROP_TOUCHSCREEN_MODE);
|
||||
@@ -1346,6 +1352,24 @@ gtk_settings_class_init (GtkSettingsClass *class)
|
||||
NULL);
|
||||
g_assert (result == PROP_SHELL_SHOWS_MENUBAR);
|
||||
|
||||
/**
|
||||
* GtkSettings:gtk-press-and-hold-timeout:
|
||||
*
|
||||
* The amount of time, in milliseconds, a button has to be pressed
|
||||
* before the press-and-hold signal with the trigger action is emitted.
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
result = settings_install_property_parser (class,
|
||||
g_param_spec_int ("gtk-press-and-hold-timeout",
|
||||
P_("Press And Hold Timeout"),
|
||||
P_("Timeout before press-and-hold action activates"),
|
||||
0, G_MAXINT,
|
||||
DEFAULT_TIMEOUT_PRESS_AND_HOLD,
|
||||
GTK_PARAM_READWRITE),
|
||||
NULL);
|
||||
g_assert (result == PROP_PRESS_AND_HOLD_TIMEOUT);
|
||||
|
||||
g_type_class_add_private (class, sizeof (GtkSettingsPrivate));
|
||||
}
|
||||
|
||||
@@ -1441,6 +1465,33 @@ gtk_settings_get_style (GtkStyleProvider *provider,
|
||||
|
||||
settings_ensure_style (settings);
|
||||
|
||||
/* Set animation for press and hold */
|
||||
if (gtk_widget_path_iter_has_class (path, 0, GTK_STYLE_CLASS_PRESS_AND_HOLD))
|
||||
{
|
||||
GtkAnimationDescription *anim_desc;
|
||||
GtkStyleProperties *copy;
|
||||
gint duration;
|
||||
|
||||
copy = gtk_style_properties_new ();
|
||||
gtk_style_properties_merge (copy, settings->priv->style, TRUE);
|
||||
|
||||
g_object_get (settings,
|
||||
"gtk-press-and-hold-timeout", &duration,
|
||||
NULL);
|
||||
|
||||
anim_desc = _gtk_animation_description_new (duration,
|
||||
GTK_TIMELINE_PROGRESS_LINEAR,
|
||||
FALSE);
|
||||
gtk_style_properties_set (copy,
|
||||
GTK_STATE_FLAG_ACTIVE,
|
||||
"transition", anim_desc,
|
||||
NULL);
|
||||
|
||||
_gtk_animation_description_unref (anim_desc);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
return g_object_ref (settings->priv->style);
|
||||
}
|
||||
|
||||
|
||||
@@ -647,6 +647,13 @@ struct _GtkStyleContextClass
|
||||
*/
|
||||
#define GTK_STYLE_CLASS_RIGHT "right"
|
||||
|
||||
/**
|
||||
* GTK_STYLE_CLASS_PRESS_AND_HOLD:
|
||||
*
|
||||
* A CSS class for the press and hold activity indicator.
|
||||
*/
|
||||
#define GTK_STYLE_CLASS_PRESS_AND_HOLD "press-and-hold"
|
||||
|
||||
/* Predefined set of widget regions */
|
||||
|
||||
/**
|
||||
|
||||
+54
-26
@@ -378,6 +378,11 @@ static void gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
guint time);
|
||||
|
||||
static gboolean gtk_text_view_popup_menu (GtkWidget *widget);
|
||||
static gboolean gtk_text_view_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
static void gtk_text_view_move_cursor (GtkTextView *text_view,
|
||||
GtkMovementStep step,
|
||||
@@ -463,7 +468,9 @@ static void gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
|
||||
gint y);
|
||||
|
||||
static void gtk_text_view_do_popup (GtkTextView *text_view,
|
||||
GdkEventButton *event);
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button);
|
||||
|
||||
static void cancel_pending_scroll (GtkTextView *text_view);
|
||||
static void gtk_text_view_queue_scroll (GtkTextView *text_view,
|
||||
@@ -631,7 +638,8 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
widget_class->drag_data_received = gtk_text_view_drag_data_received;
|
||||
|
||||
widget_class->popup_menu = gtk_text_view_popup_menu;
|
||||
|
||||
widget_class->press_and_hold = gtk_text_view_press_and_hold;
|
||||
|
||||
container_class->add = gtk_text_view_add;
|
||||
container_class->remove = gtk_text_view_remove;
|
||||
container_class->forall = gtk_text_view_forall;
|
||||
@@ -4268,8 +4276,15 @@ gtk_text_view_grab_notify (GtkWidget *widget,
|
||||
if (priv->grab_device &&
|
||||
gtk_widget_device_is_shadowed (widget, priv->grab_device))
|
||||
{
|
||||
if (priv->drag_start_x >= 0)
|
||||
{
|
||||
priv->drag_start_x = -1;
|
||||
priv->drag_start_y = -1;
|
||||
}
|
||||
|
||||
gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget));
|
||||
gtk_text_view_unobscure_mouse_cursor (GTK_TEXT_VIEW (widget));
|
||||
priv->grab_device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4547,7 +4562,8 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
gtk_text_view_do_popup (text_view, event);
|
||||
gtk_text_view_do_popup (text_view, event->device,
|
||||
event->time, event->button);
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->button == 1)
|
||||
@@ -4570,6 +4586,7 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
|
||||
gtk_widget_get_modifier_mask (widget,
|
||||
GDK_MODIFIER_INTENT_EXTEND_SELECTION)))
|
||||
{
|
||||
priv->grab_device = event->device;
|
||||
priv->drag_start_x = event->x;
|
||||
priv->drag_start_y = event->y;
|
||||
priv->pending_place_cursor_button = event->button;
|
||||
@@ -8310,16 +8327,18 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
signals[POPULATE_POPUP],
|
||||
0,
|
||||
priv->popup_menu);
|
||||
|
||||
if (info->device)
|
||||
gtk_menu_popup_for_device (GTK_MENU (priv->popup_menu),
|
||||
info->device, NULL, NULL, NULL, NULL, NULL,
|
||||
info->button, info->time);
|
||||
|
||||
if (gdk_device_get_source (info->device) != GDK_SOURCE_KEYBOARD)
|
||||
gtk_menu_popup_for_device (GTK_MENU (priv->popup_menu),
|
||||
info->device, NULL, NULL, NULL, NULL, NULL,
|
||||
info->button, info->time);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
|
||||
popup_position_func, text_view,
|
||||
0, gtk_get_current_event_time ());
|
||||
gtk_menu_popup_for_device (GTK_MENU (priv->popup_menu),
|
||||
info->device, NULL, NULL,
|
||||
popup_position_func,
|
||||
text_view, NULL,
|
||||
0, info->time);
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
|
||||
}
|
||||
}
|
||||
@@ -8330,7 +8349,9 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
|
||||
static void
|
||||
gtk_text_view_do_popup (GtkTextView *text_view,
|
||||
GdkEventButton *event)
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button)
|
||||
{
|
||||
PopupInfo *info = g_new (PopupInfo, 1);
|
||||
|
||||
@@ -8339,19 +8360,9 @@ gtk_text_view_do_popup (GtkTextView *text_view,
|
||||
* we get them, then we actually pop up the menu.
|
||||
*/
|
||||
info->text_view = g_object_ref (text_view);
|
||||
|
||||
if (event)
|
||||
{
|
||||
info->button = event->button;
|
||||
info->time = event->time;
|
||||
info->device = event->device;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->button = 0;
|
||||
info->time = gtk_get_current_event_time ();
|
||||
info->device = NULL;
|
||||
}
|
||||
info->button = button;
|
||||
info->time = _time;
|
||||
info->device = device;
|
||||
|
||||
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
|
||||
GDK_SELECTION_CLIPBOARD),
|
||||
@@ -8363,7 +8374,24 @@ gtk_text_view_do_popup (GtkTextView *text_view,
|
||||
static gboolean
|
||||
gtk_text_view_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);
|
||||
gtk_text_view_do_popup (GTK_TEXT_VIEW (widget),
|
||||
gtk_get_current_event_device (),
|
||||
gtk_get_current_event_time (),
|
||||
0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_view_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
|
||||
gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), device,
|
||||
GDK_CURRENT_TIME, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -2596,6 +2596,63 @@ render_spinner (GtkThemingEngine *engine,
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
render_press_and_hold (GtkThemingEngine *engine,
|
||||
cairo_t *cr,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
gdouble progress, radius, border_width;
|
||||
GdkRGBA color, bg_color;
|
||||
GtkStateFlags flags;
|
||||
GtkBorder border;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
if (!gtk_theming_engine_state_is_running (engine,
|
||||
GTK_STATE_FLAG_ACTIVE,
|
||||
&progress))
|
||||
progress = 0;
|
||||
|
||||
flags = gtk_theming_engine_get_state (engine);
|
||||
gtk_theming_engine_get_background_color (engine, flags, &bg_color);
|
||||
gtk_theming_engine_get_color (engine, flags, &color);
|
||||
gtk_theming_engine_get_border (engine, flags, &border);
|
||||
|
||||
border_width = (gdouble) MAX (MAX (border.top, border.bottom),
|
||||
MAX (border.left, border.right));
|
||||
|
||||
radius = MIN (width, height) / 2;
|
||||
|
||||
if (border_width == 0 ||
|
||||
border_width >= radius - border_width)
|
||||
border_width = MAX (1, radius / 4);
|
||||
|
||||
cairo_set_line_width (cr, border_width);
|
||||
radius -= border_width;
|
||||
|
||||
/* Arcs start from the negative Y axis */
|
||||
cairo_arc (cr,
|
||||
width / 2, height / 2,
|
||||
radius,
|
||||
- G_PI_2, - G_PI_2 + (2 * G_PI));
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &bg_color);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_arc (cr,
|
||||
width / 2, height / 2,
|
||||
radius,
|
||||
- G_PI_2,
|
||||
- G_PI_2 + (2 * G_PI * progress));
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_theming_engine_render_activity (GtkThemingEngine *engine,
|
||||
cairo_t *cr,
|
||||
@@ -2608,6 +2665,10 @@ gtk_theming_engine_render_activity (GtkThemingEngine *engine,
|
||||
{
|
||||
render_spinner (engine, cr, x, y, width, height);
|
||||
}
|
||||
else if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_PRESS_AND_HOLD))
|
||||
{
|
||||
render_press_and_hold (engine, cr, x, y, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_theming_engine_render_background (engine, cr, x, y, width, height);
|
||||
|
||||
+22
-3
@@ -35,6 +35,7 @@ struct GtkTimelinePriv
|
||||
guint source_id;
|
||||
|
||||
GTimer *timer;
|
||||
gdouble elapsed_time;
|
||||
|
||||
gdouble progress;
|
||||
gdouble last_progress;
|
||||
@@ -309,16 +310,15 @@ gtk_timeline_run_frame (GtkTimeline *timeline)
|
||||
{
|
||||
GtkTimelinePriv *priv;
|
||||
gdouble delta_progress, progress;
|
||||
guint elapsed_time;
|
||||
|
||||
priv = timeline->priv;
|
||||
|
||||
elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
|
||||
priv->elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000);
|
||||
g_timer_start (priv->timer);
|
||||
|
||||
if (priv->animations_enabled)
|
||||
{
|
||||
delta_progress = (gdouble) elapsed_time / priv->duration;
|
||||
delta_progress = (gdouble) priv->elapsed_time / priv->duration;
|
||||
progress = priv->last_progress;
|
||||
|
||||
if (priv->direction == GTK_TIMELINE_DIRECTION_BACKWARD)
|
||||
@@ -509,6 +509,25 @@ _gtk_timeline_is_running (GtkTimeline *timeline)
|
||||
return (priv->source_id != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_timeline_get_elapsed_time:
|
||||
* @timeline: A #GtkTimeline
|
||||
*
|
||||
* Returns the elapsed time since the last GtkTimeline::frame signal
|
||||
*
|
||||
* Return Value: elapsed time in milliseconds since the last frame
|
||||
**/
|
||||
guint
|
||||
_gtk_timeline_get_elapsed_time (GtkTimeline *timeline)
|
||||
{
|
||||
GtkTimelinePriv *priv;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TIMELINE (timeline), 0);
|
||||
|
||||
priv = timeline->priv;
|
||||
return priv->elapsed_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_timeline_get_fps:
|
||||
* @timeline: A #GtkTimeline
|
||||
|
||||
@@ -84,6 +84,7 @@ void _gtk_timeline_pause (GtkTimeline
|
||||
void _gtk_timeline_rewind (GtkTimeline *timeline);
|
||||
|
||||
gboolean _gtk_timeline_is_running (GtkTimeline *timeline);
|
||||
guint _gtk_timeline_get_elapsed_time (GtkTimeline *timeline);
|
||||
|
||||
guint _gtk_timeline_get_fps (GtkTimeline *timeline);
|
||||
void _gtk_timeline_set_fps (GtkTimeline *timeline,
|
||||
|
||||
@@ -658,13 +658,9 @@ gtk_toggle_button_update_state (GtkButton *button)
|
||||
{
|
||||
GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
|
||||
GtkToggleButtonPrivate *priv = toggle_button->priv;
|
||||
gboolean depressed, touchscreen;
|
||||
gboolean depressed;
|
||||
GtkStateFlags new_state = 0;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (button)),
|
||||
"gtk-touchscreen-mode", &touchscreen,
|
||||
NULL);
|
||||
|
||||
new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
|
||||
~(GTK_STATE_FLAG_INCONSISTENT |
|
||||
GTK_STATE_FLAG_PRELIGHT |
|
||||
@@ -680,7 +676,7 @@ gtk_toggle_button_update_state (GtkButton *button)
|
||||
else
|
||||
depressed = priv->active;
|
||||
|
||||
if (!touchscreen && button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
|
||||
if (button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
|
||||
new_state |= GTK_STATE_FLAG_PRELIGHT;
|
||||
|
||||
if (depressed)
|
||||
|
||||
+17
-5
@@ -1537,22 +1537,34 @@ _gtk_tooltip_hide (GtkWidget *widget)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tooltips_enabled (GdkWindow *window)
|
||||
tooltips_enabled (GdkEvent *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GdkInputSource source;
|
||||
GdkWindow *window;
|
||||
gboolean enabled;
|
||||
gboolean touchscreen;
|
||||
GdkScreen *screen;
|
||||
GtkSettings *settings;
|
||||
|
||||
window = event->any.window;
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
if (!source_device)
|
||||
return FALSE;
|
||||
|
||||
source = gdk_device_get_source (source_device);
|
||||
screen = gdk_window_get_screen (window);
|
||||
settings = gtk_settings_get_for_screen (screen);
|
||||
|
||||
g_object_get (settings,
|
||||
"gtk-touchscreen-mode", &touchscreen,
|
||||
"gtk-enable-tooltips", &enabled,
|
||||
NULL);
|
||||
|
||||
return (!touchscreen && enabled);
|
||||
if (enabled &&
|
||||
source != GDK_SOURCE_TOUCH)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1564,7 +1576,7 @@ _gtk_tooltip_handle_event (GdkEvent *event)
|
||||
GdkDisplay *display;
|
||||
GtkTooltip *current_tooltip;
|
||||
|
||||
if (!tooltips_enabled (event->any.window))
|
||||
if (!tooltips_enabled (event))
|
||||
return;
|
||||
|
||||
/* Returns coordinates relative to has_tooltip_widget's allocation. */
|
||||
|
||||
+624
@@ -398,6 +398,8 @@ struct _GtkWidgetPrivate
|
||||
/* The widget's parent */
|
||||
GtkWidget *parent;
|
||||
|
||||
GSList *captured_events;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
/* Number of gtk_widget_push_verify_invariants () */
|
||||
guint verifying_invariants_count;
|
||||
@@ -479,6 +481,8 @@ enum {
|
||||
QUERY_TOOLTIP,
|
||||
DRAG_FAILED,
|
||||
STYLE_UPDATED,
|
||||
CAPTURED_EVENT,
|
||||
PRESS_AND_HOLD,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@@ -534,6 +538,24 @@ struct _GtkStateData
|
||||
guint operation : 2;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* The widget */
|
||||
GtkWidget *widget;
|
||||
|
||||
/* animation */
|
||||
GtkWidget *popup;
|
||||
guint delay_animation_id;
|
||||
guint size;
|
||||
|
||||
gint start_x;
|
||||
gint start_y;
|
||||
gint current_x;
|
||||
gint current_y;
|
||||
|
||||
GdkDevice *device;
|
||||
} PressAndHoldData;
|
||||
|
||||
/* --- prototypes --- */
|
||||
static void gtk_widget_base_class_init (gpointer g_class);
|
||||
static void gtk_widget_class_init (GtkWidgetClass *klass);
|
||||
@@ -700,6 +722,10 @@ static void gtk_widget_set_device_enabled_internal (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
gboolean recurse,
|
||||
gboolean enabled);
|
||||
static gboolean event_window_is_still_viewable (GdkEvent *event);
|
||||
|
||||
static gboolean gtk_widget_press_and_hold_cancel (GtkWidget *widget);
|
||||
|
||||
|
||||
/* --- variables --- */
|
||||
static gpointer gtk_widget_parent_class = NULL;
|
||||
@@ -728,6 +754,7 @@ static GQuark quark_visual = 0;
|
||||
static GQuark quark_modifier_style = 0;
|
||||
static GQuark quark_enabled_devices = 0;
|
||||
static GQuark quark_size_groups = 0;
|
||||
static GQuark quark_press_and_hold = 0;
|
||||
GParamSpecPool *_gtk_widget_child_property_pool = NULL;
|
||||
GObjectNotifyContext *_gtk_widget_child_property_notify_context = NULL;
|
||||
|
||||
@@ -852,6 +879,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
quark_modifier_style = g_quark_from_static_string ("gtk-widget-modifier-style");
|
||||
quark_enabled_devices = g_quark_from_static_string ("gtk-widget-enabled-devices");
|
||||
quark_size_groups = g_quark_from_static_string ("gtk-widget-size-groups");
|
||||
quark_press_and_hold = g_quark_from_static_string ("gtk-widget-press-and-hold");
|
||||
|
||||
style_property_spec_pool = g_param_spec_pool_new (FALSE);
|
||||
_gtk_widget_child_property_pool = g_param_spec_pool_new (TRUE);
|
||||
@@ -930,6 +958,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
klass->grab_broken_event = NULL;
|
||||
klass->query_tooltip = gtk_widget_real_query_tooltip;
|
||||
klass->style_updated = gtk_widget_real_style_updated;
|
||||
klass->press_and_hold = NULL;
|
||||
|
||||
klass->show_help = gtk_widget_real_show_help;
|
||||
|
||||
@@ -1793,6 +1822,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
* #GtkWidget::key-press-event) and finally a generic
|
||||
* #GtkWidget::event-after signal.
|
||||
*
|
||||
* An event can be captured before ::event signal is emitted by connecting to
|
||||
* ::captured-event event signal.
|
||||
*
|
||||
* Returns: %TRUE to stop other handlers from being invoked for the event
|
||||
* and to cancel the emission of the second specific ::event signal.
|
||||
* %FALSE to propagate the event further and to allow the emission of
|
||||
@@ -1829,6 +1861,53 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
/**
|
||||
* GtkWidget::captured-event:
|
||||
* @widget: the object which received the signal.
|
||||
* @event: the #GdkEvent which triggered this signal
|
||||
*
|
||||
* The ::captured-event signal is emitted before the ::event signal to
|
||||
* allow capturing an event before the specialized events are emitted.
|
||||
* The event is propagated starting from the top-level container to
|
||||
* the widget that received the event going down the hierarchy.
|
||||
*
|
||||
* This signal returns a #GtkCapturedEventFlags with the handling
|
||||
* status of the event, if %GTK_CAPTURED_EVENT_HANDLED is enabled,
|
||||
* the event will be considered to be handled, and thus not propagated
|
||||
* further.
|
||||
*
|
||||
* If, additionally, %GTK_CAPTURED_EVENT_STORE is enabled, the event will
|
||||
* be stored so it can possibly be re-sent at a later stage. See
|
||||
* gtk_widget_release_captured_events().
|
||||
*
|
||||
* If no flags are enabled, the captured event will be propagated even
|
||||
* further, eventually triggering the emission of the #GtkWidget::event
|
||||
* signal on the widget that received the event if no parent widgets
|
||||
* captured it.
|
||||
*
|
||||
* <note><para>Enabling %GTK_CAPTURED_EVENT_STORE without
|
||||
* %GTK_CAPTURED_EVENT_HANDLED is not allowed to avoid doubly
|
||||
* event emission.</para></note>
|
||||
*
|
||||
* <warning><para>%GTK_CAPTURED_EVENT_STORE will not keep any track of
|
||||
* event parity (eg. ensuring that button/key presses and releases
|
||||
* are paired, or focus/crossing events) nor consistency, so use with
|
||||
* discretion.</para></warning>
|
||||
*
|
||||
* Returns: a #GtkCapturedEventFlags specifying what to do with the event.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
widget_signals[CAPTURED_EVENT] =
|
||||
g_signal_new (I_("captured-event"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, captured_event),
|
||||
_gtk_captured_enum_accumulator, NULL,
|
||||
_gtk_marshal_FLAGS__BOXED,
|
||||
GTK_TYPE_CAPTURED_EVENT_FLAGS, 1,
|
||||
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
/**
|
||||
* GtkWidget::button-press-event:
|
||||
* @widget: the object which received the signal.
|
||||
@@ -3000,6 +3079,66 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
_gtk_marshal_BOOLEAN__UINT,
|
||||
G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
|
||||
|
||||
/**
|
||||
* GtkWidget::press-and-hold:
|
||||
* @widget: the object which received the signal
|
||||
* @action: a #GtkPressAndHoldAction specifying the action
|
||||
* @x: if the action is not %GTK_PRESS_AND_HOLD_CANCEL, the x coordinate
|
||||
* of the cursor position where the request has been emitted, relative
|
||||
* to widget->window, otherwise undefined
|
||||
* @y: if the action is not %GTK_PRESS_AND_HOLD_CANCEL, the y coordinate
|
||||
* of the cursor position where the request has been emitted, relative
|
||||
* to widget->window, otherwise undefined
|
||||
*
|
||||
* Connect to this signal and correctly handle all of its actions if you
|
||||
* want your widget to support the press-n-hold operation. The
|
||||
* press-and-hold operation is defined as keeping a mouse button pressed
|
||||
* for a given amount of time (specified in the "press-and-hold-timeout"
|
||||
* GtkSetting); during this time the mouse is only allowed to move a little
|
||||
* bit (not past the drag threshold), else the press-and-hold operation will
|
||||
* be terminated.
|
||||
*
|
||||
* From the above passage we can distill three actions for which this
|
||||
* signal will be emitted: query, emitted when the mouse button goes
|
||||
* down; trigger, emitted if the mouse button has been kept down for the
|
||||
* specified amount of time and movements did not pass the drag threshold;
|
||||
* and cancel, emitted when the press-and-hold operation has been terminated
|
||||
* before the trigger action has been emitted.
|
||||
*
|
||||
* For query, @action will be set to %GTK_PRESS_AND_HOLD_QUERY, @x and @y
|
||||
* will be set to the cursor position.
|
||||
* A return value of %FALSE means no press-and-hold action should occur
|
||||
* for these coordinates on the given widget, when %TRUE is returned
|
||||
* a trigger action may be emitted later on.
|
||||
*
|
||||
* The trigger action is emitted by setting @action to be
|
||||
* %GTK_PRESS_AND_HOLD_TRIGGER, the @x and @y coordinates are set to the
|
||||
* cursor's current location (this includes any movements made between
|
||||
* the original query and this trigger). In this case the return value
|
||||
* is ignored.
|
||||
*
|
||||
* When @action is %GTK_WIDGET_PRESS_AND_HOLD_CANCEL, @x and @y are both
|
||||
* undefined. The return value is ignored too as
|
||||
* this action is only there for informational purposes.
|
||||
*
|
||||
* Returns: a boolean indicating how to proceed based on the value of
|
||||
* @action, as described above.
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
widget_signals[PRESS_AND_HOLD] =
|
||||
g_signal_new (I_("press-and-hold"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, press_and_hold),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__OBJECT_ENUM_INT_INT,
|
||||
G_TYPE_BOOLEAN, 4,
|
||||
GDK_TYPE_DEVICE,
|
||||
GTK_TYPE_PRESS_AND_HOLD_ACTION,
|
||||
G_TYPE_INT,
|
||||
G_TYPE_INT);
|
||||
|
||||
binding_set = gtk_binding_set_by_class (klass);
|
||||
gtk_binding_entry_add_signal (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK,
|
||||
"popup-menu", 0);
|
||||
@@ -4422,6 +4561,12 @@ gtk_widget_realize (GtkWidget *widget)
|
||||
_gtk_widget_enable_device_events (widget);
|
||||
gtk_widget_update_devices_mask (widget, TRUE);
|
||||
|
||||
/* Enable button motion events for press and hold */
|
||||
if (!gtk_widget_get_has_window (widget))
|
||||
gdk_window_set_events (priv->window,
|
||||
gdk_window_get_events (priv->window) | GDK_BUTTON_MOTION_MASK);
|
||||
gtk_widget_add_events (widget, GDK_BUTTON_MOTION_MASK);
|
||||
|
||||
gtk_widget_pop_verify_invariants (widget);
|
||||
}
|
||||
}
|
||||
@@ -5863,6 +6008,68 @@ gtk_widget_event (GtkWidget *widget,
|
||||
return gtk_widget_event_internal (widget, event);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_widget_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GtkCapturedEventFlags flags;
|
||||
GtkWidgetPrivate *priv;
|
||||
gboolean return_val;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
|
||||
g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE);
|
||||
|
||||
priv = widget->priv;
|
||||
|
||||
if (event->type == GDK_EXPOSE)
|
||||
{
|
||||
g_warning ("Events of type GDK_EXPOSE cannot be synthesized. To get "
|
||||
"the same effect, call gdk_window_invalidate_rect/region(), "
|
||||
"followed by gdk_window_process_updates().");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!event_window_is_still_viewable (event))
|
||||
return TRUE;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
g_signal_emit (widget, widget_signals[CAPTURED_EVENT], 0, event, &flags);
|
||||
|
||||
/* Only store events that have been handled, so we don't end up
|
||||
* sending twice the same event.
|
||||
*/
|
||||
if (flags & GTK_CAPTURED_EVENT_STORE)
|
||||
{
|
||||
if ((flags & GTK_CAPTURED_EVENT_HANDLED) != 0)
|
||||
priv->captured_events = g_slist_prepend (priv->captured_events,
|
||||
gdk_event_copy (event));
|
||||
else
|
||||
g_warning ("Captured events can only be stored if they are claimed "
|
||||
"to be handled by the capturing widget. The use of "
|
||||
"GTK_CAPTURED_EVENT_HANDLED is mandatory if using "
|
||||
"GTK_CAPTURED_EVENT_STORE.");
|
||||
}
|
||||
|
||||
/* The widget that was originally to receive the event
|
||||
* handles motion hints, but the capturing widget might
|
||||
* not, so ensure we get further motion events.
|
||||
*/
|
||||
if ((flags & GTK_CAPTURED_EVENT_HANDLED) != 0 &&
|
||||
event->type == GDK_MOTION_NOTIFY &&
|
||||
event->motion.is_hint &&
|
||||
(gdk_window_get_events (event->any.window) &
|
||||
GDK_POINTER_MOTION_HINT_MASK) != 0)
|
||||
gdk_event_request_motions (&event->motion);
|
||||
|
||||
return_val = (flags & GTK_CAPTURED_EVENT_HANDLED) != 0 ||
|
||||
!WIDGET_REALIZED_FOR_EVENT (widget, event);
|
||||
|
||||
g_object_unref (widget);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/* Returns TRUE if a translation should be done */
|
||||
gboolean
|
||||
_gtk_widget_get_translation_to_window (GtkWidget *widget,
|
||||
@@ -6400,6 +6607,14 @@ void
|
||||
_gtk_widget_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
PressAndHoldData *data;
|
||||
|
||||
data = g_object_get_qdata (G_OBJECT (widget), quark_press_and_hold);
|
||||
|
||||
if (data && data->device &&
|
||||
gtk_widget_device_is_shadowed (widget, data->device))
|
||||
gtk_widget_press_and_hold_cancel (widget);
|
||||
|
||||
g_signal_emit (widget, widget_signals[GRAB_NOTIFY], 0, was_grabbed);
|
||||
}
|
||||
|
||||
@@ -6714,6 +6929,344 @@ gtk_widget_has_focus (GtkWidget *widget)
|
||||
return widget->priv->has_focus;
|
||||
}
|
||||
|
||||
/* --- Press and hold --- */
|
||||
|
||||
static inline PressAndHoldData *
|
||||
gtk_widget_peek_press_and_hold_data (GtkWidget *widget)
|
||||
{
|
||||
return g_object_get_qdata (G_OBJECT (widget), quark_press_and_hold);
|
||||
}
|
||||
|
||||
static void
|
||||
press_and_hold_data_free (PressAndHoldData *data)
|
||||
{
|
||||
if (data->popup)
|
||||
gtk_widget_destroy (data->popup);
|
||||
|
||||
if (data->delay_animation_id)
|
||||
g_source_remove (data->delay_animation_id);
|
||||
|
||||
g_slice_free (PressAndHoldData, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_widget_set_press_and_hold_data (GtkWidget *widget,
|
||||
PressAndHoldData *data)
|
||||
{
|
||||
g_object_set_qdata_full (G_OBJECT (widget),
|
||||
quark_press_and_hold,
|
||||
data,
|
||||
(GDestroyNotify) press_and_hold_data_free);
|
||||
}
|
||||
|
||||
static inline PressAndHoldData *
|
||||
gtk_widget_get_press_and_hold_data (GtkWidget *widget)
|
||||
{
|
||||
PressAndHoldData *data;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
if (!data)
|
||||
{
|
||||
data = g_slice_new0 (PressAndHoldData);
|
||||
data->widget = widget;
|
||||
gtk_widget_set_press_and_hold_data (widget, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_widget_press_and_hold_cancel (GtkWidget *widget)
|
||||
{
|
||||
PressAndHoldData *data;
|
||||
gboolean return_value;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
g_assert (data != NULL);
|
||||
|
||||
g_signal_emit (widget, widget_signals[PRESS_AND_HOLD],
|
||||
0,
|
||||
data->device,
|
||||
GTK_PRESS_AND_HOLD_CANCEL,
|
||||
-1, -1,
|
||||
&return_value);
|
||||
|
||||
gtk_widget_set_press_and_hold_data (widget, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_widget_press_and_hold_check_cancel (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
PressAndHoldData *data;
|
||||
|
||||
if (event->type != GDK_BUTTON_RELEASE)
|
||||
return FALSE;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
|
||||
if (data &&
|
||||
data->device == gdk_event_get_device ((GdkEvent *) event))
|
||||
{
|
||||
gtk_widget_press_and_hold_cancel (widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_widget_press_and_hold_check_threshold (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
PressAndHoldData *data;
|
||||
GdkDevice *device;
|
||||
|
||||
if (event->type != GDK_MOTION_NOTIFY)
|
||||
return FALSE;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
|
||||
if (!data)
|
||||
return FALSE;
|
||||
|
||||
device = gdk_event_get_device ((GdkEvent *) event);
|
||||
|
||||
if (data->device != device)
|
||||
return FALSE;
|
||||
|
||||
_gtk_widget_find_at_coords (event->window, event->x, event->y,
|
||||
&data->current_x, &data->current_y);
|
||||
|
||||
/* Stop press-and-hold if we dragged too far from the starting point */
|
||||
if (gtk_drag_check_threshold (widget, data->start_x, data->start_y,
|
||||
data->current_x, data->current_y))
|
||||
{
|
||||
gtk_widget_press_and_hold_cancel (widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (data->popup)
|
||||
gtk_window_move (GTK_WINDOW (data->popup),
|
||||
event->x_root - data->size / 2,
|
||||
event->y_root - data->size / 2);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_widget_press_and_hold_timeout (gpointer user_data)
|
||||
{
|
||||
gboolean return_value;
|
||||
GtkWidget *widget = GTK_WIDGET (user_data);
|
||||
PressAndHoldData *data;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
g_assert (data != NULL);
|
||||
|
||||
/* Done, clean up and emit the trigger signal */
|
||||
g_signal_emit (widget, widget_signals[PRESS_AND_HOLD],
|
||||
0,
|
||||
data->device,
|
||||
GTK_PRESS_AND_HOLD_TRIGGER,
|
||||
data->current_x, data->current_y,
|
||||
&return_value);
|
||||
|
||||
gtk_widget_set_press_and_hold_data (widget, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
press_and_hold_animation_draw (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
gpointer user_data)
|
||||
{
|
||||
PressAndHoldData *data;
|
||||
GtkStyleContext *context;
|
||||
GtkStateFlags state;
|
||||
gint width, height;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (GTK_WIDGET (user_data));
|
||||
g_assert (data != NULL);
|
||||
|
||||
width = gtk_widget_get_allocated_width (widget);
|
||||
height = gtk_widget_get_allocated_height (widget);
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
state = gtk_widget_get_state_flags (widget);
|
||||
gtk_style_context_set_state (context, state);
|
||||
|
||||
if (!gtk_style_context_state_is_running (context, GTK_STATE_FLAG_ACTIVE, NULL))
|
||||
{
|
||||
/* The animation just finished, so hide the widget
|
||||
* and finish the press and hold operation.
|
||||
*/
|
||||
gdk_threads_add_idle (gtk_widget_press_and_hold_timeout,
|
||||
user_data);
|
||||
gtk_widget_hide (widget);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gtk_widget_is_composited (widget))
|
||||
{
|
||||
cairo_t *mask_cr;
|
||||
cairo_region_t *region;
|
||||
cairo_surface_t *mask;
|
||||
|
||||
mask = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
|
||||
|
||||
mask_cr = cairo_create (mask);
|
||||
gtk_render_activity (context, mask_cr, 0, 0, width, height);
|
||||
cairo_destroy (mask_cr);
|
||||
|
||||
region = gdk_cairo_region_create_from_surface (mask);
|
||||
gdk_window_shape_combine_region (gtk_widget_get_window (widget), region, 0, 0);
|
||||
cairo_region_destroy (region);
|
||||
|
||||
cairo_surface_destroy (mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_save (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
gtk_render_activity (context, cr, 0, 0, width, height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_widget_press_and_hold_begin_animation_timeout (gpointer user_data)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (user_data);
|
||||
PressAndHoldData *data;
|
||||
gint x, y;
|
||||
|
||||
data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
g_assert (data != NULL);
|
||||
|
||||
gdk_window_get_device_position (gdk_screen_get_root_window (gtk_widget_get_screen (widget)),
|
||||
data->device, &x, &y, NULL);
|
||||
gtk_window_move (GTK_WINDOW (data->popup),
|
||||
x - data->size / 2,
|
||||
y - data->size / 2);
|
||||
gtk_widget_show (data->popup);
|
||||
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (data->popup),
|
||||
GTK_STATE_FLAG_ACTIVE, FALSE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_widget_press_and_hold_query (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
gboolean return_value = FALSE;
|
||||
|
||||
g_signal_emit (widget, widget_signals[PRESS_AND_HOLD],
|
||||
0,
|
||||
device,
|
||||
GTK_PRESS_AND_HOLD_QUERY,
|
||||
x, y,
|
||||
&return_value);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_widget_press_and_hold_check_start (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
PressAndHoldData *data = gtk_widget_peek_press_and_hold_data (widget);
|
||||
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
|
||||
/* Press and hold already in process? */
|
||||
if (data)
|
||||
return FALSE;
|
||||
|
||||
data = gtk_widget_get_press_and_hold_data (widget);
|
||||
|
||||
if (gtk_widget_press_and_hold_query (widget, data->device,
|
||||
event->x, event->y))
|
||||
{
|
||||
gint timeout, begin_ani_timeout;
|
||||
GdkScreen *screen;
|
||||
GdkVisual *visual;
|
||||
GtkStyleContext *context;
|
||||
cairo_region_t *region;
|
||||
GdkDevice *source_device;
|
||||
GdkInputSource source;
|
||||
|
||||
_gtk_widget_find_at_coords (event->window,
|
||||
event->x, event->y,
|
||||
&data->start_x, &data->start_y);
|
||||
|
||||
data->current_x = data->start_x;
|
||||
data->current_y = data->start_y;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (widget)),
|
||||
"gtk-press-and-hold-timeout", &timeout,
|
||||
"gtk-timeout-initial", &begin_ani_timeout,
|
||||
NULL);
|
||||
|
||||
screen = gtk_widget_get_screen (widget);
|
||||
visual = gdk_screen_get_rgba_visual (screen);
|
||||
|
||||
data->popup = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_window_set_screen (GTK_WINDOW (data->popup), screen);
|
||||
if (visual)
|
||||
gtk_widget_set_visual (data->popup, visual);
|
||||
gtk_widget_set_app_paintable (data->popup, TRUE);
|
||||
gtk_widget_realize (data->popup);
|
||||
|
||||
context = gtk_widget_get_style_context (data->popup);
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_PRESS_AND_HOLD);
|
||||
|
||||
g_signal_connect (data->popup, "draw",
|
||||
G_CALLBACK (press_and_hold_animation_draw),
|
||||
widget);
|
||||
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
source = gdk_device_get_source (source_device);
|
||||
|
||||
if (source == GDK_SOURCE_TOUCH)
|
||||
{
|
||||
/* Have an indicator with 2.5cm of diameter */
|
||||
data->size = (25 * gdk_screen_get_width (screen)) /
|
||||
gdk_screen_get_width_mm (screen);
|
||||
}
|
||||
else
|
||||
data->size = gdk_display_get_default_cursor_size (gtk_widget_get_display (widget));
|
||||
|
||||
gtk_window_resize (GTK_WINDOW (data->popup), data->size, data->size);
|
||||
|
||||
region = cairo_region_create ();
|
||||
gdk_window_input_shape_combine_region (gtk_widget_get_window (data->popup), region, 0, 0);
|
||||
cairo_region_destroy (region);
|
||||
|
||||
/* delay loading the animation by the double click timeout */
|
||||
data->delay_animation_id =
|
||||
gdk_threads_add_timeout (begin_ani_timeout,
|
||||
gtk_widget_press_and_hold_begin_animation_timeout,
|
||||
widget);
|
||||
|
||||
data->device = gdk_event_get_device ((GdkEvent *) event);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_has_visible_focus:
|
||||
* @widget: a #GtkWidget
|
||||
@@ -10167,6 +10720,12 @@ gtk_widget_finalize (GObject *object)
|
||||
|
||||
_gtk_widget_free_cached_sizes (widget);
|
||||
|
||||
if (priv->captured_events)
|
||||
{
|
||||
g_slist_foreach (priv->captured_events, (GFunc) gdk_event_free, NULL);
|
||||
g_slist_free (priv->captured_events);
|
||||
}
|
||||
|
||||
if (g_object_is_floating (object))
|
||||
g_warning ("A floating object was finalized. This means that someone\n"
|
||||
"called g_object_unref() on an object that had only a floating\n"
|
||||
@@ -13914,3 +14473,68 @@ _gtk_widget_set_style (GtkWidget *widget,
|
||||
{
|
||||
widget->priv->style = style;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_release_captured_events:
|
||||
* @widget: the #GtkWidget holding the events
|
||||
* @emit: #TRUE if the events must be emitted on the targed widget
|
||||
*
|
||||
* Releases the events that a widget has captured and stored
|
||||
* in the #GtkWidget::captured-event signal. if @emit is #TRUE,
|
||||
* the events will be emitted on the target widget (the widget
|
||||
* that would receive the event if no signal capturing happened)
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
void
|
||||
gtk_widget_release_captured_events (GtkWidget *widget,
|
||||
gboolean emit)
|
||||
{
|
||||
GtkWidgetPrivate *priv;
|
||||
GSList *l;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
|
||||
priv = widget->priv;
|
||||
|
||||
if (emit)
|
||||
{
|
||||
priv->captured_events = g_slist_reverse (priv->captured_events);
|
||||
|
||||
for (l = priv->captured_events; l; l = l->next)
|
||||
{
|
||||
GtkWidget *event_widget;
|
||||
GdkEvent *event = l->data;
|
||||
|
||||
event_widget = gtk_get_event_widget (event);
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_PROPERTY_NOTIFY:
|
||||
case GDK_FOCUS_CHANGE:
|
||||
case GDK_CONFIGURE:
|
||||
case GDK_MAP:
|
||||
case GDK_UNMAP:
|
||||
case GDK_SELECTION_CLEAR:
|
||||
case GDK_SELECTION_REQUEST:
|
||||
case GDK_SELECTION_NOTIFY:
|
||||
case GDK_CLIENT_EVENT:
|
||||
case GDK_VISIBILITY_NOTIFY:
|
||||
case GDK_WINDOW_STATE:
|
||||
case GDK_GRAB_BROKEN:
|
||||
case GDK_DAMAGE:
|
||||
/* These events are capturable, but don't bubble up */
|
||||
gtk_widget_event (event_widget, event);
|
||||
break;
|
||||
default:
|
||||
/* All other capturable events do bubble up */
|
||||
gtk_propagate_event (event_widget, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_foreach (priv->captured_events, (GFunc) gdk_event_free, NULL);
|
||||
g_slist_free (priv->captured_events);
|
||||
priv->captured_events = NULL;
|
||||
}
|
||||
|
||||
+17
-2
@@ -49,6 +49,13 @@ typedef enum
|
||||
GTK_WIDGET_HELP_WHATS_THIS
|
||||
} GtkWidgetHelpType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GTK_PRESS_AND_HOLD_QUERY,
|
||||
GTK_PRESS_AND_HOLD_TRIGGER,
|
||||
GTK_PRESS_AND_HOLD_CANCEL
|
||||
} GtkPressAndHoldAction;
|
||||
|
||||
/* Macro for casting a pointer to a GtkWidget or GtkWidgetClass pointer.
|
||||
* Macros for testing whether `widget' or `klass' are of type GTK_TYPE_WIDGET.
|
||||
*/
|
||||
@@ -425,6 +432,14 @@ struct _GtkWidgetClass
|
||||
|
||||
void (* style_updated) (GtkWidget *widget);
|
||||
|
||||
GtkCapturedEventFlags (* captured_event) (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
gboolean (* press_and_hold) (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y);
|
||||
/*< private >*/
|
||||
|
||||
GtkWidgetClassPrivate *priv;
|
||||
@@ -435,8 +450,6 @@ struct _GtkWidgetClass
|
||||
void (*_gtk_reserved4) (void);
|
||||
void (*_gtk_reserved5) (void);
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
void (*_gtk_reserved8) (void);
|
||||
};
|
||||
|
||||
struct _GtkWidgetAuxInfo
|
||||
@@ -892,6 +905,8 @@ GtkWidgetPath * gtk_widget_get_path (GtkWidget *widget);
|
||||
GdkModifierType gtk_widget_get_modifier_mask (GtkWidget *widget,
|
||||
GdkModifierIntent intent);
|
||||
|
||||
void gtk_widget_release_captured_events (GtkWidget *widget,
|
||||
gboolean emit);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -163,6 +163,16 @@ void _gtk_widget_set_style (GtkWidget *widget,
|
||||
GtkStyle *style);
|
||||
|
||||
|
||||
gboolean _gtk_widget_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
gboolean _gtk_widget_press_and_hold_check_start (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
gboolean _gtk_widget_press_and_hold_check_cancel (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
gboolean _gtk_widget_press_and_hold_check_threshold (GtkWidget *widget,
|
||||
GdkEventMotion *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_WIDGET_PRIVATE_H__ */
|
||||
|
||||
@@ -63,6 +63,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
|
||||
testicontheme \
|
||||
testimage \
|
||||
testinput \
|
||||
testkineticscrolling \
|
||||
testlockbutton \
|
||||
testmenubars \
|
||||
testmountoperation \
|
||||
@@ -76,6 +77,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
|
||||
testorientable \
|
||||
testoverlay \
|
||||
testprint \
|
||||
testpressandhold \
|
||||
testrecentchooser \
|
||||
testrecentchoosermenu \
|
||||
testrichtext \
|
||||
@@ -179,6 +181,7 @@ testgrid_DEPENDENCIES = $(TEST_DEPS)
|
||||
testgtk_DEPENDENCIES = $(TEST_DEPS)
|
||||
testinput_DEPENDENCIES = $(TEST_DEPS)
|
||||
testimage_DEPENDENCIES = $(TEST_DEPS)
|
||||
testkineticscrolling_DEPENDENCIES = $(TEST_DEPS)
|
||||
testlockbutton_DEPENDENCIES = $(TEST_DEPS)
|
||||
testmenubars_DEPENDENCIES = $(TEST_DEPS)
|
||||
testmountoperation_DEPENDENCIES = $(TEST_DEPS)
|
||||
@@ -194,6 +197,7 @@ testappchooserbutton_DEPENDENCIES = $(TEST_DEPS)
|
||||
testorientable_DEPENDENCIES = $(TEST_DEPS)
|
||||
testoverlay_DEPENDENCIES = $(TEST_DEPS)
|
||||
testprint_DEPENDENCIES = $(TEST_DEPS)
|
||||
testpressandhold_DEPENDENCIES = $(TEST_DEPS)
|
||||
testrecentchooser_DEPENDENCIES = $(TEST_DEPS)
|
||||
testrecentchoosermenu_DEPENDENCIES = $(TEST_DEPS)
|
||||
testrichtext_DEPENDENCIES = $(TEST_DEPS)
|
||||
@@ -277,6 +281,7 @@ testiconview_LDADD = $(LDADDS)
|
||||
testiconview_keynav_LDADD = $(LDADDS)
|
||||
testinput_LDADD = $(LDADDS)
|
||||
testimage_LDADD = $(LDADDS)
|
||||
testkineticscrolling_LDADD = $(LDADDS)
|
||||
testlockbutton_LDADD = $(LDADDS)
|
||||
testmenubars_LDADD = $(LDADDS)
|
||||
testmountoperation_LDADD = $(LDADDS)
|
||||
@@ -292,6 +297,7 @@ testappchooserbutton_LDADD = $(LDADDS)
|
||||
testorientable_LDADD = $(LDADDS)
|
||||
testoverlay_LDADD = $(LDADDS)
|
||||
testprint_LDADD = $(LDADDS)
|
||||
testpressandhold_LDADD = $(LDADDS)
|
||||
testrecentchooser_LDADD = $(LDADDS)
|
||||
testrecentchoosermenu_LDADD = $(LDADDS)
|
||||
testrichtext_LDADD = $(LDADDS)
|
||||
@@ -405,6 +411,9 @@ testprint_SOURCES = \
|
||||
testprintfileoperation.h \
|
||||
testprintfileoperation.c
|
||||
|
||||
testpressandhold_SOURCES = \
|
||||
testpressandhold.c
|
||||
|
||||
testsocket_SOURCES = \
|
||||
testsocket.c \
|
||||
testsocket_common.c
|
||||
@@ -521,6 +530,7 @@ testpixbuf_save_SOURCES = testpixbuf-save.c
|
||||
|
||||
widget_factory_SOURCES = widget-factory.c
|
||||
|
||||
testkineticscrolling_SOURCES = testkineticscrolling.c
|
||||
|
||||
EXTRA_DIST += \
|
||||
gradient1.png \
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
enum
|
||||
{
|
||||
TARGET_GTK_TREE_MODEL_ROW
|
||||
};
|
||||
|
||||
static GtkTargetEntry row_targets[] =
|
||||
{
|
||||
{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW }
|
||||
};
|
||||
|
||||
static void
|
||||
on_button_clicked (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
g_print ("Button %d clicked\n", GPOINTER_TO_INT (data));
|
||||
}
|
||||
|
||||
static void
|
||||
kinetic_scrolling (void)
|
||||
{
|
||||
GtkWidget *window, *swindow, *grid;
|
||||
GtkWidget *label;
|
||||
GtkWidget *button_grid, *button;
|
||||
GtkWidget *treeview;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkListStore *store;
|
||||
GtkWidget *textview;
|
||||
gint i;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
|
||||
g_signal_connect (window, "delete_event",
|
||||
G_CALLBACK (gtk_main_quit), NULL);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
|
||||
label = gtk_label_new ("Non scrollable widget using viewport");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_show (label);
|
||||
|
||||
label = gtk_label_new ("Scrollable widget: TreeView");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_show (label);
|
||||
|
||||
label = gtk_label_new ("Scrollable widget: TextView");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_show (label);
|
||||
|
||||
button_grid = gtk_grid_new ();
|
||||
for (i = 0; i < 80; i++)
|
||||
{
|
||||
gchar *label = g_strdup_printf ("Button number %d", i);
|
||||
|
||||
button = gtk_button_new_with_label (label);
|
||||
gtk_grid_attach (GTK_GRID (button_grid), button, 0, i, 1, 1);
|
||||
gtk_widget_set_hexpand (button, TRUE);
|
||||
gtk_widget_show (button);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (on_button_clicked),
|
||||
GINT_TO_POINTER (i));
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
swindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow),
|
||||
GTK_KINETIC_SCROLLING_ENABLED);
|
||||
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), button_grid);
|
||||
gtk_widget_show (button_grid);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), swindow, 0, 1, 1, 1);
|
||||
gtk_widget_show (swindow);
|
||||
|
||||
treeview = gtk_tree_view_new ();
|
||||
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview),
|
||||
GDK_BUTTON1_MASK,
|
||||
row_targets,
|
||||
G_N_ELEMENTS (row_targets),
|
||||
GDK_ACTION_MOVE | GDK_ACTION_COPY);
|
||||
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (treeview),
|
||||
row_targets,
|
||||
G_N_ELEMENTS (row_targets),
|
||||
GDK_ACTION_MOVE | GDK_ACTION_COPY);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
g_object_set (renderer, "editable", TRUE, NULL);
|
||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||
0, "Title",
|
||||
renderer,
|
||||
"text", 0,
|
||||
NULL);
|
||||
store = gtk_list_store_new (1, G_TYPE_STRING);
|
||||
for (i = 0; i < 80; i++)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gchar *label = g_strdup_printf ("Row number %d", i);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter, 0, label, -1);
|
||||
g_free (label);
|
||||
}
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
|
||||
g_object_unref (store);
|
||||
|
||||
swindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow),
|
||||
GTK_KINETIC_SCROLLING_ENABLED |
|
||||
GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS);
|
||||
gtk_container_add (GTK_CONTAINER (swindow), treeview);
|
||||
gtk_widget_show (treeview);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), swindow, 1, 1, 1, 1);
|
||||
gtk_widget_set_hexpand (swindow, TRUE);
|
||||
gtk_widget_set_vexpand (swindow, TRUE);
|
||||
gtk_widget_show (swindow);
|
||||
|
||||
textview = gtk_text_view_new ();
|
||||
swindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_kinetic_scrolling (GTK_SCROLLED_WINDOW (swindow),
|
||||
GTK_KINETIC_SCROLLING_ENABLED |
|
||||
GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS);
|
||||
gtk_container_add (GTK_CONTAINER (swindow), textview);
|
||||
gtk_widget_show (textview);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), swindow, 2, 1, 1, 1);
|
||||
gtk_widget_set_hexpand (swindow, TRUE);
|
||||
gtk_widget_set_vexpand (swindow, TRUE);
|
||||
gtk_widget_show (swindow);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (window), grid);
|
||||
gtk_widget_show (grid);
|
||||
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gtk_init (NULL, NULL);
|
||||
|
||||
kinetic_scrolling ();
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/* testpressandhold.c: Test application for GTK+ >= 3.2 press-n-hold code
|
||||
*
|
||||
* Copyright (C) 2007,2008 Imendio AB
|
||||
* Contact: Kristian Rietveld <kris@imendio.com>
|
||||
*
|
||||
* This work is provided "as is"; redistribution and modification
|
||||
* in whole or in part, in any medium, physical or electronic is
|
||||
* permitted without restriction.
|
||||
*
|
||||
* This work 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.
|
||||
*
|
||||
* In no event shall the authors or contributors be liable for any
|
||||
* direct, indirect, incidental, special, exemplary, or consequential
|
||||
* damages (including, but not limited to, procurement of substitute
|
||||
* goods or services; loss of use, data, or profits; or business
|
||||
* interruption) however caused and on any theory of liability, whether
|
||||
* in contract, strict liability, or tort (including negligence or
|
||||
* otherwise) arising in any way out of the use of this software, even
|
||||
* if advised of the possibility of such damage.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
press_and_hold_show_menu (GtkWidget *widget,
|
||||
GdkDevice *device)
|
||||
{
|
||||
GtkWidget *menu;
|
||||
GtkWidget *item;
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
|
||||
item = gtk_menu_item_new_with_label ("Test 1");
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
gtk_widget_show (item);
|
||||
|
||||
item = gtk_menu_item_new_with_label ("Test 2");
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
gtk_widget_show (item);
|
||||
|
||||
item = gtk_menu_item_new_with_label ("Test 3");
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
gtk_widget_show (item);
|
||||
|
||||
gtk_menu_popup_for_device (GTK_MENU (menu), device,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
1,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y,
|
||||
gpointer user_data)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case GTK_PRESS_AND_HOLD_QUERY:
|
||||
g_print ("press-and-hold-query on %s\n", gtk_widget_get_name (widget));
|
||||
break;
|
||||
|
||||
case GTK_PRESS_AND_HOLD_TRIGGER:
|
||||
g_print ("press-and-hold-trigger on %s\n", gtk_widget_get_name (widget));
|
||||
press_and_hold_show_menu (widget, device);
|
||||
break;
|
||||
|
||||
case GTK_PRESS_AND_HOLD_CANCEL:
|
||||
g_print ("press-and-hold-cancel on %s\n", gtk_widget_get_name (widget));
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GtkTreeModel *
|
||||
create_model (void)
|
||||
{
|
||||
GtkTreeStore *store;
|
||||
GtkTreeIter iter;
|
||||
|
||||
store = gtk_tree_store_new (1, G_TYPE_STRING);
|
||||
|
||||
/* A tree store with some random words ... */
|
||||
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
|
||||
0, "File Manager", -1);
|
||||
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
|
||||
0, "Gossip", -1);
|
||||
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
|
||||
0, "System Settings", -1);
|
||||
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
|
||||
0, "The GIMP", -1);
|
||||
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
|
||||
0, "Terminal", -1);
|
||||
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
|
||||
0, "Word Processor", -1);
|
||||
|
||||
return GTK_TREE_MODEL (store);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GtkWidget *label, *checkbutton, *tree_view, *entry;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Press and Hold test");
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
|
||||
g_signal_connect (window, "delete_event",
|
||||
G_CALLBACK (gtk_main_quit), NULL);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
label = gtk_button_new_with_label ("Press-n-hold me!");
|
||||
g_signal_connect (label, "press-and-hold",
|
||||
G_CALLBACK (press_and_hold), NULL);
|
||||
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
|
||||
|
||||
label = gtk_button_new_with_label ("No press and hold");
|
||||
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
|
||||
|
||||
checkbutton = gtk_check_button_new_with_label ("Checkable check button");
|
||||
g_signal_connect (checkbutton, "press-and-hold",
|
||||
G_CALLBACK (press_and_hold), NULL);
|
||||
gtk_box_pack_start (GTK_BOX (box), checkbutton, FALSE, FALSE, 0);
|
||||
|
||||
|
||||
tree_view = gtk_tree_view_new_with_model (create_model ());
|
||||
gtk_widget_set_size_request (tree_view, 200, 240);
|
||||
|
||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
|
||||
0, "Test",
|
||||
gtk_cell_renderer_text_new (),
|
||||
"text", 0,
|
||||
NULL);
|
||||
|
||||
g_signal_connect (tree_view, "press-and-hold",
|
||||
G_CALLBACK (press_and_hold), NULL);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box), tree_view, FALSE, FALSE, 0);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_entry_set_text (GTK_ENTRY (entry), "Press and hold me");
|
||||
g_signal_connect (entry, "press-and-hold",
|
||||
G_CALLBACK (press_and_hold), NULL);
|
||||
gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 0);
|
||||
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -53,6 +53,16 @@ content_height_changed (GtkSpinButton *spin_button,
|
||||
gtk_scrolled_window_set_min_content_height (swindow, (gint)value);
|
||||
}
|
||||
|
||||
static void
|
||||
kinetic_scrolling_changed (GtkToggleButton *toggle_button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkScrolledWindow *swindow = data;
|
||||
gboolean enabled = gtk_toggle_button_get_active (toggle_button);
|
||||
|
||||
gtk_scrolled_window_set_kinetic_scrolling (swindow, enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
scrollable_policy (void)
|
||||
{
|
||||
@@ -199,6 +209,13 @@ scrollable_policy (void)
|
||||
g_signal_connect (G_OBJECT (widget), "changed",
|
||||
G_CALLBACK (label_flip_changed), label);
|
||||
|
||||
/* Add Kinetic scrolling control here */
|
||||
widget = gtk_check_button_new_with_label ("Kinetic scrolling");
|
||||
gtk_widget_show (widget);
|
||||
gtk_box_pack_start (GTK_BOX (cntl), widget, TRUE, TRUE, 0);
|
||||
g_signal_connect (G_OBJECT (widget), "toggled",
|
||||
G_CALLBACK (kinetic_scrolling_changed), swindow);
|
||||
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user