1//======================================================================== 2// Monitor information tool 3// Copyright (c) Camilla Löwy <elmindreda@glfw.org> 4// 5// This software is provided 'as-is', without any express or implied 6// warranty. In no event will the authors be held liable for any damages 7// arising from the use of this software. 8// 9// Permission is granted to anyone to use this software for any purpose, 10// including commercial applications, and to alter it and redistribute it 11// freely, subject to the following restrictions: 12// 13// 1. The origin of this software must not be misrepresented; you must not 14// claim that you wrote the original software. If you use this software 15// in a product, an acknowledgment in the product documentation would 16// be appreciated but is not required. 17// 18// 2. Altered source versions must be plainly marked as such, and must not 19// be misrepresented as being the original software. 20// 21// 3. This notice may not be removed or altered from any source 22// distribution. 23// 24//======================================================================== 25// 26// This test prints monitor and video mode information or verifies video 27// modes 28// 29//======================================================================== 30 31#define GLAD_GL_IMPLEMENTATION 32#include <glad/gl.h> 33#define GLFW_INCLUDE_NONE 34#include <GLFW/glfw3.h> 35 36#include <stdio.h> 37#include <string.h> 38#include <stdlib.h> 39 40#include "getopt.h" 41 42enum Mode 43{ 44 LIST_MODE, 45 TEST_MODE 46}; 47 48static void usage(void) 49{ 50 printf("Usage: monitors [-t]\n"); 51 printf(" monitors -h\n"); 52} 53 54static int euclid(int a, int b) 55{ 56 return b ? euclid(b, a % b) : a; 57} 58 59static const char* format_mode(const GLFWvidmode* mode) 60{ 61 static char buffer[512]; 62 const int gcd = euclid(mode->width, mode->height); 63 64 snprintf(buffer, 65 sizeof(buffer), 66 "%i x %i x %i (%i:%i) (%i %i %i) %i Hz", 67 mode->width, mode->height, 68 mode->redBits + mode->greenBits + mode->blueBits, 69 mode->width / gcd, mode->height / gcd, 70 mode->redBits, mode->greenBits, mode->blueBits, 71 mode->refreshRate); 72 73 buffer[sizeof(buffer) - 1] = '\0'; 74 return buffer; 75} 76 77static void error_callback(int error, const char* description) 78{ 79 fprintf(stderr, "Error: %s\n", description); 80} 81 82static void framebuffer_size_callback(GLFWwindow* window, int width, int height) 83{ 84 printf("Framebuffer resized to %ix%i\n", width, height); 85 86 glViewport(0, 0, width, height); 87} 88 89static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 90{ 91 if (key == GLFW_KEY_ESCAPE) 92 glfwSetWindowShouldClose(window, GLFW_TRUE); 93} 94 95static void list_modes(GLFWmonitor* monitor) 96{ 97 int count, x, y, width_mm, height_mm, i; 98 int workarea_x, workarea_y, workarea_width, workarea_height; 99 float xscale, yscale; 100 101 const GLFWvidmode* mode = glfwGetVideoMode(monitor); 102 const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); 103 104 glfwGetMonitorPos(monitor, &x, &y); 105 glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm); 106 glfwGetMonitorContentScale(monitor, &xscale, &yscale); 107 glfwGetMonitorWorkarea(monitor, &workarea_x, &workarea_y, &workarea_width, &workarea_height); 108 109 printf("Name: %s (%s)\n", 110 glfwGetMonitorName(monitor), 111 glfwGetPrimaryMonitor() == monitor ? "primary" : "secondary"); 112 printf("Current mode: %s\n", format_mode(mode)); 113 printf("Virtual position: %i, %i\n", x, y); 114 printf("Content scale: %f x %f\n", xscale, yscale); 115 116 printf("Physical size: %i x %i mm (%0.2f dpi at %i x %i)\n", 117 width_mm, height_mm, mode->width * 25.4f / width_mm, mode->width, mode->height); 118 printf("Monitor work area: %i x %i starting at %i, %i\n", 119 workarea_width, workarea_height, workarea_x, workarea_y); 120 121 printf("Modes:\n"); 122 123 for (i = 0; i < count; i++) 124 { 125 printf("%3u: %s", (unsigned int) i, format_mode(modes + i)); 126 127 if (memcmp(mode, modes + i, sizeof(GLFWvidmode)) == 0) 128 printf(" (current mode)"); 129 130 putchar('\n'); 131 } 132} 133 134static void test_modes(GLFWmonitor* monitor) 135{ 136 int i, count; 137 GLFWwindow* window; 138 const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); 139 140 for (i = 0; i < count; i++) 141 { 142 const GLFWvidmode* mode = modes + i; 143 GLFWvidmode current; 144 145 glfwWindowHint(GLFW_RED_BITS, mode->redBits); 146 glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); 147 glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); 148 glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); 149 150 printf("Testing mode %u on monitor %s: %s\n", 151 (unsigned int) i, 152 glfwGetMonitorName(monitor), 153 format_mode(mode)); 154 155 window = glfwCreateWindow(mode->width, mode->height, 156 "Video Mode Test", 157 glfwGetPrimaryMonitor(), 158 NULL); 159 if (!window) 160 { 161 printf("Failed to enter mode %u: %s\n", 162 (unsigned int) i, 163 format_mode(mode)); 164 continue; 165 } 166 167 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 168 glfwSetKeyCallback(window, key_callback); 169 170 glfwMakeContextCurrent(window); 171 gladLoadGL(glfwGetProcAddress); 172 glfwSwapInterval(1); 173 174 glfwSetTime(0.0); 175 176 while (glfwGetTime() < 5.0) 177 { 178 glClear(GL_COLOR_BUFFER_BIT); 179 glfwSwapBuffers(window); 180 glfwPollEvents(); 181 182 if (glfwWindowShouldClose(window)) 183 { 184 printf("User terminated program\n"); 185 186 glfwTerminate(); 187 exit(EXIT_SUCCESS); 188 } 189 } 190 191 glGetIntegerv(GL_RED_BITS, ¤t.redBits); 192 glGetIntegerv(GL_GREEN_BITS, ¤t.greenBits); 193 glGetIntegerv(GL_BLUE_BITS, ¤t.blueBits); 194 195 glfwGetWindowSize(window, ¤t.width, ¤t.height); 196 197 if (current.redBits != mode->redBits || 198 current.greenBits != mode->greenBits || 199 current.blueBits != mode->blueBits) 200 { 201 printf("*** Color bit mismatch: (%i %i %i) instead of (%i %i %i)\n", 202 current.redBits, current.greenBits, current.blueBits, 203 mode->redBits, mode->greenBits, mode->blueBits); 204 } 205 206 if (current.width != mode->width || current.height != mode->height) 207 { 208 printf("*** Size mismatch: %ix%i instead of %ix%i\n", 209 current.width, current.height, 210 mode->width, mode->height); 211 } 212 213 printf("Closing window\n"); 214 215 glfwDestroyWindow(window); 216 window = NULL; 217 218 glfwPollEvents(); 219 } 220} 221 222int main(int argc, char** argv) 223{ 224 int ch, i, count, mode = LIST_MODE; 225 GLFWmonitor** monitors; 226 227 while ((ch = getopt(argc, argv, "th")) != -1) 228 { 229 switch (ch) 230 { 231 case 'h': 232 usage(); 233 exit(EXIT_SUCCESS); 234 case 't': 235 mode = TEST_MODE; 236 break; 237 default: 238 usage(); 239 exit(EXIT_FAILURE); 240 } 241 } 242 243 glfwSetErrorCallback(error_callback); 244 245 glfwInitHint(GLFW_COCOA_MENUBAR, GLFW_FALSE); 246 247 if (!glfwInit()) 248 exit(EXIT_FAILURE); 249 250 monitors = glfwGetMonitors(&count); 251 252 for (i = 0; i < count; i++) 253 { 254 if (mode == LIST_MODE) 255 list_modes(monitors[i]); 256 else if (mode == TEST_MODE) 257 test_modes(monitors[i]); 258 } 259 260 glfwTerminate(); 261 exit(EXIT_SUCCESS); 262} 263 264