Commit adcbd294ddac23fdf004452540a03e1e45860f75

Authored by DarkGod
1 parent 5b1dac20

Added requested window positioning option to the VideoOptions dialog. Useful for…

… borderless windows and multi-monitor setups.
... ... @@ -457,14 +457,14 @@ function _M:setResolution(res, force)
457 457
458 458 -- Change the window size
459 459 print("setResolution: switching resolution to", res, r[1], r[2], r[3], r[4], force and "(forced)")
460   - local old_w, old_h, old_f = self.w, self.h, self.fullscreen
  460 + local old_w, old_h, old_f, old_b = self.w, self.h, self.fullscreen, self.borderless
461 461 core.display.setWindowSize(r[1], r[2], r[3], r[4])
462 462
463 463 -- Don't write self.w/h/fullscreen yet
464   - local new_w, new_h, new_f = core.display.size()
  464 + local new_w, new_h, new_f, new_b = core.display.size()
465 465
466 466 -- Check if a resolution change actually happened
467   - if new_w ~= old_w or new_h ~= old_h or new_f ~= old_f then
  467 + if new_w ~= old_w or new_h ~= old_h or new_f ~= old_f or new_b ~= old_b then
468 468 print("setResolution: performing onResolutionChange...\n")
469 469 self:onResolutionChange()
470 470 -- onResolutionChange saves settings...
... ... @@ -486,7 +486,8 @@ function _M:onResolutionChange()
486 486
487 487 -- Get new resolution and save
488 488 self.w, self.h, self.fullscreen, self.borderless = core.display.size()
489   - config.settings.window.size = ("%dx%d%s"):format(self.w, self.h, self.fullscreen and " Fullscreen" or (self.borderless and " Borderless" or " Windowed"))
  489 + config.settings.window.size = ("%dx%d%s"):format(self.w, self.h, self.fullscreen and " Fullscreen" or (self.borderless and " Borderless" or " Windowed"))
  490 +
490 491 self:saveSettings("resolution", ("window.size = '%s'\n"):format(config.settings.window.size))
491 492 print("onResolutionChange: resolution changed to ", self.w, self.h, "from", ow, oh)
492 493
... ... @@ -495,9 +496,13 @@ function _M:onResolutionChange()
495 496 print("onResolutionChange: no game yet!")
496 497 return
497 498 end
  499 +
  500 + -- Redraw existing dialogs
  501 + self:updateVideoDialogs()
498 502
499 503 -- No actual resize
500   - if ow == self.w and oh == self.h then
  504 + if ow == self.w and oh == self.h
  505 + and of == self.fullscreen and ob == self.borderless then
501 506 print("onResolutionChange: no actual resize, no confirm dialog.")
502 507 return
503 508 end
... ... @@ -543,7 +548,26 @@ end
543 548
544 549 --- Called when the game window is moved around
545 550 function _M:onWindowMoved(x, y)
  551 + config.settings.window.pos.x = x
  552 + config.settings.window.pos.y = y
546 553 self:saveSettings("window_pos", ("window.pos = {x=%d, y=%d}\n"):format(x, y))
  554 +
  555 + -- Redraw existing dialogs
  556 + self:updateVideoDialogs()
  557 +end
  558 +
  559 +--- Update any registered video options dialogs with the latest changes.
  560 +function _M:updateVideoDialogs()
  561 + -- Update the video settings dialogs if any are registered.
  562 + -- We don't know which dialog (if any) is VideoOptions, so iterate through.
  563 + --
  564 + -- Note: If the title of the video options dialog changes, this
  565 + -- functionality will break.
  566 + for i, v in ipairs(self.dialogs) do
  567 + if v.title == "Video Options" then
  568 + v.c_list:drawTree()
  569 + end
  570 + end
