Browse Source

Merge pull request #316 from Areloch/UpdatedWindowsSettingsOptions

Updated version of OTHGMars' updated window and resolution options modes.
Brian Roberts 4 years ago
parent
commit
add299e1b8

+ 14 - 0
Engine/source/gui/controls/guiGameListMenuCtrl.cpp

@@ -533,6 +533,14 @@ void GuiGameListMenuCtrl::addRow(const char* label, const char* bitmapName, cons
    addRow(row, label, callback, icon, yPad, true, enabled, Row::Mode::Keybind, tooltip);
    addRow(row, label, callback, icon, yPad, true, enabled, Row::Mode::Keybind, tooltip);
 }
 }
 
 
+void GuiGameListMenuCtrl::removeRow(const S32& row)
+{
+   if (row == -1 || row >= mRows.size())
+      return;
+
+   mRows.erase(row);
+}
+
 Point2I  GuiGameListMenuCtrl::getMinExtent() const
 Point2I  GuiGameListMenuCtrl::getMinExtent() const
 {
 {
    Point2I parentMin = Parent::getMinExtent();
    Point2I parentMin = Parent::getMinExtent();
@@ -1521,6 +1529,12 @@ DefineEngineMethod(GuiGameListMenuCtrl, addKeybindRow, void,
    object->addRow(label, bitmapName, callback, icon, yPad, enabled, tooltip);
    object->addRow(label, bitmapName, callback, icon, yPad, enabled, tooltip);
 }
 }
 
 
+DefineEngineMethod(GuiGameListMenuCtrl, removeRow, void, (S32 row),,
+   "Removes the row at the provided index")
+{
+   object->removeRow(row);
+}
+
 DefineEngineMethod(GuiGameListMenuCtrl, getCurrentOption, const char*, (S32 row), ,
 DefineEngineMethod(GuiGameListMenuCtrl, getCurrentOption, const char*, (S32 row), ,
    "Gets the text for the currently selected option of the given row.\n\n"
    "Gets the text for the currently selected option of the given row.\n\n"
    "@param row Index of the row to get the option from.\n"
    "@param row Index of the row to get the option from.\n"

+ 3 - 0
Engine/source/gui/controls/guiGameListMenuCtrl.h

@@ -163,6 +163,9 @@ public:
 
 
    void addRow(const char* label, const char* bitmapName, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip);
    void addRow(const char* label, const char* bitmapName, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip);
 
 
+   //Removes row at the provided index
+   void GuiGameListMenuCtrl::removeRow(const S32& row);
+
    /// Gets the text for the currently selected option of the given row.
    /// Gets the text for the currently selected option of the given row.
    ///
    ///
    /// \param rowIndex Index of the row to get the option from.
    /// \param rowIndex Index of the row to get the option from.

+ 35 - 2
Engine/source/gui/core/guiCanvas.cpp

@@ -238,7 +238,8 @@ bool GuiCanvas::onAdd()
          mPlatformWindow->lockSize(true);
          mPlatformWindow->lockSize(true);
       
       
       // Set a minimum on the window size so people can't break us by resizing tiny.
       // Set a minimum on the window size so people can't break us by resizing tiny.
-      mPlatformWindow->setMinimumWindowSize(Point2I(640,480));
+      mPlatformWindow->setMinimumWindowSize(Point2I(Con::getIntVariable("$Video::minimumXResolution", 1024),
+         Con::getIntVariable("$Video::minimumYResolution", 720)));
 
 
       // Now, we have to hook in our event callbacks so we'll get
       // Now, we have to hook in our event callbacks so we'll get
       // appropriate events from the window.
       // appropriate events from the window.
@@ -2462,6 +2463,35 @@ DefineEngineMethod( GuiCanvas, getMonitorRect, RectI, (S32 index),,
    return PlatformWindowManager::get()->getMonitorRect(index);
    return PlatformWindowManager::get()->getMonitorRect(index);
 }
 }
 
 
+DefineEngineMethod( GuiCanvas, getMonitorUsableRect, RectI, (S32 index),,
+               "@brief Use this function to get the usable desktop area represented by a display, with the primary display located at 0,0.\n\n"
+               "This is the same area as Canvas.getMonitorRect() reports, but with portions reserved by the system removed. "
+               "For example, on Apple Mac OS X, this subtracts the area occupied by the menu bar and dock.\n"
+               "Setting a window to be fullscreen generally bypasses these unusable areas, so these are good guidelines for "
+               "the maximum space available to a non - fullscreen window."
+               "@param index The monitor index.\n\n"
+               "@return The rectangular region of the requested monitor.")
+{
+   return PlatformWindowManager::get()->getMonitorUsableRect(index);
+}
+
+DefineEngineMethod(GuiCanvas, getMonitorModeCount, S32, (S32 monitorIndex), (0),
+   "Gets the number of video modes available on the selected monitor.\n\n")
+{
+   return PlatformWindowManager::get()->getMonitorModeCount(monitorIndex);
+}
+DefineEngineMethod(GuiCanvas, getMonitorMode, const char*, (S32 monitorIndex, S32 modeIndex), (0),
+   "Gets a video mode string from the selected monitor.\n\n")
+{
+   char* buf = Con::getReturnBuffer(PlatformWindowManager::get()->getMonitorMode(monitorIndex, modeIndex));
+   return buf;
+}
+DefineEngineMethod(GuiCanvas, getMonitorDesktopMode, const char*, (S32 monitorIndex), (0),
+   "Gets the current desktop mode for the selected monitor.\n\n")
+{
+   char* buf = Con::getReturnBuffer(PlatformWindowManager::get()->getMonitorDesktopMode(monitorIndex));
+   return buf;
+}
 
 
 DefineEngineMethod( GuiCanvas, getVideoMode, const char*, (),,
 DefineEngineMethod( GuiCanvas, getVideoMode, const char*, (),,
                "@brief Gets the current screen mode as a string.\n\n"
                "@brief Gets the current screen mode as a string.\n\n"
@@ -2698,8 +2728,11 @@ DefineEngineMethod( GuiCanvas, restoreWindow, void, (), , "() - restore this can
 DefineEngineMethod( GuiCanvas, setFocus, void, (), , "() - Claim OS input focus for this canvas' window.")
 DefineEngineMethod( GuiCanvas, setFocus, void, (), , "() - Claim OS input focus for this canvas' window.")
 {
 {
    PlatformWindow* window = object->getPlatformWindow();
    PlatformWindow* window = object->getPlatformWindow();
-   if( window )
+   if (window)
+   {
       window->setFocus();
       window->setFocus();
+      window->appEvent.trigger(window->getWindowId(), GainFocus);
+   }
 }
 }
 
 
 DefineEngineMethod( GuiCanvas, setMenuBar, void, ( GuiControl* menu ),,
 DefineEngineMethod( GuiCanvas, setMenuBar, void, ( GuiControl* menu ),,

+ 18 - 1
Engine/source/windowManager/platformWindowMgr.h

@@ -90,6 +90,23 @@ public:
    // Get the requested monitor's rectangular region.
    // Get the requested monitor's rectangular region.
    virtual RectI getMonitorRect(U32 index) { return RectI(0, 0, 0, 0); }
    virtual RectI getMonitorRect(U32 index) { return RectI(0, 0, 0, 0); }
 
 
+   // Get the requested monitor's rectangular region.
+   // Use this function to get the usable desktop area represented by a display,
+   // with the primary display located at 0,0. 
+   virtual RectI getMonitorUsableRect(U32 index) { return RectI(0, 0, 0, 0); }
+
+   // Retrieve the number of display modes available on a monitor.  Provides a default
+   // count of 0 for systems that don't provide information on connected monitors.
+   virtual U32 getMonitorModeCount(U32 monitorIndex) { return 0; }
+
+   // Gets a display mode for a specific monitor.  Provides a default of "" for platorms
+   // that do not provide information on connected monitors.
+   virtual const String getMonitorMode(U32 monitorIndex, U32 modeIndex) { return String::EmptyString; }
+
+   // Gets the current desktop display mode for a specific monitor.  Provides a default
+   // of "" for platorms that do not provide information on connected monitors.
+   virtual const String getMonitorDesktopMode(U32 monitorIndex) { return String::EmptyString; }
+
    /// Populate a vector with all monitors and their extents in window space.
    /// Populate a vector with all monitors and their extents in window space.
    virtual void getMonitorRegions(Vector<RectI> &regions) = 0;
    virtual void getMonitorRegions(Vector<RectI> &regions) = 0;
 
 
@@ -152,4 +169,4 @@ private:
 /// need to get the window manager from somewhere else.
 /// need to get the window manager from somewhere else.
 PlatformWindowManager *CreatePlatformWindowManager();
 PlatformWindowManager *CreatePlatformWindowManager();
 
 
-#endif
+#endif

+ 59 - 10
Engine/source/windowManager/sdl/sdlWindow.cpp

@@ -161,10 +161,18 @@ void PlatformWindowSDL::_setVideoMode( const GFXVideoMode &mode )
 {
 {
    mVideoMode = mode;
    mVideoMode = mode;
    mSuppressReset = true;
    mSuppressReset = true;
+   S32 newDisplay = Con::getIntVariable("pref::Video::deviceId", 0);
 
 
    // Set our window to have the right style based on the mode
    // Set our window to have the right style based on the mode
    if(mode.fullScreen && !Platform::getWebDeployment() && !mOffscreenRender)
    if(mode.fullScreen && !Platform::getWebDeployment() && !mOffscreenRender)
-   {     
+   {
+      SDL_Rect rect_sdl;
+      // Move the window onto the correct monitor before setting fullscreen
+      if (0 == SDL_GetDisplayBounds(newDisplay, &rect_sdl))
+      {
+         SDL_SetWindowPosition(mWindowHandle, rect_sdl.x, rect_sdl.y);
+      }
+
       setSize(mode.resolution);
       setSize(mode.resolution);
 
 
       SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
       SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
@@ -187,10 +195,19 @@ void PlatformWindowSDL::_setVideoMode( const GFXVideoMode &mode )
          SDL_SetWindowFullscreen( mWindowHandle, 0);
          SDL_SetWindowFullscreen( mWindowHandle, 0);
       }
       }
 
 
+      // Restore the window to it's original size/position before applying changes
+      SDL_RestoreWindow(mWindowHandle);
+
+      // pref::Video::deviceMode values 0-windowed, 1-borderless, 2-fullscreen
+      bool hasBorder = (0 == Con::getIntVariable("pref::Video::deviceMode", 0));
+      SDL_SetWindowBordered(mWindowHandle, hasBorder ? SDL_TRUE : SDL_FALSE);
       setSize(mode.resolution);
       setSize(mode.resolution);
-      centerWindow();
+      SDL_SetWindowPosition(mWindowHandle, SDL_WINDOWPOS_CENTERED_DISPLAY(newDisplay), SDL_WINDOWPOS_CENTERED_DISPLAY(newDisplay));
+      if (hasBorder && Con::getBoolVariable("pref::Video::isMaximized", false))
+         SDL_MaximizeWindow(mWindowHandle);
    }
    }
 
 
+   getScreenResChangeSignal().trigger(this, true);
    mSuppressReset = false;
    mSuppressReset = false;
 }
 }
 
 
@@ -216,7 +233,7 @@ void PlatformWindowSDL::_setFullscreen(const bool fullscreen)
    if(fullscreen && !mOffscreenRender)
    if(fullscreen && !mOffscreenRender)
    {
    {
       Con::printf("PlatformWindowSDL::setFullscreen (full) enter");
       Con::printf("PlatformWindowSDL::setFullscreen (full) enter");
-      SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN_DESKTOP);
+      SDL_SetWindowFullscreen( mWindowHandle, SDL_WINDOW_FULLSCREEN);
    }
    }
    else
    else
    {
    {
@@ -245,7 +262,7 @@ const char * PlatformWindowSDL::getCaption()
 
 
 void PlatformWindowSDL::setFocus()
 void PlatformWindowSDL::setFocus()
 {
 {
-   SDL_SetWindowInputFocus(mWindowHandle);
+   SDL_RaiseWindow(mWindowHandle);
 }
 }
 
 
 void PlatformWindowSDL::setClientExtent( const Point2I newExtent )
 void PlatformWindowSDL::setClientExtent( const Point2I newExtent )
@@ -322,11 +339,6 @@ void PlatformWindowSDL::centerWindow()
 bool PlatformWindowSDL::setSize( const Point2I &newSize )
 bool PlatformWindowSDL::setSize( const Point2I &newSize )
 {
 {
    SDL_SetWindowSize(mWindowHandle, newSize.x, newSize.y);
    SDL_SetWindowSize(mWindowHandle, newSize.x, newSize.y);
-
-   // Let GFX get an update about the new resolution
-   if (mTarget.isValid())
-      mTarget->resetMode();
-
    return true;
    return true;
 }
 }
 
 
@@ -475,6 +487,12 @@ void PlatformWindowSDL::_triggerMouseButtonNotify(const SDL_Event& event)
       case SDL_BUTTON_MIDDLE:
       case SDL_BUTTON_MIDDLE:
          button = 2;
          button = 2;
          break;
          break;
+      case SDL_BUTTON_X1:
+         button = 3;
+         break;
+      case SDL_BUTTON_X2:
+         button = 4;
+         break;
       default:
       default:
          return;
          return;
    }
    }
@@ -547,6 +565,24 @@ void PlatformWindowSDL::_triggerTextNotify(const SDL_Event& evt)
    }
    }
 }
 }
 
 
