diff --git a/src/console.c b/src/console.c
index 67d995f98a79a68d889c019b3c7dc95762c0573c..cbfcb6e3821feedeb0a556cd873aec54969f84af 100644
--- a/src/console.c
+++ b/src/console.c
@@ -76,7 +76,6 @@ static UINT8  con_hudlines;             // number of console heads up message li
 static UINT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines
 
        INT32 con_clearlines;      // top screen lines to refresh when view reduced
-       boolean con_hudupdate;   // when messages scroll, we need a backgrnd refresh
 
 // console text output
 static char *con_line;          // console text output current line
@@ -1348,9 +1347,6 @@ static void CON_Linefeed(void)
 
 	con_line = &con_buffer[(con_cy%con_totallines)*con_width];
 	memset(con_line, ' ', con_width);
-
-	// make sure the view borders are refreshed if hud messages scroll
-	con_hudupdate = true; // see HU_Erase()
 }
 
 // Outputs text into the console text buffer
@@ -1579,13 +1575,6 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...)
 //
 void CONS_Error(const char *msg)
 {
-#if defined(RPC_NO_WINDOWS_H) && defined(_WINDOWS)
-	if (!graphics_started)
-	{
-		MessageBoxA(vid.WndParent, msg, "SRB2 Warning", MB_OK);
-		return;
-	}
-#endif
 	CONS_Printf("\x82%s", msg); // write error msg in different colour
 	CONS_Printf(M_GetText("Press ENTER to continue\n"));
 
@@ -1809,7 +1798,6 @@ static void CON_DrawConsole(void)
 
 	//FIXME: refresh borders only when console bg is translucent
 	con_clearlines = con_curlines; // clear console draw from view borders
-	con_hudupdate = true; // always refresh while console is on
 
 	// draw console background
 	if (cons_backpic.value || con_forcepic)
diff --git a/src/console.h b/src/console.h
index f22f8dcbc18e595b6fb57b942bca8c0eb3cf15e2..2794770eba117f9055a290edbb3bb36c19578d63 100644
--- a/src/console.h
+++ b/src/console.h
@@ -41,7 +41,6 @@ extern INT32 con_clipviewtop;
 extern INT32 con_destlines;
 
 extern INT32 con_clearlines; // lines of top of screen to refresh
-extern boolean con_hudupdate; // hud messages have changed, need refresh
 extern UINT32 con_scalefactor; // console text scale factor
 
 extern consvar_t cons_backcolor;
diff --git a/src/d_main.c b/src/d_main.c
index 5861f988655c62e9b812b13d48832c940f66ebc2..e3143d22ce0effe84393d5f1b1153c4f5aa953d3 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -325,7 +325,7 @@ static void D_Display(void)
 	// 4. The frame is ready to be drawn!
 
 	// Check for change of renderer or screen size (video mode)
-	if ((setrenderneeded || setmodeneeded) && !wipe)
+	if (vid.change.set && !wipe)
 		SCR_SetMode(); // change video mode
 
 	// Recalc the screen
@@ -405,13 +405,11 @@ static void D_Display(void)
 		case GS_LEVEL:
 			if (!gametic)
 				break;
-			HU_Erase();
 			AM_Drawer();
 			break;
 
 		case GS_INTERMISSION:
 			Y_IntermissionDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -426,13 +424,11 @@ static void D_Display(void)
 
 		case GS_ENDING:
 			F_EndingDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
 		case GS_CUTSCENE:
 			F_CutsceneDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -442,7 +438,6 @@ static void D_Display(void)
 
 		case GS_EVALUATION:
 			F_GameEvaluationDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
@@ -452,7 +447,6 @@ static void D_Display(void)
 
 		case GS_CREDITS:
 			F_CreditDrawer();
-			HU_Erase();
 			HU_Drawer();
 			break;
 
diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c
index 3b0a12a328df587e1cd20d0312cf96ce6c8df847..3a1cbd223269e6d3b08741f2b60c091fb42c4db0 100644
--- a/src/dummy/i_video.c
+++ b/src/dummy/i_video.c
@@ -35,9 +35,10 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h)
 
 void VID_PrepareModeList(void){}
 
-INT32 VID_SetMode(INT32 modenum)
+void VID_SetSize(INT32 width, INT32 height)
 {
-	(void)modenum;
+	(void)width;
+	(void)height;
 	return 0;
 }
 
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index eb0b9e332297a0219c1ef19f922dea5b8547d868..d9a0fefe6ce6c377be70bc27c98d6ded4407f1c8 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -22,7 +22,7 @@
 #include "hw_drv.h"
 
 #include "../m_misc.h" //FIL_WriteFile()
-#include "../r_draw.h" //viewborderlump
+#include "../r_draw.h"
 #include "../r_main.h"
 #include "../w_wad.h"
 #include "../z_zone.h"
@@ -1005,136 +1005,6 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight)
 	HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
 }
 
