forked from AuroraMiddleware/gtk
x11: implement gdk_window_apply_fullscreen_mode()
for the X11 backend using the EWMH mechanism _NET_WM_FULLSCREEN_MONITORS. https://bugzilla.gnome.org/show_bug.cgi?id=691856
This commit is contained in:
parent
54dc823d67
commit
dac6a76ef2
@ -779,12 +779,179 @@ init_xfree_xinerama (GdkScreen *screen)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
init_solaris_xinerama_indices (GdkX11Screen *x11_screen)
|
||||
{
|
||||
#ifdef HAVE_SOLARIS_XINERAMA
|
||||
XRectangle x_monitors[MAXFRAMEBUFFERS];
|
||||
unsigned char hints[16];
|
||||
gint result;
|
||||
gint monitor_num;
|
||||
gint x_n_monitors;
|
||||
gint i;
|
||||
|
||||
if (!XineramaGetState (x11_screen->xdisplay, x11_screen->screen_num))
|
||||
return FALSE;
|
||||
|
||||
result = XineramaGetInfo (x11_screen->xdisplay, x11_screen->screen_num,
|
||||
x_monitors, hints, &x_n_monitors);
|
||||
|
||||
if (result == 0)
|
||||
return FALSE;
|
||||
|
||||
|
||||
for (monitor_num = 0; monitor_num < x11_screen->n_monitors; ++monitor_num)
|
||||
{
|
||||
for (i = 0; i < x_n_monitors; ++i)
|
||||
{
|
||||
if (x11_screen->monitors[monitor_num].geometry.x == x_monitors[i].x &&
|
||||
x11_screen->monitors[monitor_num].geometry.y == x_monitors[i].y &&
|
||||
x11_screen->monitors[monitor_num].geometry.width == x_monitors[i].width &&
|
||||
x11_screen->monitors[monitor_num].geometry.height == x_monitors[i].height)
|
||||
{
|
||||
g_hash_table_insert (x11_screen->xinerama_matches,
|
||||
GINT_TO_POINTER (monitor_num),
|
||||
GINT_TO_POINTER (i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
#endif /* HAVE_SOLARIS_XINERAMA */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
init_xfree_xinerama_indices (GdkX11Screen *x11_screen)
|
||||
{
|
||||
#ifdef HAVE_XFREE_XINERAMA
|
||||
XineramaScreenInfo *x_monitors;
|
||||
gint monitor_num;
|
||||
gint x_n_monitors;
|
||||
gint i;
|
||||
|
||||
if (!XineramaIsActive (x11_screen->xdisplay))
|
||||
return FALSE;
|
||||
|
||||
x_monitors = XineramaQueryScreens (x11_screen->xdisplay, &x_n_monitors);
|
||||
if (x_n_monitors <= 0 || x_monitors == NULL)
|
||||
{
|
||||
if (x_monitors)
|
||||
XFree (x_monitors);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (monitor_num = 0; monitor_num < x11_screen->n_monitors; ++monitor_num)
|
||||
{
|
||||
for (i = 0; i < x_n_monitors; ++i)
|
||||
{
|
||||
if (x11_screen->monitors[monitor_num].geometry.x == x_monitors[i].x_org &&
|
||||
x11_screen->monitors[monitor_num].geometry.y == x_monitors[i].y_org &&
|
||||
x11_screen->monitors[monitor_num].geometry.width == x_monitors[i].width &&
|
||||
x11_screen->monitors[monitor_num].geometry.height == x_monitors[i].height)
|
||||
{
|
||||
g_hash_table_insert (x11_screen->xinerama_matches,
|
||||
GINT_TO_POINTER (monitor_num),
|
||||
GINT_TO_POINTER (i));
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree (x_monitors);
|
||||
return TRUE;
|
||||
#endif /* HAVE_XFREE_XINERAMA */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
init_xinerama_indices (GdkX11Screen *x11_screen)
|
||||
{
|
||||
int opcode, firstevent, firsterror;
|
||||
|
||||
x11_screen->xinerama_matches = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
if (XQueryExtension (x11_screen->xdisplay, "XINERAMA",
|
||||
&opcode, &firstevent, &firsterror))
|
||||
{
|
||||
x11_screen->xinerama_matches = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
/* Solaris Xinerama first, then XFree/Xorg Xinerama
|
||||
* to match the order in init_multihead()
|
||||
*/
|
||||
if (init_solaris_xinerama_indices (x11_screen) == FALSE)
|
||||
init_xfree_xinerama_indices (x11_screen);
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
_gdk_x11_screen_get_xinerama_index (GdkScreen *screen,
|
||||
gint monitor_num)
|
||||
{
|
||||
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
|
||||
gpointer val;
|
||||
|
||||
g_return_val_if_fail (monitor_num < x11_screen->n_monitors, -1);
|
||||
|
||||
if (x11_screen->xinerama_matches == NULL)
|
||||
init_xinerama_indices (x11_screen);
|
||||
|
||||
if (g_hash_table_lookup_extended (x11_screen->xinerama_matches, GINT_TO_POINTER (monitor_num), NULL, &val))
|
||||
return (GPOINTER_TO_INT(val));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
|
||||
gint *top,
|
||||
gint *bottom,
|
||||
gint *left,
|
||||
gint *right)
|
||||
{
|
||||
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
|
||||
gint top_most_pos = HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen);
|
||||
gint left_most_pos = WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen);
|
||||
gint bottom_most_pos = 0;
|
||||
gint right_most_pos = 0;
|
||||
gint monitor_num;
|
||||
|
||||
for (monitor_num = 0; monitor_num < x11_screen->n_monitors; monitor_num++)
|
||||
{
|
||||
gint monitor_x = x11_screen->monitors[monitor_num].geometry.x;
|
||||
gint monitor_y = x11_screen->monitors[monitor_num].geometry.y;
|
||||
gint monitor_max_x = monitor_x + x11_screen->monitors[monitor_num].geometry.width;
|
||||
gint monitor_max_y = monitor_y + x11_screen->monitors[monitor_num].geometry.height;
|
||||
|
||||
if (left && left_most_pos > monitor_x)
|
||||
{
|
||||
left_most_pos = monitor_x;
|
||||
*left = monitor_num;
|
||||
}
|
||||
if (right && right_most_pos < monitor_max_x)
|
||||
{
|
||||
right_most_pos = monitor_max_x;
|
||||
*right = monitor_num;
|
||||
}
|
||||
if (top && top_most_pos > monitor_y)
|
||||
{
|
||||
top_most_pos = monitor_y;
|
||||
*top = monitor_num;
|
||||
}
|
||||
if (bottom && bottom_most_pos < monitor_max_y)
|
||||
{
|
||||
bottom_most_pos = monitor_max_y;
|
||||
*bottom = monitor_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deinit_multihead (GdkScreen *screen)
|
||||
{
|
||||
GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
|
||||
|
||||
free_monitors (x11_screen->monitors, x11_screen->n_monitors);
|
||||
g_clear_pointer (&x11_screen->xinerama_matches, g_hash_table_destroy);
|
||||
|
||||
x11_screen->n_monitors = 0;
|
||||
x11_screen->monitors = NULL;
|
||||
|
@ -91,6 +91,9 @@ struct _GdkX11Screen
|
||||
|
||||
/* cache for window->translate vfunc */
|
||||
GC subwindow_gcs[32];
|
||||
|
||||
/* cache for Xinerama monitor indices */
|
||||
GHashTable *xinerama_matches;
|
||||
};
|
||||
|
||||
struct _GdkX11ScreenClass
|
||||
@ -110,6 +113,13 @@ void _gdk_x11_screen_size_changed (GdkScreen *screen,
|
||||
XEvent *event);
|
||||
void _gdk_x11_screen_process_owner_change (GdkScreen *screen,
|
||||
XEvent *event);
|
||||
gint _gdk_x11_screen_get_xinerama_index (GdkScreen *screen,
|
||||
gint monitor_num);
|
||||
void _gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
|
||||
gint *top,
|
||||
gint *bottom,
|
||||
gint *left,
|
||||
gint *right);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -97,6 +97,7 @@ const int _gdk_x11_event_mask_table[21] =
|
||||
const gint _gdk_x11_event_mask_table_size = G_N_ELEMENTS (_gdk_x11_event_mask_table);
|
||||
|
||||
/* Forward declarations */
|
||||
static void gdk_x11_window_apply_fullscreen_mode (GdkWindow *window);
|
||||
static void gdk_window_set_static_win_gravity (GdkWindow *window,
|
||||
gboolean on);
|
||||
static gboolean gdk_window_icon_name_set (GdkWindow *window);
|
||||
@ -1354,6 +1355,13 @@ gdk_window_x11_show (GdkWindow *window, gboolean already_mapped)
|
||||
|
||||
if (unset_bg)
|
||||
_gdk_x11_window_tmp_reset_bg (window, TRUE);
|
||||
|
||||
/* Fullscreen on current monitor is the default, no need to apply this mode
|
||||
* when mapping a window. This also ensures that the default behavior remains
|
||||
* consistent with pre-fullscreen mode implementation.
|
||||
*/
|
||||
if (window->fullscreen_mode != GDK_FULLSCREEN_ON_CURRENT_MONITOR)
|
||||
gdk_x11_window_apply_fullscreen_mode (window);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3625,6 +3633,99 @@ gdk_x11_window_unmaximize (GdkWindow *window)
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_window_apply_fullscreen_mode (GdkWindow *window)
|
||||
{
|
||||
if (GDK_WINDOW_DESTROYED (window) ||
|
||||
!WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
|
||||
return;
|
||||
|
||||
/* _NET_WM_FULLSCREEN_MONITORS gives an indication to the window manager as
|
||||
* to which monitors so span across when the window is fullscreen, but it's
|
||||
* not a state in itself so this would have no effect if the window is not
|
||||
* mapped.
|
||||
*/
|
||||
|
||||
if (GDK_WINDOW_IS_MAPPED (window))
|
||||
{
|
||||
XClientMessageEvent xclient;
|
||||
gint gdk_monitors[4];
|
||||
gint i;
|
||||
|
||||
memset (&xclient, 0, sizeof (xclient));
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = GDK_WINDOW_XID (window);
|
||||
xclient.display = GDK_WINDOW_XDISPLAY (window);
|
||||
xclient.format = 32;
|
||||
|
||||
switch (window->fullscreen_mode)
|
||||
{
|
||||
case GDK_FULLSCREEN_ON_CURRENT_MONITOR:
|
||||
|
||||
/* FIXME: This is not part of the EWMH spec!
|
||||
*
|
||||
* There is no documented mechanism to remove the property
|
||||
* _NET_WM_FULLSCREEN_MONITORS once set, so we use use a set of
|
||||
* invalid, largest possible value.
|
||||
*
|
||||
* When given values larger than actual possible monitor values, most
|
||||
* window managers who support the _NET_WM_FULLSCREEN_MONITORS spec
|
||||
* will simply unset _NET_WM_FULLSCREEN_MONITORS and revert to their
|
||||
* default behavior.
|
||||
*
|
||||
* Successfully tested on mutter/metacity, kwin, compiz and xfwm4.
|
||||
*
|
||||
* Note, this (non documented) mechanism is unlikely to be an issue
|
||||
* as it's used only for transitionning back from "all monitors" to
|
||||
* "current monitor" mode.
|
||||
*
|
||||
* Applications who don't change the default mode won't trigger this
|
||||
* mechanism.
|
||||
*/
|
||||
for (i = 0; i < 4; ++i)
|
||||
xclient.data.l[i] = G_MAXLONG;
|
||||
|
||||
break;
|
||||
|
||||
case GDK_FULLSCREEN_ON_ALL_MONITORS:
|
||||
|
||||
_gdk_x11_screen_get_edge_monitors (GDK_WINDOW_SCREEN (window),
|
||||
&gdk_monitors[0],
|
||||
&gdk_monitors[1],
|
||||
&gdk_monitors[2],
|
||||
&gdk_monitors[3]);
|
||||
/* Translate all 4 monitors from the GDK set into XINERAMA indices */
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
xclient.data.l[i] = _gdk_x11_screen_get_xinerama_index (GDK_WINDOW_SCREEN (window),
|
||||
gdk_monitors[i]);
|
||||
/* Sanity check, if XINERAMA is not available, we could have invalid
|
||||
* negative values for the XINERAMA indices.
|
||||
*/
|
||||
if (xclient.data.l[i] < 0)
|
||||
{
|
||||
g_warning ("gdk_x11_window_apply_fullscreen_mode: Invalid XINERAMA monitor index");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_warning ("gdk_x11_window_apply_fullscreen_mode: Unhandled fullscreen mode %d",
|
||||
window->fullscreen_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send fullscreen monitors client message */
|
||||
xclient.data.l[4] = 1; /* source indication */
|
||||
xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
|
||||
"_NET_WM_FULLSCREEN_MONITORS");
|
||||
XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
(XEvent *)&xclient);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_window_fullscreen (GdkWindow *window)
|
||||
{
|
||||
@ -3633,10 +3734,16 @@ gdk_x11_window_fullscreen (GdkWindow *window)
|
||||
return;
|
||||
|
||||
if (GDK_WINDOW_IS_MAPPED (window))
|
||||
gdk_wmspec_change_state (TRUE, window,
|
||||
gdk_atom_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
|
||||
GDK_NONE);
|
||||
|
||||
{
|
||||
gdk_wmspec_change_state (TRUE, window,
|
||||
gdk_atom_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
|
||||
GDK_NONE);
|
||||
/* Actual XRandR layout may have change since we computed the fullscreen
|
||||
* monitors in GDK_FULLSCREEN_ON_ALL_MONITORS mode.
|
||||
*/
|
||||
if (window->fullscreen_mode == GDK_FULLSCREEN_ON_ALL_MONITORS)
|
||||
gdk_x11_window_apply_fullscreen_mode (window);
|
||||
}
|
||||
else
|
||||
gdk_synthesize_window_state (window,
|
||||
0,
|
||||
@ -5022,6 +5129,7 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
|
||||
impl_class->maximize = gdk_x11_window_maximize;
|
||||
impl_class->unmaximize = gdk_x11_window_unmaximize;
|
||||
impl_class->fullscreen = gdk_x11_window_fullscreen;
|
||||
impl_class->apply_fullscreen_mode = gdk_x11_window_apply_fullscreen_mode;
|
||||
impl_class->unfullscreen = gdk_x11_window_unfullscreen;
|
||||
impl_class->set_keep_above = gdk_x11_window_set_keep_above;
|
||||
impl_class->set_keep_below = gdk_x11_window_set_keep_below;
|
||||
|
Loading…
Reference in New Issue
Block a user