/* GDK - The GIMP Drawing Kit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 * Copyright (C) 1998-2002 Tor Lillqvist
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

#include <stdlib.h>

#include "gdk.h" /* gdk_rectangle_intersect */
#include "gdkevents.h"
#include "gdkpixmap.h"
#include "gdkwindow.h"
#include "gdkdisplay.h"
#include "gdkprivate-win32.h"
#include "gdkinput-win32.h"

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <stdio.h> /* sprintf */

static GdkColormap* gdk_window_impl_win32_get_colormap (GdkDrawable *drawable);
static void         gdk_window_impl_win32_set_colormap (GdkDrawable *drawable,
							GdkColormap *cmap);
static void         gdk_window_impl_win32_get_size     (GdkDrawable *drawable,
							gint *width,
							gint *height);
static GdkRegion*   gdk_window_impl_win32_get_visible_region (GdkDrawable *drawable);
static void gdk_window_impl_win32_init       (GdkWindowImplWin32      *window);
static void gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass);
static void gdk_window_impl_win32_finalize   (GObject                 *object);

static gpointer parent_class = NULL;

GType
_gdk_window_impl_win32_get_type (void)
{
  static GType object_type = 0;

  if (!object_type)
    {
      static const GTypeInfo object_info =
      {
        sizeof (GdkWindowImplWin32Class),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) gdk_window_impl_win32_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GdkWindowImplWin32),
        0,              /* n_preallocs */
        (GInstanceInitFunc) gdk_window_impl_win32_init,
      };
      
      object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_WIN32,
                                            "GdkWindowImplWin32",
                                            &object_info, 0);
    }
  
  return object_type;
}

GType
_gdk_window_impl_get_type (void)
{
  return _gdk_window_impl_win32_get_type ();
}

static void
gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
{
  impl->width = 1;
  impl->height = 1;

  impl->hcursor = NULL;
  impl->hicon = NULL;
  impl->hint_flags = 0;
  impl->extension_events_selected = FALSE;
}

static void
gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
  
  parent_class = g_type_class_peek_parent (klass);

  object_class->finalize = gdk_window_impl_win32_finalize;

  drawable_class->set_colormap = gdk_window_impl_win32_set_colormap;
  drawable_class->get_colormap = gdk_window_impl_win32_get_colormap;
  drawable_class->get_size = gdk_window_impl_win32_get_size;

  /* Visible and clip regions are the same */
  drawable_class->get_clip_region = gdk_window_impl_win32_get_visible_region;
  drawable_class->get_visible_region = gdk_window_impl_win32_get_visible_region;
}

static void
gdk_window_impl_win32_finalize (GObject *object)
{
  GdkWindowObject *wrapper;
  GdkDrawableImplWin32 *draw_impl;
  GdkWindowImplWin32 *window_impl;
  
  g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (object));

  draw_impl = GDK_DRAWABLE_IMPL_WIN32 (object);
  window_impl = GDK_WINDOW_IMPL_WIN32 (object);
  
  wrapper = (GdkWindowObject*) draw_impl->wrapper;

  if (!GDK_WINDOW_DESTROYED (wrapper))
    {
      gdk_win32_handle_table_remove (draw_impl->handle);
    }

  if (window_impl->hcursor != NULL)
    {
      if (GetCursor () == window_impl->hcursor)
	SetCursor (NULL);
      GDI_CALL (DestroyCursor, (window_impl->hcursor));
      window_impl->hcursor = NULL;
    }
  if (window_impl->hicon != NULL)
    {
      GDI_CALL (DestroyIcon, (window_impl->hicon));
      window_impl->hicon = NULL;
    }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

void
_gdk_win32_adjust_client_rect (GdkWindow *window,
			       RECT      *rect)
{
  LONG style, exstyle;

  style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
  exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
  API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
}

void
_gdk_win32_get_adjusted_client_rect (GdkWindow *window,
				     RECT      *rect)
{
  GetClientRect (GDK_WINDOW_HWND (window), rect);
  _gdk_win32_adjust_client_rect (window, rect);
}

static GdkColormap*
gdk_window_impl_win32_get_colormap (GdkDrawable *drawable)
{
  GdkDrawableImplWin32 *drawable_impl;
  
  g_return_val_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (drawable), NULL);

  drawable_impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);

  if (!((GdkWindowObject *) drawable_impl->wrapper)->input_only && 
      drawable_impl->colormap == NULL)
    {
      drawable_impl->colormap = gdk_colormap_get_system ();
      g_object_ref (drawable_impl->colormap);
    }
  
  return drawable_impl->colormap;
}

static void
gdk_window_impl_win32_set_colormap (GdkDrawable *drawable,
				    GdkColormap *cmap)
{
  GdkWindowImplWin32 *impl;
  GdkDrawableImplWin32 *draw_impl;
  
  g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (drawable));

  impl = GDK_WINDOW_IMPL_WIN32 (drawable);
  draw_impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);

  /* chain up */
  GDK_DRAWABLE_CLASS (parent_class)->set_colormap (drawable, cmap);
  
  if (cmap)
    {
      /* XXX */
      g_print("gdk_window_impl_win32_set_colormap: XXX\n");
    }
}

static void
gdk_window_impl_win32_get_size (GdkDrawable *drawable,
				gint        *width,
				gint        *height)
{
  g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (drawable));

  if (width)
    *width = GDK_WINDOW_IMPL_WIN32 (drawable)->width;
  if (height)
    *height = GDK_WINDOW_IMPL_WIN32 (drawable)->height;
}

static GdkRegion*
gdk_window_impl_win32_get_visible_region (GdkDrawable *drawable)
{
  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (drawable);
  GdkRectangle result_rect;

  result_rect.x = 0;
  result_rect.y = 0;
  result_rect.width = impl->width;
  result_rect.height = impl->height;

  gdk_rectangle_intersect (&result_rect, &impl->position_info.clip_rect, &result_rect);

  return gdk_region_rectangle (&result_rect);
}

void
_gdk_windowing_window_init (void)
{
  GdkWindowObject *private;
  GdkWindowImplWin32 *impl;
  GdkDrawableImplWin32 *draw_impl;
  GdkRectangle rect;
  gint i;

  g_assert (_gdk_parent_root == NULL);
  
  _gdk_parent_root = g_object_new (GDK_TYPE_WINDOW, NULL);
  private = (GdkWindowObject *)_gdk_parent_root;
  impl = GDK_WINDOW_IMPL_WIN32 (private->impl);
  draw_impl = GDK_DRAWABLE_IMPL_WIN32 (private->impl);
  
  draw_impl->handle = _gdk_root_window;
  draw_impl->wrapper = GDK_DRAWABLE (private);
  draw_impl->colormap = gdk_colormap_get_system ();
  g_object_ref (draw_impl->colormap);
  
  private->window_type = GDK_WINDOW_ROOT;
  private->depth = gdk_visual_get_system ()->depth;

  rect = _gdk_monitors[0];
  for (i = 1; i < _gdk_num_monitors; i++)
    gdk_rectangle_union (&rect, _gdk_monitors+i, &rect);

  impl->width = rect.width;
  impl->height = rect.height;

  _gdk_window_init_position (GDK_WINDOW (private));

  gdk_win32_handle_table_insert (&_gdk_root_window, _gdk_parent_root);

  GDK_NOTE (MISC, g_print ("_gdk_parent_root=%p\n", GDK_WINDOW_HWND (_gdk_parent_root)));
}

static const gchar *
get_default_title (void)
{
  const char *title;
  title = g_get_application_name ();
  if (!title)
    title = g_get_prgname ();

  return title;
}

/* RegisterGdkClass
 *   is a wrapper function for RegisterWindowClassEx.
 *   It creates at least one unique class for every 
 *   GdkWindowType. If support for single window-specific icons
 *   is ever needed (e.g Dialog specific), every such window should
 *   get its own class
 */
static ATOM
RegisterGdkClass (GdkWindowType wtype)
{
  static ATOM klassTOPLEVEL = 0;
  static ATOM klassDIALOG   = 0;
  static ATOM klassCHILD    = 0;
  static ATOM klassTEMP     = 0;
  static HICON hAppIcon = NULL;
  static WNDCLASSEX wcl; 
  ATOM klass = 0;

  wcl.cbSize = sizeof (WNDCLASSEX);
  wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
                  * on WM_SIZE and WM_MOVE. Flicker, Performance!
                  */
  wcl.lpfnWndProc = _gdk_win32_window_procedure;
  wcl.cbClsExtra = 0;
  wcl.cbWndExtra = 0;
  wcl.hInstance = _gdk_app_hmodule;
  wcl.hIcon = 0;
  /* initialize once! */
  if (0 == hAppIcon)
    {
      gchar sLoc [MAX_PATH+1];

      if (0 != GetModuleFileName (_gdk_app_hmodule, sLoc, MAX_PATH))
	{
	  hAppIcon = ExtractIcon (_gdk_app_hmodule, sLoc, 0);
	  if (0 == hAppIcon)
	    {
	      if (0 != GetModuleFileName (_gdk_dll_hinstance, sLoc, MAX_PATH))
		hAppIcon = ExtractIcon (_gdk_dll_hinstance, sLoc, 0);
	    }
	}
      if (0 == hAppIcon) 
	hAppIcon = LoadIcon (NULL, IDI_APPLICATION);
    }

  wcl.lpszMenuName = NULL;
  wcl.hIconSm = 0;

  /* initialize once per class */
  /*
   * HB: Setting the background brush leads to flicker, because we
   * don't get asked how to clear the background. This is not what
   * we want, at least not for input_only windows ...
   */
#define ONCE_PER_CLASS() \
  wcl.hIcon = CopyIcon (hAppIcon); \
  wcl.hIconSm = CopyIcon (hAppIcon); \
  wcl.hbrBackground = NULL; \
  wcl.hCursor = LoadCursor (NULL, IDC_ARROW); 
  
  switch (wtype)
    {
    case GDK_WINDOW_TOPLEVEL:
      if (0 == klassTOPLEVEL)
	{
	  wcl.lpszClassName = "gdkWindowToplevel";
	  
	  ONCE_PER_CLASS();
	  klassTOPLEVEL = RegisterClassEx (&wcl);
	}
      klass = klassTOPLEVEL;
      break;
      
    case GDK_WINDOW_CHILD:
      if (0 == klassCHILD)
	{
	  wcl.lpszClassName = "gdkWindowChild";
	  
	  wcl.style |= CS_PARENTDC; /* MSDN: ... enhances system performance. */
	  ONCE_PER_CLASS();
	  klassCHILD = RegisterClassEx (&wcl);
	}
      klass = klassCHILD;
      break;
      
    case GDK_WINDOW_DIALOG:
      if (0 == klassDIALOG)
	{
	  wcl.lpszClassName = "gdkWindowDialog";
	  wcl.style |= CS_SAVEBITS;
	  ONCE_PER_CLASS();
	  klassDIALOG = RegisterClassEx (&wcl);
	}
      klass = klassDIALOG;
      break;
      
    case GDK_WINDOW_TEMP:
      if (0 == klassTEMP)
	{
	  wcl.lpszClassName = "gdkWindowTemp";
	  wcl.style |= CS_SAVEBITS;
	  ONCE_PER_CLASS();
	  klassTEMP = RegisterClassEx (&wcl);
	}
      klass = klassTEMP;
      break;
      
    default:
      g_assert_not_reached ();
      break;
    }
  
  if (klass == 0)
    {
      WIN32_API_FAILED ("RegisterClassEx");
      g_error ("That is a fatal error");
    }
  return klass;
}

