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)) {