mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-09 10:20:07 +00:00
gtk: Add suspended window state
This is implemented using a new xdg_toplevel `suspended` state, and is meant for allowing applications to know when they can stop doing unnecessary work and thus save power. In the other backends, the `suspended` state is set at the same time as `minimized` as it's the closest there is to traditional windowing systems.
This commit is contained in:
parent
03a8b9cf17
commit
7f946eff01
@ -85,6 +85,7 @@ typedef enum
|
||||
* @GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE: whether the bottom edge is resizable
|
||||
* @GDK_TOPLEVEL_STATE_LEFT_TILED: whether the left edge is tiled
|
||||
* @GDK_TOPLEVEL_STATE_LEFT_RESIZABLE: whether the left edge is resizable
|
||||
* @GDK_TOPLEVEL_STATE_SUSPENDED: the surface is not visible to the user
|
||||
*
|
||||
* Specifies the state of a toplevel surface.
|
||||
*
|
||||
@ -111,7 +112,8 @@ typedef enum
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_TILED = 1 << 12,
|
||||
GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE = 1 << 13,
|
||||
GDK_TOPLEVEL_STATE_LEFT_TILED = 1 << 14,
|
||||
GDK_TOPLEVEL_STATE_LEFT_RESIZABLE = 1 << 15
|
||||
GDK_TOPLEVEL_STATE_LEFT_RESIZABLE = 1 << 15,
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED = 1 << 16
|
||||
} GdkToplevelState;
|
||||
|
||||
/**
|
||||
|
@ -73,7 +73,10 @@ typedef NSString *CALayerContentsGravity;
|
||||
|
||||
-(void)windowDidMiniaturize:(NSNotification *)aNotification
|
||||
{
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_TOPLEVEL_STATE_MINIMIZED);
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface),
|
||||
0,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
}
|
||||
|
||||
-(void)windowDidDeminiaturize:(NSNotification *)aNotification
|
||||
@ -83,7 +86,10 @@ typedef NSString *CALayerContentsGravity;
|
||||
else if (GDK_IS_MACOS_POPUP_SURFACE (gdk_surface))
|
||||
_gdk_macos_popup_surface_attach_to_parent (GDK_MACOS_POPUP_SURFACE (gdk_surface));
|
||||
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_TOPLEVEL_STATE_MINIMIZED, 0);
|
||||
gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface),
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED,
|
||||
0);
|
||||
}
|
||||
|
||||
-(void)windowDidBecomeKey:(NSNotification *)aNotification
|
||||
|
@ -620,6 +620,9 @@ xdg_toplevel_configure (void *data,
|
||||
pending_state |= (GDK_TOPLEVEL_STATE_TILED |
|
||||
GDK_TOPLEVEL_STATE_LEFT_TILED);
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_SUSPENDED:
|
||||
pending_state |= GDK_TOPLEVEL_STATE_SUSPENDED;
|
||||
break;
|
||||
default:
|
||||
/* Unknown state */
|
||||
break;
|
||||
|
@ -3014,9 +3014,11 @@ gdk_event_translate (MSG *msg,
|
||||
unset_bits = 0;
|
||||
|
||||
if (IsIconic (msg->hwnd))
|
||||
set_bits |= GDK_TOPLEVEL_STATE_MINIMIZED;
|
||||
set_bits |= (GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
else
|
||||
unset_bits |= GDK_TOPLEVEL_STATE_MINIMIZED;
|
||||
unset_bits |= (GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
|
||||
if (IsZoomed (msg->hwnd))
|
||||
set_bits |= GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
|
@ -418,12 +418,18 @@ do_net_wm_state_changes (GdkSurface *surface)
|
||||
if (old_state & GDK_TOPLEVEL_STATE_MINIMIZED)
|
||||
{
|
||||
if (!toplevel->have_hidden)
|
||||
unset |= GDK_TOPLEVEL_STATE_MINIMIZED;
|
||||
{
|
||||
unset |= (GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (toplevel->have_hidden)
|
||||
set |= GDK_TOPLEVEL_STATE_MINIMIZED;
|
||||
{
|
||||
set |= (GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update edge constraints and tiling */
|
||||
@ -810,9 +816,12 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
|
||||
* the minimized bit off.
|
||||
*/
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
gdk_synthesize_surface_state (surface,
|
||||
0,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED);
|
||||
{
|
||||
gdk_synthesize_surface_state (surface,
|
||||
0,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
}
|
||||
}
|
||||
|
||||
if (surface_impl->toplevel &&
|
||||
@ -841,9 +850,12 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
|
||||
{
|
||||
/* Unset minimized if it was set */
|
||||
if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED)
|
||||
gdk_synthesize_surface_state (surface,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED,
|
||||
0);
|
||||
{
|
||||
gdk_synthesize_surface_state (surface,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED,
|
||||
0);
|
||||
}
|
||||
|
||||
if (toplevel)
|
||||
gdk_surface_thaw_updates (surface);
|
||||
|
@ -3270,7 +3270,10 @@ gdk_x11_surface_minimize (GdkSurface *surface)
|
||||
else
|
||||
{
|
||||
/* Flip our client side flag, the real work happens on map. */
|
||||
gdk_synthesize_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MINIMIZED);
|
||||
gdk_synthesize_surface_state (surface,
|
||||
0,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED);
|
||||
gdk_wmspec_change_state (TRUE, surface,
|
||||
"_NET_WM_STATE_HIDDEN",
|
||||
NULL);
|
||||
@ -3293,7 +3296,10 @@ gdk_x11_surface_unminimize (GdkSurface *surface)
|
||||
else
|
||||
{
|
||||
/* Flip our client side flag, the real work happens on map. */
|
||||
gdk_synthesize_surface_state (surface, GDK_TOPLEVEL_STATE_MINIMIZED, 0);
|
||||
gdk_synthesize_surface_state (surface,
|
||||
GDK_TOPLEVEL_STATE_MINIMIZED |
|
||||
GDK_TOPLEVEL_STATE_SUSPENDED,
|
||||
0);
|
||||
gdk_wmspec_change_state (FALSE, surface,
|
||||
"_NET_WM_STATE_HIDDEN",
|
||||
NULL);
|
||||
|
@ -238,6 +238,7 @@ typedef struct
|
||||
guint client_decorated : 1; /* Decorations drawn client-side */
|
||||
guint use_client_shadow : 1; /* Decorations use client-side shadows */
|
||||
guint maximized : 1;
|
||||
guint suspended : 1;
|
||||
guint fullscreen : 1;
|
||||
guint tiled : 1;
|
||||
|
||||
@ -300,6 +301,7 @@ enum {
|
||||
|
||||
/* Readonly properties */
|
||||
PROP_IS_ACTIVE,
|
||||
PROP_SUSPENDED,
|
||||
|
||||
/* Writeonly properties */
|
||||
PROP_STARTUP_ID,
|
||||
@ -973,6 +975,18 @@ gtk_window_class_init (GtkWindowClass *klass)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkWindow:suspended: (attributes org.gtk.Property.get=gtk_window_is_suspended)
|
||||
*
|
||||
* Whether the window is suspended.
|
||||
*
|
||||
* See [method@Gtk.Window.is_suspended] for details about what suspended means.
|
||||
*/
|
||||
window_props[PROP_SUSPENDED] =
|
||||
g_param_spec_boolean ("suspended", NULL, NULL,
|
||||
FALSE,
|
||||
GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkWindow:application: (attributes org.gtk.Property.get=gtk_window_get_application org.gtk.Property.set=gtk_window_set_application)
|
||||
*
|
||||
@ -1281,6 +1295,27 @@ gtk_window_is_fullscreen (GtkWindow *window)
|
||||
return priv->fullscreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_window_is_suspended: (attributes org.gtk.Property.get=suspended)
|
||||
* @window: a `GtkWindow`
|
||||
*
|
||||
* Retrieves the current suspended state of @window.
|
||||
*
|
||||
* A window being suspended means it's currently not visible to the user, for
|
||||
* example by being on a inactive workspace, minimized, obstructed.
|
||||
*
|
||||
* Returns: whether the window is suspended.
|
||||
*/
|
||||
gboolean
|
||||
gtk_window_is_suspended (GtkWindow *window)
|
||||
{
|
||||
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
|
||||
|
||||
return priv->suspended;
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_window_toggle_maximized (GtkWindow *window)
|
||||
{
|
||||
@ -1911,6 +1946,9 @@ gtk_window_get_property (GObject *object,
|
||||
case PROP_FULLSCREENED:
|
||||
g_value_set_boolean (value, gtk_window_is_fullscreen (window));
|
||||
break;
|
||||
case PROP_SUSPENDED:
|
||||
g_value_set_boolean (value, gtk_window_is_suspended (window));
|
||||
break;
|
||||
case PROP_FOCUS_WIDGET:
|
||||
g_value_set_object (value, gtk_window_get_focus (window));
|
||||
break;
|
||||
@ -4679,6 +4717,13 @@ surface_state_changed (GtkWidget *widget)
|
||||
g_object_notify_by_pspec (G_OBJECT (widget), window_props[PROP_MAXIMIZED]);
|
||||
}
|
||||
|
||||
if (changed_mask & GDK_TOPLEVEL_STATE_SUSPENDED)
|
||||
{
|
||||
priv->suspended = (new_surface_state & GDK_TOPLEVEL_STATE_SUSPENDED) ? TRUE : FALSE;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (widget), window_props[PROP_SUSPENDED]);
|
||||
}
|
||||
|
||||
update_edge_constraints (window, new_surface_state);
|
||||
|
||||
if (changed_mask & (GDK_TOPLEVEL_STATE_FULLSCREEN |
|
||||
|
@ -244,6 +244,9 @@ gboolean gtk_window_is_maximized (GtkWindow *window);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_window_is_fullscreen (GtkWindow *window);
|
||||
|
||||
GDK_AVAILABLE_IN_4_12
|
||||
gboolean gtk_window_is_suspended (GtkWindow *window);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_window_destroy (GtkWindow *window);
|
||||
|
||||
|
@ -18,7 +18,7 @@ harfbuzz_req = '>= 2.6.0'
|
||||
fribidi_req = '>= 1.0.6'
|
||||
cairo_req = '>= 1.14.0'
|
||||
gdk_pixbuf_req = '>= 2.30.0'
|
||||
wayland_proto_req = '>= 1.31'
|
||||
wayland_proto_req = '>= 1.32'
|
||||
wayland_req = '>= 1.21.0'
|
||||
graphene_req = '>= 1.10.0'
|
||||
epoxy_req = '>= 1.4'
|
||||
|
@ -103,6 +103,7 @@ gtk_tests = [
|
||||
['teststack'],
|
||||
['testrevealer'],
|
||||
['testrevealer2'],
|
||||
['testsuspended'],
|
||||
['testwindowsize'],
|
||||
['testpopover'],
|
||||
['listmodel'],
|
||||
|
@ -4542,6 +4542,8 @@ surface_state_callback (GdkSurface *window,
|
||||
msg = g_strconcat ((const char *)g_object_get_data (G_OBJECT (label), "title"), ": ",
|
||||
(new_state & GDK_TOPLEVEL_STATE_MINIMIZED) ?
|
||||
"minimized" : "not minimized", ", ",
|
||||
(new_state & GDK_TOPLEVEL_STATE_SUSPENDED) ?
|
||||
"suspended" : "not suspended", ", ",
|
||||
(new_state & GDK_TOPLEVEL_STATE_STICKY) ?
|
||||
"sticky" : "not sticky", ", ",
|
||||
(new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) ?
|
||||
|
46
tests/testsuspended.c
Normal file
46
tests/testsuspended.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
quit_cb (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
gboolean *done = data;
|
||||
|
||||
*done = TRUE;
|
||||
|
||||
g_main_context_wakeup (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
report_suspended_state (GtkWindow *window)
|
||||
{
|
||||
g_print ("Window is %s\n",
|
||||
gtk_window_is_suspended (window) ? "suspended" : "active");
|
||||
}
|
||||
|
||||
static void
|
||||
suspended_changed_cb (GtkWindow *window)
|
||||
{
|
||||
report_suspended_state (window);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window;
|
||||
gboolean done = FALSE;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
|
||||
g_signal_connect (window, "notify::suspended",
|
||||
G_CALLBACK (suspended_changed_cb), &done);
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
report_suspended_state (GTK_WINDOW (window));
|
||||
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user