547 571 end
548 572
549 573 --- Sets the gamma of the window
... ...
... ... @@ -61,7 +61,35 @@ function _M:use(item)
61 61 elseif self.c_bl.checked then mode = " Borderless"
62 62 end
63 63 local r = item.r..mode
64   - game:setResolution(r, true)
  64 + local _, _, w, h = r:find("^([0-9]+)x([0-9]+)")
  65 +
  66 + -- See if we need a restart (confirm).
  67 + if core.display.setWindowSizeRequiresRestart(w, h, self.c_fs.checked
  68 + , self.c_bl.checked) then
  69 + Dialog:yesnoPopup("Engine Restart Required"
  70 + , "Continue?" .. (game.creating_player and "" or " (progress will be saved)")
  71 + , function(restart)
  72 + if restart then
  73 + local resetPos = Dialog:yesnoPopup("Reset Window Position?"
  74 + , "Simply restart or restart+reset window position?"
  75 + , function(simplyRestart)
  76 + if not simplyRestart then
  77 + core.display.setWindowPos(0, 0)
  78 + game:onWindowMoved(0, 0)
  79 + end
  80 + game:setResolution(r, true)
  81 + -- Save game and reboot
  82 + if not game.creating_player then game:saveGame() end
  83 + util.showMainMenu(false, nil, nil
  84 + , game.__mod_info.short_name, game.save_name
  85 + , false)
  86 + end, "Restart", "Restart with reset")
  87 + end
  88 + end, "Yes", "No")
  89 + else
  90 + game:setResolution(r, true)
  91 + end
  92 +
65 93 game:unregisterDialog(self)
66 94 if self.on_change then self.on_change(r) end
67 95 end
... ...
... ... @@ -66,7 +66,7 @@ function _M:generateList()
66 66 list[#list+1] = { zone=zone, name=string.toTString"#GOLD##{bold}#Resolution#WHITE##{normal}#", status=function(item)
67 67 return config.settings.window.size
68 68 end, fct=function(item)
69   - local menu = require("engine.dialogs.DisplayResolution").new(function() self.c_list:drawItem(item) end)
  69 + local menu = require("engine.dialogs.DisplayResolution").new(function() self.c_list:drawItem(item) end)
70 70 game:registerDialog(menu)
71 71 end,}
72 72
... ... @@ -180,6 +180,59 @@ function _M:generateList()
180 180 game:saveSettings("censor_boot", ("censor_boot = %s\n"):format(tostring(config.settings.censor_boot)))
181 181 self.c_list:drawItem(item)
182 182 end,}
183   -
  183 +
  184 + -- *Requested* Window Position
  185 + -- SDL tends to lie about where windows are positioned in fullscreen mode,
  186 + -- so always store the position requests, not the actual positions.
  187 + local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text="Request a specific origin point for the game window.\nThis point corresponds to where the upper left corner of the window will be located.\nUseful when dealing with multiple monitors and borderless windows.\n\nThe default origin is (0,0).\n\nNote: This value will automatically revert after ten seconds if not confirmed by the user.#WHITE#"}
  188 + list[#list+1] = { zone=zone, name=string.toTString"#GOLD##{bold}#Requested Window Position#WHITE##{normal}#", status=function(item)
  189 + local curX, curY = config.settings.window.pos.x, config.settings.window.pos.y
  190 + return table.concat({"(", curX, ",", curY, ")"})
  191 + end, fct=function(item)
  192 + local itemRef = item
  193 + local oldX, oldY = config.settings.window.pos.x, config.settings.window.pos.y
  194 + local newX, newY
  195 + local function revertMove()
  196 + core.display.setWindowPos(oldX, oldY)
  197 + config.settings.window.pos.x = oldX
  198 + config.settings.window.pos.y = oldY
  199 + self.c_list:drawItem(itemRef)
  200 + end
  201 + -- TODO: Maybe change this to a GetText and parse?
  202 + game:registerDialog(GetQuantity.new("Window Origin: X-Coordinate", "Enter the x-coordinate", oldX, 99999
  203 + , function(qty)
  204 + newX=util.bound(qty, -99999, 99999)
  205 + game:registerDialog(GetQuantity.new("Window Origin: Y-Coordinate", "Enter the y-coordinate", oldY, 99999
  206 + , function(qty)
  207 + newY = util.bound(qty, -99999, 99999)
  208 + core.display.setWindowPos(newX, newY)
  209 + config.settings.window.pos.x = newX
  210 + config.settings.window.pos.y = newY
  211 + self.c_list:drawItem(itemRef)
  212 + local userAnswered = false
  213 + local confirmDialog = Dialog:yesnoPopup("Position changed.", "Save position?"
  214 + , function(ret)
  215 + userAnswered = true
  216 + if ret then
  217 + -- Write out settings
  218 + game:onWindowMoved(newX, newY)
  219 + else
  220 + -- Revert
  221 + revertMove()
  222 + end
  223 + end
  224 + , "Accept", "Revert")
  225 + game:registerTimer(10
  226 + , function()
  227 + -- Blast out changes if no response
  228 + if not userAnswered then
  229 + game:unregisterDialog(confirmDialog)
  230 + revertMove()
  231 + end
  232 + end )
  233 + end, -99999))
  234 + end, -99999))
  235 + end,}
  236 +
