/* Compile with:
gcc -g -O2 $(pkg-config --cflags --libs gtk+-2.0) bug316180.c -o bug316180
*/

#include <gtk/gtk.h>
#include <gdk/gdkx.h>

static gboolean
gtk_window_map_event (GtkWidget *widget,
                      GdkEvent  *event,
                      gpointer   user_data)
{
  if (!GTK_WIDGET_MAPPED (widget))
    {
      /* we should be be unmapped, but are getting a MapEvent, this may happen
       * to toplevel XWindows if mapping was intercepted by a window manager
       * and an unmap request occoured while the MapRequestEvent was still
       * being handled. we work around this situaiton here by re-requesting
       * the window being unmapped. more details can be found in:
       *   http://bugzilla.gnome.org/show_bug.cgi?id=316180
       */
      gdk_window_hide (widget->window);
    }
  return FALSE;
}

int
main (int argc, char *argv[])
{
  /* initialize and get root window */
  gtk_init (&argc, &argv);

  gint test_layer = 0;          // 0=XUnmapWindow, 1=XWithdrawWindow, 2=Gdk, 3=Gtk+, 4=Gtk+show-now, 5=Gtk+FIXUP
  if (argc >= 2)
    test_layer = g_ascii_strtoull (argv[1], NULL, 10);

  GtkWidget *gtkwindow = NULL;
  GdkWindow *gdkwindow = NULL;
  if (test_layer <= 2)
    {
      GdkWindow *root_window = gdk_screen_get_root_window (gdk_screen_get_default());
      /* create toplevel XWindow */
      GdkWindowAttr attributes = { 0, };
      attributes.window_type = GDK_WINDOW_TOPLEVEL;
      attributes.width = attributes.height = 50;
      attributes.event_mask = GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK;
      gint attributes_mask = 0; // GDK_WA_VISUAL | GDK_WA_COLORMAP;
      gdkwindow = gdk_window_new (root_window, &attributes, attributes_mask);
      /* set background color to ease debugging */
      GdkColor gdkcolor = { 0, };
      gdkcolor.red = gdkcolor.green = gdkcolor.blue = 0x8080;
      if (gdk_colormap_alloc_color (gdk_window_get_colormap (gdkwindow), &gdkcolor, FALSE, TRUE))
        {
          gdk_window_set_background (gdkwindow, &gdkcolor);
          gdk_colormap_free_colors (gdk_window_get_colormap (gdkwindow), &gdkcolor, 1);
        }
    }
  else if (test_layer >= 3)
    gtkwindow = g_object_new (GTK_TYPE_WINDOW, NULL);

  /* create window already */
  gdk_flush();

  /* map and withdraw immediately */
  if (test_layer <= 1)          // XLib
    {
      if (test_layer == 1)
        g_printerr ("Map/Withdraw+Unmap XWindow\n");
      else
        g_printerr ("Map/Unmap XWindow\n");
      Display *display = gdk_x11_drawable_get_xdisplay (gdkwindow);
      XID win = gdk_x11_drawable_get_xid (gdkwindow);
      XMapWindow (display, win);
      if (test_layer == 1)
        XWithdrawWindow (display, win, 0);      // doesn't influence behaviour
      // XSync (display, 0);                    // <- only makes unmapping racier
      XUnmapWindow (display, win);
    }
  else if (test_layer == 2)     // Gdk
    {
      g_printerr ("Show/Hide GdkWindow\n");
      gdk_window_show (gdkwindow); /* does XMapWindow() */
      gdk_window_hide (gdkwindow); /* does XWithdrawWindow(); XUnmapWindow() */
    }
  else if (test_layer == 3)     // Gtk
    {
      g_printerr ("Show/Hide GtkWindow\n");
      gtk_widget_show (gtkwindow);
      gtk_widget_hide (gtkwindow);
    }
  else if (test_layer == 4)     // Gtk+show-now
    {
      g_printerr ("Show_now/Hide GtkWindow\n");
      gtk_widget_show_now (gtkwindow);
      gtk_widget_hide (gtkwindow);
    }
  else if (test_layer >= 5)     // Gtk+FIXUP
    {
      g_printerr ("Show/Hide GtkWindow, MapEvent fix\n");
      g_signal_connect (gtkwindow, "map-event", G_CALLBACK (gtk_window_map_event), NULL);
      gtk_widget_show (gtkwindow);
      gtk_widget_hide (gtkwindow);
    }

  /* print out incoming events (with --gdk-debug=events) */
  gtk_main ();

  return 0;
}