+void PlatformWindowSDL::_updateMonitorFromMove(const SDL_Event& evt)
+{
+   SDL_Rect sdlRect;
+   S32 monitorCount = SDL_GetNumVideoDisplays();
+   for (S32 index = 0; index < monitorCount; ++index)
+   {
+      if (0 == SDL_GetDisplayBounds(index, &sdlRect))
+      {
+         if ((evt.window.data1 >= sdlRect.x) && (evt.window.data1 < (sdlRect.x + sdlRect.w)) &&
+            (evt.window.data2 >= sdlRect.y) && (evt.window.data2 < (sdlRect.y + sdlRect.h)))
+         {
+            Con::setIntVariable("pref::Video::deviceId", index);
+            return;
+         }
+      }
+   }
+}
+
 void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
 void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
 {
 {
    switch(evt.type)
    switch(evt.type)
@@ -594,7 +630,11 @@ void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
             case SDL_WINDOWEVENT_FOCUS_LOST:
             case SDL_WINDOWEVENT_FOCUS_LOST:
                appEvent.trigger(getWindowId(), LoseFocus);
                appEvent.trigger(getWindowId(), LoseFocus);
                break;
                break;
-            case SDL_WINDOWEVENT_MAXIMIZED:
+            case SDL_WINDOWEVENT_MOVED:
+            {
+               _updateMonitorFromMove(evt);
+               break;
+            }
             case SDL_WINDOWEVENT_RESIZED:
             case SDL_WINDOWEVENT_RESIZED:
             {
             {
                int width, height;
                int width, height;
@@ -602,6 +642,7 @@ void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
                mVideoMode.resolution.set(width, height);
                mVideoMode.resolution.set(width, height);
                getGFXTarget()->resetMode();
                getGFXTarget()->resetMode();
                resizeEvent.trigger(getWindowId(), width, height);
                resizeEvent.trigger(getWindowId(), width, height);
+               getScreenResChangeSignal().trigger(this, true);
                break;
                break;
             }
             }
             case SDL_WINDOWEVENT_CLOSE:
             case SDL_WINDOWEVENT_CLOSE:
@@ -609,6 +650,14 @@ void PlatformWindowSDL::_processSDLEvent(SDL_Event &evt)
                appEvent.trigger(getWindowId(), WindowClose);
                appEvent.trigger(getWindowId(), WindowClose);
                mClosing = true;
                mClosing = true;
             }
             }
