Compare commits

..

1 Commits

Author SHA1 Message Date
Nelson Benítez León
571d399af5 gtkwidget: better handle when trying to focus a widget with no GtkRoot
Issue #5676 found a case where GTK tried to focus a widget with
a NULL GtkRoot. That specific case was a GtkButton which was a
GtkExpander's child, and until the GtkExpander is expanded (and
thus the GtkButton becomes visible) the button has no GtkRoot,
yet GTK tried to focus on it when GtkExpander's code called
gtk_widget_focus_child() on it.

We could change GtkExpander code to check if widget has no GtkRoot
and in that case avoid calling gtk_widget_focus_child(), but
it seems generally better to handle this at GtkWidget level so
it may cover other widgets that could misbehave in a similar way
as GtkExpander.

So in this patch:

We turn a critical message (failed assertion) into a proper warning
which informs the user about the non-allowed action.

We also make sure gtk_widget_focus_child() properly returns FALSE
when called on an unrooted widget.

Fixes #5676
2023-04-05 22:57:04 -04:00
2 changed files with 19 additions and 66 deletions

View File

@@ -213,64 +213,20 @@ gtk_uri_launcher_set_uri (GtkUriLauncher *self,
/* {{{ Async implementation */
#ifndef G_OS_WIN32
static void show_uri_done (GObject *source,
GAsyncResult *result,
gpointer data);
typedef struct {
GtkUriLauncher *launcher;
GtkWindow *window;
GCancellable *cancellable;
GTask *task;
GAsyncReadyCallback orig_callback;
gpointer orig_callback_data;
} CallbackData;
static void
free_callback_data (CallbackData *data)
{
g_clear_object (&data->launcher);
g_clear_object (&data->task);
g_clear_object (&data->window);
g_clear_object (&data->cancellable);
g_free (data);
}
static gboolean
show_uri_in_idle (CallbackData *cbdata)
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_show_uri_full (cbdata->window, cbdata->launcher->uri, GDK_CURRENT_TIME,
cbdata->cancellable, show_uri_done, cbdata->task);
G_GNUC_END_IGNORE_DEPRECATIONS
free_callback_data (cbdata);
return FALSE;
}
static void
open_done (GObject *source,
GAsyncResult *result,
gpointer data)
{
CallbackData *cbdata = (CallbackData *) data;
GTask *task = G_TASK (data);
GError *error = NULL;
if (!gtk_openuri_portal_open_uri_finish (result, &error)) {
/* DBus method failed or is not implemented,
* try again without using portal - Issue #5733 */
GTask *task;
task = g_task_new (cbdata->launcher, cbdata->cancellable,
cbdata->orig_callback, cbdata->orig_callback_data);
g_task_set_check_cancellable (task, FALSE);
g_task_set_source_tag (task, open_done);
g_clear_object (&cbdata->task);
cbdata->task = g_object_ref (task);
g_idle_add (G_SOURCE_FUNC (show_uri_in_idle), cbdata);
} else {
g_task_return_boolean (cbdata->task, TRUE);
free_callback_data (cbdata);
}
if (!gtk_openuri_portal_open_uri_finish (result, &error))
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
#endif
@@ -344,19 +300,9 @@ gtk_uri_launcher_launch (GtkUriLauncher *self,
}
#ifndef G_OS_WIN32
if (gtk_openuri_portal_is_available ()) {
CallbackData *callback_data;
callback_data = g_new (CallbackData, 1);
callback_data->launcher = g_object_ref (self);
callback_data->task = g_object_ref (task);
callback_data->window = parent ? g_object_ref (parent) : NULL;
callback_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
callback_data->orig_callback = callback;
callback_data->orig_callback_data = user_data;
gtk_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, callback_data);
} else
if (gtk_openuri_portal_is_available ())
gtk_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task);
else
#endif
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_show_uri_full (parent, self->uri, GDK_CURRENT_TIME, cancellable, show_uri_done, task);

View File

@@ -5020,6 +5020,7 @@ gtk_widget_real_focus (GtkWidget *widget,
GtkDirectionType direction)
{
GtkWidget *focus;
GtkRoot *root;
/* For focusable widgets, we want to focus the widget
* before its children. We differentiate 3 cases:
@@ -5037,7 +5038,12 @@ gtk_widget_real_focus (GtkWidget *widget,
return FALSE;
}
focus = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (widget)));
root = gtk_widget_get_root (widget);
if (!root) {
g_warning ("Attempted to focus a widget with no GtkRoot");
return FALSE;
}
focus = gtk_window_get_focus (GTK_WINDOW (root));
if (focus && gtk_widget_is_ancestor (focus, widget))
{
@@ -6883,7 +6889,8 @@ gtk_widget_child_focus (GtkWidget *widget,
if (!_gtk_widget_get_visible (widget) ||
!gtk_widget_is_sensitive (widget) ||
!gtk_widget_get_can_focus (widget))
!gtk_widget_get_can_focus (widget)||
!gtk_widget_get_root (widget))
return FALSE;
/* Emit ::focus in any case, even if focusable is FALSE,