GdkWindow*
gdk_window_new (GdkWindow     *parent,
		GdkWindowAttr *attributes,
		gint           attributes_mask)
{
  HANDLE hparent;
  ATOM klass = 0;
  DWORD dwStyle = 0, dwExStyle;
  RECT rect;
  GdkWindow *window;
  GdkWindowObject *private;
  GdkWindowImplWin32 *impl;
  GdkDrawableImplWin32 *draw_impl;
  GdkScreen *screen;
  GdkVisual *visual;
  const gchar *title;
  char *mbtitle;
  gint window_width, window_height;
  gint offset_x = 0, offset_y = 0;

  g_return_val_if_fail (attributes != NULL, NULL);

  if (!parent)
    {
      screen = gdk_screen_get_default ();
      parent = gdk_screen_get_root_window (screen);
    }
  else
    screen = gdk_drawable_get_screen (parent);

  g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
  
  GDK_NOTE (MISC,
	    g_print ("gdk_window_new: %s\n",
		     (attributes->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" :
		      (attributes->window_type == GDK_WINDOW_CHILD ? "CHILD" :
		       (attributes->window_type == GDK_WINDOW_DIALOG ? "DIALOG" :
			(attributes->window_type == GDK_WINDOW_TEMP ? "TEMP" :
			 "???"))))));

  if (GDK_WINDOW_DESTROYED (parent))
    return NULL;
  
  hparent = GDK_WINDOW_HWND (parent);

  window = g_object_new (GDK_TYPE_WINDOW, NULL);
  private = (GdkWindowObject *)window;
  impl = GDK_WINDOW_IMPL_WIN32 (private->impl);
  draw_impl = GDK_DRAWABLE_IMPL_WIN32 (private->impl);
  draw_impl->wrapper = GDK_DRAWABLE (window);

  /* Windows with a foreign parent are treated as if they are children
   * of the root window, except for actual creation.
   */
  if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_FOREIGN)
    parent = _gdk_parent_root;
  
  private->parent = (GdkWindowObject *)parent;

  if (attributes_mask & GDK_WA_X)
    private->x = attributes->x;
  else
    private->x = 0;
  
  if (attributes_mask & GDK_WA_Y)
    private->y = attributes->y;
  else if (attributes_mask & GDK_WA_X)
    private->y = 100;		/* ??? We must put it somewhere... */
  else
    private->y = 0;
  
  if (attributes_mask & GDK_WA_VISUAL)
    visual = attributes->visual;
  else
    visual = gdk_visual_get_system ();

  impl->width = (attributes->width > 1) ? (attributes->width) : (1);
  impl->height = (attributes->height > 1) ? (attributes->height) : (1);
  impl->extension_events_selected = FALSE;
  private->window_type = attributes->window_type;

  if (attributes->wclass == GDK_INPUT_OUTPUT)
    {
      dwExStyle = 0;

      private->input_only = FALSE;
      private->depth = visual->depth;
      
      if (attributes_mask & GDK_WA_COLORMAP)
	{
	  draw_impl->colormap = attributes->colormap;
          g_object_ref (attributes->colormap);
        }
      else
	{
	  draw_impl->colormap = gdk_screen_get_system_colormap (screen);
	  g_object_ref (draw_impl->colormap);
	}
    }
  else
    {
      dwExStyle = WS_EX_TRANSPARENT;
      private->depth = 0;
      private->input_only = TRUE;
      draw_impl->colormap = gdk_colormap_get_system ();
      g_object_ref (draw_impl->colormap);
      GDK_NOTE (MISC, g_print ("...GDK_INPUT_ONLY, system colormap"));
    }

  switch (private->window_type)
    {
    case GDK_WINDOW_TOPLEVEL:
      dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
      hparent = _gdk_root_window;
      offset_x = _gdk_offset_x;
      offset_y = _gdk_offset_y;
      break;

    case GDK_WINDOW_CHILD:
      dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
      break;

    case GDK_WINDOW_DIALOG:
      dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
#if 0
      dwExStyle |= WS_EX_TOPMOST; /* //HB: want this? */
#endif
      hparent = _gdk_root_window;
      offset_x = _gdk_offset_x;
      offset_y = _gdk_offset_y;
      break;

    case GDK_WINDOW_TEMP:
      dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
      /* a temp window is not necessarily a top level window */
      dwStyle |= (_gdk_parent_root == parent ? WS_POPUP : WS_CHILDWINDOW);
      dwExStyle |= WS_EX_TOOLWINDOW;
      offset_x = _gdk_offset_x;
      offset_y = _gdk_offset_y;
      break;

    case GDK_WINDOW_ROOT:
      g_error ("cannot make windows of type GDK_WINDOW_ROOT");
      break;

    default:
      g_assert_not_reached ();
    }

  _gdk_window_init_position (GDK_WINDOW (private));

  if (private->window_type != GDK_WINDOW_CHILD)
    {
      rect.left = rect.top = 0;
      rect.right = impl->position_info.width;
      rect.bottom = impl->position_info.height;

      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);

      window_width = rect.right - rect.left;
      window_height = rect.bottom - rect.top;
    }
  else
    {
      window_width = impl->position_info.width;
      window_height = impl->position_info.height;
    }

  if (impl->position_info.big)
    private->guffaw_gravity = TRUE;

  if (attributes_mask & GDK_WA_TITLE)
    title = attributes->title;
  else
    title = get_default_title ();
  if (!title || !*title)
    title = "GDK client window";

  private->event_mask = GDK_STRUCTURE_MASK | attributes->event_mask;
      
  if (private->parent && private->parent->guffaw_gravity)
    {
      /* XXX ??? */
    }

  if (private->parent)
    private->parent->children = g_list_prepend (private->parent->children, window);

  klass = RegisterGdkClass (private->window_type);

  mbtitle = g_locale_from_utf8 (title, -1, NULL, NULL, NULL);
  
#ifdef WITHOUT_WM_CREATE
  draw_impl->handle =
    CreateWindowEx (dwExStyle,
		    MAKEINTRESOURCE(klass),
		    mbtitle,
		    dwStyle,
		    ((attributes_mask & GDK_WA_X) ?
		     impl->position_info.x - offset_x : CW_USEDEFAULT),
		    impl->position_info.y - offset_y, 
		    window_width, window_height,
		    hparent,
		    NULL,
		    _gdk_app_hmodule,
		    NULL);
#else
  {
  HWND hwndNew =
    CreateWindowEx (dwExStyle,
		    MAKEINTRESOURCE(klass),
		    mbtitle,
		    dwStyle,
		    ((attributes_mask & GDK_WA_X) ?
		     impl->position_info.x - offset_x: CW_USEDEFAULT),
		    impl->position_info.y - offset_y, 
		    window_width, window_height,
		    hparent,
		    NULL,
		    _gdk_app_hmodule,
		    window);
  if (GDK_WINDOW_HWND (window) != hwndNew)
    {
      g_warning("gdk_window_new: gdk_event_translate::WM_CREATE (%p, %p) HWND mismatch.",
		GDK_WINDOW_HWND (window),
		hwndNew);

      /* HB: IHMO due to a race condition the handle was increased by
       * one, which causes much trouble. Because I can't find the 
       * real bug, try to workaround it ...
       * To reproduce: compile with MSVC 5, DEBUG=1
       */
# if 0
      gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
      GDK_WINDOW_HWND (window) = hwndNew;
      gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
# else
      /* the old behaviour, but with warning */
      draw_impl->handle = hwndNew;
# endif

    }
  }
  g_object_ref (window);
  gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
#endif

  GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@+%d+%d %p = %p\n",
			   mbtitle,
			   window_width, window_height,
			   ((attributes_mask & GDK_WA_X) ?
			    impl->position_info.x - offset_x: CW_USEDEFAULT),
			   impl->position_info.y - offset_y, 
			   hparent,
			   GDK_WINDOW_HWND (window)));

  g_free (mbtitle);

  if (draw_impl->handle == NULL)
    {
      WIN32_API_FAILED ("CreateWindowEx");
      g_object_unref (window);
      return NULL;
    }

