src/window.cpp
branchcpp_gui
changeset 6235 5077e6ed3788
parent 6158 ca1471170695
child 6236 ec056d324811
--- a/src/window.cpp	Sun Feb 11 21:20:30 2007 +0000
+++ b/src/window.cpp	Sun Feb 11 22:57:24 2007 +0000
@@ -19,74 +19,594 @@
 // delta between mouse cursor and upper left corner of dragged window
 static Point _drag_delta;
 
-static Window _windows[25];
-Window *_z_windows[lengthof(_windows)];
-Window **_last_z_window; ///< always points to the next free space in the z-array
+/*static*/ WindowList Window::s_list;
 
-void CDECL SetWindowWidgetsDisabledState(Window *w, bool disab_stat, int widgets, ...)
+//static Window _windows[25];
+//Window *_z_windows[lengthof(_windows)];
+//Window **_last_z_window; ///< always points to the next free space in the z-array
+
+int32 CountedObject::AddRef()
+{
+	return ++m_ref_cnt;
+}
+
+int32 CountedObject::Release()
+{
+	int32 res = --m_ref_cnt;
+	assert(res >= 0);
+	if (res == 0) {
+		FinalRelease();
+		delete this;
+	}
+	return res;
+}
+
+void WindowList::Add(Window *w)
+{
+	/* we will add the new window before first vital window or at the end */
+	Iterator it = w->IsVital() ? m_list.end() : FindFirstVitalWindow();
+	/* it should be now at the proper position where new window should be added */
+	m_list.insert(it, w);
+}
+
+void WindowList::Remove(Window *w)
+{
+	Iterator it = Find(w);
+	if (it != m_list.end()) m_list.erase(it);
+}
+
+WindowList::Iterator WindowList::Find(Window *w)
+{
+	struct Match {
+		Window *m_w;
+		bool EnumProc(Iterator it)
+		{
+			return (*it).w == m_w;
+		}
+	} match = {w};
+
+	Iterator it = EnumT(match);
+	if (it == m_list.end()) {
+		DEBUG(misc, 3, "Window (cls %d, number %d) is not open, probably removed by recursive calls",
+			w->window_class, w->window_number);
+	}
+	return it;
+}
+
+WindowList::Iterator WindowList::FindFirstVitalWindow()
+{
+	struct MatchNonVital {
+		bool EnumProc(Iterator it)
+		{
+			return !(*it).w->IsVital();
+		}
+	} match;
+
+	Iterator it = ReverseEnumT(match);
+	/* we have stopped on last non-vital window. Move one step forward to locate first vital window. */
+	if (it != m_list.end()) ++it;
+	return it;
+}
+
+WindowList::Iterator WindowList::FindByClass(WindowClass cls)
+{
+	struct MatchCls {
+		WindowClass  m_cls;
+		bool EnumProc(Iterator it)
+		{
+			Window *w = (*it).w;
+			return w->window_class == m_cls;
+		}
+	} match = {cls};
+
+	Iterator it = EnumT(match);
+	return it;
+}
+
+WindowList::Iterator WindowList::FindById(WindowClass cls, WindowNumber num)
+{
+	struct MatchClsAndId {
+		WindowClass  m_cls;
+		WindowNumber m_num;
+		bool EnumProc(Iterator it)
+		{
+			Window *w = (*it).w;
+			return w->window_class == m_cls && w->window_number == m_num;
+		}
+	} match = {cls, num};
+
+	Iterator it = EnumT(match);
+	return it;
+}
+
+/* Open a new window.
+* This function is called from AllocateWindow() or AllocateWindowDesc()
+* See descriptions for those functions for usage
+* See AllocateWindow() for description of arguments.
+* Only addition here is window_number, which is the window_number being assigned to the new window
+*/
+Window::Window(
+							 int x, int y, int w, int h,
+							 WindowProc *proc, WindowClass cls, const Widget *widget, int wnd_number)
+{
+	//Window *w = FindFreeWindow();
+
+	///* We have run out of windows, close one and use that as the place for our new one */
+	//if (w == NULL) {
+	//	w = FindDeletableWindow();
+	//	if (w == NULL) w = ForceFindDeletableWindow();
+	//	w->Close();
+	//}
+
+	// Set up window properties
+	//memset(w, 0, sizeof(*w));
+	ZeroInit();
+
+	window_class = cls;
+	flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
+	caption_color = 0xFF;
+	left = x;
+	top = y;
+	width = w;
+	height = h;
+	wndproc = proc;
+	AssignWidgetToWindow(this, widget);
+	resize.width = width;
+	resize.height = height;
+	resize.step_width = 1;
+	resize.step_height = 1;
+	window_number = wnd_number;
+
+	//{
+	//	Window **wz = _last_z_window;
+
+	//	/* Hacky way of specifying always-on-top windows. These windows are
+	//	 * always above other windows because they are moved below them.
+	//	 * status-bar is above news-window because it has been created earlier.
+	//	 * Also, as the chat-window is excluded from this, it will always be
+	//	 * the last window, thus always on top.
+	//	 * XXX - Yes, ugly, probably needs something like w->always_on_top flag
+	//	 * to implement correctly, but even then you need some kind of distinction
+	//	 * between on-top of chat/news and status windows, because these conflict */
+	//	if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) {
+	//		if (FindWindowById(WC_MAIN_TOOLBAR, 0)     != NULL) wz--;
+	//		if (FindWindowById(WC_STATUS_BAR, 0)       != NULL) wz--;
+	//		if (FindWindowById(WC_NEWS_WINDOW, 0)      != NULL) wz--;
+	//		if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
+
+	//		assert(wz >= _z_windows);
+	//		if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
+	//	}
+
+	//	*wz = w;
+	//	_last_z_window++;
+	//}
+
+	/* add our new window into z-order list */
+	Window::s_list.Add(this);
+
+	SetDirty();
+	CallWindowEventNP(this, WE_CREATE);
+
+	//return w;
+}
+
+/** Find the Window whose parent pointer points to this window
+* @parent w Window to find child of
+* @return return a Window pointer that is the child of w, or NULL otherwise */
+Window* Window::FindChild() const
+{
+	Window *v;
+	FOR_ALL_WINDOWS(v) {
+		if (v->parent == this) return v;
+	}
+
+	return NULL;
+}
+
+void Window::SetDirty() const
+{
+	if (this == NULL) return;
+	SetDirtyBlocks(left, top, left + width, top + height);
+}
+
+/*virtual*/ void Window::FinalRelease()
+{
+	/* Delete any children a window might have in a head-recursive manner */
+	Window *v = FindChild();
+	if (v != NULL) v->Close();
+
+	if (_thd.place_mode != VHM_NONE &&
+		_thd.window_class == window_class &&
+		_thd.window_number == window_number) {
+			ResetObjectToPlace();
+	}
+
+	CallWindowEventNP(this, WE_DESTROY);
+	if (viewport != NULL) DeleteWindowViewport(this);
+
+	SetDirty();
+	free(widget);
+	widget = NULL;
+	widget_count = 0;
+	parent = NULL;
+}
+
+/*virtual*/ void Window::Close()
+{
+	s_list.Remove(this);
+}
+
+/*virtual*/ bool Window::IsVital()
+{
+	WindowClass wc = window_class;
+	return (wc == WC_MAIN_TOOLBAR || wc == WC_STATUS_BAR || wc == WC_NEWS_WINDOW || wc == WC_SEND_NETWORK_MSG);
+}
+
+/**
+* Open a new window. If there is no space for a new window, close an open
+* window. Try to avoid stickied windows, but if there is no else, close one of
+* those as well. Then make sure all created windows are below some always-on-top
+* ones. Finally set all variables and call the WE_CREATE event
+* @param x offset in pixels from the left of the screen
+* @param y offset in pixels from the top of the screen
+* @param width width in pixels of the window
+* @param height height in pixels of the window
+* @param *proc @see WindowProc function to call when any messages/updates happen to the window
+* @param cls @see WindowClass class of the window, used for identification and grouping
+* @param *widget @see Widget pointer to the window layout and various elements
+* @return @see Window pointer of the newly created window
+*/
+/*static*/ Window* Window::Allocate(
+																		int x, int y, int width, int height,
+																		WindowProc *proc, WindowClass cls, const Widget *widget)
+{
+	return new Window(x, y, width, height, proc, cls, widget, 0);
+}
+
+/*static*/ Window* Window::Get(WindowList::Iterator it)
+{
+	return (it != s_list.m_list.end()) ? (*it).w : NULL;
+}
+
+/*static*/ Window* Window::FindById(WindowClass cls, WindowNumber num)
+{
+	return Get(s_list.FindById(cls, num));
+}
+
+/*static*/ void Window::SetDirtyById(WindowClass cls, WindowNumber num)
+{
+	Window *w = FindById(cls, num);
+	if (w != NULL) w->SetDirty();
+}
+
+void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...)
 {
 	va_list wdg_list;
 
 	va_start(wdg_list, widgets);
 
 	while (widgets != WIDGET_LIST_END) {
-		SetWindowWidgetDisabledState(w, widgets, disab_stat);
-		widgets = va_arg(wdg_list, int);
-	}
-
-	va_end(wdg_list);
-}
-
-void CDECL SetWindowWidgetsHiddenState(Window *w, bool hidden_stat, int widgets, ...)
-{
-	va_list wdg_list;
-
-	va_start(wdg_list, widgets);
-
-	while (widgets != WIDGET_LIST_END) {
-		SetWindowWidgetHiddenState(w, widgets, hidden_stat);
+		SetWindowWidgetDisabledState(this, widgets, disab_stat);
 		widgets = va_arg(wdg_list, int);
 	}
 
 	va_end(wdg_list);
 }
 
