Compare commits

...

36 Commits

Author SHA1 Message Date
Matthias Clasen
4b6cef7f18 popup: Add a close keybinding, make grabs work
Making grabs work turned out to be a tricky timing thing.
We can't call move_to_rect in realize, since that will
already determine the surface type as a side-effect. Instead,
call seat_grab just-in-time in map, and call surface_show
in the grab prepare func.
2019-04-07 18:47:04 +02:00
Matthias Clasen
b9e75b8b51 popup: Use xdg-popup for relative placement
The initial placement is correct under both X and Wayland,
but a) the surface doesn't follow the parent under X when
it is moved, and it doesn't follow the attach point under
Wayland when it is resized.
2019-04-07 18:47:04 +02:00
Matthias Clasen
532aa7c4e2 widget: Don't snapshot foreign children
When snapshotting, we walk down the widget tree.
We need to skip children that have a different
root, since those will do their own snapshot.
2019-04-07 18:47:04 +02:00
Matthias Clasen
9a57f80d3f icon view accessible: Stop presenting windows
Thats really not its business.
2019-04-07 18:47:04 +02:00
Matthias Clasen
f139cf29c5 widget: Review and replace uses of get_toplevel
Now that roots can have parent widgets, we need to
carefully examine all calls of gtk_widget_get_toplevel,
and replace them with gtk_widget_get_root if we want
the nearest root, and not the ultimate end of the parent
chain.
2019-04-07 18:47:04 +02:00
Matthias Clasen
4ef6038129 testpopup: popup on demand
Add a button to show the popup.
2019-04-07 18:47:04 +02:00
Matthias Clasen
53de417dd4 popup: Miscellaneous fixes
The main fix here is that re-showing a popup now works.
2019-04-07 18:47:04 +02:00
Matthias Clasen
1f314e0373 widget: Use root pointer focus apis 2019-04-07 18:47:04 +02:00
Matthias Clasen
050d050efd main: Use root pointer focus apis 2019-04-07 18:47:04 +02:00
Matthias Clasen
321fa9a0c8 popup: Implement root pointer focus apis 2019-04-07 18:47:04 +02:00
Matthias Clasen
d21c95d2d3 window: Implement root pointer focus apis 2019-04-07 18:47:04 +02:00
Matthias Clasen
38e227b426 root: Add pointer focus apis
This copies all the private GtkWindow apis for
handling pointer focus.
2019-04-07 18:47:04 +02:00
Matthias Clasen
ce97d39785 popup: Add backdrop 2019-04-07 18:47:04 +02:00
Matthias Clasen
7647e1d279 popup: Add more keybindings
This makes Enter and Space work to activate things.
2019-04-07 18:47:04 +02:00
Matthias Clasen
72f942a6df main: Use root api for mnemonic activation 2019-04-07 18:47:04 +02:00
Matthias Clasen
2156e23751 label: Use root api for mnemonic setup 2019-04-07 18:47:04 +02:00
Matthias Clasen
b2cbf6918b popup: Implement mnemonics
Implement the root mnemonic api.
2019-04-07 18:47:04 +02:00
Matthias Clasen
27ec50e731 window: Implement root mnemonic api
Hook up the root mnemonic api to the existing
mnemonic machinery.
2019-04-07 18:47:04 +02:00
Matthias Clasen
989de7c8f5 root: Add api for mnemonics
Copy the add/remove_mnemonic and activate_key apis
from GtkWindow.
2019-04-07 18:47:04 +02:00
Matthias Clasen
867641fad8 label: Make default activation work in roots
Use the GtkRoot API when activating the default widget.
This makes things work in GtkWindow and GtkPopup.
2019-04-07 18:47:04 +02:00
Matthias Clasen
de0d313067 text: Make default activation work in roots
Use the GtkRoot API when activating the default widget.
This makes things work in GtkWindow and GtkPopup.
2019-04-07 18:47:04 +02:00
Matthias Clasen
5e2d2d0d83 widget: Make grabbing default work for roots
Use the GtkRoot api to make grabbing the default
work in roots other than GtkWindow.
2019-04-07 18:47:04 +02:00
Matthias Clasen
14617f92dd popup: Implement the GtkRoot::default-widget
Add the ::default-widget property.
2019-04-07 18:47:04 +02:00
Matthias Clasen
0075a7efee window: Implement GtkRoot::default-widget
Implement the ::default-widget property.
2019-04-07 18:47:04 +02:00
Matthias Clasen
2e76f8e464 root: Add an activate_focus api
This makes sense to parallel what GtkWindow has,
and for key bindings.
2019-04-07 18:47:04 +02:00
Matthias Clasen
143c5982bc root: Add default handling
Add a default-widget property with getter/setter
and a gtk_root_activate_default() function.
2019-04-07 18:47:04 +02:00
Matthias Clasen
fc49f0163e inspector: Show popups
This is useful for debugging.
2019-04-07 18:47:04 +02:00
Matthias Clasen
4180f1aa89 Add a way to enumerate popups
This is temporary. The ultimate goal is for popups to
appear in the tree as children of the widget they are
attached to.
2019-04-07 18:47:04 +02:00
Matthias Clasen
c2b13bded1 main: guard window-specific code paths
This was overlooked when I first tried to
make things for GtkRoot.
2019-04-07 18:47:04 +02:00
Matthias Clasen
988d958ce6 widget: guard popover-specific code paths
This is essentially a special case just for GtkPopover,
which is the last widget with a child surface.
2019-04-07 18:47:04 +02:00
Matthias Clasen
1cae68daec testpopup: Use a GtkPopup 2019-04-07 18:47:04 +02:00
Matthias Clasen
87aa844e37 Introduce GtkPopup
This is a from-scratch GtkRoot implementation
that is meant to eventually replace popovers.
2019-04-07 18:47:04 +02:00
Matthias Clasen
b1d871d26e window: Implement GtkRoot::check_resize
Hook up the existing window configure machinery
to the new idle sizer.
2019-04-07 18:47:04 +02:00
Matthias Clasen
bbc63dbae8 widget: Use the new idle sizer 2019-04-07 18:47:04 +02:00
Matthias Clasen
e8233d3db3 css: Use the new idle sizer 2019-04-07 18:47:04 +02:00
Matthias Clasen
55ddbec246 Redo the idle sizer
Move the idle sizer from GtkContainer to GtkRoot
and call it layout phase.
2019-04-07 18:47:04 +02:00
27 changed files with 1943 additions and 403 deletions

View File

@@ -614,7 +614,6 @@ static gboolean
gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
{
GtkIconViewItemAccessible *item;
GtkWidget *toplevel;
g_return_val_if_fail (GTK_IS_ICON_VIEW_ITEM_ACCESSIBLE (component), FALSE);
@@ -624,13 +623,6 @@ gtk_icon_view_item_accessible_grab_focus (AtkComponent *component)
gtk_widget_grab_focus (item->widget);
_gtk_icon_view_set_cursor_item (GTK_ICON_VIEW (item->widget), item->item, NULL);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->widget));
if (gtk_widget_is_toplevel (toplevel))
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_window_present (GTK_WINDOW (toplevel));
G_GNUC_END_IGNORE_DEPRECATIONS
}
return TRUE;
}

View File

@@ -534,12 +534,11 @@ gtk_menu_item_accessible_get_keybinding (AtkAction *action,
if (GTK_IS_MENU_BAR (parent))
{
GtkWidget *toplevel;
GtkRoot *root;
toplevel = gtk_widget_get_toplevel (parent);
if (toplevel && GTK_IS_WINDOW (toplevel))
mnemonic_modifier =
gtk_window_get_mnemonic_modifier (GTK_WINDOW (toplevel));
root = gtk_widget_get_root (parent);
if (root && GTK_IS_WINDOW (root))
mnemonic_modifier = gtk_window_get_mnemonic_modifier (GTK_WINDOW (root));
}
child = find_item_label (temp_item);

View File

@@ -171,6 +171,7 @@
#include <gtk/gtkpicture.h>
#include <gtk/gtkpopover.h>
#include <gtk/gtkpopovermenu.h>
#include <gtk/gtkpopup.h>
#include <gtk/gtkprintcontext.h>
#include <gtk/gtkprintoperation.h>
#include <gtk/gtkprintoperationpreview.h>

View File

@@ -259,16 +259,14 @@ other_application_item_activated_cb (GtkAppChooserButton *self)
{
GtkAppChooserButtonPrivate *priv = gtk_app_chooser_button_get_instance_private (self);
GtkWidget *dialog, *widget;
GtkWindow *toplevel;
GtkRoot *root;
toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)));
dialog = gtk_app_chooser_dialog_new_for_content_type (toplevel,
root = gtk_widget_get_root (GTK_WIDGET (self));
dialog = gtk_app_chooser_dialog_new_for_content_type (GTK_WINDOW (root),
GTK_DIALOG_DESTROY_WITH_PARENT,
priv->content_type);
gtk_window_set_modal (GTK_WINDOW (dialog), gtk_window_get_modal (toplevel));
gtk_app_chooser_dialog_set_heading (GTK_APP_CHOOSER_DIALOG (dialog),
priv->heading);
gtk_window_set_modal (GTK_WINDOW (dialog), gtk_window_get_modal (GTK_WINDOW (root)));
gtk_app_chooser_dialog_set_heading (GTK_APP_CHOOSER_DIALOG (dialog), priv->heading);
widget = gtk_app_chooser_dialog_get_widget (GTK_APP_CHOOSER_DIALOG (dialog));
g_object_set (widget,

View File

@@ -452,7 +452,7 @@ gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
if (!is_editable)
return NULL;
surface = gtk_widget_get_surface (gtk_widget_get_toplevel (widget));
surface = gtk_widget_get_surface (widget);
if (event)
seat = gdk_event_get_seat (event);

View File

@@ -524,7 +524,7 @@ ensure_dialog (GtkColorButton *button)
priv->cs_dialog = dialog = gtk_color_chooser_dialog_new (priv->title, NULL);
gtk_window_set_hide_on_close (GTK_WINDOW (dialog), TRUE);
if (gtk_widget_is_toplevel (parent) && GTK_IS_WINDOW (parent))
if (GTK_IS_WINDOW (parent))
{
if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (dialog)))
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));