#ifdef WITHOUT_WM_CREATE
  g_object_ref (window);
  gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);
#endif

  gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
				  (attributes->cursor) :
				  NULL));

  return window;
}

GdkWindow *
gdk_window_foreign_new_for_display (GdkDisplay      *display,
                                    GdkNativeWindow  anid)
{
  GdkWindow *window;
  GdkWindowObject *private;
  GdkWindowImplWin32 *impl;
  GdkDrawableImplWin32 *draw_impl;

  HANDLE parent;
  RECT rect;
  POINT point;

  g_return_val_if_fail (display == gdk_display_get_default (), NULL);

  window = g_object_new (GDK_TYPE_WINDOW, NULL);
  private = (GdkWindowObject *)window;
  impl = GDK_WINDOW_IMPL_WIN32 (private->impl);
  draw_impl = GDK_DRAWABLE_IMPL_WIN32 (private->impl);
  draw_impl->wrapper = GDK_DRAWABLE (window);
  parent = GetParent ((HWND)anid);
  
  private->parent = gdk_win32_handle_table_lookup ((GdkNativeWindow) parent);
  if (!private->parent || GDK_WINDOW_TYPE (private->parent) == GDK_WINDOW_FOREIGN)
    private->parent = (GdkWindowObject *)_gdk_parent_root;
  
  private->parent->children = g_list_prepend (private->parent->children, window);

  draw_impl->handle = (HWND) anid;
  GetClientRect ((HWND) anid, &rect);
  point.x = rect.left;
  point.y = rect.right;
  ClientToScreen ((HWND) anid, &point);
  if (parent != _gdk_root_window)
    ScreenToClient (parent, &point);
  private->x = point.x;
  private->y = point.y;
  impl->width = rect.right - rect.left;
  impl->height = rect.bottom - rect.top;
  private->window_type = GDK_WINDOW_FOREIGN;
  private->destroyed = FALSE;
  private->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */
  if (IsWindowVisible ((HWND) anid))
    private->state &= (~GDK_WINDOW_STATE_WITHDRAWN);
  else
    private->state |= GDK_WINDOW_STATE_WITHDRAWN;
  private->depth = gdk_visual_get_system ()->depth;

  _gdk_window_init_position (GDK_WINDOW (private));

  g_object_ref (window);
  gdk_win32_handle_table_insert (&GDK_WINDOW_HWND (window), window);

  return window;
}

GdkWindow*
gdk_window_lookup (GdkNativeWindow hwnd)
{
  return (GdkWindow*) gdk_win32_handle_table_lookup (hwnd); 
}

void
_gdk_windowing_window_destroy (GdkWindow *window,
			       gboolean   recursing,
			       gboolean   foreign_destroy)
{
  GdkWindowObject *private = (GdkWindowObject *)window;

  g_return_if_fail (GDK_IS_WINDOW (window));
  
  GDK_NOTE (MISC, g_print ("_gdk_windowing_window_destroy: %p\n",
			   GDK_WINDOW_HWND (window)));

  if (private->extension_events != 0)
    _gdk_input_window_destroy (window);

  if (private->window_type == GDK_WINDOW_FOREIGN)
    {
      if (!foreign_destroy && (private->parent != NULL))
	{
	  /* It's somebody else's window, but in our hierarchy,
	   * so reparent it to the root window, and then call
	   * DestroyWindow() on it.
	   */
	  gdk_window_hide (window);
	  gdk_window_reparent (window, NULL, 0, 0);
	  
	  /* Is this too drastic? Many (most?) applications
	   * quit if any window receives WM_QUIT I think.
	   * OTOH, I don't think foreign windows are much
	   * used, so the question is maybe academic.
	   */
	  PostMessage (GDK_WINDOW_HWND (window), WM_QUIT, 0, 0);
	}
    }
  else if (!recursing && !foreign_destroy)
    {
      private->destroyed = TRUE;
      DestroyWindow (GDK_WINDOW_HWND (window));
    }
}

/* This function is called when the window really gone.
 */
void
gdk_window_destroy_notify (GdkWindow *window)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  GDK_NOTE (EVENTS,
	    g_print ("gdk_window_destroy_notify: %p%s\n",
		     GDK_WINDOW_HWND (window),
		     (GDK_WINDOW_DESTROYED (window) ? " (destroyed)" : "")));

  if (!GDK_WINDOW_DESTROYED (window))
    {
      if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_FOREIGN)
	g_warning ("window %p unexpectedly destroyed",
		   GDK_WINDOW_HWND (window));

      _gdk_window_destroy (window, TRUE);
    }
  
  gdk_win32_handle_table_remove (GDK_WINDOW_HWND (window));
  g_object_unref (window);
}

static void
get_outer_rect (GdkWindow *window,
		gint       width,
		gint       height,
		RECT      *rect)
{
  LONG style, exstyle;
      
  style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);
  exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);
      
  rect->left = rect->top = 0;
  rect->right = width;
  rect->bottom = height;
      
  API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
}

static void
adjust_for_gravity_hints (GdkWindowImplWin32 *impl,
			  RECT               *outer_rect,
			  gint		     *x,
			  gint		     *y)
{
  if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
    {
      gint orig_x = *x, orig_y = *y;

      switch (impl->hints.win_gravity)
	{
	case GDK_GRAVITY_NORTH:
	case GDK_GRAVITY_CENTER:
	case GDK_GRAVITY_SOUTH:
	  *x -= (outer_rect->right - outer_rect->left) / 2;
	  *x += impl->width / 2;
	  break;
	      
	case GDK_GRAVITY_SOUTH_EAST:
	case GDK_GRAVITY_EAST:
	case GDK_GRAVITY_NORTH_EAST:
	  *x -= outer_rect->right - outer_rect->left;
	  *x += impl->width;
	  break;

	case GDK_GRAVITY_STATIC:
	  *x += outer_rect->left;
	  break;

	default:
	  break;
	}

      switch (impl->hints.win_gravity)
	{
	case GDK_GRAVITY_WEST:
	case GDK_GRAVITY_CENTER:
	case GDK_GRAVITY_EAST:
	  *y -= (outer_rect->bottom - outer_rect->top) / 2;
	  *y += impl->height / 2;
	  break;

	case GDK_GRAVITY_SOUTH_WEST:
	case GDK_GRAVITY_SOUTH:
	case GDK_GRAVITY_SOUTH_EAST:
	  *y -= outer_rect->bottom - outer_rect->top;
	  *y += impl->height;
	  break;

	case GDK_GRAVITY_STATIC:
	  *y += outer_rect->top;
	  break;

	default:
	  break;
	}
      GDK_NOTE (MISC,
		(orig_x != *x || orig_y != *y) ?
		g_print ("adjust_for_gravity_hints: x: %d->%d, y: %d->%d\n",
			 orig_x, *x, orig_y, *y)
		  : (void) 0);
    }
}

static void
show_window_internal (GdkWindow *window,
                      gboolean   raise,
		      gboolean   deiconify)
{
  GdkWindowObject *private;
  HWND old_active_window;
  
  private = (GdkWindowObject *) window;

  if (private->destroyed)
    return;

  GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s%s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (private->state),
			   (raise ? " raise" : ""),
			   (deiconify ? " deiconify" : "")));
  
  /* If asked to show (not deiconify) an withdrawn and iconified
   * window, do that.
   */
  if (!deiconify &&
      !GDK_WINDOW_IS_MAPPED (window) &&
      (private->state & GDK_WINDOW_STATE_ICONIFIED))
    {	
      ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
      return;
    }
  
  /* If asked to just show an iconified window, do nothing. */
  if (!deiconify && (private->state & GDK_WINDOW_STATE_ICONIFIED))
    return;
  
  /* If asked to deiconify an already noniconified window, do
   * nothing. (Especially, don't cause the window to rise and
   * activate. There are different calls for that.)
   */
  if (deiconify && !(private->state & GDK_WINDOW_STATE_ICONIFIED))
    return;
  
  /* If asked to show (but not raise) a window that is already
   * visible, do nothing.
   */
  if (!deiconify && !raise && IsWindowVisible (GDK_WINDOW_HWND (window)))
    return;

  /* Other cases */
  
  if (!GDK_WINDOW_IS_MAPPED (window))
    gdk_synthesize_window_state (window,
				 GDK_WINDOW_STATE_WITHDRAWN,
				 0);

  old_active_window = GetActiveWindow ();

  if (private->state & GDK_WINDOW_STATE_FULLSCREEN)
    gdk_window_fullscreen (window);
  else if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
    ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
  else if (private->state & GDK_WINDOW_STATE_ICONIFIED)
    ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
  else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
    ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
  else
    ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);

  if (raise)
    if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
      SetWindowPos (GDK_WINDOW_HWND (window), HWND_TOPMOST, 0, 0, 0, 0,
		    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
    else
      BringWindowToTop (GDK_WINDOW_HWND (window));
  else if (old_active_window != GDK_WINDOW_HWND (window))
    SetActiveWindow (old_active_window);
}

void
gdk_window_show_unraised (GdkWindow *window)
{
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  show_window_internal (window, FALSE, FALSE);
}

void
gdk_window_show (GdkWindow *window)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  show_window_internal (window, TRUE, FALSE);
}

void
gdk_window_hide (GdkWindow *window)
{
  GdkWindowObject *private;
  
  g_return_if_fail (window != NULL);

  private = (GdkWindowObject*) window;
  if (private->destroyed)
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_hide: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (private->state)));
  
  if (GDK_WINDOW_IS_MAPPED (window))
    gdk_synthesize_window_state (window,
				 0,
				 GDK_WINDOW_STATE_WITHDRAWN);
  
  _gdk_window_clear_update_area (window);
  
  if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
    ShowOwnedPopups (GDK_WINDOW_HWND (window), FALSE);
  
  if (GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
    {
      SetWindowPos(GDK_WINDOW_HWND (window), HWND_BOTTOM, 0, 0, 0, 0,
		   SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
    }
  else
    {
      ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE);
    }
}