184 237 self.list = list
185 238 end
... ...
... ... @@ -125,7 +125,7 @@ function _M:generate()
125 125 end,
126 126 __TEXTINPUT = function(c)
127 127 if self.first then self.first = false self.tmp = {} self.cursor = 1 end
128   - if #self.tmp and (c == '0' or c == '1' or c == '2' or c == '3' or c == '4' or c == '5' or c == '6' or c == '7' or c == '8' or c == '9') then
  128 + if #self.tmp and (c == '-' or c == '0' or c == '1' or c == '2' or c == '3' or c == '4' or c == '5' or c == '6' or c == '7' or c == '8' or c == '9') then
129 129 table.insert(self.tmp, self.cursor, c)
130 130 self.cursor = self.cursor + 1
131 131 self.scroll = util.scroll(self.cursor, self.scroll, self.max_display)
... ...
... ... @@ -1888,7 +1888,7 @@ function util.showMainMenu(no_reboot, reboot_engine, reboot_engine_version, rebo
1888 1888 core.game.setRealtime(0)
1889 1889
1890 1890 -- Save any remaining files
1891   - savefile_pipe:forceWait()
  1891 + if savefile_pipe then savefile_pipe:forceWait() end
1892 1892
1893 1893 if game and type(game) == "table" and game.__session_time_played_start then
1894 1894 if game.onDealloc then game:onDealloc() end
... ...
... ... @@ -267,7 +267,7 @@ static GLenum sdl_gl_texture_format(SDL_Surface *s) {
267 267 static char *largest_black = NULL;
268 268 static int largest_size = 0;
269 269 void make_texture_for_surface(SDL_Surface *s, int *fw, int *fh, bool clamp) {
270   - // Paramétrage de la texture.
  270 + // Paramétrage de la texture.
271 271 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_BORDER : GL_REPEAT);
272 272 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_BORDER : GL_REPEAT);
273 273 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
... ... @@ -574,6 +574,15 @@ static int sdl_screen_size(lua_State *L)
574 574 return 4;
575 575 }
576 576
  577 +static int sdl_window_pos(lua_State *L)
  578 +{
  579 + int x, y;
  580 + SDL_GetWindowPosition(window, &x, &y);
  581 + lua_pushnumber(L, x);
  582 + lua_pushnumber(L, y);
  583 + return 2;
  584 +}
  585 +
577 586 static int sdl_new_font(lua_State *L)
578 587 {
579 588 const char *name = luaL_checkstring(L, 1);
... ... @@ -2327,12 +2336,23 @@ static int sdl_set_window_size(lua_State *L)
2327 2336 return 1;
2328 2337 }
2329 2338
2330   -static int sdl_set_window_pos(lua_State *L)
  2339 +static int sdl_set_window_size_restart_check(lua_State *L)