View File

@@ -193,7 +193,7 @@ popup_edit (GtkWidget *widget,
GtkColorEditor *editor)
{
GtkWidget *popup = NULL;
GtkWidget *toplevel;
GtkRoot *root;
GtkWidget *focus;
gint position;
gint s, e;
@@ -224,8 +224,8 @@ popup_edit (GtkWidget *widget,
else if (popup)
{
dismiss_current_popup (editor);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
g_set_object (&editor->priv->popdown_focus, gtk_root_get_focus (GTK_ROOT (toplevel)));
root = gtk_widget_get_root (GTK_WIDGET (editor));
g_set_object (&editor->priv->popdown_focus, gtk_root_get_focus (root));
editor->priv->current_popup = popup;
editor->priv->popup_position = position;
gtk_widget_show (popup);

View File

@@ -85,14 +85,6 @@
* See more about implementing custom widgets at https://wiki.gnome.org/HowDoI/CustomWidgets
*/
struct _GtkContainerPrivate
{
guint resize_handler;
guint restyle_pending : 1;
};
enum {
ADD,
REMOVE,
@@ -126,7 +118,6 @@ static GQuark hadjustment_key_id;
static guint container_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkContainer, gtk_container, GTK_TYPE_WIDGET,
G_ADD_PRIVATE (GtkContainer)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_container_buildable_init))
@@ -245,10 +236,6 @@ static void
gtk_container_destroy (GtkWidget *widget)
{
GtkContainer *container = GTK_CONTAINER (widget);
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
if (priv->restyle_pending)
priv->restyle_pending = FALSE;
gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
@@ -333,113 +320,6 @@ gtk_container_remove (GtkContainer *container,
g_object_unref (container);
}
static gboolean
gtk_container_needs_idle_sizer (GtkContainer *container)
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
if (priv->restyle_pending)
return TRUE;
return gtk_widget_needs_allocate (GTK_WIDGET (container));
}
static void
gtk_container_idle_sizer (GdkFrameClock *clock,
GtkContainer *container)
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
/* We validate the style contexts in a single loop before even trying
* to handle resizes instead of doing validations inline.
* This is mostly necessary for compatibility reasons with old code,
* because both style_updated and size_allocate functions often change
* styles and so could cause infinite loops in this function.
*
* It's important to note that even an invalid style context returns
* sane values. So the result of an invalid style context will never be
* a program crash, but only a wrong layout or rendering.
*/
if (priv->restyle_pending)
{
priv->restyle_pending = FALSE;
gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (container)));
}
/* we may be invoked with a container_resize_queue of NULL, because
* queue_resize could have been adding an extra idle function while
* the queue still got processed. we better just ignore such case
* than trying to explicitly work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
if (gtk_widget_needs_allocate (GTK_WIDGET (container)))
{
if (GTK_IS_WINDOW (container))
gtk_window_check_resize (GTK_WINDOW (container));
else
g_warning ("gtk_container_idle_sizer() called on a non-window");
}
if (!gtk_container_needs_idle_sizer (container))
{
gtk_container_stop_idle_sizer (container);
}
else
{
gdk_frame_clock_request_phase (clock,
GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
}
void
gtk_container_start_idle_sizer (GtkContainer *container)
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
GdkFrameClock *clock;
if (priv->resize_handler != 0)
return;
if (!gtk_container_needs_idle_sizer (container))
return;
clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
if (clock == NULL)
return;
priv->resize_handler = g_signal_connect (clock, "layout",
G_CALLBACK (gtk_container_idle_sizer), container);
gdk_frame_clock_request_phase (clock,
GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_container_stop_idle_sizer (GtkContainer *container)
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
if (priv->resize_handler == 0)
return;
g_signal_handler_disconnect (gtk_widget_get_frame_clock (GTK_WIDGET (container)),
priv->resize_handler);
priv->resize_handler = 0;
}
void
_gtk_container_queue_restyle (GtkContainer *container)
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
g_return_if_fail (GTK_CONTAINER (container));
if (priv->restyle_pending)
return;
priv->restyle_pending = TRUE;
gtk_container_start_idle_sizer (container);
}
static GtkSizeRequestMode
gtk_container_get_request_mode (GtkWidget *widget)
{

View File

@@ -26,9 +26,6 @@
G_BEGIN_DECLS
void _gtk_container_queue_restyle (GtkContainer *container);
void gtk_container_stop_idle_sizer (GtkContainer *container);
void gtk_container_start_idle_sizer (GtkContainer *container);
void gtk_container_set_focus_child (GtkContainer *container,
GtkWidget *child);

View File

@@ -19,7 +19,7 @@
#include "gtkcsswidgetnodeprivate.h"
#include "gtkcontainerprivate.h"
#include "gtkrootprivate.h"
#include "gtkcssanimatedstyleprivate.h"
#include "gtkprivate.h"
#include "gtksettingsprivate.h"
@@ -60,7 +60,7 @@ gtk_css_widget_node_queue_callback (GtkWidget *widget,
GtkCssNode *node = user_data;
gtk_css_node_invalidate_frame_clock (node, TRUE);
_gtk_container_queue_restyle (GTK_CONTAINER (widget));
gtk_root_queue_restyle (GTK_ROOT (widget));
return G_SOURCE_CONTINUE;
}
@@ -70,8 +70,7 @@ gtk_css_widget_node_queue_validate (GtkCssNode *node)
{
GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node);
if (widget_node->widget && _gtk_widget_is_toplevel (widget_node->widget) &&
GTK_IS_CONTAINER (widget_node->widget))
if (widget_node->widget && GTK_IS_ROOT (widget_node->widget))
widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget_node->widget,
gtk_css_widget_node_queue_callback,
node,
@@ -83,10 +82,12 @@ gtk_css_widget_node_dequeue_validate (GtkCssNode *node)
{
GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node);
if (widget_node->widget && _gtk_widget_is_toplevel (widget_node->widget) &&
GTK_IS_CONTAINER (widget_node->widget))
gtk_widget_remove_tick_callback (widget_node->widget,
widget_node->validate_cb_id);
if (widget_node->validate_cb_id)
{
gtk_widget_remove_tick_callback (widget_node->widget,
widget_node->validate_cb_id);
widget_node->validate_cb_id = 0;
}
}
static void

View File

@@ -884,7 +884,7 @@ gtk_drag_begin_internal (GtkWidget *widget,
int y)
{
GtkDragSourceInfo *info;
GtkWidget *toplevel;
GtkRoot *root;
GdkDrag *drag;
double px, py;
int dx, dy;
@@ -893,9 +893,9 @@ gtk_drag_begin_internal (GtkWidget *widget,
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
device = gdk_device_get_associated_device (device);
toplevel = gtk_widget_get_toplevel (widget);
gtk_widget_translate_coordinates (widget, toplevel, x, y, &x, &y);
gdk_surface_get_device_position (gtk_widget_get_surface (toplevel),
root = gtk_widget_get_root (widget);
gtk_widget_translate_coordinates (widget, GTK_WIDGET (root), x, y, &x, &y);
gdk_surface_get_device_position (gtk_widget_get_surface (GTK_WIDGET (root)),
device,
&px, &py,
NULL);
@@ -906,7 +906,7 @@ gtk_drag_begin_internal (GtkWidget *widget,
content->widget = g_object_ref (widget);
content->formats = gdk_content_formats_ref (target_list);
drag = gdk_drag_begin (gtk_widget_get_surface (toplevel), device, GDK_CONTENT_PROVIDER (content), actions, dx, dy);
drag = gdk_drag_begin (gtk_widget_get_surface (GTK_WIDGET (root)), device, GDK_CONTENT_PROVIDER (content), actions, dx, dy);
if (drag == NULL)
{
g_object_unref (content);

View File

@@ -34,10 +34,9 @@
static void
gtk_drag_dest_realized (GtkWidget *widget)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
GtkRoot *root = gtk_widget_get_root (widget);
if (gtk_widget_is_toplevel (toplevel))
gdk_surface_register_dnd (gtk_widget_get_surface (toplevel));
gdk_surface_register_dnd (gtk_widget_get_surface (GTK_WIDGET (root)));
}
static void
@@ -45,10 +44,10 @@ gtk_drag_dest_hierarchy_changed (GtkWidget *widget,
GParamSpec *pspec,
gpointer data)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
GtkRoot *root = gtk_widget_get_root (widget);
if (gtk_widget_is_toplevel (toplevel) && gtk_widget_get_realized (toplevel))
gdk_surface_register_dnd (gtk_widget_get_surface (toplevel));
if (root && gtk_widget_get_realized (GTK_WIDGET (root)))
gdk_surface_register_dnd (gtk_widget_get_surface (GTK_WIDGET (root)));
}
static void

View File

@@ -254,7 +254,7 @@ struct _GtkLabelPrivate
{
GtkLabelSelectionInfo *select_info;
GtkWidget *mnemonic_widget;
GtkWindow *mnemonic_window;
GtkRoot *mnemonic_root;
PangoAttrList *attrs;
PangoAttrList *markup_attrs;
@@ -477,7 +477,7 @@ static void gtk_label_update_active_link (GtkWidget *widget,
static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
static void gtk_label_setup_mnemonic (GtkLabel *label,
GtkWidget *toplevel,
GtkRoot *root,
guint last_key);
static void gtk_label_drag_data_get (GtkWidget *widget,
GdkDrag *drag,
@@ -1302,7 +1302,7 @@ gtk_label_init (GtkLabel *label)
priv->attrs = NULL;
priv->mnemonic_widget = NULL;
priv->mnemonic_window = NULL;
priv->mnemonic_root = NULL;
priv->mnemonics_visible = TRUE;
}
@@ -1743,7 +1743,7 @@ gtk_label_mnemonic_activate (GtkWidget *widget,
static void
gtk_label_setup_mnemonic (GtkLabel *label,
GtkWidget *toplevel,
GtkRoot *root,
guint last_key)
{
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
@@ -1754,12 +1754,10 @@ gtk_label_setup_mnemonic (GtkLabel *label,
if (last_key != GDK_KEY_VoidSymbol)
{
if (priv->mnemonic_window)
if (priv->mnemonic_root)
{
gtk_window_remove_mnemonic (priv->mnemonic_window,
last_key,
widget);
priv->mnemonic_window = NULL;
gtk_root_remove_mnemonic (priv->mnemonic_root, last_key, widget);
priv->mnemonic_root = NULL;
}
if (mnemonic_menu)
{
@@ -1775,7 +1773,7 @@ gtk_label_setup_mnemonic (GtkLabel *label,
connect_mnemonics_visible_notify (GTK_LABEL (widget));
if (toplevel && gtk_widget_is_toplevel (toplevel))
if (root)
{
GtkWidget *menu_shell;
@@ -1792,10 +1790,8 @@ gtk_label_setup_mnemonic (GtkLabel *label,
if (!GTK_IS_MENU (menu_shell))
{
gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
priv->mnemonic_keyval,
widget);
priv->mnemonic_window = GTK_WINDOW (toplevel);
gtk_root_add_mnemonic (root, priv->mnemonic_keyval, widget);
priv->mnemonic_root = root;
}
}
@@ -1811,7 +1807,7 @@ gtk_label_root (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_label_parent_class)->root (widget);
gtk_label_setup_mnemonic (label, gtk_widget_get_toplevel (widget), priv->mnemonic_keyval);
gtk_label_setup_mnemonic (label, gtk_widget_get_root (widget), priv->mnemonic_keyval);
}
static void
@@ -2146,7 +2142,7 @@ gtk_label_recalculate (GtkLabel *label)
if (keyval != priv->mnemonic_keyval)
{
gtk_label_setup_mnemonic (label, gtk_widget_get_toplevel (GTK_WIDGET (label)), keyval);
gtk_label_setup_mnemonic (label, gtk_widget_get_root (GTK_WIDGET (label)), keyval);
g_object_notify_by_pspec (G_OBJECT (label), label_props[PROP_MNEMONIC_KEYVAL]);
}
@@ -4563,28 +4559,28 @@ static void
connect_mnemonics_visible_notify (GtkLabel *label)
{
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
GtkWidget *toplevel;
GtkRoot *root;
gboolean connected;
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
root = gtk_widget_get_root (GTK_WIDGET (label));
if (!GTK_IS_WINDOW (toplevel))
if (!GTK_IS_WINDOW (root))
return;
/* always set up this widgets initial value */
priv->mnemonics_visible =
gtk_window_get_mnemonics_visible (GTK_WINDOW (toplevel));
gtk_window_get_mnemonics_visible (GTK_WINDOW (root));
connected =
GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (toplevel), quark_mnemonics_visible_connected));
GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (root), quark_mnemonics_visible_connected));
if (!connected)
{
g_signal_connect (toplevel,
g_signal_connect (root,
"notify::mnemonics-visible",
G_CALLBACK (label_mnemonics_visible_changed),
label);
g_object_set_qdata (G_OBJECT (toplevel),
g_object_set_qdata (G_OBJECT (root),
quark_mnemonics_visible_connected,
GINT_TO_POINTER (1));
}
@@ -5875,12 +5871,10 @@ gtk_label_move_cursor (GtkLabel *label,
count > 0 ?
GTK_DIR_RIGHT : GTK_DIR_LEFT))
{
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (label));
if (toplevel)
gtk_widget_child_focus (toplevel,
count > 0 ?
GTK_DIR_RIGHT : GTK_DIR_LEFT);
if (root)
gtk_widget_child_focus (root, count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT);
}
}
else
@@ -6162,11 +6156,14 @@ gtk_label_activate_link (GtkLabel *label,
const gchar *uri)
{
GtkWidget *widget = GTK_WIDGET (label);
GtkWidget *top_level = gtk_widget_get_toplevel (widget);
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
guint32 timestamp = gtk_get_current_event_time ();
GError *error = NULL;
if (!gtk_show_uri_on_window (GTK_WINDOW (top_level), uri, timestamp, &error))
if (!GTK_IS_WINDOW (toplevel))
return;
if (!gtk_show_uri_on_window (GTK_WINDOW (toplevel), uri, timestamp, &error))
{
g_warning ("Unable to show '%s': %s", uri, error->message);
g_error_free (error);
@@ -6209,31 +6206,9 @@ gtk_label_activate_current_link (GtkLabel *label)
link = gtk_label_get_focus_link (label);
if (link)
{
emit_activate_link (label, link);
}
emit_activate_link (label, link);
else
{
GtkWidget *toplevel;
GtkWindow *window;
GtkWidget *default_widget, *focus_widget;
toplevel = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
{
window = GTK_WINDOW (toplevel);
if (window)
{
default_widget = gtk_window_get_default_widget (window);
focus_widget = gtk_root_get_focus (GTK_ROOT (window));
if (default_widget != widget &&
!(widget == focus_widget && (!default_widget || !gtk_widget_is_sensitive (default_widget))))
gtk_window_activate_default (window);
}
}
}
gtk_root_activate_default (gtk_widget_get_root (widget));
}
static GtkLabelLink *

View File

@@ -1592,7 +1592,7 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
static GtkWidget *
update_pointer_focus_state (GtkWindow *toplevel,
update_pointer_focus_state (GtkRoot *root,
GdkEvent *event,
GtkWidget *new_target)
{
@@ -1603,13 +1603,12 @@ update_pointer_focus_state (GtkWindow *toplevel,
device = gdk_event_get_device (event);
sequence = gdk_event_get_event_sequence (event);
old_target = gtk_window_lookup_pointer_focus_widget (toplevel, device, sequence);
old_target = gtk_root_lookup_pointer_focus (root, device, sequence);
if (old_target == new_target)
return old_target;
gdk_event_get_coords (event, &x, &y);
gtk_window_update_pointer_focus (toplevel, device, sequence,
new_target, x, y);
gtk_root_update_pointer_focus (root, device, sequence, new_target, x, y);
return old_target;
}
@@ -1660,8 +1659,7 @@ static GtkWidget *
handle_pointing_event (GdkEvent *event)
{
GtkWidget *target = NULL, *old_target = NULL, *event_widget;
GtkWindow *toplevel;
GtkWidget *toplevel_widget;
GtkRoot *toplevel;
GdkEventSequence *sequence;
GdkDevice *device;
gdouble x, y;
@@ -1671,11 +1669,7 @@ handle_pointing_event (GdkEvent *event)
if (!device || !gdk_event_get_coords (event, &x, &y))
return event_widget;
toplevel_widget = gtk_widget_get_toplevel (event_widget);
if (!GTK_IS_WINDOW (toplevel_widget))
return event_widget;
toplevel = GTK_WINDOW (toplevel_widget);
toplevel = gtk_widget_get_root (event_widget);
sequence = gdk_event_get_event_sequence (event);
@@ -1690,7 +1684,7 @@ handle_pointing_event (GdkEvent *event)
old_target = update_pointer_focus_state (toplevel, event, NULL);
if (event->any.type == GDK_LEAVE_NOTIFY)
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), old_target, NULL,
gtk_synthesize_crossing_events (toplevel, old_target, NULL,
event, event->crossing.mode);
break;
case GDK_ENTER_NOTIFY:
@@ -1700,30 +1694,28 @@ handle_pointing_event (GdkEvent *event)
case GDK_TOUCH_BEGIN:
case GDK_TOUCH_UPDATE:
case GDK_MOTION_NOTIFY:
target = gtk_window_lookup_pointer_focus_implicit_grab (toplevel, device, sequence);
target = gtk_root_lookup_pointer_focus_implicit_grab (toplevel, device, sequence);
if (!target)
target = gtk_widget_pick (toplevel_widget, x, y);
target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y);
if (!target)
target = toplevel_widget;
target = GTK_WIDGET (toplevel);
old_target = update_pointer_focus_state (toplevel, event, target);
if (event->any.type == GDK_MOTION_NOTIFY || event->any.type == GDK_ENTER_NOTIFY)
{
if (!gtk_window_lookup_pointer_focus_implicit_grab (toplevel, device,
sequence))
if (!gtk_root_lookup_pointer_focus_implicit_grab (toplevel, device, sequence))
{
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), old_target, target,
event, GDK_CROSSING_NORMAL);
gtk_synthesize_crossing_events (toplevel, old_target, target, event, GDK_CROSSING_NORMAL);
}
gtk_window_maybe_update_cursor (toplevel, NULL, device);
gtk_root_maybe_update_cursor (toplevel, NULL, device);
}
if (event->any.type == GDK_TOUCH_BEGIN)
gtk_window_set_pointer_focus_grab (toplevel, device, sequence, target);
gtk_root_set_pointer_focus_grab (toplevel, device, sequence, target);
/* Let it take the effective pointer focus anyway, as it may change due
* to implicit grabs.
@@ -1732,12 +1724,10 @@ handle_pointing_event (GdkEvent *event)
break;
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
target = gtk_window_lookup_effective_pointer_focus_widget (toplevel,
device,
sequence);
gtk_window_set_pointer_focus_grab (toplevel, device, sequence,
event->any.type == GDK_BUTTON_PRESS ?
target : NULL);
target = gtk_root_lookup_effective_pointer_focus (toplevel, device, sequence);
gtk_root_set_pointer_focus_grab (toplevel, device, sequence,
event->any.type == GDK_BUTTON_PRESS ?
target : NULL);
if (event->any.type == GDK_BUTTON_RELEASE)
{
@@ -1745,9 +1735,8 @@ handle_pointing_event (GdkEvent *event)
new_target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y);
if (new_target == NULL)
new_target = GTK_WIDGET (toplevel);
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), target, new_target, event,
GDK_CROSSING_UNGRAB);
gtk_window_maybe_update_cursor (toplevel, NULL, device);
gtk_synthesize_crossing_events (toplevel, target, new_target, event, GDK_CROSSING_UNGRAB);
gtk_root_maybe_update_cursor (toplevel, NULL, device);
}
set_widget_active_state (target, event->any.type == GDK_BUTTON_RELEASE);
@@ -1762,9 +1751,7 @@ handle_pointing_event (GdkEvent *event)
}
if (!target)
target = gtk_window_lookup_effective_pointer_focus_widget (toplevel,
device,
sequence);
target = gtk_root_lookup_effective_pointer_focus (toplevel, device, sequence);
return target ? target : old_target;
}
@@ -1854,7 +1841,7 @@ gtk_main_do_event (GdkEvent *event)
GtkWidget *focus_widget;
if (event->any.type == GDK_KEY_PRESS &&
gtk_window_activate_key (GTK_WINDOW (target_widget), (GdkEventKey *) event))
gtk_root_activate_key (GTK_ROOT (target_widget), (GdkEventKey *) event))
goto cleanup;
focus_widget = gtk_root_get_focus (GTK_ROOT (target_widget));
@@ -1919,7 +1906,7 @@ gtk_main_do_event (GdkEvent *event)
case GDK_DELETE:
g_object_ref (target_widget);
if (!gtk_window_group_get_current_grab (window_group) ||
gtk_widget_get_toplevel (gtk_window_group_get_current_grab (window_group)) == target_widget)
GTK_WIDGET (gtk_widget_get_root (gtk_window_group_get_current_grab (window_group))) == target_widget)
{
if (!GTK_IS_WINDOW (target_widget) ||
!gtk_window_emit_close_request (GTK_WINDOW (target_widget)))
@@ -1952,11 +1939,11 @@ gtk_main_do_event (GdkEvent *event)
case GDK_KEY_RELEASE:
/* make focus visible in a window that receives a key event */
{
GtkWidget *window;
GtkRoot *root;
window = gtk_widget_get_toplevel (grab_widget);
if (GTK_IS_WINDOW (window))
gtk_window_set_focus_visible (GTK_WINDOW (window), TRUE);
root = gtk_widget_get_root (grab_widget);
if (GTK_IS_WINDOW (root))
gtk_window_set_focus_visible (GTK_WINDOW (root), TRUE);
}
/* Catch alt press to enable auto-mnemonics;
@@ -1968,17 +1955,17 @@ gtk_main_do_event (GdkEvent *event)
!GTK_IS_MENU_SHELL (grab_widget))
{
gboolean mnemonics_visible;
GtkWidget *window;
GtkRoot *root;
mnemonics_visible = (event->any.type == GDK_KEY_PRESS);
window = gtk_widget_get_toplevel (grab_widget);
if (GTK_IS_WINDOW (window))
root = gtk_widget_get_root (grab_widget);
if (GTK_IS_WINDOW (root))
{
if (mnemonics_visible)
_gtk_window_schedule_mnemonics_visible (GTK_WINDOW (window));
_gtk_window_schedule_mnemonics_visible (GTK_WINDOW (root));
else
gtk_window_set_mnemonics_visible (GTK_WINDOW (window), FALSE);
gtk_window_set_mnemonics_visible (GTK_WINDOW (root), FALSE);
}
}
/* else fall through */