-
-// ==========================================================================
-//                                                             R_DRAW.C STUFF
-// ==========================================================================
-
-// ------------------
-// HWR_DrawViewBorder
-// Fill the space around the view window with a Doom flat texture, draw the
-// beveled edges.
-// 'clearlines' is useful to clear the heads up messages, when the view
-// window is reduced, it doesn't refresh all the view borders.
-// ------------------
-void HWR_DrawViewBorder(INT32 clearlines)
-{
-	INT32 x, y;
-	INT32 top, side;
-	INT32 baseviewwidth, baseviewheight;
-	INT32 basewindowx, basewindowy;
-	patch_t *patch;
-
-//    if (gl_viewwidth == vid.width)
-//        return;
-
-	if (!clearlines)
-		clearlines = BASEVIDHEIGHT; // refresh all
-
-	// calc view size based on original game resolution
-	baseviewwidth =  FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwidth), vid.fdupx)); //(cv_viewsize.value * BASEVIDWIDTH/10)&~7;
-	baseviewheight = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewheight), vid.fdupy));
-	top = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_baseviewwindowy), vid.fdupy));
-	side = FixedInt(FixedDiv(FLOAT_TO_FIXED(gl_viewwindowx), vid.fdupx));
-
-	// top
-	HWR_DrawFlatFill(0, 0,
-		BASEVIDWIDTH, (top < clearlines ? top : clearlines),
-		st_borderpatchnum);
-
-	// left
-	if (top < clearlines)
-		HWR_DrawFlatFill(0, top, side,
-			(clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
-			st_borderpatchnum);
-
-	// right
-	if (top < clearlines)
-		HWR_DrawFlatFill(side + baseviewwidth, top, side,
-			(clearlines-top < baseviewheight ? clearlines-top : baseviewheight),
-			st_borderpatchnum);
-
-	// bottom
-	if (top + baseviewheight < clearlines)
-		HWR_DrawFlatFill(0, top + baseviewheight,
-			BASEVIDWIDTH, BASEVIDHEIGHT, st_borderpatchnum);
-
-	//
-	// draw the view borders
-	//
-
-	basewindowx = (BASEVIDWIDTH - baseviewwidth)>>1;
-	if (baseviewwidth == BASEVIDWIDTH)
-		basewindowy = 0;
-	else
-		basewindowy = top;
-
-	// top edge
-	if (clearlines > basewindowy - 8)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH);
-		for (x = 0; x < baseviewwidth; x += 8)
-			HWR_DrawPatch(patch, basewindowx + x, basewindowy - 8,
-				0);
-	}
-
-	// bottom edge
-	if (clearlines > basewindowy + baseviewheight)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH);
-		for (x = 0; x < baseviewwidth; x += 8)
-			HWR_DrawPatch(patch, basewindowx + x,
-				basewindowy + baseviewheight, 0);
-	}
-
-	// left edge
-	if (clearlines > basewindowy)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH);
-		for (y = 0; y < baseviewheight && basewindowy + y < clearlines;
-			y += 8)
-		{
-			HWR_DrawPatch(patch, basewindowx - 8, basewindowy + y,
-				0);
-		}
-	}
-
-	// right edge
-	if (clearlines > basewindowy)
-	{
-		patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH);
-		for (y = 0; y < baseviewheight && basewindowy+y < clearlines;
-			y += 8)
-		{
-			HWR_DrawPatch(patch, basewindowx + baseviewwidth,
-				basewindowy + y, 0);
-		}
-	}
-
-	// Draw beveled corners.
-	if (clearlines > basewindowy - 8)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TL],
-				PU_PATCH),
-			basewindowx - 8, basewindowy - 8, 0);
-
-	if (clearlines > basewindowy - 8)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TR],
-				PU_PATCH),
-			basewindowx + baseviewwidth, basewindowy - 8, 0);
-
-	if (clearlines > basewindowy+baseviewheight)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BL],
-				PU_PATCH),
-			basewindowx - 8, basewindowy + baseviewheight, 0);
-
-	if (clearlines > basewindowy + baseviewheight)
-		HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BR],
-				PU_PATCH),
-			basewindowx + baseviewwidth,
-			basewindowy + baseviewheight, 0);
-}
-
-
 // ==========================================================================
 //                                                     AM_MAP.C DRAWING STUFF
 // ==========================================================================
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 091e2b2fba50e46638aa6ee52bff2d7e6c81f9f0..38e55872a1543d9261c8827718cb5a5d41c26536 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -2051,76 +2051,6 @@ void HU_Drawer(void)
 	}
 }
 
-//======================================================================
-//                 HUD MESSAGES CLEARING FROM SCREEN
-//======================================================================
-
-// Clear old messages from the borders around the view window
-// (only for reduced view, refresh the borders when needed)
-//
-// startline: y coord to start clear,
-// clearlines: how many lines to clear.
-//
-static INT32 oldclearlines;
-
-void HU_Erase(void)
-{
-	INT32 topline, bottomline;
-	INT32 y, yoffset;
-
-#ifdef HWRENDER
-	// clear hud msgs on double buffer (OpenGL mode)
-	boolean secondframe;
-	static INT32 secondframelines;
-#endif
-
-	if (con_clearlines == oldclearlines && !con_hudupdate && !chat_on)
-		return;
-
-#ifdef HWRENDER
-	// clear the other frame in double-buffer modes
-	secondframe = (con_clearlines != oldclearlines);
-	if (secondframe)
-		secondframelines = oldclearlines;
-#endif
-
-	// clear the message lines that go away, so use _oldclearlines_
-	bottomline = oldclearlines;
-	oldclearlines = con_clearlines;
-	if (chat_on && OLDCHAT)
-		if (bottomline < 8)
-			bottomline = 8; // only do it for consolechat. consolechat is gay.
-
-	if (automapactive || viewwindowx == 0) // hud msgs don't need to be cleared
-		return;
-
-	// software mode copies view border pattern & beveled edges from the backbuffer
-	if (rendermode == render_soft)
-	{
-		topline = 0;
-		for (y = topline, yoffset = y*vid.width; y < bottomline; y++, yoffset += vid.width)
-		{
-			if (y < viewwindowy || y >= viewwindowy + viewheight)
-				R_VideoErase(yoffset, vid.width); // erase entire line
-			else
-			{
-				R_VideoErase(yoffset, viewwindowx); // erase left border
-				// erase right border
-				R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
-			}
-		}
-		con_hudupdate = false; // if it was set..
-	}
-#ifdef HWRENDER
-	else if (rendermode != render_none)
-	{
-		// refresh just what is needed from the view borders
-		HWR_DrawViewBorder(secondframelines);
-		con_hudupdate = secondframe;
-	}
-#endif
-}
-
 //======================================================================
 //                   IN-LEVEL MULTIPLAYER RANKINGS
 //======================================================================
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index 8647e4500cb2ce1ebf76015dbcc9031a0b5f4082..b3069c215f1d6f7e09d471c9393c7b250057d942 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -111,7 +111,6 @@ boolean HU_Responder(event_t *ev);
 void HU_Ticker(void);
 void HU_Drawer(void);
 char HU_dequeueChatChar(void);
-void HU_Erase(void);
 void HU_clearChatChars(void);
 void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags);	// Lat': Ping drawer for scoreboard.
 void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer);
diff --git a/src/i_video.h b/src/i_video.h
index 8efca5f9ab28da6312755d9e11a6c8791149f26b..117961e1d4543236a0cd48aedd97250e5fff0aed 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -73,20 +73,9 @@ INT32 VID_NumModes(void);
 */
 INT32 VID_GetModeForSize(INT32 w, INT32 h);
 
-
-/**	\brief	The VID_SetMode function
-
-	Set the video mode right now,
-	the video mode change is delayed until the start of the next refresh
-	by setting the setmodeneeded to a value >0
-	setup a video mode, this is to be called from the menu
-
-
-	\param	modenum	video mode to set to
-
-	\return	current video mode
+/**	\brief Changes the current resolution
 */
