[gtk+/gtk-3-20] win32: rework how to enumerate the monitors



commit bd725d3208408fdc30977a4642caa4702283e94d
Author: Ignacio Casal Quinteiro <icq gnome org>
Date:   Mon Feb 20 10:27:11 2017 +0100

    win32: rework how to enumerate the monitors
    
    It is racy to enumerate first the monitors and then reenumerate
    using the previous counter since at that point we might endup
    getting a new monitor and crash on the assert.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=779002

 gdk/win32/gdkscreen-win32.c |   86 ++++++++++++++++++------------------------
 1 files changed, 37 insertions(+), 49 deletions(-)
---
diff --git a/gdk/win32/gdkscreen-win32.c b/gdk/win32/gdkscreen-win32.c
index 2a8d101..8861f72 100644
--- a/gdk/win32/gdkscreen-win32.c
+++ b/gdk/win32/gdkscreen-win32.c
@@ -38,7 +38,7 @@ struct _GdkWin32Screen
   GdkScreen parent_instance;
 
   gint num_monitors;
-  GdkWin32Monitor *monitors;
+  GdkWin32Monitor **monitors;
 
   GdkVisual *system_visual;
   GdkVisual *rgba_visual;
@@ -57,6 +57,15 @@ struct _GdkWin32ScreenClass
 
 G_DEFINE_TYPE (GdkWin32Screen, gdk_win32_screen, GDK_TYPE_SCREEN)
 
+static void
+free_monitor (gpointer user_data)
+{
+  GdkWin32Monitor *monitor = (GdkWin32Monitor *)user_data;
+
+  g_free (monitor->name);
+  g_free (monitor);
+}
+
 static gint
 get_color_precision (gulong mask)
 {
@@ -263,9 +272,9 @@ init_root_window_size (GdkWin32Screen *screen)
   GdkRectangle rect;
   int i;
 
-  rect = screen->monitors[0].rect;
+  rect = screen->monitors[0]->rect;
   for (i = 1; i < screen->num_monitors; i++)
-    gdk_rectangle_union (&rect, &screen->monitors[i].rect, &rect);
+    gdk_rectangle_union (&rect, &screen->monitors[i]->rect, &rect);
 
   screen->root_window->width = rect.width;
   screen->root_window->height = rect.height;
@@ -309,22 +318,9 @@ init_root_window (GdkWin32Screen *screen_win32)
   GDK_NOTE (MISC, g_print ("screen->root_window=%p\n", window));
 }
 
-static BOOL CALLBACK
-count_monitor (HMONITOR hmonitor,
-               HDC      hdc,
-               LPRECT   rect,
-               LPARAM   data)
-{
-  gint *n = (gint *) data;
-
-  (*n)++;
-
-  return TRUE;
-}
-
 typedef struct {
     GdkWin32Screen *screen;
-    gint index;
+    GPtrArray *monitors;
 } EnumMonitorData;
 
 static BOOL CALLBACK
