diff --git a/src/Makefile.am b/src/Makefile.am index 5f2b10dd6..2755d15f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,8 @@ libmutter_la_SOURCES = \ core/keybindings.c \ core/keybindings-private.h \ core/main.c \ + core/monitor.c \ + core/monitor-private.h \ core/mutter-Xatomtype.h \ core/place.c \ core/place.h \ diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h new file mode 100644 index 000000000..bc1ee25e1 --- /dev/null +++ b/src/core/monitor-private.h @@ -0,0 +1,97 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * \file screen-private.h Handling of monitor configuration + * + * Managing multiple monitors + * This file contains structures and functions that handle + * multiple monitors, including reading the current configuration + * and available hardware, and applying it. + * + * This interface is private to mutter, API users should look + * at MetaScreen instead. + */ + +/* + * Copyright (C) 2001 Havoc Pennington + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_MONITOR_PRIVATE_H +#define META_MONITOR_PRIVATE_H + +#include "display-private.h" +#include +#include "stack-tracker.h" +#include "ui.h" + +#include + +typedef struct _MetaOutput MetaOutput; +typedef struct _MetaMonitorInfo MetaMonitorInfo; + +struct _MetaOutput +{ + MetaMonitorInfo *monitor; + char *name; + int width_mm; + int height_mm; + CoglSubpixelOrder subpixel_order; +}; + +struct _MetaMonitorInfo +{ + int number; + int xinerama_index; + MetaRectangle rect; + gboolean is_primary; + gboolean in_fullscreen; + float refresh_rate; + + /* The primary or first output for this crtc, 0 if we can't figure out. */ + glong output_id; +}; + +#define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ()) +#define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager)) +#define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass)) +#define META_IS_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER)) +#define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_MONITOR_MANAGER)) +#define META_MONITOR_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass)) + +typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass; +typedef struct _MetaMonitorManager MetaMonitorManager; + +GType meta_monitor_manager_get_type (void); + +void meta_monitor_manager_initialize (Display *display); +MetaMonitorManager *meta_monitor_manager_get (void); + +MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager, + int *n_infos); + +MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager, + int *n_outputs); + +int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager); + +void meta_monitor_manager_invalidate (MetaMonitorManager *manager); + +#endif diff --git a/src/core/monitor.c b/src/core/monitor.c new file mode 100644 index 000000000..05d4f2b41 --- /dev/null +++ b/src/core/monitor.c @@ -0,0 +1,356 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2001, 2002 Havoc Pennington + * Copyright (C) 2002, 2003 Red Hat Inc. + * Some ICCCM manager selection code derived from fvwm2, + * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team + * Copyright (C) 2003 Rob Adams + * Copyright (C) 2004-2006 Elijah Newren + * Copyright (C) 2013 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include + +#ifdef HAVE_RANDR +#include +#endif + +#include "monitor-private.h" + +struct _MetaMonitorManager +{ + GObject parent_instance; + + /* Outputs refers to physical screens, + while monitor_infos refer to logical ones (aka CRTC) + They can be different if two outputs are + in clone mode + */ + MetaOutput *outputs; + int primary_monitor_index; + int n_outputs; + + MetaMonitorInfo *monitor_infos; + int n_monitor_infos; + +#ifdef HAVE_RANDR + Display *xdisplay; +#endif +}; + +struct _MetaMonitorManagerClass +{ + GObjectClass parent_class; +}; + +enum { + MONITORS_CHANGED, + SIGNALS_LAST +}; + +static int signals[SIGNALS_LAST]; + +G_DEFINE_TYPE (MetaMonitorManager, meta_monitor_manager, G_TYPE_OBJECT); + +static void +make_dummy_monitor_config (MetaMonitorManager *manager) +{ + manager->monitor_infos = g_new0 (MetaMonitorInfo, 1); + manager->n_monitor_infos = 1; + + manager->monitor_infos[0].number = 0; + manager->monitor_infos[0].xinerama_index = 0; + manager->monitor_infos[0].rect.x = 0; + manager->monitor_infos[0].rect.y = 0; + if (manager->xdisplay) + { + Screen *screen = ScreenOfDisplay (manager->xdisplay, + DefaultScreen (manager->xdisplay)); + + manager->monitor_infos[0].rect.width = WidthOfScreen (screen); + manager->monitor_infos[0].rect.height = HeightOfScreen (screen); + } + else + { + manager->monitor_infos[0].rect.width = 1024; + manager->monitor_infos[0].rect.height = 768; + } + manager->monitor_infos[0].refresh_rate = 60.0f; + manager->monitor_infos[0].is_primary = TRUE; + manager->monitor_infos[0].in_fullscreen = -1; + manager->monitor_infos[0].output_id = 1; + + manager->outputs = g_new0 (MetaOutput, 1); + manager->n_outputs = 1; + + manager->outputs[0].monitor = &manager->monitor_infos[0]; + manager->outputs[0].name = g_strdup ("LVDS"); + manager->outputs[0].width_mm = 222; + manager->outputs[0].height_mm = 125; + manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; +} + +#ifdef HAVE_RANDR + +/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the + * outputs the "main". This is the one we consider "owning" the windows, so if + * the mirroring is changed to a dual monitor setup then the windows are moved to the + * crtc that now has that main output. If one of the outputs is the primary that is + * always the main, otherwise we just use the first. + */ +static void +find_main_output_for_crtc (MetaMonitorManager *manager, + XRRScreenResources *resources, + XRRCrtcInfo *crtc, + MetaMonitorInfo *info, + GArray *outputs) +{ + XRROutputInfo *output; + RROutput primary_output; + int i; + + primary_output = XRRGetOutputPrimary (manager->xdisplay, + DefaultRootWindow (manager->xdisplay)); + + for (i = 0; i < crtc->noutput; i++) + { + output = XRRGetOutputInfo (manager->xdisplay, resources, crtc->outputs[i]); + + if (output->connection != RR_Disconnected) + { + MetaOutput meta_output; + + meta_output.name = g_strdup (output->name); + meta_output.width_mm = output->mm_width; + meta_output.height_mm = output->mm_height; + meta_output.subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + + g_array_append_val (outputs, meta_output); + + if (crtc->outputs[i] == primary_output) + { + info->output_id = crtc->outputs[i]; + info->is_primary = TRUE; + manager->primary_monitor_index = info->number; + } + else if (info->output_id == 0) + { + info->output_id = crtc->outputs[i]; + } + } + + XRRFreeOutputInfo (output); + } +} + +static void +read_monitor_infos_from_xrandr (MetaMonitorManager *manager) +{ + XRRScreenResources *resources; + GArray *outputs; + int i, j; + + resources = XRRGetScreenResourcesCurrent (manager->xdisplay, + DefaultRootWindow (manager->xdisplay)); + if (!resources) + return make_dummy_monitor_config (manager); + + outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput)); + + manager->n_outputs = 0; + manager->n_monitor_infos = resources->ncrtc; + + manager->monitor_infos = g_new0 (MetaMonitorInfo, manager->n_monitor_infos); + + for (i = 0; i < resources->ncrtc; i++) + { + XRRCrtcInfo *crtc; + MetaMonitorInfo *info; + + crtc = XRRGetCrtcInfo (manager->xdisplay, resources, resources->crtcs[i]); + + info = &manager->monitor_infos[i]; + + info->number = i; + info->rect.x = crtc->x; + info->rect.y = crtc->y; + info->rect.width = crtc->width; + info->rect.height = crtc->height; + info->in_fullscreen = -1; + + for (j = 0; j < resources->nmode; j++) + { + if (resources->modes[j].id == crtc->mode) + info->refresh_rate = (resources->modes[j].dotClock / + ((float)resources->modes[j].hTotal * + resources->modes[j].vTotal)); + } + + find_main_output_for_crtc (manager, resources, crtc, info, outputs); + + XRRFreeCrtcInfo (crtc); + } + + manager->n_outputs = outputs->len; + manager->outputs = (void*)g_array_free (outputs, FALSE); + + XRRFreeScreenResources (resources); +} + +#endif + +/* + * meta_has_dummy_output: + * + * Returns TRUE if the only available monitor is the dummy one + * backing the ClutterStage window. + */ +static gboolean +has_dummy_output (void) +{ + return FALSE; +} + +static void +meta_monitor_manager_init (MetaMonitorManager *manager) +{ +} + +static void +read_current_config (MetaMonitorManager *manager) +{ + if (has_dummy_output ()) + return make_dummy_monitor_config (manager); + +#ifdef HAVE_RANDR + return read_monitor_infos_from_xrandr (manager); +#endif +} + +static MetaMonitorManager * +meta_monitor_manager_new (Display *display) +{ + MetaMonitorManager *manager; + + manager = g_object_new (META_TYPE_MONITOR_MANAGER, NULL); + + manager->xdisplay = display; + + read_current_config (manager); + return manager; +} + +static void +free_output_array (MetaOutput *old_outputs, + int n_old_outputs) +{ + int i; + + for (i = 0; i < n_old_outputs; i++) + g_free (old_outputs[i].name); + g_free (old_outputs); +} + +static void +meta_monitor_manager_finalize (GObject *object) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (object); + + free_output_array (manager->outputs, manager->n_outputs); + g_free (manager->monitor_infos); + + G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object); +} + +static void +meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_monitor_manager_finalize; + + signals[MONITORS_CHANGED] = + g_signal_new ("monitors-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static MetaMonitorManager *global_manager; + +void +meta_monitor_manager_initialize (Display *display) +{ + global_manager = meta_monitor_manager_new (display); +} + +MetaMonitorManager * +meta_monitor_manager_get (void) +{ + g_assert (global_manager != NULL); + + return global_manager; +} + +MetaMonitorInfo * +meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager, + int *n_infos) +{ + *n_infos = manager->n_monitor_infos; + return manager->monitor_infos; +} + +MetaOutput * +meta_monitor_manager_get_outputs (MetaMonitorManager *manager, + int *n_outputs) +{ + *n_outputs = manager->n_outputs; + return manager->outputs; +} + +int +meta_monitor_manager_get_primary_index (MetaMonitorManager *manager) +{ + return manager->primary_monitor_index; +} + +void +meta_monitor_manager_invalidate (MetaMonitorManager *manager) +{ + MetaOutput *old_outputs; + MetaMonitorInfo *old_monitor_infos; + int n_old_outputs; + + /* Save the old monitor infos, so they stay valid during the update */ + old_outputs = manager->outputs; + n_old_outputs = manager->n_outputs; + old_monitor_infos = manager->monitor_infos; + + read_current_config (manager); + + g_signal_emit (manager, signals[MONITORS_CHANGED], 0); + + g_free (old_monitor_infos); + free_output_array (old_outputs, n_old_outputs); +} + diff --git a/src/core/screen-private.h b/src/core/screen-private.h index 83adb8317..894eda5e4 100644 --- a/src/core/screen-private.h +++ b/src/core/screen-private.h @@ -38,17 +38,7 @@ #include #include "stack-tracker.h" #include "ui.h" - -typedef struct _MetaMonitorInfo MetaMonitorInfo; - -struct _MetaMonitorInfo -{ - int number; - MetaRectangle rect; - gboolean is_primary; - gboolean in_fullscreen; - XID output; /* The primary or first output for this crtc, None if no xrandr */ -}; +#include "monitor-private.h" typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window, gpointer user_data); @@ -100,10 +90,11 @@ struct _MetaScreen Window wm_sn_selection_window; Atom wm_sn_atom; guint32 wm_sn_timestamp; - + MetaMonitorInfo *monitor_infos; - int primary_monitor_index; int n_monitor_infos; + int primary_monitor_index; + gboolean has_xinerama_indices; /* Cache the current monitor */ int last_monitor_index; @@ -257,4 +248,9 @@ void meta_screen_workspace_switched (MetaScreen *screen, void meta_screen_set_active_workspace_hint (MetaScreen *screen); +int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen, + int index); +int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, + int index); + #endif diff --git a/src/core/screen.c b/src/core/screen.c index 6db3ea385..cb02f201b 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -48,10 +48,6 @@ #include -#ifdef HAVE_RANDR -#include -#endif - #include #include #include @@ -76,6 +72,9 @@ static void meta_screen_sn_event (SnMonitorEvent *event, void *user_data); #endif +static void on_monitors_changed (MetaMonitorManager *manager, + MetaScreen *screen); + enum { PROP_N_WORKSPACES = 1, @@ -350,250 +349,93 @@ set_wm_icon_size_hint (MetaScreen *screen) #undef N_VALS } -/* The list of monitors reported by the windowing system might include - * mirrored monitors with identical bounds. Since mirrored monitors - * shouldn't be treated as separate monitors for most purposes, we - * filter them out here. (We ignore the possibility of partially - * overlapping monitors because they are rare and it's hard to come - * up with any sensible interpretation.) - */ static void -filter_mirrored_monitors (MetaScreen *screen) +meta_screen_ensure_xinerama_indices (MetaScreen *screen) { - int i, j; + XineramaScreenInfo *infos; + int n_infos, i, j; - /* Currently always true and simplifies things */ - g_assert (screen->primary_monitor_index == 0); + if (screen->has_xinerama_indices) + return; - for (i = 1; i < screen->n_monitor_infos; i++) + screen->has_xinerama_indices = TRUE; + + if (!XineramaIsActive (screen->display->xdisplay)) + return; + + infos = XineramaQueryScreens (screen->display->xdisplay, &n_infos); + if (n_infos <= 0 || infos == NULL) { - /* In case we've filtered previous monitors */ - screen->monitor_infos[i].number = i; + meta_XFree (infos); + return; + } - for (j = 0; j < i; j++) + for (i = 0; i < screen->n_monitor_infos; ++i) + { + for (j = 0; j < n_infos; ++j) { - if (meta_rectangle_equal (&screen->monitor_infos[i].rect, - &screen->monitor_infos[j].rect)) - { - memmove (&screen->monitor_infos[i], - &screen->monitor_infos[i + 1], - (screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo)); - screen->n_monitor_infos--; - i--; - - continue; - } + if (screen->monitor_infos[i].rect.x == infos[j].x_org && + screen->monitor_infos[i].rect.y == infos[j].y_org && + screen->monitor_infos[i].rect.width == infos[j].width && + screen->monitor_infos[i].rect.height == infos[j].height) + screen->monitor_infos[i].xinerama_index = j; } } + + meta_XFree (infos); } -#ifdef HAVE_RANDR -static MetaMonitorInfo * -find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h) +int +meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen, + int index) +{ + meta_screen_ensure_xinerama_indices (screen); + + return screen->monitor_infos[index].xinerama_index; +} + +int +meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen, + int index) { - MetaMonitorInfo *info; int i; + meta_screen_ensure_xinerama_indices (screen); + for (i = 0; i < screen->n_monitor_infos; i++) - { - info = &screen->monitor_infos[i]; - if (x == info->rect.x && - y == info->rect.y && - w == info->rect.width && - h == info->rect.height) - return info; - } - return NULL; + if (screen->monitor_infos[i].xinerama_index == index) + return i; + + return -1; } -/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the - * outputs the "main". This is the one we consider "owning" the windows, so if - * the mirroring is changed to a dual monitor setup then the windows are moved to the - * crtc that now has that main output. If one of the outputs is the primary that is - * always the main, otherwise we just use the first. - */ -static XID -find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc) -{ - XRROutputInfo *output; - RROutput primary_output; - int i; - XID res; - - primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot); - - res = None; - for (i = 0; i < crtc->noutput; i++) - { - output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]); - if (output->connection != RR_Disconnected && - (res == None || crtc->outputs[i] == primary_output)) - res = crtc->outputs[i]; - XRRFreeOutputInfo (output); - } - - return res; -} - -#endif - static void reload_monitor_infos (MetaScreen *screen) { - MetaDisplay *display; + GList *tmp; + MetaMonitorManager *manager; - { - GList *tmp; + tmp = screen->workspaces; + while (tmp != NULL) + { + MetaWorkspace *space = tmp->data; - tmp = screen->workspaces; - while (tmp != NULL) - { - MetaWorkspace *space = tmp->data; + meta_workspace_invalidate_work_area (space); + + tmp = tmp->next; + } - meta_workspace_invalidate_work_area (space); - - tmp = tmp->next; - } - } + /* Any previous screen->monitor_infos or screen->outputs is freed by the caller */ - display = screen->display; - - /* Any previous screen->monitor_infos is freed by the caller */ - - screen->monitor_infos = NULL; - screen->n_monitor_infos = 0; screen->last_monitor_index = 0; - - /* Xinerama doesn't have a concept of primary monitor, however XRandR - * does. However, the XRandR xinerama compat code always sorts the - * primary output first, so we rely on that here. We could use the - * native XRandR calls instead of xinerama, but that would be - * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as - * that is defined in terms of xinerama monitor indexes. - * So, since we don't need anything in xrandr except the primary - * we can keep using xinerama and use the first monitor as the - * primary. - */ - screen->primary_monitor_index = 0; - + screen->has_xinerama_indices = FALSE; screen->display->monitor_cache_invalidated = TRUE; - if (g_getenv ("MUTTER_DEBUG_XINERAMA")) - { - meta_topic (META_DEBUG_XINERAMA, - "Pretending a single monitor has two Xinerama screens\n"); + manager = meta_monitor_manager_get (); - screen->monitor_infos = g_new0 (MetaMonitorInfo, 2); - screen->n_monitor_infos = 2; - - screen->monitor_infos[0].number = 0; - screen->monitor_infos[0].rect = screen->rect; - screen->monitor_infos[0].rect.width = screen->rect.width / 2; - screen->monitor_infos[0].in_fullscreen = -1; - - screen->monitor_infos[1].number = 1; - screen->monitor_infos[1].rect = screen->rect; - screen->monitor_infos[1].rect.x = screen->rect.width / 2; - screen->monitor_infos[1].rect.width = screen->rect.width / 2; - screen->monitor_infos[0].in_fullscreen = -1; - } - - if (screen->n_monitor_infos == 0 && - XineramaIsActive (display->xdisplay)) - { - XineramaScreenInfo *infos; - int n_infos; - int i; - - n_infos = 0; - infos = XineramaQueryScreens (display->xdisplay, &n_infos); - - meta_topic (META_DEBUG_XINERAMA, - "Found %d Xinerama screens on display %s\n", - n_infos, display->name); - - if (n_infos > 0) - { - screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos); - screen->n_monitor_infos = n_infos; - - i = 0; - while (i < n_infos) - { - screen->monitor_infos[i].number = infos[i].screen_number; - screen->monitor_infos[i].rect.x = infos[i].x_org; - screen->monitor_infos[i].rect.y = infos[i].y_org; - screen->monitor_infos[i].rect.width = infos[i].width; - screen->monitor_infos[i].rect.height = infos[i].height; - screen->monitor_infos[i].in_fullscreen = -1; - - meta_topic (META_DEBUG_XINERAMA, - "Monitor %d is %d,%d %d x %d\n", - screen->monitor_infos[i].number, - screen->monitor_infos[i].rect.x, - screen->monitor_infos[i].rect.y, - screen->monitor_infos[i].rect.width, - screen->monitor_infos[i].rect.height); - - ++i; - } - } - - meta_XFree (infos); - -#ifdef HAVE_RANDR - { - XRRScreenResources *resources; - - resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot); - if (resources) - { - for (i = 0; i < resources->ncrtc; i++) - { - XRRCrtcInfo *crtc; - MetaMonitorInfo *info; - - crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]); - info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height); - if (info) - info->output = find_main_output_for_crtc (screen, resources, crtc); - - XRRFreeCrtcInfo (crtc); - } - XRRFreeScreenResources (resources); - } - } -#endif - } - else if (screen->n_monitor_infos > 0) - { - meta_topic (META_DEBUG_XINERAMA, - "No Xinerama extension or Xinerama inactive on display %s\n", - display->name); - } - - /* If no Xinerama, fill in the single screen info so - * we can use the field unconditionally - */ - if (screen->n_monitor_infos == 0) - { - meta_topic (META_DEBUG_XINERAMA, - "No Xinerama screens, using default screen info\n"); - - screen->monitor_infos = g_new0 (MetaMonitorInfo, 1); - screen->n_monitor_infos = 1; - - screen->monitor_infos[0].number = 0; - screen->monitor_infos[0].rect = screen->rect; - screen->monitor_infos[0].in_fullscreen = -1; - } - - filter_mirrored_monitors (screen); - - screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE; - - g_assert (screen->n_monitor_infos > 0); - g_assert (screen->monitor_infos != NULL); + screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager, + &screen->n_monitor_infos); + screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager); } /* The guard window allows us to leave minimized windows mapped so @@ -852,11 +694,17 @@ meta_screen_new (MetaDisplay *display, screen->compositor_data = NULL; screen->guard_window = None; - screen->monitor_infos = NULL; - screen->n_monitor_infos = 0; - screen->last_monitor_index = 0; - - reload_monitor_infos (screen); + { + MetaMonitorManager *manager; + + meta_monitor_manager_initialize (screen->display->xdisplay); + + reload_monitor_infos (screen); + + manager = meta_monitor_manager_get (); + g_signal_connect (manager, "monitors-changed", + G_CALLBACK (on_monitors_changed), screen); + } meta_screen_set_cursor (screen, META_CURSOR_DEFAULT); @@ -941,7 +789,7 @@ meta_screen_new (MetaDisplay *display, meta_verbose ("Added screen %d ('%s') root 0x%lx\n", screen->number, screen->screen_name, screen->xroot); - + return screen; } @@ -3002,14 +2850,17 @@ meta_screen_resize (MetaScreen *screen, int width, int height) { - GSList *windows, *tmp; - MetaMonitorInfo *old_monitor_infos; - screen->rect.width = width; screen->rect.height = height; - /* Save the old monitor infos, so they stay valid during the update */ - old_monitor_infos = screen->monitor_infos; + meta_monitor_manager_invalidate (meta_monitor_manager_get ()); +} + +static void +on_monitors_changed (MetaMonitorManager *manager, + MetaScreen *screen) +{ + GSList *tmp, *windows; reload_monitor_infos (screen); set_desktop_geometry_hint (screen); @@ -3021,8 +2872,8 @@ meta_screen_resize (MetaScreen *screen, changes.x = 0; changes.y = 0; - changes.width = width; - changes.height = height; + changes.width = screen->rect.width; + changes.height = screen->rect.height; XConfigureWindow(screen->display->xdisplay, screen->guard_window, @@ -3032,7 +2883,8 @@ meta_screen_resize (MetaScreen *screen, if (screen->display->compositor) meta_compositor_sync_screen_size (screen->display->compositor, - screen, width, height); + screen, + screen->rect.width, screen->rect.height); /* Queue a resize on all the windows */ meta_screen_foreach_window (screen, meta_screen_resize_func, 0); @@ -3048,7 +2900,6 @@ meta_screen_resize (MetaScreen *screen, meta_window_update_for_monitors_changed (window); } - g_free (old_monitor_infos); g_slist_free (windows); meta_screen_queue_check_fullscreen (screen); diff --git a/src/core/window-private.h b/src/core/window-private.h index 2fb101670..e7255beab 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -165,7 +165,7 @@ struct _MetaWindow * been overridden (via a client message), the window will cover the union of * these monitors. If not, this is the single monitor which the window's * origin is on. */ - long fullscreen_monitors[4]; + gint fullscreen_monitors[4]; /* Whether we're trying to constrain the window to be fully onscreen */ guint require_fully_onscreen : 1; diff --git a/src/core/window.c b/src/core/window.c index 33723535d..b5a4984bb 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -2108,10 +2108,14 @@ set_net_wm_state (MetaWindow *window) if (window->fullscreen) { - data[0] = window->fullscreen_monitors[0]; - data[1] = window->fullscreen_monitors[1]; - data[2] = window->fullscreen_monitors[2]; - data[3] = window->fullscreen_monitors[3]; + data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[0]); + data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[1]); + data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[2]); + data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen, + window->fullscreen_monitors[3]); meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n"); meta_error_trap_push (window->display); @@ -4785,7 +4789,8 @@ meta_window_update_for_monitors_changed (MetaWindow *window) { MetaMonitorInfo *info = &window->screen->monitor_infos[i]; - if (info->output == old->output) + if (info->output_id != 0 && + info->output_id == old->output_id) { new = info; break; @@ -7130,10 +7135,14 @@ meta_window_client_message (MetaWindow *window, meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n", window->desc); - top = event->xclient.data.l[0]; - bottom = event->xclient.data.l[1]; - left = event->xclient.data.l[2]; - right = event->xclient.data.l[3]; + top = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[0]); + bottom = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[1]); + left = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[2]); + right = meta_screen_xinerama_index_to_monitor_index (window->screen, + event->xclient.data.l[3]); /* source_indication = event->xclient.data.l[4]; */ meta_window_update_fullscreen_monitors (window, top, bottom, left, right);