GDK W32: Ensure that we use made-up monitors when there are none
authorРуслан Ижбулатов <lrn1986@gmail.com>
Fri, 20 Jan 2017 10:23:00 +0000 (10:23 +0000)
committerРуслан Ижбулатов <lrn1986@gmail.com>
Fri, 20 Jan 2017 12:45:57 +0000 (12:45 +0000)
Previously GDK only made up monitors when it initially found none. Now it
also makes up monitors when it initially finds some, but later fails to get
their informatin in a normal way and finally prunes them out, being left with
zero monitors.

Having zero-length monitor array is unexpected and causes a number
of critical warnings and some critical functionality (such as displaying
drop-down menus) fails in such cases.

Ideally, there might be such a way to interrogate W32 API that produces the
information about non-real (but active) monitors out of it so that it isn't
necessary for us to make stuff up. However, this code is already complicated,
and i am not prepared to dig W32 API to find a way to do this.

This fixes the issues people had when they accessed a Windows desktop via RDP.

https://bugzilla.gnome.org/show_bug.cgi?id=777527

gdk/win32/gdkmonitor-win32.c

index 1686eb59beb60d72bcc34a2f1f041daa6938902e..ea58cb5fc58cf07ce2af876ef0485fe2a64e0387 100644 (file)
@@ -722,6 +722,25 @@ enum_monitor (HMONITOR hmonitor,
   return TRUE;
 }
 
+static void
+prune_monitors (EnumMonitorData *data)
+{
+  gint i;
+
+  for (i = 0; i < data->monitors->len; i++)
+    {
+      GdkWin32Monitor *m;
+
+      m = g_ptr_array_index (data->monitors, i);
+
+      if (m->remove)
+        {
+          g_ptr_array_remove_index (data->monitors, i);
+          continue;
+        }
+    }
+}
+
 GPtrArray *
 _gdk_win32_display_get_monitor_list (GdkWin32Display *win32_display)
 {
@@ -743,6 +762,18 @@ _gdk_win32_display_get_monitor_list (GdkWin32Display *win32_display)
 
   EnumDisplayMonitors (NULL, NULL, enum_monitor, (LPARAM) &data);
 
+  prune_monitors (&data);
+
+  if (data.monitors->len == 0 && data.have_monitor_devices)
+    {
+      /* We thought we had monitors, but enumeration eventually failed, and
+       * we have none. Try again, this time making stuff up as we go.
+       */
+      data.have_monitor_devices = FALSE;
+      EnumDisplayMonitors (NULL, NULL, enum_monitor, (LPARAM) &data);
+      prune_monitors (&data);
+    }
+
   _gdk_offset_x = G_MININT;
   _gdk_offset_y = G_MININT;
 
@@ -753,12 +784,6 @@ _gdk_win32_display_get_monitor_list (GdkWin32Display *win32_display)
 
       m = g_ptr_array_index (data.monitors, i);
 
-      if (m->remove)
-        {
-          g_ptr_array_remove_index (data.monitors, i);
-          continue;
-        }
-
       /* Calculate offset */
       gdk_monitor_get_geometry (GDK_MONITOR (m), &rect);
       _gdk_offset_x = MAX (_gdk_offset_x, -rect.x);