-void CDECL SetWindowWidgetsLoweredState(Window *w, bool lowered_stat, int widgets, ...)
+void CDECL Window::SetWidgetsHiddenState(bool hidden_stat, int widgets, ...)
 {
 	va_list wdg_list;
 
 	va_start(wdg_list, widgets);
 
 	while (widgets != WIDGET_LIST_END) {
-		SetWindowWidgetLoweredState(w, widgets, lowered_stat);
+		SetWindowWidgetHiddenState(this, widgets, hidden_stat);
 		widgets = va_arg(wdg_list, int);
 	}
 
 	va_end(wdg_list);
 }
 
-void RaiseWindowButtons(Window *w)
+void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...)
+{
+	va_list wdg_list;
+
+	va_start(wdg_list, widgets);
+
+	while (widgets != WIDGET_LIST_END) {
+		SetWindowWidgetLoweredState(this, widgets, lowered_stat);
+		widgets = va_arg(wdg_list, int);
+	}
+
+	va_end(wdg_list);
+}
+
+void Window::RaiseButtons()
 {
 	uint i;
 
-	for (i = 0; i < w->widget_count; i++) {
-		if (IsWindowWidgetLowered(w, i)) {
-			RaiseWindowWidget(w, i);
-			InvalidateWidget(w, i);
+	for (i = 0; i < widget_count; i++) {
+		if (IsWindowWidgetLowered(this, i)) {
+			RaiseWindowWidget(this, i);
+			InvalidateWidget(this, i);
 		}
 	}
 }
 
-void HandleButtonClick(Window *w, byte widget)
+void Window::HandleButtonClick(byte widget)
 {
-	LowerWindowWidget(w, widget);
-	w->flags4 |= 5 << WF_TIMEOUT_SHL;
-	InvalidateWidget(w, widget);
+	LowerWindowWidget(this, widget);
+	this->flags4 |= 5 << WF_TIMEOUT_SHL;
+	InvalidateWidget(this, widget);
+}
+
+/** On clicking on a window, make it the frontmost window of all. However
+* there are certain windows that always need to be on-top; these include
+* - Toolbar, Statusbar (always on)
+* - New window, Chatbar (only if open)
+* The window is marked dirty for a repaint if the window is actually moved
+* @param w window that is put into the foreground
+* @return pointer to the window, the same as the input pointer
+*/
+void Window::BringToFront()
+{
+	WindowPtr wp = this;
+	WindowList::Iterator it = Window::s_list.Find(this);
+	Window::s_list.Remove(this);
+	Window::s_list.Add(this);
+
+	SetDirty();
+}
+
+/** Find a window and make it the top-window on the screen. The window
+* gets a white border for a brief period of time to visualize its
+* "activation"
+* @return a pointer to the window thus activated */
+/*static*/ Window* Window::BringToFrontById(WindowClass cls, WindowNumber num)
+{
+	Window *w = FindById(cls, num);
+	if (w != NULL) {
+		w->flags4 |= WF_WHITE_BORDER_MASK;
+		w->BringToFront();
+	}
+	return w;
+}
+
+static bool _dragging_window;
+
+void Window::StartDrag()
+{
+	flags4 |= WF_DRAGGING;
+	_dragging_window = true;
+
+	_drag_delta.x = left - _cursor.pos.x;
+	_drag_delta.y = top  - _cursor.pos.y;
+
+	BringToFront();
+	DeleteWindowById(WC_DROPDOWN_MENU, 0);
+}
+
+bool Window::ContinueDrag()
+{
+	const Widget *t = &widget[1]; // the title bar ... ugh
+	const Window *v;
+	int x;
+	int y;
+	int nx;
+	int ny;
+
+	// Stop the dragging if the left mouse button was released
+	if (!_left_button_down) {
+		flags4 &= ~WF_DRAGGING;
+		_dragging_window = false;
+		return false;
+	}
+
+	SetDirty();
+
+	x = _cursor.pos.x + _drag_delta.x;
+	y = _cursor.pos.y + _drag_delta.y;
+	nx = x;
+	ny = y;
+
+	if (_patches.window_snap_radius != 0) {
+		Window *v;
+
+		int hsnap = _patches.window_snap_radius;
+		int vsnap = _patches.window_snap_radius;
+		int delta;
+
+		FOR_ALL_WINDOWS(v) {
+			if (v == this) continue; // Don't snap at yourself
+
+			if (y + height > v->top && y < v->top + v->height) {
+				// Your left border <-> other right border
+				delta = abs(v->left + v->width - x);
+				if (delta <= hsnap) {
+					nx = v->left + v->width;
+					hsnap = delta;
+				}
+
+				// Your right border <-> other left border
+				delta = abs(v->left - x - width);
+				if (delta <= hsnap) {
+					nx = v->left - width;
+					hsnap = delta;
+				}
+			}
+
+			if (top + height >= v->top && top <= v->top + v->height) {
+				// Your left border <-> other left border
+				delta = abs(v->left - x);
+				if (delta <= hsnap) {
+					nx = v->left;
+					hsnap = delta;
+				}
+
+				// Your right border <-> other right border
+				delta = abs(v->left + v->width - x - width);
+				if (delta <= hsnap) {
+					nx = v->left + v->width - width;
+					hsnap = delta;
+				}
+			}
+
+			if (x + width > v->left && x < v->left + v->width) {
+				// Your top border <-> other bottom border
+				delta = abs(v->top + v->height - y);
+				if (delta <= vsnap) {
+					ny = v->top + v->height;
+					vsnap = delta;
+				}
+
+				// Your bottom border <-> other top border
+				delta = abs(v->top - y - height);
+				if (delta <= vsnap) {
+					ny = v->top - height;
+					vsnap = delta;
+				}
+			}
+
+			if (left + width >= v->left && left <= v->left + v->width) {
+				// Your top border <-> other top border
+				delta = abs(v->top - y);
+				if (delta <= vsnap) {
+					ny = v->top;
+					vsnap = delta;
+				}
+
+				// Your bottom border <-> other bottom border
+				delta = abs(v->top + v->height - y - height);
+				if (delta <= vsnap) {
+					ny = v->top + v->height - height;
+					vsnap = delta;
+				}
+			}
+		}
+	}
+
+	// Make sure the window doesn't leave the screen
+	// 13 is the height of the title bar
+	nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
+	ny = clamp(ny, 0, _screen.height - 13);
+
+	// Make sure the title bar isn't hidden by behind the main tool bar
+	v = Window::FindById(WC_MAIN_TOOLBAR, 0);
+	if (v != NULL) {
+		int v_bottom = v->top + v->height;
+		int v_right = v->left + v->width;
+		if (ny + t->top >= v->top && ny + t->top < v_bottom) {
+			if ((v->left < 13 && nx + t->left < v->left) ||
+				(v_right > _screen.width - 13 && nx + t->right > v_right)) {
+					ny = v_bottom;
+			} else {
+				if (nx + t->left > v->left - 13 &&
+					nx + t->right < v_right + 13) {
+						if (top >= v_bottom) {
+							ny = v_bottom;
+						} else if (left < nx) {
+							nx = v->left - 13 - t->left;
+						} else {
+							nx = v_right + 13 - t->right;
+						}
+				}
+			}
+		}
+	}
+
+	if (viewport != NULL) {
+		viewport->left += nx - left;
+		viewport->top  += ny - top;
+	}
+	left = nx;
+	top  = ny;
+
+	SetDirty();
+	return false;
+}
+
+void Window::StartSizing()
+{
+	flags4 |= WF_SIZING;
+	_dragging_window = true;
+
+	_drag_delta.x = _cursor.pos.x;
+	_drag_delta.y = _cursor.pos.y;
+
+	BringToFront();
+	DeleteWindowById(WC_DROPDOWN_MENU, 0);
+}
+
+bool Window::ContinueSizing()
+{
+	WindowEvent e;
+	int x, y;
+
+	/* Stop the sizing if the left mouse button was released */
+	if (!_left_button_down) {
+		flags4 &= ~WF_SIZING;
+		SetDirty();
+		_dragging_window = false;
+		return false;
+	}
+
+	x = _cursor.pos.x - _drag_delta.x;
+	y = _cursor.pos.y - _drag_delta.y;
+
+	/* X and Y has to go by step.. calculate it.
+	* The cast to int is necessary else x/y are implicitly casted to
+	* unsigned int, which won't work. */
+	if (resize.step_width > 1) x -= x % (int)resize.step_width;
+
+	if (resize.step_height > 1) y -= y % (int)resize.step_height;
+
+	/* Check if we don't go below the minimum set size */
+	if ((int)width + x < (int)resize.width)
+		x = resize.width - width;
+	if ((int)height + y < (int)resize.height)
+		y = resize.height - height;
+
+	/* Window already on size */
+	if (x == 0 && y == 0) return false;
+
+	/* Now find the new cursor pos.. this is NOT _cursor, because
+	we move in steps. */
+	_drag_delta.x += x;
+	_drag_delta.y += y;
+
+	/* ResizeWindow sets both pre- and after-size to dirty for redrawal */
+	ResizeWindow(this, x, y);
+
+	e.event = WE_RESIZE;
+	e.we.sizing.size.x = x + width;
+	e.we.sizing.size.y = y + height;
+	e.we.sizing.diff.x = x;
+	e.we.sizing.diff.y = y;
+	wndproc(this, &e);
+	return false;
+
+}
+
+/*static*/ bool Window::HandleWindowDragging(void)
+{
+	// Get out immediately if no window is being dragged at all.
+	if (!_dragging_window) return true;
+
+	// Otherwise find the window...
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
+		if (w->flags4 & WF_DRAGGING) {
+			return w->ContinueDrag();
+		} else if (w->flags4 & WF_SIZING) {
+			return w->ContinueSizing();
+		}
+	}
+	_dragging_window = false;
+	return false;
 }
 
 
-static void StartWindowDrag(Window *w);
-static void StartWindowSizing(Window *w);
 
 static void DispatchLeftClickEvent(Window *w, int x, int y)
 {
@@ -112,7 +632,7 @@
 				case WWT_PANEL   | WWB_PUSHBUTTON: /* WWT_PUSHBTN */
 				case WWT_IMGBTN  | WWB_PUSHBUTTON: /* WWT_PUSHIMGBTN */
 				case WWT_TEXTBTN | WWB_PUSHBUTTON: /* WWT_PUSHTXTBTN */
-					HandleButtonClick(w, e.we.click.widget);
+					w->HandleButtonClick(e.we.click.widget);
 					break;
 			}
 		} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) {
@@ -121,18 +641,18 @@
 
 		if (w->desc_flags & WDF_STD_BTN) {
 			if (e.we.click.widget == 0) { /* 'X' */
-				DeleteWindow(w);
+				w->Close();
 				return;
 			}
 
 			if (e.we.click.widget == 1) { /* 'Title bar' */
-				StartWindowDrag(w);
+				w->StartDrag();
 				return;
 			}
 		}
 
 		if (w->desc_flags & WDF_RESIZABLE && wi->type == WWT_RESIZEBOX) {
-			StartWindowSizing(w);
+			w->StartSizing();
 			InvalidateWidget(w, e.we.click.widget);
 			return;
 		}
@@ -196,64 +716,63 @@
 			int pos = clamp(sb->pos + wheel, 0, sb->count - sb->cap);
 			if (pos != sb->pos) {
 				sb->pos = pos;
-				SetWindowDirty(w);
+				w->SetDirty();
 			}
 		}
 	}
 }
 
