Browse Source

Adds BORDERLESS_WINDOWED_MODE for PLATFORM_DESKTOP (#3216)

ubkp 2 years ago
parent
commit
464e714a2e
2 changed files with 94 additions and 0 deletions
  1. 2 0
      src/raylib.h
  2. 92 0
      src/rcore.c

+ 2 - 0
src/raylib.h

@@ -526,6 +526,7 @@ typedef enum {
     FLAG_WINDOW_TRANSPARENT = 0x00000010,   // Set to allow transparent framebuffer
     FLAG_WINDOW_TRANSPARENT = 0x00000010,   // Set to allow transparent framebuffer
     FLAG_WINDOW_HIGHDPI     = 0x00002000,   // Set to support HighDPI
     FLAG_WINDOW_HIGHDPI     = 0x00002000,   // Set to support HighDPI
     FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED
     FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED
+    FLAG_BORDERLESS_WINDOWED_MODE = 0x00008000, // Set to run program in borderless windowed mode
     FLAG_MSAA_4X_HINT       = 0x00000020,   // Set to try enabling MSAA 4X
     FLAG_MSAA_4X_HINT       = 0x00000020,   // Set to try enabling MSAA 4X
     FLAG_INTERLACED_HINT    = 0x00010000    // Set to try enabling interlaced video format (for V3D)
     FLAG_INTERLACED_HINT    = 0x00010000    // Set to try enabling interlaced video format (for V3D)
 } ConfigFlags;
 } ConfigFlags;
@@ -947,6 +948,7 @@ RLAPI bool IsWindowState(unsigned int flag);                      // Check if on
 RLAPI void SetWindowState(unsigned int flags);                    // Set window configuration state using flags (only PLATFORM_DESKTOP)
 RLAPI void SetWindowState(unsigned int flags);                    // Set window configuration state using flags (only PLATFORM_DESKTOP)
 RLAPI void ClearWindowState(unsigned int flags);                  // Clear window configuration state flags
 RLAPI void ClearWindowState(unsigned int flags);                  // Clear window configuration state flags
 RLAPI void ToggleFullscreen(void);                                // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)
 RLAPI void ToggleFullscreen(void);                                // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)
+RLAPI void ToggleBorderlessWindowed(void);                        // Toggle window state: borderless windowed (only PLATFORM_DESKTOP)
 RLAPI void MaximizeWindow(void);                                  // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
 RLAPI void MaximizeWindow(void);                                  // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
 RLAPI void MinimizeWindow(void);                                  // Set window state: minimized, if resizable (only PLATFORM_DESKTOP)
 RLAPI void MinimizeWindow(void);                                  // Set window state: minimized, if resizable (only PLATFORM_DESKTOP)
 RLAPI void RestoreWindow(void);                                   // Set window state: not minimized/maximized (only PLATFORM_DESKTOP)
 RLAPI void RestoreWindow(void);                                   // Set window state: not minimized/maximized (only PLATFORM_DESKTOP)

+ 92 - 0
src/rcore.c

@@ -412,6 +412,8 @@ typedef struct CoreData {
         Size render;                        // Framebuffer width and height (render area, including black bars if required)
         Size render;                        // Framebuffer width and height (render area, including black bars if required)
         Point renderOffset;                 // Offset from render area (must be divided by 2)
         Point renderOffset;                 // Offset from render area (must be divided by 2)
         Matrix screenScale;                 // Matrix to scale screen (framebuffer rendering)
         Matrix screenScale;                 // Matrix to scale screen (framebuffer rendering)
+        Point previousPosition;             // Previous screen position (required on borderless windowed toggle)
+        Size previousScreen;                // Previous screen size (required on borderless windowed toggle)
 
 
         char **dropFilepaths;         // Store dropped files paths pointers (provided by GLFW)
         char **dropFilepaths;         // Store dropped files paths pointers (provided by GLFW)
         unsigned int dropFileCount;         // Count dropped files strings
         unsigned int dropFileCount;         // Count dropped files strings
@@ -1324,6 +1326,82 @@ void ToggleFullscreen(void)
 #endif
 #endif
 }
 }
 
 
