1 /**
2  * Copyright (c) 2006-2019 LOVE Development Team
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty.  In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  *    claim that you wrote the original software. If you use this software
14  *    in a product, an acknowledgment in the product documentation would be
15  *    appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  *    misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  **/
20 
21 #include "wrap_Window.h"
22 #include "sdl/Window.h"
23 
24 namespace love
25 {
26 namespace window
27 {
28 
29 #define instance() (Module::getInstance<Window>(Module::M_WINDOW))
30 
w_getDisplayCount(lua_State * L)31 int w_getDisplayCount(lua_State *L)
32 {
33 	lua_pushinteger(L, instance()->getDisplayCount());
34 	return 1;
35 }
36 
w_getDisplayName(lua_State * L)37 int w_getDisplayName(lua_State *L)
38 {
39 	int index = (int) luaL_checkinteger(L, 1) - 1;
40 
41 	const char *name = nullptr;
42 	luax_catchexcept(L, [&](){ name = instance()->getDisplayName(index); });
43 
44 	lua_pushstring(L, name);
45 	return 1;
46 }
47 
settingName(Window::Setting setting)48 static const char *settingName(Window::Setting setting)
49 {
50 	const char *name = nullptr;
51 	Window::getConstant(setting, name);
52 	return name;
53 }
54 
readWindowSettings(lua_State * L,int idx,WindowSettings & settings)55 static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings)
56 {
57 	luax_checktablefields<Window::Setting>(L, idx, "window setting", Window::getConstant);
58 
59 	lua_getfield(L, idx, settingName(Window::SETTING_FULLSCREEN_TYPE));
60 	if (!lua_isnoneornil(L, -1))
61 	{
62 		const char *typestr = luaL_checkstring(L, -1);
63 		if (!Window::getConstant(typestr, settings.fstype))
64 			return luax_enumerror(L, "fullscreen type", Window::getConstants(settings.fstype), typestr);
65 	}
66 	lua_pop(L, 1);
67 
68 	settings.fullscreen = luax_boolflag(L, idx, settingName(Window::SETTING_FULLSCREEN), settings.fullscreen);
69 	settings.msaa = luax_intflag(L, idx, settingName(Window::SETTING_MSAA), settings.msaa);
70 	settings.stencil = luax_boolflag(L, idx, settingName(Window::SETTING_STENCIL), settings.stencil);
71 	settings.depth = luax_intflag(L, idx, settingName(Window::SETTING_DEPTH), settings.depth);
72 	settings.resizable = luax_boolflag(L, idx, settingName(Window::SETTING_RESIZABLE), settings.resizable);
73 	settings.minwidth = luax_intflag(L, idx, settingName(Window::SETTING_MIN_WIDTH), settings.minwidth);
74 	settings.minheight = luax_intflag(L, idx, settingName(Window::SETTING_MIN_HEIGHT), settings.minheight);
75 	settings.borderless = luax_boolflag(L, idx, settingName(Window::SETTING_BORDERLESS), settings.borderless);
76 	settings.centered = luax_boolflag(L, idx, settingName(Window::SETTING_CENTERED), settings.centered);
77 	settings.display = luax_intflag(L, idx, settingName(Window::SETTING_DISPLAY), settings.display+1) - 1;
78 	settings.highdpi = luax_boolflag(L, idx, settingName(Window::SETTING_HIGHDPI), settings.highdpi);
79 	settings.usedpiscale = luax_boolflag(L, idx, settingName(Window::SETTING_USE_DPISCALE), settings.usedpiscale);
80 
81 	lua_getfield(L, idx, settingName(Window::SETTING_VSYNC));
82 	if (lua_isnumber(L, -1))
83 		settings.vsync = (int) lua_tointeger(L, -1);
84 	else if (lua_isboolean(L, -1))
85 		settings.vsync = lua_toboolean(L, -1);
86 	lua_pop(L, 1);
87 
88 	lua_getfield(L, idx, settingName(Window::SETTING_X));
89 	lua_getfield(L, idx, settingName(Window::SETTING_Y));
90 	settings.useposition = !(lua_isnoneornil(L, -2) && lua_isnoneornil(L, -1));
91 	if (settings.useposition)
92 	{
93 		settings.x = (int) luaL_optinteger(L, -2, 0);
94 		settings.y = (int) luaL_optinteger(L, -1, 0);
95 	}
96 	lua_pop(L, 2);
97 
98 	// We don't explicitly set the refresh rate, it's "read-only".
99 	return 0;
100 }
101 
w_setMode(lua_State * L)102 int w_setMode(lua_State *L)
103 {
104 	int w = (int) luaL_checkinteger(L, 1);
105 	int h = (int) luaL_checkinteger(L, 2);
106 
107 	if (lua_isnoneornil(L, 3))
108 	{
109 		luax_catchexcept(L, [&](){ luax_pushboolean(L, instance()->setWindow(w, h, nullptr)); });
110 		return 1;
111 	}
112 
113 	// Defaults come from WindowSettings itself.
114 	WindowSettings settings;
115 
116 	readWindowSettings(L, 3, settings);
117 
118 	luax_catchexcept(L,
119 		[&](){ luax_pushboolean(L, instance()->setWindow(w, h, &settings)); }
120 	);
121 
122 	return 1;
123 }
124 
w_updateMode(lua_State * L)125 int w_updateMode(lua_State *L)
126 {
127 	int w, h;
128 	WindowSettings settings;
129 	instance()->getWindow(w, h, settings);
130 
131 	if (lua_gettop(L) == 0)
132 		return luaL_error(L, "Expected at least one argument");
133 
134 	int idx = 1;
135 	if (lua_isnumber(L, 1))
136 	{
137 		idx = 3;
138 		w = (int) luaL_checkinteger(L, 1);
139 		h = (int) luaL_checkinteger(L, 2);
140 	}
141 
142 	if (!lua_isnoneornil(L, idx))
143 		readWindowSettings(L, idx, settings);
144 
145 	luax_catchexcept(L,
146 		[&](){ luax_pushboolean(L, instance()->setWindow(w, h, &settings)); }
147 	);
148 	return 1;
149 }
150 
w_getMode(lua_State * L)151 int w_getMode(lua_State *L)
152 {
153 	int w, h;
154 	WindowSettings settings;
155 	instance()->getWindow(w, h, settings);
156 	lua_pushnumber(L, w);
157 	lua_pushnumber(L, h);
158 
159 	if (lua_istable(L, 1))
160 		lua_pushvalue(L, 1);
161 	else
162 		lua_newtable(L);
163 
164 	const char *fstypestr = "desktop";
165 	Window::getConstant(settings.fstype, fstypestr);
166 
167 	lua_pushstring(L, fstypestr);
168 	lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN_TYPE));
169 
170 	luax_pushboolean(L, settings.fullscreen);
171 	lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN));
172 
173 	lua_pushinteger(L, settings.vsync);
174 	lua_setfield(L, -2, settingName(Window::SETTING_VSYNC));
175 
176 	lua_pushinteger(L, settings.msaa);
177 	lua_setfield(L, -2, settingName(Window::SETTING_MSAA));
178 
179 	luax_pushboolean(L, settings.stencil);
180 	lua_setfield(L, -2, settingName(Window::SETTING_STENCIL));
181 
182 	lua_pushinteger(L, settings.depth);
183 	lua_setfield(L, -2, settingName(Window::SETTING_DEPTH));
184 
185 	luax_pushboolean(L, settings.resizable);
186 	lua_setfield(L, -2, settingName(Window::SETTING_RESIZABLE));
187 
188 	lua_pushinteger(L, settings.minwidth);
189 	lua_setfield(L, -2, settingName(Window::SETTING_MIN_WIDTH));
190 
191 	lua_pushinteger(L, settings.minheight);
192 	lua_setfield(L, -2, settingName(Window::SETTING_MIN_HEIGHT));
193 
194 	luax_pushboolean(L, settings.borderless);
195 	lua_setfield(L, -2, settingName(Window::SETTING_BORDERLESS));
196 
197 	luax_pushboolean(L, settings.centered);
198 	lua_setfield(L, -2, settingName(Window::SETTING_CENTERED));
199 
200 	// Display index is 0-based internally and 1-based in Lua.
201 	lua_pushinteger(L, settings.display + 1);
202 	lua_setfield(L, -2, settingName(Window::SETTING_DISPLAY));
203 
204 	luax_pushboolean(L, settings.highdpi);
205 	lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI));
206 
207 	luax_pushboolean(L, settings.usedpiscale);
208 	lua_setfield(L, -2, settingName(Window::SETTING_USE_DPISCALE));
209 
210 	lua_pushnumber(L, settings.refreshrate);
211 	lua_setfield(L, -2, settingName(Window::SETTING_REFRESHRATE));
212 
213 	lua_pushinteger(L, settings.x);
214 	lua_setfield(L, -2, settingName(Window::SETTING_X));
215 
216 	lua_pushinteger(L, settings.y);
217 	lua_setfield(L, -2, settingName(Window::SETTING_Y));
218 
219 	return 3;
220 }
221 
w_getDisplayOrientation(lua_State * L)222 int w_getDisplayOrientation(lua_State *L)
223 {
224 	int displayindex = 0;
225 	if (!lua_isnoneornil(L, 1))
226 		displayindex = (int) luaL_checkinteger(L, 1) - 1;
227 	else
228 	{
229 		int x, y;
230 		instance()->getPosition(x, y, displayindex);
231 	}
232 
233 	const char *orientationstr = nullptr;
234 	if (!Window::getConstant(instance()->getDisplayOrientation(displayindex), orientationstr))
235 		return luaL_error(L, "Unknown display orientation type.");
236 
237 	lua_pushstring(L, orientationstr);
238 	return 1;
239 }
240 
w_getFullscreenModes(lua_State * L)241 int w_getFullscreenModes(lua_State *L)
242 {
243 	int displayindex = 0;
244 	if (!lua_isnoneornil(L, 1))
245 		displayindex = (int) luaL_checkinteger(L, 1) - 1;
246 	else
247 	{
248 		int x, y;
249 		instance()->getPosition(x, y, displayindex);
250 	}
251 
252 	std::vector<Window::WindowSize> modes = instance()->getFullscreenSizes(displayindex);
253 
254 	lua_createtable(L, (int) modes.size(), 0);
255 
256 	for (size_t i = 0; i < modes.size(); i++)
257 	{
258 		lua_pushinteger(L, i + 1);
259 		lua_createtable(L, 0, 2);
260 
261 		// Inner table attribs.
262 
263 		lua_pushinteger(L, modes[i].width);
264 		lua_setfield(L, -2, "width");
265 
266 		lua_pushinteger(L, modes[i].height);
267 		lua_setfield(L, -2, "height");
268 
269 		// Inner table attribs end.
270 
271 		lua_settable(L, -3);
272 	}
273 
274 	return 1;
275 }
276 
w_setFullscreen(lua_State * L)277 int w_setFullscreen(lua_State *L)
278 {
279 	bool fullscreen = luax_checkboolean(L, 1);
280 	Window::FullscreenType fstype = Window::FULLSCREEN_MAX_ENUM;
281 
282 	const char *typestr = lua_isnoneornil(L, 2) ? 0 : luaL_checkstring(L, 2);
283 	if (typestr && !Window::getConstant(typestr, fstype))
284 		return luax_enumerror(L, "fullscreen type", Window::getConstants(fstype), typestr);
285 
286 	bool success = false;
287 	luax_catchexcept(L, [&]() {
288 		if (fstype == Window::FULLSCREEN_MAX_ENUM)
289 			success = instance()->setFullscreen(fullscreen);
290 		else
291 			success = instance()->setFullscreen(fullscreen, fstype);
292 	});
293 
294 	luax_pushboolean(L, success);
295 	return 1;
296 }
297 
w_getFullscreen(lua_State * L)298 int w_getFullscreen(lua_State *L)
299 {
300 	int w, h;
301 	WindowSettings settings;
302 	instance()->getWindow(w, h, settings);
303 
304 	const char *typestr;
305 	if (!Window::getConstant(settings.fstype, typestr))
306 		luaL_error(L, "Unknown fullscreen type.");
307 
308 	luax_pushboolean(L, settings.fullscreen);
309 	lua_pushstring(L, typestr);
310 	return 2;
311 }
312 
w_isOpen(lua_State * L)313 int w_isOpen(lua_State *L)
314 {
315 	luax_pushboolean(L, instance()->isOpen());
316 	return 1;
317 }
318 
w_close(lua_State * L)319 int w_close(lua_State *L)
320 {
321 	luax_catchexcept(L, [&]() { instance()->close(); });
322 	return 0;
323 }
324 
w_getDesktopDimensions(lua_State * L)325 int w_getDesktopDimensions(lua_State *L)
326 {
327 	int width = 0, height = 0;
328 	int displayindex = 0;
329 	if (!lua_isnoneornil(L, 1))
330 		displayindex = (int) luaL_checkinteger(L, 1) - 1;
331 	else
332 	{
333 		int x, y;
334 		instance()->getPosition(x, y, displayindex);
335 	}
336 	instance()->getDesktopDimensions(displayindex, width, height);
337 	lua_pushinteger(L, width);
338 	lua_pushinteger(L, height);
339 	return 2;
340 }
341 
w_setPosition(lua_State * L)342 int w_setPosition(lua_State *L)
343 {
344 	int x = (int) luaL_checkinteger(L, 1);
345 	int y = (int) luaL_checkinteger(L, 2);
346 
347 	int displayindex = 0;
348 	if (!lua_isnoneornil(L, 3))
349 		displayindex = (int) luaL_checkinteger(L, 3) - 1;
350 	else
351 	{
352 		int x_unused, y_unused;
353 		instance()->getPosition(x_unused, y_unused, displayindex);
354 	}
355 
356 	instance()->setPosition(x, y, displayindex);
357 	return 0;
358 }
359 
w_getPosition(lua_State * L)360 int w_getPosition(lua_State *L)
361 {
362 	int x = 0;
363 	int y = 0;
364 	int displayindex = 0;
365 	instance()->getPosition(x, y, displayindex);
366 	lua_pushinteger(L, x);
367 	lua_pushinteger(L, y);
368 	lua_pushinteger(L, displayindex + 1);
369 	return 3;
370 }
371 
w_getSafeArea(lua_State * L)372 int w_getSafeArea(lua_State *L)
373 {
374 	Rect area = instance()->getSafeArea();
375 	lua_pushnumber(L, area.x);
376 	lua_pushnumber(L, area.y);
377 	lua_pushnumber(L, area.w);
378 	lua_pushnumber(L, area.h);
379 	return 4;
380 }
381 
w_setIcon(lua_State * L)382 int w_setIcon(lua_State *L)
383 {
384 	image::ImageData *i = luax_checktype<image::ImageData>(L, 1);
385 	bool success = false;
386 	luax_catchexcept(L, [&]() { success = instance()->setIcon(i); });
387 	luax_pushboolean(L, success);
388 	return 1;
389 }
390 
w_getIcon(lua_State * L)391 int w_getIcon(lua_State *L)
392 {
393 	image::ImageData *i = instance()->getIcon();
394 	luax_pushtype(L, i);
395 	return 1;
396 }
397 
w_setVSync(lua_State * L)398 int w_setVSync(lua_State *L)
399 {
400 	int vsync = 0;
401 	if (lua_type(L, 1) == LUA_TBOOLEAN)
402 		vsync = lua_toboolean(L, 1);
403 	else
404 		vsync = (int)luaL_checkinteger(L, 1);
405 	instance()->setVSync(vsync);
406 	return 0;
407 }
408 
w_getVSync(lua_State * L)409 int w_getVSync(lua_State *L)
410 {
411 	lua_pushinteger(L, instance()->getVSync());
412 	return 1;
413 }
414 
w_setDisplaySleepEnabled(lua_State * L)415 int w_setDisplaySleepEnabled(lua_State *L)
416 {
417 	instance()->setDisplaySleepEnabled(luax_checkboolean(L, 1));
418 	return 0;
419 }
420 
w_isDisplaySleepEnabled(lua_State * L)421 int w_isDisplaySleepEnabled(lua_State *L)
422 {
423 	luax_pushboolean(L, instance()->isDisplaySleepEnabled());
424 	return 1;
425 }
426 
w_setTitle(lua_State * L)427 int w_setTitle(lua_State *L)
428 {
429 	std::string title = luax_checkstring(L, 1);
430 	instance()->setWindowTitle(title);
431 	return 0;
432 }
433 
w_getTitle(lua_State * L)434 int w_getTitle(lua_State *L)
435 {
436 	luax_pushstring(L, instance()->getWindowTitle());
437 	return 1;
438 }
439 
w_hasFocus(lua_State * L)440 int w_hasFocus(lua_State *L)
441 {
442 	luax_pushboolean(L, instance()->hasFocus());
443 	return 1;
444 }
445 
w_hasMouseFocus(lua_State * L)446 int w_hasMouseFocus(lua_State *L)
447 {
448 	luax_pushboolean(L, instance()->hasMouseFocus());
449 	return 1;
450 }
451 
w_isVisible(lua_State * L)452 int w_isVisible(lua_State *L)
453 {
454 	luax_pushboolean(L, instance()->isVisible());
455 	return 1;
456 }
457 
w_getDPIScale(lua_State * L)458 int w_getDPIScale(lua_State *L)
459 {
460 	lua_pushnumber(L, instance()->getDPIScale());
461 	return 1;
462 }
463 
w_getNativeDPIScale(lua_State * L)464 int w_getNativeDPIScale(lua_State *L)
465 {
466 	lua_pushnumber(L, instance()->getNativeDPIScale());
467 	return 1;
468 }
469 
w_toPixels(lua_State * L)470 int w_toPixels(lua_State *L)
471 {
472 	double wx = luaL_checknumber(L, 1);
473 
474 	if (lua_isnoneornil(L, 2))
475 	{
476 		lua_pushnumber(L, instance()->toPixels(wx));
477 		return 1;
478 	}
479 
480 	double wy = luaL_checknumber(L, 2);
481 	double px = 0.0, py = 0.0;
482 
483 	instance()->toPixels(wx, wy, px, py);
484 
485 	lua_pushnumber(L, px);
486 	lua_pushnumber(L, py);
487 
488 	return 2;
489 }
490 
w_fromPixels(lua_State * L)491 int w_fromPixels(lua_State *L)
492 {
493 	double px = luaL_checknumber(L, 1);
494 
495 	if (lua_isnoneornil(L, 2))
496 	{
497 		lua_pushnumber(L, instance()->fromPixels(px));
498 		return 1;
499 	}
500 
501 	double py = luaL_checknumber(L, 2);
502 	double wx = 0.0, wy = 0.0;
503 
504 	instance()->fromPixels(px, py, wx, wy);
505 
506 	lua_pushnumber(L, wx);
507 	lua_pushnumber(L, wy);
508 
509 	return 2;
510 }
511 
w_minimize(lua_State *)512 int w_minimize(lua_State* /*L*/)
513 {
514 	instance()->minimize();
515 	return 0;
516 }
517 
w_maximize(lua_State *)518 int w_maximize(lua_State *)
519 {
520 	instance()->maximize();
521 	return 0;
522 }
523 
w_restore(lua_State *)524 int w_restore(lua_State *)
525 {
526 	instance()->restore();
527 	return 0;
528 }
529 
w_isMaximized(lua_State * L)530 int w_isMaximized(lua_State *L)
531 {
532 	luax_pushboolean(L, instance()->isMaximized());
533 	return 1;
534 }
535 
w_isMinimized(lua_State * L)536 int w_isMinimized(lua_State *L)
537 {
538 	luax_pushboolean(L, instance()->isMinimized());
539 	return 1;
540 }
541 
w_showMessageBox(lua_State * L)542 int w_showMessageBox(lua_State *L)
543 {
544 	Window::MessageBoxData data = {};
545 	data.type = Window::MESSAGEBOX_INFO;
546 
547 	data.title = luaL_checkstring(L, 1);
548 	data.message = luaL_checkstring(L, 2);
549 
550 	// If we have a table argument, we assume a list of button names, which
551 	// means we should use the more complex message box API.
552 	if (lua_istable(L, 3))
553 	{
554 		size_t numbuttons = luax_objlen(L, 3);
555 		if (numbuttons == 0)
556 			return luaL_error(L, "Must have at least one messagebox button.");
557 
558 		// Array of button names.
559 		for (size_t i = 0; i < numbuttons; i++)
560 		{
561 			lua_rawgeti(L, 3, (int) i + 1);
562 			data.buttons.push_back(luax_checkstring(L, -1));
563 			lua_pop(L, 1);
564 		}
565 
566 		// Optional table entry specifying the button to use when enter is pressed.
567 		lua_getfield(L, 3, "enterbutton");
568 		if (!lua_isnoneornil(L, -1))
569 			data.enterButtonIndex = (int) luaL_checkinteger(L, -1) - 1;
570 		else
571 			data.enterButtonIndex = 0;
572 		lua_pop(L, 1);
573 
574 		// Optional table entry specifying the button to use when esc is pressed.
575 		lua_getfield(L, 3, "escapebutton");
576 		if (!lua_isnoneornil(L, -1))
577 			data.escapeButtonIndex = (int) luaL_checkinteger(L, -1) - 1;
578 		else
579 			data.escapeButtonIndex = (int) data.buttons.size() - 1;
580 		lua_pop(L, 1);
581 
582 		const char *typestr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4);
583 		if (typestr && !Window::getConstant(typestr, data.type))
584 			return luax_enumerror(L, "messagebox type", Window::getConstants(data.type), typestr);
585 
586 		data.attachToWindow = luax_optboolean(L, 5, true);
587 
588 		int pressedbutton = instance()->showMessageBox(data);
589 		lua_pushinteger(L, pressedbutton + 1);
590 	}
591 	else
592 	{
593 		const char *typestr = lua_isnoneornil(L, 3) ? nullptr : luaL_checkstring(L, 3);
594 		if (typestr && !Window::getConstant(typestr, data.type))
595 			return luax_enumerror(L, "messagebox type", Window::getConstants(data.type), typestr);
596 
597 		data.attachToWindow = luax_optboolean(L, 4, true);
598 
599 		// Display a simple message box.
600 		bool success = instance()->showMessageBox(data.title, data.message, data.type, data.attachToWindow);
601 		luax_pushboolean(L, success);
602 	}
603 
604 	return 1;
605 }
606 
w_requestAttention(lua_State * L)607 int w_requestAttention(lua_State *L)
608 {
609 	bool continuous = luax_optboolean(L, 1, false);
610 	instance()->requestAttention(continuous);
611 	return 0;
612 }
613 
614 static const luaL_Reg functions[] =
615 {
616 	{ "getDisplayCount", w_getDisplayCount },
617 	{ "getDisplayName", w_getDisplayName },
618 	{ "setMode", w_setMode },
619 	{ "updateMode", w_updateMode },
620 	{ "getMode", w_getMode },
621 	{ "getDisplayOrientation", w_getDisplayOrientation },
622 	{ "getFullscreenModes", w_getFullscreenModes },
623 	{ "setFullscreen", w_setFullscreen },
624 	{ "getFullscreen", w_getFullscreen },
625 	{ "isOpen", w_isOpen },
626 	{ "close", w_close },
627 	{ "getDesktopDimensions", w_getDesktopDimensions },
628 	{ "setPosition", w_setPosition },
629 	{ "getPosition", w_getPosition },
630 	{ "getSafeArea", w_getSafeArea },
631 	{ "setIcon", w_setIcon },
632 	{ "getIcon", w_getIcon },
633 	{ "setVSync", w_setVSync },
634 	{ "getVSync", w_getVSync },
635 	{ "setDisplaySleepEnabled", w_setDisplaySleepEnabled },
636 	{ "isDisplaySleepEnabled", w_isDisplaySleepEnabled },
637 	{ "setTitle", w_setTitle },
638 	{ "getTitle", w_getTitle },
639 	{ "hasFocus", w_hasFocus },
640 	{ "hasMouseFocus", w_hasMouseFocus },
641 	{ "isVisible", w_isVisible },
642 	{ "getDPIScale", w_getDPIScale },
643 	{ "getNativeDPIScale", w_getNativeDPIScale },
644 	{ "toPixels", w_toPixels },
645 	{ "fromPixels", w_fromPixels },
646 	{ "minimize", w_minimize },
647 	{ "maximize", w_maximize },
648 	{ "restore", w_restore },
649 	{ "isMaximized", w_isMaximized },
650 	{ "isMinimized", w_isMinimized },
651 	{ "showMessageBox", w_showMessageBox },
652 	{ "requestAttention", w_requestAttention },
653 	{ 0, 0 }
654 };
655 
luaopen_love_window(lua_State * L)656 extern "C" int luaopen_love_window(lua_State *L)
657 {
658 	Window *instance = instance();
659 	if (instance == nullptr)
660 		luax_catchexcept(L, [&](){ instance = new love::window::sdl::Window(); });
661 	else
662 		instance->retain();
663 
664 	WrappedModule w;
665 	w.module = instance;
666 	w.name = "window";
667 	w.type = &Module::type;
668 	w.functions = functions;
669 	w.types = 0;
670 
671 	return luax_register_module(L, w);
672 }
673 
674 } // window
675 } // love
676