-static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom);
+static void DrawOverlappedWindow(WindowList::Iterator it, int left, int top, int right, int bottom);
 
 void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
 {
-	Window* const *wz;
 	DrawPixelInfo bk;
 	_cur_dpi = &bk;
 
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
+	const Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (right > w->left &&
 				bottom > w->top &&
 				left < w->left + w->width &&
 				top < w->top + w->height) {
-			DrawOverlappedWindow(wz, left, top, right, bottom);
+			DrawOverlappedWindow(it, left, top, right, bottom);
 		}
 	}
 }
 
-static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom)
+static void DrawOverlappedWindow(WindowList::Iterator wit, int left, int top, int right, int bottom)
 {
-	Window* const *vz = wz;
-	int x;
+	Window *w = (*wit).w;
 
-	while (++vz != _last_z_window) {
-		const Window *v = *vz;
+	for (WindowList::Iterator vit = wit; ++vit != Window::s_list.m_list.end(); ) {
+		const Window *v = (*vit).w;
+		int x;
 
 		if (right > v->left &&
 				bottom > v->top &&
 				left < v->left + v->width &&
 				top < v->top + v->height) {
 			if (left < (x=v->left)) {
-				DrawOverlappedWindow(wz, left, top, x, bottom);
-				DrawOverlappedWindow(wz, x, top, right, bottom);
+				DrawOverlappedWindow(wit, left, top, x, bottom);
+				DrawOverlappedWindow(wit, x, top, right, bottom);
 				return;
 			}
 
 			if (right > (x=v->left + v->width)) {
-				DrawOverlappedWindow(wz, left, top, x, bottom);
-				DrawOverlappedWindow(wz, x, top, right, bottom);
+				DrawOverlappedWindow(wit, left, top, x, bottom);
+				DrawOverlappedWindow(wit, x, top, right, bottom);
 				return;
 			}
 
 			if (top < (x=v->top)) {
-				DrawOverlappedWindow(wz, left, top, right, x);
-				DrawOverlappedWindow(wz, left, x, right, bottom);
+				DrawOverlappedWindow(wit, left, top, right, x);
+				DrawOverlappedWindow(wit, left, x, right, bottom);
 				return;
 			}
 
 			if (bottom > (x=v->top + v->height)) {
-				DrawOverlappedWindow(wz, left, top, right, x);
-				DrawOverlappedWindow(wz, left, x, right, bottom);
+				DrawOverlappedWindow(wit, left, top, right, x);
+				DrawOverlappedWindow(wit, left, x, right, bottom);
 				return;
 			}
 
@@ -265,12 +784,12 @@
 		DrawPixelInfo *dp = _cur_dpi;
 		dp->width = right - left;
 		dp->height = bottom - top;
-		dp->left = left - (*wz)->left;
-		dp->top = top - (*wz)->top;
+		dp->left = left - w->left;
+		dp->top = top - w->top;
 		dp->pitch = _screen.pitch;
 		dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left;
 		dp->zoom = 0;
-		CallWindowEventNP(*wz, WE_PAINT);
+		CallWindowEventNP(w, WE_PAINT);
 	}
 }
 
@@ -282,104 +801,48 @@
 	w->wndproc(w, &e);
 }
 
-void SetWindowDirty(const Window *w)
-{
-	if (w == NULL) return;
-	SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
-}
-
-/** Find the Window whose parent pointer points to this window
- * @parent w Window to find child of
- * @return return a Window pointer that is the child of w, or NULL otherwise */
-static Window *FindChildWindow(const Window *w)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *v = *wz;
-		if (v->parent == w) return v;
-	}
-
-	return NULL;
-}
-
 /** Find the z-value of a window. A window must already be open
  * or the behaviour is undefined but function should never fail */