-INT32 VID_SetMode(INT32 modenum);
+void VID_SetSize(INT32 width, INT32 height);
 
 /**	\brief Checks the render state
 	\return	true if the renderer changed
diff --git a/src/m_menu.c b/src/m_menu.c
index 12003f945c8ec9d9c73a15a6ef833f1549c4970f..6c75936d0cbb20dbc79e4e795563553862a4944c 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -167,7 +167,8 @@ static  INT32   (*setupcontrols)[2];  // pointer to the gamecontrols of the play
 
 // shhh... what am I doing... nooooo!
 static INT32 vidm_testingmode = 0;
-static INT32 vidm_previousmode;
+static INT32 vidm_previouswidth;
+static INT32 vidm_previousheight;
 static INT32 vidm_selected = 0;
 static INT32 vidm_nummodes;
 static INT32 vidm_column_size;
@@ -3872,7 +3873,7 @@ void M_Ticker(void)
 	{
 		// restore the previous video mode
 		if (--vidm_testingmode == 0)
-			setmodeneeded = vidm_previousmode + 1;
+			SCR_ChangeResolution(vidm_previouswidth, vidm_previousheight);
 	}
 
 	if (currentMenu == &OP_ScreenshotOptionsDef)
@@ -4106,53 +4107,6 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines)
 {
 	// Solid color textbox.
 	V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 159);
-	//V_DrawFill(x+8, y+8, width*8, boxlines*8, 31);
-/*
-	patch_t *p;
-	INT32 cx, cy, n;
-	INT32 step, boff;
-
-	step = 8;
-	boff = 8;
-
-	// draw left side
-	cx = x;
-	cy = y;
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TL], PU_PATCH));
-	cy += boff;
-	p = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH);
-	for (n = 0; n < boxlines; n++)
-	{
-		V_DrawScaledPatch(cx, cy, 0, p);
-		cy += step;
-	}
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_PATCH));
-
-	// draw middle
-	V_DrawFlatFill(x + boff, y + boff, width*step, boxlines*step, st_borderpatchnum);
-
-	cx += boff;
-	cy = y;
-	while (width > 0)
-	{
-		V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH));
-		V_DrawScaledPatch(cx, y + boff + boxlines*step, 0, W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH));
-		width--;
-		cx += step;
-	}
-
-	// draw right side
-	cy = y;
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TR], PU_PATCH));
-	cy += boff;
-	p = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH);
-	for (n = 0; n < boxlines; n++)
-	{
-		V_DrawScaledPatch(cx, cy, 0, p);
-		cy += step;
-	}
-	V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_PATCH));
-*/
 }
 
 static fixed_t staticalong = 0;
@@ -13375,8 +13329,7 @@ static modedesc_t modedescs[MAXMODEDESCS];
 
 static void M_VideoModeMenu(INT32 choice)
 {
-	INT32 i, j, vdup, nummodes, width, height;
-	const char *desc;
+	INT32 i;
 
 	(void)choice;
 
@@ -13385,66 +13338,33 @@ static void M_VideoModeMenu(INT32 choice)
 #if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)
 	VID_PrepareModeList(); // FIXME: hack
 #endif
+
 	vidm_nummodes = 0;
 	vidm_selected = 0;
-	nummodes = VID_NumModes();
 
-#ifdef _WINDOWS
-	// clean that later: skip windowed mode 0, video modes menu only shows FULL SCREEN modes
-	if (nummodes <= NUMSPECIALMODES)
-		i = 0; // unless we have nothing
-	else
-		i = NUMSPECIALMODES;
-#else
-	// DOS does not skip mode 0, because mode 0 is ALWAYS present
-	i = 0;
-#endif
-	for (; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++)
+	INT32 nummodes = VID_NumModes();
+
+	for (i = 0; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++)
 	{
-		desc = VID_GetModeName(i);
+		const char *desc = VID_GetModeName(i);
 		if (desc)
 		{
-			vdup = 0;
-
-			// when a resolution exists both under VGA and VESA, keep the
-			// VESA mode, which is always a higher modenum
-			for (j = 0; j < vidm_nummodes; j++)
-			{
-				if (!strcmp(modedescs[j].desc, desc))
-				{
-					// mode(0): 320x200 is always standard VGA, not vesa
-					if (modedescs[j].modenum)
-					{
-						modedescs[j].modenum = i;
-						vdup = 1;
-
-						if (i == vid.modenum)
-							vidm_selected = j;
-					}
-					else
-						vdup = 1;
+			// Pull out the width and height
+			INT32 width, height;
+			sscanf(desc, "%u%*c%u", &width, &height);
 
-					break;
-				}
-			}
-
-			if (!vdup)
-			{
-				modedescs[vidm_nummodes].modenum = i;
-				modedescs[vidm_nummodes].desc = desc;
-
-				if (i == vid.modenum)
-					vidm_selected = vidm_nummodes;
+			modedescs[vidm_nummodes].width = width;
+			modedescs[vidm_nummodes].height = height;
+			modedescs[vidm_nummodes].desc = desc;
 
-				// Pull out the width and height
-				sscanf(desc, "%u%*c%u", &width, &height);
+			if (width == vid.width && height == vid.height)
+				vidm_selected = vidm_nummodes;
 
-				// Show multiples of 320x200 as green.
-				if (SCR_IsAspectCorrect(width, height))
-					modedescs[vidm_nummodes].goodratio = 1;
+			// Show multiples of 320x200 as green.
+			if (SCR_IsAspectCorrect(width, height))
+				modedescs[vidm_nummodes].goodratio = 1;
 
-				vidm_nummodes++;
-			}
+			vidm_nummodes++;
 		}
 	}
 
@@ -13522,11 +13442,11 @@ static void M_DrawVideoMode(void)
 				vid.width, vid.height));
 		V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 116, (cv_fullscreen.value ? 0 : V_TRANSLUCENT),
 			va("Default mode is %c%dx%d",
-				(SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : (!(VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value)+1) ? 0x85 : 0x80),
+				(SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : 0x80,
 				cv_scr_width.value, cv_scr_height.value));
 		V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 124, (cv_fullscreen.value ? V_TRANSLUCENT : 0),
 			va("Windowed mode is %c%dx%d",
-				(SCR_IsAspectCorrect(cv_scr_width_w.value, cv_scr_height_w.value)) ? 0x83 : (!(VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value)+1) ? 0x85 : 0x80),
+				(SCR_IsAspectCorrect(cv_scr_width_w.value, cv_scr_height_w.value)) ? 0x83 : 0x80,
 				cv_scr_width_w.value, cv_scr_height_w.value));
 
 		V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 138,