2331 2340 {
2332 2341 int w = luaL_checknumber(L, 1);
2333 2342 int h = luaL_checknumber(L, 2);
  2343 + bool fullscreen = lua_toboolean(L, 3);
  2344 + bool borderless = lua_toboolean(L, 4);
  2345 +
  2346 + lua_pushboolean(L, resizeNeedsNewWindow(w, h, fullscreen, borderless));
  2347 + return 1;
  2348 +}
  2349 +
  2350 +static int sdl_set_window_pos(lua_State *L)
  2351 +{
  2352 + int x = luaL_checknumber(L, 1);
  2353 + int y = luaL_checknumber(L, 2);
2334 2354
2335   - SDL_SetWindowPosition(window, w, h);
  2355 + do_move(x, y);
2336 2356
2337 2357 lua_pushboolean(L, TRUE);
2338 2358 return 1;
... ... @@ -2923,6 +2943,7 @@ static const struct luaL_Reg displaylib[] =
2923 2943 {"getTextBlended", get_text_aa},
2924 2944 {"forceRedraw", sdl_redraw_screen},
2925 2945 {"size", sdl_screen_size},
  2946 + {"windowPos", sdl_window_pos},
2926 2947 {"newFont", sdl_new_font},
2927 2948 {"newSurface", sdl_new_surface},
2928 2949 {"newTile", sdl_new_tile},
... ... @@ -2940,6 +2961,7 @@ static const struct luaL_Reg displaylib[] =
2940 2961 {"loadImageMemory", sdl_load_image_mem},
2941 2962 {"setWindowTitle", sdl_set_window_title},
2942 2963 {"setWindowSize", sdl_set_window_size},
  2964 + {"setWindowSizeRequiresRestart", sdl_set_window_size_restart_check},
2943 2965 {"setWindowPos", sdl_set_window_pos},
2944 2966 {"getModesList", sdl_get_modes_list},
2945 2967 {"setMouseCursor", sdl_set_mouse_cursor},
... ...
... ... @@ -50,12 +50,14 @@
50 50 #define WIDTH 800
51 51 #define HEIGHT 600
52 52 #define DEFAULT_IDLE_FPS (2)
  53 +#define WINDOW_ICON_PATH ("/engines/default/data/gfx/te4-icon.png")
53 54
54 55 int start_xpos = -1, start_ypos = -1;
55 56 char *override_home = NULL;
56 57 int g_argc = 0;
57 58 char **g_argv;
58 59 SDL_Window *window = NULL;
  60 +SDL_Surface *windowIconSurface = NULL;
59 61 SDL_GLContext maincontext; /* Our opengl context handle */
60 62 bool is_fullscreen = FALSE;
61 63 bool is_borderless = FALSE;
... ... @@ -805,21 +807,81 @@ int resizeWindow(int width, int height)
805 807 return( TRUE );
806 808 }
807 809
  810 +/* @see main.h#resizeNeedsNewWindow */
  811 +extern bool resizeNeedsNewWindow(int w, int h, bool fullscreen, bool borderless)
  812 +{
  813 + /* Note: w and h currently not a factor */
  814 + bool newWindowNeeded = window && ( (is_borderless && !borderless)
  815 + || (!is_borderless && borderless) );
  816 + return (newWindowNeeded);
  817 +}
  818 +
  819 +/* @see main.h#do_move */
  820 +void do_move(int w, int h) {
  821 + /* Save the origin in case a window needs to be remade later. */
  822 + start_xpos = w;
  823 + start_ypos = h;
  824 +
  825 + /* Can't move a fullscreen SDL window in one go.*/
  826 + if (is_fullscreen) {
  827 + /* Drop out of fullscreen so we can move the window. */
  828 + SDL_SetWindowFullscreen(window, SDL_FALSE);
  829 +
  830 + }
  831 +
  832 + /* Move the window */
  833 + SDL_SetWindowPosition(window, w, h);
  834 +
  835 + /* Jump back into fullscreen if necessary */
  836 + if (is_fullscreen) {
  837 + if (!SDL_SetWindowFullscreen(window, SDL_TRUE)) {
  838 + /* Fullscreen change successful */
  839 + is_fullscreen = SDL_TRUE;
  840 +
  841 + } else {
  842 + /* Error switching fullscreen mode */
  843 + printf("[DO MOVE] Unable to return window"
  844 + " to fullscreen mode: %s\n", SDL_GetError());
  845 + SDL_ClearError();
  846 + }
  847 +
  848 + }
  849 +
  850 +}
  851 +
  852 +/* @see main.h#do_resize */
