xwayland: Set xrandr primary output

To find XWayland output that should be the primary one, iterate through all
XWayland outputs, and compare their geometry to the geometry of the primary
logical monitor.

To avoid possible race conditions (Mutter's monitor configuration already
updated, but Xrandr not yet), set the output both after Randr notifications and
after 'monitors-changed' signal.

https://gitlab.gnome.org/GNOME/mutter/-/issues/1407

Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1558>
This commit is contained in:
Aleksandr Mezin 2020-11-11 18:17:14 +06:00 committed by Marge Bot
parent 357f3250cb
commit 4f544b6362
4 changed files with 123 additions and 1 deletions

View File

@ -67,6 +67,10 @@ typedef struct
GList *x11_windows;
MetaXWaylandDnd *dnd;
gboolean has_xrandr;
int rr_event_base;
int rr_error_base;
} MetaXWaylandManager;
struct _MetaWaylandCompositor

View File

@ -36,6 +36,9 @@ meta_xwayland_complete_init (MetaDisplay *display,
void
meta_xwayland_shutdown (MetaXWaylandManager *manager);
gboolean
meta_xwayland_handle_xevent (XEvent *event);
/* wl_data_device/X11 selection interoperation */
void meta_xwayland_init_dnd (Display *xdisplay);
void meta_xwayland_shutdown_dnd (Display *xdisplay);

View File

@ -39,8 +39,10 @@
#include <linux/random.h>
#endif
#include <unistd.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xauth.h>
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-settings-private.h"
#include "core/main-private.h"
#include "meta/main.h"
@ -52,6 +54,9 @@ static int display_number_override = -1;
static void meta_xwayland_stop_xserver (MetaXWaylandManager *manager);
static void
meta_xwayland_set_primary_output (Display *xdisplay);
void
meta_xwayland_associate_window_with_surface (MetaWindow *window,
MetaWaylandSurface *surface)
@ -871,17 +876,50 @@ meta_xwayland_init (MetaXWaylandManager *manager,
return TRUE;
}
static void
monitors_changed_cb (MetaMonitorManager *monitor_manager)
{
MetaX11Display *x11_display = meta_get_display ()->x11_display;
meta_xwayland_set_primary_output (x11_display->xdisplay);
}
static void
on_x11_display_closing (MetaDisplay *display)
{
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
meta_xwayland_shutdown_dnd (xdisplay);
g_signal_handlers_disconnect_by_func (meta_monitor_manager_get (),
monitors_changed_cb,
NULL);
g_signal_handlers_disconnect_by_func (display,
on_x11_display_closing,
NULL);
}
static void
meta_xwayland_init_xrandr (MetaXWaylandManager *manager,
Display *xdisplay)
{
MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
manager->has_xrandr = XRRQueryExtension (xdisplay,
&manager->rr_event_base,
&manager->rr_error_base);
if (!manager->has_xrandr)
return;
XRRSelectInput (xdisplay, DefaultRootWindow (xdisplay),
RRCrtcChangeNotifyMask | RROutputChangeNotifyMask);
g_signal_connect (monitor_manager, "monitors-changed",
G_CALLBACK (monitors_changed_cb), NULL);
meta_xwayland_set_primary_output (xdisplay);
}
/* To be called right after connecting */
void
meta_xwayland_complete_init (MetaDisplay *display,
@ -904,6 +942,7 @@ meta_xwayland_complete_init (MetaDisplay *display,
G_CALLBACK (on_x11_display_closing), NULL);
meta_xwayland_init_dnd (xdisplay);
add_local_user_to_xhost (xdisplay);
meta_xwayland_init_xrandr (manager, xdisplay);
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
{
@ -945,3 +984,79 @@ meta_xwayland_shutdown (MetaXWaylandManager *manager)
g_clear_pointer (&manager->auth_file, g_free);
}
}
static void
meta_xwayland_set_primary_output (Display *xdisplay)
{
XRRScreenResources *resources;
MetaMonitorManager *monitor_manager;
MetaLogicalMonitor *primary_monitor;
int i;
monitor_manager = meta_monitor_manager_get ();
primary_monitor =
meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
if (!primary_monitor)
return;
resources = XRRGetScreenResourcesCurrent (xdisplay,
DefaultRootWindow (xdisplay));
if (!resources)
return;
for (i = 0; i < resources->noutput; i++)
{
RROutput output_id = resources->outputs[i];
XRROutputInfo *xrandr_output;
XRRCrtcInfo *crtc_info = NULL;
MetaRectangle crtc_geometry;
xrandr_output = XRRGetOutputInfo (xdisplay, resources, output_id);
if (!xrandr_output)
continue;
if (xrandr_output->crtc)
crtc_info = XRRGetCrtcInfo (xdisplay, resources, xrandr_output->crtc);
XRRFreeOutputInfo (xrandr_output);
if (!crtc_info)
continue;
crtc_geometry.x = crtc_info->x;
crtc_geometry.y = crtc_info->y;
crtc_geometry.width = crtc_info->width;
crtc_geometry.height = crtc_info->height;
XRRFreeCrtcInfo (crtc_info);
if (meta_rectangle_equal (&crtc_geometry, &primary_monitor->rect))
{
XRRSetOutputPrimary (xdisplay, DefaultRootWindow (xdisplay),
output_id);
break;
}
}
XRRFreeScreenResources (resources);
}
gboolean
meta_xwayland_handle_xevent (XEvent *event)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaXWaylandManager *manager = &compositor->xwayland_manager;
if (meta_xwayland_dnd_handle_event (event))
return TRUE;
if (manager->has_xrandr && event->type == manager->rr_event_base + RRNotify)
{
MetaX11Display *x11_display = meta_get_display ()->x11_display;
meta_xwayland_set_primary_output (x11_display->xdisplay);
return TRUE;
}
return FALSE;
}

View File

@ -1793,7 +1793,7 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () &&
meta_xwayland_dnd_handle_event (event))
meta_xwayland_handle_xevent (event))
{
bypass_gtk = bypass_compositor = TRUE;
goto out;