diff --git a/data/core/docview.lua b/data/core/docview.lua index b679eb6f..6ab86fc6 100644 --- a/data/core/docview.lua +++ b/data/core/docview.lua @@ -560,7 +560,7 @@ function DocView:draw_overlay() local T = config.blink_period for _, line1, col1, line2, col2 in self.doc:get_selections() do if line1 >= minline and line1 <= maxline - and system.window_has_focus() then + and system.window_has_focus(core.window) then if ime.editing then self:draw_ime_decoration(line1, col1, line2, col2) else diff --git a/data/core/emptyview.lua b/data/core/emptyview.lua index 2152da3b..5b126e24 100644 --- a/data/core/emptyview.lua +++ b/data/core/emptyview.lua @@ -1,3 +1,4 @@ +local core = require "core" local style = require "core.style" local keymap = require "core.keymap" local View = require "core.view" diff --git a/data/core/init.lua b/data/core/init.lua index ec6cebd5..49732bca 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -27,8 +27,8 @@ local function save_session() local fp = io.open(USERDIR .. PATHSEP .. "session.lua", "w") if fp then fp:write("return {recents=", common.serialize(core.recent_projects), - ", window=", common.serialize(table.pack(system.get_window_size())), - ", window_mode=", common.serialize(system.get_window_mode()), + ", window=", common.serialize(table.pack(system.get_window_size(core.window))), + ", window_mode=", common.serialize(system.get_window_mode(core.window)), ", previous_find=", common.serialize(core.previous_find), ", previous_replace=", common.serialize(core.previous_replace), "}\n") @@ -689,12 +689,16 @@ function core.init() EXEDIR = common.normalize_volume(EXEDIR) end + core.window = renwindow._restore() + if core.window == nil then + core.window = renwindow.create("") + end do local session = load_session() if session.window_mode == "normal" then - system.set_window_size(table.unpack(session.window)) + system.set_window_size(core.window, table.unpack(session.window)) elseif session.window_mode == "maximized" then - system.set_window_mode("maximized") + system.set_window_mode(core.window, "maximized") end core.recent_projects = session.recents or {} core.previous_find = session.previous_find or {} @@ -922,7 +926,10 @@ end function core.restart() - quit_with_function(function() core.restart_request = true end) + quit_with_function(function() + core.restart_request = true + core.window:_persist() + end) end @@ -1309,7 +1316,7 @@ function core.on_event(type, ...) elseif type == "touchmoved" then core.root_view:on_touch_moved(...) elseif type == "resized" then - core.window_mode = system.get_window_mode() + core.window_mode = system.get_window_mode(core.window) elseif type == "minimized" or type == "maximized" or type == "restored" then core.window_mode = type == "restored" and "normal" or type elseif type == "filedropped" then @@ -1356,7 +1363,7 @@ function core.step() core.redraw = true end - local width, height = renderer.get_size() + local width, height = core.window:get_size() -- update core.root_view.size.x, core.root_view.size.y = width, height @@ -1376,12 +1383,12 @@ function core.step() -- update window title local current_title = get_title_filename(core.active_view) if current_title ~= nil and current_title ~= core.window_title then - system.set_window_title(core.compose_window_title(current_title)) + system.set_window_title(core.window, core.compose_window_title(current_title)) core.window_title = current_title end -- draw - renderer.begin_frame() + renderer.begin_frame(core.window) core.clip_rect_stack[1] = { 0, 0, width, height } renderer.set_clip_rect(table.unpack(core.clip_rect_stack[1])) core.root_view:draw() @@ -1453,7 +1460,7 @@ function core.run() if core.restart_request or core.quit_request then break end if not did_redraw then - if system.window_has_focus() or not did_step or run_threads_full < 2 then + if system.window_has_focus(core.window) or not did_step or run_threads_full < 2 then local now = system.get_time() if not next_step then -- compute the time until the next blink local t = now - core.blink_start diff --git a/data/core/nagview.lua b/data/core/nagview.lua index 1a7fa193..b11d0218 100644 --- a/data/core/nagview.lua +++ b/data/core/nagview.lua @@ -54,7 +54,7 @@ function NagView:get_target_height() end function NagView:get_scrollable_size() - local w, h = system.get_window_size() + local w, h = system.get_window_size(core.window) if self.visible and self:get_target_height() > h then self.size.y = h return self:get_target_height() diff --git a/docs/api/renderer.lua b/docs/api/renderer.lua index e912d645..c1936219 100644 --- a/docs/api/renderer.lua +++ b/docs/api/renderer.lua @@ -116,10 +116,13 @@ function renderer.get_size() end --- ---Tell the rendering system that we want to build a new frame to render. -function renderer.begin_frame() end +--- +---@param window renwindow +function renderer.begin_frame(window) end --- ---Tell the rendering system that we finished building the frame. +--- function renderer.end_frame() end --- diff --git a/docs/api/renwindow.lua b/docs/api/renwindow.lua new file mode 100644 index 00000000..d31330e2 --- /dev/null +++ b/docs/api/renwindow.lua @@ -0,0 +1,28 @@ +---@meta + +--- +---Functionality to create and manage windows +---@class renwindow +renwindow = {} + +--- +---Create a new window +--- +--- +--- +---@param x integer? if nil will be undefined +---@param y integer? if nil will be undefined +---@param width integer? if nil or less than 1 will be calculated from display +---@param height integer? if nil or less than 1 will be calculated from display +--- +---@return renwindow +function renwindow.create(x, y, width, height) end + +--- +--- Get width and height of a window +--- +---@param renwindow +--- +---@return number width +---@return number height +function renwindow.get_size(window) end diff --git a/docs/api/system.lua b/docs/api/system.lua index 792fa623..e7f2d2e1 100644 --- a/docs/api/system.lua +++ b/docs/api/system.lua @@ -76,8 +76,9 @@ function system.set_cursor(type) end --- ---Change the window title. --- +---@param window renwindow ---@param title string -function system.set_window_title(title) end +function system.set_window_title(window, title) end ---@alias system.windowmode ---| "normal" @@ -88,14 +89,17 @@ function system.set_window_title(title) end --- ---Change the window mode. --- +---@param window renwindow ---@param mode system.windowmode -function system.set_window_mode(mode) end +function system.set_window_mode(window, mode) end --- ----Retrieve the current window mode. +---Retrieve the window mode. +--- +---@param window renwindow --- ---@return system.windowmode mode -function system.get_window_mode() end +function system.get_window_mode(window) end --- ---Toggle between bordered and borderless. @@ -118,32 +122,31 @@ function system.set_window_hit_test(title_height, controls_width, resize_border) --- ---Get the size and coordinates of the window. --- +---@param window renwindow +--- ---@return number width ---@return number height ---@return number x ---@return number y -function system.get_window_size() end +function system.get_window_size(window) end --- ---Sets the size and coordinates of the window. --- +---@param window renwindow ---@param width number ---@param height number ---@param x number ---@param y number -function system.set_window_size(width, height, x, y) end +function system.set_window_size(window, width, height, x, y) end --- ---Check if the window currently has focus. --- +---@param window renwindow +--- ---@return boolean -function system.window_has_focus() end - ---- ----Gets the mode of the window. ---- ----@return system.windowmode -function system.get_window_mode() end +function system.window_has_focus(window) end --- ---Sets the position of the IME composition window. @@ -161,7 +164,9 @@ function system.clear_ime() end --- ---Raise the main window and give it input focus. ---Note: may not always be obeyed by the users window manager. -function system.raise_window() end +-- +---@param window renwindow +function system.raise_window(window) end --- ---Opens a message box to display an error message. @@ -300,10 +305,12 @@ function system.fuzzy_match(haystack, needle, file) end --- ---Change the opacity (also known as transparency) of the window. --- +---@param window renwindow ---@param opacity number A value from 0.0 to 1.0, the lower the value ---the less visible the window will be. +--- ---@return boolean success True if the operation suceeded. -function system.set_window_opacity(opacity) end +function system.set_window_opacity(window, opacity) end --- ---Loads a lua native module using the default Lua API or lite-xl native plugin API. diff --git a/src/api/api.c b/src/api/api.c index acf6eec2..888a6e42 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -2,6 +2,7 @@ int luaopen_system(lua_State *L); int luaopen_renderer(lua_State *L); +int luaopen_renwindow(lua_State *L); int luaopen_regex(lua_State *L); int luaopen_process(lua_State *L); int luaopen_dirmonitor(lua_State* L); @@ -10,6 +11,7 @@ int luaopen_utf8extra(lua_State* L); static const luaL_Reg libs[] = { { "system", luaopen_system }, { "renderer", luaopen_renderer }, + { "renwindow", luaopen_renwindow }, { "regex", luaopen_regex }, { "process", luaopen_process }, { "dirmonitor", luaopen_dirmonitor }, diff --git a/src/api/api.h b/src/api/api.h index e27112c6..4544d606 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -9,6 +9,7 @@ #define API_TYPE_PROCESS "Process" #define API_TYPE_DIRMONITOR "Dirmonitor" #define API_TYPE_NATIVE_PLUGIN "NativePlugin" +#define API_TYPE_RENWINDOW "RenWindow" #define API_CONSTANT_DEFINE(L, idx, key, n) (lua_pushnumber(L, n), lua_setfield(L, idx - 1, key)) diff --git a/src/api/renderer.c b/src/api/renderer.c index 2a57e23a..fdd6ed72 100644 --- a/src/api/renderer.c +++ b/src/api/renderer.c @@ -1,9 +1,12 @@ #include +#include #include "api.h" #include "../renderer.h" #include "../rencache.h" #include "lua.h" +RenWindow *active_window_renderer = NULL; + // a reference index to a table that stores the fonts static int RENDERER_FONT_REF = LUA_NOREF; @@ -90,7 +93,7 @@ static int f_font_load(lua_State *L) { return ret_code; RenFont** font = lua_newuserdata(L, sizeof(RenFont*)); - *font = ren_font_load(window_renderer, filename, size, antialiasing, hinting, style); + *font = ren_font_load(filename, size, antialiasing, hinting, style); if (!*font) return luaL_error(L, "failed to load font"); luaL_setmetatable(L, API_TYPE_FONT); @@ -136,7 +139,7 @@ static int f_font_copy(lua_State *L) { } for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { RenFont** font = lua_newuserdata(L, sizeof(RenFont*)); - *font = ren_font_copy(window_renderer, fonts[i], size, antialiasing, hinting, style); + *font = ren_font_copy(fonts[i], size, antialiasing, hinting, style); if (!*font) return luaL_error(L, "failed to copy font"); luaL_setmetatable(L, API_TYPE_FONT); @@ -204,7 +207,7 @@ static int f_font_get_width(lua_State *L) { size_t len; const char *text = luaL_checklstring(L, 2, &len); - lua_pushnumber(L, ren_font_group_get_width(window_renderer, fonts, text, len, NULL)); + lua_pushnumber(L, ren_font_group_get_width(fonts, text, len, NULL)); return 1; } @@ -223,7 +226,7 @@ static int f_font_get_size(lua_State *L) { static int f_font_set_size(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); float size = luaL_checknumber(L, 2); - ren_font_group_set_size(window_renderer, fonts, size); + ren_font_group_set_size(fonts, size); return 0; } @@ -281,8 +284,9 @@ static int f_show_debug(lua_State *L) { static int f_get_size(lua_State *L) { - int w, h; - ren_get_size(window_renderer, &w, &h); + int w = 0, h = 0; + if (active_window_renderer) + ren_get_size(active_window_renderer, &w, &h); lua_pushnumber(L, w); lua_pushnumber(L, h); return 2; @@ -290,13 +294,17 @@ static int f_get_size(lua_State *L) { static int f_begin_frame(UNUSED lua_State *L) { - rencache_begin_frame(window_renderer); + assert(active_window_renderer == NULL); + active_window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + rencache_begin_frame(active_window_renderer); return 0; } static int f_end_frame(UNUSED lua_State *L) { - rencache_end_frame(window_renderer); + assert(active_window_renderer != NULL); + rencache_end_frame(active_window_renderer); + active_window_renderer = NULL; // clear the font reference table lua_newtable(L); lua_rawseti(L, LUA_REGISTRYINDEX, RENDERER_FONT_REF); @@ -312,28 +320,31 @@ static RenRect rect_to_grid(lua_Number x, lua_Number y, lua_Number w, lua_Number static int f_set_clip_rect(lua_State *L) { + assert(active_window_renderer != NULL); lua_Number x = luaL_checknumber(L, 1); lua_Number y = luaL_checknumber(L, 2); lua_Number w = luaL_checknumber(L, 3); lua_Number h = luaL_checknumber(L, 4); RenRect rect = rect_to_grid(x, y, w, h); - rencache_set_clip_rect(window_renderer, rect); + rencache_set_clip_rect(active_window_renderer, rect); return 0; } static int f_draw_rect(lua_State *L) { + assert(active_window_renderer != NULL); lua_Number x = luaL_checknumber(L, 1); lua_Number y = luaL_checknumber(L, 2); lua_Number w = luaL_checknumber(L, 3); lua_Number h = luaL_checknumber(L, 4); RenRect rect = rect_to_grid(x, y, w, h); RenColor color = checkcolor(L, 5, 255); - rencache_draw_rect(window_renderer, rect, color); + rencache_draw_rect(active_window_renderer, rect, color); return 0; } static int f_draw_text(lua_State *L) { + assert(active_window_renderer != NULL); RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); @@ -354,7 +365,7 @@ static int f_draw_text(lua_State *L) { double x = luaL_checknumber(L, 3); int y = luaL_checknumber(L, 4); RenColor color = checkcolor(L, 5, 255); - x = rencache_draw_text(window_renderer, fonts, text, len, x, y, color); + x = rencache_draw_text(active_window_renderer, fonts, text, len, x, y, color); lua_pushnumber(L, x); return 1; } diff --git a/src/api/renwindow.c b/src/api/renwindow.c new file mode 100644 index 00000000..84687da4 --- /dev/null +++ b/src/api/renwindow.c @@ -0,0 +1,113 @@ +#include "api.h" +#include "../renwindow.h" +#include "lua.h" +#include + +static RenWindow *persistant_window = NULL; + +static void init_window_icon(SDL_Window *window) { +#if !defined(_WIN32) && !defined(__APPLE__) + #include "../resources/icons/icon.inl" + (void) icon_rgba_len; /* unused */ + SDL_Surface *surf = SDL_CreateRGBSurfaceFrom( + icon_rgba, 64, 64, + 32, 64 * 4, + 0x000000ff, + 0x0000ff00, + 0x00ff0000, + 0xff000000); + SDL_SetWindowIcon(window, surf); + SDL_FreeSurface(surf); +#endif +} + +static int f_renwin_create(lua_State *L) { + const char *title = luaL_checkstring(L, 1); + const int x = luaL_optinteger(L, 2, SDL_WINDOWPOS_UNDEFINED); + const int y = luaL_optinteger(L, 3, SDL_WINDOWPOS_UNDEFINED); + float width = luaL_optnumber(L, 4, 0); + float height = luaL_optnumber(L, 5, 0); + + if (width < 1 || height < 1) { + SDL_DisplayMode dm; + SDL_GetCurrentDisplayMode(0, &dm); + + if (width < 1) { + width = dm.w * 0.8; + } + if (height < 1) { + height = dm.h * 0.8; + } + } + + SDL_Window *window = SDL_CreateWindow( + title, x, y, width, height, + SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN + ); + if (!window) { + return luaL_error(L, "Error creating lite-xl window: %s", SDL_GetError()); + } + init_window_icon(window); + + RenWindow **window_renderer = (RenWindow**)lua_newuserdata(L, sizeof(RenWindow*)); + luaL_setmetatable(L, API_TYPE_RENWINDOW); + + *window_renderer = ren_create(window); + + return 1; +} + +static int f_renwin_gc(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + if (window_renderer != persistant_window) + ren_destroy(window_renderer); + + return 0; +} + +static int f_renwin_get_size(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + int w, h; + ren_get_size(window_renderer, &w, &h); + lua_pushnumber(L, w); + lua_pushnumber(L, h); + return 2; +} + +static int f_renwin_persist(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + + persistant_window = window_renderer; + return 0; +} + +static int f_renwin_restore(lua_State *L) { + if (!persistant_window) { + lua_pushnil(L); + } + else { + RenWindow **window_renderer = (RenWindow**)lua_newuserdata(L, sizeof(RenWindow*)); + luaL_setmetatable(L, API_TYPE_RENWINDOW); + + *window_renderer = persistant_window; + } + + return 1; +} + +static const luaL_Reg renwindow_lib[] = { + { "create", f_renwin_create }, + { "__gc", f_renwin_gc }, + { "get_size", f_renwin_get_size }, + { "_persist", f_renwin_persist }, + { "_restore", f_renwin_restore }, + {NULL, NULL} +}; + +int luaopen_renwindow(lua_State* L) { + luaL_newmetatable(L, API_TYPE_RENWINDOW); + luaL_setfuncs(L, renwindow_lib, 0); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + return 1; +} diff --git a/src/api/system.c b/src/api/system.c index f599e800..f301dba5 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -74,7 +74,7 @@ static SDL_HitTestResult SDLCALL hit_test(SDL_Window *window, const SDL_Point *p const int controls_width = hit_info->controls_width; int w, h; - SDL_GetWindowSize(window_renderer->window, &w, &h); + SDL_GetWindowSize(window, &w, &h); if (pt->y < hit_info->title_height && #if RESIZE_FROM_TOP @@ -186,6 +186,7 @@ top: case SDL_WINDOWEVENT: if (e.window.event == SDL_WINDOWEVENT_RESIZED) { + RenWindow* window_renderer = ren_find_window_from_id(e.window.windowID); ren_resize_window(window_renderer); lua_pushstring(L, "resized"); /* The size below will be in points. */ @@ -222,13 +223,16 @@ top: goto top; case SDL_DROPFILE: - SDL_GetMouseState(&mx, &my); - lua_pushstring(L, "filedropped"); - lua_pushstring(L, e.drop.file); - lua_pushinteger(L, mx * window_renderer->scale_x); - lua_pushinteger(L, my * window_renderer->scale_y); - SDL_free(e.drop.file); - return 4; + { + RenWindow* window_renderer = ren_find_window_from_id(e.drop.windowID); + SDL_GetMouseState(&mx, &my); + lua_pushstring(L, "filedropped"); + lua_pushstring(L, e.drop.file); + lua_pushinteger(L, mx * window_renderer->scale_x); + lua_pushinteger(L, my * window_renderer->scale_y); + SDL_free(e.drop.file); + return 4; + } case SDL_KEYDOWN: #ifdef __APPLE__ @@ -280,36 +284,45 @@ top: #endif case SDL_MOUSEBUTTONDOWN: - if (e.button.button == 1) { SDL_CaptureMouse(1); } - lua_pushstring(L, "mousepressed"); - lua_pushstring(L, button_name(e.button.button)); - lua_pushinteger(L, e.button.x * window_renderer->scale_x); - lua_pushinteger(L, e.button.y * window_renderer->scale_y); - lua_pushinteger(L, e.button.clicks); - return 5; + { + if (e.button.button == 1) { SDL_CaptureMouse(1); } + RenWindow* window_renderer = ren_find_window_from_id(e.button.windowID); + lua_pushstring(L, "mousepressed"); + lua_pushstring(L, button_name(e.button.button)); + lua_pushinteger(L, e.button.x * window_renderer->scale_x); + lua_pushinteger(L, e.button.y * window_renderer->scale_y); + lua_pushinteger(L, e.button.clicks); + return 5; + } case SDL_MOUSEBUTTONUP: - if (e.button.button == 1) { SDL_CaptureMouse(0); } - lua_pushstring(L, "mousereleased"); - lua_pushstring(L, button_name(e.button.button)); - lua_pushinteger(L, e.button.x * window_renderer->scale_x); - lua_pushinteger(L, e.button.y * window_renderer->scale_y); - return 4; + { + if (e.button.button == 1) { SDL_CaptureMouse(0); } + RenWindow* window_renderer = ren_find_window_from_id(e.button.windowID); + lua_pushstring(L, "mousereleased"); + lua_pushstring(L, button_name(e.button.button)); + lua_pushinteger(L, e.button.x * window_renderer->scale_x); + lua_pushinteger(L, e.button.y * window_renderer->scale_y); + return 4; + } case SDL_MOUSEMOTION: - SDL_PumpEvents(); - while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) { - e.motion.x = event_plus.motion.x; - e.motion.y = event_plus.motion.y; - e.motion.xrel += event_plus.motion.xrel; - e.motion.yrel += event_plus.motion.yrel; + { + SDL_PumpEvents(); + while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) { + e.motion.x = event_plus.motion.x; + e.motion.y = event_plus.motion.y; + e.motion.xrel += event_plus.motion.xrel; + e.motion.yrel += event_plus.motion.yrel; + } + RenWindow* window_renderer = ren_find_window_from_id(e.motion.windowID); + lua_pushstring(L, "mousemoved"); + lua_pushinteger(L, e.motion.x * window_renderer->scale_x); + lua_pushinteger(L, e.motion.y * window_renderer->scale_y); + lua_pushinteger(L, e.motion.xrel * window_renderer->scale_x); + lua_pushinteger(L, e.motion.yrel * window_renderer->scale_y); + return 5; } - lua_pushstring(L, "mousemoved"); - lua_pushinteger(L, e.motion.x * window_renderer->scale_x); - lua_pushinteger(L, e.motion.y * window_renderer->scale_y); - lua_pushinteger(L, e.motion.xrel * window_renderer->scale_x); - lua_pushinteger(L, e.motion.yrel * window_renderer->scale_y); - return 5; case SDL_MOUSEWHEEL: lua_pushstring(L, "mousewheel"); @@ -324,49 +337,64 @@ top: return 3; case SDL_FINGERDOWN: - SDL_GetWindowSize(window_renderer->window, &w, &h); + { + RenWindow* window_renderer = ren_find_window_from_id(e.tfinger.windowID); + SDL_GetWindowSize(window_renderer->window, &w, &h); - lua_pushstring(L, "touchpressed"); - lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); - lua_pushinteger(L, e.tfinger.fingerId); - return 4; + lua_pushstring(L, "touchpressed"); + lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); + lua_pushinteger(L, e.tfinger.fingerId); + return 4; + } case SDL_FINGERUP: - SDL_GetWindowSize(window_renderer->window, &w, &h); + { + RenWindow* window_renderer = ren_find_window_from_id(e.tfinger.windowID); + SDL_GetWindowSize(window_renderer->window, &w, &h); - lua_pushstring(L, "touchreleased"); - lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); - lua_pushinteger(L, e.tfinger.fingerId); - return 4; + lua_pushstring(L, "touchreleased"); + lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); + lua_pushinteger(L, e.tfinger.fingerId); + return 4; + } case SDL_FINGERMOTION: - SDL_PumpEvents(); - while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_FINGERMOTION, SDL_FINGERMOTION) > 0) { - e.tfinger.x = event_plus.tfinger.x; - e.tfinger.y = event_plus.tfinger.y; - e.tfinger.dx += event_plus.tfinger.dx; - e.tfinger.dy += event_plus.tfinger.dy; - } - SDL_GetWindowSize(window_renderer->window, &w, &h); + { + SDL_PumpEvents(); + while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_FINGERMOTION, SDL_FINGERMOTION) > 0) { + e.tfinger.x = event_plus.tfinger.x; + e.tfinger.y = event_plus.tfinger.y; + e.tfinger.dx += event_plus.tfinger.dx; + e.tfinger.dy += event_plus.tfinger.dy; + } + RenWindow* window_renderer = ren_find_window_from_id(e.tfinger.windowID); + SDL_GetWindowSize(window_renderer->window, &w, &h); - lua_pushstring(L, "touchmoved"); - lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.dx * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.dy * h)); - lua_pushinteger(L, e.tfinger.fingerId); - return 6; + lua_pushstring(L, "touchmoved"); + lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.dx * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.dy * h)); + lua_pushinteger(L, e.tfinger.fingerId); + return 6; + } case SDL_APP_WILLENTERFOREGROUND: case SDL_APP_DIDENTERFOREGROUND: - #ifdef LITE_USE_SDL_RENDERER - rencache_invalidate(); - #else - SDL_UpdateWindowSurface(window_renderer->window); - #endif - lua_pushstring(L, e.type == SDL_APP_WILLENTERFOREGROUND ? "enteringforeground" : "enteredforeground"); - return 1; + { + #ifdef LITE_USE_SDL_RENDERER + rencache_invalidate(); + #else + RenWindow** window_list; + size_t window_count = ren_get_window_list(&window_list); + while (window_count) { + SDL_UpdateWindowSurface(window_list[--window_count]->window); + } + #endif + lua_pushstring(L, e.type == SDL_APP_WILLENTERFOREGROUND ? "enteringforeground" : "enteredforeground"); + return 1; + } case SDL_APP_WILLENTERBACKGROUND: lua_pushstring(L, "enteringbackground"); return 1; @@ -428,7 +456,8 @@ static int f_set_cursor(lua_State *L) { static int f_set_window_title(lua_State *L) { - const char *title = luaL_checkstring(L, 1); + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + const char *title = luaL_checkstring(L, 2); SDL_SetWindowTitle(window_renderer->window, title); return 0; } @@ -438,7 +467,8 @@ static const char *window_opts[] = { "normal", "minimized", "maximized", "fullsc enum { WIN_NORMAL, WIN_MINIMIZED, WIN_MAXIMIZED, WIN_FULLSCREEN }; static int f_set_window_mode(lua_State *L) { - int n = luaL_checkoption(L, 1, "normal", window_opts); + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + int n = luaL_checkoption(L, 2, "normal", window_opts); SDL_SetWindowFullscreen(window_renderer->window, n == WIN_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); if (n == WIN_NORMAL) { SDL_RestoreWindow(window_renderer->window); } @@ -449,26 +479,38 @@ static int f_set_window_mode(lua_State *L) { static int f_set_window_bordered(lua_State *L) { + RenWindow** window_list; + size_t window_count = ren_get_window_list(&window_list); int bordered = lua_toboolean(L, 1); - SDL_SetWindowBordered(window_renderer->window, bordered); + while (window_count) { + SDL_SetWindowBordered(window_list[--window_count]->window, bordered); + } + return 0; } static int f_set_window_hit_test(lua_State *L) { + RenWindow** window_list; + size_t window_count = ren_get_window_list(&window_list); if (lua_gettop(L) == 0) { - SDL_SetWindowHitTest(window_renderer->window, NULL, NULL); + while (window_count) { + SDL_SetWindowHitTest(window_list[--window_count]->window, NULL, NULL); + } return 0; } window_hit_info->title_height = luaL_checknumber(L, 1); window_hit_info->controls_width = luaL_checknumber(L, 2); window_hit_info->resize_border = luaL_checknumber(L, 3); - SDL_SetWindowHitTest(window_renderer->window, hit_test, window_hit_info); + while (window_count) { + SDL_SetWindowHitTest(window_list[--window_count]->window, hit_test, window_hit_info); + } return 0; } static int f_get_window_size(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); int x, y, w, h; SDL_GetWindowSize(window_renderer->window, &w, &h); SDL_GetWindowPosition(window_renderer->window, &x, &y); @@ -481,10 +523,11 @@ static int f_get_window_size(lua_State *L) { static int f_set_window_size(lua_State *L) { - double w = luaL_checknumber(L, 1); - double h = luaL_checknumber(L, 2); - double x = luaL_checknumber(L, 3); - double y = luaL_checknumber(L, 4); + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + double w = luaL_checknumber(L, 2); + double h = luaL_checknumber(L, 3); + double x = luaL_checknumber(L, 4); + double y = luaL_checknumber(L, 5); SDL_SetWindowSize(window_renderer->window, w, h); SDL_SetWindowPosition(window_renderer->window, x, y); ren_resize_window(window_renderer); @@ -493,6 +536,7 @@ static int f_set_window_size(lua_State *L) { static int f_window_has_focus(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); unsigned flags = SDL_GetWindowFlags(window_renderer->window); lua_pushboolean(L, flags & SDL_WINDOW_INPUT_FOCUS); return 1; @@ -500,6 +544,7 @@ static int f_window_has_focus(lua_State *L) { static int f_get_window_mode(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); unsigned flags = SDL_GetWindowFlags(window_renderer->window); if (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { lua_pushstring(L, "fullscreen"); @@ -532,6 +577,7 @@ static int f_clear_ime(lua_State *L) { static int f_raise_window(lua_State *L) { + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); /* SDL_RaiseWindow should be enough but on some window managers like the one used on Gnome the window needs to first have input focus in order @@ -922,7 +968,8 @@ static int f_fuzzy_match(lua_State *L) { } static int f_set_window_opacity(lua_State *L) { - double n = luaL_checknumber(L, 1); + RenWindow *window_renderer = *(RenWindow**)luaL_checkudata(L, 1, API_TYPE_RENWINDOW); + double n = luaL_checknumber(L, 2); int r = SDL_SetWindowOpacity(window_renderer->window, n); lua_pushboolean(L, r > -1); return 1; diff --git a/src/main.c b/src/main.c index d3a19b99..74453b18 100644 --- a/src/main.c +++ b/src/main.c @@ -17,9 +17,6 @@ #include #endif - -static SDL_Window *window; - static void get_exe_filename(char *buf, int sz) { #if _WIN32 int len; @@ -56,23 +53,6 @@ static void get_exe_filename(char *buf, int sz) { #endif } - -static void init_window_icon(void) { -#if !defined(_WIN32) && !defined(__APPLE__) - #include "../resources/icons/icon.inl" - (void) icon_rgba_len; /* unused */ - SDL_Surface *surf = SDL_CreateRGBSurfaceFrom( - icon_rgba, 64, 64, - 32, 64 * 4, - 0x000000ff, - 0x0000ff00, - 0x00ff0000, - 0xff000000); - SDL_SetWindowIcon(window, surf); - SDL_FreeSurface(surf); -#endif -} - #ifdef _WIN32 #define LITE_OS_HOME "USERPROFILE" #define LITE_PATHSEP_PATTERN "\\\\" @@ -165,18 +145,9 @@ int main(int argc, char **argv) { SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - SDL_DisplayMode dm; - SDL_GetCurrentDisplayMode(0, &dm); - - window = SDL_CreateWindow( - "", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8, - SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); - init_window_icon(); - if (!window) { - fprintf(stderr, "Error creating lite-xl window: %s", SDL_GetError()); - exit(1); + if ( ren_init() ) { + fprintf(stderr, "internal font error when starting the application\n"); } - window_renderer = ren_init(window); lua_State *L; init_lua: @@ -265,10 +236,9 @@ init_lua: goto init_lua; } - // This allows the window to be destroyed before lite-xl is done with - // reaping child processes - ren_free(window_renderer); lua_close(L); + ren_free(); + return EXIT_SUCCESS; } diff --git a/src/meson.build b/src/meson.build index abf512cb..60acf45c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,6 +1,7 @@ lite_sources = [ 'api/api.c', 'api/renderer.c', + 'api/renwindow.c', 'api/regex.c', 'api/system.c', 'api/process.c', diff --git a/src/rencache.c b/src/rencache.c index a77f82ca..b75b824b 100644 --- a/src/rencache.c +++ b/src/rencache.c @@ -192,7 +192,7 @@ void rencache_draw_rect(RenWindow *window_renderer, RenRect rect, RenColor color double rencache_draw_text(RenWindow *window_renderer, RenFont **fonts, const char *text, size_t len, double x, int y, RenColor color) { int x_offset; - double width = ren_font_group_get_width(window_renderer, fonts, text, len, &x_offset); + double width = ren_font_group_get_width(fonts, text, len, &x_offset); RenRect rect = { x + x_offset, y, (int)(width - x_offset), ren_font_group_get_height(fonts) }; if (rects_overlap(last_clip_rect, rect)) { int sz = len + 1; diff --git a/src/renderer.c b/src/renderer.c index 80b2b057..eefb1fa0 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -22,7 +22,8 @@ #define MAX_LOADABLE_GLYPHSETS (MAX_UNICODE / GLYPHSET_SIZE) #define SUBPIXEL_BITMAPS_CACHED 3 -RenWindow* window_renderer = NULL; +static RenWindow **window_list = NULL; +static size_t window_count = 0; static FT_Library library; // draw_rect_surface is used as a 1x1 surface to simplify ren_draw_rect with blending @@ -248,7 +249,7 @@ static void font_file_close(FT_Stream stream) { } } -RenFont* ren_font_load(RenWindow *window_renderer, const char* path, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style) { +RenFont* ren_font_load(const char* path, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style) { RenFont *font = NULL; FT_Face face = NULL; @@ -267,8 +268,7 @@ RenFont* ren_font_load(RenWindow *window_renderer, const char* path, float size, if (FT_Open_Face(library, &(FT_Open_Args){ .flags = FT_OPEN_STREAM, .stream = &font->stream }, 0, &face)) goto failure; - const int surface_scale = renwin_get_surface(window_renderer).scale; - if (FT_Set_Pixel_Sizes(face, 0, (int)(size*surface_scale))) + if (FT_Set_Pixel_Sizes(face, 0, (int)(size))) goto failure; strcpy(font->path, path); @@ -305,12 +305,12 @@ rwops_failure: return NULL; } -RenFont* ren_font_copy(RenWindow *window_renderer, RenFont* font, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, int style) { +RenFont* ren_font_copy(RenFont* font, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, int style) { antialiasing = antialiasing == -1 ? font->antialiasing : antialiasing; hinting = hinting == -1 ? font->hinting : hinting; style = style == -1 ? font->style : style; - return ren_font_load(window_renderer, font->path, size, antialiasing, hinting, style); + return ren_font_load(font->path, size, antialiasing, hinting, style); } const char* ren_font_get_path(RenFont *font) { @@ -344,12 +344,11 @@ float ren_font_group_get_size(RenFont **fonts) { return fonts[0]->size; } -void ren_font_group_set_size(RenWindow *window_renderer, RenFont **fonts, float size) { - const int surface_scale = renwin_get_surface(window_renderer).scale; +void ren_font_group_set_size(RenFont **fonts, float size) { for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { font_clear_glyph_cache(fonts[i]); FT_Face face = fonts[i]->face; - FT_Set_Pixel_Sizes(face, 0, (int)(size*surface_scale)); + FT_Set_Pixel_Sizes(face, 0, (int)(size)); fonts[i]->size = size; #ifdef LITE_USE_SDL_RENDERER fonts[i]->scale = surface_scale; @@ -366,7 +365,7 @@ int ren_font_group_get_height(RenFont **fonts) { return fonts[0]->height; } -double ren_font_group_get_width(RenWindow *window_renderer, RenFont **fonts, const char *text, size_t len, int *x_offset) { +double ren_font_group_get_width(RenFont **fonts, const char *text, size_t len, int *x_offset) { double width = 0; const char* end = text + len; GlyphMetric* metric = NULL; GlyphSet* set = NULL; @@ -383,11 +382,10 @@ double ren_font_group_get_width(RenWindow *window_renderer, RenFont **fonts, con *x_offset = metric->bitmap_left; // TODO: should this be scaled by the surface scale? } } - const int surface_scale = renwin_get_surface(window_renderer).scale; if (!set_x_offset) { *x_offset = 0; } - return width / surface_scale; + return width; } double ren_draw_text(RenSurface *rs, RenFont **fonts, const char *text, size_t len, float x, int y, RenColor color) { @@ -519,29 +517,55 @@ void ren_draw_rect(RenSurface *rs, RenRect rect, RenColor color) { } /*************** Window Management ****************/ -RenWindow* ren_init(SDL_Window *win) { - assert(win); - int error = FT_Init_FreeType( &library ); - if ( error ) { - fprintf(stderr, "internal font error when starting the application\n"); - return NULL; +static void ren_add_window(RenWindow *window_renderer) { + window_count += 1; + window_list = realloc(window_list, window_count); + window_list[window_count-1] = window_renderer; +} + +static void ren_remove_window(RenWindow *window_renderer) { + for (size_t i = 0; i < window_count; ++i) { + if (window_list[i] == window_renderer) { + window_count -= 1; + memmove(&window_list[i], &window_list[i+1], window_count - i); + return; + } } +} + +int ren_init(void) { + int err; + + draw_rect_surface = SDL_CreateRGBSurface(0, 1, 1, 32, + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + + if ((err = FT_Init_FreeType( &library ))) + return err; + + return 0; +} + +void ren_free(void) { + SDL_FreeSurface(draw_rect_surface); +} + +RenWindow* ren_create(SDL_Window *win) { + assert(win); RenWindow* window_renderer = calloc(1, sizeof(RenWindow)); window_renderer->window = win; renwin_init_surface(window_renderer); renwin_init_command_buf(window_renderer); renwin_clip_to_surface(window_renderer); - draw_rect_surface = SDL_CreateRGBSurface(0, 1, 1, 32, - 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + ren_add_window(window_renderer); return window_renderer; } -void ren_free(RenWindow* window_renderer) { +void ren_destroy(RenWindow* window_renderer) { assert(window_renderer); + ren_remove_window(window_renderer); renwin_free(window_renderer); - SDL_FreeSurface(draw_rect_surface); free(window_renderer->command_buf); window_renderer->command_buf = NULL; window_renderer->command_buf_size = 0; @@ -553,14 +577,14 @@ void ren_resize_window(RenWindow *window_renderer) { renwin_update_scale(window_renderer); } - +// TODO: Does not work nicely with multiple windows void ren_update_rects(RenWindow *window_renderer, RenRect *rects, int count) { static bool initial_frame = true; + renwin_update_rects(window_renderer, rects, count); if (initial_frame) { renwin_show_window(window_renderer); initial_frame = false; } - renwin_update_rects(window_renderer, rects, count); } @@ -571,6 +595,27 @@ void ren_set_clip_rect(RenWindow *window_renderer, RenRect rect) { void ren_get_size(RenWindow *window_renderer, int *x, int *y) { RenSurface rs = renwin_get_surface(window_renderer); - *x = rs.surface->w / rs.scale; - *y = rs.surface->h / rs.scale; + *x = rs.surface->w; + *y = rs.surface->h; +} + +size_t ren_get_window_list(RenWindow ***window_list_dest) { + *window_list_dest = window_list; + return window_count; +} + +RenWindow* ren_find_window(SDL_Window *window) { + for (size_t i = 0; i < window_count; ++i) { + RenWindow* window_renderer = window_list[i]; + if (window_renderer->window == window) { + return window_renderer; + } + } + + return NULL; +} + +RenWindow* ren_find_window_from_id(uint32_t id) { + SDL_Window *window = SDL_GetWindowFromID(id); + return ren_find_window(window); } diff --git a/src/renderer.h b/src/renderer.h index 1cd6bc88..6f4fd521 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -23,31 +23,34 @@ typedef struct { SDL_Surface *surface; int scale; } RenSurface; struct RenWindow; typedef struct RenWindow RenWindow; -extern RenWindow* window_renderer; -RenFont* ren_font_load(RenWindow *window_renderer, const char *filename, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style); -RenFont* ren_font_copy(RenWindow *window_renderer, RenFont* font, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, int style); +RenFont* ren_font_load(const char *filename, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style); +RenFont* ren_font_copy(RenFont* font, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, int style); const char* ren_font_get_path(RenFont *font); void ren_font_free(RenFont *font); int ren_font_group_get_tab_size(RenFont **font); int ren_font_group_get_height(RenFont **font); float ren_font_group_get_size(RenFont **font); -void ren_font_group_set_size(RenWindow *window_renderer, RenFont **font, float size); +void ren_font_group_set_size(RenFont **font, float size); #ifdef LITE_USE_SDL_RENDERER void update_font_scale(RenWindow *window_renderer, RenFont **fonts); #endif void ren_font_group_set_tab_size(RenFont **font, int n); -double ren_font_group_get_width(RenWindow *window_renderer, RenFont **font, const char *text, size_t len, int *x_offset); +double ren_font_group_get_width(RenFont **font, const char *text, size_t len, int *x_offset); double ren_draw_text(RenSurface *rs, RenFont **font, const char *text, size_t len, float x, int y, RenColor color); void ren_draw_rect(RenSurface *rs, RenRect rect, RenColor color); -RenWindow* ren_init(SDL_Window *win); -void ren_free(RenWindow* window_renderer); +int ren_init(void); +void ren_free(void); +RenWindow* ren_create(SDL_Window *win); +void ren_destroy(RenWindow* window_renderer); void ren_resize_window(RenWindow *window_renderer); void ren_update_rects(RenWindow *window_renderer, RenRect *rects, int count); void ren_set_clip_rect(RenWindow *window_renderer, RenRect rect); void ren_get_size(RenWindow *window_renderer, int *x, int *y); /* Reports the size in points. */ - +size_t ren_get_window_list(RenWindow ***window_list_dest); +RenWindow* ren_find_window(SDL_Window *window); +RenWindow* ren_find_window_from_id(uint32_t id); #endif