Merge branch 'master' into master-2.1
This commit is contained in:
commit
5df1640595
|
@ -232,7 +232,7 @@ end
|
||||||
function DocView:on_mouse_moved(x, y, ...)
|
function DocView:on_mouse_moved(x, y, ...)
|
||||||
DocView.super.on_mouse_moved(self, x, y, ...)
|
DocView.super.on_mouse_moved(self, x, y, ...)
|
||||||
|
|
||||||
if self:scrollbar_overlaps_point(x, y) or self.dragging_scrollbar then
|
if self.hovered_scrollbar_track or self.dragging_scrollbar then
|
||||||
self.cursor = "arrow"
|
self.cursor = "arrow"
|
||||||
else
|
else
|
||||||
self.cursor = "ibeam"
|
self.cursor = "ibeam"
|
||||||
|
@ -275,8 +275,8 @@ function DocView:mouse_selection(doc, snap_type, line1, col1, line2, col2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function DocView:on_mouse_released(button)
|
function DocView:on_mouse_released(...)
|
||||||
DocView.super.on_mouse_released(self, button)
|
DocView.super.on_mouse_released(self, ...)
|
||||||
self.mouse_selecting = nil
|
self.mouse_selecting = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -469,6 +469,10 @@ local style = require "core.style"
|
||||||
-- style.font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Regular.ttf", 14 * SCALE)
|
-- style.font = renderer.font.load(DATADIR .. "/fonts/FiraSans-Regular.ttf", 14 * SCALE)
|
||||||
-- style.code_font = renderer.font.load(DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", 14 * SCALE)
|
-- style.code_font = renderer.font.load(DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", 14 * SCALE)
|
||||||
--
|
--
|
||||||
|
-- DATADIR is the location of the installed Lite XL Lua code, default color
|
||||||
|
-- schemes and fonts.
|
||||||
|
-- USERDIR is the location of the Lite XL configuration directory.
|
||||||
|
--
|
||||||
-- font names used by lite:
|
-- font names used by lite:
|
||||||
-- style.font : user interface
|
-- style.font : user interface
|
||||||
-- style.big_font : big text in welcome screen
|
-- style.big_font : big text in welcome screen
|
||||||
|
|
|
@ -34,3 +34,12 @@ table.pack = table.pack or pack or function(...) return {...} end
|
||||||
table.unpack = table.unpack or unpack
|
table.unpack = table.unpack or unpack
|
||||||
|
|
||||||
bit32 = bit32 or require "core.bit"
|
bit32 = bit32 or require "core.bit"
|
||||||
|
|
||||||
|
-- Because AppImages change the working directory before running the executable,
|
||||||
|
-- we need to change it back to the original one.
|
||||||
|
-- https://github.com/AppImage/AppImageKit/issues/172
|
||||||
|
-- https://github.com/AppImage/AppImageKit/pull/191
|
||||||
|
local appimage_owd = os.getenv("OWD")
|
||||||
|
if os.getenv("APPIMAGE") and appimage_owd then
|
||||||
|
system.chdir(appimage_owd)
|
||||||
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ local style = {}
|
||||||
style.padding = { x = common.round(14 * SCALE), y = common.round(7 * SCALE) }
|
style.padding = { x = common.round(14 * SCALE), y = common.round(7 * SCALE) }
|
||||||
style.divider_size = common.round(1 * SCALE)
|
style.divider_size = common.round(1 * SCALE)
|
||||||
style.scrollbar_size = common.round(4 * SCALE)
|
style.scrollbar_size = common.round(4 * SCALE)
|
||||||
|
style.expanded_scrollbar_size = common.round(12 * SCALE)
|
||||||
style.caret_width = common.round(2 * SCALE)
|
style.caret_width = common.round(2 * SCALE)
|
||||||
style.tab_width = common.round(170 * SCALE)
|
style.tab_width = common.round(170 * SCALE)
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ style.line_number2 = { common.color "#83838f" } -- With cursor
|
||||||
style.line_highlight = { common.color "#343438" }
|
style.line_highlight = { common.color "#343438" }
|
||||||
style.scrollbar = { common.color "#414146" }
|
style.scrollbar = { common.color "#414146" }
|
||||||
style.scrollbar2 = { common.color "#4b4b52" } -- Hovered
|
style.scrollbar2 = { common.color "#4b4b52" } -- Hovered
|
||||||
|
style.scrollbar_track = { common.color "#252529" }
|
||||||
style.nagbar = { common.color "#FF0000" }
|
style.nagbar = { common.color "#FF0000" }
|
||||||
style.nagbar_text = { common.color "#FFFFFF" }
|
style.nagbar_text = { common.color "#FFFFFF" }
|
||||||
style.nagbar_dim = { common.color "rgba(0, 0, 0, 0.45)" }
|
style.nagbar_dim = { common.color "rgba(0, 0, 0, 0.45)" }
|
||||||
|
|
|
@ -18,6 +18,13 @@ function View:new()
|
||||||
self.scroll = { x = 0, y = 0, to = { x = 0, y = 0 } }
|
self.scroll = { x = 0, y = 0, to = { x = 0, y = 0 } }
|
||||||
self.cursor = "arrow"
|
self.cursor = "arrow"
|
||||||
self.scrollable = false
|
self.scrollable = false
|
||||||
|
self.scrollbar = {
|
||||||
|
x = { thumb = 0, track = 0 },
|
||||||
|
y = { thumb = 0, track = 0 },
|
||||||
|
w = { thumb = 0, track = 0, to = { thumb = 0, track = 0 } },
|
||||||
|
h = { thumb = 0, track = 0 },
|
||||||
|
}
|
||||||
|
self.scrollbar_alpha = { value = 0, to = 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
function View:move_towards(t, k, dest, rate)
|
function View:move_towards(t, k, dest, rate)
|
||||||
|
@ -57,29 +64,62 @@ function View:get_scrollable_size()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function View:get_scrollbar_track_rect()
|
||||||
|
local sz = self:get_scrollable_size()
|
||||||
|
if sz <= self.size.y or sz == math.huge then
|
||||||
|
return 0, 0, 0, 0
|
||||||
|
end
|
||||||
|
local width = style.scrollbar_size
|
||||||
|
if self.hovered_scrollbar_track or self.dragging_scrollbar then
|
||||||
|
width = style.expanded_scrollbar_size
|
||||||
|
end
|
||||||
|
return
|
||||||
|
self.position.x + self.size.x - width,
|
||||||
|
self.position.y,
|
||||||
|
width,
|
||||||
|
self.size.y
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:get_scrollbar_rect()
|
function View:get_scrollbar_rect()
|
||||||
local sz = self:get_scrollable_size()
|
local sz = self:get_scrollable_size()
|
||||||
if sz <= self.size.y or sz == math.huge then
|
if sz <= self.size.y or sz == math.huge then
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
end
|
end
|
||||||
local h = math.max(20, self.size.y * self.size.y / sz)
|
local h = math.max(20, self.size.y * self.size.y / sz)
|
||||||
|
local width = style.scrollbar_size
|
||||||
|
if self.hovered_scrollbar_track or self.dragging_scrollbar then
|
||||||
|
width = style.expanded_scrollbar_size
|
||||||
|
end
|
||||||
return
|
return
|
||||||
self.position.x + self.size.x - style.scrollbar_size,
|
self.position.x + self.size.x - width,
|
||||||
self.position.y + self.scroll.y * (self.size.y - h) / (sz - self.size.y),
|
self.position.y + self.scroll.y * (self.size.y - h) / (sz - self.size.y),
|
||||||
style.scrollbar_size,
|
width,
|
||||||
h
|
h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:scrollbar_overlaps_point(x, y)
|
function View:scrollbar_overlaps_point(x, y)
|
||||||
local sx, sy, sw, sh = self:get_scrollbar_rect()
|
local sx, sy, sw, sh = self:get_scrollbar_rect()
|
||||||
return x >= sx - sw * 3 and x < sx + sw and y >= sy and y < sy + sh
|
return x >= sx - style.scrollbar_size * 3 and x < sx + sw and y > sy and y <= sy + sh
|
||||||
|
end
|
||||||
|
|
||||||
|
function View:scrollbar_track_overlaps_point(x, y)
|
||||||
|
local sx, sy, sw, sh = self:get_scrollbar_track_rect()
|
||||||
|
return x >= sx - style.scrollbar_size * 3 and x < sx + sw and y > sy and y <= sy + sh
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:on_mouse_pressed(button, x, y, clicks)
|
function View:on_mouse_pressed(button, x, y, clicks)
|
||||||
if self:scrollbar_overlaps_point(x, y) then
|
if self:scrollbar_track_overlaps_point(x, y) then
|
||||||
self.dragging_scrollbar = true
|
if self:scrollbar_overlaps_point(x, y) then
|
||||||
|
self.dragging_scrollbar = true
|
||||||
|
else
|
||||||
|
local _, _, _, sh = self:get_scrollbar_rect()
|
||||||
|
local ly = (y - self.position.y) - sh / 2
|
||||||
|
local pct = common.clamp(ly / self.size.y, 0, 100)
|
||||||
|
self.scroll.to.y = self:get_scrollable_size() * pct
|
||||||
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -96,6 +136,7 @@ function View:on_mouse_moved(x, y, dx, dy)
|
||||||
self.scroll.to.y = self.scroll.to.y + delta
|
self.scroll.to.y = self.scroll.to.y + delta
|
||||||
end
|
end
|
||||||
self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y)
|
self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y)
|
||||||
|
self.hovered_scrollbar_track = self.hovered_scrollbar or self:scrollbar_track_overlaps_point(x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,10 +173,33 @@ function View:clamp_scroll_position()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function View:update_scrollbar()
|
||||||
|
local x, y, w, h = self:get_scrollbar_rect()
|
||||||
|
self.scrollbar.w.to.thumb = w
|
||||||
|
self:move_towards(self.scrollbar.w, "thumb", self.scrollbar.w.to.thumb, 0.3)
|
||||||
|
self.scrollbar.x.thumb = x + w - self.scrollbar.w.thumb
|
||||||
|
self.scrollbar.y.thumb = y
|
||||||
|
self.scrollbar.h.thumb = h
|
||||||
|
|
||||||
|
local x, y, w, h = self:get_scrollbar_track_rect()
|
||||||
|
self.scrollbar.w.to.track = w
|
||||||
|
self:move_towards(self.scrollbar.w, "track", self.scrollbar.w.to.track, 0.3)
|
||||||
|
self.scrollbar.x.track = x + w - self.scrollbar.w.track
|
||||||
|
self.scrollbar.y.track = y
|
||||||
|
self.scrollbar.h.track = h
|
||||||
|
|
||||||
|
-- we use 100 for a smoother transition
|
||||||
|
self.scrollbar_alpha.to = (self.hovered_scrollbar_track or self.dragging_scrollbar) and 100 or 0
|
||||||
|
self:move_towards(self.scrollbar_alpha, "value", self.scrollbar_alpha.to, 0.3)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:update()
|
function View:update()
|
||||||
self:clamp_scroll_position()
|
self:clamp_scroll_position()
|
||||||
self:move_towards(self.scroll, "x", self.scroll.to.x, 0.3)
|
self:move_towards(self.scroll, "x", self.scroll.to.x, 0.3)
|
||||||
self:move_towards(self.scroll, "y", self.scroll.to.y, 0.3)
|
self:move_towards(self.scroll, "y", self.scroll.to.y, 0.3)
|
||||||
|
|
||||||
|
self:update_scrollbar()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,11 +210,29 @@ function View:draw_background(color)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function View:draw_scrollbar()
|
function View:draw_scrollbar_track()
|
||||||
local x, y, w, h = self:get_scrollbar_rect()
|
if not (self.hovered_scrollbar_track or self.dragging_scrollbar)
|
||||||
|
and self.scrollbar_alpha.value == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local color = { table.unpack(style.scrollbar_track) }
|
||||||
|
color[4] = color[4] * self.scrollbar_alpha.value / 100
|
||||||
|
renderer.draw_rect(self.scrollbar.x.track, self.scrollbar.y.track,
|
||||||
|
self.scrollbar.w.track, self.scrollbar.h.track, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function View:draw_scrollbar_thumb()
|
||||||
local highlight = self.hovered_scrollbar or self.dragging_scrollbar
|
local highlight = self.hovered_scrollbar or self.dragging_scrollbar
|
||||||
local color = highlight and style.scrollbar2 or style.scrollbar
|
local color = highlight and style.scrollbar2 or style.scrollbar
|
||||||
renderer.draw_rect(x, y, w, h, color)
|
renderer.draw_rect(self.scrollbar.x.thumb, self.scrollbar.y.thumb,
|
||||||
|
self.scrollbar.w.thumb, self.scrollbar.h.thumb, color)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function View:draw_scrollbar()
|
||||||
|
self:draw_scrollbar_track()
|
||||||
|
self:draw_scrollbar_thumb()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -76,12 +76,21 @@ local max_symbols = config.plugins.autocomplete.max_symbols
|
||||||
core.add_thread(function()
|
core.add_thread(function()
|
||||||
local cache = setmetatable({}, { __mode = "k" })
|
local cache = setmetatable({}, { __mode = "k" })
|
||||||
|
|
||||||
|
local function get_syntax_symbols(symbols, doc)
|
||||||
|
if doc.syntax then
|
||||||
|
for sym in pairs(doc.syntax.symbols) do
|
||||||
|
symbols[sym] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function get_symbols(doc)
|
local function get_symbols(doc)
|
||||||
if doc.disable_symbols then return {} end
|
|
||||||
local i = 1
|
|
||||||
local s = {}
|
local s = {}
|
||||||
|
get_syntax_symbols(s, doc)
|
||||||
|
if doc.disable_symbols then return s end
|
||||||
|
local i = 1
|
||||||
local symbols_count = 0
|
local symbols_count = 0
|
||||||
while i < #doc.lines do
|
while i <= #doc.lines do
|
||||||
for sym in doc.lines[i]:gmatch(config.symbol_pattern) do
|
for sym in doc.lines[i]:gmatch(config.symbol_pattern) do
|
||||||
if not s[sym] then
|
if not s[sym] then
|
||||||
symbols_count = symbols_count + 1
|
symbols_count = symbols_count + 1
|
||||||
|
@ -139,6 +148,7 @@ core.add_thread(function()
|
||||||
for _, doc in ipairs(core.docs) do
|
for _, doc in ipairs(core.docs) do
|
||||||
if not cache_is_valid(doc) then
|
if not cache_is_valid(doc) then
|
||||||
valid = false
|
valid = false
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,7 @@ syntax.add {
|
||||||
patterns = {
|
patterns = {
|
||||||
{ pattern = { "#", "\n" }, type = "comment" },
|
{ pattern = { "#", "\n" }, type = "comment" },
|
||||||
{ pattern = { '[ruU]?"""', '"""'; '\\' }, type = "string" },
|
{ pattern = { '[ruU]?"""', '"""'; '\\' }, type = "string" },
|
||||||
|
{ pattern = { "[ruU]?'''", "'''", '\\' }, type = "string" },
|
||||||
{ pattern = { '[ruU]?"', '"', '\\' }, type = "string" },
|
{ pattern = { '[ruU]?"', '"', '\\' }, type = "string" },
|
||||||
{ pattern = { "[ruU]?'", "'", '\\' }, type = "string" },
|
{ pattern = { "[ruU]?'", "'", '\\' }, type = "string" },
|
||||||
{ pattern = "0x[%da-fA-F]+", type = "number" },
|
{ pattern = "0x[%da-fA-F]+", type = "number" },
|
||||||
|
|
64
meson.build
64
meson.build
|
@ -69,30 +69,68 @@ endif
|
||||||
if not get_option('source-only')
|
if not get_option('source-only')
|
||||||
libm = cc.find_library('m', required : false)
|
libm = cc.find_library('m', required : false)
|
||||||
libdl = cc.find_library('dl', required : false)
|
libdl = cc.find_library('dl', required : false)
|
||||||
lua_fallback = ['lua', 'lua_dep']
|
|
||||||
lua_quick_fallback = []
|
|
||||||
if get_option('wrap_mode') == 'forcefallback'
|
|
||||||
lua_quick_fallback = lua_fallback
|
|
||||||
endif
|
|
||||||
|
|
||||||
lua_dep = dependency('lua5.4', fallback: lua_quick_fallback, required : false)
|
default_fallback_options = ['warning_level=0', 'werror=false']
|
||||||
if not lua_dep.found()
|
|
||||||
lua_dep = dependency('lua', fallback: ['lua', 'lua_dep'],
|
# Lua has no official .pc file
|
||||||
|
# so distros come up with their own names
|
||||||
|
lua_names = [
|
||||||
|
'lua5.4', # Debian
|
||||||
|
'lua-5.4', # FreeBSD
|
||||||
|
'lua', # Fedora
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach lua : lua_names
|
||||||
|
last_lua = (lua == lua_names[-1])
|
||||||
|
lua_dep = dependency(lua, fallback: last_lua ? ['lua', 'lua_dep'] : [], required : last_lua,
|
||||||
version: '>= 5.4',
|
version: '>= 5.4',
|
||||||
default_options: ['default_library=static', 'line_editing=false', 'interpreter=false']
|
default_options: default_fallback_options + ['default_library=static', 'line_editing=false', 'interpreter=false']
|
||||||
)
|
)
|
||||||
endif
|
if lua_dep.found()
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
pcre2_dep = dependency('libpcre2-8', fallback: ['pcre2', 'libpcre2_8'],
|
pcre2_dep = dependency('libpcre2-8', fallback: ['pcre2', 'libpcre2_8'],
|
||||||
default_options: ['default_library=static', 'grep=false', 'test=false']
|
default_options: default_fallback_options + ['default_library=static', 'grep=false', 'test=false']
|
||||||
)
|
)
|
||||||
|
|
||||||
freetype_dep = dependency('freetype2', fallback: ['freetype2', 'freetype_dep'],
|
freetype_dep = dependency('freetype2', fallback: ['freetype2', 'freetype_dep'],
|
||||||
default_options: ['default_library=static', 'zlib=disabled', 'bzip2=disabled', 'png=disabled', 'harfbuzz=disabled', 'brotli=disabled']
|
default_options: default_fallback_options + ['default_library=static', 'zlib=disabled', 'bzip2=disabled', 'png=disabled', 'harfbuzz=disabled', 'brotli=disabled']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
sdl_options = ['default_library=static']
|
||||||
|
|
||||||
|
# we explicitly need these
|
||||||
|
sdl_options += 'use_loadso=enabled'
|
||||||
|
sdl_options += 'prefer_dlopen=true'
|
||||||
|
sdl_options += 'use_video=enabled'
|
||||||
|
sdl_options += 'use_atomic=enabled'
|
||||||
|
sdl_options += 'use_threads=enabled'
|
||||||
|
# investigate if this is truly needed
|
||||||
|
# Do not remove before https://github.com/libsdl-org/SDL/issues/5413 is released
|
||||||
|
sdl_options += 'use_events=enabled'
|
||||||
|
|
||||||
|
# we leave this up to what the host system has
|
||||||
|
sdl_options += 'use_video_x11=auto'
|
||||||
|
sdl_options += 'use_video_wayland=auto'
|
||||||
|
|
||||||
|
# we don't need these
|
||||||
|
sdl_options += 'use_timers=disabled'
|
||||||
|
sdl_options += 'use_sensor=disabled'
|
||||||
|
sdl_options += 'use_haptic=disabled'
|
||||||
|
sdl_options += 'use_audio=disabled'
|
||||||
|
sdl_options += 'use_cpuinfo=disabled'
|
||||||
|
sdl_options += 'use_joystick=disabled'
|
||||||
|
sdl_options += 'use_video_opengl=disabled'
|
||||||
|
sdl_options += 'use_video_openglesv2=disabled'
|
||||||
|
sdl_options += 'use_video_vulkan=disabled'
|
||||||
|
sdl_options += 'use_video_offscreen=disabled'
|
||||||
|
sdl_options += 'use_power=disabled'
|
||||||
|
|
||||||
sdl_dep = dependency('sdl2', fallback: ['sdl2', 'sdl2_dep'],
|
sdl_dep = dependency('sdl2', fallback: ['sdl2', 'sdl2_dep'],
|
||||||
default_options: ['default_library=static']
|
default_options: default_fallback_options + sdl_options
|
||||||
)
|
)
|
||||||
|
|
||||||
lite_deps = [lua_dep, sdl_dep, freetype_dep, pcre2_dep, libm, libdl]
|
lite_deps = [lua_dep, sdl_dep, freetype_dep, pcre2_dep, libm, libdl]
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<name>Lite XL</name>
|
<name>Lite XL</name>
|
||||||
<summary>A lightweight text editor written in Lua</summary>
|
<summary>A lightweight text editor written in Lua</summary>
|
||||||
<content_rating type="oars-1.0" />
|
<content_rating type="oars-1.0" />
|
||||||
|
<launchable type="desktop-id">org.lite_xl.lite_xl.desktop</launchable>
|
||||||
|
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
// https://stackoverflow.com/questions/60645/overlapped-i-o-on-anonymous-pipe
|
// https://stackoverflow.com/questions/60645/overlapped-i-o-on-anonymous-pipe
|
||||||
|
@ -21,19 +22,23 @@
|
||||||
|
|
||||||
#define READ_BUF_SIZE 2048
|
#define READ_BUF_SIZE 2048
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
typedef HANDLE process_handle;
|
||||||
|
#else
|
||||||
|
typedef int process_handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool running;
|
bool running;
|
||||||
int returncode, deadline;
|
int returncode, deadline;
|
||||||
long pid;
|
long pid;
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
PROCESS_INFORMATION process_information;
|
PROCESS_INFORMATION process_information;
|
||||||
HANDLE child_pipes[3][2];
|
|
||||||
OVERLAPPED overlapped[2];
|
OVERLAPPED overlapped[2];
|
||||||
bool reading[2];
|
bool reading[2];
|
||||||
char buffer[2][READ_BUF_SIZE];
|
char buffer[2][READ_BUF_SIZE];
|
||||||
#else
|
|
||||||
int child_pipes[3][2];
|
|
||||||
#endif
|
#endif
|
||||||
|
process_handle child_pipes[3][2];
|
||||||
} process_t;
|
} process_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -91,7 +96,7 @@ static bool poll_process(process_t* proc, int timeout) {
|
||||||
#endif
|
#endif
|
||||||
if (timeout)
|
if (timeout)
|
||||||
SDL_Delay(5);
|
SDL_Delay(5);
|
||||||
} while (timeout == WAIT_INFINITE || SDL_GetTicks() - ticks < timeout);
|
} while (timeout == WAIT_INFINITE || (int)SDL_GetTicks() - ticks < timeout);
|
||||||
|
|
||||||
return proc->running;
|
return proc->running;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +122,9 @@ static bool signal_process(process_t* proc, signal_e sig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_start(lua_State* L) {
|
static int process_start(lua_State* L) {
|
||||||
|
int retval = 1;
|
||||||
size_t env_len = 0, key_len, val_len;
|
size_t env_len = 0, key_len, val_len;
|
||||||
const char *cmd[256], *env_names[256] = { NULL }, *env_values[256] = { NULL }, *cwd = NULL;
|
const char *cmd[256] = { NULL }, *env_names[256] = { NULL }, *env_values[256] = { NULL }, *cwd = NULL;
|
||||||
bool detach = false;
|
bool detach = false;
|
||||||
int deadline = 10, new_fds[3] = { STDIN_FD, STDOUT_FD, STDERR_FD };
|
int deadline = 10, new_fds[3] = { STDIN_FD, STDOUT_FD, STDERR_FD };
|
||||||
luaL_checktype(L, 1, LUA_TTABLE);
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
@ -134,7 +140,11 @@ static int process_start(lua_State* L) {
|
||||||
lua_rawget(L, 1);
|
lua_rawget(L, 1);
|
||||||
cmd[i-1] = luaL_checkstring(L, -1);
|
cmd[i-1] = luaL_checkstring(L, -1);
|
||||||
}
|
}
|
||||||
cmd[cmd_len] = NULL;
|
|
||||||
|
// this should never trip
|
||||||
|
// but if it does we are in deep trouble
|
||||||
|
assert(cmd[0]);
|
||||||
|
|
||||||
if (arg_len > 1) {
|
if (arg_len > 1) {
|
||||||
lua_getfield(L, 2, "env");
|
lua_getfield(L, 2, "env");
|
||||||
if (!lua_isnil(L, -1)) {
|
if (!lua_isnil(L, -1)) {
|
||||||
|
@ -158,8 +168,14 @@ static int process_start(lua_State* L) {
|
||||||
lua_getfield(L, 2, "stdout"); new_fds[STDOUT_FD] = luaL_optnumber(L, -1, STDOUT_FD);
|
lua_getfield(L, 2, "stdout"); new_fds[STDOUT_FD] = luaL_optnumber(L, -1, STDOUT_FD);
|
||||||
lua_getfield(L, 2, "stderr"); new_fds[STDERR_FD] = luaL_optnumber(L, -1, STDERR_FD);
|
lua_getfield(L, 2, "stderr"); new_fds[STDERR_FD] = luaL_optnumber(L, -1, STDERR_FD);
|
||||||
for (int stream = STDIN_FD; stream <= STDERR_FD; ++stream) {
|
for (int stream = STDIN_FD; stream <= STDERR_FD; ++stream) {
|
||||||
if (new_fds[stream] > STDERR_FD || new_fds[stream] < REDIRECT_PARENT)
|
if (new_fds[stream] > STDERR_FD || new_fds[stream] < REDIRECT_PARENT) {
|
||||||
return luaL_error(L, "redirect to handles, FILE* and paths are not supported");
|
for (size_t i = 0; i < env_len; ++i) {
|
||||||
|
free((char*)env_names[i]);
|
||||||
|
free((char*)env_values[i]);
|
||||||
|
}
|
||||||
|
retval = luaL_error(L, "redirect to handles, FILE* and paths are not supported");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,16 +204,21 @@ static int process_start(lua_State* L) {
|
||||||
sprintf(pipeNameBuffer, "\\\\.\\Pipe\\RemoteExeAnon.%08lx.%08lx", GetCurrentProcessId(), InterlockedIncrement(&PipeSerialNumber));
|
sprintf(pipeNameBuffer, "\\\\.\\Pipe\\RemoteExeAnon.%08lx.%08lx", GetCurrentProcessId(), InterlockedIncrement(&PipeSerialNumber));
|
||||||
self->child_pipes[i][0] = CreateNamedPipeA(pipeNameBuffer, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
self->child_pipes[i][0] = CreateNamedPipeA(pipeNameBuffer, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
||||||
PIPE_TYPE_BYTE | PIPE_WAIT, 1, READ_BUF_SIZE, READ_BUF_SIZE, 0, NULL);
|
PIPE_TYPE_BYTE | PIPE_WAIT, 1, READ_BUF_SIZE, READ_BUF_SIZE, 0, NULL);
|
||||||
if (self->child_pipes[i][0] == INVALID_HANDLE_VALUE)
|
if (self->child_pipes[i][0] == INVALID_HANDLE_VALUE) {
|
||||||
return luaL_error(L, "Error creating read pipe: %d.", GetLastError());
|
retval = luaL_error(L, "Error creating read pipe: %d.", GetLastError());
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
self->child_pipes[i][1] = CreateFileA(pipeNameBuffer, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
self->child_pipes[i][1] = CreateFileA(pipeNameBuffer, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (self->child_pipes[i][1] == INVALID_HANDLE_VALUE) {
|
if (self->child_pipes[i][1] == INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(self->child_pipes[i][0]);
|
CloseHandle(self->child_pipes[i][0]);
|
||||||
return luaL_error(L, "Error creating write pipe: %d.", GetLastError());
|
retval = luaL_error(L, "Error creating write pipe: %d.", GetLastError());
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (!SetHandleInformation(self->child_pipes[i][i == STDIN_FD ? 1 : 0], HANDLE_FLAG_INHERIT, 0) ||
|
if (!SetHandleInformation(self->child_pipes[i][i == STDIN_FD ? 1 : 0], HANDLE_FLAG_INHERIT, 0) ||
|
||||||
!SetHandleInformation(self->child_pipes[i][i == STDIN_FD ? 0 : 1], HANDLE_FLAG_INHERIT, 1))
|
!SetHandleInformation(self->child_pipes[i][i == STDIN_FD ? 0 : 1], HANDLE_FLAG_INHERIT, 1)) {
|
||||||
return luaL_error(L, "Error inheriting pipes: %d.", GetLastError());
|
retval = luaL_error(L, "Error inheriting pipes: %d.", GetLastError());
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -237,24 +258,25 @@ static int process_start(lua_State* L) {
|
||||||
environmentBlock[offset++] = 0;
|
environmentBlock[offset++] = 0;
|
||||||
if (env_len > 0)
|
if (env_len > 0)
|
||||||
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, environmentBlock, offset, (LPWSTR)wideEnvironmentBlock, sizeof(wideEnvironmentBlock));
|
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, environmentBlock, offset, (LPWSTR)wideEnvironmentBlock, sizeof(wideEnvironmentBlock));
|
||||||
if (!CreateProcess(NULL, commandLine, NULL, NULL, true, (detach ? DETACHED_PROCESS : CREATE_NO_WINDOW) | CREATE_UNICODE_ENVIRONMENT, env_len > 0 ? wideEnvironmentBlock : NULL, cwd, &siStartInfo, &self->process_information))
|
if (!CreateProcess(NULL, commandLine, NULL, NULL, true, (detach ? DETACHED_PROCESS : CREATE_NO_WINDOW) | CREATE_UNICODE_ENVIRONMENT, env_len > 0 ? wideEnvironmentBlock : NULL, cwd, &siStartInfo, &self->process_information)) {
|
||||||
return luaL_error(L, "Error creating a process: %d.", GetLastError());
|
retval = luaL_error(L, "Error creating a process: %d.", GetLastError());
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
self->pid = (long)self->process_information.dwProcessId;
|
self->pid = (long)self->process_information.dwProcessId;
|
||||||
if (detach)
|
if (detach)
|
||||||
CloseHandle(self->process_information.hProcess);
|
CloseHandle(self->process_information.hProcess);
|
||||||
CloseHandle(self->process_information.hThread);
|
CloseHandle(self->process_information.hThread);
|
||||||
#else
|
#else
|
||||||
for (int i = 0; i < 3; ++i) { // Make only the parents fd's non-blocking. Children should block.
|
for (int i = 0; i < 3; ++i) { // Make only the parents fd's non-blocking. Children should block.
|
||||||
if (pipe(self->child_pipes[i]) || fcntl(self->child_pipes[i][i == STDIN_FD ? 1 : 0], F_SETFL, O_NONBLOCK) == -1)
|
if (pipe(self->child_pipes[i]) || fcntl(self->child_pipes[i][i == STDIN_FD ? 1 : 0], F_SETFL, O_NONBLOCK) == -1) {
|
||||||
return luaL_error(L, "Error creating pipes: %s", strerror(errno));
|
retval = luaL_error(L, "Error creating pipes: %s", strerror(errno));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self->pid = (long)fork();
|
self->pid = (long)fork();
|
||||||
if (self->pid < 0) {
|
if (self->pid < 0) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
retval = luaL_error(L, "Error running fork: %s.", strerror(errno));
|
||||||
close(self->child_pipes[i][0]);
|
goto cleanup;
|
||||||
close(self->child_pipes[i][1]);
|
|
||||||
}
|
|
||||||
return luaL_error(L, "Error running fork: %s.", strerror(errno));
|
|
||||||
} else if (!self->pid) {
|
} else if (!self->pid) {
|
||||||
setpgrp();
|
setpgrp();
|
||||||
for (int stream = 0; stream < 3; ++stream) {
|
for (int stream = 0; stream < 3; ++stream) {
|
||||||
|
@ -265,23 +287,28 @@ static int process_start(lua_State* L) {
|
||||||
dup2(self->child_pipes[new_fds[stream]][new_fds[stream] == STDIN_FD ? 0 : 1], stream);
|
dup2(self->child_pipes[new_fds[stream]][new_fds[stream] == STDIN_FD ? 0 : 1], stream);
|
||||||
close(self->child_pipes[stream][stream == STDIN_FD ? 1 : 0]);
|
close(self->child_pipes[stream][stream == STDIN_FD ? 1 : 0]);
|
||||||
}
|
}
|
||||||
int set;
|
size_t set;
|
||||||
for (set = 0; set < env_len && setenv(env_names[set], env_values[set], 1) == 0; ++set);
|
for (set = 0; set < env_len && setenv(env_names[set], env_values[set], 1) == 0; ++set);
|
||||||
if (set == env_len && (!detach || setsid() != -1) && (!cwd || chdir(cwd) != -1))
|
if (set == env_len && (!detach || setsid() != -1) && (!cwd || chdir(cwd) != -1))
|
||||||
execvp((const char*)cmd[0], (char* const*)cmd);
|
execvp(cmd[0], (char** const)cmd);
|
||||||
const char* msg = strerror(errno);
|
const char* msg = strerror(errno);
|
||||||
int result = write(STDERR_FD, msg, strlen(msg)+1);
|
size_t result = write(STDERR_FD, msg, strlen(msg)+1);
|
||||||
_exit(result == strlen(msg)+1 ? -1 : -2);
|
_exit(result == strlen(msg)+1 ? -1 : -2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
cleanup:
|
||||||
for (size_t i = 0; i < env_len; ++i) {
|
for (size_t i = 0; i < env_len; ++i) {
|
||||||
free((char*)env_names[i]);
|
free((char*)env_names[i]);
|
||||||
free((char*)env_values[i]);
|
free((char*)env_values[i]);
|
||||||
}
|
}
|
||||||
for (int stream = 0; stream < 3; ++stream)
|
for (int stream = 0; stream < 3; ++stream) {
|
||||||
close_fd(&self->child_pipes[stream][stream == STDIN_FD ? 0 : 1]);
|
process_handle* pipe = &self->child_pipes[stream][stream == STDIN_FD ? 0 : 1];
|
||||||
|
if (*pipe) {
|
||||||
|
close_fd(pipe);
|
||||||
|
}
|
||||||
|
}
|
||||||
self->running = true;
|
self->running = true;
|
||||||
return 1;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int g_read(lua_State* L, int stream, unsigned long read_size) {
|
static int g_read(lua_State* L, int stream, unsigned long read_size) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <string.h>
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "../renderer.h"
|
#include "../renderer.h"
|
||||||
#include "../rencache.h"
|
#include "../rencache.h"
|
||||||
|
@ -166,14 +167,14 @@ static int f_get_size(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_begin_frame(lua_State *L) {
|
static int f_begin_frame(UNUSED lua_State *L) {
|
||||||
rencache_begin_frame(L);
|
rencache_begin_frame();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_end_frame(lua_State *L) {
|
static int f_end_frame(UNUSED lua_State *L) {
|
||||||
rencache_end_frame(L);
|
rencache_end_frame();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +215,7 @@ static int f_draw_text(lua_State *L) {
|
||||||
float x = luaL_checknumber(L, 3);
|
float x = luaL_checknumber(L, 3);
|
||||||
int y = luaL_checknumber(L, 4);
|
int y = luaL_checknumber(L, 4);
|
||||||
RenColor color = checkcolor(L, 5, 255);
|
RenColor color = checkcolor(L, 5, 255);
|
||||||
x = rencache_draw_text(L, fonts, text, x, y, color);
|
x = rencache_draw_text(fonts, text, x, y, color);
|
||||||
lua_pushnumber(L, x);
|
lua_pushnumber(L, x);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct HitTestInfo {
|
||||||
};
|
};
|
||||||
typedef struct HitTestInfo HitTestInfo;
|
typedef struct HitTestInfo HitTestInfo;
|
||||||
|
|
||||||
static HitTestInfo window_hit_info[1] = {{0, 0}};
|
static HitTestInfo window_hit_info[1] = {{0, 0, 0}};
|
||||||
|
|
||||||
#define RESIZE_FROM_TOP 0
|
#define RESIZE_FROM_TOP 0
|
||||||
#define RESIZE_FROM_RIGHT 0
|
#define RESIZE_FROM_RIGHT 0
|
||||||
|
@ -705,13 +705,15 @@ static int f_set_window_opacity(lua_State *L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void (*fptr)(void);
|
||||||
|
|
||||||
typedef struct lua_function_node {
|
typedef struct lua_function_node {
|
||||||
const char *symbol;
|
const char *symbol;
|
||||||
void *address;
|
fptr address;
|
||||||
} lua_function_node;
|
} lua_function_node;
|
||||||
|
|
||||||
#define P(FUNC) { "lua_" #FUNC, (void*)(lua_##FUNC) }
|
#define P(FUNC) { "lua_" #FUNC, (fptr)(lua_##FUNC) }
|
||||||
#define U(FUNC) { "luaL_" #FUNC, (void*)(luaL_##FUNC) }
|
#define U(FUNC) { "luaL_" #FUNC, (fptr)(luaL_##FUNC) }
|
||||||
static void* api_require(const char* symbol) {
|
static void* api_require(const char* symbol) {
|
||||||
static lua_function_node nodes[] = {
|
static lua_function_node nodes[] = {
|
||||||
P(atpanic), P(checkstack),
|
P(atpanic), P(checkstack),
|
||||||
|
@ -749,9 +751,9 @@ static void* api_require(const char* symbol) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
for (int i = 0; i < sizeof(nodes) / sizeof(lua_function_node); ++i) {
|
for (size_t i = 0; i < sizeof(nodes) / sizeof(lua_function_node); ++i) {
|
||||||
if (strcmp(nodes[i].symbol, symbol) == 0)
|
if (strcmp(nodes[i].symbol, symbol) == 0)
|
||||||
return nodes[i].address;
|
return *(void**)(&nodes[i].address);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -775,10 +777,12 @@ static int f_load_native_plugin(lua_State *L) {
|
||||||
const char *basename = strrchr(name, '.');
|
const char *basename = strrchr(name, '.');
|
||||||
basename = !basename ? name : basename + 1;
|
basename = !basename ? name : basename + 1;
|
||||||
snprintf(entrypoint_name, sizeof(entrypoint_name), "luaopen_lite_xl_%s", basename);
|
snprintf(entrypoint_name, sizeof(entrypoint_name), "luaopen_lite_xl_%s", basename);
|
||||||
int (*ext_entrypoint) (lua_State *L, void*) = SDL_LoadFunction(library, entrypoint_name);
|
int (*ext_entrypoint) (lua_State *L, void* (*)(const char*));
|
||||||
|
*(void**)(&ext_entrypoint) = SDL_LoadFunction(library, entrypoint_name);
|
||||||
if (!ext_entrypoint) {
|
if (!ext_entrypoint) {
|
||||||
snprintf(entrypoint_name, sizeof(entrypoint_name), "luaopen_%s", basename);
|
snprintf(entrypoint_name, sizeof(entrypoint_name), "luaopen_%s", basename);
|
||||||
int (*entrypoint)(lua_State *L) = SDL_LoadFunction(library, entrypoint_name);
|
int (*entrypoint)(lua_State *L);
|
||||||
|
*(void**)(&entrypoint) = SDL_LoadFunction(library, entrypoint_name);
|
||||||
if (!entrypoint)
|
if (!entrypoint)
|
||||||
return luaL_error(L, "Unable to load %s: Can't find %s(lua_State *L, void *XL)", name, entrypoint_name);
|
return luaL_error(L, "Unable to load %s: Can't find %s(lua_State *L, void *XL)", name, entrypoint_name);
|
||||||
result = entrypoint(L);
|
result = entrypoint(L);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdalign.h>
|
#include <stdalign.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
#include "rencache.h"
|
#include "rencache.h"
|
||||||
|
@ -28,7 +29,7 @@ typedef struct {
|
||||||
RenColor color;
|
RenColor color;
|
||||||
RenFont *fonts[FONT_FALLBACK_MAX];
|
RenFont *fonts[FONT_FALLBACK_MAX];
|
||||||
float text_x;
|
float text_x;
|
||||||
char text[0];
|
char text[];
|
||||||
} Command;
|
} Command;
|
||||||
|
|
||||||
static unsigned cells_buf1[CELLS_X * CELLS_Y];
|
static unsigned cells_buf1[CELLS_X * CELLS_Y];
|
||||||
|
@ -134,7 +135,7 @@ void rencache_draw_rect(RenRect rect, RenColor color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float rencache_draw_text(lua_State *L, RenFont **fonts, const char *text, float x, int y, RenColor color)
|
float rencache_draw_text(RenFont **fonts, const char *text, float x, int y, RenColor color)
|
||||||
{
|
{
|
||||||
float width = ren_font_group_get_width(fonts, text);
|
float width = ren_font_group_get_width(fonts, text);
|
||||||
RenRect rect = { x, y, (int)width, ren_font_group_get_height(fonts) };
|
RenRect rect = { x, y, (int)width, ren_font_group_get_height(fonts) };
|
||||||
|
@ -159,7 +160,7 @@ void rencache_invalidate(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_begin_frame(lua_State *L) {
|
void rencache_begin_frame() {
|
||||||
/* reset all cells if the screen width/height has changed */
|
/* reset all cells if the screen width/height has changed */
|
||||||
int w, h;
|
int w, h;
|
||||||
ren_get_size(&w, &h);
|
ren_get_size(&w, &h);
|
||||||
|
@ -200,7 +201,7 @@ static void push_rect(RenRect r, int *count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_end_frame(lua_State *L) {
|
void rencache_end_frame() {
|
||||||
/* update cells from commands */
|
/* update cells from commands */
|
||||||
Command *cmd = NULL;
|
Command *cmd = NULL;
|
||||||
RenRect cr = screen_rect;
|
RenRect cr = screen_rect;
|
||||||
|
|
|
@ -8,10 +8,9 @@
|
||||||
void rencache_show_debug(bool enable);
|
void rencache_show_debug(bool enable);
|
||||||
void rencache_set_clip_rect(RenRect rect);
|
void rencache_set_clip_rect(RenRect rect);
|
||||||
void rencache_draw_rect(RenRect rect, RenColor color);
|
void rencache_draw_rect(RenRect rect, RenColor color);
|
||||||
float rencache_draw_text(lua_State *L, RenFont **font,
|
float rencache_draw_text(RenFont **font, const char *text, float x, int y, RenColor color);
|
||||||
const char *text, float x, int y, RenColor color);
|
|
||||||
void rencache_invalidate(void);
|
void rencache_invalidate(void);
|
||||||
void rencache_begin_frame(lua_State *L);
|
void rencache_begin_frame();
|
||||||
void rencache_end_frame(lua_State *L);
|
void rencache_end_frame();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
static RenWindow window_renderer = {0};
|
static RenWindow window_renderer = {0};
|
||||||
static FT_Library library;
|
static FT_Library library;
|
||||||
|
|
||||||
|
// draw_rect_surface is used as a 1x1 surface to simplify ren_draw_rect with blending
|
||||||
|
static SDL_Surface *draw_rect_surface;
|
||||||
|
|
||||||
static void* check_alloc(void *ptr) {
|
static void* check_alloc(void *ptr) {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
fprintf(stderr, "Fatal error: memory allocation failed\n");
|
fprintf(stderr, "Fatal error: memory allocation failed\n");
|
||||||
|
@ -43,27 +46,28 @@ typedef struct RenFont {
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
GlyphSet* sets[SUBPIXEL_BITMAPS_CACHED][MAX_LOADABLE_GLYPHSETS];
|
GlyphSet* sets[SUBPIXEL_BITMAPS_CACHED][MAX_LOADABLE_GLYPHSETS];
|
||||||
float size, space_advance, tab_advance;
|
float size, space_advance, tab_advance;
|
||||||
short max_height, baseline, height;
|
unsigned short max_height, baseline, height;
|
||||||
ERenFontAntialiasing antialiasing;
|
ERenFontAntialiasing antialiasing;
|
||||||
ERenFontHinting hinting;
|
ERenFontHinting hinting;
|
||||||
unsigned char style;
|
unsigned char style;
|
||||||
char path[0];
|
char path[1];
|
||||||
} RenFont;
|
} RenFont;
|
||||||
|
|
||||||
static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
|
static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
|
||||||
|
const unsigned char *up = (unsigned char*)p;
|
||||||
unsigned res, n;
|
unsigned res, n;
|
||||||
switch (*p & 0xf0) {
|
switch (*p & 0xf0) {
|
||||||
case 0xf0 : res = *p & 0x07; n = 3; break;
|
case 0xf0 : res = *up & 0x07; n = 3; break;
|
||||||
case 0xe0 : res = *p & 0x0f; n = 2; break;
|
case 0xe0 : res = *up & 0x0f; n = 2; break;
|
||||||
case 0xd0 :
|
case 0xd0 :
|
||||||
case 0xc0 : res = *p & 0x1f; n = 1; break;
|
case 0xc0 : res = *up & 0x1f; n = 1; break;
|
||||||
default : res = *p; n = 0; break;
|
default : res = *up; n = 0; break;
|
||||||
}
|
}
|
||||||
while (n--) {
|
while (n--) {
|
||||||
res = (res << 6) | (*(++p) & 0x3f);
|
res = (res << 6) | (*(++up) & 0x3f);
|
||||||
}
|
}
|
||||||
*dst = res;
|
*dst = res;
|
||||||
return p + 1;
|
return (const char*)up + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int font_set_load_options(RenFont* font) {
|
static int font_set_load_options(RenFont* font) {
|
||||||
|
@ -136,7 +140,7 @@ static void font_load_glyphset(RenFont* font, int idx) {
|
||||||
if (pen_x == 0)
|
if (pen_x == 0)
|
||||||
continue;
|
continue;
|
||||||
set->surface = check_alloc(SDL_CreateRGBSurface(0, pen_x, font->max_height, font->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? 24 : 8, 0, 0, 0, 0));
|
set->surface = check_alloc(SDL_CreateRGBSurface(0, pen_x, font->max_height, font->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? 24 : 8, 0, 0, 0, 0));
|
||||||
unsigned char* pixels = set->surface->pixels;
|
uint8_t* pixels = set->surface->pixels;
|
||||||
for (int i = 0; i < MAX_GLYPHSET; ++i) {
|
for (int i = 0; i < MAX_GLYPHSET; ++i) {
|
||||||
int glyph_index = FT_Get_Char_Index(font->face, i + idx * MAX_GLYPHSET);
|
int glyph_index = FT_Get_Char_Index(font->face, i + idx * MAX_GLYPHSET);
|
||||||
if (!glyph_index || FT_Load_Glyph(font->face, glyph_index, load_option))
|
if (!glyph_index || FT_Load_Glyph(font->face, glyph_index, load_option))
|
||||||
|
@ -145,11 +149,11 @@ static void font_load_glyphset(RenFont* font, int idx) {
|
||||||
font_set_style(&slot->outline, (64 / bitmaps_cached) * j, font->style);
|
font_set_style(&slot->outline, (64 / bitmaps_cached) * j, font->style);
|
||||||
if (FT_Render_Glyph(slot, render_option))
|
if (FT_Render_Glyph(slot, render_option))
|
||||||
continue;
|
continue;
|
||||||
for (int line = 0; line < slot->bitmap.rows; ++line) {
|
for (unsigned int line = 0; line < slot->bitmap.rows; ++line) {
|
||||||
int target_offset = set->surface->pitch * line + set->metrics[i].x0 * byte_width;
|
int target_offset = set->surface->pitch * line + set->metrics[i].x0 * byte_width;
|
||||||
int source_offset = line * slot->bitmap.pitch;
|
int source_offset = line * slot->bitmap.pitch;
|
||||||
if (font->antialiasing == FONT_ANTIALIASING_NONE) {
|
if (font->antialiasing == FONT_ANTIALIASING_NONE) {
|
||||||
for (int column = 0; column < slot->bitmap.width; ++column) {
|
for (unsigned int column = 0; column < slot->bitmap.width; ++column) {
|
||||||
int current_source_offset = source_offset + (column / 8);
|
int current_source_offset = source_offset + (column / 8);
|
||||||
int source_pixel = slot->bitmap.buffer[current_source_offset];
|
int source_pixel = slot->bitmap.buffer[current_source_offset];
|
||||||
pixels[++target_offset] = ((source_pixel >> (7 - (column % 8))) & 0x1) << 7;
|
pixels[++target_offset] = ((source_pixel >> (7 - (column % 8))) & 0x1) << 7;
|
||||||
|
@ -169,6 +173,9 @@ static GlyphSet* font_get_glyphset(RenFont* font, unsigned int codepoint, int su
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenFont* font_group_get_glyph(GlyphSet** set, GlyphMetric** metric, RenFont** fonts, unsigned int codepoint, int bitmap_index) {
|
static RenFont* font_group_get_glyph(GlyphSet** set, GlyphMetric** metric, RenFont** fonts, unsigned int codepoint, int bitmap_index) {
|
||||||
|
if (!metric) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (bitmap_index < 0)
|
if (bitmap_index < 0)
|
||||||
bitmap_index += SUBPIXEL_BITMAPS_CACHED;
|
bitmap_index += SUBPIXEL_BITMAPS_CACHED;
|
||||||
for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) {
|
for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) {
|
||||||
|
@ -177,7 +184,7 @@ static RenFont* font_group_get_glyph(GlyphSet** set, GlyphMetric** metric, RenFo
|
||||||
if ((*metric)->loaded || codepoint < 0xFF)
|
if ((*metric)->loaded || codepoint < 0xFF)
|
||||||
return fonts[i];
|
return fonts[i];
|
||||||
}
|
}
|
||||||
if (!(*metric)->loaded && codepoint > 0xFF && codepoint != 0x25A1)
|
if (*metric && !(*metric)->loaded && codepoint > 0xFF && codepoint != 0x25A1)
|
||||||
return font_group_get_glyph(set, metric, fonts, 0x25A1, bitmap_index);
|
return font_group_get_glyph(set, metric, fonts, 0x25A1, bitmap_index);
|
||||||
return fonts[0];
|
return fonts[0];
|
||||||
}
|
}
|
||||||
|
@ -195,7 +202,7 @@ RenFont* ren_font_load(const char* path, float size, ERenFontAntialiasing antial
|
||||||
font->face = face;
|
font->face = face;
|
||||||
font->size = size;
|
font->size = size;
|
||||||
font->height = (short)((face->height / (float)face->units_per_EM) * font->size);
|
font->height = (short)((face->height / (float)face->units_per_EM) * font->size);
|
||||||
font->baseline = (short)((face->bbox.yMax / (float)face->units_per_EM) * font->size);
|
font->baseline = (short)((face->ascender / (float)face->units_per_EM) * font->size);
|
||||||
font->antialiasing = antialiasing;
|
font->antialiasing = antialiasing;
|
||||||
font->hinting = hinting;
|
font->hinting = hinting;
|
||||||
font->style = style;
|
font->style = style;
|
||||||
|
@ -233,7 +240,11 @@ void ren_font_group_set_tab_size(RenFont **fonts, int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int ren_font_group_get_tab_size(RenFont **fonts) {
|
int ren_font_group_get_tab_size(RenFont **fonts) {
|
||||||
return font_get_glyphset(fonts[0], '\t', 0)->metrics['\t'].xadvance / fonts[0]->space_advance;
|
int advance = font_get_glyphset(fonts[0], '\t', 0)->metrics['\t'].xadvance;
|
||||||
|
if (fonts[0]->space_advance) {
|
||||||
|
advance /= fonts[0]->space_advance;
|
||||||
|
}
|
||||||
|
return advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
float ren_font_group_get_size(RenFont **fonts) {
|
float ren_font_group_get_size(RenFont **fonts) {
|
||||||
|
@ -251,6 +262,8 @@ float ren_font_group_get_width(RenFont **fonts, const char *text) {
|
||||||
unsigned int codepoint;
|
unsigned int codepoint;
|
||||||
text = utf8_to_codepoint(text, &codepoint);
|
text = utf8_to_codepoint(text, &codepoint);
|
||||||
RenFont* font = font_group_get_glyph(&set, &metric, fonts, codepoint, 0);
|
RenFont* font = font_group_get_glyph(&set, &metric, fonts, codepoint, 0);
|
||||||
|
if (!metric)
|
||||||
|
break;
|
||||||
width += (!font || metric->xadvance) ? metric->xadvance : fonts[0]->space_advance;
|
width += (!font || metric->xadvance) ? metric->xadvance : fonts[0]->space_advance;
|
||||||
}
|
}
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = renwin_surface_scale(&window_renderer);
|
||||||
|
@ -266,7 +279,7 @@ float ren_draw_text(RenFont **fonts, const char *text, float x, int y, RenColor
|
||||||
y *= surface_scale;
|
y *= surface_scale;
|
||||||
int bytes_per_pixel = surface->format->BytesPerPixel;
|
int bytes_per_pixel = surface->format->BytesPerPixel;
|
||||||
const char* end = text + strlen(text);
|
const char* end = text + strlen(text);
|
||||||
unsigned char* destination_pixels = surface->pixels;
|
uint8_t* destination_pixels = surface->pixels;
|
||||||
int clip_end_x = clip.x + clip.width, clip_end_y = clip.y + clip.height;
|
int clip_end_x = clip.x + clip.width, clip_end_y = clip.y + clip.height;
|
||||||
|
|
||||||
while (text < end) {
|
while (text < end) {
|
||||||
|
@ -274,13 +287,15 @@ float ren_draw_text(RenFont **fonts, const char *text, float x, int y, RenColor
|
||||||
text = utf8_to_codepoint(text, &codepoint);
|
text = utf8_to_codepoint(text, &codepoint);
|
||||||
GlyphSet* set = NULL; GlyphMetric* metric = NULL;
|
GlyphSet* set = NULL; GlyphMetric* metric = NULL;
|
||||||
RenFont* font = font_group_get_glyph(&set, &metric, fonts, codepoint, (int)(fmod(pen_x, 1.0) * SUBPIXEL_BITMAPS_CACHED));
|
RenFont* font = font_group_get_glyph(&set, &metric, fonts, codepoint, (int)(fmod(pen_x, 1.0) * SUBPIXEL_BITMAPS_CACHED));
|
||||||
|
if (!metric)
|
||||||
|
break;
|
||||||
int start_x = floor(pen_x) + metric->bitmap_left;
|
int start_x = floor(pen_x) + metric->bitmap_left;
|
||||||
int end_x = (metric->x1 - metric->x0) + start_x;
|
int end_x = (metric->x1 - metric->x0) + start_x;
|
||||||
int glyph_end = metric->x1, glyph_start = metric->x0;
|
int glyph_end = metric->x1, glyph_start = metric->x0;
|
||||||
if (!metric->loaded && codepoint > 0xFF)
|
if (!metric->loaded && codepoint > 0xFF)
|
||||||
ren_draw_rect((RenRect){ start_x + 1, y, font->space_advance - 1, ren_font_group_get_height(fonts) }, color);
|
ren_draw_rect((RenRect){ start_x + 1, y, font->space_advance - 1, ren_font_group_get_height(fonts) }, color);
|
||||||
if (set->surface && color.a > 0 && end_x >= clip.x && start_x < clip_end_x) {
|
if (set->surface && color.a > 0 && end_x >= clip.x && start_x < clip_end_x) {
|
||||||
unsigned char* source_pixels = set->surface->pixels;
|
uint8_t* source_pixels = set->surface->pixels;
|
||||||
for (int line = metric->y0; line < metric->y1; ++line) {
|
for (int line = metric->y0; line < metric->y1; ++line) {
|
||||||
int target_y = line + y - metric->bitmap_top + font->baseline * surface_scale;
|
int target_y = line + y - metric->bitmap_top + font->baseline * surface_scale;
|
||||||
if (target_y < clip.y)
|
if (target_y < clip.y)
|
||||||
|
@ -294,15 +309,30 @@ float ren_draw_text(RenFont **fonts, const char *text, float x, int y, RenColor
|
||||||
start_x += offset;
|
start_x += offset;
|
||||||
glyph_start += offset;
|
glyph_start += offset;
|
||||||
}
|
}
|
||||||
unsigned int* destination_pixel = (unsigned int*)&destination_pixels[surface->pitch * target_y + start_x * bytes_per_pixel];
|
uint32_t* destination_pixel = (uint32_t*)&(destination_pixels[surface->pitch * target_y + start_x * bytes_per_pixel]);
|
||||||
unsigned char* source_pixel = &source_pixels[line * set->surface->pitch + glyph_start * (font->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? 3 : 1)];
|
uint8_t* source_pixel = &source_pixels[line * set->surface->pitch + glyph_start * (font->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? 3 : 1)];
|
||||||
for (int x = glyph_start; x < glyph_end; ++x) {
|
for (int x = glyph_start; x < glyph_end; ++x) {
|
||||||
unsigned int destination_color = *destination_pixel;
|
uint32_t destination_color = *destination_pixel;
|
||||||
|
// the standard way of doing this would be SDL_GetRGBA, but that introduces a performance regression. needs to be investigated
|
||||||
SDL_Color dst = { (destination_color & surface->format->Rmask) >> surface->format->Rshift, (destination_color & surface->format->Gmask) >> surface->format->Gshift, (destination_color & surface->format->Bmask) >> surface->format->Bshift, (destination_color & surface->format->Amask) >> surface->format->Ashift };
|
SDL_Color dst = { (destination_color & surface->format->Rmask) >> surface->format->Rshift, (destination_color & surface->format->Gmask) >> surface->format->Gshift, (destination_color & surface->format->Bmask) >> surface->format->Bshift, (destination_color & surface->format->Amask) >> surface->format->Ashift };
|
||||||
SDL_Color src = { *(font->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? source_pixel++ : source_pixel), *(font->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? source_pixel++ : source_pixel), *source_pixel++ };
|
SDL_Color src;
|
||||||
|
|
||||||
|
if (font->antialiasing == FONT_ANTIALIASING_SUBPIXEL) {
|
||||||
|
src.r = *(source_pixel++);
|
||||||
|
src.g = *(source_pixel++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
src.r = *(source_pixel);
|
||||||
|
src.g = *(source_pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
src.b = *(source_pixel++);
|
||||||
|
src.a = 0xFF;
|
||||||
|
|
||||||
r = (color.r * src.r * color.a + dst.r * (65025 - src.r * color.a) + 32767) / 65025;
|
r = (color.r * src.r * color.a + dst.r * (65025 - src.r * color.a) + 32767) / 65025;
|
||||||
g = (color.g * src.g * color.a + dst.g * (65025 - src.g * color.a) + 32767) / 65025;
|
g = (color.g * src.g * color.a + dst.g * (65025 - src.g * color.a) + 32767) / 65025;
|
||||||
b = (color.b * src.b * color.a + dst.b * (65025 - src.b * color.a) + 32767) / 65025;
|
b = (color.b * src.b * color.a + dst.b * (65025 - src.b * color.a) + 32767) / 65025;
|
||||||
|
// the standard way of doing this would be SDL_GetRGBA, but that introduces a performance regression. needs to be investigated
|
||||||
*destination_pixel++ = dst.a << surface->format->Ashift | r << surface->format->Rshift | g << surface->format->Gshift | b << surface->format->Bshift;
|
*destination_pixel++ = dst.a << surface->format->Ashift | r << surface->format->Rshift | g << surface->format->Gshift | b << surface->format->Bshift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,31 +373,21 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
y2 = y2 > clip.y + clip.height ? clip.y + clip.height : y2;
|
y2 = y2 > clip.y + clip.height ? clip.y + clip.height : y2;
|
||||||
|
|
||||||
SDL_Surface *surface = renwin_get_surface(&window_renderer);
|
SDL_Surface *surface = renwin_get_surface(&window_renderer);
|
||||||
uint32_t *d = surface->pixels;
|
SDL_Rect dest_rect = { x1, y1, x2 - x1, y2 - y1 };
|
||||||
d += x1 + y1 * surface->w;
|
|
||||||
int dr = surface->w - (x2 - x1);
|
|
||||||
if (color.a == 0xff) {
|
if (color.a == 0xff) {
|
||||||
uint32_t translated = SDL_MapRGB(surface->format, color.r, color.g, color.b);
|
uint32_t translated = SDL_MapRGB(surface->format, color.r, color.g, color.b);
|
||||||
SDL_Rect rect = { x1, y1, x2 - x1, y2 - y1 };
|
SDL_FillRect(surface, &dest_rect, translated);
|
||||||
SDL_FillRect(surface, &rect, translated);
|
|
||||||
} else {
|
} else {
|
||||||
RenColor current_color;
|
uint32_t *pixel = (uint32_t *)draw_rect_surface->pixels;
|
||||||
RenColor blended_color;
|
*pixel = SDL_MapRGBA(draw_rect_surface->format, color.r, color.g, color.b, color.a);
|
||||||
for (int j = y1; j < y2; j++) {
|
SDL_BlitScaled(draw_rect_surface, NULL, surface, &dest_rect);
|
||||||
for (int i = x1; i < x2; i++, d++)
|
|
||||||
{
|
|
||||||
SDL_GetRGB(*d, surface->format, ¤t_color.r, ¤t_color.g, ¤t_color.b);
|
|
||||||
blended_color = blend_pixel(current_color, color);
|
|
||||||
*d = SDL_MapRGB(surface->format, blended_color.r, blended_color.g, blended_color.b);
|
|
||||||
}
|
|
||||||
d += dr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************** Window Management ****************/
|
/*************** Window Management ****************/
|
||||||
void ren_free_window_resources() {
|
void ren_free_window_resources() {
|
||||||
renwin_free(&window_renderer);
|
renwin_free(&window_renderer);
|
||||||
|
SDL_FreeSurface(draw_rect_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_init(SDL_Window *win) {
|
void ren_init(SDL_Window *win) {
|
||||||
|
@ -380,6 +400,8 @@ void ren_init(SDL_Window *win) {
|
||||||
window_renderer.window = win;
|
window_renderer.window = win;
|
||||||
renwin_init_surface(&window_renderer);
|
renwin_init_surface(&window_renderer);
|
||||||
renwin_clip_to_surface(&window_renderer);
|
renwin_clip_to_surface(&window_renderer);
|
||||||
|
draw_rect_surface = SDL_CreateRGBSurface(0, 1, 1, 32,
|
||||||
|
0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define UNUSED __attribute__((__unused__))
|
||||||
|
#else
|
||||||
|
#define UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FONT_FALLBACK_MAX 4
|
#define FONT_FALLBACK_MAX 4
|
||||||
typedef struct RenFont RenFont;
|
typedef struct RenFont RenFont;
|
||||||
typedef enum { FONT_HINTING_NONE, FONT_HINTING_SLIGHT, FONT_HINTING_FULL } ERenFontHinting;
|
typedef enum { FONT_HINTING_NONE, FONT_HINTING_SLIGHT, FONT_HINTING_FULL } ERenFontHinting;
|
||||||
|
|
|
@ -27,7 +27,7 @@ static void setup_renderer(RenWindow *ren, int w, int h) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void renwin_init_surface(RenWindow *ren) {
|
void renwin_init_surface(UNUSED RenWindow *ren) {
|
||||||
#ifdef LITE_USE_SDL_RENDERER
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
if (ren->surface) {
|
if (ren->surface) {
|
||||||
SDL_FreeSurface(ren->surface);
|
SDL_FreeSurface(ren->surface);
|
||||||
|
@ -39,7 +39,7 @@ void renwin_init_surface(RenWindow *ren) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int renwin_surface_scale(RenWindow *ren) {
|
int renwin_surface_scale(UNUSED RenWindow *ren) {
|
||||||
#ifdef LITE_USE_SDL_RENDERER
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
return ren->surface_scale;
|
return ren->surface_scale;
|
||||||
#else
|
#else
|
||||||
|
@ -72,7 +72,7 @@ SDL_Surface *renwin_get_surface(RenWindow *ren) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void renwin_resize_surface(RenWindow *ren) {
|
void renwin_resize_surface(UNUSED RenWindow *ren) {
|
||||||
#ifdef LITE_USE_SDL_RENDERER
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
int new_w, new_h;
|
int new_w, new_h;
|
||||||
SDL_GL_GetDrawableSize(ren->window, &new_w, &new_h);
|
SDL_GL_GetDrawableSize(ren->window, &new_w, &new_h);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
[wrap-file]
|
[wrap-file]
|
||||||
directory = SDL2-2.0.18
|
directory = SDL2-2.0.20
|
||||||
source_url = https://www.libsdl.org/release/SDL2-2.0.18.tar.gz
|
source_url = https://libsdl.org/release/SDL2-2.0.20.tar.gz
|
||||||
source_filename = SDL2-2.0.18.tar.gz
|
source_filename = SDL2-2.0.20.tar.gz
|
||||||
source_hash = 94d40cd73dbfa10bb6eadfbc28f355992bb2d6ef6761ad9d4074eff95ee5711c
|
source_hash = c56aba1d7b5b0e7e999e4a7698c70b63a3394ff9704b5f6e1c57e0c16f04dd06
|
||||||
patch_filename = sdl2_2.0.18-2_patch.zip
|
patch_filename = sdl2_2.0.20-3_patch.zip
|
||||||
patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_2.0.18-2/get_patch
|
patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_2.0.20-3/get_patch
|
||||||
patch_hash = cd77f33395d3d019bb89217b9da41fc640ed8c78cbbbebc5c662155a25e2820e
|
patch_hash = ade644ba46cefa4f1f9e57aa23bacc5dabf762d1f90d8416a1e1e4b0b7a188c4
|
||||||
|
|
||||||
[provide]
|
[provide]
|
||||||
sdl2 = sdl2_dep
|
sdl2 = sdl2_dep
|
||||||
|
|
Loading…
Reference in New Issue