} if (count > 0) {
LRESULT wmNotifyChild (int wParam, int lParam) {	NMHDR hdr = new NMHDR ();	OS.MoveMemory (hdr, lParam, NMHDR.sizeof);	switch (hdr.code) {		case OS.TVN_GETDISPINFOA:		case OS.TVN_GETDISPINFOW: {			NMTVDISPINFO lptvdi = new NMTVDISPINFO ();			OS.MoveMemory (lptvdi, lParam, NMTVDISPINFO.sizeof);			/*			* Feature in Windows.  When a new tree item is inserted			* using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before			* TVM_INSERTITEM returns and before the item is added to			* the items array.  The fix is to check for null.			* 			* NOTE: This only happens on XP with the version 6.00 of			* COMCTL32.DLL,			*/			if (items == null) break;			TreeItem item = items [lptvdi.lParam];			if (item == null) break;			if ((lptvdi.mask & OS.TVIF_TEXT) != 0) {				String string = item.text;				TCHAR buffer = new TCHAR (getCodePage (), string, false);				int byteCount = Math.min (buffer.length (), lptvdi.cchTextMax - 1) * TCHAR.sizeof;				OS.MoveMemory (lptvdi.pszText, buffer, byteCount);				OS.MoveMemory (lptvdi.pszText + byteCount, new byte [TCHAR.sizeof], TCHAR.sizeof);				lptvdi.cchTextMax = Math.min (lptvdi.cchTextMax, string.length () + 1);			}			if ((lptvdi.mask & (OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE)) != 0) {				Image image = item.image;				lptvdi.iImage = OS.I_IMAGENONE;				if (image != null) {					lptvdi.iImage = lptvdi.iSelectedImage = imageIndex (image);				}			}			OS.MoveMemory (lParam, lptvdi, NMTVDISPINFO.sizeof);			break;		}		case OS.NM_CUSTOMDRAW: {			if (!customDraw) break;			NMTVCUSTOMDRAW nmcd = new NMTVCUSTOMDRAW ();			OS.MoveMemory (nmcd, lParam, NMTVCUSTOMDRAW.sizeof);					switch (nmcd.dwDrawStage) {				case OS.CDDS_PREPAINT: {					return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);				}				case OS.CDDS_POSTPAINT: {					if (linesVisible) {						int hDC = nmcd.hdc;						if (hwndHeader != 0) {							int x = 0;							RECT rect = new RECT ();							HDITEM hdItem = new HDITEM ();							hdItem.mask = OS.HDI_WIDTH;							int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);							for (int i=0; i<count; i++) {								OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);								OS.SetRect (rect, x, nmcd.top, x + hdItem.cxy, nmcd.bottom);								OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_RIGHT);								x += hdItem.cxy;							}						}						RECT rect = new RECT ();						int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);						rect.left = hItem;						if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {							int height = rect.bottom - rect.top;							while (rect.bottom < nmcd.bottom) {								int top = rect.top + height;								OS.SetRect (rect, rect.left, top, rect.right, top + height);								OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);							}						}					}					return new LRESULT (OS.CDRF_DODEFAULT);				}				case OS.CDDS_ITEMPREPAINT: {					/*					* Feature in Windows.  When a new tree item is inserted					* using TVM_INSERTITEM and the tree is using custom draw,					* a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns					* and before the item is added to the items array.  The					* fix is to check for null.					* 					* NOTE: This only happens on XP with the version 6.00 of					* COMCTL32.DLL,					*/					TreeItem item = items [nmcd.lItemlParam];					if (item == null) break;					if (nmcd.left >= nmcd.right || nmcd.top >= nmcd.bottom) {						break;					}					int hDC = nmcd.hdc;					OS.SaveDC (hDC);					if (linesVisible) {						RECT rect = new RECT ();						OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);						OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);					}					if (!printClient && (style & SWT.FULL_SELECTION) == 0) {						if (hwndHeader != 0) {							int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);							if (count != 0) {								HDITEM hdItem = new HDITEM ();								hdItem.mask = OS.HDI_WIDTH;								OS.SendMessage (hwndHeader, OS.HDM_GETITEM, 0, hdItem);								int hRgn = OS.CreateRectRgn (nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);								OS.SelectClipRgn (hDC, hRgn);								OS.DeleteObject (hRgn);							}						}					}					if (item.font == -1 && item.foreground == -1 && item.background == -1) {						if (item.cellForeground == null && item.cellBackground == null && item.cellFont == null) {							return new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);						}					}					int hFont = item.cellFont != null ? item.cellFont [0] : item.font;					if (hFont != -1) OS.SelectObject (hDC, hFont);					if (OS.IsWindowEnabled (handle)) {						TVITEM tvItem = new TVITEM ();						tvItem.mask = OS.TVIF_STATE;						tvItem.hItem = item.handle;						OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);						if ((tvItem.state & (OS.TVIS_SELECTED | OS.TVIS_DROPHILITED)) == 0) {							int clrText = item.cellForeground != null ? item.cellForeground [0] : item.foreground;							nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;							int clrTextBk = item.cellBackground != null ? item.cellBackground [0] : item.background;							nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk;							OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);						}					}					return new LRESULT (OS.CDRF_NEWFONT | OS.CDRF_NOTIFYPOSTPAINT);				}				case OS.CDDS_ITEMPOSTPAINT: {					TreeItem item = items [nmcd.lItemlParam];					if (item == null) break;					/*					* Feature in Windows.  Under certain circumstances, Windows					* sends CDDS_ITEMPOSTPAINT for an empty rectangle.  This is					* not a problem providing that graphics do not occur outside					* the rectangle.  The fix is to test for the rectangle and					* draw nothing.					* 					* NOTE:  This seems to happen when both I_IMAGECALLBACK					* and LPSTR_TEXTCALLBACK are used at the same time with					* TVM_SETITEM.					*/					if (nmcd.left >= nmcd.right || nmcd.top >= nmcd.bottom) {						break;					}					int hDC = nmcd.hdc;					OS.RestoreDC (hDC, -1);					OS.SetBkMode (hDC, OS.TRANSPARENT);					boolean useColor = OS.IsWindowEnabled (handle);					if (useColor) {						if ((style & SWT.FULL_SELECTION) != 0) {							TVITEM tvItem = new TVITEM ();							tvItem.mask = OS.TVIF_STATE;							tvItem.hItem = item.handle;							OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);							if ((tvItem.state & OS.TVIS_SELECTED) != 0) {								useColor = false;							} else {								/*								* Feature in Windows.  When the mouse is pressed and the								* selection is first drawn for a tree, the item is drawn								* selected, but the TVIS_SELECTED bits for the item are								* not set.  When the user moves the mouse slightly and								* a drag and drop operation is not started, the item is								* drawn again and this time TVIS_SELECTED is set.  This								* means that an item that is in a tree that has the style								* TVS_FULLROWSELECT and that also contains colored cells								* will not draw the entire row selected until the user								* moves the mouse.  The fix is to test for the selection								* colors and guess that the item is selected.								* 								* NOTE: This code doesn't work when the foreground and								* background of the tree are set to the selection colors								* but this does not happen in a regular application.								*/								int clrForeground = OS.GetTextColor (hDC);								if (clrForeground == OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {									int clrBackground = OS.GetBkColor (hDC);									if (clrBackground == OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {										useColor = false;									}								}							}						} else {							OS.SetTextColor (hDC, getForegroundPixel ());						}					}					if (hwndHeader != 0) {						GCData data = new GCData();						data.device = display;						GC gc = GC.win32_new (hDC, data);						int x = 0, gridWidth = linesVisible ? GRID_WIDTH : 0;						Point size = null;						RECT rect = new RECT ();						HDITEM hdItem = new HDITEM ();						hdItem.mask = OS.HDI_WIDTH;						int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);						for (int i=0; i<count; i++) {							OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);							if (i > 0) {								OS.SetRect (rect, x, nmcd.top, x + hdItem.cxy, nmcd.bottom - gridWidth);								if (printClient || (style & SWT.FULL_SELECTION) != 0) {									drawBackground (hDC, OS.GetBkColor (hDC), rect);								}								if (useColor) {									int clrTextBk = item.cellBackground != null ? item.cellBackground [i] : item.background;									if (clrTextBk != -1) drawBackground (hDC, clrTextBk, rect);								}								Image image = item.images != null ? item.images [i] : null;								if (image != null) {									Rectangle bounds = image.getBounds ();									if (size == null) size = getImageSize ();									gc.drawImage (image, 0, 0, bounds.width, bounds.height, rect.left, rect.top, size.x, size.y);									OS.SetRect (rect, rect.left + size.x + INSET, rect.top, rect.right - INSET, rect.bottom);								} else {									OS.SetRect (rect, rect.left + INSET, rect.top, rect.right - INSET, rect.bottom);								}								/*								* Bug in Windows.  When DrawText() is used with DT_VCENTER								* and DT_ENDELLIPSIS, the ellipsis can draw outside of the								* rectangle when the rectangle is empty.  The fix is avoid								* all text drawing for empty rectangles.								*/								if (rect.left < rect.right) {									if (item.strings != null && item.strings [i] != null) {										int hFont = item.cellFont != null ? item.cellFont [i] : item.font;										hFont = hFont != -1 ? OS.SelectObject (hDC, hFont) : -1;										int clrText = -1;										if (useColor) {											clrText = item.cellForeground != null ? item.cellForeground [i] : item.foreground;											clrText = clrText != -1? OS.SetTextColor (hDC, clrText) : -1;										}										int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER | OS.DT_ENDELLIPSIS;										TreeColumn column = columns [i];										if ((column.style & SWT.LEFT) != 0) flags |= OS.DT_LEFT;										if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;										if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;										TCHAR buffer = new TCHAR (getCodePage (), item.strings [i], false);										OS.DrawText (hDC, buffer, buffer.length (), rect, flags);										if (hFont != -1) OS.SelectObject (hDC, hFont);										if (clrText != -1) OS.SetTextColor (hDC, clrText);									}								}							}							x += hdItem.cxy;							if (printClient || (style & SWT.FULL_SELECTION) != 0) {								OS.SetRect (rect, x, nmcd.top, nmcd.right, nmcd.bottom - gridWidth);								drawBackground (hDC, OS.GetBkColor (hDC), rect);							}						}						gc.dispose ();					}					if (linesVisible) {						if (printClient && (style & SWT.FULL_SELECTION) == 0) {							if (hwndHeader != 0) {								int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);								if (count != 0 && printClient) {									HDITEM hdItem = new HDITEM ();									hdItem.mask = OS.HDI_WIDTH;									OS.SendMessage (hwndHeader, OS.HDM_GETITEM, 0, hdItem);									RECT rect = new RECT ();									OS.SetRect (rect, nmcd.left + hdItem.cxy, nmcd.top, nmcd.right, nmcd.bottom);									OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);								}							}						}						RECT rect = new RECT ();						if (OS.COMCTL32_MAJOR < 6 || (style & SWT.FULL_SELECTION) != 0) {							OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);						} else {							rect.left = item.handle;							if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect) != 0) {								int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);								if (hItem == item.handle) {									OS.SetRect (rect, rect.right, nmcd.top, nmcd.right, nmcd.bottom);								} else {									TVITEM tvItem = new TVITEM ();									tvItem.mask = OS.TVIF_STATE;									tvItem.hItem = item.handle;									OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);									if ((tvItem.state & OS.TVIS_SELECTED) != 0) {										OS.SetRect (rect, rect.right, nmcd.top, nmcd.right, nmcd.bottom);									} else {										OS.SetRect (rect, rect.left, nmcd.top, nmcd.right, nmcd.bottom);									}								}							} else {								rect.left = 0;							}						}						OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);					}					return new LRESULT (OS.CDRF_DODEFAULT);				}			}			break;		}		case OS.NM_DBLCLK: {			if (!ignoreSelect) {				int pos = OS.GetMessagePos ();				POINT pt = new POINT ();				pt.x = (short) (pos & 0xFFFF);				pt.y = (short) (pos >> 16);				OS.ScreenToClient (handle, pt);				TVHITTESTINFO lpht = new TVHITTESTINFO ();				lpht.x = pt.x;				lpht.y = pt.y;				OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);				if ((lpht.flags & OS.TVHT_ONITEM) == 0) break;				Event event = new Event ();				int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);				if (hItem != 0) {					TVITEM tvItem = new TVITEM ();					tvItem.hItem = hItem;					tvItem.mask = OS.TVIF_PARAM;					OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);					event.item = items [tvItem.lParam];				}				postEvent (SWT.DefaultSelection, event);			}			if (hooks (SWT.DefaultSelection)) return LRESULT.ONE;			break;		}		case OS.TVN_SELCHANGEDA:		case OS.TVN_SELCHANGEDW: {			if ((style & SWT.MULTI) != 0) {				if (lockSelection) {					/* Restore the old selection state of both items */					if (oldSelected) {						TVITEM tvItem = new TVITEM ();						int offset = NMHDR.sizeof + 4;						OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);						tvItem.mask = OS.TVIF_STATE;						tvItem.stateMask = OS.TVIS_SELECTED;						tvItem.state = OS.TVIS_SELECTED;						OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);					}					if (!newSelected && ignoreSelect) {						TVITEM tvItem = new TVITEM ();						int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;						OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);						tvItem.mask = OS.TVIF_STATE;						tvItem.stateMask = OS.TVIS_SELECTED;						tvItem.state = 0;						OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);					}				}			}			if (!ignoreSelect) {				TVITEM tvItem = new TVITEM ();				int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;				OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);				hAnchor = tvItem.hItem;				Event event = new Event ();				event.item = items [tvItem.lParam];				postEvent (SWT.Selection, event);			}			updateScrollBar ();			break;		}		case OS.TVN_SELCHANGINGA:		case OS.TVN_SELCHANGINGW: {			if ((style & SWT.MULTI) != 0) {				if (lockSelection) {					/* Save the old selection state for both items */					TVITEM tvItem = new TVITEM ();					int offset1 = NMHDR.sizeof + 4;					OS.MoveMemory (tvItem, lParam + offset1, TVITEM.sizeof);					oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;					int offset2 = NMHDR.sizeof + 4 + TVITEM.sizeof;					OS.MoveMemory (tvItem, lParam + offset2, TVITEM.sizeof);					newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;				}			}			if (!ignoreSelect && !ignoreDeselect) {				hAnchor = 0;				if ((style & SWT.MULTI) != 0) deselectAll ();			}			break;		}		case OS.TVN_ITEMEXPANDEDA:		case OS.TVN_ITEMEXPANDEDW: {			updateScrollBar ();			break;		}		case OS.TVN_ITEMEXPANDINGA:		case OS.TVN_ITEMEXPANDINGW: {			if (!ignoreExpand) {				TVITEM tvItem = new TVITEM ();				int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;				OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);				/*				* Feature in Windows.  In some cases, TVM_ITEMEXPANDING				* is sent from within TVM_DELETEITEM for the tree item				* being destroyed.  By the time the message is sent,				* the item has already been removed from the list of				* items.  The fix is to check for null. 				*/				if (items == null) break;				TreeItem item = items [tvItem.lParam];				if (item == null) break;				Event event = new Event ();				event.item = item;				int [] action = new int [1];				OS.MoveMemory (action, lParam + NMHDR.sizeof, 4);				switch (action [0]) {					case OS.TVE_EXPAND:						/*						* Bug in Windows.  When the numeric keypad asterisk						* key is used to expand every item in the tree, Windows						* sends TVN_ITEMEXPANDING to items in the tree that						* have already been expanded.  The fix is to detect						* that the item is already expanded and ignore the						* notification.						*/						if ((tvItem.state & OS.TVIS_EXPANDED) == 0) {							sendEvent (SWT.Expand, event);							if (isDisposed ()) return LRESULT.ZERO;						}						break;					case OS.TVE_COLLAPSE:						sendEvent (SWT.Collapse, event);						if (isDisposed ()) return LRESULT.ZERO;						break;				}			}			break;		}		case OS.TVN_BEGINDRAGA:		case OS.TVN_BEGINDRAGW:		case OS.TVN_BEGINRDRAGA:		case OS.TVN_BEGINRDRAGW: {			TVITEM tvItem = new TVITEM ();			int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;			OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);			if (tvItem.hItem != 0 && (tvItem.state & OS.TVIS_SELECTED) == 0) {				ignoreSelect = ignoreDeselect = true;				OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, tvItem.hItem);				ignoreSelect = ignoreDeselect = false;			}			dragStarted = true;			break;		}		case OS.NM_RECOGNIZEGESTURE: {			/* 			* Feature in Pocket PC.  The tree and table controls detect the tap			* and hold gesture by default. They send a GN_CONTEXTMENU message to show			* the popup menu.  This default behaviour is unwanted on Pocket PC 2002			* when no menu has been set, as it still draws a red circle.  The fix			* is to disable this default behaviour when no menu is set by returning			* TRUE when receiving the Pocket PC 2002 specific NM_RECOGNIZEGESTURE			* message.			*/			if (OS.IsPPC) {				boolean hasMenu = menu != null && !menu.isDisposed ();				if (!hasMenu && !hooks (SWT.MenuDetect)) return LRESULT.ONE;			}			break;		}		case OS.GN_CONTEXTMENU: {			if (OS.IsPPC) {				boolean hasMenu = menu != null && !menu.isDisposed ();				if (hasMenu || hooks (SWT.MenuDetect)) {					NMRGINFO nmrg = new NMRGINFO ();					OS.MoveMemory (nmrg, lParam, NMRGINFO.sizeof);					showMenu (nmrg.x, nmrg.y);					gestureCompleted = true;					return LRESULT.ONE;				}			}			break;		}	}	return super.wmNotifyChild (wParam, lParam);}