Tcl Source Code

Artifact [2773bf1e53]
Login

Artifact 2773bf1e5378b19096d1dbdd90eebe3db5ccfb3f:

Attachment "None" to ticket [402096ffff] added by nobody 2000-10-24 05:24:11.
Index: tkWinWm.c
===================================================================
RCS file: /cvsroot/tk/win/tkWinWm.c,v
retrieving revision 1.27
diff -c -r1.27 tkWinWm.c
*** tkWinWm.c	2000/11/03 01:22:17	1.27
--- tkWinWm.c	2000/11/13 19:12:49
***************
*** 53,58 ****
--- 53,116 ----
  #define HANDLER_SIZE(cmdLength) \
      ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
  
+ /* 
+  * These next four structs represent how the icon information is stored
+  * in an ICO file, and in an icon resource.
+  */
+ typedef struct {
+ 	UINT			Width, Height, Colors; /*  Width, Height and bpp */
+ 	LPBYTE			lpBits;                /*  ptr to DIB bits */
+ 	DWORD			dwNumBytes;            /*  how many bytes? */
+ 	LPBITMAPINFO	lpbi;                          /*  ptr to header */
+ 	LPBYTE			lpXOR;                 /*  ptr to XOR image bits */
+ 	LPBYTE			lpAND;                 /*  ptr to AND image bits */
+ 	HICON			hIcon;                 /*  DAS ICON */
+ } ICONIMAGE, *LPICONIMAGE;
+ typedef struct {
+ 	BOOL		bHasChanged;                     /*  Has image changed? */
+ 	TCHAR		szOriginalICOFileName[MAX_PATH]; /*  Original name */
+ 	TCHAR		szOriginalDLLFileName[MAX_PATH]; /*  Original name */
+ 	int		nNumImages;                      /*  How many images? */
+ 	ICONIMAGE	IconImages[1];                   /*  Image entries */
+ } ICONRESOURCE, *LPICONRESOURCE;
+ typedef struct {
+ 	BYTE	bWidth;               /*  Width of the image */
+ 	BYTE	bHeight;              /*  Height of the image (times 2) */
+ 	BYTE	bColorCount;          /*  Number of colors in image (0 if >=8bpp) */
+ 	BYTE	bReserved;            /*  Reserved */
+ 	WORD	wPlanes;              /*  Color Planes */
+ 	WORD	wBitCount;            /*  Bits per pixel */
+ 	DWORD	dwBytesInRes;         /*  how many bytes in this resource? */
+ 	DWORD	dwImageOffset;        /*  where in the file is this image */
+ } ICONDIRENTRY, *LPICONDIRENTRY;
+ typedef struct {
+ 	WORD			idReserved;   /*  Reserved */
+ 	WORD			idType;       /*  resource type (1 for icons) */
+ 	WORD			idCount;      /*  how many images? */
+ 	ICONDIRENTRY	idEntries[1];         /*  the entries for each image */
+ } ICONDIR, *LPICONDIR;
+ 
+ /* 
+  * A pointer to one of these strucutures is associated with each
+  * toplevel.  This allows us to free up all memory associated with icon
+  * resources when a window is deleted or if the window's icon is
+  * changed.  They are simply reference counted according to:
+  * 
+  * (i) how many WmInfo structures point to this object
+  * (ii) whether the ThreadSpecificData defined in this file contains
+  * a pointer to this object.
+  * 
+  * The former count is for windows whose icons are individually
+  * set, and the latter is for the global default icon choice.
+  */
+ typedef struct WinIconInstance {
+     int refCount;		/* Number of instances that share this
+ 				  * data structure. */
+     LPICONRESOURCE iconResource; /* Pointer to icon resource data for image. */
+ } WinIconInstance;
+ 
+ typedef struct WinIconInstance *WinIconPtr;
+ 
  /*
   * A data structure of the following type holds window-manager-related
   * information for each top-level window in an application.

***************
*** 165,170 ****
--- 223,230 ----
  				* property, or NULL. */
      int flags;			/* Miscellaneous flags, defined below. */
      int numTransients;		/* number of transients on this window */
+     WinIconPtr iconPtr;     /* pointer to titlebar icon structure for
+                                  * this window, or NULL. */
      struct TkWmInfo *nextPtr;	/* Next in list of all top-level windows. */
  } WmInfo;
  
***************
*** 256,261 ****
--- 316,323 ----
  				  * been initialized. */
      int firstWindow;             /* Flag, cleared when the first window
  				  * is mapped in a non-iconic state. */
+     WinIconPtr iconPtr;   /* IconPtr being used as default for all
+                                   * toplevels, or NULL. */
  } ThreadSpecificData;
  static Tcl_ThreadDataKey dataKey;
  
***************
*** 269,275 ****
  				* been initialized. */
  TCL_DECLARE_MUTEX(winWmMutex)
  
- 
  /*
   * Forward declarations for procedures defined in this file:
   */