+            case SDL_WINDOWEVENT_MINIMIZED:
+               break;
+            case SDL_WINDOWEVENT_MAXIMIZED:
+               Con::setBoolVariable("pref::Video::isMaximized", true);
+               break;
+            case SDL_WINDOWEVENT_RESTORED:
+               Con::setBoolVariable("pref::Video::isMaximized", false);
+               break;
 
 
             default:
             default:
                break;
                break;

+ 1 - 0
Engine/source/windowManager/sdl/sdlWindow.h

@@ -98,6 +98,7 @@ private:
    void _triggerMouseWheelNotify(const SDL_Event& event);
    void _triggerMouseWheelNotify(const SDL_Event& event);
    void _triggerKeyNotify(const SDL_Event& event);
    void _triggerKeyNotify(const SDL_Event& event);
    void _triggerTextNotify(const SDL_Event& event);
    void _triggerTextNotify(const SDL_Event& event);
+   void _updateMonitorFromMove(const SDL_Event& event);
 
 
 public:
 public:
    PlatformWindowSDL();
    PlatformWindowSDL();

+ 72 - 0
Engine/source/windowManager/sdl/sdlWindowMgr.cpp

@@ -143,6 +143,74 @@ RectI PlatformWindowManagerSDL::getMonitorRect(U32 index)
    return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
    return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
 }
 }
 
 
+RectI PlatformWindowManagerSDL::getMonitorUsableRect(U32 index)
+{
+   SDL_Rect sdlRect;
+   if (0 != SDL_GetDisplayUsableBounds(index, &sdlRect))
+   {
+      Con::errorf("SDL_GetDisplayUsableBounds() failed: %s", SDL_GetError());
+      return RectI(0, 0, 0, 0);
+   }
+
+   return RectI(sdlRect.x, sdlRect.y, sdlRect.w, sdlRect.h);
+}
+
+U32 PlatformWindowManagerSDL::getMonitorModeCount(U32 monitorIndex)
+{
+   S32 modeCount = SDL_GetNumDisplayModes(monitorIndex);
+   if (modeCount < 0)
+   {
+      Con::errorf("SDL_GetNumDisplayModes(%d) failed: %s", monitorIndex, SDL_GetError());
+      modeCount = 0;
+   }
+
+   return (U32)modeCount;
+}
+
+const String PlatformWindowManagerSDL::getMonitorMode(U32 monitorIndex, U32 modeIndex)
+{
+   SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
+   if (SDL_GetDisplayMode(monitorIndex, modeIndex, &mode) != 0)
+   {
+      Con::errorf("SDL_GetDisplayMode(%d, %d) failed: %s", monitorIndex, modeIndex, SDL_GetError());
+      return String::EmptyString;
+   }
+
+   GFXVideoMode vm;
+   vm.resolution.set(mode.w, mode.h);
+   vm.refreshRate = mode.refresh_rate;
+   vm.bitDepth = 32;
+   vm.antialiasLevel = 0;
+   vm.fullScreen = false;
+   vm.wideScreen = false;
+
+   return vm.toString();
+}
+
+const String PlatformWindowManagerSDL::getMonitorDesktopMode(U32 monitorIndex)
+{
+   SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
+   if (SDL_GetDesktopDisplayMode(monitorIndex, &mode) != 0)
+   {
+      Con::errorf("SDL_GetDesktopDisplayMode(%d) failed: %s", monitorIndex, SDL_GetError());
+      return String::EmptyString;
+   }
+
+   GFXVideoMode vm;
+   vm.resolution.set(mode.w, mode.h);
+   vm.refreshRate = mode.refresh_rate;
+
+   int bbp;
+   unsigned int r, g, b, a;
+   SDL_PixelFormatEnumToMasks(mode.format, &bbp, &r, &g, &b, &a);
+   vm.bitDepth = bbp;
+   vm.antialiasLevel = 0;
+   vm.fullScreen = false;
+   vm.wideScreen = ((mode.w / 16) * 9) == mode.h;
+
+   return vm.toString();
+}
+
 void PlatformWindowManagerSDL::getMonitorRegions(Vector<RectI> &regions)
 void PlatformWindowManagerSDL::getMonitorRegions(Vector<RectI> &regions)
 {
 {
    SDL_Rect sdlRect;
    SDL_Rect sdlRect;
@@ -251,6 +319,9 @@ PlatformWindow *PlatformWindowManagerSDL::createWindow(GFXDevice *device, const
 
 
    linkWindow(window);
    linkWindow(window);
 
 
+   SDL_SetWindowMinimumSize(window->mWindowHandle, Con::getIntVariable("$Video::minimumXResolution", 1024),
+         Con::getIntVariable("$Video::minimumYResolution", 720));
+
    return window;
    return window;
 }
 }
 
 
@@ -513,3 +584,4 @@ AFTER_MODULE_INIT(gfx)
    SDL_StopTextInput();
    SDL_StopTextInput();
 #endif
 #endif
 }
 }