@@ -13680,7 +13600,7 @@ static void M_HandleVideoMode(INT32 ch)
 	{
 		// change back to the previous mode quickly
 		case KEY_ESCAPE:
-			setmodeneeded = vidm_previousmode + 1;
+			SCR_ChangeResolution(vidm_previouswidth, vidm_previousheight);
 			vidm_testingmode = 0;
 			break;
 
@@ -13722,7 +13642,7 @@ static void M_HandleVideoMode(INT32 ch)
 			break;
 
 		case KEY_ENTER:
-			if (vid.modenum == modedescs[vidm_selected].modenum)
+			if (vid.width == modedescs[vidm_selected].width && vid.height == modedescs[vidm_selected].height)
 			{
 				S_StartSound(NULL, sfx_strpst);
 				SCR_SetDefaultMode();
@@ -13731,9 +13651,11 @@ static void M_HandleVideoMode(INT32 ch)
 			{
 				S_StartSound(NULL, sfx_menu1);
 				vidm_testingmode = 15*TICRATE;
-				vidm_previousmode = vid.modenum;
-				if (!setmodeneeded) // in case the previous setmode was not finished
-					setmodeneeded = modedescs[vidm_selected].modenum + 1;
+				vidm_previouswidth = vid.width;
+				vidm_previousheight = vid.height;
+
+				if (!vid.change.set) // in case the previous setmode was not finished
+					SCR_SetWindowSize(modedescs[vidm_selected].width, modedescs[vidm_selected].height);
 			}
 			break;
 
@@ -13751,9 +13673,9 @@ static void M_HandleVideoMode(INT32 ch)
 			CV_Set(&cv_scr_width_w, cv_scr_width_w.defaultvalue);
 			CV_Set(&cv_scr_height_w, cv_scr_height_w.defaultvalue);
 			if (cv_fullscreen.value)
-				setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value)+1;
+				SCR_SetWindowSize(cv_scr_width.value, cv_scr_height.value);
 			else
-				setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value)+1;
+				SCR_SetWindowSize(cv_scr_width_w.value, cv_scr_height_w.value);
 			break;
 
 		case KEY_F10: // Renderer toggle, also processed inside menus
diff --git a/src/m_menu.h b/src/m_menu.h
index c925c7f49c775d4a6e0becd7e2c5eb03d60784e4..ebb8dbde351aae055d1c4a903135bc909ef861ff 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -413,7 +413,7 @@ extern gtdesc_t gametypedesc[NUMGAMETYPES];
 // mode descriptions for video mode menu
 typedef struct
 {
-	INT32 modenum; // video mode number in the vidmodes list
+	INT32 width, height;
 	const char *desc;  // XXXxYYY
 	UINT8 goodratio; // aspect correct if 1
 } modedesc_t;
diff --git a/src/r_draw.c b/src/r_draw.c
index b0467e4f728d4cf757b53484a3d5ca4fda9d91cc..79ad9adde954f741054d81f182937ffb89da6ffd 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -722,100 +722,6 @@ void R_InitViewBuffer(INT32 width, INT32 height)
 	}
 }
 
-/**	\brief viewborder patches lump numbers
-*/
-lumpnum_t viewborderlump[8];
-
-/**	\brief Store the lumpnumber of the viewborder patches
-*/
-
-void R_InitViewBorder(void)
-{
-	viewborderlump[BRDR_T] = W_GetNumForName("brdr_t");
-	viewborderlump[BRDR_B] = W_GetNumForName("brdr_b");
-	viewborderlump[BRDR_L] = W_GetNumForName("brdr_l");
-	viewborderlump[BRDR_R] = W_GetNumForName("brdr_r");
-	viewborderlump[BRDR_TL] = W_GetNumForName("brdr_tl");
-	viewborderlump[BRDR_BL] = W_GetNumForName("brdr_bl");
-	viewborderlump[BRDR_TR] = W_GetNumForName("brdr_tr");
-	viewborderlump[BRDR_BR] = W_GetNumForName("brdr_br");
-}
-
-#if 0
-/**	\brief R_FillBackScreen
-
-	Fills the back screen with a pattern for variable screen sizes
-	Also draws a beveled edge.
-*/
-void R_FillBackScreen(void)
-{
-	UINT8 *src, *dest;
-	patch_t *patch;
-	INT32 x, y, step, boff;
-
-	// quickfix, don't cache lumps in both modes
-	if (rendermode != render_soft)
-		return;
-
-	// draw pattern around the status bar too (when hires),
-	// so return only when in full-screen without status bar.
-	if (scaledviewwidth == vid.width && viewheight == vid.height)
-		return;
-
-	src = scr_borderpatch;
-	dest = screens[1];
-
-	for (y = 0; y < vid.height; y++)
-	{
-		for (x = 0; x < vid.width/128; x++)
-		{
-			M_Memcpy (dest, src+((y&127)<<7), 128);
-			dest += 128;
-		}
-
-		if (vid.width&127)
-		{
-			M_Memcpy(dest, src+((y&127)<<7), vid.width&127);
-			dest += (vid.width&127);
-		}
-	}
-
-	// don't draw the borders when viewwidth is full vid.width.
-	if (scaledviewwidth == vid.width)
-		return;
-
-	step = 8;
-	boff = 8;
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_T], PU_CACHE);
-	for (x = 0; x < scaledviewwidth; x += step)
-		V_DrawPatch(viewwindowx + x, viewwindowy - boff, 1, patch);
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_B], PU_CACHE);
-	for (x = 0; x < scaledviewwidth; x += step)
-		V_DrawPatch(viewwindowx + x, viewwindowy + viewheight, 1, patch);
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_L], PU_CACHE);
-	for (y = 0; y < viewheight; y += step)
-		V_DrawPatch(viewwindowx - boff, viewwindowy + y, 1, patch);
-
-	patch = W_CacheLumpNum(viewborderlump[BRDR_R],PU_CACHE);
-	for (y = 0; y < viewheight; y += step)
-		V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + y, 1,
-			patch);
-
-	// Draw beveled corners.
-	V_DrawPatch(viewwindowx - boff, viewwindowy - boff, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_TL], PU_CACHE));
-	V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy - boff, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_TR], PU_CACHE));
-	V_DrawPatch(viewwindowx - boff, viewwindowy + viewheight, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_BL], PU_CACHE));
-	V_DrawPatch(viewwindowx + scaledviewwidth, viewwindowy + viewheight, 1,
-		W_CacheLumpNum(viewborderlump[BRDR_BR], PU_CACHE));
-}
-#endif
-
 /**	\brief	The R_VideoErase function
 
 	Copy a screen buffer.
@@ -837,55 +743,6 @@ void R_VideoErase(size_t ofs, INT32 count)
 	M_Memcpy(screens[0] + ofs, screens[1] + ofs, count);
 }
 
-#if 0
-/**	\brief The R_DrawViewBorder
-
-  Draws the border around the view
-	for different size windows?
-*/
-void R_DrawViewBorder(void)
-{
-	INT32 top, side, ofs;
-
-	if (rendermode == render_none)
-		return;
-#ifdef HWRENDER
-	if (rendermode != render_soft)
-	{
-		HWR_DrawViewBorder(0);
-		return;
-	}
-	else
-#endif
-
-#ifdef DEBUG
-	fprintf(stderr,"RDVB: vidwidth %d vidheight %d scaledviewwidth %d viewheight %d\n",
-		vid.width, vid.height, scaledviewwidth, viewheight);
-#endif
-
-	if (scaledviewwidth == vid.width)
-		return;
-
-	top = (vid.height - viewheight)>>1;
-	side = (vid.width - scaledviewwidth)>>1;
-
-	// copy top and one line of left side
-	R_VideoErase(0, top*vid.width+side);
-
-	// copy one line of right side and bottom
-	ofs = (viewheight+top)*vid.width - side;
-	R_VideoErase(ofs, top*vid.width + side);
-
-	// copy sides using wraparound
-	ofs = top*vid.width + vid.width-side;
-	side <<= 1;
-
-    // simpler using our VID_Blit routine
-	VID_BlitLinearScreen(screens[1] + ofs, screens[0] + ofs, side, viewheight - 1,
-		vid.width, vid.width);
-}
-#endif
-
 // R_CalcTiltedLighting
 // Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly.
 static INT32 tiltlighting[MAXVIDWIDTH];
