? win/tkWinPointer.xbutton.c
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tktoolkit/tk/ChangeLog,v
retrieving revision 1.758.2.179
diff -u -r1.758.2.179 ChangeLog
--- ChangeLog	23 Sep 2004 00:56:13 -0000	1.758.2.179
+++ ChangeLog	23 Sep 2004 01:43:57 -0000
@@ -1,3 +1,12 @@
+2004-09-22  Jeff Hobbs  <jeffh@ActiveState.com>
+
+	* win/tkWinInt.h (TkWinDisplayChanged): added decl
+	* win/tkWinX.c (TkWinDisplayChanged, TkpOpenDisplay): Correctly
+	* win/tkWinWm.c (InvalidateSubTreeDepth, WmProc):     handle color
+	and screen resolution changes.  Tested for 16/24/32 bpp changes on
+	XP.  May need more fixes for 8bpp switch, use of special
+	colormaps, or other special palette handling cases.  [Bug 223689]
+
 2004-09-22  Mo DeJong  <mdejong@users.sourceforge.net>
 
 	* generic/tkInt.decls: Add decl for TkWinGetPlatformTheme.
Index: win/tkWinInt.h
===================================================================
RCS file: /cvsroot/tktoolkit/tk/win/tkWinInt.h,v
retrieving revision 1.14.2.4
diff -u -r1.14.2.4 tkWinInt.h
--- win/tkWinInt.h	23 Sep 2004 00:56:15 -0000	1.14.2.4
+++ win/tkWinInt.h	23 Sep 2004 01:43:57 -0000
@@ -172,6 +172,11 @@
 EXTERN HICON	TkWinGetIcon(Tk_Window tkw, DWORD iconsize);
 
 /*
+ * Used by tkWinX.c on for certain system display change messages
+ */
+EXTERN void	TkWinDisplayChanged(Display *display);
+
+/*
  * The following structure keeps track of whether we are using the 
  * multi-byte or the wide-character interfaces to the operating system.
  * System calls should be made through the following function table.
Index: win/tkWinWm.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/win/tkWinWm.c,v
retrieving revision 1.54.2.12
diff -u -r1.54.2.12 tkWinWm.c
--- win/tkWinWm.c	23 Sep 2004 00:35:09 -0000	1.54.2.12
+++ win/tkWinWm.c	23 Sep 2004 01:43:57 -0000
@@ -416,6 +416,7 @@
 			    int isForemost));
 static void		InvalidateSubTree _ANSI_ARGS_((TkWindow *winPtr,
 			    Colormap colormap));
+static void		InvalidateSubTreeDepth _ANSI_ARGS_((TkWindow *winPtr));
 static int		ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
 			    char *string, TkWindow *winPtr));
 static void		RefreshColormap _ANSI_ARGS_((Colormap colormap,
@@ -5829,6 +5830,13 @@
 {
     TkWindow *winPtr = (TkWindow *) tkwin;
 
+    /*
+     * XXX: This is not correct for multiple monitors.  There may be many
+     * changes required to get this right, and it may effect existing
+     * applications that don't consider possible <0 vroot.  See
+     * http://msdn.microsoft.com/library/en-us/gdi/monitor_3lrn.asp
+     * for more info.
+     */
     *xPtr = 0;
     *yPtr = 0;
     *widthPtr = DisplayWidth(winPtr->display, winPtr->screenNum);