+

+ 5 - 1
Engine/source/windowManager/sdl/sdlWindowMgr.h

@@ -109,6 +109,10 @@ public:
    virtual U32 getMonitorCount();
    virtual U32 getMonitorCount();
    virtual const char* getMonitorName(U32 index);
    virtual const char* getMonitorName(U32 index);
    virtual RectI getMonitorRect(U32 index);
    virtual RectI getMonitorRect(U32 index);
+   virtual RectI getMonitorUsableRect(U32 index);
+   virtual U32 getMonitorModeCount(U32 monitorIndex);
+   virtual const String getMonitorMode(U32 monitorIndex, U32 modeIndex);
+   virtual const String getMonitorDesktopMode(U32 monitorIndex);
 
 
    virtual void getMonitorRegions(Vector<RectI> &regions);
    virtual void getMonitorRegions(Vector<RectI> &regions);
    virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode);
    virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode);
@@ -133,4 +137,4 @@ public:
    void updateSDLTextInputState(KeyboardInputState state);
    void updateSDLTextInputState(KeyboardInputState state);
 };
 };
 
 
-#endif
+#endif

+ 147 - 81
Templates/BaseGame/game/core/gui/scripts/canvas.cs

@@ -54,102 +54,77 @@ $WORD::FULLSCREEN = 2;
 $WORD::BITDEPTH = 3;
 $WORD::BITDEPTH = 3;
 $WORD::REFRESH = 4;
 $WORD::REFRESH = 4;
 $WORD::AA = 5;
 $WORD::AA = 5;