diff --git a/src/r_draw.h b/src/r_draw.h
index ea03a8e3d53e059570822a0119ee6431f45d105a..09fd2fff2e52f60935fd86294318fffbc69c892d 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -81,25 +81,6 @@ extern UINT32 nflatyshift;
 extern UINT32 nflatshiftup;
 extern UINT32 nflatmask;
 
-/// \brief Top border
-#define BRDR_T 0
-/// \brief Bottom border
-#define BRDR_B 1
-/// \brief Left border
-#define BRDR_L 2
-/// \brief Right border
-#define BRDR_R 3
-/// \brief Topleft border
-#define BRDR_TL 4
-/// \brief Topright border
-#define BRDR_TR 5
-/// \brief Bottomleft border
-#define BRDR_BL 6
-/// \brief Bottomright border
-#define BRDR_BR 7
-
-extern lumpnum_t viewborderlump[8];
-
 // ------------------------------------------------
 // r_draw.c COMMON ROUTINES FOR BOTH 8bpp and 16bpp
 // ------------------------------------------------
@@ -150,17 +131,8 @@ boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel);
 extern UINT8 skincolor_modified[];
 
 void R_InitViewBuffer(INT32 width, INT32 height);
-void R_InitViewBorder(void);
 void R_VideoErase(size_t ofs, INT32 count);
 
-// Rendering function.
-#if 0
-void R_FillBackScreen(void);
-
-// If the view size is not full screen, draws a border around it.
-void R_DrawViewBorder(void);
-#endif
-
 #define TRANSPARENTPIXEL 255
 
 // -----------------
diff --git a/src/r_main.c b/src/r_main.c
index 55bb9c4ffefdfee11f38ec50a28cff7de2748ffb..39231981c566d31ea282362687efbafe3302840e 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1016,8 +1016,6 @@ void R_Init(void)
 	//I_OutputMsg("\nR_InitData");
 	R_InitData();
 
-	//I_OutputMsg("\nR_InitViewBorder");
-	R_InitViewBorder();
 	R_SetViewSize(); // setsizeneeded is set true
 
 	//I_OutputMsg("\nR_InitPlanes");
diff --git a/src/screen.c b/src/screen.c
index fe5b399958e7082bd872478a53a4ef2b3da37df1..1017706eb37889f6dc8181af783b174a95dd7399 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -62,8 +62,29 @@ void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
 // global video state
 // ------------------
 viddef_t vid;
-INT32 setmodeneeded; //video mode change needed if > 0 (the mode number to set + 1)
-UINT8 setrenderneeded = 0;
+
+// windowed video modes from which to choose from.
+INT32 windowedModes[MAXWINMODES][2] =
+{
+	{1920,1200}, // 1.60,6.00
+	{1920,1080}, // 1.66
+	{1680,1050}, // 1.60,5.25
+	{1600,1200}, // 1.33
+	{1600, 900}, // 1.66
+	{1366, 768}, // 1.66
+	{1440, 900}, // 1.60,4.50
+	{1280,1024}, // 1.33?
+	{1280, 960}, // 1.33,4.00
+	{1280, 800}, // 1.60,4.00
+	{1280, 720}, // 1.66
+	{1152, 864}, // 1.33,3.60
+	{1024, 768}, // 1.33,3.20
+	{ 800, 600}, // 1.33,2.50
+	{ 640, 480}, // 1.33,2.00
+	{ 640, 400}, // 1.60,2.00
+	{ 320, 240}, // 1.33,1.00
+	{ 320, 200}, // 1.60,1.00
+};
 
 static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}};
 