@@ -352,10 +348,6 @@ enum_monitor (HMONITOR hmonitor,
   MONITORINFOEXA2 monitor_info;
   HDC hDC;
 
-  g_assert (data->index < data->screen->num_monitors);
-
-  monitor = data->screen->monitors + data->index;
-
   monitor_info.cbSize = sizeof (MONITORINFOEXA2);
   GetMonitorInfoA (hmonitor, (MONITORINFO *) &monitor_info);
 
@@ -363,6 +355,7 @@ enum_monitor (HMONITOR hmonitor,
 #define MONITORINFOF_PRIMARY 1
 #endif
 
+  monitor = g_new0 (GdkWin32Monitor, 1);
   monitor->name = g_strdup (monitor_info.szDevice);
   hDC = CreateDCA ("DISPLAY", monitor_info.szDevice, NULL, NULL);
   monitor->width_mm = GetDeviceCaps (hDC, HORZSIZE);
@@ -377,17 +370,13 @@ enum_monitor (HMONITOR hmonitor,
   monitor->work_rect.width = monitor_info.rcWork.right - monitor_info.rcWork.left;
   monitor->work_rect.height = monitor_info.rcWork.bottom - monitor_info.rcWork.top;
 
-  if (monitor_info.dwFlags & MONITORINFOF_PRIMARY && data->index != 0)
-    {
-      /* Put primary monitor at index 0, just in case somebody needs
-       * to know which one is the primary.
-       */
-      GdkWin32Monitor temp = *monitor;
-      *monitor = data->screen->monitors[0];
-      data->screen->monitors[0] = temp;
-    }
-
-  data->index++;
+  if (monitor_info.dwFlags & MONITORINFOF_PRIMARY)
+    /* Put primary monitor at index 0, just in case somebody needs
+     * to know which one is the primary.
+     */
+    g_ptr_array_insert (data->monitors, 0, monitor);
+  else
+    g_ptr_array_add (data->monitors, monitor);
 
   return TRUE;
 }
@@ -395,27 +384,27 @@ enum_monitor (HMONITOR hmonitor,
 static void
 init_monitors (GdkWin32Screen *screen)
 {
-  gint count;
   EnumMonitorData data;
   gint i;
 
-  count = 0;
-  EnumDisplayMonitors (NULL, NULL, count_monitor, (LPARAM) &count);
-  screen->num_monitors = count;
+  data.screen = screen;
+  data.monitors = g_ptr_array_new ();
 
-  screen->monitors = g_renew (GdkWin32Monitor, screen->monitors, screen->num_monitors);
+  for (i = 0; i < screen->num_monitors; i++)
+    free_monitor (screen->monitors[i]);
 
-  data.screen = screen;
-  data.index = 0;
   EnumDisplayMonitors (NULL, NULL, enum_monitor, (LPARAM) &data);
 
+  screen->num_monitors = data.monitors->len;
+  screen->monitors = (GdkWin32Monitor **)g_ptr_array_free (data.monitors, FALSE);
+
   _gdk_offset_x = G_MININT;
   _gdk_offset_y = G_MININT;
 
   /* Calculate offset */
   for (i = 0; i < screen->num_monitors; i++)
     {
-      GdkRectangle *rect = &screen->monitors[i].rect;
+      GdkRectangle *rect = &screen->monitors[i]->rect;
       _gdk_offset_x = MAX (_gdk_offset_x, -rect->x);
       _gdk_offset_y = MAX (_gdk_offset_y, -rect->y);
     }
@@ -426,10 +415,10 @@ init_monitors (GdkWin32Screen *screen)
   for (i = 0; i < screen->num_monitors; i++)
     {
       GdkRectangle *rect;
-      rect = &screen->monitors[i].rect;
+      rect = &screen->monitors[i]->rect;
       rect->x += _gdk_offset_x;
       rect->y += _gdk_offset_y;
-      rect = &screen->monitors[i].work_rect;
+      rect = &screen->monitors[i]->work_rect;
       rect->x += _gdk_offset_x;
       rect->y += _gdk_offset_y;
       GDK_NOTE (MISC, g_print ("Monitor %d: %dx%d@%+d%+d\n", i,
@@ -546,7 +535,7 @@ gdk_win32_screen_get_monitor_width_mm (GdkScreen *screen,
   g_return_val_if_fail (screen == gdk_display_get_default_screen (gdk_display_get_default ()), 0);
   g_return_val_if_fail (num_monitor < win32_screen->num_monitors, 0);
 
-  return win32_screen->monitors[num_monitor].width_mm;
+  return win32_screen->monitors[num_monitor]->width_mm;
 }
 
 static gint
@@ -558,7 +547,7 @@ gdk_win32_screen_get_monitor_height_mm (GdkScreen *screen,
   g_return_val_if_fail (screen == gdk_display_get_default_screen (gdk_display_get_default ()), 0);
   g_return_val_if_fail (num_monitor < win32_screen->num_monitors, 0);
 
-  return win32_screen->monitors[num_monitor].height_mm;
+  return win32_screen->monitors[num_monitor]->height_mm;
 }
 
 static gchar *
@@ -570,7 +559,7 @@ gdk_win32_screen_get_monitor_plug_name (GdkScreen *screen,
   g_return_val_if_fail (screen == gdk_display_get_default_screen (gdk_display_get_default ()), NULL);
   g_return_val_if_fail (num_monitor < win32_screen->num_monitors, NULL);
 
-  return g_strdup (win32_screen->monitors[num_monitor].name);
+  return g_strdup (win32_screen->monitors[num_monitor]->name);
 }
 
 static void
@@ -583,7 +572,7 @@ gdk_win32_screen_get_monitor_geometry (GdkScreen    *screen,
   g_return_if_fail (screen == gdk_display_get_default_screen (gdk_display_get_default ()));
   g_return_if_fail (num_monitor < win32_screen->num_monitors);
 
-  *dest = win32_screen->monitors[num_monitor].rect;
+  *dest = win32_screen->monitors[num_monitor]->rect;
 }
 
 static void
@@ -596,7 +585,7 @@ gdk_win32_screen_get_monitor_workarea (GdkScreen    *screen,
   g_return_if_fail (screen == gdk_display_get_default_screen (gdk_display_get_default ()));
   g_return_if_fail (num_monitor < win32_screen->num_monitors);
 
-  *dest = win32_screen->monitors[num_monitor].work_rect;
+  *dest = win32_screen->monitors[num_monitor]->work_rect;
 }
 
 static gint
@@ -754,8 +743,7 @@ gdk_win32_screen_finalize (GObject *object)
   gint i;
 
   for (i = 0; i < screen->num_monitors; i++)
-    g_free (screen->monitors[i].name);
-  g_free (screen->monitors);
+    free_monitor (screen->monitors[i]);
 
   G_OBJECT_CLASS (gdk_win32_screen_parent_class)->finalize (object);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]