+$Video::ModeTags = "Windowed\tBorderless\tFullscreen";
+$Video::ModeWindowed = 0;
+$Video::ModeBorderless = 1;
+$Video::ModeFullscreen = 2;
+$Video::minimumXResolution = 1024;
+$Video::minimumYResolution = 720;
 
 
 function configureCanvas()
 function configureCanvas()
 {
 {
    // Setup a good default if we don't have one already.
    // Setup a good default if we don't have one already.
-   if ($pref::Video::Resolution $= "")
-      $pref::Video::Resolution = "800 600";
-   if ($pref::Video::FullScreen $= "")
-      $pref::Video::FullScreen = false;
-   if ($pref::Video::BitDepth $= "")
-      $pref::Video::BitDepth = "32";
-   if ($pref::Video::RefreshRate $= "")
-      $pref::Video::RefreshRate = "60";
-   if ($pref::Video::AA $= "")
-      $pref::Video::AA = "4";
+   if (($pref::Video::deviceId $= "") || ($pref::Video::deviceId < 0) ||
+         ($pref::Video::deviceId >= Canvas.getMonitorCount()))
+      $pref::Video::deviceId = 0;  // Monitor 0
 
 
-   %resX = $pref::Video::Resolution.x;
-   %resY = $pref::Video::Resolution.y;
-   %fs = $pref::Video::FullScreen;
-   %bpp = $pref::Video::BitDepth;
-   %rate = $pref::Video::RefreshRate;
-   %aa = $pref::Video::AA;
-   
-   if($cliFullscreen !$= "") {
-      %fs = $cliFullscreen;
-      $cliFullscreen = "";
+   if (($pref::Video::deviceMode $= "") || ($pref::Video::deviceMode < 0) ||
+      ($pref::Video::deviceMode >= getFieldCount($Video::ModeTags)))
+   {
+      $pref::Video::deviceMode = $Video::ModeBorderless;
+      $pref::Video::mode = Canvas.getBestCanvasRes($pref::Video::deviceId, $pref::Video::deviceMode);
+      Canvas.modeStrToPrefs($pref::Video::mode);
    }
    }
-   
+
+   if($cliFullscreen !$= "")
+      $pref::Video::deviceMode = $cliFullscreen ? 2 : 0;
+
+   // Default to borderless at desktop resolution if there is no saved pref or
+   // command line arg
+   if (($pref::Video::Resolution $= "") || ($pref::Video::Resolution.x < $Video::minimumXResolution) ||
+      ($pref::Video::Resolution.y < $Video::minimumYResolution))
+   {
+      $pref::Video::mode = Canvas.getBestCanvasRes($pref::Video::deviceId, $pref::Video::deviceMode);
+      Canvas.modeStrToPrefs($pref::Video::mode);
+   }
+
+   if ($pref::Video::deviceMode != $Video::ModeFullscreen)
+      $pref::Video::FullScreen = false;
+   %modeStr = Canvas.prefsToModeStr();
+
    echo("--------------");
    echo("--------------");
-   echo("Attempting to set resolution to \"" @ %resX SPC %resY SPC %fs SPC %bpp SPC %rate SPC %aa @ "\"");
-   
-   %deskRes    = getDesktopResolution();      
-   %deskResX   = getWord(%deskRes, $WORD::RES_X);
-   %deskResY   = getWord(%deskRes, $WORD::RES_Y);
-   %deskResBPP = getWord(%deskRes, 2);
-   
-   // We shouldn't be getting this any more but just in case...
-   if (%bpp $= "Default")
-      %bpp = %deskResBPP;
-      
+   echo("Attempting to set resolution to \"" @ %modeStr @ "\"");
+
    // Make sure we are running at a valid resolution
    // Make sure we are running at a valid resolution
-   if (%fs $= "0" || %fs $= "false")
+   if (!Canvas.checkCanvasRes(%modeStr, $pref::Video::deviceId, $pref::Video::deviceMode, true))
    {
    {
-      // Windowed mode has to use the same bit depth as the desktop
-      %bpp = %deskResBPP;
-      
-      // Windowed mode also has to run at a smaller resolution than the desktop
-      if ((%resX >= %deskResX) || (%resY >= %deskResY))
-      {
-         warn("Warning: The requested windowed resolution is equal to or larger than the current desktop resolution. Attempting to find a better resolution");
-      
-         %resCount = Canvas.getModeCount();
-         for (%i = (%resCount - 1); %i >= 0; %i--)
-         {
-            %testRes = Canvas.getMode(%i);
-            %testResX = getWord(%testRes, $WORD::RES_X);
-            %testResY = getWord(%testRes, $WORD::RES_Y);
-            %testBPP  = getWord(%testRes, $WORD::BITDEPTH);
-
-            if (%testBPP != %bpp)
-               continue;
-            
-            if ((%testResX < %deskResX) && (%testResY < %deskResY))
-            {
-               // This will work as our new resolution
-               %resX = %testResX;
-               %resY = %testResY;
-               
-               warn("Warning: Switching to \"" @ %resX SPC %resY SPC %bpp @ "\"");
-               
-               break;
-            }
-         }
-      }
+      %modeStr = Canvas.getBestCanvasRes($pref::Video::deviceId, $pref::Video::deviceMode);
+      Canvas.modeStrToPrefs(%modeStr);
    }
    }
    
    
-   $pref::Video::Resolution = %resX SPC %resY;
-   $pref::Video::FullScreen = %fs;
-   $pref::Video::BitDepth = %bpp;
-   $pref::Video::RefreshRate = %rate;
-   $pref::Video::AA = %aa;
-   
-   if (%fs == 1 || %fs $= "true")
-      %fsLabel = "Yes";
-   else
-      %fsLabel = "No";
+   %fsLabel = getField($Video::ModeTags, $pref::Video::deviceMode);
+   %resX = $pref::Video::Resolution.x;
+   %resY = $pref::Video::Resolution.y;
+   %bpp  = $pref::Video::BitDepth;
+   %rate = $pref::Video::RefreshRate;
+   %fsaa = $pref::Video::AA;
+   %fs = ($pref::Video::deviceMode == 2);
 
 
    echo("Accepted Mode: " NL
    echo("Accepted Mode: " NL
-      "--Resolution : " @  %resX SPC %resY NL 
-      "--Full Screen : " @ %fsLabel NL
+      "--Resolution     : " @  %resX SPC %resY NL
+      "--Screen Mode    : " @ %fsLabel NL
       "--Bits Per Pixel : " @ %bpp NL
       "--Bits Per Pixel : " @ %bpp NL
-      "--Refresh Rate : " @ %rate NL
-      "--AA TypeXLevel : " @ %aa NL
+      "--Refresh Rate   : " @ %rate NL
+      "--FSAA Level     : " @ %fsaa NL
       "--------------");
       "--------------");
-      
+
    // Actually set the new video mode
    // Actually set the new video mode
    Canvas.setVideoMode(%resX, %resY, %fs, %bpp, %rate, %aa);
    Canvas.setVideoMode(%resX, %resY, %fs, %bpp, %rate, %aa);
+   Canvas.setFocus();
+
+   // Lock and unlock the mouse to force the position to sync with the platform window
+   lockMouse(true);
+   lockMouse(false);
 
 
    commandToServer('setClientAspectRatio', %resX, %resY);
    commandToServer('setClientAspectRatio', %resX, %resY);
 
 
@@ -157,6 +132,97 @@ function configureCanvas()
    // We need to parse the setting between AA modes, and then it's level
    // We need to parse the setting between AA modes, and then it's level
    // It's formatted as AATypexAALevel
    // It's formatted as AATypexAALevel
    // So, FXAAx4 or MLAAx2
    // So, FXAAx4 or MLAAx2
-   if ( isObject( FXAAPostFX ) )
-      FXAAPostFX.isEnabled = ( %aa > 0 ) ? true : false;
+   if ( isObject( FXAA_PostEffect ) )
+      FXAA_PostEffect.isEnabled = ( %aa > 0 ) ? true : false;
+}
+
+function GuiCanvas::modeStrToPrefs(%this, %modeStr)
+{
+   $pref::Video::Resolution = %modeStr.x SPC %modeStr.y;
+   $pref::Video::FullScreen = getWord(%modeStr, $WORD::FULLSCREEN);
+   $pref::Video::BitDepth = getWord(%modeStr, $WORD::BITDEPTH);
+   $pref::Video::RefreshRate = getWord(%modeStr, $WORD::REFRESH);
+   $pref::Video::AA = getWord(%modeStr, $WORD::AA);
+}
+
+function GuiCanvas::prefsToModeStr(%this)
+{
+   %modeStr = $pref::Video::Resolution SPC $pref::Video::FullScreen SPC
+      $pref::Video::BitDepth SPC $pref::Video::RefreshRate SPC $pref::Video::AA;
+
+   return %modeStr;
+}
+
+function GuiCanvas::checkCanvasRes(%this, %mode, %deviceId, %deviceMode, %startup)
+{
+   %resX = getWord(%mode, $WORD::RES_X);
+   %resY = getWord(%mode, $WORD::RES_Y);
+
+   // Make sure it meets the minimum resolution requirement
+   if ((%resX < $Video::minimumXResolution) || (%resY < $Video::minimumYResolution))
+      return false;
+
+   if (%deviceMode == $Video::ModeWindowed)
+   {  // Windowed must be smaller than the device usable area
+      %deviceRect = getWords(%this.getMonitorUsableRect(%deviceId), 2);
+      if ((%resY > %deviceRect.y) || (%resX > (%deviceRect.x - 2)))
+         return false;
+      return true;
+   }
+   else if (%deviceMode == $Video::ModeBorderless)
+   {  // Borderless must be at or less than the device res
+      %deviceRect = getWords(%this.getMonitorRect(%deviceId), 2);
+      if ((%resX > %deviceRect.x) || (%resY > %deviceRect.y))
+         return false;
+
+      return true;
+   }
+
+   if (!%startup)
+      return true;
+
+   // Checking saved prefs, make sure the mode still exists
+   %bpp = getWord(%mode, $WORD::BITDEPTH);
+   %rate = getWord(%mode, $WORD::REFRESH);
+
+   %resCount = %this.getMonitorModeCount(%deviceId);
+   for (%i = (%resCount - 1); %i >= 0; %i--)
+   {
+      %testRes = %this.getMonitorMode(%deviceId, %i);
+      %testResX = getWord(%testRes, $WORD::RES_X);
+      %testResY = getWord(%testRes, $WORD::RES_Y);
+      %testBPP  = getWord(%testRes, $WORD::BITDEPTH);
+      %testRate = getWord(%testRes, $WORD::REFRESH);
+
+      if ((%testResX == %resX) && (%testResY == %resY) &&
+            (%testBPP == %bpp) && (%testRate == %rate))
+         return true;
+   }
+
+   return false;
+}
+
+// Find the best video mode setting for the device and display mode
+function GuiCanvas::getBestCanvasRes(%this, %deviceId, %deviceMode)
+{
+   if (%deviceMode == $Video::ModeWindowed)
+      %deviceRect = getWords(%this.getMonitorUsableRect(%deviceId), 2);
+   else
+      %deviceRect = getWords(%this.getMonitorRect(%deviceId), 2);
+
+   %resCount = %this.getModeCount();
+   for (%i = %resCount - 1; %i >= 0; %i--)
+   {
+      %testRes = %this.getMode(%i);
+      %resX = getWord(%testRes, $WORD::RES_X);
+      %resY = getWord(%testRes, $WORD::RES_Y);
+
+      if ((%resX > %deviceRect.x) || (%resY > %deviceRect.y))
+         continue;
+
+      return %testRes;
+   }
+
+   // Nothing found? return first mode
+   return %this.getMonitorMode(%deviceId, 0);
 }
 }