-Window **FindWindowZPosition(const Window *w)
-{
-	Window **wz;
-
-	for (wz = _z_windows; wz != _last_z_window; wz++) {
-		if (*wz == w) return wz;
-	}
-
-	DEBUG(misc, 3, "Window (cls %d, number %d) is not open, probably removed by recursive calls",
-		w->window_class, w->window_number);
-	return NULL;
-}
-
-void DeleteWindow(Window *w)
-{
-	Window *v;
-	Window **wz;
-	if (w == NULL) return;
-
-	/* Delete any children a window might have in a head-recursive manner */
-	v = FindChildWindow(w);
-	if (v != NULL) DeleteWindow(v);
+//WindowList::Iterator FindWindowZPosition(const Window *w)
+//{
+//	Window *wz;
+//	FOR_ALL_WINDOWS(wz) {
+//		if (wz == w) return it;
+//	}
+//
+//	DEBUG(misc, 3, "Window (cls %d, number %d) is not open, probably removed by recursive calls",
+//		w->window_class, w->window_number);
+//	return Window::s_list.m_list.end();
+//}
 
-	if (_thd.place_mode != VHM_NONE &&
-			_thd.window_class == w->window_class &&
-			_thd.window_number == w->window_number) {
-		ResetObjectToPlace();
-	}
-
-	CallWindowEventNP(w, WE_DESTROY);
-	if (w->viewport != NULL) DeleteWindowViewport(w);
-
-	SetWindowDirty(w);
-	free(w->widget);
-	w->widget = NULL;
-	w->widget_count = 0;
-	w->parent = NULL;
-
-	/* Find the window in the z-array, and effectively remove it
-	 * by moving all windows after it one to the left */
-	wz = FindWindowZPosition(w);
-	if (wz == NULL) return;
-	memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz);
-	_last_z_window--;
-}
-
-Window *FindWindowById(WindowClass cls, WindowNumber number)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == cls && w->window_number == number) return w;
-	}
-
-	return NULL;
-}
+//Window *FindWindowById(WindowClass cls, WindowNumber number)
+//{
+//	Window *w;
+//
+//	FOR_ALL_WINDOWS(w) {
+//		if (w->window_class == cls && w->window_number == number) return w;
+//	}
+//
+//	return NULL;
+//}
 
 void DeleteWindowById(WindowClass cls, WindowNumber number)
 {
-	DeleteWindow(FindWindowById(cls, number));
+	Window *w = Window::FindById(cls, number);
+	if (w != NULL) w->Close();
 }
 
 void DeleteWindowByClass(WindowClass cls)
 {
-	Window* const *wz;
 
 restart_search:
 	/* When we find the window to delete, we need to restart the search
 	 * as deleting this window could cascade in deleting (many) others
 	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == cls) {
-			DeleteWindow(w);
+			w->Close();
 			goto restart_search;
 		}
 	}
@@ -391,16 +854,15 @@
  * @param id PlayerID player identifier */
 void DeletePlayerWindows(PlayerID id)
 {
-	Window* const *wz;
 
 restart_search:
 	/* When we find the window to delete, we need to restart the search
 	 * as deleting this window could cascade in deleting (many) others
 	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->caption_color == id) {
-			DeleteWindow(w);
+			w->Close();
 			goto restart_search;
 		}
 	}
@@ -416,10 +878,9 @@
  * @param new_player PlayerID of the new owner of the window */
 void ChangeWindowOwner(PlayerID old_player, PlayerID new_player)
 {
-	Window* const *wz;
+	Window *w;
 
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
+	FOR_ALL_WINDOWS(w) {
 
 		if (w->caption_color != old_player)      continue;
 		if (w->window_class == WC_PLAYER_COLOR)  continue;
@@ -436,60 +897,6 @@
 	}
 }
 
-static void BringWindowToFront(const Window *w);
-
-/** Find a window and make it the top-window on the screen. The window
- * gets a white border for a brief period of time to visualize its
- * "activation"
- * @return a pointer to the window thus activated */
-Window *BringWindowToFrontById(WindowClass cls, WindowNumber number)
-{
-	Window *w = FindWindowById(cls, number);
-
-	if (w != NULL) {
-		w->flags4 |= WF_WHITE_BORDER_MASK;
-		BringWindowToFront(w);
-		SetWindowDirty(w);
-	}
-
-	return w;
-}
-
-static inline bool IsVitalWindow(const Window *w)
-{
-	WindowClass wc = w->window_class;
-	return (wc == WC_MAIN_TOOLBAR || wc == WC_STATUS_BAR || wc == WC_NEWS_WINDOW || wc == WC_SEND_NETWORK_MSG);
-}
-
-/** On clicking on a window, make it the frontmost window of all. However
- * there are certain windows that always need to be on-top; these include
- * - Toolbar, Statusbar (always on)
- * - New window, Chatbar (only if open)
- * The window is marked dirty for a repaint if the window is actually moved
- * @param w window that is put into the foreground
- * @return pointer to the window, the same as the input pointer
- */
-static void BringWindowToFront(const Window *w)
-{
-	Window *tempz;
-	Window **wz = FindWindowZPosition(w);
-	Window **vz = _last_z_window;
-
-	/* Bring the window just below the vital windows */
-	do {
-		if (--vz < _z_windows) return;
-	} while (IsVitalWindow(*vz));
-
-	if (wz == vz) return; // window is already in the right position
-	assert(wz < vz);
-
-	tempz = *wz;
-	memmove(wz, wz + 1, (byte*)vz - (byte*)wz);
-	*vz = tempz;
-
-	SetWindowDirty(w);
-}
-
 /** We have run out of windows, so find a suitable candidate for replacement.
  * Keep all important windows intact. These are
  * - Main window (gamefield), Toolbar, Statusbar (always on)
@@ -497,18 +904,21 @@
  * - Any sticked windows since we wanted to keep these
  * @return w pointer to the window that is going to be deleted
  */
-static Window *FindDeletableWindow(void)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) {
-			return w;
-		}
-	}
-	return NULL;
-}
+//static Window *FindDeletableWindow(void)
+//{
+//	Window *w;
+//	FOR_ALL_WINDOWS(w) {
+//		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) {
+//			return w;
+//		}
+//	}
+//	FOR_ALL_WINDOWS(w) {
+//		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) {
+//			return w;
+//		}
+//	}
+//	return NULL;
+//}
 
 /** A window must be freed, and all are marked as important windows. Ease the
  * restriction a bit by allowing to delete sticky windows. Keep important/vital
@@ -517,16 +927,16 @@
  * @see FindDeletableWindow()
  * @return w Pointer to the window that is being deleted
  */