@@ -6858,6 +6866,62 @@
 /*
  *----------------------------------------------------------------------
  *
+ * InvalidateSubTreeDepth --
+ *
+ *	This function recursively updates depth info for a window and
+ *	all of its children that belong to the same toplevel.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	Sets the depth of each window to that of the display.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+InvalidateSubTreeDepth(winPtr)
+    TkWindow *winPtr;
+{
+    Display *display = Tk_Display(winPtr);
+    int screenNum = Tk_ScreenNumber(winPtr);
+    TkWindow *childPtr;
+
+    winPtr->depth = DefaultDepth(display, screenNum);
+
+#if 0
+    /*
+     * XXX: What other elements may require changes?  Changing just
+     * the depth works for standard windows and 16/24/32-bpp changes.
+     * I suspect 8-bit (palettized) displays may require colormap and/or
+     * visual changes as well.
+     */
+
+    if (winPtr->window) {
+	InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
+    }
+    winPtr->visual = DefaultVisual(display, screenNum);
+    winPtr->atts.colormap = DefaultColormap(display, screenNum);
+    winPtr->dirtyAtts |= CWColormap;
+#endif
+
+    for (childPtr = winPtr->childList; childPtr != NULL;
+	 childPtr = childPtr->nextPtr) {
+	/*
+	 * We can stop the descent when we hit a toplevel window, as it
+	 * should get its own message.
+	 */
+
+	if (!Tk_TopWinHierarchy(childPtr)) {
+	    InvalidateSubTreeDepth(childPtr);
+	}
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TkWinGetSystemPalette --
  *
  *	Retrieves the currently installed foreground palette.
@@ -7145,6 +7209,48 @@
 	    result = 0;
 	    goto done;
 
+	case WM_DISPLAYCHANGE:
+	    /* display and/or color resolution changed */
+	    winPtr = GetTopLevel(hwnd);
+	    if (winPtr) {
+		Screen *screen = Tk_Screen(winPtr);
+		if (screen->root_depth != (int) wParam) {
+		    /*
+		     * Color resolution changed, so do extensive rebuild of
+		     * display parameters.  This will affect the display for
+		     * all Tk windows.  We will receive this event for each
+		     * toplevel, but this check makes us update only once, for
+		     * the first toplevel that receives the message.
+		     */
+		    TkWinDisplayChanged(Tk_Display(winPtr));
+		} else {
+		    HDC dc = GetDC(NULL);
+		    screen->width   = LOWORD(lParam); /* horizontal res */
+		    screen->height  = HIWORD(lParam); /* vertical res */
+		    screen->mwidth  = MulDiv(screen->width, 254,
+			    GetDeviceCaps(dc, LOGPIXELSX) * 10);
+		    screen->mheight = MulDiv(screen->height, 254,
+			    GetDeviceCaps(dc, LOGPIXELSY) * 10);
+		    ReleaseDC(NULL, dc);
+		}
+		if (Tk_Depth(winPtr) != (int) wParam) {
+		    /*
+		     * Defer the window depth check to here so that each
+		     * toplevel will properly update depth info.
+		     */
+		    InvalidateSubTreeDepth(winPtr);
+		}
+	    }
+	    result = 0;
+	    goto done;
+
+	case WM_SYSCOLORCHANGE:
+	    /*
+	     * XXX: Called when system color changes.  We need to
+	     * update any widgets that use a system color.
+	     */
+	    break;
+
 	case WM_PALETTECHANGED:
 	    result = InstallColormaps(hwnd, WM_PALETTECHANGED,
 		    hwnd == (HWND)wParam);
Index: win/tkWinX.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/win/tkWinX.c,v
retrieving revision 1.25.2.3
diff -u -r1.25.2.3 tkWinX.c
--- win/tkWinX.c	23 Sep 2004 00:56:15 -0000	1.25.2.3
+++ win/tkWinX.c	23 Sep 2004 01:43:57 -0000
@@ -348,7 +348,7 @@
  *----------------------------------------------------------------------
  */
 
-int		
+int
 TkWinGetPlatformId()
 {
     if (tkPlatformId == 0) {
@@ -406,7 +406,7 @@
  *----------------------------------------------------------------------
  */
 
-int		
+int
 TkWinGetPlatformTheme()
 {
     if (tkPlatformId == 0) {
@@ -446,6 +446,100 @@
 /*
  *----------------------------------------------------------------------
  *
+ * TkWinDisplayChanged --
+ *
+ *	Called to set up initial screen info or when an event indicated
+ *	display (screen) change.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	May change info regarding the screen.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkWinDisplayChanged(Display *display)
+{
+    HDC dc;
+    Screen *screen;
+
+    if (display == NULL || display->screens == NULL) {
+	return;
+    }
+    screen = display->screens;
+
+    dc = GetDC(NULL);
+    screen->width = GetDeviceCaps(dc, HORZRES);
+    screen->height = GetDeviceCaps(dc, VERTRES);
+    screen->mwidth = MulDiv(screen->width, 254,
+	    GetDeviceCaps(dc, LOGPIXELSX) * 10);
+    screen->mheight = MulDiv(screen->height, 254,
+	    GetDeviceCaps(dc, LOGPIXELSY) * 10);
+
+    /*
+     * On windows, when creating a color bitmap, need two pieces of
+     * information: the number of color planes and the number of pixels per
+     * plane.  Need to remember both quantities so that when constructing an
+     * HBITMAP for offscreen rendering, we can specify the correct value for
+     * the number of planes.  Otherwise the HBITMAP won't be compatible with
+     * the HWND and we'll just get blank spots copied onto the screen.
+     */
+
+    screen->ext_data = (XExtData *) GetDeviceCaps(dc, PLANES);
+    screen->root_depth = GetDeviceCaps(dc, BITSPIXEL) * (int) screen->ext_data;
+
+    if (screen->root_visual != NULL) {
+	ckfree((char *) screen->root_visual);
+    }
+    screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
+    screen->root_visual->visualid = 0;
+    if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
+	screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE);
+	screen->root_visual->class = PseudoColor;
+	screen->root_visual->red_mask = 0x0;
+	screen->root_visual->green_mask = 0x0;
+	screen->root_visual->blue_mask = 0x0;
+    } else if (screen->root_depth == 4) {
+	screen->root_visual->class = StaticColor;
+	screen->root_visual->map_entries = 16;
+    } else if (screen->root_depth == 8) {
+	screen->root_visual->class = StaticColor;
+	screen->root_visual->map_entries = 256;
+    } else if (screen->root_depth == 12) {
+	screen->root_visual->class = TrueColor;
+	screen->root_visual->map_entries = 32;
+	screen->root_visual->red_mask = 0xf0;
+	screen->root_visual->green_mask = 0xf000;
+	screen->root_visual->blue_mask = 0xf00000;
+    } else if (screen->root_depth == 16) {
+	screen->root_visual->class = TrueColor;
+	screen->root_visual->map_entries = 64;
+	screen->root_visual->red_mask = 0xf8;
+	screen->root_visual->green_mask = 0xfc00;
+	screen->root_visual->blue_mask = 0xf80000;
+    } else if (screen->root_depth >= 24) {
+	screen->root_visual->class = TrueColor;
+	screen->root_visual->map_entries = 256;
+	screen->root_visual->red_mask = 0xff;
+	screen->root_visual->green_mask = 0xff00;
+	screen->root_visual->blue_mask = 0xff0000;
+    }
+    screen->root_visual->bits_per_rgb = screen->root_depth;
+    ReleaseDC(NULL, dc);
+
+    if (screen->cmap != None) {
+	XFreeColormap(display, screen->cmap);
+    }
+    screen->cmap = XCreateColormap(display, None, screen->root_visual,
+	    AllocNone);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TkpOpenDisplay --
  *
  *	Create the Display structure and fill it with device
@@ -465,7 +559,6 @@
     CONST char *display_name;
 {
     Screen *screen;
-    HDC dc;
     TkWinDrawable *twdPtr;
     Display *display;
     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
@@ -487,21 +580,14 @@
     strcpy(display->display_name, display_name);
 
     display->cursor_font = 1;
-    display->nscreens = 1;
-    display->request = 1;
-    display->qlen = 0;
+    display->nscreens    = 1;
+    display->request     = 1;
+    display->qlen        = 0;
 
     screen = (Screen *) ckalloc(sizeof(Screen));
+    ZeroMemory(screen, sizeof(Screen));
     screen->display = display;
 
-    dc = GetDC(NULL);
-    screen->width = GetDeviceCaps(dc, HORZRES);
-    screen->height = GetDeviceCaps(dc, VERTRES);
-    screen->mwidth = MulDiv(screen->width, 254,
-	    GetDeviceCaps(dc, LOGPIXELSX) * 10);
-    screen->mheight = MulDiv(screen->height, 254,
-	    GetDeviceCaps(dc, LOGPIXELSY) * 10);
-    
     /*
      * Set up the root window.
      */
@@ -516,72 +602,24 @@
     screen->root = (Window)twdPtr;
 
     /*
-     * On windows, when creating a color bitmap, need two pieces of 
-     * information: the number of color planes and the number of 
-     * pixels per plane.  Need to remember both quantities so that
-     * when constructing an HBITMAP for offscreen rendering, we can
-     * specify the correct value for the number of planes.  Otherwise
-     * the HBITMAP won't be compatible with the HWND and we'll just
-     * get blank spots copied onto the screen.
-     */
-
-    screen->ext_data = (XExtData *) GetDeviceCaps(dc, PLANES);
-    screen->root_depth = GetDeviceCaps(dc, BITSPIXEL) * (int) screen->ext_data;
-
-    screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
-    screen->root_visual->visualid = 0;
-    if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
-	screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE);
-	screen->root_visual->class = PseudoColor;
-	screen->root_visual->red_mask = 0x0;
-	screen->root_visual->green_mask = 0x0;
-	screen->root_visual->blue_mask = 0x0;
-    } else {
-	if (screen->root_depth == 4) {
-	    screen->root_visual->class = StaticColor;
-	    screen->root_visual->map_entries = 16;
-	} else if (screen->root_depth == 8) {
-	    screen->root_visual->class = StaticColor;
-	    screen->root_visual->map_entries = 256;
-	} else if (screen->root_depth == 12) {
-	    screen->root_visual->class = TrueColor;
-	    screen->root_visual->map_entries = 32;
-	    screen->root_visual->red_mask = 0xf0;
-	    screen->root_visual->green_mask = 0xf000;
-	    screen->root_visual->blue_mask = 0xf00000;
-	} else if (screen->root_depth == 16) {
-	    screen->root_visual->class = TrueColor;
-	    screen->root_visual->map_entries = 64;
-	    screen->root_visual->red_mask = 0xf8;
-	    screen->root_visual->green_mask = 0xfc00;
-	    screen->root_visual->blue_mask = 0xf80000;
-	} else if (screen->root_depth >= 24) {
-	    screen->root_visual->class = TrueColor;
-	    screen->root_visual->map_entries = 256;
-	    screen->root_visual->red_mask = 0xff;
-	    screen->root_visual->green_mask = 0xff00;
-	    screen->root_visual->blue_mask = 0xff0000;
-	}
-    }
-    screen->root_visual->bits_per_rgb = screen->root_depth;
-    ReleaseDC(NULL, dc);
-
-    /*
      * Note that these pixel values are not palette relative.
      */
 
     screen->white_pixel = RGB(255, 255, 255);
     screen->black_pixel = RGB(0, 0, 0);
+    screen->cmap        = None;
 
     display->screens		= screen;
     display->nscreens		= 1;
     display->default_screen	= 0;
-    screen->cmap = XCreateColormap(display, None, screen->root_visual,
-	    AllocNone);
+
+    TkWinDisplayChanged(display);
+
     tsdPtr->winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
     ZeroMemory(tsdPtr->winDisplay, sizeof(TkDisplay));
     tsdPtr->winDisplay->display = display;
     tsdPtr->updatingClipboard = FALSE;
+
     return tsdPtr->winDisplay;
 }
 