+ 38 - 4
Templates/BaseGame/game/core/rendering/scripts/graphicsOptions.cs

@@ -721,14 +721,19 @@ function _makePrettyResString( %resString, %giveAspectRation )
    return %outRes;   
    return %outRes;   
 }
 }
 
 
-function getScreenResolutionList()
+function getScreenResolutionList(%deviceID, %deviceMode)
 {
 {
    %returnsList = "";
    %returnsList = "";
-   
+
    %resCount = Canvas.getModeCount();
    %resCount = Canvas.getModeCount();
    for (%i = 0; %i < %resCount; %i++)
    for (%i = 0; %i < %resCount; %i++)
    {
    {
       %testResString = Canvas.getMode( %i );
       %testResString = Canvas.getMode( %i );
+
+      // Make sure it's valid for the monitor and mode selections
+      if (!Canvas.checkCanvasRes(%testResString, %deviceID, %deviceMode, false))
+         continue;
+
       %testRes = _makePrettyResString( %testResString );
       %testRes = _makePrettyResString( %testResString );
       
       
       //sanitize
       //sanitize
@@ -747,11 +752,40 @@ function getScreenResolutionList()
       if(%found)
       if(%found)
          continue;
          continue;
                      
                      
-      if(%i != 0)
+      if(%returnsList !$= "")
          %returnsList = %returnsList @ "\t" @ %testRes;
          %returnsList = %returnsList @ "\t" @ %testRes;
       else
       else
          %returnsList = %testRes;
          %returnsList = %testRes;
    }
    }
-   
+
+   return %returnsList;
+}
+
+// Return a sorted tab-separated list of all refresh rates available for %resolution.
+function getScreenRefreshList(%resolution)
+{
+   %rateArray = new ArrayObject();
+   %resCount = Canvas.getModeCount();
+   for (%i = 0; %i < %resCount; %i++)
+   {
+      %testRes = Canvas.getMode(%i);
+      if ((%testRes.x != %resolution.x) || (%testRes.y != %resolution.y))
+         continue;
+      %rate = getWord(%testRes, $WORD::REFRESH);
+      if (%rateArray.getIndexFromKey(%rate) == -1)
+         %rateArray.add(%rate, %rate);
+   }
+
+   %rateArray.sort(true);
+   %returnsList = "";
+   for (%i = 0; %i < %rateArray.count(); %i++)
+   {
+      %rate = %rateArray.getKey(%i);
+      %returnsList = %returnsList @ ((%i == 0) ? %rate : ("\t" @ %rate));
+   }
+   if (%returnsList $= "")
+      %returnsList = "60";
+
+   %rateArray.delete();
    return %returnsList;
    return %returnsList;
 }
 }

+ 0 - 5
Templates/BaseGame/game/data/defaults.cs

@@ -27,11 +27,6 @@ $sceneLighting::cacheLighting = 1;
 
 
 $pref::Video::displayDevice = "D3D11";
 $pref::Video::displayDevice = "D3D11";
 $pref::Video::disableVerticalSync = 1;
 $pref::Video::disableVerticalSync = 1;
-$pref::Video::Resolution = "1024 768";
-$pref::Video::FullScreen = false;
-$pref::Video::BitDepth = "32";
-$pref::Video::RefreshRate = "60";
-$pref::Video::AA = "4";
 $pref::Video::defaultFenceCount = 0;
 $pref::Video::defaultFenceCount = 0;
 $pref::Video::screenShotSession = 0;
 $pref::Video::screenShotSession = 0;
 $pref::Video::screenShotFormat = "PNG";
 $pref::Video::screenShotFormat = "PNG";

+ 164 - 45
Templates/BaseGame/game/data/ui/guis/optionsMenu.cs

@@ -196,13 +196,44 @@ function OptionsMenu::populateDisplaySettingsList(%this)
    OptionName.setText("");
    OptionName.setText("");
    OptionDescription.setText("");
    OptionDescription.setText("");
    
    
-   %resolutionList = getScreenResolutionList();
    OptionsMenuSettingsList.addOptionRow("Display API", "D3D11\tOpenGL", false, "", -1, -30, true, "The display API used for rendering.", $pref::Video::displayDevice);
    OptionsMenuSettingsList.addOptionRow("Display API", "D3D11\tOpenGL", false, "", -1, -30, true, "The display API used for rendering.", $pref::Video::displayDevice);