void
gdk_window_withdraw (GdkWindow *window)
{
  GdkWindowObject *private;
  
  g_return_if_fail (window != NULL);
  
  private = (GdkWindowObject*) window;
  if (private->destroyed)
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (private->state)));
  
  gdk_window_hide (window);	/* ??? */
}

void
gdk_window_move (GdkWindow *window,
		 gint       x,
		 gint       y)
{
  GdkWindowObject *private = (GdkWindowObject *)window;
  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_move: %p: +%d+%d\n",
			   GDK_WINDOW_HWND (window), x, y));
      
  impl = GDK_WINDOW_IMPL_WIN32 (private->impl);

  if (private->state & GDK_WINDOW_STATE_FULLSCREEN)
    return;

  if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
    _gdk_window_move_resize_child (window, x, y, impl->width, impl->height);
  else
    {
      RECT outer_rect;

      get_outer_rect (window, impl->width, impl->height, &outer_rect);
      
      adjust_for_gravity_hints (impl, &outer_rect, &x, &y);

      API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
			       x - _gdk_offset_x, y - _gdk_offset_y, 0, 0,
			       SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
    }
}

void
gdk_window_resize (GdkWindow *window,
		   gint       width,
		   gint       height)
{
  GdkWindowObject *private = (GdkWindowObject*) window;
  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  if (width < 1)
    width = 1;
  if (height < 1)
    height = 1;

  GDK_NOTE (MISC, g_print ("gdk_window_resize: %p: %dx%d\n",
			   GDK_WINDOW_HWND (window), width, height));

  impl = GDK_WINDOW_IMPL_WIN32 (private->impl);
  
  if (private->state & GDK_WINDOW_STATE_FULLSCREEN)
    return;

  if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
    _gdk_window_move_resize_child (window, private->x, private->y, width, height);
  else
    {
      RECT outer_rect;
      get_outer_rect (window, width, height, &outer_rect);

      API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
			       0, 0,
			       outer_rect.right - outer_rect.left,
			       outer_rect.bottom - outer_rect.top,
			       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
      private->resize_count += 1;
    }
}

void
gdk_window_move_resize (GdkWindow *window,
			gint       x,
			gint       y,
			gint       width,
			gint       height)
{
  GdkWindowObject *private = (GdkWindowObject*) window;
  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  if (width < 1)
    width = 1;
  if (height < 1)
    height = 1;
  
  impl = GDK_WINDOW_IMPL_WIN32 (private->impl);

  if (private->state & GDK_WINDOW_STATE_FULLSCREEN)
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %p: %dx%d@+%d+%d\n",
			   GDK_WINDOW_HWND (window),
			   width, height, x, y));
  
  if (GDK_WINDOW_TYPE (private) == GDK_WINDOW_CHILD)
    _gdk_window_move_resize_child (window, x, y, width, height);
  else
    {
      RECT outer_rect;

      get_outer_rect (window, width, height, &outer_rect);

      adjust_for_gravity_hints (impl, &outer_rect, &x, &y);

      API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
			       x - _gdk_offset_x, y - _gdk_offset_y,
			       outer_rect.right - outer_rect.left,
			       outer_rect.bottom - outer_rect.top,
			       SWP_NOACTIVATE | SWP_NOZORDER));
    }
}

void
gdk_window_reparent (GdkWindow *window,
		     GdkWindow *new_parent,
		     gint       x,
		     gint       y)
{
  GdkWindowObject *window_private;
  GdkWindowObject *parent_private;
  GdkWindowObject *old_parent_private;
  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);

  if (!new_parent)
    new_parent = _gdk_parent_root;

  window_private = (GdkWindowObject*) window;
  old_parent_private = (GdkWindowObject *) window_private->parent;
  parent_private = (GdkWindowObject*) new_parent;
  impl = GDK_WINDOW_IMPL_WIN32 (window_private->impl);

  if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (new_parent))
    {
      GDK_NOTE (MISC, g_print ("gdk_window_reparent: %p: %p\n",
			       GDK_WINDOW_HWND (window),
			       GDK_WINDOW_HWND (new_parent)));

      API_CALL (SetParent, (GDK_WINDOW_HWND (window),
			    GDK_WINDOW_HWND (new_parent)));

      API_CALL (MoveWindow, (GDK_WINDOW_HWND (window),
			     x, y, impl->width, impl->height, TRUE));
    }

  /* From here on, we treat parents of type GDK_WINDOW_FOREIGN like
   * the root window
   */
  if (GDK_WINDOW_TYPE (new_parent) == GDK_WINDOW_FOREIGN)
    new_parent = _gdk_parent_root;
  
  window_private->parent = (GdkWindowObject *)new_parent;

  if (old_parent_private)
    old_parent_private->children =
      g_list_remove (old_parent_private->children, window);

#if 0
  if ((old_parent_private &&
       (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
      (!old_parent_private && parent_private->guffaw_gravity))
    gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
#endif

  parent_private->children = g_list_prepend (parent_private->children, window);
  _gdk_window_init_position (GDK_WINDOW (window_private));
}

void
_gdk_windowing_window_clear_area (GdkWindow *window,
				  gint       x,
				  gint       y,
				  gint       width,
				  gint       height)
{
  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);

  if (!GDK_WINDOW_DESTROYED (window))
    {
      HDC hdc;

      if (width == 0)
	width = impl->width - x;
      if (height == 0)
	height = impl->height - y;
      GDK_NOTE (MISC, g_print ("_gdk_windowing_window_clear_area: %p: "
			       "%dx%d@+%d+%d\n",
			       GDK_WINDOW_HWND (window),
			       width, height, x, y));
      hdc = GetDC (GDK_WINDOW_HWND (window));
      IntersectClipRect (hdc, x, y, x + width + 1, y + height + 1);
      SendMessage (GDK_WINDOW_HWND (window), WM_ERASEBKGND, (WPARAM) hdc, 0);
      GDI_CALL (ReleaseDC, (GDK_WINDOW_HWND (window), hdc));
    }
}

void
_gdk_windowing_window_clear_area_e (GdkWindow *window,
				    gint       x,
				    gint       y,
				    gint       width,
				    gint       height)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (!GDK_WINDOW_DESTROYED (window))
    {
      RECT rect;

      GDK_NOTE (MISC, g_print ("_gdk_windowing_window_clear_area_e: %p: "
			       "%dx%d@+%d+%d\n",
			       GDK_WINDOW_HWND (window),
			       width, height, x, y));

      rect.left = x;
      rect.right = x + width + 1;
      rect.top = y;
      rect.bottom = y + height + 1;
      GDI_CALL (InvalidateRect, (GDK_WINDOW_HWND (window), &rect, TRUE));
      UpdateWindow (GDK_WINDOW_HWND (window));
    }
}

void
gdk_window_raise (GdkWindow *window)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (!GDK_WINDOW_DESTROYED (window))
    {
      GDK_NOTE (MISC, g_print ("gdk_window_raise: %p\n",
			       GDK_WINDOW_HWND (window)));

      API_CALL (BringWindowToTop, (GDK_WINDOW_HWND (window)));
    }
}

void
gdk_window_lower (GdkWindow *window)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (!GDK_WINDOW_DESTROYED (window))
    {
      GDK_NOTE (MISC, g_print ("gdk_window_lower: %p\n",
			       GDK_WINDOW_HWND (window)));

      API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_BOTTOM, 0, 0, 0, 0,
			       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
    }
}

void
gdk_window_set_hints (GdkWindow *window,
		      gint       x,
		      gint       y,
		      gint       min_width,
		      gint       min_height,
		      gint       max_width,
		      gint       max_height,
		      gint       flags)
{
  /* Note that this function is obsolete */

  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;
  
  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);

  GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %p: %dx%d..%dx%d @+%d+%d\n",
			   GDK_WINDOW_HWND (window),
			   min_width, min_height, max_width, max_height,
			   x, y));

  if (flags)
    {
      GdkGeometry geom;
      gint geom_mask = 0;

      geom.min_width  = min_width;
      geom.min_height = min_height;
      geom.max_width  = max_width;
      geom.max_height = max_height;

      if (flags & GDK_HINT_MIN_SIZE)
        geom_mask |= GDK_HINT_MIN_SIZE;

      if (flags & GDK_HINT_MAX_SIZE)
        geom_mask |= GDK_HINT_MAX_SIZE;

      gdk_window_set_geometry_hints (window, &geom, geom_mask);
    }
}

void 
gdk_window_set_geometry_hints (GdkWindow      *window,
			       GdkGeometry    *geometry,
			       GdkWindowHints  geom_mask)
{
  GdkWindowImplWin32 *impl;
#if 0
  WINDOWPLACEMENT size_hints;
  RECT rect;
  gint new_width = 0, new_height = 0;
#endif

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints: %p\n",
			   GDK_WINDOW_HWND (window)));

  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);

  impl->hint_flags = geom_mask;
  impl->hints = *geometry;

  if (geom_mask & GDK_HINT_POS)
    ; /* even the X11 mplementation doesn't care */

  if (geom_mask & GDK_HINT_MIN_SIZE)
    {
      GDK_NOTE (MISC, g_print ("... MIN_SIZE: %dx%d\n",
			       geometry->min_width, geometry->min_height));

#if 0
      /* Check if the current size of the window is in bounds */
      GetClientRect (GDK_WINDOW_HWND (window), &rect);

      if (rect.right < geometry->min_width &&
	  rect.bottom < geometry->min_height)
	{
	  new_width = geometry->min_width;
	  new_height = geometry->min_height;
	}
      else if (rect.right < geometry->min_width)
	{
	  new_width = geometry->min_width;
	  new_height = rect.bottom;
	}
      else if (rect.bottom < geometry->min_height)
	{
	  new_width = rect.right;
	  new_height = geometry->min_height;
	}
#endif
    }
  
  if (geom_mask & GDK_HINT_MAX_SIZE)
    {
      GDK_NOTE (MISC, g_print ("... MAX_SIZE: %dx%d\n",
			       geometry->max_width, geometry->max_height));

#if 0
      /* Check if the current size of the window is in bounds */
      GetClientRect (GDK_WINDOW_HWND (window), &rect);

      if (rect.right > geometry->max_width &&
	  rect.bottom > geometry->max_height)
	{
	  new_width = geometry->max_width;
	  new_height = geometry->max_height;
	}
      else if (rect.right > geometry->max_width)
	{
	  new_width = geometry->max_width;
	  new_height = rect.bottom;
	}
      else if (rect.bottom > geometry->max_height)
	{
	  new_width = rect.right;
	  new_height = geometry->max_height;
	}
#endif
    }