@@ -95,13 +116,9 @@ consvar_t cv_fullscreen = CVAR_INIT ("fullscreen", "Yes", CV_SAVE|CV_CALL, CV_Ye
 // =========================================================================
 
 INT32 scr_bpp; // current video mode bytes per pixel
-UINT8 *scr_borderpatch; // flat used to fill the reduced view borders set at ST_Init()
 
 // =========================================================================
 
-//  Short and Tall sky drawer, for the current color mode
-void (*walldrawerfunc)(void);
-
 boolean R_ASM = true;
 boolean R_486 = false;
 boolean R_586 = false;
@@ -215,35 +232,26 @@ void SCR_SetMode(void)
 	if (dedicated)
 		return;
 
-	if (!(setmodeneeded || setrenderneeded) || WipeInAction)
+	if (!vid.change.set || WipeInAction)
 		return; // should never happen and don't change it during a wipe, BAD!
 
-	// Lactozilla: Renderer switching
-	if (setrenderneeded)
+	if (vid.change.renderer != -1)
 	{
-		// stop recording movies (APNG only)
-		if (setrenderneeded && (moviemode == MM_APNG))
+		if (moviemode == MM_APNG)
 			M_StopMovie();
-
-		// VID_SetMode will call VID_CheckRenderer itself,
-		// so no need to do this in here.
-		if (!setmodeneeded)
-			VID_CheckRenderer();
-
-		vid.recalc = 1;
 	}
 
-	// Set the video mode in the video interface.
-	if (setmodeneeded)
-		VID_SetMode(setmodeneeded - 1);
+	if (vid.change.set)
+		VID_SetSize(vid.change.width, vid.change.height);
 
 	V_SetPalette(0);
 
 	SCR_SetDrawFuncs();
 
-	// set the apprpriate drawer for the sky (tall or INT16)
-	setmodeneeded = 0;
-	setrenderneeded = 0;
+	vid.change.set = VID_RESOLUTION_UNCHANGED;
+	vid.change.width = -1;
+	vid.change.height = -1;
+	vid.change.renderer = -1;
 }
 
 // do some initial settings for the game loading screen
@@ -350,11 +358,41 @@ void SCR_Recalc(void)
 #endif
 }
 
+boolean SCR_IsValidResolution(INT32 width, INT32 height)
+{
+	if (width < BASEVIDWIDTH || width > MAXVIDWIDTH)
+		return false;
+	if (height < BASEVIDHEIGHT || height > MAXVIDHEIGHT)
+		return false;
+	return true;
+}
+
+void SCR_ChangeResolution(INT32 width, INT32 height)
+{
+	if (SCR_IsValidResolution(width, height))
+	{
+		vid.change.width = width;
+		vid.change.height = height;
+		vid.change.renderer = -1;
+		vid.change.set = VID_RESOLUTION_CHANGED;
+	}
+}
+
+void SCR_SetWindowSize(INT32 width, INT32 height)
+{
+	if (SCR_IsValidResolution(width, height))
+	{
+		vid.change.width = width;
+		vid.change.height = height;
+		vid.change.renderer = -1;
+		vid.change.set = VID_RESOLUTION_RESIZED_WINDOW;
+	}
+}
+
 // Check for screen cmd-line parms: to force a resolution.
 //
-// Set the video mode to set at the 1st display loop (setmodeneeded)
+// Set the video mode to set at the 1st display loop
 //
-
 void SCR_CheckDefaultMode(void)
 {
 	INT32 scr_forcex, scr_forcey; // resolution asked from the cmd-line
@@ -374,21 +412,35 @@ void SCR_CheckDefaultMode(void)
 	if (scr_forcex && scr_forcey)
 	{
 		CONS_Printf(M_GetText("Using resolution: %d x %d\n"), scr_forcex, scr_forcey);
-		// returns -1 if not found, thus will be 0 (no mode change) if not found
-		setmodeneeded = VID_GetModeForSize(scr_forcex, scr_forcey) + 1;
+		SCR_ChangeResolution(scr_forcex, scr_forcey);
 	}
 	else
 	{
 		CONS_Printf(M_GetText("Default resolution: %d x %d\n"), cv_scr_width.value, cv_scr_height.value);
 		CONS_Printf(M_GetText("Windowed resolution: %d x %d\n"), cv_scr_width_w.value, cv_scr_height_w.value);
 		CONS_Printf(M_GetText("Default bit depth: %d bits\n"), cv_scr_depth.value);
+
+		INT32 width, height;
+
 		if (cv_fullscreen.value)
-			setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; // see note above
+		{
+			width = cv_scr_width.value;
+			height = cv_scr_height.value;
+		}
 		else
-			setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value) + 1; // see note above
+		{
+			width = cv_scr_width_w.value;
+			height = cv_scr_height_w.value;
+		}
 
-		if (setmodeneeded <= 0)
+		if (!SCR_IsValidResolution(width, height))
+		{
 			CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution\n");
+			width = BASEVIDWIDTH;
+			height = BASEVIDHEIGHT;
+		}
+
+		SCR_ChangeResolution(width, height);
 	}
 
 	if (cv_renderer.value != (signed)rendermode)
@@ -422,31 +474,40 @@ void SCR_ChangeFullscreen(void)
 	if (graphics_started)
 	{
 		VID_PrepareModeList();
+
+		INT32 width, height;
+
 		if (cv_fullscreen.value)
-			setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1;
+		{
+			width = cv_scr_width.value;
+			height = cv_scr_height.value;
+		}
 		else
-			setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value) + 1;
+		{
+			width = cv_scr_width_w.value;
+			height = cv_scr_height_w.value;
+		}
 
-		if (setmodeneeded <= 0) // hacky safeguard
+		if (!SCR_IsValidResolution(width, height))
 		{
-			CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution.\n");
-			setmodeneeded = VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT) + 1;
+			CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution\n");
+			width = BASEVIDWIDTH;
+			height = BASEVIDHEIGHT;
 		}
+
+		SCR_ChangeResolution(width, height);
 	}
-	return;
 #endif
 }
 
 void SCR_ChangeRenderer(void)
 {
-	if (chosenrendermode != render_none
-	|| (signed)rendermode == cv_renderer.value)
+	if (chosenrendermode != render_none || (signed)rendermode == cv_renderer.value)
 		return;
 
 #ifdef HWRENDER
 	// Check if OpenGL loaded successfully (or wasn't disabled) before switching to it.
-	if ((vid.glstate == VID_GL_LIBRARY_ERROR)
-	&& (cv_renderer.value == render_opengl))
+	if (vid.glstate == VID_GL_LIBRARY_ERROR && cv_renderer.value == render_opengl)
 	{
 		if (M_CheckParm("-nogl"))
 			CONS_Alert(CONS_ERROR, "OpenGL rendering was disabled!\n");
@@ -457,11 +518,11 @@ void SCR_ChangeRenderer(void)
 
 	if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) // Clear these out before switching to software
 		HWR_ClearAllTextures();
-
 #endif
 
 	// Set the new render mode
-	setrenderneeded = cv_renderer.value;
+	vid.change.renderer = cv_renderer.value;
+	vid.change.set = VID_RESOLUTION_CHANGED;
 }
 
 boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