-   OptionsMenuSettingsList.addOptionRow("Resolution", %resolutionList, false, "", -1, -30, true, "Resolution of the game window", _makePrettyResString( $pref::Video::mode ));
-   OptionsMenuSettingsList.addOptionRow("Fullscreen", "No\tYes", false, "", -1, -30, true, "", convertBoolToYesNo($pref::Video::FullScreen));
-   OptionsMenuSettingsList.addOptionRow("VSync", "No\tYes", false, "", -1, -30, true, "", convertBoolToYesNo(!$pref::Video::disableVerticalSync));
    
    
-   OptionsMenuSettingsList.addOptionRow("Refresh Rate", "30\t60\t75", false, "", -1, -30, true, "", $pref::Video::RefreshRate);
+   %numDevices = Canvas.getMonitorCount();
+   %devicesList = "";
+   for(%i = 0; %i < %numDevices; %i++)
+   {
+      %device = (%i+1) @ " - " @ Canvas.getMonitorName(%i);
+      if(%i==0)
+         %devicesList = %device;
+      else
+         %devicesList = %devicesList @ "\t" @ %device;
+   }
+   
+   %selectedDevice = getField(%devicesList, $pref::Video::deviceId);
+   OptionsMenuSettingsList.addOptionRow("Display Device", %devicesList, false, "onDisplayModeChange", -1, -30, true, "The display devices the window should be on.", %selectedDevice);
+      
+   if (%numDevices > 1)
+      OptionsMenuSettingsList.setRowEnabled(1, true);
+   else
+      OptionsMenuSettingsList.setRowEnabled(1, false);
+   
+   %mode = getField($Video::ModeTags, $pref::Video::deviceMode);
+   OptionsMenuSettingsList.addOptionRow("Window Mode", $Video::ModeTags, false, "onDisplayModeChange", -1, -30, true, "", %mode);
+   
+   %resolutionList = getScreenResolutionList($pref::Video::deviceId, $pref::Video::deviceMode);
+   OptionsMenuSettingsList.addOptionRow("Resolution", %resolutionList, false, "onDisplayResChange", -1, -30, true, "Resolution of the game window", _makePrettyResString( $pref::Video::mode ));
+   
+   //If they're doing borderless, the window resolution must match the display resolution
+   if(%mode !$= "Borderless")
+      OptionsMenuSettingsList.setRowEnabled(3, true);
+   else
+      OptionsMenuSettingsList.setRowEnabled(3, false);
+   
+   OptionsMenuSettingsList.addOptionRow("VSync", "No\tYes", false, "", -1, -30, true, "", convertBoolToYesNo(!$pref::Video::disableVerticalSync));
+
+
+   %refreshList = getScreenRefreshList($pref::Video::mode);
+   OptionsMenuSettingsList.addOptionRow("Refresh Rate", %refreshList, false, "", -1, -30, true, "", $pref::Video::RefreshRate);
    
    
    //move to gameplay tab
    //move to gameplay tab
    OptionsMenuSettingsList.addSliderRow("Field of View", 75, 5, "65 100", "", -1, -30);
    OptionsMenuSettingsList.addSliderRow("Field of View", 75, 5, "65 100", "", -1, -30);
@@ -215,20 +246,8 @@ function OptionsMenu::populateDisplaySettingsList(%this)
 
 
 function OptionsMenu::applyDisplaySettings(%this)
 function OptionsMenu::applyDisplaySettings(%this)
 {
 {
-   //%newAdapter    = GraphicsMenuDriver.getText();
-	//%numAdapters   = GFXInit::getAdapterCount();
 	%newDevice     = OptionsMenuSettingsList.getCurrentOption(0);
 	%newDevice     = OptionsMenuSettingsList.getCurrentOption(0);
 							
 							
-	/*for( %i = 0; %i < %numAdapters; %i ++ )
-	{
-	   %targetAdapter = GFXInit::getAdapterName( %i );
-	   if( GFXInit::getAdapterName( %i ) $= %newDevice )
-	   {
-	      %newDevice = GFXInit::getAdapterType( %i );
-	      break;
-	   }
-	}*/
-	   
    // Change the device.
    // Change the device.
    if ( %newDevice !$= $pref::Video::displayDevice )
    if ( %newDevice !$= $pref::Video::displayDevice )
    {
    {
@@ -324,9 +343,16 @@ function OptionsMenu::applyGraphicsSettings(%this)
                                  
                                  
       $pref::Video::defaultAnisotropy = %level;
       $pref::Video::defaultAnisotropy = %level;
    }
    }
-   
-   updateDisplaySettings();
-   
+
+   %newFSAA = OptionsMenuSettingsList.getCurrentOption(9);
+   if (%newFSAA $= "off")
+      %newFSAA = 0;
+   if (%newFSAA !$= $pref::Video::AA)
+   {
+      $pref::Video::AA = %newFSAA;
+      configureCanvas();
+   }
+
    echo("Exporting client prefs");
    echo("Exporting client prefs");
    %prefPath = getPrefpath();
    %prefPath = getPrefpath();
    export("$pref::*", %prefPath @ "/clientPrefs.cs", false);
    export("$pref::*", %prefPath @ "/clientPrefs.cs", false);
@@ -335,37 +361,58 @@ function OptionsMenu::applyGraphicsSettings(%this)
 function updateDisplaySettings()
 function updateDisplaySettings()
 {
 {
    //Update the display settings now
    //Update the display settings now
-   $pref::Video::Resolution = getWord(OptionsMenuSettingsList.getCurrentOption(1), 0) SPC getWord(OptionsMenuSettingsList.getCurrentOption(1), 2);
-   %newBpp        = 32; // ... its not 1997 anymore.
-	$pref::Video::FullScreen = convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(2)) == 0 ? "false" : "true";
-	$pref::Video::RefreshRate    = OptionsMenuSettingsList.getCurrentOption(4);
-	%newVsync = !convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(3));	
-	//$pref::Video::AA = GraphicsMenuAA.getSelected();
-	
-   /*if ( %newFullScreen $= "false" )
-	{
-      // If we're in windowed mode switch the fullscreen check
-      // if the resolution is bigger than the desktop.
-      %deskRes    = getDesktopResolution();      
-      %deskResX   = getWord(%deskRes, $WORD::RES_X);
-      %deskResY   = getWord(%deskRes, $WORD::RES_Y);
-	   if (  getWord( %newRes, $WORD::RES_X ) > %deskResX || 
-	         getWord( %newRes, $WORD::RES_Y ) > %deskResY )
-      {
-         $pref::Video::FullScreen = "true";
-         GraphicsMenuFullScreen.setStateOn( true );
-      }
-	}*/
+   %deviceName = OptionsMenuSettingsList.getCurrentOption(1);
+   %newDeviceID = getWord(%deviceName, 0) - 1;
+   %deviceModeName = OptionsMenuSettingsList.getCurrentOption(2);
+   %newDeviceMode = 0;
+   foreach$(%modeName in $Video::ModeTags)
+   {
+      if (%deviceModeName $= %modeName)
+         break;
+      else
+         %newDeviceMode++;
+   }
 
 
+   %newRes = getWord(OptionsMenuSettingsList.getCurrentOption(3), 0) SPC getWord(OptionsMenuSettingsList.getCurrentOption(3), 2);
+   %newBpp = 32; // ... its not 1997 anymore.
+	%newFullScreen = %deviceModeName $= "Fullscreen" ? true : false;
+	%newRefresh    = OptionsMenuSettingsList.getCurrentOption(5);
+	%newVsync = !convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(4));	
+	%newFSAA = $pref::Video::AA;
+	
    // Build the final mode string.
    // Build the final mode string.
-	%newMode = $pref::Video::Resolution SPC $pref::Video::FullScreen SPC %newBpp SPC $pref::Video::RefreshRate SPC $pref::Video::AA;
+	%newMode = %newRes SPC %newFullScreen SPC %newBpp SPC %newRefresh SPC %newFSAA;
 	
 	
    // Change the video mode.   
    // Change the video mode.   
-   if (  %newMode !$= $pref::Video::mode || 
-         %newVsync != $pref::Video::disableVerticalSync )
+   if (  %newMode !$= $pref::Video::mode || %newDeviceID != $pref::Video::deviceId ||
+         %newVsync != $pref::Video::disableVerticalSync || %newDeviceMode != $pref::Video::deviceMode)
    {
    {
+      if ( %testNeedApply )
+         return true;
+
+      //****Edge Case Hack
+      // If we're in fullscreen mode and switching to a different monitor at the
+      // same resolution and maintaining fullscreen, GFX...WindowTarget::resetMode()
+      // will early-out because there is no "mode change" and the monitor change
+      // will not get applied. Instead of modifying platform code, we're going to
+      // move onto the new monitor in borderless and immediately switch to FS.
+      if (%newFullScreen && $pref::Video::FullScreen &&
+         ($pref::Video::Resolution $= %newRes) && ($pref::Video::deviceId != %newDeviceID))
+      {
+         $pref::Video::deviceId = %newDeviceID;
+         $pref::Video::deviceMode = $Video::ModeBorderless;
+         %tmpModeStr = Canvas.getMonitorMode(%newDeviceID, 0);
+         Canvas.setVideoMode(%tmpModeStr.x, %tmpModeStr.y, false, 32, getWord(%tmpModeStr, $WORD::REFRESH), %aa);
+      }
+
       $pref::Video::mode = %newMode;
       $pref::Video::mode = %newMode;
-      $pref::Video::disableVerticalSync = %newVsync;      
+      $pref::Video::disableVerticalSync = %newVsync;
+      $pref::Video::deviceId = %newDeviceID;
+      $pref::Video::deviceMode = %newDeviceMode;
+      $pref::Video::Resolution = %newRes;
+      $pref::Video::FullScreen = %newFullScreen;
+      $pref::Video::RefreshRate = %newRefresh;
+      $pref::Video::AA = %newFSAA;
       configureCanvas();
       configureCanvas();
    }
    }
 }
 }
