monitor.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. //========================================================================
  2. // GLFW 3.4 - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2002-2006 Marcus Geelnard
  5. // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
  6. //
  7. // This software is provided 'as-is', without any express or implied
  8. // warranty. In no event will the authors be held liable for any damages
  9. // arising from the use of this software.
  10. //
  11. // Permission is granted to anyone to use this software for any purpose,
  12. // including commercial applications, and to alter it and redistribute it
  13. // freely, subject to the following restrictions:
  14. //
  15. // 1. The origin of this software must not be misrepresented; you must not
  16. // claim that you wrote the original software. If you use this software
  17. // in a product, an acknowledgment in the product documentation would
  18. // be appreciated but is not required.
  19. //
  20. // 2. Altered source versions must be plainly marked as such, and must not
  21. // be misrepresented as being the original software.
  22. //
  23. // 3. This notice may not be removed or altered from any source
  24. // distribution.
  25. //
  26. //========================================================================
  27. // Please use C89 style variable declarations in this file because VS 2010
  28. //========================================================================
  29. #include "internal.h"
  30. #include <assert.h>
  31. #include <math.h>
  32. #include <float.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <limits.h>
  36. // Lexically compare video modes, used by qsort
  37. //
  38. static int compareVideoModes(const void* fp, const void* sp)
  39. {
  40. const GLFWvidmode* fm = fp;
  41. const GLFWvidmode* sm = sp;
  42. const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
  43. const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
  44. const int farea = fm->width * fm->height;
  45. const int sarea = sm->width * sm->height;
  46. // First sort on color bits per pixel
  47. if (fbpp != sbpp)
  48. return fbpp - sbpp;
  49. // Then sort on screen area
  50. if (farea != sarea)
  51. return farea - sarea;
  52. // Then sort on width
  53. if (fm->width != sm->width)
  54. return fm->width - sm->width;
  55. // Lastly sort on refresh rate
  56. return fm->refreshRate - sm->refreshRate;
  57. }
  58. // Retrieves the available modes for the specified monitor
  59. //
  60. static bool refreshVideoModes(_GLFWmonitor* monitor)
  61. {
  62. int modeCount;
  63. GLFWvidmode* modes;
  64. if (monitor->modes)
  65. return true;
  66. modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
  67. if (!modes)
  68. return false;
  69. qsort(modes, modeCount, sizeof(modes[0]), compareVideoModes);
  70. free(monitor->modes);
  71. monitor->modes = modes;
  72. monitor->modeCount = modeCount;
  73. return true;
  74. }
  75. //////////////////////////////////////////////////////////////////////////
  76. ////// GLFW event API //////
  77. //////////////////////////////////////////////////////////////////////////
  78. // Notifies shared code of a monitor connection or disconnection
  79. //
  80. void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
  81. {
  82. if (action == GLFW_CONNECTED)
  83. {
  84. _glfw.monitorCount++;
  85. _glfw.monitors =
  86. realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount);
  87. if (placement == _GLFW_INSERT_FIRST)
  88. {
  89. memmove(_glfw.monitors + 1,
  90. _glfw.monitors,
  91. ((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
  92. _glfw.monitors[0] = monitor;
  93. }
  94. else
  95. _glfw.monitors[_glfw.monitorCount - 1] = monitor;
  96. }
  97. else if (action == GLFW_DISCONNECTED)
  98. {
  99. int i;
  100. _GLFWwindow* window;
  101. for (window = _glfw.windowListHead; window; window = window->next)
  102. {
  103. if (window->monitor == monitor)
  104. {
  105. int width, height, xoff, yoff;
  106. _glfwPlatformGetWindowSize(window, &width, &height);
  107. _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
  108. _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL);
  109. _glfwPlatformSetWindowPos(window, xoff, yoff);
  110. }
  111. }
  112. for (i = 0; i < _glfw.monitorCount; i++)
  113. {
  114. if (_glfw.monitors[i] == monitor)
  115. {
  116. remove_i_from_array(_glfw.monitors, i, _glfw.monitorCount);
  117. break;
  118. }
  119. }
  120. }
  121. if (_glfw.callbacks.monitor)
  122. _glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
  123. if (action == GLFW_DISCONNECTED)
  124. _glfwFreeMonitor(monitor);
  125. }
  126. // Notifies shared code that a full screen window has acquired or released
  127. // a monitor
  128. //
  129. void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
  130. {
  131. monitor->window = window;
  132. }
  133. //////////////////////////////////////////////////////////////////////////
  134. ////// GLFW internal API //////
  135. //////////////////////////////////////////////////////////////////////////
  136. // Allocates and returns a monitor object with the specified name and dimensions
  137. //
  138. _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
  139. {
  140. _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
  141. monitor->widthMM = widthMM;
  142. monitor->heightMM = heightMM;
  143. if (name)
  144. monitor->name = _glfw_strdup(name);
  145. return monitor;
  146. }
  147. // Frees a monitor object and any data associated with it
  148. //
  149. void _glfwFreeMonitor(_GLFWmonitor* monitor)
  150. {
  151. if (monitor == NULL)
  152. return;
  153. _glfwPlatformFreeMonitor(monitor);
  154. _glfwFreeGammaArrays(&monitor->originalRamp);
  155. _glfwFreeGammaArrays(&monitor->currentRamp);
  156. free(monitor->modes);
  157. free(monitor->name);
  158. free(monitor);
  159. }
  160. // Allocates red, green and blue value arrays of the specified size
  161. //
  162. void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
  163. {
  164. ramp->red = calloc(size, sizeof(unsigned short));
  165. ramp->green = calloc(size, sizeof(unsigned short));
  166. ramp->blue = calloc(size, sizeof(unsigned short));
  167. ramp->size = size;
  168. }
  169. // Frees the red, green and blue value arrays and clears the struct
  170. //
  171. void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
  172. {
  173. free(ramp->red);
  174. free(ramp->green);
  175. free(ramp->blue);
  176. memset(ramp, 0, sizeof(GLFWgammaramp));
  177. }
  178. // Chooses the video mode most closely matching the desired one
  179. //
  180. const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
  181. const GLFWvidmode* desired)
  182. {
  183. int i;
  184. unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
  185. unsigned int rateDiff, leastRateDiff = UINT_MAX;
  186. unsigned int colorDiff, leastColorDiff = UINT_MAX;
  187. const GLFWvidmode* current;
  188. const GLFWvidmode* closest = NULL;
  189. if (!refreshVideoModes(monitor))
  190. return NULL;
  191. for (i = 0; i < monitor->modeCount; i++)
  192. {
  193. current = monitor->modes + i;
  194. colorDiff = 0;
  195. if (desired->redBits != GLFW_DONT_CARE)
  196. colorDiff += abs(current->redBits - desired->redBits);
  197. if (desired->greenBits != GLFW_DONT_CARE)
  198. colorDiff += abs(current->greenBits - desired->greenBits);
  199. if (desired->blueBits != GLFW_DONT_CARE)
  200. colorDiff += abs(current->blueBits - desired->blueBits);
  201. sizeDiff = abs((current->width - desired->width) *
  202. (current->width - desired->width) +
  203. (current->height - desired->height) *
  204. (current->height - desired->height));
  205. if (desired->refreshRate != GLFW_DONT_CARE)
  206. rateDiff = abs(current->refreshRate - desired->refreshRate);
  207. else
  208. rateDiff = UINT_MAX - current->refreshRate;
  209. if ((colorDiff < leastColorDiff) ||
  210. (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
  211. (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
  212. {
  213. closest = current;
  214. leastSizeDiff = sizeDiff;
  215. leastRateDiff = rateDiff;
  216. leastColorDiff = colorDiff;
  217. }
  218. }
  219. return closest;
  220. }
  221. // Performs lexical comparison between two @ref GLFWvidmode structures
  222. //
  223. int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
  224. {
  225. return compareVideoModes(fm, sm);
  226. }
  227. // Splits a color depth into red, green and blue bit depths
  228. //
  229. void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
  230. {
  231. int delta;
  232. // We assume that by 32 the user really meant 24
  233. if (bpp == 32)
  234. bpp = 24;
  235. // Convert "bits per pixel" to red, green & blue sizes
  236. *red = *green = *blue = bpp / 3;
  237. delta = bpp - (*red * 3);
  238. if (delta >= 1)
  239. *green = *green + 1;
  240. if (delta == 2)
  241. *red = *red + 1;
  242. }
  243. //////////////////////////////////////////////////////////////////////////
  244. ////// GLFW public API //////
  245. //////////////////////////////////////////////////////////////////////////
  246. GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
  247. {
  248. assert(count != NULL);
  249. *count = 0;
  250. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  251. *count = _glfw.monitorCount;
  252. return (GLFWmonitor**) _glfw.monitors;
  253. }
  254. GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
  255. {
  256. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  257. if (!_glfw.monitorCount)
  258. return NULL;
  259. return (GLFWmonitor*) _glfw.monitors[0];
  260. }
  261. GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
  262. {
  263. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  264. assert(monitor != NULL);
  265. if (xpos)
  266. *xpos = 0;
  267. if (ypos)
  268. *ypos = 0;
  269. _GLFW_REQUIRE_INIT();
  270. _glfwPlatformGetMonitorPos(monitor, xpos, ypos);
  271. }
  272. GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle,
  273. int* xpos, int* ypos,
  274. int* width, int* height)
  275. {
  276. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  277. assert(monitor != NULL);
  278. if (xpos)
  279. *xpos = 0;
  280. if (ypos)
  281. *ypos = 0;
  282. if (width)
  283. *width = 0;
  284. if (height)
  285. *height = 0;
  286. _GLFW_REQUIRE_INIT();
  287. _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height);
  288. }
  289. GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
  290. {
  291. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  292. assert(monitor != NULL);
  293. if (widthMM)
  294. *widthMM = 0;
  295. if (heightMM)
  296. *heightMM = 0;
  297. _GLFW_REQUIRE_INIT();
  298. if (widthMM)
  299. *widthMM = monitor->widthMM;
  300. if (heightMM)
  301. *heightMM = monitor->heightMM;
  302. }
  303. GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
  304. float* xscale, float* yscale)
  305. {
  306. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  307. assert(monitor != NULL);
  308. if (xscale)
  309. *xscale = 0.f;
  310. if (yscale)
  311. *yscale = 0.f;
  312. _GLFW_REQUIRE_INIT();
  313. _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale);
  314. }
  315. GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
  316. {
  317. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  318. assert(monitor != NULL);
  319. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  320. return monitor->name;
  321. }
  322. GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
  323. {
  324. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  325. assert(monitor != NULL);
  326. _GLFW_REQUIRE_INIT();
  327. monitor->userPointer = pointer;
  328. }
  329. GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
  330. {
  331. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  332. assert(monitor != NULL);
  333. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  334. return monitor->userPointer;
  335. }
  336. GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
  337. {
  338. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  339. _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
  340. return cbfun;
  341. }
  342. GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
  343. {
  344. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  345. assert(monitor != NULL);
  346. assert(count != NULL);
  347. *count = 0;
  348. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  349. if (!refreshVideoModes(monitor))
  350. return NULL;
  351. *count = monitor->modeCount;
  352. return monitor->modes;
  353. }
  354. GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
  355. {
  356. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  357. assert(monitor != NULL);
  358. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  359. if (!_glfwPlatformGetVideoMode(monitor, &monitor->currentMode)) return NULL;
  360. return &monitor->currentMode;
  361. }
  362. GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
  363. {
  364. unsigned int i;
  365. unsigned short* values;
  366. GLFWgammaramp ramp;
  367. const GLFWgammaramp* original;
  368. assert(handle != NULL);
  369. assert(gamma > 0.f);
  370. assert(gamma <= FLT_MAX);
  371. _GLFW_REQUIRE_INIT();
  372. if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
  373. {
  374. _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
  375. return;
  376. }
  377. original = glfwGetGammaRamp(handle);
  378. if (!original)
  379. return;
  380. values = calloc(original->size, sizeof(unsigned short));
  381. for (i = 0; i < original->size; i++)
  382. {
  383. float value;
  384. // Calculate intensity
  385. value = i / (float) (original->size - 1);
  386. // Apply gamma curve
  387. value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
  388. // Clamp to value range
  389. value = fminf(value, 65535.f);
  390. values[i] = (unsigned short) value;
  391. }
  392. ramp.red = values;
  393. ramp.green = values;
  394. ramp.blue = values;
  395. ramp.size = original->size;
  396. glfwSetGammaRamp(handle, &ramp);
  397. free(values);
  398. }
  399. GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
  400. {
  401. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  402. assert(monitor != NULL);
  403. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  404. _glfwFreeGammaArrays(&monitor->currentRamp);
  405. if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp))
  406. return NULL;
  407. return &monitor->currentRamp;
  408. }
  409. GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
  410. {
  411. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  412. assert(monitor != NULL);
  413. assert(ramp != NULL);
  414. assert(ramp->size > 0);
  415. assert(ramp->red != NULL);
  416. assert(ramp->green != NULL);
  417. assert(ramp->blue != NULL);
  418. if (ramp->size <= 0)
  419. {
  420. _glfwInputError(GLFW_INVALID_VALUE,
  421. "Invalid gamma ramp size %i",
  422. ramp->size);
  423. return;
  424. }
  425. _GLFW_REQUIRE_INIT();
  426. if (!monitor->originalRamp.size)
  427. {
  428. if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp))
  429. return;
  430. }
  431. _glfwPlatformSetGammaRamp(monitor, ramp);
  432. }