-static Window *ForceFindDeletableWindow(void)
-{
-	Window* const *wz;
-
-	for (wz = _z_windows;; wz++) {
-		Window *w = *wz;
-		assert(wz < _last_z_window);
-		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
-	}
-}
+//static Window *ForceFindDeletableWindow(void)
+//{
+//	Window* const *wz;
+//
+//	for (wz = _z_windows;; wz++) {
+//		Window *w = *wz;
+//		assert(wz < _last_z_window);
+//		if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
+//	}
+//}
 
 bool IsWindowOfPrototype(const Window *w, const Widget *widget)
 {
@@ -553,115 +963,28 @@
 	}
 }
 
-static Window *FindFreeWindow(void)
-{
-	Window *w;
-
-	for (w = _windows; w < endof(_windows); w++) {
-		Window* const *wz;
-		bool window_in_use = false;
-
-		FOR_ALL_WINDOWS(wz) {
-			if (*wz == w) {
-				window_in_use = true;
-				break;
-			}
-		}
-
-		if (!window_in_use) return w;
-	}
-
-	assert(_last_z_window == endof(_z_windows));
-	return NULL;
-}
-
-/* Open a new window.
- * This function is called from AllocateWindow() or AllocateWindowDesc()
- * See descriptions for those functions for usage
- * See AllocateWindow() for description of arguments.
- * Only addition here is window_number, which is the window_number being assigned to the new window
- */
-static Window *LocalAllocateWindow(
-							int x, int y, int width, int height,
-							WindowProc *proc, WindowClass cls, const Widget *widget, int window_number)
-{
-	Window *w = FindFreeWindow();
-
-	/* We have run out of windows, close one and use that as the place for our new one */
-	if (w == NULL) {
-		w = FindDeletableWindow();
-		if (w == NULL) w = ForceFindDeletableWindow();
-		DeleteWindow(w);
-	}
+//static Window *FindFreeWindow(void)
+//{
+//	Window *w;
+//
+//	for (w = _windows; w < endof(_windows); w++) {
+//		Window* const *wz;
+//		bool window_in_use = false;
+//
+//		FOR_ALL_WINDOWS(wz) {
+//			if (*wz == w) {
+//				window_in_use = true;
+//				break;
+//			}
+//		}
+//
+//		if (!window_in_use) return w;
+//	}
+//
+//	assert(_last_z_window == endof(_z_windows));
+//	return NULL;
+//}
 
-	// Set up window properties
-	memset(w, 0, sizeof(*w));
-	w->window_class = cls;
-	w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
-	w->caption_color = 0xFF;
-	w->left = x;
-	w->top = y;
-	w->width = width;
-	w->height = height;
-	w->wndproc = proc;
-	AssignWidgetToWindow(w, widget);
-	w->resize.width = width;
-	w->resize.height = height;
-	w->resize.step_width = 1;
-	w->resize.step_height = 1;
-	w->window_number = window_number;
-
-	{
-		Window **wz = _last_z_window;
-
-		/* Hacky way of specifying always-on-top windows. These windows are
-		 * always above other windows because they are moved below them.
-		 * status-bar is above news-window because it has been created earlier.
-		 * Also, as the chat-window is excluded from this, it will always be
-		 * the last window, thus always on top.
-		 * XXX - Yes, ugly, probably needs something like w->always_on_top flag
-		 * to implement correctly, but even then you need some kind of distinction
-		 * between on-top of chat/news and status windows, because these conflict */
-		if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) {
-			if (FindWindowById(WC_MAIN_TOOLBAR, 0)     != NULL) wz--;
-			if (FindWindowById(WC_STATUS_BAR, 0)       != NULL) wz--;
-			if (FindWindowById(WC_NEWS_WINDOW, 0)      != NULL) wz--;
-			if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
-
-			assert(wz >= _z_windows);
-			if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
-		}
-
-		*wz = w;
-		_last_z_window++;
-	}
-
-	SetWindowDirty(w);
-	CallWindowEventNP(w, WE_CREATE);
-
-	return w;
-}
-
-/**
- * Open a new window. If there is no space for a new window, close an open
- * window. Try to avoid stickied windows, but if there is no else, close one of
- * those as well. Then make sure all created windows are below some always-on-top
- * ones. Finally set all variables and call the WE_CREATE event
- * @param x offset in pixels from the left of the screen
- * @param y offset in pixels from the top of the screen
- * @param width width in pixels of the window
- * @param height height in pixels of the window
- * @param *proc @see WindowProc function to call when any messages/updates happen to the window
- * @param cls @see WindowClass class of the window, used for identification and grouping
- * @param *widget @see Widget pointer to the window layout and various elements
- * @return @see Window pointer of the newly created window
- */
-Window *AllocateWindow(
-							int x, int y, int width, int height,
-							WindowProc *proc, WindowClass cls, const Widget *widget)
-{
-	return LocalAllocateWindow(x, y, width, height, proc, cls, widget, 0);
-}
 
 typedef struct SizeRect {
 	int left,top,width,height;
@@ -673,7 +996,6 @@
 static bool IsGoodAutoPlace1(int left, int top)
 {
 	int right,bottom;
-	Window* const *wz;
 
 	_awap_r.left= left;
 	_awap_r.top = top;
@@ -684,8 +1006,8 @@
 		return false;
 
 	// Make sure it is not obscured by any window.
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == WC_MAIN_WINDOW) continue;
 
 		if (right > w->left &&
@@ -702,7 +1024,6 @@
 static bool IsGoodAutoPlace2(int left, int top)
 {
 	int width,height;
-	Window* const *wz;
 
 	_awap_r.left= left;
 	_awap_r.top = top;
@@ -713,8 +1034,8 @@
 	if (top < 22 || top > _screen.height - (height>>2)) return false;
 
 	// Make sure it is not obscured by any window.
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == WC_MAIN_WINDOW) continue;
 
 		if (left + width > w->left &&
@@ -730,7 +1051,6 @@
 
 static Point GetAutoPlacePosition(int width, int height)
 {
-	Window* const *wz;
 	Point pt;
 
 	_awap_r.width = width;
@@ -738,8 +1058,8 @@
 
 	if (IsGoodAutoPlace1(0, 24)) goto ok_pos;
 
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == WC_MAIN_WINDOW) continue;
 
 		if (IsGoodAutoPlace1(w->left+w->width+2,w->top)) goto ok_pos;
@@ -752,8 +1072,7 @@
 		if (IsGoodAutoPlace1(w->left+w->width-width,w->top-   height-2)) goto ok_pos;
 	}
 
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == WC_MAIN_WINDOW) continue;
 
 		if (IsGoodAutoPlace2(w->left+w->width+2,w->top)) goto ok_pos;
@@ -766,9 +1085,7 @@
 		int left=0,top=24;
 
 restart:;
-		FOR_ALL_WINDOWS(wz) {
-			const Window *w = *wz;
-
+		FOR_ALL_WINDOWS(w) {
 			if (w->left == left && w->top == top) {
 				left += 5;
 				top += 5;
@@ -796,7 +1113,7 @@
 	 * However if it falls too extremely outside window positions, reposition
 	 * it to an automatic place */
 	if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ &&
-			(w = FindWindowById(desc->parent_cls, window_number)) != NULL &&
+			(w = Window::FindById(desc->parent_cls, window_number)) != NULL &&
 			w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) {
 
 		pt.x = w->left + 10;
@@ -807,11 +1124,11 @@
 	} else {
 		switch (desc->left) {
 			case WDP_ALIGN_TBR: { /* Align the right side with the top toolbar */
-				w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+				w = Window::FindById(WC_MAIN_TOOLBAR, 0);
 				pt.x = (w->left + w->width) - desc->width;
 			}	break;
 			case WDP_ALIGN_TBL: /* Align the left side with the top toolbar */
-				pt.x = FindWindowById(WC_MAIN_TOOLBAR, 0)->left;
+				pt.x = Window::FindById(WC_MAIN_TOOLBAR, 0)->left;
 				break;
 			case WDP_AUTO: /* Find a good automatic position for the window */
 				pt = GetAutoPlacePosition(desc->width, desc->height);
@@ -842,7 +1159,7 @@
 	}
 
 allocate_window:
-	w = LocalAllocateWindow(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets, window_number);
+	w = new Window(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets, window_number);
 	w->desc_flags = desc->flags;
 	return w;
 }
@@ -867,7 +1184,7 @@
 {
 	Window *w;
 
-	if (BringWindowToFrontById(desc->cls, window_number)) return NULL;
+	if (Window::BringToFrontById(desc->cls, window_number) != NULL) return NULL;
 	w = LocalAllocateWindowDesc(desc, window_number);
 	return w;
 }
@@ -877,10 +1194,8 @@
  * @return a pointer to the found window if any, NULL otherwise */
 Window *FindWindowFromPt(int x, int y)
 {
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		Window *w = *--wz;
+	Window *w;
+	REVERSED_FOR_ALL_WINDOWS(w) {
 		if (IS_INSIDE_1D(x, w->left, w->width) && IS_INSIDE_1D(y, w->top, w->height)) {
 			return w;
 		}
@@ -893,28 +1208,30 @@
 {
 	IConsoleClose();
 
-	memset(&_windows, 0, sizeof(_windows));
-	_last_z_window = _z_windows;
+	//memset(&_windows, 0, sizeof(_windows));
+	//_last_z_window = _z_windows;
 	InitViewports();
 	_no_scroll = 0;
 }
 
 void UnInitWindowSystem(void)
 {
-	Window **wz;
+	Window::s_list.m_list.clear();
 
-restart_search:
-	/* Delete all windows, reset z-array.
-	 *When we find the window to delete, we need to restart the search
-	 * as deleting this window could cascade in deleting (many) others
-	 * anywhere in the z-array. We call DeleteWindow() so that it can properly
-	 * release own alloc'd memory, which otherwise could result in memleaks */
-	FOR_ALL_WINDOWS(wz) {
-		DeleteWindow(*wz);
-		goto restart_search;
-	}
-
-	assert(_last_z_window == _z_windows);
+//	Window **wz;
+//
+//restart_search:
+//	/* Delete all windows, reset z-array.
+//	 *When we find the window to delete, we need to restart the search
+//	 * as deleting this window could cascade in deleting (many) others
+//	 * anywhere in the z-array. We call DeleteWindow() so that it can properly
+//	 * release own alloc'd memory, which otherwise could result in memleaks */
+//	FOR_ALL_WINDOWS(wz) {
+//		DeleteWindow(*wz);
+//		goto restart_search;
+//	}
+//
+//	assert(_last_z_window == _z_windows);
 }
 
 void ResetWindowSystem(void)
@@ -930,31 +1247,26 @@
 static void DecreaseWindowCounters(void)
 {
 	Window *w;
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		w = *--wz;
+	REVERSED_FOR_ALL_WINDOWS(w) {
 		// Unclick scrollbar buttons if they are pressed.
 		if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) {
 			w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP);
-			SetWindowDirty(w);
+			w->SetDirty();
 		}
 		CallWindowEventNP(w, WE_MOUSELOOP);
 	}
 
-	for (wz = _last_z_window; wz != _z_windows;) {
-		w = *--wz;
-
+	REVERSED_FOR_ALL_WINDOWS(w) {
 		if (w->flags4&WF_TIMEOUT_MASK && !(--w->flags4&WF_TIMEOUT_MASK)) {
 			CallWindowEventNP(w, WE_TIMEOUT);
-			if (w->desc_flags & WDF_UNCLICK_BUTTONS) RaiseWindowButtons(w);
+			if (w->desc_flags & WDF_UNCLICK_BUTTONS) w->RaiseButtons();
 		}
 	}
 }
 
 Window *GetCallbackWnd(void)
 {
-	return FindWindowById(_thd.window_class, _thd.window_number);
+	return Window::FindById(_thd.window_class, _thd.window_number);
 }
 
 static void HandlePlacePresize(void)
@@ -1008,7 +1320,7 @@
 
 	if (!_popup_menu_active) return true;
 
-	w = FindWindowById(WC_TOOLBAR_MENU, 0);
+	w = Window::FindById(WC_TOOLBAR_MENU, 0);
 	if (w == NULL) {
 		_popup_menu_active = false;
 		return false;
@@ -1030,9 +1342,13 @@
 
 static bool HandleMouseOver(void)
 {
+	static WindowClass  last_cls;
+	static WindowNumber last_num;
+
 	Window *w;
 	WindowEvent e;
-	static Window *last_w = NULL;
+
+	Window *last_w = Window::FindById(last_cls, last_num);
 
 	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
 
@@ -1043,7 +1359,9 @@
 		e.we.mouseover.pt.y = -1;
 		if (last_w->wndproc) last_w->wndproc(last_w, &e);
 	}
-	last_w = w;
+
+	last_cls = w->window_class;
+	last_num = w->window_number;
 
 	if (w != NULL) {
 		// send an event in client coordinates.
@@ -1074,7 +1392,7 @@
 
 	if (x == 0 && y == 0) return;
 
-	SetWindowDirty(w);
+	w->SetDirty();
 	for (wi = w->widget; wi->type != WWT_LAST; wi++) {
 		/* Isolate the resizing flags */
 		byte rsizeflag = GB(wi->display_flags, 0, 4);
@@ -1107,238 +1425,11 @@
 	if (resize_width)  w->width  += x;
 	if (resize_height) w->height += y;
 
-	SetWindowDirty(w);
+	w->SetDirty();
 }
 
-static bool _dragging_window;
-
-static bool HandleWindowDragging(void)
-{
-	Window* const *wz;
-	// Get out immediately if no window is being dragged at all.
-	if (!_dragging_window) return true;
-
-	// Otherwise find the window...
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		if (w->flags4 & WF_DRAGGING) {
-			const Widget *t = &w->widget[1]; // the title bar ... ugh
-			const Window *v;
-			int x;
-			int y;
-			int nx;
-			int ny;
-
-			// Stop the dragging if the left mouse button was released
-			if (!_left_button_down) {
-				w->flags4 &= ~WF_DRAGGING;
-				break;
-			}
-
-			SetWindowDirty(w);
-
-			x = _cursor.pos.x + _drag_delta.x;
-			y = _cursor.pos.y + _drag_delta.y;
-			nx = x;
-			ny = y;
-
-			if (_patches.window_snap_radius != 0) {
-				Window* const *vz;
-
-				int hsnap = _patches.window_snap_radius;
-				int vsnap = _patches.window_snap_radius;
-				int delta;
-
-				FOR_ALL_WINDOWS(vz) {
-					const Window *v = *vz;
-
-					if (v == w) continue; // Don't snap at yourself
-
-					if (y + w->height > v->top && y < v->top + v->height) {
-						// Your left border <-> other right border
-						delta = abs(v->left + v->width - x);
-						if (delta <= hsnap) {
-							nx = v->left + v->width;
-							hsnap = delta;
-						}
-
-						// Your right border <-> other left border
-						delta = abs(v->left - x - w->width);
-						if (delta <= hsnap) {
-							nx = v->left - w->width;
-							hsnap = delta;
-						}
-					}
-
-					if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
-						// Your left border <-> other left border
-						delta = abs(v->left - x);
-						if (delta <= hsnap) {
-							nx = v->left;
-							hsnap = delta;
-						}
-
-						// Your right border <-> other right border
-						delta = abs(v->left + v->width - x - w->width);
-						if (delta <= hsnap) {
-							nx = v->left + v->width - w->width;
-							hsnap = delta;
-						}
-					}
-
-					if (x + w->width > v->left && x < v->left + v->width) {
-						// Your top border <-> other bottom border
-						delta = abs(v->top + v->height - y);
-						if (delta <= vsnap) {
-							ny = v->top + v->height;
-							vsnap = delta;
-						}
-
-						// Your bottom border <-> other top border
-						delta = abs(v->top - y - w->height);
-						if (delta <= vsnap) {
-							ny = v->top - w->height;
-							vsnap = delta;
-						}
-					}
-
-					if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
-						// Your top border <-> other top border
-						delta = abs(v->top - y);
-						if (delta <= vsnap) {
-							ny = v->top;
-							vsnap = delta;
-						}
-
-						// Your bottom border <-> other bottom border
-						delta = abs(v->top + v->height - y - w->height);
-						if (delta <= vsnap) {
-							ny = v->top + v->height - w->height;
-							vsnap = delta;
-						}
-					}
-				}
-			}
-
-			// Make sure the window doesn't leave the screen
-			// 13 is the height of the title bar
-			nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
-			ny = clamp(ny, 0, _screen.height - 13);
-
-			// Make sure the title bar isn't hidden by behind the main tool bar
-			v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-			if (v != NULL) {
-				int v_bottom = v->top + v->height;
-				int v_right = v->left + v->width;
-				if (ny + t->top >= v->top && ny + t->top < v_bottom) {
-					if ((v->left < 13 && nx + t->left < v->left) ||
-							(v_right > _screen.width - 13 && nx + t->right > v_right)) {
-						ny = v_bottom;
-					} else {
-						if (nx + t->left > v->left - 13 &&
-								nx + t->right < v_right + 13) {
-							if (w->top >= v_bottom) {
-								ny = v_bottom;
-							} else if (w->left < nx) {
-								nx = v->left - 13 - t->left;
-							} else {
-								nx = v_right + 13 - t->right;
-							}
-						}
-					}
-				}
-			}
-
-			if (w->viewport != NULL) {
-				w->viewport->left += nx - w->left;
-				w->viewport->top  += ny - w->top;
-			}
-			w->left = nx;
-			w->top  = ny;
-
-			SetWindowDirty(w);
-			return false;
-		} else if (w->flags4 & WF_SIZING) {
-			WindowEvent e;
-			int x, y;
-
-			/* Stop the sizing if the left mouse button was released */
-			if (!_left_button_down) {
-				w->flags4 &= ~WF_SIZING;
-				SetWindowDirty(w);
-				break;
-			}
-
-			x = _cursor.pos.x - _drag_delta.x;
-			y = _cursor.pos.y - _drag_delta.y;
-
-			/* X and Y has to go by step.. calculate it.
-			 * The cast to int is necessary else x/y are implicitly casted to
-			 * unsigned int, which won't work. */
-			if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width;
-
-			if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height;
-
-			/* Check if we don't go below the minimum set size */
-			if ((int)w->width + x < (int)w->resize.width)
-				x = w->resize.width - w->width;
-			if ((int)w->height + y < (int)w->resize.height)
-				y = w->resize.height - w->height;
-
-			/* Window already on size */
-			if (x == 0 && y == 0) return false;
-
-			/* Now find the new cursor pos.. this is NOT _cursor, because
-			    we move in steps. */
-			_drag_delta.x += x;
-			_drag_delta.y += y;
-
-			/* ResizeWindow sets both pre- and after-size to dirty for redrawal */
-			ResizeWindow(w, x, y);
-
-			e.event = WE_RESIZE;
-			e.we.sizing.size.x = x + w->width;
-			e.we.sizing.size.y = y + w->height;
-			e.we.sizing.diff.x = x;
-			e.we.sizing.diff.y = y;
-			w->wndproc(w, &e);
-			return false;
-		}
-	}
-
-	_dragging_window = false;
-	return false;
-}
-
-static void StartWindowDrag(Window *w)
-{
-	w->flags4 |= WF_DRAGGING;
-	_dragging_window = true;
-
-	_drag_delta.x = w->left - _cursor.pos.x;
-	_drag_delta.y = w->top  - _cursor.pos.y;
-
-	BringWindowToFront(w);
-	DeleteWindowById(WC_DROPDOWN_MENU, 0);
-}
-
-static void StartWindowSizing(Window *w)
-{
-	w->flags4 |= WF_SIZING;
-	_dragging_window = true;
-
-	_drag_delta.x = _cursor.pos.x;
-	_drag_delta.y = _cursor.pos.y;
-
-	BringWindowToFront(w);
-	DeleteWindowById(WC_DROPDOWN_MENU, 0);
-}
-
-
 static bool HandleScrollbarScrolling(void)
 {
-	Window* const *wz;
 	int i;
 	int pos;
 	Scrollbar *sb;
@@ -1347,14 +1438,13 @@
 	if (!_scrolling_scrollbar) return true;
 
 	// Find the scrolling window
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->flags4 & WF_SCROLL_MIDDLE) {
 			// Abort if no button is clicked any more.
 			if (!_left_button_down) {
 				w->flags4 &= ~WF_SCROLL_MIDDLE;
-				SetWindowDirty(w);
+				w->SetDirty();
 				break;
 			}
 
@@ -1373,7 +1463,7 @@
 			pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap));
 			if (pos != sb->pos) {
 				sb->pos = pos;
-				SetWindowDirty(w);
+				w->SetDirty();
 			}
 			return false;
 		}
@@ -1423,32 +1513,30 @@
  * modal-popup; function returns a false and child window gets a white border
  * @param w Window to bring on-top
  * @return false if the window has an active modal child, true otherwise */
-static bool MaybeBringWindowToFront(const Window *w)
+static bool MaybeBringWindowToFront(Window *w)
 {
 	bool bring_to_front = false;
-	Window* const *wz;
-	Window* const *uz;
 
 	if (w->window_class == WC_MAIN_WINDOW ||
-			IsVitalWindow(w) ||
+			w->IsVital() ||
 			w->window_class == WC_TOOLTIPS ||
 			w->window_class == WC_DROPDOWN_MENU) {
 		return true;
 	}
 
-	wz = FindWindowZPosition(w);
-	for (uz = wz; ++uz != _last_z_window;) {
-		Window *u = *uz;
+	WindowList::Iterator wit = Window::s_list.Find(w);
+	for (WindowList::Iterator it = wit; it != Window::s_list.m_list.end(); it++) {
+		Window *u = (*it).w;
 
 		/* A modal child will prevent the activation of the parent window */
 		if (u->parent == w && (u->desc_flags & WDF_MODAL)) {
 			u->flags4 |= WF_WHITE_BORDER_MASK;
-			SetWindowDirty(u);
+			u->SetDirty();
 			return false;
 		}
 
 		if (u->window_class == WC_MAIN_WINDOW ||
-				IsVitalWindow(u) ||
+				u->IsVital() ||
 				u->window_class == WC_TOOLTIPS ||
 				u->window_class == WC_DROPDOWN_MENU) {
 			continue;
@@ -1465,7 +1553,7 @@
 		bring_to_front = true;
 	}
 
-	if (bring_to_front) BringWindowToFront(w);
+	if (bring_to_front) w->BringToFront();
 	return true;
 }
 
@@ -1496,7 +1584,7 @@
  */
 void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, int msg, int wparam, int lparam)
 {
-	Window *w = FindWindowById(wnd_class, wnd_num);
+	Window *w = Window::FindById(wnd_class, wnd_num);
 	if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam);
 }
 
@@ -1509,10 +1597,10 @@
  */
 void SendWindowMessageClass(WindowClass wnd_class, int msg, int wparam, int lparam)
 {
-	Window* const *wz;
+	Window *w;
 
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->window_class == wnd_class) SendWindowMessageW(*wz, msg, wparam, lparam);
+	FOR_ALL_WINDOWS(w) {
+		if (w->window_class == wnd_class) SendWindowMessageW(w, msg, wparam, lparam);
 	}
 }
 