diff --git a/src/screen.h b/src/screen.h
index 65e82ff4df2bff3701a0f57d4667ee32a34784f5..6205356857ac3a6d852babd62387e74c284c6848 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -53,20 +53,20 @@ typedef struct viddef_s
 	size_t rowbytes; // bytes per scanline of the VIDEO mode
 	INT32 width; // PIXELS per scanline
 	INT32 height;
-	union { // don't need numpages for OpenGL, so we can use it for fullscreen/windowed mode
-		INT32 numpages; // always 1, page flipping todo
-		INT32 windowed; // windowed or fullscren mode?
-	} u;
 	INT32 recalc; // if true, recalc vid-based stuff
 	UINT8 *direct; // linear frame buffer, or vga base mem.
 	INT32 dupx, dupy; // scale 1, 2, 3 value for menus & overlays
-	INT32/*fixed_t*/ fdupx, fdupy; // same as dupx, dupy, but exact value when aspect ratio isn't 320/200
+	INT32 fdupx, fdupy; // same as dupx, dupy, but exact value when aspect ratio isn't 320/200
 	INT32 bpp; // BYTES per pixel: 1 = 256color, 2 = highcolor
 
-	INT32 baseratio; // Used to get the correct value for lighting walls
+	struct {
+		INT32 width;
+		INT32 height;
+		INT32 renderer;
+		UINT8 set;
+	} change;
 
 	// for Win32 version
-	DNWH WndParent; // handle of the application's window
 	UINT8 smalldupx, smalldupy; // factor for a little bit of scaling
 	UINT8 meddupx, meddupy; // factor for moderate, but not full, scaling
 #ifdef HWRENDER
@@ -76,41 +76,23 @@ typedef struct viddef_s
 #endif
 } viddef_t;
 
+enum
+{
+	VID_RESOLUTION_UNCHANGED = 0,
+	VID_RESOLUTION_CHANGED = 1,
+	VID_RESOLUTION_RESIZED_WINDOW = 2
+};
+
 enum
 {
 	VID_GL_LIBRARY_NOTLOADED  = 0,
 	VID_GL_LIBRARY_LOADED     = 1,
-	VID_GL_LIBRARY_ERROR      = -1,
+	VID_GL_LIBRARY_ERROR      = -1
 };
 
-// internal additional info for vesa modes only
-typedef struct
-{
-	INT32 vesamode; // vesa mode number plus LINEAR_MODE bit
-	void *plinearmem; // linear address of start of frame buffer
-} vesa_extra_t;
-// a video modes from the video modes list,
-// note: video mode 0 is always standard VGA320x200.
-typedef struct vmode_s
-{
-	struct vmode_s *pnext;
-	char *name;
-	UINT32 width, height;
-	UINT32 rowbytes; // bytes per scanline
-	UINT32 bytesperpixel; // 1 for 256c, 2 for highcolor
-	INT32 windowed; // if true this is a windowed mode
-	INT32 numpages;
-	vesa_extra_t *pextradata; // vesa mode extra data
-#ifdef _WIN32
-	INT32 (WINAPI *setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode);
-#else
-	INT32 (*setmode)(viddef_t *lvid, struct vmode_s *pcurrentmode);
-#endif
-	INT32 misc; // misc for display driver (r_opengl.dll etc)
-} vmode_t;
+#define MAXWINMODES 18
 
-#define NUMSPECIALMODES  4
-extern vmode_t specialmodes[NUMSPECIALMODES];
+extern INT32 windowedModes[MAXWINMODES][2];
 
 // ---------------------------------------------
 // color mode dependent drawer function pointers
@@ -187,17 +169,18 @@ extern boolean R_SSE2;
 // screen variables
 // ----------------
 extern viddef_t vid;
-extern INT32 setmodeneeded; // mode number to set if needed, or 0
-extern UINT8 setrenderneeded;
 
 extern double averageFPS;
 
+void SCR_ChangeResolution(INT32 width, INT32 height);
+void SCR_SetWindowSize(INT32 width, INT32 height);
 void SCR_ChangeRenderer(void);
 
+boolean SCR_IsValidResolution(INT32 width, INT32 height);
+
 extern CV_PossibleValue_t cv_renderer_t[];
 
 extern INT32 scr_bpp;
-extern UINT8 *scr_borderpatch; // patch used to fill the view borders
 
 extern consvar_t cv_scr_width, cv_scr_height, cv_scr_width_w, cv_scr_height_w, cv_scr_depth, cv_fullscreen;
 extern consvar_t cv_renderview, cv_renderer;
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index a90700fa99c4bd8d5b382facfc2df11945bd3eef..846b4c742d3f66217c0668bf013b50835763b727 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -87,9 +87,6 @@
 #include "ogl_sdl.h"
 #endif
 
-// maximum number of windowed modes (see windowedModes[][])
-#define MAXWINMODES (18)
-
 rendermode_t rendermode = render_soft;
 rendermode_t chosenrendermode = render_none; // set by command line arguments
 
@@ -162,29 +159,6 @@ static void Impl_SetWindowIcon(void);
 static SDL_Surface *icoSurface = NULL;
 #endif
 
-// windowed video modes from which to choose from.
-static INT32 windowedModes[MAXWINMODES][2] =
-{
-	{1920,1200}, // 1.60,6.00
-	{1920,1080}, // 1.66
-	{1680,1050}, // 1.60,5.25
-	{1600,1200}, // 1.33
-	{1600, 900}, // 1.66
-	{1366, 768}, // 1.66
-	{1440, 900}, // 1.60,4.50
-	{1280,1024}, // 1.33?
-	{1280, 960}, // 1.33,4.00
-	{1280, 800}, // 1.60,4.00
-	{1280, 720}, // 1.66
-	{1152, 864}, // 1.33,3.60
-	{1024, 768}, // 1.33,3.20
-	{ 800, 600}, // 1.33,2.50
-	{ 640, 480}, // 1.33,2.00
-	{ 640, 400}, // 1.60,2.00
-	{ 320, 240}, // 1.33,1.00
-	{ 320, 200}, // 1.60,1.00
-};
-
 static char vidModeName[MAXWINMODES][32];
 static const char *fallback_resolution_name = "Fallback";
 