--- 331,336 ----
***************
*** 307,318 ****
  			    WPARAM wParam, LPARAM lParam));
  static void		WmWaitVisibilityProc _ANSI_ARGS_((
  			    ClientData clientData, XEvent *eventPtr));
  
  /*
   *----------------------------------------------------------------------
   *
!  * InitWm --
   *
   *	This routine creates the Wm toplevel decorative frame class.
   *
   * Results:
--- 368,635 ----
  			    WPARAM wParam, LPARAM lParam));
  static void		WmWaitVisibilityProc _ANSI_ARGS_((
  			    ClientData clientData, XEvent *eventPtr));
+ static LPICONRESOURCE   ReadIconFromICOFile _ANSI_ARGS_((
+ 			    Tcl_Interp *interp, LPCTSTR fileName));
+ static WinIconPtr       ReadIconFromFile _ANSI_ARGS_((
+ 			    Tcl_Interp *interp, char *fileName));
+ static int     		ReadICOHeader _ANSI_ARGS_((HANDLE hFile));
+ static BOOL 		AdjustIconImagePointers _ANSI_ARGS_((LPICONIMAGE lpImage));
+ static HICON 		MakeIconFromResource _ANSI_ARGS_((LPICONIMAGE lpIcon));
+ static HICON 		GetIcon _ANSI_ARGS_((WinIconPtr titlebaricon, 
+ 			    int icon_size));
+ static int 		WinSetIcon _ANSI_ARGS_((Tcl_Interp *interp, char *fileName, 
+ 			    Tk_Window tkw));
+ static void 		FreeIcon _ANSI_ARGS_((LPICONRESOURCE lpIR));
+ static void  		DecrIconRefCount _ANSI_ARGS_((WinIconPtr titlebaricon));
+ 
+ /* Used in BytesPerLine */
+ #define WIDTHBYTES(bits)      ((((bits) + 31)>>5)<<2)
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * DIBNumColors --
+  *
+  *	Calculates the number of entries in the color table, given by 
+  *	LPSTR lpbi - pointer to the CF_DIB memory block.  Used by
+  *	titlebar icon code.
+  *
+  * Results:
+  *	
+  *      WORD - Number of entries in the color table.
+  *
+  * Side effects: None.
+  *	
+  *
+  *----------------------------------------------------------------------
+  */
+ static WORD DIBNumColors( LPSTR lpbi )
+ {
+     WORD wBitCount;
+     DWORD dwClrUsed;
+ 
+     dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
+ 
+     if (dwClrUsed)
+ 	return (WORD) dwClrUsed;
+ 
+     wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
+ 

+     switch (wBitCount)
+     {
+ 	case 1: return 2;
+ 	case 4: return 16;
+ 	case 8:	return 256;
+ 	default:return 0;
+     }
+ }
  
  /*
   *----------------------------------------------------------------------
   *
!  * PaletteSize --
!  *
!  *	Calculates the number of bytes in the color table, as given by
!  *	LPSTR lpbi - pointer to the CF_DIB memory block.  Used by
!  *	titlebar icon code.
!  *
!  * Results:
!  *	number of bytes in the color table
!  *
!  * Side effects: None.
!  *	
!  *
!  *----------------------------------------------------------------------
!  */
! static WORD PaletteSize( LPSTR lpbi )
! {
!     return ((WORD)( DIBNumColors( lpbi ) * sizeof( RGBQUAD )) );
! }
! 
! /*
!  *----------------------------------------------------------------------
!  *
!  * FindDIBits --
!  *
!  *	Locate the image bits in a CF_DIB format DIB, as given by
!  *	LPSTR lpbi - pointer to the CF_DIB memory block.  Used by
!  *	titlebar icon code.
!  *
!  * Results:
!  *	pointer to the image bits
!  *
!  * Side effects: None
!  *	
!  *
!  *----------------------------------------------------------------------
!  */
! static LPSTR FindDIBBits( LPSTR lpbi )
! {
!    return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) );
! }
! 
! /*
!  *----------------------------------------------------------------------
!  *
!  * BytesPerLine --
!  *
!  *	Calculates the number of bytes in one scan line, as given by
!  *	LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER
!  *	that begins the CF_DIB block.  Used by titlebar icon code.
!  *
!  * Results:
!  *	number of bytes in one scan line (DWORD aligned)
!  *
!  * Side effects: None
!  *	
!  *
!  *----------------------------------------------------------------------
!  */
! static DWORD BytesPerLine( LPBITMAPINFOHEADER lpBMIH )
! {
!     return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
! }
! 
! /*
!  *----------------------------------------------------------------------
!  *
!  * AdjustIconImagePointers --
!  *
!  *	Adjusts internal pointers in icon resource struct, as given
!  *	by LPICONIMAGE lpImage - the resource to handle.  Used by
!  *	titlebar icon code.
!  *
!  * Results:
!  *	BOOL - TRUE for success, FALSE for failure
!  *
!  * Side effects:
!  *	
!  *
!  *----------------------------------------------------------------------
!  */
! BOOL AdjustIconImagePointers( LPICONIMAGE lpImage )
! {
!     /*  Sanity check */
!     if (lpImage==NULL)
! 	return FALSE;
!     /*  BITMAPINFO is at beginning of bits */
!     lpImage->lpbi = (LPBITMAPINFO)lpImage->lpBits;
!     /*  Width - simple enough */
!     lpImage->Width = lpImage->lpbi->bmiHeader.biWidth;
!     /*  Icons are stored in funky format where height is doubled - account for it */
!     lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2;
!     /*  How many colors? */
!     lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes * lpImage->lpbi->bmiHeader.biBitCount;
!     /*  XOR bits follow the header and color table */
!     lpImage->lpXOR = (LPBYTE)FindDIBBits(((LPSTR)lpImage->lpbi));
!     /*  AND bits follow the XOR bits */

!     lpImage->lpAND = lpImage->lpXOR + (lpImage->Height*BytesPerLine((LPBITMAPINFOHEADER)(lpImage->lpbi)));
!     return TRUE;
! }
! 
! /*
!  *----------------------------------------------------------------------
!  *
!  * MakeIconFromResource --
!  *
!  *	
!  *
!  * Results:
!  *	
!  *
!  * Side effects:
!  *	
!  *
!  *----------------------------------------------------------------------
!  */
! static HICON MakeIconFromResource( LPICONIMAGE lpIcon ){
!     HICON hIcon ;
!     static FARPROC pfnCreateIconFromResourceEx=NULL;
!     static int initinfo=0;
!     /*  Sanity Check */
!     if (lpIcon == NULL)
! 	return NULL;
!     if (lpIcon->lpBits == NULL)
! 	return NULL;
!     if (!initinfo) {
! 	HMODULE hMod = GetModuleHandleA("USER32.DLL");
! 	initinfo=1;
! 	if(hMod){
! 	    pfnCreateIconFromResourceEx = GetProcAddress(hMod,"CreateIconFromResourceEx");
! 	}
!     }
!     /*  Let the OS do the real work :) */
!     if (pfnCreateIconFromResourceEx!=NULL) {
! 	hIcon = (HICON) (pfnCreateIconFromResourceEx)
! 	(lpIcon->lpBits, lpIcon->dwNumBytes, TRUE, 0x00030000,
! 	(*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biWidth,
! 	(*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biHeight/2, 0 );
!     } else {
! 	hIcon = NULL;
!     }
!     /*  It failed, odds are good we're on NT so try the non-Ex way */
!     if (hIcon == NULL)    {
! 	/*  We would break on NT if we try with a 16bpp image */
! 	if (lpIcon->lpbi->bmiHeader.biBitCount != 16) {
! 	    hIcon = CreateIconFromResource( lpIcon->lpBits, lpIcon->dwNumBytes, TRUE, 0x00030000 );
! 	}
!     }
!     return hIcon;
! }
! 
! /*
!  *----------------------------------------------------------------------
   *
+  * ReadICOHeader --
+  *
+  *	Reads the header from an ICO file, as specfied by hFile.
+  *
+  * Results:
+  *	UINT - Number of images in file, -1 for failure.
+  *
+  * Side effects:
+  *	Registers a new window class.
+  *
+  *----------------------------------------------------------------------
+  */
+ static int ReadICOHeader( HANDLE hFile )
+ {
+     WORD    Input;
+     DWORD	dwBytesRead;
+ 
+     /*  Read the 'reserved' WORD */
+     if (! ReadFile( hFile, &Input, sizeof( WORD ), &dwBytesRead, NULL ))
+ 	return -1;
+     /*  Did we get a WORD? */
+     if (dwBytesRead != sizeof( WORD ))
+ 	return -1;
+     /*  Was it 'reserved' ?   (ie 0) */
+     if (Input != 0)
+ 	return -1;
+     /*  Read the type WORD */
+     if (! ReadFile( hFile, &Input, sizeof( WORD ), &dwBytesRead, NULL ))
+ 	return -1;
+     /*  Did we get a WORD? */
+     if (dwBytesRead != sizeof( WORD ))
+ 	return -1;
+     /*  Was it type 1? */
+     if (Input != 1)
+ 	return -1;
+     /*  Get the count of images */
+     if (! ReadFile( hFile, &Input, sizeof( WORD ), &dwBytesRead, NULL ))
+ 	return -1;
+     /*  Did we get a WORD? */
+     if (dwBytesRead != sizeof( WORD ))
+ 	return -1;
+     /*  Return the count */
+     return (int)Input;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * InitWindowClass --
+  *
   *	This routine creates the Wm toplevel decorative frame class.
   *

   * Results:
***************
*** 323,360 ****
   *
   *----------------------------------------------------------------------
   */
! 
! static void
! InitWm(void)
! {
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
!             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
      WNDCLASS * classPtr;
  
      if (! tsdPtr->initialized) {
  	tsdPtr->initialized = 1;
  	tsdPtr->firstWindow = 1;
      }
      if (! initialized) {
  	Tcl_MutexLock(&winWmMutex);
  	if (! initialized) {
  	    initialized = 1;
- 	    classPtr = &toplevelClass;
  
!     /*
!      * When threads are enabled, we cannot use CLASSDC because
!      * threads will then write into the same device context.
!      * 
!      * This is a hack; we should add a subsystem that manages
!      * device context on a per-thread basis.  See also tkWinX.c,
!      * which also initializes a WNDCLASS structure.
!      */
  
! #ifdef TCL_THREADS
  	    classPtr->style = CS_HREDRAW | CS_VREDRAW;
! #else
  	    classPtr->style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
! #endif
  	    classPtr->cbClsExtra = 0;
  	    classPtr->cbWndExtra = 0;
  	    classPtr->hInstance = Tk_GetHINSTANCE();
--- 640,675 ----
   *
   *----------------------------------------------------------------------
   */
! static int InitWindowClass(WinIconPtr titlebaricon) {
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
! 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
      WNDCLASS * classPtr;
+     classPtr = &toplevelClass;
  
      if (! tsdPtr->initialized) {
  	tsdPtr->initialized = 1;
  	tsdPtr->firstWindow = 1;
+ 	tsdPtr->iconPtr = NULL;
      }
      if (! initialized) {
  	Tcl_MutexLock(&winWmMutex);
  	if (! initialized) {
  	    initialized = 1;
  
! 	    /*
! 	     * When threads are enabled, we cannot use CLASSDC because
! 	     * threads will then write into the same device context.
! 	     * 
! 	     * This is a hack; we should add a subsystem that manages
! 	     * device context on a per-thread basis.  See also tkWinX.c,
! 	     * which also initializes a WNDCLASS structure.
! 	     */
  
! 	#ifdef TCL_THREADS
  	    classPtr->style = CS_HREDRAW | CS_VREDRAW;
! 	#else
  	    classPtr->style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
! 	#endif
  	    classPtr->cbClsExtra = 0;
  	    classPtr->cbWndExtra = 0;
  	    classPtr->hInstance = Tk_GetHINSTANCE();
***************
*** 362,368 ****
  	    classPtr->lpszMenuName = NULL;
  	    classPtr->lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
  	    classPtr->lpfnWndProc = WmProc;
! 	    classPtr->hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
  	    classPtr->hCursor = LoadCursor(NULL, IDC_ARROW);
  
  	    if (!RegisterClass(classPtr)) {
--- 677,695 ----
  	    classPtr->lpszMenuName = NULL;
  	    classPtr->lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
  	    classPtr->lpfnWndProc = WmProc;
! 	    if (titlebaricon == NULL) {
! 		classPtr->hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
! 	    } else {
! 		classPtr->hIcon = GetIcon(titlebaricon, ICON_BIG);
! 		if (classPtr->hIcon == NULL) {
! 		    return TCL_ERROR;
! 		}

! 		/* 
! 		* Store pointer to default icon so we know when 
! 		* we need to free that information
! 		*/
! 		tsdPtr->iconPtr = titlebaricon;
! 	    }
  	    classPtr->hCursor = LoadCursor(NULL, IDC_ARROW);
  
  	    if (!RegisterClass(classPtr)) {
***************
*** 371,381 ****
--- 698,1160 ----
  	}
  	Tcl_MutexUnlock(&winWmMutex);
      }
+     return TCL_OK;
  }
  
  /*
   *----------------------------------------------------------------------
   *
+  * InitWm --
+  *
+  *	This initialises the window manager
+  *
+  * Results:
+  *	None.
+  *
+  * Side effects:
+  *	Registers a new window class.
+  *
+  *----------------------------------------------------------------------
+  */
+ static void
+ InitWm(void)
+ {
+     /* Ignore return result */
+     (void) InitWindowClass(NULL);
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * WinSetIcon --
+  *
+  *	Sets either the default toplevel titlebar icon, or the icon
+  *	for a specific toplevel (if tkw is given, then only that
+  *	window is used).
+  *
+  * Results:
+  *	A standard Tcl return code.
+  *
+  * Side effects:
+  *	One or all windows may have their icon changed.
+  *	The Tcl result may be modified.
+  *	The window-manager will be initialised if it wasn't already.
+  *	The given window will be forced into existence.
+  *
+  *----------------------------------------------------------------------
+  */
+ int
+ WinSetIcon(interp, fileName, tkw)
+     Tcl_Interp *interp;
+     char *fileName;
+     Tk_Window tkw;
+ {
+     WinIconPtr titlebaricon = NULL;
+     WmInfo *wmPtr;
+     HWND hwnd;
+     int application = 0;
+     
+     if (tkw == NULL) {
+         tkw = Tk_MainWindow(interp);
+ 	application = 1;
+     }
+     
+     if (!(Tk_IsTopLevel(tkw))) {
+ 	Tcl_AppendResult(interp, "window \"", Tk_PathName(tkw), 
+ 		"\" isn't a top-level window", (char *) NULL);
+ 	return TCL_ERROR;
+     }
+     if (Tk_WindowId(tkw) == None) {
+ 	Tk_MakeWindowExist(tkw);
+     }
+     /* 
+      * Either return NULL, or return a valid titlebaricon with its
+      * ref count already incremented.
+      */
+     titlebaricon = ReadIconFromFile(interp, fileName);
+     if (titlebaricon == NULL) {
+ 	return TCL_ERROR;
+     }
+     /* Now we must get the window's wrapper, not the window itself */
+     wmPtr = ((TkWindow*)tkw)->wmInfoPtr;
+     hwnd = wmPtr->wrapper;
+ 
+     if (application) {
+ 	if (hwnd == NULL) {
+ 	    /* 
+ 	     * I don't actually think this is ever the correct thing, unless
+ 	     * perhaps the window doesn't have a wrapper.  But I believe all
+ 	     * windows have wrappers.
+ 	     */
+ 	    hwnd = Tk_GetHWND(Tk_WindowId(tkw));
+ 	}
+ 	/* 
+ 	* If we aren't initialised, then just initialise with the user's
+ 	* icon.  Otherwise our icon choice will be ignored moments later
+ 	* when Tk finishes initialising.
+ 	*/
+ 	if (!initialized) {
+ 	    if (InitWindowClass(titlebaricon) != TCL_OK) {
+ 		Tcl_AppendResult(interp,"Unable to set icon", (char*)NULL);
+ 		goto setIconError;
+ 	    }
+ 	} else {
+ 	    ThreadSpecificData *tsdPtr;
+ 	    if (!SetClassLong(hwnd, GCL_HICONSM, (LPARAM)GetIcon(titlebaricon, ICON_SMALL))) {

+ 		/* For some reason this triggers, even though it seems to be successful */
+ 		/* This is probably related to the WNDCLASS vs WNDCLASSEX difference */
+ 		/*
+ 		* Tcl_AppendResult(interp,"Unable to set new small icon", (char*)NULL);
+ 		* return TCL_ERROR;
+ 		*/
+ 		
+ 	    }
+ 	    if (!SetClassLong(hwnd, GCL_HICON, (LPARAM)GetIcon(titlebaricon, ICON_BIG))) {
+ 		Tcl_AppendResult(interp,"Unable to set new icon", (char*)NULL);
+ 		goto setIconError;
+ 	    }
+ 	    tsdPtr = (ThreadSpecificData *) 
+ 		    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ 	    if (tsdPtr->iconPtr != NULL) {
+ 		DecrIconRefCount(tsdPtr->iconPtr);
+ 	    }
+ 	    tsdPtr->iconPtr = titlebaricon;
+ 	}
+     } else {
+ 	if (!initialized) {
+ 	    /* 
+ 	     * Need to initialise the wm otherwise we will fail on
+ 	     * code which tries to set a toplevel's icon before that
+ 	     * happens
+ 	     */
+ 	    InitWindowClass(NULL);
+ 	}
+ 	/* 
+ 	* The following code is exercised if you do
+ 	* 
+ 	*   toplevel .t ; wm titlebaricon .t foo.icr
+ 	* 
+ 	* i.e. the wm hasn't had time to properly create
+ 	* the '.t' window before you set the icon.
+ 	*/
+ 	if (hwnd == NULL) {
+ 	    /* 
+ 	     * This little snippet is copied from the 'Map' function,
+ 	     * and should probably be placed in one proper location
+ 	     */
+ 	    if (wmPtr->titleUid == NULL) {
+ 		wmPtr->titleUid = wmPtr->winPtr->nameUid;
+ 	    }
+ 	    UpdateWrapper(wmPtr->winPtr);
+ 	    wmPtr = ((TkWindow*)tkw)->wmInfoPtr;
+ 	    hwnd = wmPtr->wrapper;
+ 	    if (hwnd == NULL) {
+ 		Tcl_AppendResult(interp,"Can't set icon; window has no wrapper.", (char*)NULL);
+ 		goto setIconError;
+ 	    }
+ 	}
+ 	SendMessage(hwnd,WM_SETICON,ICON_SMALL,(LPARAM)GetIcon(titlebaricon, ICON_SMALL));
+ 	SendMessage(hwnd,WM_SETICON,ICON_BIG,(LPARAM)GetIcon(titlebaricon, ICON_BIG));
+ 	
+ 	/* Sort out new and old icon issues */
+ 	if (wmPtr->iconPtr != NULL) {
+ 	    /* Free any old icon ptr which is associated with this window */
+ 	    DecrIconRefCount(wmPtr->iconPtr);
+ 	}
+ 	/* 
+ 	* We do not need to increment the ref count for the titlebaricon, because
+ 	* it was already incremented when we retrieved it 
+ 	*/
+ 	wmPtr->iconPtr = titlebaricon;
+     }
+     return TCL_OK;
+   setIconError:
+     /* We didn't use the titlebaricon after all */
+     DecrIconRefCount(titlebaricon);
+     return TCL_ERROR;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * ReadIconFromFile --
+  *
+  *	Read the contents of a .ico, .icr, etc. file and extract an
+  *	icon resource, if possible, otherwise NULL is returned, and
+  *	an error message will already be in the interpreter.  Note that
+  *	currently this procedure is simply a straightforward cast, but
+  *	in the future we may require more complex icon formats, and this
+  *	procedure will then need to do the manipulation.
+  *
+  * Results:
+  *	A WinIconPtr structure containing the icons in the file, with
+  *	its ref count already incremented. The calling procedure should
+  *	either place this structure inside a WmInfo structure, or it should
+  *	pass it on to DecrIconRefCount() to ensure no memory leaks occur.

+  *
+  * Side effects:
+  *	Memory is allocated for the returned structure and the icons
+  *	it contains.  If the structure is not wanted, it should be
+  *	passed to DecrIconRefCount, and in any case a valid ref count
+  *	should be ensured to avoid memory leaks.
+  *	
+  *	Currently icon resources are not shared, so the ref count
+  *	of one of these structures will always be 0 or 1.  However
+  *	all we need do is implement a hash table to map between filenames
+  *	and WinIconPtr structures and no other code will need to 
+  *	be changed.  The pseudo-code for this is implemented below
+  *	in the 'if (0)' branch.
+  *
+  *----------------------------------------------------------------------
+  */
+ static WinIconPtr 
+ ReadIconFromFile(interp, fileName) 
+     Tcl_Interp *interp;
+     char *fileName;
+ {
+     LPICONRESOURCE lpIR;
+     WinIconPtr titlebaricon;
+ 
+     if (0 /* If we already have an icon for this filename */) {
+ 	titlebaricon = NULL; /* Get the real value from a hash table */
+ 	titlebaricon->refCount++;
+     } else {
+ 	lpIR = ReadIconFromICOFile(interp,fileName);
+ 
+ 	titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
+ 	titlebaricon->iconResource = lpIR;
+ 	titlebaricon->refCount = 1;
+     }
+     return titlebaricon;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * DecrIconRefCount --
+  *
+  *	Reduces the reference count.
+  *
+  * Results:
+  *	None.
+  *
+  * Side effects:
+  *	If the ref count falls to zero, free the memory associated
+  *	with the icon resource structures.  In this case the pointer
+  *	passed into this function is no longer valid.
+  *
+  *----------------------------------------------------------------------
+  */
+ static void DecrIconRefCount(WinIconPtr titlebaricon) {
+     titlebaricon->refCount--;
+     
+     if (titlebaricon->refCount <= 0) {
+ 	if (titlebaricon->iconResource != NULL) {
+ 	    FreeIcon(titlebaricon->iconResource);
+ 	}
+ 	titlebaricon->iconResource = NULL;
+     }
+     ckfree((char*)titlebaricon);
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * FreeIcon --
+  *
+  *	Frees all memory associated with a previously loaded 
+  *	titlebaricon.  The titlebaricon pointer is no longer
+  *	valid once this function returns.
+  *
+  * Results:
+  *	None.
+  *
+  * Side effects:
+  *	
+  *
+  *----------------------------------------------------------------------
+  */
+ static void FreeIcon(LPICONRESOURCE lpIR) {
+     int i;
+     
+     /* Free all the bits */
+     for (i=0; i< lpIR->nNumImages; i++) {
+ 	if (lpIR->IconImages[i].lpBits != NULL) {
+ 	    ckfree((char*)lpIR->IconImages[i].lpBits);
+ 	}
+ 	if (lpIR->IconImages[i].hIcon != NULL) {
+ 	    DestroyIcon(lpIR->IconImages[i].hIcon);
+ 	}
+     }
+     ckfree ((char*)lpIR);
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * GetIcon --
+  *
+  *	Extracts an icon of a given size from an icon resource
+  *
+  * Results:
+  *	Returns the icon, if found, else NULL.
+  *

+  * Side effects:
+  *	
+  *
+  *----------------------------------------------------------------------
+  */
+ static HICON GetIcon(WinIconPtr titlebaricon, int icon_size) {
+     LPICONRESOURCE lpIR = titlebaricon->iconResource;
+     unsigned int size = (icon_size == 0 ? 16 : 32);
+     int i;
+     
+     for( i = 0; i < lpIR->nNumImages; i++ ) {
+ 	/*take the first or a 32x32 16 color icon*/
+ 	if(lpIR->IconImages[i].Height==size 
+ 	   && lpIR->IconImages[i].Width==size
+ 	   && lpIR->IconImages[i].Colors >= 4) {
+ 	    return lpIR->IconImages[i].hIcon;
+ 	}
+     }
+     return NULL;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
+  * ReadIconFromICOFile --
+  *
+  *	Reads an Icon Resource from an ICO file, as given by 
+  *	LPCTSTR fileName - Name of the ICO file
+  *
+  * Results:
+  *	Returns an icon resource, if found, else NULL.
+  *
+  * Side effects:
+  *      May leave error messages in the Tcl interpreter.
+  *
+  *----------------------------------------------------------------------
+  */
+ LPICONRESOURCE ReadIconFromICOFile(Tcl_Interp* interp,LPCTSTR fileName){
+     LPICONRESOURCE    	lpIR , lpNew ;
+     HANDLE            	hFile;
+     int                 i;
+     DWORD            	dwBytesRead;
+     LPICONDIRENTRY    	lpIDE;
+ 
+ 
+     /*  Open the file */
+     if ((hFile = CreateFile( fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE)    {
+ 	Tcl_AppendResult(interp,"Error opening file \"", fileName, 
+ 	                 "\" for reading",(char*)NULL);
+ 	return NULL;
+     }
+     /*  Allocate memory for the resource structure */
+     if ((lpIR = (LPICONRESOURCE) ckalloc( sizeof(ICONRESOURCE) )) == NULL)    {
+ 	Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+ 	CloseHandle( hFile );
+ 	return NULL;
+     }
+     /*  Read in the header */
+     if ((lpIR->nNumImages = ReadICOHeader( hFile )) == -1)    {
+ 	Tcl_AppendResult(interp,"Error reading file header",(char*)NULL);
+ 	CloseHandle( hFile );
+ 	ckfree((char*) lpIR );
+ 	return NULL;
+     }
+     /*  Adjust the size of the struct to account for the images */
+     if ((lpNew = (LPICONRESOURCE) ckrealloc( (char*)lpIR, sizeof(ICONRESOURCE) + ((lpIR->nNumImages-1) * sizeof(ICONIMAGE)) )) == NULL)    {
+ 	Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+ 	CloseHandle( hFile );
+ 	ckfree( (char*)lpIR );
+ 	return NULL;
+     }
+     lpIR = lpNew;
+     /*  Store the original name */
+     lstrcpy( lpIR->szOriginalICOFileName, fileName );
+     lstrcpy( lpIR->szOriginalDLLFileName, "" );
+     /*  Allocate enough memory for the icon directory entries */
+     if ((lpIDE = (LPICONDIRENTRY) ckalloc( lpIR->nNumImages * sizeof( ICONDIRENTRY ) ) ) == NULL)     {
+ 	Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+ 	CloseHandle( hFile );
+ 	ckfree( (char*)lpIR );
+ 	return NULL;
+     }
+     /*  Read in the icon directory entries */
+     if (! ReadFile( hFile, lpIDE, lpIR->nNumImages * sizeof( ICONDIRENTRY ), &dwBytesRead, NULL ))    {
+ 	Tcl_AppendResult(interp,"Error reading file",(char*)NULL);

+ 	CloseHandle( hFile );
+ 	ckfree( (char*)lpIR );
+ 	return NULL;
+     }
+     if (dwBytesRead != lpIR->nNumImages * sizeof( ICONDIRENTRY ))    {
+ 	Tcl_AppendResult(interp,"Error reading file",(char*)NULL);
+ 	CloseHandle( hFile );
+ 	ckfree( (char*)lpIR );
+ 	return NULL;
+     }
+     /*  Loop through and read in each image */
+     for( i = 0; i < lpIR->nNumImages; i++ )    {
+ 	/*  Allocate memory for the resource */
+ 	if ((lpIR->IconImages[i].lpBits = (LPBYTE) ckalloc(lpIDE[i].dwBytesInRes)) == NULL)
+ 	{
+ 	    Tcl_AppendResult(interp,"Error allocating memory",(char*)NULL);
+ 	    CloseHandle( hFile );
+ 	    ckfree( (char*)lpIR );
+ 	    ckfree( (char*)lpIDE );
+ 	    return NULL;
+ 	}
+ 	lpIR->IconImages[i].dwNumBytes = lpIDE[i].dwBytesInRes;
+ 	/*  Seek to beginning of this image */
+ 	if (SetFilePointer( hFile, lpIDE[i].dwImageOffset, NULL, FILE_BEGIN ) == 0xFFFFFFFF)
+ 	{
+ 	    Tcl_AppendResult(interp,"Error seeking in file",(char*)NULL);
+ 	    CloseHandle( hFile );
+ 	    ckfree( (char*)lpIR );
+ 	    ckfree( (char*)lpIDE );
+ 	    return NULL;
+ 	}
+ 	/*  Read it in */
+ 	if (! ReadFile( hFile, lpIR->IconImages[i].lpBits, lpIDE[i].dwBytesInRes, &dwBytesRead, NULL ))
+ 	{
+ 	    Tcl_AppendResult(interp,"Error reading file",(char*)NULL);
+ 	    CloseHandle( hFile );
+ 	    ckfree( (char*)lpIR );
+ 	    ckfree( (char*)lpIDE );
+ 	    return NULL;
+ 	}
+ 	if (dwBytesRead != lpIDE[i].dwBytesInRes) 
+ 	{
+ 	    Tcl_AppendResult(interp,"Error reading file",(char*)NULL);
+ 	    CloseHandle( hFile );
+ 	    ckfree( (char*)lpIDE );
+ 	    ckfree( (char*)lpIR );
+ 	    return NULL;
+ 	}
+ 	/*  Set the internal pointers appropriately */
+ 	if (!AdjustIconImagePointers( &(lpIR->IconImages[i]))) {
+ 	    Tcl_AppendResult(interp,"Error converting to internal format",(char*)NULL);
+ 	    CloseHandle( hFile );
+ 	    ckfree( (char*)lpIDE );
+ 	    ckfree( (char*)lpIR );
+ 	    return NULL;
+ 	}
+ 	lpIR->IconImages[i].hIcon=MakeIconFromResource(&(lpIR->IconImages[i]));
+     }
+     /*  Clean up */
+     ckfree((char*)lpIDE);
+     CloseHandle(hFile);
+     if(lpIR==NULL){
+ 	Tcl_AppendResult(interp,"Reading of ",fileName," failed!",(char*)NULL);
+ 	return NULL;
+     }
+     return lpIR;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
   * GetTopLevel --
   *
   *	This function retrieves the TkWindow associated with the
***************
*** 389,395 ****
   *
   *----------------------------------------------------------------------
   */
- 
  static TkWindow *
  GetTopLevel(hwnd)
      HWND hwnd;
--- 1168,1173 ----
***************
*** 625,630 ****
--- 1403,1409 ----
      wmPtr->cmdArgv = NULL;
      wmPtr->clientMachine = NULL;
      wmPtr->flags = WM_NEVER_MAPPED;
+     wmPtr->iconPtr = NULL;
      wmPtr->nextPtr = winPtr->dispPtr->firstWmPtr;
      winPtr->dispPtr->firstWmPtr = wmPtr;
  
***************
*** 673,678 ****
--- 1452,1459 ----
      HWND child = TkWinGetHWND(winPtr->window);
      int x, y, width, height, state;
      WINDOWPLACEMENT place;
+     HICON hSmallIcon = NULL;
+     HICON hBigIcon = NULL;

      Tcl_DString titleString;
      int *childStateInfo = NULL;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
***************
*** 795,800 ****
--- 1576,1586 ----
  #endif
      }
      oldWrapper = SetParent(child, wmPtr->wrapper);
+     if (oldWrapper) {
+ 	hSmallIcon = (HICON) SendMessage(oldWrapper,WM_GETICON,ICON_SMALL,(LPARAM)NULL);
+ 	hBigIcon = (HICON) SendMessage(oldWrapper,WM_GETICON,ICON_BIG,(LPARAM)NULL);
+     }
+     
      if (oldWrapper && (oldWrapper != wmPtr->wrapper) 
  	    && (oldWrapper != GetDesktopWindow())) {
  #ifdef _WIN64
***************
*** 834,840 ****
  
      wmPtr->flags &= ~WM_NEVER_MAPPED;
      SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0);
! 
      /*
       * Force an initial transition from withdrawn to the real
       * initial state.	
--- 1620,1626 ----
  
      wmPtr->flags &= ~WM_NEVER_MAPPED;
      SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0);
!     
      /*
       * Force an initial transition from withdrawn to the real
       * initial state.	
***************
*** 844,849 ****
--- 1630,1642 ----
      wmPtr->hints.initial_state = WithdrawnState;
      TkpWmSetState(winPtr, state);
  
+     if (hSmallIcon != NULL) {
+ 	SendMessage(wmPtr->wrapper,WM_SETICON,ICON_SMALL,(LPARAM)hSmallIcon);
+     }
+     if (hBigIcon != NULL) {
+ 	SendMessage(wmPtr->wrapper,WM_SETICON,ICON_BIG,(LPARAM)hBigIcon);
+     }
+ 
      /*
       * If we are embedded then force a mapping of the window now,
       * because we do not necessarily own the wrapper and may not
***************
*** 1158,1163 ****
--- 1951,1965 ----
  	    DestroyWindow(Tk_GetHWND(winPtr->window));
  	}
      }
+     if (wmPtr->iconPtr != NULL) {
+ 	/* 
+ 	* This may delete the icon resource data.  I believe we
+ 	* should do this after destroying the decorative frame,
+ 	* because the decorative frame is using this icon.
+ 	*/
+         DecrIconRefCount(wmPtr->iconPtr);
+     }
+     
      ckfree((char *) wmPtr);
      winPtr->wmInfoPtr = NULL;
  }
***************
*** 1674,1688 ****
  	}
      } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
  	    && (length >= 5)) {
! 	Pixmap pixmap;
! 
! 	if ((argc != 3) && (argc != 4)) {
  	    Tcl_AppendResult(interp, "wrong # arguments: must be \"",
! 		    argv[0], " iconbitmap window ?bitmap?\"",
  		    (char *) NULL);
  	    return TCL_ERROR;
! 	}
! 	if (argc == 3) {
  	    if (wmPtr->hints.flags & IconPixmapHint) {
  		Tcl_SetResult(interp,
  			Tk_NameOfBitmap(winPtr->display,
--- 2476,2500 ----
  	}
      } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
  	    && (length >= 5)) {
! 	/* If true, then set for all windows. */
! 	int isDefault = 0;
! 	
! 	if ((argc < 3) || (argc > 5)) {
  	    Tcl_AppendResult(interp, "wrong # arguments: must be \"",
! 		    argv[0], " iconbitmap window ?-default? ?image?\"",
  		    (char *) NULL);
  	    return TCL_ERROR;
! 	} else if (argc == 5) {
! 	    /* If we have 5 arguments, we must have a '-default' flag */
! 	    if (strcmp(argv[3],"-default")) {
! 		Tcl_AppendResult(interp, "illegal option \"", 

! 			argv[3], " must be \"-default\"", 
! 			(char *) NULL);
! 		return TCL_ERROR;
! 	    }
! 	    isDefault = 1;
! 	} else if (argc == 3) {
! 	    /* No arguments were given */
  	    if (wmPtr->hints.flags & IconPixmapHint) {
  		Tcl_SetResult(interp,
  			Tk_NameOfBitmap(winPtr->display,
***************
*** 1690,1708 ****
  	    }
  	    return TCL_OK;
  	}
! 	if (*argv[3] == '\0') {
  	    if (wmPtr->hints.icon_pixmap != None) {
  		Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  	    }
  	    wmPtr->hints.flags &= ~IconPixmapHint;
  	} else {
! 	    pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
! 		    Tk_GetUid(argv[3]));
! 	    if (pixmap == None) {
! 		return TCL_ERROR;
  	    }
- 	    wmPtr->hints.icon_pixmap = pixmap;
- 	    wmPtr->hints.flags |= IconPixmapHint;
  	}
      } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
  	    && (length >= 5)) {
--- 2502,2546 ----
  	    }
  	    return TCL_OK;
  	}
! 	if (*argv[argc-1] == '\0') {
  	    if (wmPtr->hints.icon_pixmap != None) {
  		Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  	    }
  	    wmPtr->hints.flags &= ~IconPixmapHint;
  	} else {
! 	    /* 
! 	     * In the future this block of code will use Tk's 'image'
! 	     * functionality to allow all supported image formats.
! 	     * However, this will require a change to the way icons are
! 	     * handled.  We will need to add icon<->image conversions
! 	     * routines.
! 	     *
! 	     * Until that happens we simply try to find an icon in the
! 	     * given argument, and if that fails, we use the older
! 	     * bitmap code.  We do things this way round (icon then
! 	     * bitmap), because the bitmap code actually seems to have
! 	     * no visible effect, so we want to give the icon code the
! 	     * first try at doing something.
! 	     */
! 	    
! 	    /* 
! 	     * Try to set the icon for the window.  If it is a '-default'
! 	     * icon, we must pass in NULL
! 	     */
! 	    if (WinSetIcon(interp, argv[argc-1], 
! 			   (isDefault ? NULL : (Tk_Window) winPtr)) != TCL_OK) {
! 		/* The argument wasn't a valid icon, so try with a bitmap */
! 		/* Clear the error message which was placed in the interpreter */
! 		Pixmap pixmap;
! 		Tcl_ResetResult(interp);
! 		pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
! 			Tk_GetUid(argv[argc-1]));
! 		if (pixmap == None) {
! 		    return TCL_ERROR;
! 		}
! 		wmPtr->hints.icon_pixmap = pixmap;
! 		wmPtr->hints.flags |= IconPixmapHint;
  	    }
  	}
      } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
  	    && (length >= 5)) {