lovr-window.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. local ffi = require 'ffi'
  2. local C = ffi.os == 'Windows' and ffi.load('glfw3') or ffi.C
  3. local C_str = ffi.string
  4. ffi.cdef [[
  5. enum {
  6. GLFW_RESIZABLE = 0x00020003,
  7. GLFW_VISIBLE = 0x00020004,
  8. GLFW_DECORATED = 0x00020005,
  9. GLFW_FLOATING = 0x00020007
  10. };
  11. typedef struct {
  12. int width;
  13. int height;
  14. unsigned char* pixels;
  15. } GLFWimage;
  16. typedef struct GLFWvidmode {
  17. int width;
  18. int height;
  19. int refreshRate;
  20. } GLFWvidmode;
  21. typedef struct GLFWwindow GLFWwindow;
  22. GLFWwindow* os_get_glfw_window(void);
  23. typedef struct GLFWmonitor GLFWmonitor;
  24. GLFWmonitor** glfwGetMonitors(int *count);
  25. GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
  26. GLFWmonitor* glfwGetPrimaryMonitor(void);
  27. void glfwGetMonitorPos(GLFWmonitor* monitor, int *xpos, int *ypos);
  28. const char* glfwGetMonitorName(GLFWmonitor* monitor);
  29. const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
  30. void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
  31. void glfwGetMonitorWorkarea(GLFWmonitor *monitor, int *xpos, int *ypos, int *width, int *height);
  32. // icon
  33. void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage *images);
  34. // attributes
  35. void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value); //+
  36. int glfwGetWindowAttrib(GLFWwindow* window, int attrib); //+
  37. // size & limits
  38. void glfwSetWindowSize(GLFWwindow* window, int width, int height); //-
  39. void glfwGetWindowSize(GLFWwindow* window, int *width, int *height); //-
  40. void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); //-
  41. // position
  42. void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos);
  43. void glfwGetWindowPos(GLFWwindow* window, int *xpos, int *ypos);
  44. // minimize maximize restore
  45. void glfwMaximizeWindow(GLFWwindow* window);
  46. void glfwIconifyWindow(GLFWwindow *window);
  47. void glfwRestoreWindow(GLFWwindow *window);
  48. // title
  49. void glfwSetWindowTitle(GLFWwindow* window, const char* title);
  50. // visible
  51. void glfwShowWindow(GLFWwindow* window);
  52. void glfwHideWindow(GLFWwindow* window);
  53. // focus
  54. void glfwFocusWindow(GLFWwindow* window);
  55. // attention
  56. void glfwRequestWindowAttention(GLFWwindow* window);
  57. // opacity
  58. void glfwSetWindowOpacity(GLFWwindow* window, float opacity);
  59. float glfwGetWindowOpacity(GLFWwindow* window);
  60. // callbacks
  61. typedef void(*GLFWwindowsizefun) (GLFWwindow*, int, int); // size changed
  62. GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun callback );
  63. typedef void(*GLFWwindowmaximizefun) (GLFWwindow*, int); // maximize
  64. GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback);
  65. typedef void(*GLFWwindowposfun) (GLFWwindow*, int, int); // position changed
  66. GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun callback);
  67. typedef void(* GLFWdropfun) (GLFWwindow*, int, const char *[]);
  68. GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback);
  69. ]]
  70. local W = ffi.C.os_get_glfw_window()
  71. local window = {}
  72. local __monitors
  73. ---------------------------------------------------------------------------------------------------------------
  74. local __params = { -- default parameters list
  75. title = 'LÖVR',
  76. icon = nil,
  77. fullscreen = false,
  78. fullscreentype = "desktop",
  79. width = 1080,
  80. height = 600,
  81. minwidth = 320,
  82. minheight = 240,
  83. x = nil,
  84. y = nil,
  85. display = 1,
  86. centered = false,
  87. topmost = false,
  88. borderless = false,
  89. resizable = false,
  90. opacity = 1,
  91. vsync = 1,
  92. msaa = 0
  93. }
  94. if conf then
  95. for k,v in pairs(conf) do
  96. __params[k] = v
  97. end
  98. if type(__params.icon) == 'string' then
  99. __params.icon = lovr.data.newImage(__params.icon, false)
  100. end
  101. conf = nil
  102. end
  103. ---------------------------------------------------------------------------------------------------------------
  104. function window.getDisplayCount()
  105. local count = ffi.new('int[1]')
  106. __monitors = C.glfwGetMonitors(count)
  107. return count[0]
  108. end
  109. local function check_monitor( index, throwerr )
  110. if type(index) ~= 'number' then
  111. if throwerr then
  112. error('Bad argument #1: number expected got ' .. type(index), 3)
  113. else
  114. return false
  115. end
  116. end
  117. local dcnt = window.getDisplayCount()
  118. if index < 1 or index > dcnt then
  119. if throwerr then
  120. error('Invalid display index: ' .. tostring(index), 3)
  121. else
  122. return false
  123. end
  124. end
  125. return true
  126. end
  127. function window.getDisplayName( index )
  128. check_monitor( index, true )
  129. return C_str(C.glfwGetMonitorName( __monitors[index-1] ))
  130. end
  131. function window.getDisplayDimensions( index )
  132. check_monitor( index, true )
  133. local screenmode = C.glfwGetVideoMode( __monitors[index-1] )
  134. return screenmode.width, screenmode.height
  135. end
  136. ---------------------------------------------------------------------------------------------------------------
  137. function window.setIcon( source )
  138. if not source then
  139. C.glfwSetWindowIcon(W, 0, nil)
  140. __params.icon = nil
  141. return
  142. end
  143. if type(source) == 'string' then
  144. source = lovr.data.newImage(source, false)
  145. elseif tostring(source) ~= 'Image' then
  146. error('Bad argument #1 to setIcon (Image expected)', 2)
  147. end
  148. __params.icon = source
  149. local icon = ffi.new('GLFWimage', source:getWidth(), source:getHeight(), source:getBlob():getPointer())
  150. C.glfwSetWindowIcon(W, 1, icon)
  151. end
  152. function window.getIcon()
  153. return tostring(__params.icon) == 'Image' and __params.icon or nil
  154. end
  155. ---------------------------------------------------------------------------------------------------------------
  156. function window.setOpacity( value )
  157. value = math.max(0, math.min(value, 1))
  158. C.glfwSetWindowOpacity(W, value)
  159. end
  160. function window.getOpacity()
  161. return C.glfwGetWindowOpacity(W)
  162. end
  163. ---------------------------------------------------------------------------------------------------------------
  164. function window.setPosition( x,y )
  165. C.glfwSetWindowPos(W, x or 0, y or 0)
  166. end
  167. function window.getPosition()
  168. local x, y = ffi.new('int[1]'), ffi.new('int[1]')
  169. C.glfwGetWindowPos(W, x, y)
  170. return x[0], y[0]
  171. end
  172. ---------------------------------------------------------------------------------------------------------------
  173. function window.maximize()
  174. C.glfwMaximizeWindow(W)
  175. end
  176. function window.minimize()
  177. C.glfwIconifyWindow(W)
  178. end
  179. function window.restore()
  180. C.glfwRestoreWindow(W)
  181. end
  182. function window.focus()
  183. C.glfwFocusWindow(W)
  184. end
  185. function window.requestAttention()
  186. C.glfwRequestWindowAttention(W)
  187. end
  188. ---------------------------------------------------------------------------------------------------------------
  189. function window.setTitle( title )
  190. C.glfwSetWindowTitle(W, title)
  191. __params.title = title
  192. end
  193. function window.getTitle()
  194. return __params.title
  195. end
  196. ---------------------------------------------------------------------------------------------------------------
  197. function window.visible( state )
  198. if state then C.glfwShowWindow(W)
  199. else C.glfwHideWindow(W) end
  200. end
  201. function window.isVisible()
  202. return C.glfwGetWindowAttrib(W, C.GLFW_VISIBLE) == 1
  203. end
  204. ---------------------------------------------------------------------------------------------------------------
  205. function window.setFullscreen( state, fstype, index )
  206. index = index or 1
  207. index = check_monitor(index) and index-1 or 0
  208. local screenmode = C.glfwGetVideoMode( __monitors[index] )
  209. if state then
  210. assert(fstype == 'desktop' or fstype == 'exclusive', 'Invalid fullscreen type \''..tostring(fstype)..'\', expected one of : \'exclusive\' or \'desktop\'')
  211. if fstype == 'desktop' then
  212. C.glfwSetWindowAttrib(W, C.GLFW_DECORATED, 0)
  213. local mx, my = ffi.new('int[1]'), ffi.new('int[1]')
  214. C.glfwGetMonitorPos(__monitors[index], mx, my)
  215. C.glfwSetWindowMonitor(W, nil, mx[0],my[0], screenmode.width, screenmode.height, 0)
  216. elseif fstype == 'exclusive' then
  217. C.glfwSetWindowMonitor(W, __monitors[index], 0,0, screenmode.width, screenmode.height, 0)
  218. end
  219. __params.fullscreentype = fstype
  220. __params.fullscreen = true
  221. else
  222. __params.fullscreen = false
  223. __params.fullscreentype = nil
  224. if __params.x == nil or __params.y == nil then
  225. __params.x = math.random(0, screenmode.width*0.3)
  226. __params.y = math.random(0, screenmode.height*0.3)
  227. centered = false
  228. end
  229. C.glfwSetWindowAttrib(W, C.GLFW_DECORATED, __params.borderless and 0 or 1)
  230. C.glfwSetWindowMonitor(W, nil, __params.x, __params.y, __params.width, __params.height, 0)
  231. end
  232. end
  233. function window.getFullscreen()
  234. __params.fullscreen = C.glfwGetWindowMonitor(W) ~= nil
  235. return __params.fullscreen, __params.fullscreentype
  236. end
  237. ---------------------------------------------------------------------------------------------------------------
  238. function window.getMode()
  239. local flags = {}
  240. flags.fullscreen = C.glfwGetWindowMonitor(W) ~= nil
  241. flags.fullscreentype = __params.fullscreentype
  242. flags.x, flags.y = ffi.new('int[1]'), ffi.new('int[1]')
  243. C.glfwGetWindowPos(W, flags.x, flags.y)
  244. flags.x, flags.y = flags.x[0], flags.y[0]
  245. local width, height = ffi.new('int[1]'), ffi.new('int[1]')
  246. C.glfwGetWindowSize(W, width, height)
  247. width, height = width[0], height[0]
  248. flags.msaa = __params.msaa
  249. flags.vsync = __params.vsync
  250. flags.topmost = C.glfwGetWindowAttrib(W, C.GLFW_FLOATING) == 1
  251. flags.opacity = C.glfwGetWindowOpacity(W)
  252. flags.borderless = C.glfwGetWindowAttrib(W, C.GLFW_DECORATED) == 0
  253. flags.resizable = C.glfwGetWindowAttrib(W, C.GLFW_RESIZABLE) == 1
  254. flags.centered = __params.centered
  255. flags.display = __params.display
  256. flags.minwidth = __params.minwidth
  257. flags.minheight = __params.minheight
  258. return width, height, flags
  259. end
  260. function window.setMode( width, height, flags )
  261. if flags then
  262. local _, _, mode = window.getMode()
  263. for k,v in pairs(mode) do
  264. if not flags[k] or flags[k] == nil then
  265. flags[k] = v
  266. end
  267. end
  268. flags.display = check_monitor(flags.display) and flags.display or 1
  269. if flags.centered then
  270. local screenmode = C.glfwGetVideoMode( __monitors[flags.display-1] )
  271. local mx, my = ffi.new('int[1]'), ffi.new('int[1]')
  272. C.glfwGetMonitorPos(__monitors[flags.display-1], mx, my)
  273. flags.x = mx[0] + screenmode.width*0.5 - width*0.5
  274. flags.y = my[0] + screenmode.height*0.5 - height*0.5
  275. end
  276. C.glfwSetWindowPos(W, flags.x, flags.y)
  277. C.glfwSetWindowSizeLimits(W, flags.minwidth, flags.minheight, -1, -1)
  278. C.glfwSetWindowAttrib(W, C.GLFW_DECORATED, flags.borderless and 0 or 1)
  279. C.glfwSetWindowAttrib(W, C.GLFW_FLOATING, flags.topmost and 1 or 0)
  280. C.glfwSetWindowAttrib(W, C.GLFW_RESIZABLE, flags.resizable and 1 or 0)
  281. flags.opacity = math.max(0, math.min(flags.opacity, 1))
  282. C.glfwSetWindowOpacity(W, flags.opacity)
  283. if flags.fullscreen then
  284. window.setFullscreen(flags.fullscreen, flags.fullscreentype, flags.display)
  285. else
  286. C.glfwSetWindowSize(W, width, height)
  287. end
  288. __params.width = width
  289. __params.height = height
  290. for k,v in pairs(flags) do
  291. __params[k] = v
  292. end
  293. else
  294. C.glfwSetWindowSize(W, width, height)
  295. end
  296. end
  297. ---------------------------------------------------------------------------------------------------------------
  298. C.glfwSetWindowMaximizeCallback(W, function( target, maximized )
  299. local width, height = ffi.new('int[1]'), ffi.new('int[1]')
  300. C.glfwGetWindowSize(W, width, height)
  301. lovr.event.push('maximized', maximized == 1, width[0], height[0])
  302. end)
  303. C.glfwSetWindowPosCallback(W, function( target, x,y )
  304. if lovr.windowmoved then
  305. lovr.windowmoved(x, y)
  306. end
  307. end)
  308. C.glfwSetDropCallback(W, function( target, count, c_paths )
  309. if lovr.dragdrop then
  310. local paths = {}
  311. for i=0, count-1 do
  312. table.insert(paths, C_str(c_paths[i]))
  313. end
  314. lovr.dragdrop(paths)
  315. end
  316. end)
  317. return window