#if 0
  /* Apply new size constraints */
  if (new_width != 0 && new_height != 0)
    gdk_window_resize (window, new_width, new_height);
#endif

  if (geom_mask & GDK_HINT_BASE_SIZE)
    {
      GDK_NOTE (MISC, g_print ("... BASE_SIZE: %dx%d\n",
			       geometry->base_width, geometry->base_height));

#if 0
      size_hints.length = sizeof (size_hints);

      if (API_CALL (GetWindowPlacement, (GDK_WINDOW_HWND (window), &size_hints)))
	{
	  GDK_NOTE (MISC,
		    g_print ("... rcNormalPosition: (%ld,%ld)--(%ld,%ld)\n",
			     size_hints.rcNormalPosition.left,
			     size_hints.rcNormalPosition.top,
			     size_hints.rcNormalPosition.right,
			     size_hints.rcNormalPosition.bottom));
	  size_hints.rcNormalPosition.right =
	    size_hints.rcNormalPosition.left + geometry->base_width;
	  size_hints.rcNormalPosition.bottom =
	    size_hints.rcNormalPosition.top + geometry->base_height;
	  GDK_NOTE (MISC, g_print ("...setting: rcNormal: (%ld,%ld)--(%ld,%ld)\n",
				   size_hints.rcNormalPosition.left,
				   size_hints.rcNormalPosition.top,
				   size_hints.rcNormalPosition.right,
				   size_hints.rcNormalPosition.bottom));
	  API_CALL (SetWindowPlacement, (GDK_WINDOW_HWND (window), &size_hints));
	}
#endif
    }
  
  if (geom_mask & GDK_HINT_RESIZE_INC)
    {
      GDK_NOTE (MISC, g_print ("... RESIZE_INC: (%d,%d)\n",
			       geometry->width_inc, geometry->height_inc));
    }
  
  if (geom_mask & GDK_HINT_ASPECT)
    {
      GDK_NOTE (MISC, g_print ("... ASPECT: %g--%g\n",
			       geometry->min_aspect, geometry->max_aspect));
    }

  if (geom_mask & GDK_HINT_WIN_GRAVITY)
    {
      GDK_NOTE (MISC, g_print ("... GRAVITY: %d\n", geometry->win_gravity));
    }
}

void
gdk_window_set_title (GdkWindow   *window,
		      const gchar *title)
{
  char *mbtitle;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  g_return_if_fail (title != NULL);

  /* Empty window titles not allowed, so set it to just a period. */
  if (!title[0])
    title = ".";
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_title: %p: %s\n",
			   GDK_WINDOW_HWND (window), title));
  
  if (!GDK_WINDOW_DESTROYED (window))
    {
      /* As the title is in UTF-8 we must translate it
       * to the system codepage.
       */
      mbtitle = g_locale_from_utf8 (title, -1, NULL, NULL, NULL);
      API_CALL (SetWindowText, (GDK_WINDOW_HWND (window), mbtitle));
      g_free (mbtitle);
    }
}

void          
gdk_window_set_role (GdkWindow   *window,
		     const gchar *role)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_role: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   (role ? role : "NULL")));
  /* XXX */
}

void          
gdk_window_set_transient_for (GdkWindow *window, 
			      GdkWindow *parent)
{
  HWND window_id, parent_id;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %p: %p\n",
			   GDK_WINDOW_HWND (window),
			   GDK_WINDOW_HWND (parent)));

  if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (parent))
    return;

  if (((GdkWindowObject *) window)->window_type == GDK_WINDOW_CHILD)
    {
      GDK_NOTE (MISC, g_print ("...a child window!\n"));
      return;
    }
  
  window_id = GDK_WINDOW_HWND (window);
  parent_id = GDK_WINDOW_HWND (parent);

  /* This changes the *owner* of the window, despite the misleading
   * name. (Owner and parent are unrelated concepts.) At least that's
   * what people who seem to know what they talk about say on
   * USENET. Search on Google.
   */
  SetLastError (0);
  if (SetWindowLong (window_id, GWL_HWNDPARENT, (long) parent_id) == 0 &&
      GetLastError () != 0)
    WIN32_API_FAILED ("SetWindowLong");
}

void
gdk_window_set_background (GdkWindow *window,
			   GdkColor  *color)
{
  GdkWindowObject *private = (GdkWindowObject *)window;
  
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_background: %p: %s\n",
			   GDK_WINDOW_HWND (window), 
			   _gdk_win32_color_to_string (color)));

  private->bg_color = *color;

  if (private->bg_pixmap &&
      private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
      private->bg_pixmap != GDK_NO_BG)
    {
      g_object_unref (private->bg_pixmap);
      private->bg_pixmap = NULL;
    }
}

void
gdk_window_set_back_pixmap (GdkWindow *window,
			    GdkPixmap *pixmap,
			    gint       parent_relative)
{
  GdkWindowObject *private = (GdkWindowObject *)window;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  g_return_if_fail (pixmap == NULL || !parent_relative);
  g_return_if_fail (pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap));
  
  if (private->bg_pixmap &&
      private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
      private->bg_pixmap != GDK_NO_BG)
    g_object_unref (private->bg_pixmap);

  if (parent_relative)
    {
      private->bg_pixmap = GDK_PARENT_RELATIVE_BG;
      GDK_NOTE (MISC, g_print (G_STRLOC ": setting background pixmap to parent_relative\n"));
    }
  else
    {
      if (pixmap)
	{
	  g_object_ref (pixmap);
	  private->bg_pixmap = pixmap;
	}
      else
	{
	  private->bg_pixmap = GDK_NO_BG;
	}
    }
}

void
gdk_window_set_cursor (GdkWindow *window,
		       GdkCursor *cursor)
{
  GdkWindowImplWin32 *impl;
  GdkCursorPrivate *cursor_private;
  GdkWindowObject *parent_window;
  HCURSOR hcursor;
  HCURSOR hprevcursor;
  
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
  cursor_private = (GdkCursorPrivate*) cursor;
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  if (!cursor)
    hcursor = NULL;
  else
    hcursor = cursor_private->hcursor;
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_cursor: %p: %p\n",
			   GDK_WINDOW_HWND (window),
			   hcursor));

  /* First get the old cursor, if any (we wait to free the old one
   * since it may be the current cursor set in the Win32 API right
   * now).
   */
  hprevcursor = impl->hcursor;

  if (hcursor == NULL)
    impl->hcursor = NULL;
  else
    {
      /* We must copy the cursor as it is OK to destroy the GdkCursor
       * while still in use for some window. See for instance
       * gimp_change_win_cursor() which calls gdk_window_set_cursor
       * (win, cursor), and immediately afterwards gdk_cursor_destroy
       * (cursor).
       */
      if ((impl->hcursor = CopyCursor (hcursor)) == NULL)
	WIN32_API_FAILED ("CopyCursor");
      GDK_NOTE (MISC, g_print ("...CopyCursor (%p) = %p\n",
			       hcursor, impl->hcursor));
    }

  /* If the pointer is over our window, set new cursor if given */
  if (gdk_window_get_pointer(window, NULL, NULL, NULL) == window)
    if (impl->hcursor != NULL)
      SetCursor (impl->hcursor);

  /* Destroy the previous cursor: Need to make sure it's no longer in
   * use before we destroy it, in case we're not over our window but
   * the cursor is still set to our old one.
   */
  if (hprevcursor != NULL)
    {
      if (GetCursor() == hprevcursor)
	{
	  /* Look for a suitable cursor to use instead */
	  hcursor = NULL;
          parent_window = GDK_WINDOW_OBJECT (window)->parent;
          while (hcursor == NULL)
	    {
	      if (parent_window)
		{
		  impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
		  hcursor = impl->hcursor;
		  parent_window = parent_window->parent;
		}
	      else
		{
		  hcursor = LoadCursor (NULL, IDC_ARROW);
		}
	    }
          SetCursor (hcursor);
        }

      GDK_NOTE (MISC, g_print ("...DestroyCursor (%p)\n",
			       hprevcursor));
      
      API_CALL (DestroyCursor, (hprevcursor));
    }
}