View File

@@ -31,7 +31,7 @@ target_destroyed (gpointer data,
}
GtkPointerFocus *
gtk_pointer_focus_new (GtkWindow *toplevel,
gtk_pointer_focus_new (GtkRoot *toplevel,
GtkWidget *widget,
GdkDevice *device,
GdkEventSequence *sequence,

View File

@@ -27,13 +27,13 @@ struct _GtkPointerFocus
gint ref_count;
GdkDevice *device;
GdkEventSequence *sequence;
GtkWindow *toplevel;
GtkRoot *toplevel;
GtkWidget *target; /* Unaffected by the implicit grab */
GtkWidget *grab_widget;
gdouble x, y; /* In toplevel coordinates */
};
GtkPointerFocus * gtk_pointer_focus_new (GtkWindow *toplevel,
GtkPointerFocus * gtk_pointer_focus_new (GtkRoot *toplevel,
GtkWidget *widget,
GdkDevice *device,
GdkEventSequence *sequence,

1060
gtk/gtkpopup.c Normal file

File diff suppressed because it is too large Load Diff

73
gtk/gtkpopup.h Normal file
View File

@@ -0,0 +1,73 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2019 Red Hat, Inc.
*
* Authors:
* - Matthias Clasen <mclasen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_POPUP_H__
#define __GTK_POPUP_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkbin.h>
G_BEGIN_DECLS
#define GTK_TYPE_POPUP (gtk_popup_get_type ())
#define GTK_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_POPUP, GtkPopup))
#define GTK_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_POPUP, GtkPopupClass))
#define GTK_IS_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_POPUP))
#define GTK_IS_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_POPUP))
#define GTK_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_POPUP, GtkPopupClass))
typedef struct _GtkPopup GtkPopup;
typedef struct _GtkPopupClass GtkPopupClass;
struct _GtkPopup
{
GtkBin parent;
};
struct _GtkPopupClass
{
GtkBinClass parent_class;
/* keybinding signals */
void (* activate_focus) (GtkPopup *popup);
void (* activate_default) (GtkPopup *popup);
void (* close) (GtkPopup *popup);
};
GDK_AVAILABLE_IN_ALL
GType gtk_popup_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_popup_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_popup_set_relative_to (GtkPopup *popup,
GtkWidget *relative_to);
GDK_AVAILABLE_IN_ALL
GListModel * gtk_popup_get_popups (void);
G_END_DECLS
#endif /* __GTK_POPUP_H__ */

View File

@@ -20,6 +20,8 @@
#include "config.h"
#include "gtkrootprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkwidgetprivate.h"
#include "gdk/gdk-private.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@@ -61,12 +63,69 @@ gtk_root_default_get_surface_transform (GtkRoot *self,
*y = 0;
}
static void
gtk_root_default_check_resize (GtkRoot *self)
{
}
static void
gtk_root_default_add_mnemonic (GtkRoot *self,
guint keyval,
GtkWidget *target)
{
}
static void
gtk_root_default_remove_mnemonic (GtkRoot *self,
guint keyval,
GtkWidget *target)
{
}
static gboolean
gtk_root_default_activate_key (GtkRoot *self,
GdkEventKey *event)
{
return FALSE;
}
static void
gtk_root_default_update_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target,
double x,
double y)
{
}
static void
gtk_root_default_update_pointer_focus_on_state_change (GtkRoot *root,
GtkWidget *widget)
{
}
static GtkWidget *
gtk_root_default_lookup_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return NULL;
}
static void
gtk_root_default_init (GtkRootInterface *iface)
{
iface->get_display = gtk_root_default_get_display;
iface->get_renderer = gtk_root_default_get_renderer;
iface->get_surface_transform = gtk_root_default_get_surface_transform;
iface->check_resize = gtk_root_default_check_resize;
iface->add_mnemonic = gtk_root_default_add_mnemonic;
iface->remove_mnemonic = gtk_root_default_remove_mnemonic;
iface->activate_key = gtk_root_default_activate_key;
iface->update_pointer_focus = gtk_root_default_update_pointer_focus;
iface->update_pointer_focus_on_state_change = gtk_root_default_update_pointer_focus_on_state_change;
iface->lookup_pointer_focus = gtk_root_default_lookup_pointer_focus;
g_object_interface_install_property (iface,
g_param_spec_object ("focus-widget",
@@ -74,6 +133,13 @@ gtk_root_default_init (GtkRootInterface *iface)
P_("The focus widget"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
g_object_interface_install_property (iface,
g_param_spec_object ("default-widget",
P_("Default widget"),
P_("The default widget"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
}
GdkDisplay *
@@ -186,10 +252,315 @@ gtk_root_get_focus (GtkRoot *self)
return focus;
}
/**
* gtk_root_activate_focus:
* @self: a #GtkRoot
*
* Activates the current focused widget within the root.
*
* Returns: %TRUE if a widget got activated.
**/
gboolean
gtk_root_activate_focus (GtkRoot *self)
{
GtkWidget *focus_widget;
g_return_val_if_fail (GTK_IS_ROOT (self), FALSE);
focus_widget = gtk_root_get_focus (self);
if (focus_widget && gtk_widget_is_sensitive (focus_widget))
return gtk_widget_activate (focus_widget);
return FALSE;
}
/**
* gtk_root_set_default:
* @self: a #GtkRoot
* @widget: (allow-none): widget to be the default, or %NULL
* to unset the default widget
*
* The default widget is the widget thats activated when the user
* presses Enter in a dialog (for example). This function sets or
* unsets the default widget for a #GtkRoot.
*
* When setting (rather than unsetting) the default widget it is
* generally easier to call gtk_widget_grab_default() on the widget.
* Before making a widget the default widget, you must call
* gtk_widget_set_can_default() on the widget youd like to make
* the default.
*/
void
gtk_root_set_default (GtkRoot *self,
GtkWidget *widget)
{
g_return_if_fail (GTK_IS_ROOT (self));
g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
g_object_set (self, "default-widget", widget, NULL);
}
/**
* gtk_root_get_default:
* @self: a #GtkRoot
*
* Returns the default widget for @root. See
* gtk_root_set_default() for more details.
*
* Returns: (nullable) (transfer none): the default widget, or %NULL
* if there is none
*/
GtkWidget *
gtk_root_get_default (GtkRoot *self)
{
GtkWidget *widget;
g_return_val_if_fail (GTK_IS_ROOT (self), NULL);
g_object_get (self, "default-widget", &widget, NULL);
if (widget)
g_object_unref (widget);
return widget;
}
/**
* gtk_root_activate_default:
* @self: a #GtkRoot
*
* Activates the default widget for the window, unless the current
* focused widget has been configured to receive the default action
* (see gtk_widget_set_receives_default()), in which case the
* focused widget is activated.
*
* Returns: %TRUE if a widget got activated
*/
gboolean
gtk_root_activate_default (GtkRoot *self)
{
GtkWidget *default_widget;
GtkWidget *focus_widget;
g_return_val_if_fail (GTK_IS_ROOT (self), FALSE);
default_widget = gtk_root_get_default (self);
focus_widget = gtk_root_get_focus (self);
if (default_widget && gtk_widget_is_sensitive (default_widget) &&
(!focus_widget || !gtk_widget_get_receives_default (focus_widget)))
return gtk_widget_activate (default_widget);
else if (focus_widget && gtk_widget_is_sensitive (focus_widget))
return gtk_widget_activate (focus_widget);
return FALSE;
}
guint
gtk_root_install_properties (GObjectClass *object_class,
guint first_prop)
{
g_object_class_override_property (object_class, first_prop + GTK_ROOT_PROP_FOCUS_WIDGET, "focus-widget");
g_object_class_override_property (object_class, first_prop + GTK_ROOT_PROP_DEFAULT_WIDGET, "default-widget");
return GTK_ROOT_NUM_PROPERTIES;
}
static void
gtk_root_check_resize (GtkRoot *self)
{
g_return_if_fail (GTK_IS_ROOT (self));
GTK_ROOT_GET_IFACE (self)->check_resize (self);
}
static gboolean
gtk_root_get_restyle_pending (GtkRoot *root)
{
return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (root), "restyle-pending"));
}
static void
gtk_root_set_restyle_pending (GtkRoot *root,
gboolean pending)
{
g_object_set_data (G_OBJECT (root), "restyle-pending", GINT_TO_POINTER (pending));
}
static gboolean
gtk_root_needs_layout_phase (GtkRoot *root)
{
return gtk_root_get_restyle_pending (root) ||
gtk_widget_needs_allocate (GTK_WIDGET (root));
}
static void
gtk_root_do_layout_phase (GdkFrameClock *clock,
GtkRoot *root)
{
/* We validate the style contexts in a single loop before even trying
* to handle resizes instead of doing validations inline.
* This is mostly necessary for compatibility reasons with old code,
* because both style_updated and size_allocate functions often change
* styles and so could cause infinite loops in this function.
*
* It's important to note that even an invalid style context returns
* sane values. So the result of an invalid style context will never be
* a program crash, but only a wrong layout or rendering.
*/
if (gtk_root_get_restyle_pending (root))
{
gtk_root_set_restyle_pending (root, FALSE);
gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (root)));
}
/* we may be invoked with a container_resize_queue of NULL, because
* queue_resize could have been adding an extra idle function while
* the queue still got processed. we better just ignore such case
* than trying to explicitly work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
if (gtk_widget_needs_allocate (GTK_WIDGET (root)))
gtk_root_check_resize (root);
if (!gtk_root_needs_layout_phase (root))
gtk_root_stop_layout_phase (root);
else
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_root_start_layout_phase (GtkRoot *root)
{
GdkFrameClock *clock;
guint resize_handler;
resize_handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (root), "resize-handler"));
if (resize_handler != 0)
return;
if (!gtk_root_needs_layout_phase (root))
return;
clock = gtk_widget_get_frame_clock (GTK_WIDGET (root));
if (clock == NULL)
return;
resize_handler = g_signal_connect (clock, "layout", G_CALLBACK (gtk_root_do_layout_phase), root);
g_object_set_data (G_OBJECT (root), "resize-handler", GUINT_TO_POINTER (resize_handler));
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_root_stop_layout_phase (GtkRoot *root)
{
guint resize_handler;
resize_handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (root), "resize-handler"));
if (resize_handler == 0)
return;
g_signal_handler_disconnect (gtk_widget_get_frame_clock (GTK_WIDGET (root)), resize_handler);
g_object_set_data (G_OBJECT (root), "resize-handler", NULL);
}
void
gtk_root_queue_restyle (GtkRoot *root)
{
g_return_if_fail (GTK_ROOT (root));
if (gtk_root_get_restyle_pending (root))
return;
gtk_root_set_restyle_pending (root, TRUE);
gtk_root_start_layout_phase (root);
}
void
gtk_root_add_mnemonic (GtkRoot *root,
guint keyval,
GtkWidget *target)
{
g_return_if_fail (GTK_ROOT (root));
GTK_ROOT_GET_IFACE (root)->add_mnemonic (root, keyval, target);
}
void
gtk_root_remove_mnemonic (GtkRoot *root,
guint keyval,
GtkWidget *target)
{
g_return_if_fail (GTK_ROOT (root));
GTK_ROOT_GET_IFACE (root)->remove_mnemonic (root, keyval, target);
}
gboolean
gtk_root_activate_key (GtkRoot *root,
GdkEventKey *event)
{
g_return_val_if_fail (GTK_ROOT (root), FALSE);
return GTK_ROOT_GET_IFACE (root)->activate_key (root, event);
}
void
gtk_root_update_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target,
double x,
double y)
{
GTK_ROOT_GET_IFACE (root)->update_pointer_focus (root, device, sequence, target, x, y);
}
void
gtk_root_update_pointer_focus_on_state_change (GtkRoot *root,
GtkWidget *widget)
{
GTK_ROOT_GET_IFACE (root)->update_pointer_focus_on_state_change (root, widget);
}
GtkWidget *
gtk_root_lookup_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return GTK_ROOT_GET_IFACE (root)->lookup_pointer_focus (root, device, sequence);
}
GtkWidget *
gtk_root_lookup_pointer_focus_implicit_grab (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return GTK_ROOT_GET_IFACE (root)->lookup_pointer_focus_implicit_grab (root, device, sequence);
}
GtkWidget *
gtk_root_lookup_effective_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return GTK_ROOT_GET_IFACE (root)->lookup_effective_pointer_focus (root, device, sequence);
}
void
gtk_root_set_pointer_focus_grab (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target)
{
GTK_ROOT_GET_IFACE (root)->set_pointer_focus_grab (root, device, sequence, target);
}
void
gtk_root_maybe_update_cursor (GtkRoot *root,
GtkWidget *widget,
GdkDevice *device)
{
GTK_ROOT_GET_IFACE (root)->maybe_update_cursor (root, widget, device);
}

View File

@@ -51,6 +51,45 @@ struct _GtkRootInterface
void (* get_surface_transform) (GtkRoot *root,
int *x,
int *y);
/* size allocation */
void (* check_resize) (GtkRoot *root);
/* mnemonics */
void (* add_mnemonic) (GtkRoot *root,
guint keyval,
GtkWidget *target);
void (* remove_mnemonic) (GtkRoot *root,
guint keyval,
GtkWidget *target);
gboolean (* activate_key) (GtkRoot *root,
GdkEventKey *event);
/* pointer focus */
void (* update_pointer_focus) (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target,
double x,
double y);
void (* update_pointer_focus_on_state_change) (GtkRoot *root,
GtkWidget *widget);
GtkWidget * (* lookup_pointer_focus) (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence);
GtkWidget * (* lookup_pointer_focus_implicit_grab) (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence);
GtkWidget * (* lookup_effective_pointer_focus) (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence);
void (* set_pointer_focus_grab) (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target);
void (* maybe_update_cursor) (GtkRoot *root,
GtkWidget *widget,
GdkDevice *device);
};
GDK_AVAILABLE_IN_ALL
@@ -61,6 +100,25 @@ void gtk_root_set_focus (GtkRoot *self,
GtkWidget *focus);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_root_get_focus (GtkRoot *self);
GDK_AVAILABLE_IN_ALL
gboolean gtk_root_activate_focus (GtkRoot *self);
GDK_AVAILABLE_IN_ALL
void gtk_root_set_default (GtkRoot *self,
GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_root_get_default (GtkRoot *self);
GDK_AVAILABLE_IN_ALL
gboolean gtk_root_activate_default (GtkRoot *self);
GDK_AVAILABLE_IN_ALL
void gtk_root_add_mnemonic (GtkRoot *root,
guint keyval,
GtkWidget *target);
GDK_AVAILABLE_IN_ALL
void gtk_root_remove_mnemonic (GtkRoot *root,
guint keyval,
GtkWidget *target);
G_END_DECLS

View File

@@ -5,14 +5,48 @@
G_BEGIN_DECLS
GdkDisplay * gtk_root_get_display (GtkRoot *root);
GdkDisplay * gtk_root_get_display (GtkRoot *self);
GskRenderer * gtk_root_get_renderer (GtkRoot *self);
void gtk_root_get_surface_transform (GtkRoot *self,
int *x,
int *y);
void gtk_root_queue_restyle (GtkRoot *self);
void gtk_root_start_layout_phase (GtkRoot *self);
void gtk_root_stop_layout_phase (GtkRoot *self);
gboolean gtk_root_activate_key (GtkRoot *self,
GdkEventKey *event);
void gtk_root_update_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target,
double x,
double y);
void gtk_root_update_pointer_focus_on_state_change (GtkRoot *root,
GtkWidget *widget);
GtkWidget * gtk_root_lookup_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence);
GtkWidget * gtk_root_lookup_pointer_focus_implicit_grab (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence);
GtkWidget * gtk_root_lookup_effective_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence);
void gtk_root_set_pointer_focus_grab (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target);
void gtk_root_maybe_update_cursor (GtkRoot *root,
GtkWidget *widget,
GdkDevice *device);
enum {
GTK_ROOT_PROP_FOCUS_WIDGET,
GTK_ROOT_PROP_DEFAULT_WIDGET,
GTK_ROOT_NUM_PROPERTIES
} GtkRootProperties;