808 853 void do_resize(int w, int h, bool fullscreen, bool borderless)
809 854 {
810 855 /* Temporary width, height (since SDL might reject our resize) */
811 856 int aw, ah;
812 857 int mustPushEvent = 0;
  858 + int mustCreateIconSurface = 0;
813 859 SDL_Event fsEvent;
814 860
815 861 printf("[DO RESIZE] Requested: %dx%d (%d, %d)\n", w, h, fullscreen, borderless);
816 862
  863 + /* See if we need to reinitialize the window */
  864 + if (resizeNeedsNewWindow(w, h, fullscreen, borderless)) {
  865 + /* Destroy the current window */
  866 + SDL_GL_DeleteContext(maincontext);
  867 + SDL_DestroyWindow(window);
  868 + maincontext = 0;
  869 + window = 0;
  870 + screen = 0;
  871 + /* Clean up the old window icon */
  872 + SDL_FreeSurface(windowIconSurface);
  873 + windowIconSurface = 0;
  874 + /* Signal a new icon needs to be created. */
  875 + mustCreateIconSurface = 1;
  876 + }
  877 +
817 878 /* If there is no current window, we have to make one and initialize */
818 879 if (!window) {
819 880 window = SDL_CreateWindow("TE4",
820 881 (start_xpos == -1) ? SDL_WINDOWPOS_CENTERED : start_xpos,
821 882 (start_ypos == -1) ? SDL_WINDOWPOS_CENTERED : start_ypos, w, h,
822   - SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
  883 + SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL
  884 + | (!borderless ? SDL_WINDOW_RESIZABLE : 0)
823 885 | (fullscreen ? SDL_WINDOW_FULLSCREEN : 0)
824 886 | (borderless ? SDL_WINDOW_BORDERLESS : 0)
825 887 );
... ... @@ -834,7 +896,13 @@ void do_resize(int w, int h, bool fullscreen, bool borderless)
834 896 SDL_GL_MakeCurrent(window, maincontext);
835 897 glewInit();
836 898
  899 + /* Set the window icon. */
  900 + windowIconSurface = IMG_Load_RW(PHYSFSRWOPS_openRead(WINDOW_ICON_PATH)
  901 + , TRUE);
  902 + SDL_SetWindowIcon(window, windowIconSurface);
  903 +
837 904 } else {
  905 +
838 906 /* SDL won't allow a fullscreen resolution change in one go. Check. */
839 907 if (is_fullscreen) {
840 908 /* Drop out of fullscreen so we can change resolution. */
... ... @@ -846,8 +914,6 @@ void do_resize(int w, int h, bool fullscreen, bool borderless)
846 914
847 915 /* Update window size */
848 916 SDL_SetWindowSize(window, w, h);
849   - SDL_SetWindowBordered(window, !borderless);
850   - is_borderless = borderless;
851 917
852 918 /* Jump [back] into fullscreen if requested */
853 919 if (fullscreen) {
... ... @@ -863,11 +929,12 @@ void do_resize(int w, int h, bool fullscreen, bool borderless)
863 929 }
864 930
865 931 } else if (mustPushEvent) {
  932 + /* Handle fullscreen -> nonfullscreen transition */
866 933 /*
867 934 * Our changes will get clobbered by an automatic event from
868 935 * setWindowFullscreen. Push an event to the event loop to make
869   - * sure these changes are applied after whatever that other event
870   - * throws.
  936 + * sure these changes are applied after whatever that other
  937 + * event throws.
871 938 */
872 939 /* Create an event to push */
873 940 fsEvent.type = SDL_WINDOWEVENT;
... ... @@ -887,12 +954,8 @@ void do_resize(int w, int h, bool fullscreen, bool borderless)
887 954 /* Finally, update the screen info */
888 955 screen = SDL_GetWindowSurface(window);
889 956
890   -
891 957 }
892 958
893   -
894   - if (is_borderless) SDL_SetWindowPosition(window, 0, 0);
895   -
896 959 /* Check and see if SDL honored our resize request */
897 960 SDL_GetWindowSize(window, &aw, &ah);
898 961 printf("[DO RESIZE] Got: %dx%d (%d, %d)\n", aw, ah, is_fullscreen, borderless);
... ... @@ -1209,7 +1272,7 @@ int main(int argc, char *argv[])
1209 1272 printf("error opening screen: %s\n", SDL_GetError());
1210 1273 return 3;
1211 1274 }
1212   - SDL_SetWindowIcon(window, IMG_Load_RW(PHYSFSRWOPS_openRead("/engines/default/data/gfx/te4-icon.png"), TRUE));
  1275 +
1213 1276 SDL_SetWindowTitle(window, "T4Engine");
1214 1277 TTF_Init();
1215 1278
... ... @@ -1277,18 +1340,23 @@ int main(int argc, char *argv[])
1277 1340 break;
1278 1341 case SDL_WINDOWEVENT_MOVED: {
1279 1342 int x, y;
1280   - SDL_GetWindowPosition(window, &x, &y);
1281   - printf("move %d x %d\n", x, y);
1282   - if (current_game != LUA_NOREF)
1283   - {
1284   - lua_rawgeti(L, LUA_REGISTRYINDEX, current_game);
1285   - lua_pushstring(L, "onWindowMoved");
1286   - lua_gettable(L, -2);
1287   - lua_remove(L, -2);
1288   - lua_rawgeti(L, LUA_REGISTRYINDEX, current_game);
1289   - lua_pushnumber(L, x);
1290   - lua_pushnumber(L, y);
1291   - docall(L, 3, 0);
  1343 + /* Note: SDL can't resize a fullscreen window, so don't bother! */
  1344 + if (!is_fullscreen) {
  1345 + SDL_GetWindowPosition(window, &x, &y);
  1346 + printf("move %d x %d\n", x, y);
  1347 + if (current_game != LUA_NOREF)
  1348 + {
  1349 + lua_rawgeti(L, LUA_REGISTRYINDEX, current_game);
  1350 + lua_pushstring(L, "onWindowMoved");
  1351 + lua_gettable(L, -2);
  1352 + lua_remove(L, -2);
  1353 + lua_rawgeti(L, LUA_REGISTRYINDEX, current_game);
  1354 + lua_pushnumber(L, x);
  1355 + lua_pushnumber(L, y);
  1356 + docall(L, 3, 0);
  1357 + }
  1358 + } else {
  1359 + printf("SDL_WINDOWEVENT_MOVED: ignored due to fullscreen\n");
1292 1360 }
1293 1361 break;
1294 1362 }
... ...
... ... @@ -34,7 +34,26 @@
34 34 #endif
35 35
36 36 extern int resizeWindow(int width, int height);
  37 +
  38 +/**
  39 + * Will the requested do_resize call require a new window?
  40 + */
  41 +extern bool resizeNeedsNewWindow(int w, int h, bool fullscreen, bool borderless);
  42 +
  43 +/**
  44 + * Move the window. Handles both windowed and fullscreen window moves.
  45 + */
  46 +void do_move(int w, int h);
  47 +
  48 +/**
  49 + * Handle a resolution change request.
  50 + *
  51 + * The three window modes supported are windowed, borderless windowed,
  52 + * and fullscreen. These three modes are mutually exclusive, with the
  53 + * fullscreen flag taking priority over the borderless flag.
  54 + */
37 55 extern void do_resize(int w, int h, bool fullscreen, bool borderless);
  56 +
38 57 extern void setupRealtime(float freq);
39 58 extern void setupDisplayTimer(int fps);
40 59 extern int docall (lua_State *L, int narg, int nret);
... ...