void
gdk_window_get_geometry (GdkWindow *window,
			 gint      *x,
			 gint      *y,
			 gint      *width,
			 gint      *height,
			 gint      *depth)
{
  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
  
  if (!window)
    window = _gdk_parent_root;
  
  if (!GDK_WINDOW_DESTROYED (window))
    {
      RECT rect;

      API_CALL (GetClientRect, (GDK_WINDOW_HWND (window), &rect));

      if (window != _gdk_parent_root)
	{
	  POINT pt;
	  GdkWindow *parent = gdk_window_get_parent (window);

	  pt.x = rect.left;
	  pt.y = rect.top;
	  ClientToScreen (GDK_WINDOW_HWND (window), &pt);
	  ScreenToClient (GDK_WINDOW_HWND (parent), &pt);
	  rect.left = pt.x;
	  rect.top = pt.y;

	  pt.x = rect.right;
	  pt.y = rect.bottom;
	  ClientToScreen (GDK_WINDOW_HWND (window), &pt);
	  ScreenToClient (GDK_WINDOW_HWND (parent), &pt);
	  rect.right = pt.x;
	  rect.bottom = pt.y;

	  if (parent == _gdk_parent_root)
	    {
	      rect.left += _gdk_offset_x;
	      rect.top += _gdk_offset_y;
	      rect.right += _gdk_offset_x;
	      rect.bottom += _gdk_offset_y;
	    }
	}

      if (x)
	*x = rect.left;
      if (y)
	*y = rect.top;
      if (width)
	*width = rect.right - rect.left;
      if (height)
	*height = rect.bottom - rect.top;
      if (depth)
	*depth = gdk_drawable_get_visual (window)->depth;

      GDK_NOTE (MISC, g_print ("gdk_window_get_geometry: %p: %ldx%ldx%d@+%ld+%ld\n",
			       GDK_WINDOW_HWND (window),
			       rect.right - rect.left, rect.bottom - rect.top,
			       gdk_drawable_get_visual (window)->depth,
			       rect.left, rect.top));
    }
}

gint
gdk_window_get_origin (GdkWindow *window,
		       gint      *x,
		       gint      *y)
{
  gint return_val;
  gint tx = 0;
  gint ty = 0;

  g_return_val_if_fail (window != NULL, 0);

  if (!GDK_WINDOW_DESTROYED (window))
    {
      POINT pt;

      pt.x = 0;
      pt.y = 0;
      ClientToScreen (GDK_WINDOW_HWND (window), &pt);
      tx = pt.x;
      ty = pt.y;
      return_val = 1;
    }
  else
    return_val = 0;
  
  if (x)
    *x = tx + _gdk_offset_x;
  if (y)
    *y = ty + _gdk_offset_y;

  GDK_NOTE (MISC, g_print ("gdk_window_get_origin: %p: +%d+%d\n",
			   GDK_WINDOW_HWND (window),
			   tx, ty));
  return return_val;
}

gboolean
gdk_window_get_deskrelative_origin (GdkWindow *window,
				    gint      *x,
				    gint      *y)
{
  return gdk_window_get_origin (window, x, y);
}

void
gdk_window_get_root_origin (GdkWindow *window,
			    gint      *x,
			    gint      *y)
{
  GdkRectangle rect;

  g_return_if_fail (GDK_IS_WINDOW (window));

  gdk_window_get_frame_extents (window, &rect);

  if (x)
    *x = rect.x;

  if (y)
    *y = rect.y;

  GDK_NOTE (MISC, g_print ("gdk_window_get_root_origin: %p: +%d+%d\n",
			   GDK_WINDOW_HWND (window), rect.x, rect.y));
}

void
gdk_window_get_frame_extents (GdkWindow    *window,
                              GdkRectangle *rect)
{
  GdkWindowObject *private;
  HWND hwnd;
  RECT r;

  g_return_if_fail (GDK_IS_WINDOW (window));
  g_return_if_fail (rect != NULL);

  private = GDK_WINDOW_OBJECT (window);

  rect->x = 0;
  rect->y = 0;
  rect->width = 1;
  rect->height = 1;
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* FIXME: window is documented to be a toplevel GdkWindow, so is it really
   * necessary to walk its parent chain?
   */
  while (private->parent && ((GdkWindowObject*) private->parent)->parent)
    private = (GdkWindowObject*) private->parent;

  hwnd = GDK_WINDOW_HWND (window);

  /* find the frame window */
  while (HWND_DESKTOP != GetParent (hwnd))
    {
      hwnd = GetParent (hwnd);
      g_return_if_fail (NULL != hwnd);
    }

  API_CALL (GetWindowRect, (hwnd, &r));

  rect->x = r.left + _gdk_offset_x;
  rect->y = r.top + _gdk_offset_y;
  rect->width = r.right - r.left;
  rect->height = r.bottom - r.top;

  GDK_NOTE (MISC, g_print ("gdk_window_get_frame_extents: %p: %ldx%ld@+%ld+%ld\n",
			   GDK_WINDOW_HWND (window),
			   r.right - r.left, r.bottom - r.top,
			   r.left, r.top));
}

GdkWindow*
_gdk_windowing_window_get_pointer (GdkDisplay      *display,
				   GdkWindow       *window,
				   gint            *x,
				   gint            *y,
				   GdkModifierType *mask)
{
  GdkWindow *return_val;
  POINT screen_point, point;
  HWND hwnd, hwndc;
  BYTE kbd[256];

  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
  
  return_val = NULL;
  GetCursorPos (&screen_point);
  point = screen_point;
  ScreenToClient (GDK_WINDOW_HWND (window), &point);

  *x = point.x;
  *y = point.y;

  if (window == _gdk_parent_root)
    {
      *x += _gdk_offset_x;
      *y += _gdk_offset_y;
    }

  hwnd = WindowFromPoint (screen_point);
  if (hwnd != NULL)
    {
      gboolean done = FALSE;
      
      while (!done)
	{
	  point = screen_point;
	  ScreenToClient (hwnd, &point);
	  hwndc = ChildWindowFromPoint (hwnd, point);
	  if (hwndc == NULL)
	    done = TRUE;
	  else if (hwndc == hwnd)
	    done = TRUE;
	  else
	    hwnd = hwndc;
	}
      
      return_val = gdk_window_lookup ((GdkNativeWindow) hwnd);
    }
  else
    return_val = NULL;
      
  GetKeyboardState (kbd);
  *mask = 0;
  if (kbd[VK_SHIFT] & 0x80)
    *mask |= GDK_SHIFT_MASK;
  if (kbd[VK_CAPITAL] & 0x80)
    *mask |= GDK_LOCK_MASK;
  if (kbd[VK_CONTROL] & 0x80)
    *mask |= GDK_CONTROL_MASK;
  if (kbd[VK_MENU] & 0x80)
    *mask |= GDK_MOD1_MASK;
  if (kbd[VK_LBUTTON] & 0x80)
    *mask |= GDK_BUTTON1_MASK;
  if (kbd[VK_MBUTTON] & 0x80)
    *mask |= GDK_BUTTON2_MASK;
  if (kbd[VK_RBUTTON] & 0x80)
    *mask |= GDK_BUTTON3_MASK;
  
  return return_val;
}

void
_gdk_windowing_get_pointer (GdkDisplay       *display,
			    GdkScreen       **screen,
			    gint             *x,
			    gint             *y,
			    GdkModifierType  *mask)
{
  GdkScreen *default_screen = gdk_display_get_default_screen (display);
  GdkWindow *root_window = gdk_screen_get_root_window (default_screen);
  
  *screen = default_screen;
  _gdk_windowing_window_get_pointer (display, root_window, x, y, mask);
}

GdkWindow*
_gdk_windowing_window_at_pointer (GdkDisplay *display,
				  gint       *win_x,
				  gint       *win_y)
{
  GdkWindow *window;
  POINT point, pointc;
  HWND hwnd, hwndc;
  RECT rect;

  GetCursorPos (&pointc);
  point = pointc;
  hwnd = WindowFromPoint (point);

  if (hwnd == NULL)
    {
      window = _gdk_parent_root;
      *win_x = pointc.x + _gdk_offset_x;
      *win_y = pointc.y + _gdk_offset_y;
      return window;
    }
      
  ScreenToClient (hwnd, &point);

  do {
    hwndc = ChildWindowFromPoint (hwnd, point);
    ClientToScreen (hwnd, &point);
    ScreenToClient (hwndc, &point);
  } while (hwndc != hwnd && (hwnd = hwndc, 1));

  window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);

  if (window && (win_x || win_y))
    {
      GetClientRect (hwnd, &rect);
      *win_x = point.x - rect.left;
      *win_y = point.y - rect.top;
    }

  GDK_NOTE (MISC, g_print ("_gdk_windowing_window_at_pointer: +%d+%d %p%s\n",
			   *win_x, *win_y,
			   hwnd,
			   (window == NULL ? " NULL" : "")));

  return window;
}

GdkEventMask  
gdk_window_get_events (GdkWindow *window)
{
  g_return_val_if_fail (window != NULL, 0);
  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);

  if (GDK_WINDOW_DESTROYED (window))
    return 0;

  return GDK_WINDOW_OBJECT (window)->event_mask;
}

void          
gdk_window_set_events (GdkWindow   *window,
		       GdkEventMask event_mask)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* gdk_window_new() always sets the GDK_STRUCTURE_MASK, so better
   * set it here, too. Not that I know or remember why it is
   * necessary, will have to test some day.
   */
  GDK_WINDOW_OBJECT (window)->event_mask = GDK_STRUCTURE_MASK | event_mask;
}

void
gdk_window_shape_combine_mask (GdkWindow *window,
			       GdkBitmap *mask,
			       gint x, gint y)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (!mask)
    {
      GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %p: none\n",
			       GDK_WINDOW_HWND (window)));
      SetWindowRgn (GDK_WINDOW_HWND (window), NULL, TRUE);
    }
  else
    {
      HRGN hrgn;
      RECT rect;

      /* Convert mask bitmap to region */
      hrgn = _gdk_win32_bitmap_to_hrgn (mask);

      GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %p: %p\n",
			       GDK_WINDOW_HWND (window),
			       GDK_WINDOW_HWND (mask)));

      _gdk_win32_get_adjusted_client_rect (window, &rect);

      OffsetRgn (hrgn, -rect.left, -rect.top);
      OffsetRgn (hrgn, x, y);

      /* If this is a top-level window, add the title bar to the region */
      if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL)
	{
	  HRGN tmp = CreateRectRgn (0, 0, rect.right - rect.left, -rect.top);
	  CombineRgn (hrgn, hrgn, tmp, RGN_OR);
	  DeleteObject (tmp);
	}
      
      SetWindowRgn (GDK_WINDOW_HWND (window), hrgn, TRUE);
    }
}