@@ -1521,7 +1609,6 @@
  * 16 bits the keycode */
 void HandleKeypress(uint32 key)
 {
-	Window* const *wz;
 	WindowEvent e;
 	/* Stores if a window with a textfield for typing is open
 	 * If this is the case, keypress events are only passed to windows with text fields and
@@ -1546,18 +1633,17 @@
 	e.we.keypress.cont = true;
 
 	// check if we have a query string window open before allowing hotkeys
-	if (FindWindowById(WC_QUERY_STRING,       0) != NULL ||
-			FindWindowById(WC_SEND_NETWORK_MSG,   0) != NULL ||
-			FindWindowById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
-			FindWindowById(WC_CONSOLE,            0) != NULL ||
-			FindWindowById(WC_SAVELOAD,           0) != NULL) {
+	if (Window::FindById(WC_QUERY_STRING,       0) != NULL ||
+			Window::FindById(WC_SEND_NETWORK_MSG,   0) != NULL ||
+			Window::FindById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
+			Window::FindById(WC_CONSOLE,            0) != NULL ||
+			Window::FindById(WC_SAVELOAD,           0) != NULL) {
 		query_open = true;
 	}
 
 	// Call the event, start with the uppermost window.
-	for (wz = _last_z_window; wz != _z_windows;) {
-		Window *w = *--wz;
-
+	Window *w;
+	REVERSED_FOR_ALL_WINDOWS(w) {
 		// if a query window is open, only call the event for certain window types
 		if (query_open &&
 				w->window_class != WC_QUERY_STRING &&
@@ -1572,7 +1658,7 @@
 	}
 
 	if (e.we.keypress.cont) {
-		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		Window *w = Window::FindById(WC_MAIN_TOOLBAR, 0);
 		// When there is no toolbar w is null, check for that
 		if (w != NULL) w->wndproc(w, &e);
 	}
@@ -1630,13 +1716,13 @@
 	DecreaseWindowCounters();
 	HandlePlacePresize();
 	UpdateTileSelection();
-	if (!VpHandlePlaceSizingDrag())  return;
-	if (!HandleDragDrop())           return;
-	if (!HandlePopupMenu())          return;
-	if (!HandleWindowDragging())     return;
-	if (!HandleScrollbarScrolling()) return;
-	if (!HandleViewportScroll())     return;
-	if (!HandleMouseOver())          return;
+	if (!VpHandlePlaceSizingDrag())      return;
+	if (!HandleDragDrop())               return;
+	if (!HandlePopupMenu())              return;
+	if (!Window::HandleWindowDragging()) return;
+	if (!HandleScrollbarScrolling())     return;
+	if (!HandleViewportScroll())         return;
+	if (!HandleMouseOver())              return;
 
 	x = _cursor.pos.x;
 	y = _cursor.pos.y;
@@ -1744,31 +1830,30 @@
 
 void UpdateWindows(void)
 {
-	Window* const *wz;
 	static int we4_timer = 0;
 	int t = we4_timer + 1;
 
+	Window *w;
 	if (t >= 100) {
-		for (wz = _last_z_window; wz != _z_windows;) {
-			CallWindowEventNP(*--wz, WE_4);
+		REVERSED_FOR_ALL_WINDOWS(w) {
+			CallWindowEventNP(w, WE_4);
 		}
 		t = 0;
 	}
 	we4_timer = t;
 
-	for (wz = _last_z_window; wz != _z_windows;) {
-		Window *w = *--wz;
+	REVERSED_FOR_ALL_WINDOWS(w) {
 		if (w->flags4 & WF_WHITE_BORDER_MASK) {
 			w->flags4 -= WF_WHITE_BORDER_ONE;
 
-			if (!(w->flags4 & WF_WHITE_BORDER_MASK)) SetWindowDirty(w);
+			if (!(w->flags4 & WF_WHITE_BORDER_MASK)) w->SetDirty();
 		}
 	}
 
 	DrawDirtyBlocks();
 
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
+	FOR_ALL_WINDOWS(w) {
+		if (w->viewport != NULL) UpdateViewportPosition(w);
 	}
 	DrawTextMessage();
 	// Redraw mouse cursor in case it was hidden
@@ -1791,11 +1876,10 @@
 
 void InvalidateWindow(WindowClass cls, WindowNumber number)
 {
-	Window* const *wz;
+	Window *w;
 
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
-		if (w->window_class == cls && w->window_number == number) SetWindowDirty(w);
+	FOR_ALL_WINDOWS(w) {
+		if (w->window_class == cls && w->window_number == number) w->SetDirty();
 	}
 }
 
@@ -1811,10 +1895,8 @@
 
 void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index)
 {
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		const Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == cls && w->window_number == number) {
 			InvalidateWidget(w, widget_index);
 		}
@@ -1823,57 +1905,51 @@
 
 void InvalidateWindowClasses(WindowClass cls)
 {
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->window_class == cls) SetWindowDirty(*wz);
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
+		if (w->window_class == cls) w->SetDirty();
 	}
 }
 
 void InvalidateThisWindowData(Window *w)
 {
 	CallWindowEventNP(w, WE_INVALIDATE_DATA);
-	SetWindowDirty(w);
+	w->SetDirty();
 }
 
 void InvalidateWindowData(WindowClass cls, WindowNumber number)
 {
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w);
 	}
 }
 
 void InvalidateWindowClassesData(WindowClass cls)
 {
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz);
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
+		if (w->window_class == cls) InvalidateThisWindowData(w);
 	}
 }
 
 void CallWindowTickEvent(void)
 {
-	Window* const *wz;
-
-	for (wz = _last_z_window; wz != _z_windows;) {
-		CallWindowEventNP(*--wz, WE_TICK);
+	Window *w;
+	REVERSED_FOR_ALL_WINDOWS(w) {
+		CallWindowEventNP(w, WE_TICK);
 	}
 }
 
 void DeleteNonVitalWindows(void)
 {
-	Window* const *wz;
 
 restart_search:
 	/* When we find the window to delete, we need to restart the search
 	 * as deleting this window could cascade in deleting (many) others
 	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		if (w->window_class != WC_MAIN_WINDOW &&
 				w->window_class != WC_SELECT_GAME &&
 				w->window_class != WC_MAIN_TOOLBAR &&
@@ -1882,7 +1958,7 @@
 				w->window_class != WC_TOOLTIPS &&
 				(w->flags4 & WF_STICKY) == 0) { // do not delete windows which are 'pinned'
 
-			DeleteWindow(w);
+			w->Close();
 			goto restart_search;
 		}
 	}
@@ -1895,8 +1971,6 @@
  * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
 void DeleteAllNonVitalWindows(void)
 {
-	Window* const *wz;
-
 	/* Delete every window except for stickied ones, then sticky ones as well */
 	DeleteNonVitalWindows();
 
@@ -1904,9 +1978,10 @@
 	/* When we find the window to delete, we need to restart the search
 	 * as deleting this window could cascade in deleting (many) others
 	 * anywhere in the z-array */
-	FOR_ALL_WINDOWS(wz) {
-		if ((*wz)->flags4 & WF_STICKY) {
-			DeleteWindow(*wz);
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
+		if (w->flags4 & WF_STICKY) {
+			w->Close();
 			goto restart_search;
 		}
 	}
@@ -1925,7 +2000,7 @@
 	DEBUG(misc, 5, "Repositioning Main Toolbar...");
 
 	if (w == NULL || w->window_class != WC_MAIN_TOOLBAR) {
-		w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		w = Window::FindById(WC_MAIN_TOOLBAR, 0);
 	}
 
 	switch (_patches.toolbar_pos) {
@@ -1939,10 +2014,8 @@
 
 void RelocateAllWindows(int neww, int newh)
 {
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
+	Window *w;
+	FOR_ALL_WINDOWS(w) {
 		int left, top;
 
 		if (w->window_class == WC_MAIN_WINDOW) {