@@ -644,7 +618,14 @@ static void VID_Command_Mode_f (void)
 		CONS_Printf(M_GetText("Video mode not present\n"));
 	else
 	{
-		setmodeneeded = modenum + 1; // request vid mode change
+		if (modenum < 0)
+			modenum = 0;
+		if (modenum >= MAXWINMODES)
+			modenum = MAXWINMODES-1;
+
+		vid.change.width = windowedModes[modenum][0];
+		vid.change.height = windowedModes[modenum][1];
+		vid.change.set = VID_RESOLUTION_CHANGED;
 	}
 }
 
@@ -690,6 +671,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
 		case SDL_WINDOWEVENT_MAXIMIZED:
 			break;
 		case SDL_WINDOWEVENT_SIZE_CHANGED:
+			SCR_SetWindowSize(evt.data1, evt.data2);
 			break;
 	}
 
@@ -1386,10 +1368,10 @@ void VID_CheckGLLoaded(rendermode_t oldrender)
 		rendermode = oldrender;
 		if (chosenrendermode == render_opengl) // fallback to software
 			rendermode = render_soft;
-		if (setrenderneeded)
+		if (vid.change.renderer != -1)
 		{
 			CV_StealthSetValue(&cv_renderer, oldrender);
-			setrenderneeded = 0;
+			vid.change.renderer = 0;
 		}
 	}
 #endif
@@ -1408,9 +1390,9 @@ boolean VID_CheckRenderer(void)
 	if (dedicated)
 		return 0;
 
-	if (setrenderneeded)
+	if (vid.change.renderer != -1)
 	{
-		rendermode = setrenderneeded;
+		rendermode = vid.change.renderer;
 		rendererchanged = true;
 
 #ifdef HWRENDER
@@ -1426,12 +1408,10 @@ boolean VID_CheckRenderer(void)
 		}
 #endif
 
-		setrenderneeded = 0;
+		vid.change.renderer = -1;
 	}
 
-	SDL_bool center = setmodeneeded ? SDL_TRUE : SDL_FALSE;
-
-	if (SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, center) == SDL_FALSE)
+	if (SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, vid.change.set != VID_RESOLUTION_RESIZED_WINDOW) == SDL_FALSE)
 	{
 		if (!graphics_started)
 		{
@@ -1497,30 +1477,24 @@ void VID_GetNativeResolution(INT32 *width, INT32 *height)
 }
 #endif
 
-INT32 VID_SetMode(INT32 modeNum)
+void VID_SetSize(INT32 width, INT32 height)
 {
 	SDLdoUngrabMouse();
 
 	vid.recalc = true;
-	vid.bpp = 1;
-
-	if (modeNum < 0)
-		modeNum = 0;
-	if (modeNum >= MAXWINMODES)
-		modeNum = MAXWINMODES-1;
 
-	vid.width = windowedModes[modeNum][0];
-	vid.height = windowedModes[modeNum][1];
-	vid.modenum = modeNum;
+	if (width > 0 && height > 0 && SCR_IsValidResolution(width, height))
+	{
+		vid.width = width;
+		vid.height = height;
+	}
 
 	VID_CheckRenderer();
-
-	return SDL_TRUE;
 }
 
 static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 {
-	int flags = 0;
+	int flags = SDL_WINDOW_RESIZABLE;
 
 	if (window != NULL)
 		return SDL_TRUE;
@@ -1552,6 +1526,8 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 		return SDL_FALSE;
 	}
 
+	SDL_SetWindowMinimumSize(window, BASEVIDWIDTH, BASEVIDHEIGHT);
+
 #ifdef USE_WINDOW_ICON
 	Impl_SetWindowIcon();
 #endif
@@ -1750,14 +1726,9 @@ void I_StartupGraphics(void)
 	vid.recalc = true;
 	vid.direct = NULL;
 	vid.bpp = 1;
-	vid.WndParent = NULL;
 
 	// Create window
-	// Default size for startup
-	vid.width = BASEVIDWIDTH;
-	vid.height = BASEVIDHEIGHT;
-
-	VID_SetMode(VID_GetModeForSize(vid.width, vid.height));
+	VID_SetSize(BASEVIDWIDTH, BASEVIDHEIGHT);
 
 #ifdef HAVE_TTF
 	I_ShutdownTTF();
@@ -1827,10 +1798,10 @@ static void Impl_InitOpenGL(void)
 		vid.glstate = VID_GL_LIBRARY_ERROR;
 
 		CV_StealthSet(&cv_renderer, "Software");
+
 		rendermode = render_soft;
 
-		if (setrenderneeded)
-			setrenderneeded = 0;
+		vid.change.renderer = -1;
 	}
 #endif
 }
diff --git a/src/st_stuff.c b/src/st_stuff.c
index c6e6befc62ee046e2a0ab7b333d33db1d5a7a494..0018f620628dfbd5234efe4f7e46e96e3771dd3f 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -254,10 +254,6 @@ void ST_LoadGraphics(void)
 {
 	int i;
 
-	// SRB2 border patch
-	// st_borderpatchnum = W_GetNumForName("GFZFLR01");
-	// scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX);
-
 	// the original Doom uses 'STF' as base name for all face graphics
 	// Graue 04-08-2004: face/name graphics are now indexed by skins
 	//                   but load them in R_AddSkins, that gets called
@@ -425,12 +421,8 @@ void ST_Start(void)
 }
 
 //
-// Initializes the status bar, sets the defaults border patch for the window borders.
+// Initializes the status bar
 //
-
-// used by OpenGL mode, holds lumpnum of flat used to fill space around the viewwindow
-lumpnum_t st_borderpatchnum;
-
 void ST_Init(void)
 {
 	INT32 i;
diff --git a/src/st_stuff.h b/src/st_stuff.h
index 603be3c309c761b31fa269f2b0fbad795a489676..1bf7c5f228a9b60bf0965e991da15e66da24ee5d 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -69,7 +69,6 @@ extern boolean st_overlay; // sb overlay on or off when fullscreen
 extern INT32 st_palette; // 0 is default, any others are special palettes.
 extern INT32 st_translucency;
 
-extern lumpnum_t st_borderpatchnum;
 // patches, also used in intermission
 extern patch_t *tallnum[10];
 extern patch_t *sboscore;