From 452cac33b86f8ecd87788ba0eb0633d779c155d1 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Wed, 1 Oct 2025 17:31:03 +0100 Subject: [PATCH] [examples] Add `core_monitor_change` (#5215) * Add core monitor change example * Add monitor drawing and more information * Update monitor information every frame * Show info and window position inside the rectangle --- examples/core/core_monitor_change.c | 170 ++++++++++++++++++++++++++ examples/core/core_monitor_change.png | Bin 0 -> 17430 bytes 2 files changed, 170 insertions(+) create mode 100644 examples/core/core_monitor_change.c create mode 100644 examples/core/core_monitor_change.png diff --git a/examples/core/core_monitor_change.c b/examples/core/core_monitor_change.c new file mode 100644 index 000000000..8983556af --- /dev/null +++ b/examples/core/core_monitor_change.c @@ -0,0 +1,170 @@ +/******************************************************************************************* +* +* raylib [core] example - monitor change +* +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 5.5, last time updated with raylib 5.6 +* +* Example contributed by Maicon Santana (@maiconpintoabreu) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2025-2025 Maicon Santana (@maiconpintoabreu) +* +********************************************************************************************/ + +#include "raylib.h" + +#define MAX_MONITORS 10 + +// Monitor Details +typedef struct Monitor { + Vector2 position; + char *name; + int width; + int height; + int physicalWidth; + int physicalHeight; + int refreshRate; +} Monitor; + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + Monitor monitors[MAX_MONITORS] = { 0 }; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor change"); + + int currentMonitorIndex = GetCurrentMonitor(); + int monitorCount = 0; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Variables to find the max x and Y to calculate the scale + int maxWidth = 1; + int maxHeight = 1; + + // Monitor offset is to fix when monitor position x is negative + int monitorOffsetX = 0; + + // Rebuild monitors array every frame + monitorCount = GetMonitorCount(); + for (int i = 0; i < monitorCount; i++) + { + monitors[i] = (Monitor){ + GetMonitorPosition(i), + GetMonitorName(i), + GetMonitorWidth(i), + GetMonitorHeight(i), + GetMonitorPhysicalWidth(i), + GetMonitorPhysicalHeight(i), + GetMonitorRefreshRate(i) + }; + if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = monitors[i].position.x*-1; + + const int width = monitors[i].position.x + monitors[i].width; + const int height = monitors[i].position.y + monitors[i].height; + + if (maxWidth < width) maxWidth = width; + if (maxHeight < height) maxHeight = height; + } + + if (IsKeyPressed(KEY_ENTER) && monitorCount > 1) + { + currentMonitorIndex += 1; + + // Set index to 0 if the last one + if(currentMonitorIndex == monitorCount) currentMonitorIndex = 0; + + SetWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex + } + else + { + // Get currentMonitorIndex if manually moved + currentMonitorIndex = GetCurrentMonitor(); + } + const Monitor currentMonitor = monitors[currentMonitorIndex]; + + float monitorScale = 0.6; + + if(maxHeight > maxWidth + monitorOffsetX) monitorScale *= ((float)screenHeight/(float)maxHeight); + else monitorScale *= ((float)screenWidth/(float)(maxWidth + monitorOffsetX)); + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("Press [Enter] to move window to next monitor available", 20, 20, 20, DARKGRAY); + + DrawRectangleLines(20, 60, screenWidth - 40, screenHeight - 100, DARKGRAY); + + // Draw Monitor Rectangles with information inside + for (int i = 0; i < monitorCount; i++) + { + // Calculate retangle position and size using monitorScale + const Rectangle rec = (Rectangle){ + (monitors[i].position.x + monitorOffsetX) * monitorScale + 140, + monitors[i].position.y * monitorScale + 80, + monitors[i].width * monitorScale, + monitors[i].height * monitorScale + }; + + // Draw monitor name and information inside the rectangle + DrawText(TextFormat("[%i] %s", i, monitors[i].name), rec.x + 10, rec.y + (int)(100*monitorScale), (int)(120*monitorScale), BLUE); + DrawText( + TextFormat("Resolution: [%ipx x %ipx]\nRefreshRate: [%ihz]\nPhysical Size: [%imm x %imm]\nPosition: %3.0f x %3.0f", + monitors[i].width, + monitors[i].height, + monitors[i].refreshRate, + monitors[i].physicalWidth, + monitors[i].physicalHeight, + monitors[i].position.x, + monitors[i].position.y + ), rec.x + 10, rec.y + (int)(200*monitorScale), (int)(120*monitorScale), DARKGRAY); + + // Highlight current monitor + if (i == currentMonitorIndex) + { + DrawRectangleLinesEx(rec, 5, RED); + Vector2 windowPosition = (Vector2){ (GetWindowPosition().x + monitorOffsetX)*monitorScale + 140, GetWindowPosition().y*monitorScale + 80 }; + + // Draw window position based on monitors + DrawRectangleV(windowPosition, (Vector2){screenWidth * monitorScale, screenHeight * monitorScale}, Fade(GREEN, 0.5)); + } + else + { + DrawRectangleLinesEx(rec, 5, GRAY); + } + + } + + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/core/core_monitor_change.png b/examples/core/core_monitor_change.png new file mode 100644 index 0000000000000000000000000000000000000000..81f9eed875bf8edf2c11e911cad5265418e054ed GIT binary patch literal 17430 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