View File

@@ -3845,30 +3845,9 @@ static void
gtk_text_real_activate (GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GtkWindow *window;
GtkWidget *default_widget, *focus_widget;
GtkWidget *toplevel;
GtkWidget *widget;
widget = GTK_WIDGET (self);
if (priv->activates_default)
{
toplevel = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
{
window = GTK_WINDOW (toplevel);
if (window)
{
default_widget = gtk_window_get_default_widget (window);
focus_widget = gtk_root_get_focus (GTK_ROOT (window));
if (widget != default_widget &&
!(widget == focus_widget && (!default_widget || !gtk_widget_get_sensitive (default_widget))))
gtk_window_activate_default (window);
}
}
}
gtk_root_activate_default (gtk_widget_get_root (GTK_WIDGET (self)));
}
static void

View File

@@ -56,6 +56,7 @@
#include "gtkprivate.h"
#include "gtkrenderbackgroundprivate.h"
#include "gtkrenderborderprivate.h"
#include "gtkrootprivate.h"
#include "gtkscrollable.h"
#include "gtkselection.h"
#include "gtksettingsprivate.h"
@@ -812,7 +813,9 @@ gtk_widget_real_snapshot (GtkWidget *widget,
for (child = _gtk_widget_get_first_child (widget);
child != NULL;
child = _gtk_widget_get_next_sibling (child))
gtk_widget_snapshot_child (widget, child, snapshot);
{
gtk_widget_snapshot_child (widget, child, snapshot);
}
}
static gboolean
@@ -2535,7 +2538,7 @@ _gtk_widget_emulate_press (GtkWidget *widget,
gdk_event_get_coords (event, &x, &y);
if (!gtk_widget_compute_point (event_widget,
gtk_widget_get_toplevel (event_widget),
GTK_WIDGET (gtk_widget_get_root (event_widget)),
&GRAPHENE_POINT_INIT (x, y),
&p))
return;
@@ -2997,7 +3000,7 @@ gtk_widget_unparent (GtkWidget *widget)
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GtkWidget *old_parent;
GtkWidget *old_prev_sibling;
GtkWidget *toplevel;
GtkRoot *root;
g_return_if_fail (GTK_IS_WIDGET (widget));
@@ -3010,9 +3013,9 @@ gtk_widget_unparent (GtkWidget *widget)
g_object_freeze_notify (G_OBJECT (widget));
toplevel = _gtk_widget_get_toplevel (widget);
if (_gtk_widget_is_toplevel (toplevel))
_gtk_window_unset_focus_and_default (GTK_WINDOW (toplevel), widget);
root = _gtk_widget_get_root (widget);
if (GTK_IS_WINDOW (root))
_gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget);
if (gtk_widget_get_focus_child (priv->parent) == widget)
gtk_widget_set_focus_child (priv->parent, NULL);
@@ -3035,7 +3038,7 @@ gtk_widget_unparent (GtkWidget *widget)
if (priv->root)
gtk_widget_unroot (widget);
toplevel = NULL;
root = NULL;
/* Removing a widget from a container restores the child visible
* flag to the default state, so it doesn't affect the child
@@ -3259,14 +3262,15 @@ gtk_widget_hide (GtkWidget *widget)
if (_gtk_widget_get_visible (widget))
{
GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
GtkWidget *parent;
GtkRoot *root;
g_object_ref (widget);
gtk_widget_push_verify_invariants (widget);
if (toplevel != widget && _gtk_widget_is_toplevel (toplevel))
_gtk_window_unset_focus_and_default (GTK_WINDOW (toplevel), widget);
root = _gtk_widget_get_root (widget);
if (GTK_WIDGET (root) != widget && GTK_IS_WINDOW (root))
_gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget);
/* a parent may now be expand=FALSE since we're hidden. */
if (priv->need_compute_expand ||
@@ -3309,14 +3313,11 @@ gtk_widget_real_hide (GtkWidget *widget)
static void
update_cursor_on_state_change (GtkWidget *widget)
{
GtkWidget *toplevel;
GtkRoot *root;
toplevel = gtk_widget_get_toplevel (widget);
if (!GTK_IS_WINDOW (toplevel))
return;
gtk_window_update_pointer_focus_on_state_change (GTK_WINDOW (toplevel),
widget);
root = _gtk_widget_get_root (widget);
if (root)
gtk_root_update_pointer_focus_on_state_change (root, widget);
}
/**
@@ -3599,8 +3600,8 @@ gtk_widget_connect_frame_clock (GtkWidget *widget)
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GdkFrameClock *frame_clock;
if (GTK_IS_CONTAINER (widget) && _gtk_widget_is_toplevel (widget))
gtk_container_start_idle_sizer (GTK_CONTAINER (widget));
if (GTK_IS_ROOT (widget))
gtk_root_start_layout_phase (GTK_ROOT (widget));
frame_clock = gtk_widget_get_frame_clock (widget);
@@ -3620,8 +3621,8 @@ gtk_widget_disconnect_frame_clock (GtkWidget *widget)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
if (GTK_IS_CONTAINER (widget) && _gtk_widget_is_toplevel (widget))
gtk_container_stop_idle_sizer (GTK_CONTAINER (widget));
if (GTK_IS_ROOT (widget))
gtk_root_stop_layout_phase (GTK_ROOT (widget));
gtk_css_node_invalidate_frame_clock (priv->cssnode, FALSE);
@@ -3979,14 +3980,14 @@ gtk_widget_get_frame_clock (GtkWidget *widget)
if (priv->realized)
{
/* We use gtk_widget_get_toplevel() here to make it explicit that
/* We use gtk_widget_get_root() here to make it explicit that
* the frame clock is a property of the toplevel that a widget
* is anchored to; gdk_surface_get_toplevel() will go up the
* hierarchy anyways, but should squash any funny business with
* reparenting windows and widgets.
*/
GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
GdkSurface *surface = _gtk_widget_get_surface (toplevel);
GtkRoot *root = _gtk_widget_get_root (widget);
GdkSurface *surface = _gtk_widget_get_surface (GTK_WIDGET (root));
g_assert (surface != NULL);
return gdk_surface_get_frame_clock (surface);
@@ -4255,7 +4256,8 @@ gtk_widget_allocate (GtkWidget *widget,
{
/* Still have to move the window... */
if (_gtk_widget_get_realized (widget) &&
_gtk_widget_get_has_surface (widget))
_gtk_widget_get_has_surface (widget) &&
GTK_IS_POPOVER (widget))
{
GtkAllocation window_alloc;
@@ -4431,7 +4433,7 @@ gtk_widget_translate_coordinates (GtkWidget *src_widget,
*
* Translates the given @point in @widget's coordinates to coordinates
* relative to @targets coodinate system. In order to perform this
* operation, both widgets must share a common ancestor.
* operation, both widgets must share a common root.
*
* Returns: %TRUE if the point could be determined, %FALSE on failure.
* In this case, 0 is stored in @out_point.
@@ -4467,7 +4469,8 @@ gtk_widget_real_size_allocate (GtkWidget *widget,
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
if (_gtk_widget_get_realized (widget) &&
_gtk_widget_get_has_surface (widget))
_gtk_widget_get_has_surface (widget) &&
GTK_IS_POPOVER (widget))
{
GtkAllocation window_alloc;
@@ -5384,10 +5387,11 @@ static void
gtk_widget_real_move_focus (GtkWidget *widget,
GtkDirectionType direction)
{
GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
GtkRoot *root;
if (widget != toplevel && GTK_IS_WINDOW (toplevel))
g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0, direction);
root = _gtk_widget_get_root (widget);
if (widget != GTK_WIDGET (root))
g_signal_emit (root, widget_signals[MOVE_FOCUS], 0, direction);
}
static gboolean
@@ -5510,12 +5514,10 @@ gtk_widget_has_visible_focus (GtkWidget *widget)
if (priv->has_focus)
{
GtkWidget *toplevel;
GtkRoot *root = _gtk_widget_get_root (widget);
toplevel = _gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
draw_focus = gtk_window_get_focus_visible (GTK_WINDOW (toplevel));
if (GTK_IS_WINDOW (root))
draw_focus = gtk_window_get_focus_visible (GTK_WINDOW (root));
else
draw_focus = TRUE;
}
@@ -5697,17 +5699,10 @@ _gtk_widget_set_has_default (GtkWidget *widget,
void
gtk_widget_grab_default (GtkWidget *widget)
{
GtkWidget *window;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (gtk_widget_get_can_default (widget));
window = _gtk_widget_get_toplevel (widget);
if (window && _gtk_widget_is_toplevel (window))
gtk_window_set_default (GTK_WINDOW (window), widget);
else
g_warning (G_STRLOC ": widget not within a GtkWindow");
gtk_root_set_default (gtk_widget_get_root (widget), widget);
}
/**
@@ -5810,7 +5805,8 @@ gtk_widget_device_is_shadowed (GtkWidget *widget,
GdkDevice *device)
{
GtkWindowGroup *group;
GtkWidget *grab_widget, *toplevel;
GtkWidget *grab_widget;
GtkRoot *root;
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
@@ -5818,10 +5814,10 @@ gtk_widget_device_is_shadowed (GtkWidget *widget,
if (!_gtk_widget_get_realized (widget))
return TRUE;
toplevel = _gtk_widget_get_toplevel (widget);
root = _gtk_widget_get_root (widget);
if (GTK_IS_WINDOW (toplevel))
group = gtk_window_get_group (GTK_WINDOW (toplevel));
if (GTK_IS_WINDOW (root))
group = gtk_window_get_group (GTK_WINDOW (root));
else
group = gtk_window_get_group (NULL);
@@ -6185,9 +6181,11 @@ gtk_widget_get_has_surface (GtkWidget *widget)
gboolean
gtk_widget_is_toplevel (GtkWidget *widget)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
return GTK_IS_ROOT (widget);
return priv->parent == NULL && GTK_IS_ROOT (widget);
}
/**
@@ -6360,12 +6358,6 @@ gtk_widget_reposition_after (GtkWidget *widget,
return;
}
if (_gtk_widget_is_toplevel (widget))
{
g_warning ("Can't set a parent on a toplevel widget");
return;
}
data.old_scale_factor = gtk_widget_get_scale_factor (widget);
/* keep this function in sync with gtk_menu_attach_to_widget()
@@ -7254,13 +7246,13 @@ gtk_widget_set_child_visible (GtkWidget *widget,
priv->child_visible = TRUE;
else
{
GtkWidget *toplevel;
GtkRoot *root;
priv->child_visible = FALSE;
toplevel = _gtk_widget_get_toplevel (widget);
if (toplevel != widget && _gtk_widget_is_toplevel (toplevel))
_gtk_window_unset_focus_and_default (GTK_WINDOW (toplevel), widget);
root = _gtk_widget_get_root (widget);
if (GTK_WIDGET (root) != widget && GTK_IS_WINDOW (root))
_gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget);
}
if (priv->parent && _gtk_widget_get_realized (priv->parent))
@@ -7332,7 +7324,7 @@ _gtk_widget_scale_changed (GtkWidget *widget)
gint
gtk_widget_get_scale_factor (GtkWidget *widget)
{
GtkWidget *toplevel;
GtkRoot *root;
GdkDisplay *display;
GdkMonitor *monitor;
@@ -7341,9 +7333,9 @@ gtk_widget_get_scale_factor (GtkWidget *widget)
if (_gtk_widget_get_realized (widget))
return gdk_surface_get_scale_factor (_gtk_widget_get_surface (widget));
toplevel = _gtk_widget_get_toplevel (widget);
if (toplevel && toplevel != widget)
return gtk_widget_get_scale_factor (toplevel);
root = _gtk_widget_get_root (widget);
if (root && GTK_WIDGET (root) != widget)
return gtk_widget_get_scale_factor (GTK_WIDGET (root));
/* else fall back to something that is more likely to be right than
* just returning 1:
@@ -10168,7 +10160,8 @@ _gtk_widget_buildable_finish_accelerator (GtkWidget *widget,
if (g_slist_length (accel_groups) == 0)
{
accel_group = gtk_accel_group_new ();
gtk_window_add_accel_group (GTK_WINDOW (toplevel), accel_group);
if (GTK_IS_WINDOW (toplevel))
gtk_window_add_accel_group (GTK_WINDOW (toplevel), accel_group);
}
else
{
@@ -10264,14 +10257,14 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
if (strcmp (tagname, "accelerator") == 0)
{
AccelGroupParserData *accel_data;
GtkWidget *toplevel;
GtkRoot *root;
accel_data = (AccelGroupParserData*)user_data;
g_assert (accel_data->object);
toplevel = _gtk_widget_get_toplevel (GTK_WIDGET (accel_data->object));
root = _gtk_widget_get_root (GTK_WIDGET (accel_data->object));
_gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), toplevel, user_data);
_gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), GTK_WIDGET (root), user_data);
}
else if (strcmp (tagname, "accessibility") == 0)
{
@@ -11149,6 +11142,9 @@ gtk_widget_compute_transform (GtkWidget *widget,
g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE);
g_return_val_if_fail (out_transform != NULL, FALSE);
if (widget->priv->root != target->priv->root)
return FALSE;
/* optimization for common case: parent wants coordinates of a direct child */
if (target == widget->priv->parent)
{
@@ -11698,9 +11694,9 @@ gtk_widget_set_alloc_needed (GtkWidget *widget)
if (!priv->visible)
break;
if (_gtk_widget_is_toplevel (widget))
if (GTK_IS_ROOT (widget))
{
gtk_container_start_idle_sizer (GTK_CONTAINER (widget));
gtk_root_start_layout_phase (GTK_ROOT (widget));
break;
}
@@ -13311,6 +13307,8 @@ gtk_widget_forall (GtkWidget *widget,
*
* gtk_widget_snapshot_child() takes care of translating the origin of
* @snapshot, and deciding whether the child needs to be snapshot.
*
* This function does nothing for children that are roots themselves.
**/
void
gtk_widget_snapshot_child (GtkWidget *widget,
@@ -13322,6 +13320,9 @@ gtk_widget_snapshot_child (GtkWidget *widget,
g_return_if_fail (_gtk_widget_get_parent (child) == widget);
g_return_if_fail (snapshot != NULL);
if (GTK_IS_ROOT (child))
return;
gtk_snapshot_save (snapshot);
gtk_snapshot_transform (snapshot, priv->transform);
@@ -13395,7 +13396,7 @@ gtk_widget_set_cursor (GtkWidget *widget,
GdkCursor *cursor)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GtkWidget *toplevel;
GtkRoot *root;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (cursor == NULL || GDK_IS_CURSOR (cursor));
@@ -13403,9 +13404,9 @@ gtk_widget_set_cursor (GtkWidget *widget,
if (!g_set_object (&priv->cursor, cursor))
return;
toplevel = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
gtk_window_maybe_update_cursor (GTK_WINDOW (toplevel), widget, NULL);
root = _gtk_widget_get_root (widget);
if (root)
gtk_root_maybe_update_cursor (root, widget, NULL);
g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_CURSOR]);
}

View File

@@ -2038,6 +2038,9 @@ gtk_window_set_property (GObject *object,
case LAST_ARG + GTK_ROOT_PROP_FOCUS_WIDGET:
gtk_window_set_focus (window, g_value_get_object (value));
break;
case LAST_ARG + GTK_ROOT_PROP_DEFAULT_WIDGET:
gtk_window_set_default (window, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2150,6 +2153,9 @@ gtk_window_get_property (GObject *object,
case LAST_ARG + GTK_ROOT_PROP_FOCUS_WIDGET:
g_value_set_object (value, gtk_window_get_focus (window));
break;
case LAST_ARG + GTK_ROOT_PROP_DEFAULT_WIDGET:
g_value_set_object (value, gtk_window_get_default_widget (window));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2392,12 +2398,111 @@ gtk_window_root_get_surface_transform (GtkRoot *root,
*y = margin.top + border.top + padding.top;
}
static void
gtk_window_root_check_resize (GtkRoot *root)
{
gtk_window_check_resize (GTK_WINDOW (root));
}
static void
gtk_window_root_add_mnemonic (GtkRoot *root,
guint keyval,
GtkWidget *target)
{
gtk_window_add_mnemonic (GTK_WINDOW (root), keyval, target);
}
static void
gtk_window_root_remove_mnemonic (GtkRoot *root,
guint keyval,
GtkWidget *target)
{
gtk_window_remove_mnemonic (GTK_WINDOW (root), keyval, target);
}
static gboolean
gtk_window_root_activate_key (GtkRoot *root,
GdkEventKey *event)
{
return gtk_window_activate_key (GTK_WINDOW (root), event);
}
static void
gtk_window_root_update_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *target,
double x,
double y)
{
gtk_window_update_pointer_focus (GTK_WINDOW (root), device, sequence, target, x, y);
}
static void
gtk_window_root_update_pointer_focus_on_state_change (GtkRoot *root,
GtkWidget *widget)
{
gtk_window_update_pointer_focus_on_state_change (GTK_WINDOW (root), widget);
}
static GtkWidget *
gtk_window_root_lookup_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (root), device, sequence);
}
static GtkWidget *
gtk_window_root_lookup_pointer_focus_implicit_grab (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return gtk_window_lookup_pointer_focus_implicit_grab (GTK_WINDOW (root), device, sequence);
}
static GtkWidget *
gtk_window_root_lookup_effective_pointer_focus (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence)
{
return gtk_window_lookup_effective_pointer_focus_widget (GTK_WINDOW (root), device, sequence);
}
static void
gtk_window_root_set_pointer_focus_grab (GtkRoot *root,
GdkDevice *device,
GdkEventSequence *sequence,
GtkWidget *grab_widget)
{
gtk_window_set_pointer_focus_grab (GTK_WINDOW (root), device, sequence, grab_widget);
}
static void
gtk_window_root_maybe_update_cursor (GtkRoot *root,
GtkWidget *widget,
GdkDevice *device)
{
gtk_window_maybe_update_cursor (GTK_WINDOW (root), widget, device);
}
static void
gtk_window_root_interface_init (GtkRootInterface *iface)
{
iface->get_display = gtk_window_root_get_display;
iface->get_renderer = gtk_window_root_get_renderer;
iface->get_surface_transform = gtk_window_root_get_surface_transform;
iface->check_resize = gtk_window_root_check_resize;
iface->add_mnemonic = gtk_window_root_add_mnemonic;
iface->remove_mnemonic = gtk_window_root_remove_mnemonic;
iface->activate_key = gtk_window_root_activate_key;
iface->update_pointer_focus = gtk_window_root_update_pointer_focus;
iface->update_pointer_focus_on_state_change = gtk_window_root_update_pointer_focus_on_state_change;
iface->lookup_pointer_focus = gtk_window_root_lookup_pointer_focus;
iface->lookup_pointer_focus_implicit_grab = gtk_window_root_lookup_pointer_focus_implicit_grab;
iface->lookup_effective_pointer_focus = gtk_window_root_lookup_effective_pointer_focus;
iface->set_pointer_focus_grab = gtk_window_root_set_pointer_focus_grab;
iface->maybe_update_cursor = gtk_window_root_maybe_update_cursor;
}
/**
@@ -6377,7 +6482,7 @@ gtk_window_propagate_key_event (GtkWindow *window,
while (!handled &&
focus && focus != widget &&
gtk_widget_get_toplevel (focus) == widget)
gtk_widget_get_root (focus) == GTK_ROOT (widget))
{
GtkWidget *parent;
@@ -9992,7 +10097,7 @@ gtk_window_update_pointer_focus (GtkWindow *window,
}
else if (target)
{
focus = gtk_pointer_focus_new (window, target, device, sequence, x, y);
focus = gtk_pointer_focus_new (GTK_ROOT (window), target, device, sequence, x, y);
gtk_window_add_pointer_focus (window, focus);
gtk_pointer_focus_unref (focus);
}
@@ -10052,7 +10157,7 @@ gtk_window_maybe_revoke_implicit_grab (GtkWindow *window,
focus = cur->data;
l = cur->next;
if (focus->toplevel != window)
if (GTK_WINDOW (focus->toplevel) != window)
continue;
if (device && focus->device == device &&
@@ -10081,7 +10186,7 @@ gtk_window_set_pointer_focus_grab (GtkWindow *window,
}
static void
update_cursor (GtkWindow *toplevel,
update_cursor (GtkRoot *toplevel,
GdkDevice *device,
GtkWidget *grab_widget,
GtkWidget *target)

View File

@@ -56,6 +56,7 @@
#include "gtksearchbar.h"
#include "gtksearchentry.h"
#include "gtkeventcontrollerkey.h"
#include "gtkpopup.h"
enum
{
@@ -1144,6 +1145,7 @@ create_root_model (void)
g_object_unref);
gtk_filter_list_model_set_model (filter, gtk_window_get_toplevels ());
g_list_store_append (list, filter);
g_list_store_append (list, gtk_popup_get_popups ());
g_object_unref (filter);
flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));

View File

@@ -298,6 +298,7 @@ gtk_public_sources = files([
'gtkpicture.c',
'gtkpopover.c',
'gtkpopovermenu.c',
'gtkpopup.c',
'gtkprintcontext.c',
'gtkprintoperation.c',
'gtkprintoperationpreview.c',

View File

@@ -1,58 +1,85 @@
#include <gtk/gtk.h>
static void
draw_popup (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
clicked (GtkButton *button)
{
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_paint (cr);
g_print ("Yes!\n");
}
static GtkWidget *
add_content (GtkWidget *parent)
{
GtkWidget *box, *label, *entry, *button;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
label = gtk_label_new_with_mnemonic ("_Test");
entry = gtk_entry_new ();
button = gtk_button_new_with_mnemonic ("_Yes!");
g_signal_connect (button, "clicked", G_CALLBACK (clicked), NULL);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
gtk_widget_set_can_default (button, TRUE);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
gtk_container_add (GTK_CONTAINER (box), label);
gtk_container_add (GTK_CONTAINER (box), entry);
gtk_container_add (GTK_CONTAINER (box), button);
gtk_container_add (GTK_CONTAINER (parent), box);
gtk_widget_grab_default (button);
return entry;
}
static GtkWidget *
create_popup (GtkWidget *parent)
{
GtkWidget *popup;
popup = gtk_popup_new ();
gtk_popup_set_relative_to (GTK_POPUP (popup), parent);
gtk_style_context_add_class (gtk_widget_get_style_context (popup), "background");
gtk_style_context_add_class (gtk_widget_get_style_context (popup), "frame");
add_content (popup);
return popup;
}
static void
place_popup (GtkEventControllerMotion *motion,
gdouble x,
gdouble y,
GtkWidget *popup)
toggle_popup (GtkToggleButton *button, GtkWidget *popup)
{
}
static gboolean
on_map (GtkWidget *parent)
{
GtkWidget *popup, *da;
GtkEventController *motion;
popup = gtk_window_new (GTK_WINDOW_POPUP);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_popup, NULL, NULL);
gtk_container_add (GTK_CONTAINER (popup), da);
gtk_widget_set_size_request (GTK_WIDGET (popup), 20, 20);
gtk_window_set_transient_for (GTK_WINDOW (popup), GTK_WINDOW (parent));
motion = gtk_event_controller_motion_new ();
gtk_widget_add_controller (parent, motion);
g_signal_connect (motion, "motion", G_CALLBACK (place_popup), popup);
gtk_widget_show (popup);
return FALSE;
gtk_widget_set_visible (popup, !gtk_widget_get_visible (popup));
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *entry;
GtkWidget *box;
GtkWidget *popup;
GtkWidget *button;
gtk_init ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
g_signal_connect (window, "destroy", gtk_main_quit, NULL);
g_signal_connect (window, "map", G_CALLBACK (on_map), NULL);
entry = add_content (window);
box = gtk_widget_get_parent (entry);
popup = create_popup (entry);
button = gtk_toggle_button_new_with_mnemonic ("_Popup");
g_signal_connect (button, "toggled", G_CALLBACK (toggle_popup), popup);
gtk_container_add (GTK_CONTAINER (box), button);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show (window);