void
gdk_window_set_override_redirect (GdkWindow *window,
				  gboolean   override_redirect)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  g_warning ("gdk_window_set_override_redirect not implemented");
}

void          
gdk_window_set_icon_list (GdkWindow *window,
			  GList     *pixbufs)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* We could convert it to a hIcon and DrawIcon () it when getting
   * a WM_PAINT with IsIconic, but is it worth it ? Same probably
   * goes for gdk_window_set_icon (). Patches accepted :-)  --hb
   * Or do we only need to deliver the Icon on WM_GETICON ?
   */
}

void          
gdk_window_set_icon (GdkWindow *window, 
		     GdkWindow *icon_window,
		     GdkPixmap *pixmap,
		     GdkBitmap *mask)
{
  ICONINFO ii;
  HICON hIcon;
  gint w = 0, h = 0;
  GdkWindowImplWin32 *impl;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);

  if (pixmap)
    {
      static int num = 0;
      HBITMAP hbmmask = NULL;

      gdk_drawable_get_size (GDK_DRAWABLE(pixmap), &w, &h);

      /* we need the inverted mask for the XOR op */
      {
        HDC hdc1 = CreateCompatibleDC (NULL);
        HBITMAP hbmold1;

        hbmmask = CreateCompatibleBitmap (hdc1, w, h);
        hbmold1 = SelectObject (hdc1, hbmmask);
        if (mask)
          {
            HDC hdc2 = CreateCompatibleDC (NULL);
            HBITMAP hbmold2 = SelectObject (hdc2, GDK_PIXMAP_HBITMAP (mask));
            GDI_CALL (BitBlt, (hdc1, 0,0,w,h, hdc2, 0,0, NOTSRCCOPY));
            GDI_CALL (SelectObject, (hdc2, hbmold2));
            GDI_CALL (DeleteDC, (hdc2));
          }
        else
          {
            RECT rect;
            GetClipBox (hdc1, &rect);
            GDI_CALL (FillRect, (hdc1, &rect, GetStockObject (WHITE_BRUSH)));
          }
        GDI_CALL (SelectObject, (hdc1, hbmold1));
        GDI_CALL (DeleteDC, (hdc1));
      }

      ii.fIcon = TRUE;
      ii.xHotspot = ii.yHotspot = 0; /* ignored for icons */
      ii.hbmMask = hbmmask;
      ii.hbmColor = GDK_PIXMAP_HBITMAP (pixmap); 
      hIcon = CreateIconIndirect (&ii);
      if (!hIcon)
        WIN32_API_FAILED ("CreateIconIndirect");
      GDI_CALL (DeleteObject, (hbmmask));
#if 0 /* to debug pixmap and mask setting */
      {
        GdkPixbuf* pixbuf = NULL;
        char name[256];

        pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, w, h);
	if (pixbuf)
          {
            num = (num + 1) % 999; /* restrict maximim number */
            sprintf (name, "c:\\temp\\ico%03dpixm.png", num); 
            gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL);
            gdk_pixbuf_unref (pixbuf);
          }
        pixbuf = !mask ? NULL : gdk_pixbuf_get_from_drawable (NULL, mask, NULL, 0, 0, 0, 0, w, h);
	if (pixbuf)
          {
            sprintf (name, "c:\\temp\\ico%03dmask.png", num); 
            gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL);
            gdk_pixbuf_unref (pixbuf);
          }
      }
#endif

      hIcon = (HICON)SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
      if (impl->hicon)
        GDI_CALL (DestroyIcon, (impl->hicon));
      impl->hicon = hIcon;
    }
  else
    {
      /* reseting to default icon */
      if (impl->hicon)
        {
          hIcon = (HICON)SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, 0);
          GDI_CALL (DestroyIcon, (impl->hicon));
          impl->hicon = NULL;
        }
    }

  GDK_NOTE (MISC, g_print ("gdk_window_set_icon: %p: %p %dx%d\n", GDK_WINDOW_HWND (window), impl->hicon, w, h));
}

void
gdk_window_set_icon_name (GdkWindow   *window, 
			  const gchar *name)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;
  
  API_CALL (SetWindowText, (GDK_WINDOW_HWND (window), name));
}

void          
gdk_window_set_group (GdkWindow *window, 
		      GdkWindow *leader)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  g_return_if_fail (leader != NULL);
  g_return_if_fail (GDK_IS_WINDOW (leader));

  if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (leader))
    return;
  
  g_warning ("gdk_window_set_group not implemented");
}

void
gdk_window_set_decorations (GdkWindow      *window,
			    GdkWMDecoration decorations)
{
  LONG style, bits;
  const LONG settable_bits = WS_BORDER|WS_THICKFRAME|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_decorations: %p: %s%s%s%s%s%s%s\n",
			   GDK_WINDOW_HWND (window),
			   (decorations & GDK_DECOR_ALL ? "ALL " : ""),
			   (decorations & GDK_DECOR_BORDER ? "BORDER " : ""),
			   (decorations & GDK_DECOR_RESIZEH ? "RESIZEH " : ""),
			   (decorations & GDK_DECOR_TITLE ? "TITLE " : ""),
			   (decorations & GDK_DECOR_MENU ? "MENU " : ""),
			   (decorations & GDK_DECOR_MINIMIZE ? "MINIMIZE " : ""),
			   (decorations & GDK_DECOR_MAXIMIZE ? "MAXIMIZE " : "")));

  style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);

  bits = 0;

  if (decorations & GDK_DECOR_BORDER)
    bits |= WS_BORDER;
  if (decorations & GDK_DECOR_RESIZEH)
    bits |= WS_THICKFRAME;
  if (decorations & GDK_DECOR_TITLE)
    bits |= WS_CAPTION;
  if (decorations & GDK_DECOR_MENU)
    bits |= WS_SYSMENU;
  if (decorations & GDK_DECOR_MINIMIZE)
    bits |= WS_MINIMIZEBOX;
  if (decorations & GDK_DECOR_MAXIMIZE)
    bits |= WS_MAXIMIZEBOX;

  if (decorations & GDK_DECOR_ALL)
    style |= settable_bits, style &= ~bits;
  else
    style &= ~settable_bits, style |= bits;
  
  SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, style);
  SetWindowPos (GDK_WINDOW_HWND (window), NULL, 0, 0, 0, 0,
		SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
		SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
}

gboolean
gdk_window_get_decorations(GdkWindow       *window,
			   GdkWMDecoration *decorations)
{
  LONG style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);

  *decorations = 0;

  if (style & WS_BORDER)
    *decorations |= GDK_DECOR_BORDER;
  if (style & WS_THICKFRAME)
    *decorations |= GDK_DECOR_RESIZEH;
  if (style & WS_CAPTION)
    *decorations |= GDK_DECOR_TITLE;
  if (style & WS_SYSMENU)
    *decorations |= GDK_DECOR_MENU;
  if (style & WS_MINIMIZEBOX)
    *decorations |= GDK_DECOR_MINIMIZE;
  if (style & WS_MAXIMIZEBOX)
    *decorations |= GDK_DECOR_MAXIMIZE;

  return *decorations != 0;
}

void
gdk_window_set_functions (GdkWindow    *window,
			  GdkWMFunction functions)
{
  LONG style, bits;
  const LONG settable_bits = (WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU);

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  GDK_NOTE (MISC, g_print ("gdk_window_set_functions: %p: %s%s%s%s%s%s\n",
			   GDK_WINDOW_HWND (window),
			   (functions & GDK_FUNC_ALL ? "ALL " : ""),
			   (functions & GDK_FUNC_RESIZE ? "RESIZE " : ""),
			   (functions & GDK_FUNC_MOVE ? "MOVE " : ""),
			   (functions & GDK_FUNC_MINIMIZE ? "MINIMIZE " : ""),
			   (functions & GDK_FUNC_MAXIMIZE ? "MAXIMIZE " : ""),
			   (functions & GDK_FUNC_CLOSE ? "CLOSE " : "")));

  style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);

  bits = 0;

  if (functions & GDK_FUNC_RESIZE)
    bits |= WS_THICKFRAME;
  if (functions & GDK_FUNC_MOVE)
    bits |= (WS_THICKFRAME|WS_SYSMENU);
  if (functions & GDK_FUNC_MINIMIZE)
    bits |= WS_MINIMIZEBOX;
  if (functions & GDK_FUNC_MAXIMIZE)
    bits |= WS_MAXIMIZEBOX;
  if (functions & GDK_FUNC_CLOSE)
    bits |= WS_SYSMENU;
  
  if (functions & GDK_FUNC_ALL)
    style |= settable_bits, style &= ~bits;
  else
    style &= ~settable_bits, style |= bits;
  
  SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, style);
  SetWindowPos (GDK_WINDOW_HWND (window), NULL, 0, 0, 0, 0,
		SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
		SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
}

static void
QueryTree (HWND   hwnd,
	   HWND **children,
	   gint  *nchildren)
{
  guint i, n;
  HWND child;

  n = 0;
  do {
    if (n == 0)
      child = GetWindow (hwnd, GW_CHILD);
    else
      child = GetWindow (child, GW_HWNDNEXT);
    if (child != NULL)
      n++;
  } while (child != NULL);

  if (n > 0)
    {
      *children = g_new (HWND, n);
      for (i = 0; i < n; i++)
	{
	  if (i == 0)
	    child = GetWindow (hwnd, GW_CHILD);
	  else
	    child = GetWindow (child, GW_HWNDNEXT);
	  *children[i] = child;
	}
    }
}