@@ -537,4 +584,76 @@ function convertBoolToOnOff(%val)
       return "On";
       return "On";
    else 
    else 
       return "Off";
       return "Off";
+}
+
+function onDisplayModeChange(%val)
+{  
+   // The display device (monitor) or screen mode has changed. Refill the
+   // resolution list with only available options.
+   %deviceName = OptionsMenuSettingsList.getCurrentOption(1);
+   %newDeviceID = getWord(%deviceName, 0) - 1;
+   %deviceModeName = OptionsMenuSettingsList.getCurrentOption(2);
+   %newDeviceMode = 0;
+   foreach$(%modeName in $Video::ModeTags)
+   {
+      if (%deviceModeName $= %modeName)
+         break;
+      else
+         %newDeviceMode++;
+   }
+   %resolutionList = getScreenResolutionList(%newDeviceID, %newDeviceMode);
+
+   // If we're switching to borderless, default to monitor res
+   if (%newDeviceMode == $Video::ModeBorderless)
+      %newRes = getWords(Canvas.getMonitorRect(%newDeviceID), 2);
+   else
+   {  // Otherwise, if our old resolution is still in the list, attempt to reset it.
+      %oldRes = getWord(OptionsMenuSettingsList.getCurrentOption(3), 0) SPC getWord(OptionsMenuSettingsList.getCurrentOption(3), 2);
+
+      %found = false;
+      %retCount = getFieldCount(%resolutionList);
+      for (%i = 0; %i < %retCount; %i++)
+      {
+         %existingEntry = getField(%resolutionList, %i);
+         if ((%existingEntry.x $= %oldRes.x) && (%existingEntry.z $= %oldRes.y))
+         {
+            %found = true;
+            %newRes = %oldRes;
+            break;  
+         }
+      }
+
+      if (!%found)
+      {  // Pick the best resoltion available for the device and mode
+         %newRes = Canvas.getBestCanvasRes(%newDeviceID, %newDeviceMode);
+      }
+   }
+   
+   if(%newDeviceMode == $Video::ModeBorderless)
+      OptionsMenuSettingsList.setRowEnabled(3, false);
+   else
+      OptionsMenuSettingsList.setRowEnabled(3, true);
+      
+   OptionsMenuSettingsList.setOptions(3, %resolutionList);
+   OptionsMenuSettingsList.selectOption(3, _makePrettyResString(%newRes));
+}
+
+function onDisplayResChange(%val)
+{  // The resolution has changed. Setup refresh rates available at this res.
+   %newRes = getWord(OptionsMenuSettingsList.getCurrentOption(3), 0) SPC getWord(OptionsMenuSettingsList.getCurrentOption(3), 2);
+   %refreshList = getScreenRefreshList(%newRes);
+
+   // If our old rate still exists, select it
+   %oldRate = OptionsMenuSettingsList.getCurrentOption(5);
+   %retCount = getFieldCount(%refreshList);
+   for (%i = 0; %i < %retCount; %i++)
+   {
+      %existingEntry = getField(%refreshList, %i);
+      %newRate = %existingEntry;
+      if (%existingEntry $= %oldRate)
+         break;  
+   }
+
+   OptionsMenuSettingsList.setOptions(5, %refreshList);
+   OptionsMenuSettingsList.selectOption(5, %newRate);
 }
 }