monitor.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. //========================================================================
  2. // GLFW 3.4 - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2002-2006 Marcus Geelnard
  5. // Copyright (c) 2006-2019 Camilla Löwy <[email protected]>
  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 = (GLFWvidmode*)fp;
  41. const GLFWvidmode* sm = (GLFWvidmode*)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 GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
  61. {
  62. int modeCount;
  63. GLFWvidmode* modes;
  64. if (monitor->modes)
  65. return GLFW_TRUE;
  66. modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
  67. if (!modes)
  68. return GLFW_FALSE;
  69. qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
  70. free(monitor->modes);
  71. monitor->modes = modes;
  72. monitor->modeCount = modeCount;
  73. return GLFW_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. (_GLFWmonitor**)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. _glfw.monitorCount--;
  117. memmove(_glfw.monitors + i,
  118. _glfw.monitors + i + 1,
  119. ((size_t) _glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
  120. break;
  121. }
  122. }
  123. }
  124. if (_glfw.callbacks.monitor)
  125. _glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
  126. if (action == GLFW_DISCONNECTED)
  127. _glfwFreeMonitor(monitor);
  128. }
  129. // Notifies shared code that a full screen window has acquired or released
  130. // a monitor
  131. //
  132. void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
  133. {
  134. monitor->window = window;
  135. }
  136. //////////////////////////////////////////////////////////////////////////
  137. ////// GLFW internal API //////
  138. //////////////////////////////////////////////////////////////////////////
  139. // Allocates and returns a monitor object with the specified name and dimensions
  140. //
  141. _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
  142. {
  143. _GLFWmonitor* monitor = (_GLFWmonitor*)calloc(1, sizeof(_GLFWmonitor));
  144. monitor->widthMM = widthMM;
  145. monitor->heightMM = heightMM;
  146. if (name)
  147. monitor->name = _glfw_strdup(name);
  148. return monitor;
  149. }
  150. // Frees a monitor object and any data associated with it
  151. //
  152. void _glfwFreeMonitor(_GLFWmonitor* monitor)
  153. {
  154. if (monitor == NULL)
  155. return;
  156. _glfwPlatformFreeMonitor(monitor);
  157. _glfwFreeGammaArrays(&monitor->originalRamp);
  158. _glfwFreeGammaArrays(&monitor->currentRamp);
  159. free(monitor->modes);
  160. free(monitor->name);
  161. free(monitor);
  162. }
  163. // Allocates red, green and blue value arrays of the specified size
  164. //
  165. void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
  166. {
  167. ramp->red = (unsigned short*)calloc(size, sizeof(unsigned short));
  168. ramp->green = (unsigned short*)calloc(size, sizeof(unsigned short));
  169. ramp->blue = (unsigned short*)calloc(size, sizeof(unsigned short));
  170. ramp->size = size;
  171. }
  172. // Frees the red, green and blue value arrays and clears the struct
  173. //
  174. void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
  175. {
  176. free(ramp->red);
  177. free(ramp->green);
  178. free(ramp->blue);
  179. memset(ramp, 0, sizeof(GLFWgammaramp));
  180. }
  181. // Chooses the video mode most closely matching the desired one
  182. //
  183. const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
  184. const GLFWvidmode* desired)
  185. {
  186. int i;
  187. unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
  188. unsigned int rateDiff, leastRateDiff = UINT_MAX;
  189. unsigned int colorDiff, leastColorDiff = UINT_MAX;
  190. const GLFWvidmode* current;
  191. const GLFWvidmode* closest = NULL;
  192. if (!refreshVideoModes(monitor))
  193. return NULL;
  194. for (i = 0; i < monitor->modeCount; i++)
  195. {
  196. current = monitor->modes + i;
  197. colorDiff = 0;
  198. if (desired->redBits != GLFW_DONT_CARE)
  199. colorDiff += abs(current->redBits - desired->redBits);
  200. if (desired->greenBits != GLFW_DONT_CARE)
  201. colorDiff += abs(current->greenBits - desired->greenBits);
  202. if (desired->blueBits != GLFW_DONT_CARE)
  203. colorDiff += abs(current->blueBits - desired->blueBits);
  204. sizeDiff = abs((current->width - desired->width) *
  205. (current->width - desired->width) +
  206. (current->height - desired->height) *
  207. (current->height - desired->height));
  208. if (desired->refreshRate != GLFW_DONT_CARE)
  209. rateDiff = abs(current->refreshRate - desired->refreshRate);
  210. else
  211. rateDiff = UINT_MAX - current->refreshRate;
  212. if ((colorDiff < leastColorDiff) ||
  213. (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
  214. (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
  215. {
  216. closest = current;
  217. leastSizeDiff = sizeDiff;
  218. leastRateDiff = rateDiff;
  219. leastColorDiff = colorDiff;
  220. }
  221. }
  222. return closest;
  223. }
  224. // Performs lexical comparison between two @ref GLFWvidmode structures
  225. //
  226. int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
  227. {
  228. return compareVideoModes(fm, sm);
  229. }
  230. // Splits a color depth into red, green and blue bit depths
  231. //
  232. void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
  233. {
  234. int delta;
  235. // We assume that by 32 the user really meant 24
  236. if (bpp == 32)
  237. bpp = 24;
  238. // Convert "bits per pixel" to red, green & blue sizes
  239. *red = *green = *blue = bpp / 3;
  240. delta = bpp - (*red * 3);
  241. if (delta >= 1)
  242. *green = *green + 1;
  243. if (delta == 2)
  244. *red = *red + 1;
  245. }
  246. //////////////////////////////////////////////////////////////////////////
  247. ////// GLFW public API //////
  248. //////////////////////////////////////////////////////////////////////////
  249. GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
  250. {
  251. assert(count != NULL);
  252. *count = 0;
  253. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  254. *count = _glfw.monitorCount;
  255. return (GLFWmonitor**) _glfw.monitors;
  256. }
  257. GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
  258. {
  259. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  260. if (!_glfw.monitorCount)
  261. return NULL;
  262. return (GLFWmonitor*) _glfw.monitors[0];
  263. }
  264. GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
  265. {
  266. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  267. assert(monitor != NULL);
  268. if (xpos)
  269. *xpos = 0;
  270. if (ypos)
  271. *ypos = 0;
  272. _GLFW_REQUIRE_INIT();
  273. _glfwPlatformGetMonitorPos(monitor, xpos, ypos);
  274. }
  275. GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle,
  276. int* xpos, int* ypos,
  277. int* width, int* height)
  278. {
  279. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  280. assert(monitor != NULL);
  281. if (xpos)
  282. *xpos = 0;
  283. if (ypos)
  284. *ypos = 0;
  285. if (width)
  286. *width = 0;
  287. if (height)
  288. *height = 0;
  289. _GLFW_REQUIRE_INIT();
  290. _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height);
  291. }
  292. GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
  293. {
  294. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  295. assert(monitor != NULL);
  296. if (widthMM)
  297. *widthMM = 0;
  298. if (heightMM)
  299. *heightMM = 0;
  300. _GLFW_REQUIRE_INIT();
  301. if (widthMM)
  302. *widthMM = monitor->widthMM;
  303. if (heightMM)
  304. *heightMM = monitor->heightMM;
  305. }
  306. GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
  307. float* xscale, float* yscale)
  308. {
  309. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  310. assert(monitor != NULL);
  311. if (xscale)
  312. *xscale = 0.f;
  313. if (yscale)
  314. *yscale = 0.f;
  315. _GLFW_REQUIRE_INIT();
  316. _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale);
  317. }
  318. GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
  319. {
  320. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  321. assert(monitor != NULL);
  322. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  323. return monitor->name;
  324. }
  325. GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
  326. {
  327. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  328. assert(monitor != NULL);
  329. _GLFW_REQUIRE_INIT();
  330. monitor->userPointer = pointer;
  331. }
  332. GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
  333. {
  334. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  335. assert(monitor != NULL);
  336. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  337. return monitor->userPointer;
  338. }
  339. GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
  340. {
  341. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  342. _GLFW_SWAP_POINTERS(GLFWmonitorfun, _glfw.callbacks.monitor, cbfun);
  343. return cbfun;
  344. }
  345. GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
  346. {
  347. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  348. assert(monitor != NULL);
  349. assert(count != NULL);
  350. *count = 0;
  351. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  352. if (!refreshVideoModes(monitor))
  353. return NULL;
  354. *count = monitor->modeCount;
  355. return monitor->modes;
  356. }
  357. GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
  358. {
  359. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  360. assert(monitor != NULL);
  361. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  362. _glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
  363. return &monitor->currentMode;
  364. }
  365. GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
  366. {
  367. unsigned int i;
  368. unsigned short* values;
  369. GLFWgammaramp ramp;
  370. const GLFWgammaramp* original;
  371. assert(handle != NULL);
  372. assert(gamma > 0.f);
  373. assert(gamma <= FLT_MAX);
  374. _GLFW_REQUIRE_INIT();
  375. if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
  376. {
  377. _glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
  378. return;
  379. }
  380. original = glfwGetGammaRamp(handle);
  381. if (!original)
  382. return;
  383. values = (unsigned short*)calloc(original->size, sizeof(unsigned short));
  384. for (i = 0; i < original->size; i++)
  385. {
  386. float value;
  387. // Calculate intensity
  388. value = i / (float) (original->size - 1);
  389. // Apply gamma curve
  390. value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
  391. // Clamp to value range
  392. value = _glfw_fminf(value, 65535.f);
  393. values[i] = (unsigned short) value;
  394. }
  395. ramp.red = values;
  396. ramp.green = values;
  397. ramp.blue = values;
  398. ramp.size = original->size;
  399. glfwSetGammaRamp(handle, &ramp);
  400. free(values);
  401. }
  402. GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
  403. {
  404. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  405. assert(monitor != NULL);
  406. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  407. _glfwFreeGammaArrays(&monitor->currentRamp);
  408. if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp))
  409. return NULL;
  410. return &monitor->currentRamp;
  411. }
  412. GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
  413. {
  414. _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
  415. assert(monitor != NULL);
  416. assert(ramp != NULL);
  417. assert(ramp->size > 0);
  418. assert(ramp->red != NULL);
  419. assert(ramp->green != NULL);
  420. assert(ramp->blue != NULL);
  421. if (ramp->size <= 0)
  422. {
  423. _glfwInputError(GLFW_INVALID_VALUE,
  424. "Invalid gamma ramp size %i",
  425. ramp->size);
  426. return;
  427. }
  428. _GLFW_REQUIRE_INIT();
  429. if (!monitor->originalRamp.size)
  430. {
  431. if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp))
  432. return;
  433. }
  434. _glfwPlatformSetGammaRamp(monitor, ramp);
  435. }