static void
gdk_propagate_shapes (HANDLE   win,
		      gboolean merge)
{
   RECT emptyRect;
   HRGN region, childRegion;
   HWND *list = NULL;
   gint i, num;

   SetRectEmpty (&emptyRect);
   region = CreateRectRgnIndirect (&emptyRect);
   if (merge)
     GetWindowRgn (win, region);
   
   QueryTree (win, &list, &num);
   if (list != NULL)
     {
       WINDOWPLACEMENT placement;

       placement.length = sizeof (WINDOWPLACEMENT);
       /* go through all child windows and combine regions */
       for (i = 0; i < num; i++)
	 {
	   GetWindowPlacement (list[i], &placement);
	   if (placement.showCmd == SW_SHOWNORMAL)
	     {
	       childRegion = CreateRectRgnIndirect (&emptyRect);
	       GetWindowRgn (list[i], childRegion);
	       CombineRgn (region, region, childRegion, RGN_OR);
	       DeleteObject (childRegion);
	     }
	  }
       SetWindowRgn (win, region, TRUE);
       g_free (list);
     }
   else
     DeleteObject (region);
}

void
gdk_window_set_child_shapes (GdkWindow *window)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
   
  if (GDK_WINDOW_DESTROYED (window))
    return;

  gdk_propagate_shapes (GDK_WINDOW_HWND (window), FALSE);
}

void
gdk_window_merge_child_shapes (GdkWindow *window)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  gdk_propagate_shapes (GDK_WINDOW_HWND (window), TRUE);
}

gboolean 
gdk_window_set_static_gravities (GdkWindow *window,
				 gboolean   use_static)
{
  GdkWindowObject *private = (GdkWindowObject *)window;
  
  g_return_val_if_fail (window != NULL, FALSE);
  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);

  if (!use_static == !private->guffaw_gravity)
    return TRUE;
  
  if (use_static)
    return FALSE;
  
  private->guffaw_gravity = use_static;
  
  return TRUE;
}

/*
 * Setting window states
 */
void
gdk_window_iconify (GdkWindow *window)
{
  HWND old_active_window;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_iconify: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (((GdkWindowObject *) window)->state)));

  if (GDK_WINDOW_IS_MAPPED (window))
    {
      old_active_window = GetActiveWindow ();
      ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
      if (old_active_window != GDK_WINDOW_HWND (window))
	SetActiveWindow (old_active_window);
    }
  else
    {
      gdk_synthesize_window_state (window,
                                   0,
                                   GDK_WINDOW_STATE_ICONIFIED);
    }
}

void
gdk_window_deiconify (GdkWindow *window)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_deiconify: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (((GdkWindowObject *) window)->state)));

  if (GDK_WINDOW_IS_MAPPED (window))
    {  
      show_window_internal (window, FALSE, TRUE);
    }
  else
    {
      gdk_synthesize_window_state (window,
                                   GDK_WINDOW_STATE_ICONIFIED,
                                   0);
    }
}

void
gdk_window_stick (GdkWindow *window)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* FIXME: Do something? */
}

void
gdk_window_unstick (GdkWindow *window)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* FIXME: Do something? */
}

void
gdk_window_maximize (GdkWindow *window)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_maximize: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (((GdkWindowObject *) window)->state)));

  if (GDK_WINDOW_IS_MAPPED (window))
    ShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
  else
    gdk_synthesize_window_state (window,
				 0,
				 GDK_WINDOW_STATE_MAXIMIZED);
}

void
gdk_window_unmaximize (GdkWindow *window)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_unmaximize: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (((GdkWindowObject *) window)->state)));

  if (GDK_WINDOW_IS_MAPPED (window))
    ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
  else
    gdk_synthesize_window_state (window,
				 GDK_WINDOW_STATE_MAXIMIZED,
				 0);
}

typedef struct _FullscreenInfo FullscreenInfo;

struct _FullscreenInfo
{
  RECT  r;
  guint hint_flags;
  LONG  style;
};

void
gdk_window_fullscreen (GdkWindow *window)
{
  gint width, height;
  FullscreenInfo *fi;
  GdkWindowObject *private = (GdkWindowObject *) window;

  g_return_if_fail (GDK_IS_WINDOW (window));

  fi = g_new (FullscreenInfo, 1);

  if (!GetWindowRect (GDK_WINDOW_HWND (window), &(fi->r)))
    g_free (fi);
  else
    {
      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (private->impl);

      width = GetSystemMetrics (SM_CXSCREEN);
      height = GetSystemMetrics (SM_CYSCREEN);
 
      /* remember for restoring */
      fi->hint_flags = impl->hint_flags;
      impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
      g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
      fi->style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE);

      SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, 
                     (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
      if (!SetWindowPos (GDK_WINDOW_HWND (window), HWND_TOP /*not MOST, taskswitch!*/,
                         0, 0, width, height,
                         SWP_NOCOPYBITS | SWP_SHOWWINDOW))
        WIN32_API_FAILED ("SetWindowPos");

      gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
    }
}

void
gdk_window_unfullscreen (GdkWindow *window)
{
  FullscreenInfo *fi;
  GdkWindowObject *private = (GdkWindowObject *) window;

  g_return_if_fail (GDK_IS_WINDOW (window));

  fi = g_object_get_data (G_OBJECT(window), "fullscreen-info");
  if (fi)
    {
      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (private->impl);

      impl->hint_flags = fi->hint_flags;
      SetWindowLong (GDK_WINDOW_HWND (window), GWL_STYLE, fi->style);
      if (!SetWindowPos (GDK_WINDOW_HWND (window), HWND_NOTOPMOST,
                         fi->r.left, fi->r.top, fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
                         SWP_NOCOPYBITS | SWP_SHOWWINDOW))
         WIN32_API_FAILED ("SetWindowPos");

      g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
      g_free (fi);

      gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
    }
}

void
gdk_window_focus (GdkWindow *window,
                  guint32    timestamp)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;
  
  GDK_NOTE (MISC, g_print ("gdk_window_focus: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   _gdk_win32_window_state_to_string (((GdkWindowObject *) window)->state)));

  ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
  SetFocus (GDK_WINDOW_HWND (window));
}

void
gdk_window_set_modal_hint (GdkWindow *window,
			   gboolean   modal)
{
  GdkWindowObject *private;

  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  private = (GdkWindowObject*) window;

  private->modal_hint = modal;

  if (GDK_WINDOW_IS_MAPPED (window))
    API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), 
			     modal ? HWND_TOPMOST : HWND_NOTOPMOST,
			     0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE));
}

void
gdk_window_set_skip_taskbar_hint (GdkWindow *window,
				  gboolean   skips_taskbar)
{
  LONG extended_style;

  g_return_if_fail (GDK_IS_WINDOW (window));

  GDK_NOTE (MISC, g_print ("gdk_window_set_skip_taskbar_hint: %p: %s\n",
			   GDK_WINDOW_HWND (window),
			   skips_taskbar ? "TRUE" : "FALSE"));

  extended_style = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE);

  if (skips_taskbar)
    extended_style |= WS_EX_TOOLWINDOW;
  else
    extended_style &= ~WS_EX_TOOLWINDOW;

  SetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE, extended_style);
}

void
gdk_window_set_skip_pager_hint (GdkWindow *window,
				gboolean   skips_pager)
{
  g_return_if_fail (GDK_IS_WINDOW (window));
}

void
gdk_window_set_type_hint (GdkWindow        *window,
			  GdkWindowTypeHint hint)
{
  g_return_if_fail (window != NULL);
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  GDK_NOTE (MISC, g_print ("gdk_window_set_type_hint: %p: %d\n",
			   GDK_WINDOW_HWND (window), hint));
  switch (hint)
    {
    case GDK_WINDOW_TYPE_HINT_DIALOG:
      break;
    case GDK_WINDOW_TYPE_HINT_MENU:
      gdk_window_set_decorations (window,
				  GDK_DECOR_ALL |
				  GDK_DECOR_RESIZEH |
				  GDK_DECOR_MINIMIZE |
				  GDK_DECOR_MAXIMIZE);
      break;
    case GDK_WINDOW_TYPE_HINT_TOOLBAR:
      gdk_window_set_skip_taskbar_hint (window, TRUE);
      break;
    case GDK_WINDOW_TYPE_HINT_UTILITY:
      break;
    case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
      break;
    case GDK_WINDOW_TYPE_HINT_DOCK:
      break;
    case GDK_WINDOW_TYPE_HINT_DESKTOP:
      break;
    default:
      g_warning ("Unknown hint %d passed to gdk_window_set_type_hint", hint);
      /* Fall thru */
    case GDK_WINDOW_TYPE_HINT_NORMAL:
      break;
    }
}

void
gdk_window_shape_combine_region (GdkWindow *window,
                                 GdkRegion *shape_region,
                                 gint       offset_x,
                                 gint       offset_y)
{
  g_return_if_fail (GDK_IS_WINDOW (window));

  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* XXX: even on X implemented conditional ... */  
}

void
gdk_window_begin_resize_drag (GdkWindow     *window,
                              GdkWindowEdge  edge,
                              gint           button,
                              gint           root_x,
                              gint           root_y,
                              guint32        timestamp)
{
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* XXX: isn't all this default on win32 ... */  
}

void
gdk_window_begin_move_drag (GdkWindow *window,
                            gint       button,
                            gint       root_x,
                            gint       root_y,
                            guint32    timestamp)
{
  g_return_if_fail (GDK_IS_WINDOW (window));
  
  if (GDK_WINDOW_DESTROYED (window))
    return;

  /* XXX: isn't all this default on win32 ... */  
}

GdkWindow *
gdk_window_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
{
  g_return_val_if_fail (display == gdk_display_get_default(), NULL);

  return gdk_window_lookup (anid);
}