+// Toggle borderless windowed mode (only PLATFORM_DESKTOP)
+void ToggleBorderlessWindowed(void)
+{
+#if defined(PLATFORM_DESKTOP)
+    // Leave fullscreen before attempting to set borderless windowed mode and get screen position from it
+    bool wasOnFullscreen = false;
+    if (CORE.Window.fullscreen)
+    {
+        CORE.Window.previousPosition = CORE.Window.position;
+        ToggleFullscreen();
+        wasOnFullscreen = true;
+    }
+
+    const int monitor = GetCurrentMonitor();
+    int monitorCount;
+    GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
+    if ((monitor >= 0) && (monitor < monitorCount))
+    {
+        const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
+        if (mode)
+        {
+            if (!IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE))
+            {
+                // Store screen position and size
+                // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
+                if (!wasOnFullscreen) glfwGetWindowPos(CORE.Window.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);
+                CORE.Window.previousScreen = CORE.Window.screen;
+
+                // Set undecorated and topmost modes and flags
+                glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_FALSE);
+                CORE.Window.flags |= FLAG_WINDOW_UNDECORATED;
+                glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_TRUE);
+                CORE.Window.flags |= FLAG_WINDOW_TOPMOST;
+
+                // Get monitor position and size
+                int monitorPosX = 0;
+                int monitorPosY = 0;
+                glfwGetMonitorPos(monitors[monitor], &monitorPosX, &monitorPosY);
+                const int monitorWidth = mode->width;
+                const int monitorHeight = mode->height;
+                glfwSetWindowSize(CORE.Window.handle, monitorWidth, monitorHeight);
+
+                // Set screen position and size
+                glfwSetWindowPos(CORE.Window.handle, monitorPosX, monitorPosY);
+                glfwSetWindowSize(CORE.Window.handle, monitorWidth, monitorHeight);
+
+                // Refocus window
+                glfwFocusWindow(CORE.Window.handle);
+
+                CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
+            }
+            else
+            {
+                // Remove topmost and undecorated modes and flags
+                glfwSetWindowAttrib(CORE.Window.handle, GLFW_FLOATING, GLFW_FALSE);
+                CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST;
+                glfwSetWindowAttrib(CORE.Window.handle, GLFW_DECORATED, GLFW_TRUE);
+                CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED;
+
+                // Return previous screen size and position
+                // NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly
+                glfwSetWindowSize(CORE.Window.handle,  CORE.Window.previousScreen.width, CORE.Window.previousScreen.height);
+                glfwSetWindowPos(CORE.Window.handle, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y);
+
+                // Refocus window
+                glfwFocusWindow(CORE.Window.handle);
+
+                CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+            }
+        }
+        else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
+    }
+    else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
+#endif
+}
+
 // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
 // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
 void MaximizeWindow(void)
 void MaximizeWindow(void)
 {
 {
@@ -1373,6 +1451,13 @@ void SetWindowState(unsigned int flags)
         CORE.Window.flags |= FLAG_VSYNC_HINT;
         CORE.Window.flags |= FLAG_VSYNC_HINT;
     }
     }
 
 
+    // State change: FLAG_BORDERLESS_WINDOWED_MODE
+    // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
+    if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) != (flags & FLAG_BORDERLESS_WINDOWED_MODE)) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0))
+    {
+        ToggleBorderlessWindowed();     // NOTE: Window state flag updated inside function
+    }
+
     // State change: FLAG_FULLSCREEN_MODE
     // State change: FLAG_FULLSCREEN_MODE
     if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE))
     if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE))
     {
     {
@@ -1483,6 +1568,13 @@ void ClearWindowState(unsigned int flags)
         CORE.Window.flags &= ~FLAG_VSYNC_HINT;
         CORE.Window.flags &= ~FLAG_VSYNC_HINT;
     }
     }
 
 
+    // State change: FLAG_BORDERLESS_WINDOWED_MODE
+    // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
+    if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0))
+    {
+        ToggleBorderlessWindowed();     // NOTE: Window state flag updated inside function
+    }
+
     // State change: FLAG_FULLSCREEN_MODE
     // State change: FLAG_FULLSCREEN_MODE
     if (((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) && ((flags & FLAG_FULLSCREEN_MODE) > 0))
     if (((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) && ((flags & FLAG_FULLSCREEN_MODE) > 0))
     {
     {