diff --git a/data/core/commands/core.lua b/data/core/commands/core.lua index a13f760..afba8d2 100644 --- a/data/core/commands/core.lua +++ b/data/core/commands/core.lua @@ -28,6 +28,8 @@ command.add(nil, { ["core:toggle-fullscreen"] = function() fullscreen = not fullscreen system.set_window_mode(fullscreen and "fullscreen" or "normal") + core.show_title_bar(not fullscreen) + core.title_view:configure_hit_test(not fullscreen) end, ["core:reload-module"] = function() diff --git a/data/core/config.lua b/data/core/config.lua index 5ee5d57..4c56a69 100644 --- a/data/core/config.lua +++ b/data/core/config.lua @@ -22,6 +22,7 @@ config.transitions = true config.animation_rate = 1.0 config.blink_period = 0.8 config.draw_whitespace = false +config.borderless = true -- Disable plugin loading setting to false the config entry -- of the same name. diff --git a/data/core/init.lua b/data/core/init.lua index 442287d..fe1f52c 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -6,6 +6,7 @@ local command local keymap local RootView local StatusView +local TitleView local CommandView local NagView local DocView @@ -358,6 +359,7 @@ function core.init() keymap = require "core.keymap" RootView = require "core.rootview" StatusView = require "core.statusview" + TitleView = require "core.titleview" CommandView = require "core.commandview" NagView = require "core.nagview" DocView = require "core.docview" @@ -402,6 +404,7 @@ function core.init() core.clip_rect_stack = {{ 0,0,0,0 }} core.log_items = {} core.docs = {} + core.window_mode = "normal" core.threads = setmetatable({}, { __mode = "k" }) core.blink_start = system.get_time() core.blink_timer = core.blink_start @@ -432,9 +435,12 @@ function core.init() core.command_view = CommandView() core.status_view = StatusView() core.nag_view = NagView() + core.title_view = TitleView() local cur_node = core.root_view.root_node cur_node.is_primary_node = true + cur_node:split("up", core.title_view, {y = true}) + cur_node = cur_node.b cur_node:split("up", core.nag_view, {y = true}) cur_node = cur_node.b cur_node = cur_node:split("down", core.command_view, {y = true}) @@ -443,7 +449,7 @@ function core.init() core.project_scan_thread_id = core.add_thread(project_scan_thread) command.add_defaults() local got_user_error = not core.load_user_directory() - local got_plugin_error = not core.load_plugins() + local plugins_success, plugins_refuse_list = core.load_plugins() do local pdir, pname = project_dir_abs:match("(.*)[/\\\\](.*)") @@ -459,9 +465,35 @@ function core.init() core.error(delayed_error) end - if got_plugin_error or got_user_error or got_project_error then + if not plugins_success or got_user_error or got_project_error then command.perform("core:open-log") end + + system.set_window_bordered(not config.borderless) + core.title_view:configure_hit_test(config.borderless) + core.title_view.visible = config.borderless + + if #plugins_refuse_list.userdir.plugins > 0 or #plugins_refuse_list.datadir.plugins > 0 then + local opt = { + { font = style.font, text = "Exit", default_no = true }, + { font = style.font, text = "Continue" , default_yes = true } + } + local msg = {} + for _, entry in pairs(plugins_refuse_list) do + if #entry.plugins > 0 then + msg[#msg + 1] = string.format("Plugins from directory \"%s\":\n%s", common.home_encode(entry.dir), table.concat(entry.plugins, "\n")) + end + end + core.nag_view:show( + "Refused Plugins", + string.format( + "Some plugins are not loaded due to version mismatch.\n\n%s.\n\n" .. + "Please download a recent version from https://github.com/franko/lite-plugins.", + table.concat(msg, ".\n\n")), + opt, function(item) + if item.text == "Exit" then os.exit(1) end + end) + end end @@ -554,14 +586,53 @@ function core.restart() end +local function version_components(version) + local a, b, c = version:match('(%d+)%.(%d+)%.(%d+)') + if a then + return tonumber(a), tonumber(b), tonumber(c) + end + a, b = version:match('(%d+)%.(%d+)') + if a then + return tonumber(a), tonumber(b) + end +end + + +local function check_plugin_version(filename) + local f = io.open(filename, "r") + if not f then return false end + local version_match = false + for line in f:lines() do + local version = line:match('%-%-%s*lite%-xl%s*(%d+%.%d+)%s*$') + if not version then break end + local ver_major, ver_minor = version_components(version) + local ref_major, ref_minor = version_components(VERSION) + version_match = (ver_major == ref_major and ver_minor == ref_minor) + break + end + f:close() + return version_match +end + + function core.load_plugins() local no_errors = true + local refused_list = { + userdir = {dir = USERDIR, plugins = {}}, + datadir = {dir = DATADIR, plugins = {}}, + } for _, root_dir in ipairs {USERDIR, DATADIR} do local plugin_dir = root_dir .. "/plugins" local files = system.list_dir(plugin_dir) for _, filename in ipairs(files or {}) do local basename = filename:match("(.-)%.lua$") or filename - if config[basename] ~= false then + local version_match = check_plugin_version(plugin_dir .. '/' .. filename) + if not version_match then + core.log_quiet("Version mismatch for plugin %q from %s", basename, plugin_dir) + local ls = refused_list[root_dir == USERDIR and 'userdir' or 'datadir'].plugins + ls[#ls + 1] = filename + end + if version_match and config[basename] ~= false then local modname = "plugins." .. basename local ok = core.try(require, modname) if ok then core.log_quiet("Loaded plugin %q from %s", basename, plugin_dir) end @@ -571,7 +642,7 @@ function core.load_plugins() end end end - return no_errors + return no_errors, refused_list end @@ -624,6 +695,11 @@ function core.set_active_view(view) end +function core.show_title_bar(show) + core.title_view.visible = show +end + + function core.add_thread(f, weak_ref) local key = weak_ref or #core.threads + 1 local fn = function() return core.try(f) end @@ -741,6 +817,10 @@ function core.on_event(type, ...) core.root_view:on_mouse_released(...) elseif type == "mousewheel" then core.root_view:on_mouse_wheel(...) + elseif type == "resized" then + core.window_mode = system.get_window_mode() + elseif type == "minimized" or type == "maximized" or type == "restored" then + core.window_mode = type == "restored" and "normal" or type elseif type == "filedropped" then local filename, mx, my = ... local info = system.get_file_info(filename) @@ -769,7 +849,7 @@ local function get_title_filename(view) end -local function compose_window_title(title) +function core.compose_window_title(title) return title == "" and "Lite XL" or title .. " - Lite XL" end @@ -818,7 +898,7 @@ function core.step() -- update window title local current_title = get_title_filename(core.active_view) if current_title ~= core.window_title then - system.set_window_title(compose_window_title(current_title)) + system.set_window_title(core.compose_window_title(current_title)) core.window_title = current_title end diff --git a/data/core/nagview.lua b/data/core/nagview.lua index ff5bad1..accb1a4 100644 --- a/data/core/nagview.lua +++ b/data/core/nagview.lua @@ -1,6 +1,7 @@ local core = require "core" local command = require "core.command" local common = require "core.common" +local config = require "core.config" local View = require "core.view" local style = require "core.style" @@ -23,24 +24,33 @@ function NagView:get_title() return self.title end -function NagView:get_options_line_height() - local max = 0 - for _, opt in ipairs(self.options) do - local lh = style.font:get_height(opt.text) - if lh > max then max = lh end - end - return max +-- The two methods below are duplicated from DocView +function NagView:get_line_height() + return math.floor(style.font:get_height() * config.line_height) end -function NagView:get_line_height() - return self.max_lh + 2 * BORDER_WIDTH + 2 * style.padding.y +function NagView:get_line_text_y_offset() + local lh = self:get_line_height() + local th = style.font:get_height() + return (lh - th) / 2 +end + +-- Buttons height without padding +function NagView:get_buttons_height() + local lh = style.font:get_height() + local bt_padding = lh / 2 + return lh + 2 * BORDER_WIDTH + 2 * bt_padding +end + +function NagView:get_target_height() + return self.target_height + 2 * style.padding.y end function NagView:update() NagView.super.update(self) if core.active_view == self and self.title then - self:move_towards(self.size, "y", self:get_line_height()) + self:move_towards(self.size, "y", self:get_target_height()) self:move_towards(self, "underline_progress", 1) else self:move_towards(self.size, "y", 0) @@ -68,10 +78,10 @@ function NagView:each_option() return coroutine.wrap(function() if not self.options then return end local opt, bw,bh,ox,oy - bh = self.max_lh + 2 * BORDER_WIDTH + style.padding.y + bh = self:get_buttons_height() ox,oy = self:get_content_offset() ox = ox + self.size.x - oy = oy + (self.size.y / 2) - (bh / 2) + oy = oy + self.size.y - bh - style.padding.y for i = #self.options, 1, -1 do opt = self.options[i] @@ -112,6 +122,7 @@ function NagView:on_text_input(text) end end + function NagView:draw() if self.size.y <= 0 or not self.title then return end @@ -129,7 +140,13 @@ function NagView:draw() end -- draw message - common.draw_text(style.font, style.nagbar_text, self.message, "left", ox, oy, self.size.x, self.size.y) + local lh = style.font:get_height() * config.line_height + oy = oy + style.padding.y + (self.target_height - self:get_message_height()) / 2 + for msg_line in self.message:gmatch("(.-)\n") do + local ty = oy + self:get_line_text_y_offset() + renderer.draw_text(style.font, msg_line, ox, ty, style.nagbar_text) + oy = oy + lh + end -- draw buttons for i, opt, bx,by,bw,bh in self:each_option() do @@ -159,14 +176,26 @@ local function findindex(tbl, prop) end end +function NagView:get_message_height() + local h = 0 + for str in string.gmatch(self.message, "(.-)\n") do + h = h + style.font:get_height() * config.line_height + end + return h +end + + function NagView:next() local opts = table.remove(self.queue, 1) or {} self.title = opts.title - self.message = opts.message + self.message = opts.message and opts.message .. "\n" self.options = opts.options self.on_selected = opts.on_selected if self.message and self.options then - self.max_lh = math.max(style.font:get_height(self.message), self:get_options_line_height()) + local message_height = self:get_message_height() + -- self.target_height is the nagview height needed to display the message and + -- the buttons, excluding the top and bottom padding space. + self.target_height = math.max(message_height, self:get_buttons_height()) self:change_hovered(findindex(self.options, "default_yes")) end self.force_focus = self.message ~= nil diff --git a/data/core/titleview.lua b/data/core/titleview.lua new file mode 100644 index 0000000..9090861 --- /dev/null +++ b/data/core/titleview.lua @@ -0,0 +1,119 @@ +local core = require "core" +local common = require "core.common" +local style = require "core.style" +local View = require "core.view" + +local restore_command = { + symbol = "w", action = function() system.set_window_mode("normal") end +} + +local maximize_command = { + symbol = "W", action = function() system.set_window_mode("maximized") end +} + +local title_commands = { + {symbol = "_", action = function() system.set_window_mode("minimized") end}, + maximize_command, + {symbol = "X", action = function() core.quit() end}, +} + +local TitleView = View:extend() + +local function title_view_height() + return style.font:get_height() + style.padding.y * 2 +end + +function TitleView:new() + TitleView.super.new(self) + self.visible = true +end + +function TitleView:configure_hit_test(borderless) + if borderless then + local title_height = title_view_height() + local icon_w = style.icon_font:get_width("_") + local icon_spacing = icon_w + local controls_width = (icon_w + icon_spacing) * #title_commands + icon_spacing + system.set_window_hit_test(title_height, controls_width, icon_spacing) + -- core.hit_test_title_height = title_height + else + system.set_window_hit_test() + end +end + +function TitleView:update() + self.size.y = self.visible and title_view_height() or 0 + title_commands[2] = core.window_mode == "maximized" and restore_command or maximize_command + TitleView.super.update(self) +end + + +function TitleView:draw_window_title() + local h = style.font:get_height() + local ox, oy = self:get_content_offset() + local color = style.text + local x, y = ox + style.padding.x, oy + style.padding.y + x = common.draw_text(style.icon_font, color, "M ", nil, x, y, 0, h) + local title = core.compose_window_title(core.window_title) + common.draw_text(style.font, color, title, nil, x, y, 0, h) +end + +function TitleView:each_control_item() + local icon_h, icon_w = style.icon_font:get_height(), style.icon_font:get_width("_") + local icon_spacing = icon_w + local ox, oy = self:get_content_offset() + ox = ox + self.size.x + local i, n = 0, #title_commands + local iter = function() + i = i + 1 + if i <= n then + local dx = - (icon_w + icon_spacing) * (n - i + 1) + local dy = style.padding.y + return title_commands[i], ox + dx, oy + dy, icon_w, icon_h + end + end + return iter +end + + +function TitleView:draw_window_controls() + for item, x, y, w, h in self:each_control_item() do + local color = item == self.hovered_item and style.text or style.dim + common.draw_text(style.icon_font, color, item.symbol, nil, x, y, 0, h) + end +end + + +function TitleView:on_mouse_pressed(button, x, y, clicks) + local caught = TitleView.super.on_mouse_pressed(self, button, x, y, clicks) + if caught then return end + core.set_active_view(core.last_active_view) + if self.hovered_item then + self.hovered_item.action() + end +end + + +function TitleView:on_mouse_moved(px, py, ...) + if self.size.y == 0 then return end + TitleView.super.on_mouse_moved(self, px, py, ...) + self.hovered_item = nil + local x_min, x_max, y_min, y_max = self.size.x, 0, self.size.y, 0 + for item, x, y, w, h in self:each_control_item() do + x_min, x_max = math.min(x, x_min), math.max(x + w, x_max) + y_min, y_max = y, y + h + if px > x and py > y and px <= x + w and py <= y + h then + self.hovered_item = item + return + end + end +end + + +function TitleView:draw() + self:draw_background(style.background2) + self:draw_window_title() + self:draw_window_controls() +end + +return TitleView diff --git a/data/fonts/icons.ttf b/data/fonts/icons.ttf index 2b24bae..00b4cc3 100644 Binary files a/data/fonts/icons.ttf and b/data/fonts/icons.ttf differ diff --git a/data/plugins/autocomplete.lua b/data/plugins/autocomplete.lua index ee318a1..c0a3d36 100644 --- a/data/plugins/autocomplete.lua +++ b/data/plugins/autocomplete.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local common = require "core.common" local config = require "core.config" diff --git a/data/plugins/autoreload.lua b/data/plugins/autoreload.lua index a077b6d..cbef8a2 100644 --- a/data/plugins/autoreload.lua +++ b/data/plugins/autoreload.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local config = require "core.config" local Doc = require "core.doc" diff --git a/data/plugins/detectindent.lua b/data/plugins/detectindent.lua index 2a97e29..9ee171e 100644 --- a/data/plugins/detectindent.lua +++ b/data/plugins/detectindent.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local command = require "core.command" local common = require "core.common" diff --git a/data/plugins/language_c.lua b/data/plugins/language_c.lua index 8e8ee98..9bb074b 100644 --- a/data/plugins/language_c.lua +++ b/data/plugins/language_c.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/language_css.lua b/data/plugins/language_css.lua index 9ea3d0d..acd0139 100644 --- a/data/plugins/language_css.lua +++ b/data/plugins/language_css.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/language_js.lua b/data/plugins/language_js.lua index af65065..9f877ef 100644 --- a/data/plugins/language_js.lua +++ b/data/plugins/language_js.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/language_lua.lua b/data/plugins/language_lua.lua index 915d273..64b7847 100644 --- a/data/plugins/language_lua.lua +++ b/data/plugins/language_lua.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/language_md.lua b/data/plugins/language_md.lua index 9f0f14e..0998c11 100644 --- a/data/plugins/language_md.lua +++ b/data/plugins/language_md.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/language_python.lua b/data/plugins/language_python.lua index e6315c4..b9c07e4 100644 --- a/data/plugins/language_python.lua +++ b/data/plugins/language_python.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/language_xml.lua b/data/plugins/language_xml.lua index 5240bdc..8687ab6 100644 --- a/data/plugins/language_xml.lua +++ b/data/plugins/language_xml.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local syntax = require "core.syntax" syntax.add { diff --git a/data/plugins/macro.lua b/data/plugins/macro.lua index 3458977..c887310 100644 --- a/data/plugins/macro.lua +++ b/data/plugins/macro.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local command = require "core.command" local keymap = require "core.keymap" diff --git a/data/plugins/projectsearch.lua b/data/plugins/projectsearch.lua index 22c16ef..c449933 100644 --- a/data/plugins/projectsearch.lua +++ b/data/plugins/projectsearch.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local common = require "core.common" local keymap = require "core.keymap" diff --git a/data/plugins/quote.lua b/data/plugins/quote.lua index b17407d..bca0797 100644 --- a/data/plugins/quote.lua +++ b/data/plugins/quote.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local command = require "core.command" local keymap = require "core.keymap" diff --git a/data/plugins/reflow.lua b/data/plugins/reflow.lua index 95090a6..9556e37 100644 --- a/data/plugins/reflow.lua +++ b/data/plugins/reflow.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local config = require "core.config" local command = require "core.command" diff --git a/data/plugins/tabularize.lua b/data/plugins/tabularize.lua index f4dda1f..3182152 100644 --- a/data/plugins/tabularize.lua +++ b/data/plugins/tabularize.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local command = require "core.command" local translate = require "core.doc.translate" diff --git a/data/plugins/toolbarview.lua b/data/plugins/toolbarview.lua index 65e782a..2edfa8b 100644 --- a/data/plugins/toolbarview.lua +++ b/data/plugins/toolbarview.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local common = require "core.common" local command = require "core.command" diff --git a/data/plugins/treeview.lua b/data/plugins/treeview.lua index 5e16ce5..44422b7 100644 --- a/data/plugins/treeview.lua +++ b/data/plugins/treeview.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local common = require "core.common" local command = require "core.command" diff --git a/data/plugins/trimwhitespace.lua b/data/plugins/trimwhitespace.lua index d4d25c8..5a43653 100644 --- a/data/plugins/trimwhitespace.lua +++ b/data/plugins/trimwhitespace.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local command = require "core.command" local Doc = require "core.doc" diff --git a/data/plugins/workspace.lua b/data/plugins/workspace.lua index 81d2207..c24358c 100644 --- a/data/plugins/workspace.lua +++ b/data/plugins/workspace.lua @@ -1,3 +1,4 @@ +-- lite-xl 1.16 local core = require "core" local common = require "core.common" local DocView = require "core.docview" diff --git a/dev-utils/fontello-config-small.json b/dev-utils/fontello-config-small.json index ff3952f..895de30 100644 --- a/dev-utils/fontello-config-small.json +++ b/dev-utils/fontello-config-small.json @@ -1,5 +1,5 @@ { - "name": "", + "name": "icons", "css_prefix_text": "icon-", "css_use_suffix": false, "hinting": true, @@ -83,6 +83,36 @@ "css": "cancel-1", "code": 67, "src": "fontawesome" + }, + { + "uid": "04f022b8bd044d4ccfffd3887ff72088", + "css": "window-minimize", + "code": 95, + "src": "fontawesome" + }, + { + "uid": "d0e62145dbf40f30e47b3819b8b43a8f", + "css": "window-restore", + "code": 119, + "src": "fontawesome" + }, + { + "uid": "7394501fc0b17cb7bda99538f92e26d6", + "css": "window-close", + "code": 88, + "src": "fontawesome" + }, + { + "uid": "559647a6f430b3aeadbecd67194451dd", + "css": "menu-1", + "code": 77, + "src": "fontawesome" + }, + { + "uid": "07f0832c07f3d9713fffb06c8bffa027", + "css": "window-maximize", + "code": 87, + "src": "fontawesome" } ] -} +} \ No newline at end of file diff --git a/dev-utils/run-plugin b/dev-utils/run-plugin new file mode 100755 index 0000000..ee950b0 --- /dev/null +++ b/dev-utils/run-plugin @@ -0,0 +1,87 @@ +#!/bin/bash + +set -o errexit + +option_copy=on +pargs=() +while [[ "$#" -gt 0 ]]; do + case $1 in + -keep) + option_copy=off + ;; + -global) + option_global=on + ;; + -*) + echo "error: unknown option \"$1\"" + exit 1 + ;; + *) + pargs+=("$1") + ;; + esac + shift +done + +if [ "${#pargs[@]}" -lt 3 ]; then + echo "usage: $0 [options] " + exit 1 +fi + +plugin_dir="${pargs[0]}" +plugin="${pargs[1]}" + +if [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "mingw"* ]]; then + run_windows=yes +fi + +rundir=".run" +bindir="$rundir/bin" +datadir="$rundir/share/lite-xl" + +userdir="$(realpath "$rundir")" +builddir="${pargs[2]}" + +build_lite () { + echo "running ninja" + ninja -C "$builddir" +} + +copy_lite_build () { + echo "copying lite executable and data" + rm -fr "$rundir" + mkdir -p "$bindir" "$datadir" + if [ ! -z ${run_windows+x} ]; then + cp "$builddir/src/lite.exe" "$bindir" + else + cp "$builddir/src/lite" "$bindir" + fi + for module_name in core plugins colors fonts; do + cp -r "data/$module_name" "$datadir" + done +} + +run_lite () { + if [ ! -z ${option_global+x} ]; then + echo "running \"lite ${pargs[@]:3}\"" + exec "$bindir/lite" "${pargs[@]:3}" + else + echo "running \"lite ${pargs[@]:3}\" with local HOME" + if [ ! -z ${run_windows+x} ]; then + USERPROFILE="$userdir" exec "$bindir/lite" "${pargs[@]:3}" + else + HOME="$userdir" exec "$bindir/lite" "${pargs[@]:3}" + fi + fi +} + +copy_plugin () { + echo "-- lite-xl 1.16" | cat - "$plugin_dir/$plugin.lua" > "$datadir/plugins/$plugin.lua" +} + +if [ $option_copy == on ]; then + build_lite + copy_lite_build +fi +copy_plugin +run_lite diff --git a/src/api/system.c b/src/api/system.c index 44f57fb..224c6ac 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -35,6 +35,62 @@ static char* key_name(char *dst, int sym) { return dst; } +struct HitTestInfo { + int title_height; + int controls_width; + int resize_border; +}; +typedef struct HitTestInfo HitTestInfo; + +static HitTestInfo window_hit_info[1] = {{0, 0}}; + +#define RESIZE_FROM_TOP 0 +#define RESIZE_FROM_RIGHT 0 + +static SDL_HitTestResult SDLCALL hit_test(SDL_Window *window, const SDL_Point *pt, void *data) { + const HitTestInfo *hit_info = (HitTestInfo *) data; + const int resize_border = hit_info->resize_border; + const int controls_width = hit_info->controls_width; + int w, h; + + SDL_GetWindowSize(window, &w, &h); + + if (pt->y < hit_info->title_height && + #if RESIZE_FROM_TOP + pt->y > hit_info->resize_border && + #endif + pt->x > resize_border && pt->x < w - controls_width) { + return SDL_HITTEST_DRAGGABLE; + } + + #define REPORT_RESIZE_HIT(name) { \ + return SDL_HITTEST_RESIZE_##name; \ + } + + if (pt->x < resize_border && pt->y < resize_border) { + REPORT_RESIZE_HIT(TOPLEFT); + #if RESIZE_FROM_TOP + } else if (pt->x > resize_border && pt->x < w - controls_width && pt->y < resize_border) { + REPORT_RESIZE_HIT(TOP); + #endif + } else if (pt->x > w - resize_border && pt->y < resize_border) { + REPORT_RESIZE_HIT(TOPRIGHT); + #if RESIZE_FROM_RIGHT + } else if (pt->x > w - resize_border && pt->y > resize_border && pt->y < h - resize_border) { + REPORT_RESIZE_HIT(RIGHT); + #endif + } else if (pt->x > w - resize_border && pt->y > h - resize_border) { + REPORT_RESIZE_HIT(BOTTOMRIGHT); + } else if (pt->x < w - resize_border && pt->x > resize_border && pt->y > h - resize_border) { + REPORT_RESIZE_HIT(BOTTOM); + } else if (pt->x < resize_border && pt->y > h - resize_border) { + REPORT_RESIZE_HIT(BOTTOMLEFT); + } else if (pt->x < resize_border && pt->y < h - resize_border && pt->y > resize_border) { + REPORT_RESIZE_HIT(LEFT); + } + + return SDL_HITTEST_NORMAL; +} static int f_poll_event(lua_State *L) { char buf[16]; @@ -61,6 +117,15 @@ top: rencache_invalidate(); lua_pushstring(L, "exposed"); return 1; + } else if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) { + lua_pushstring(L, "minimized"); + return 1; + } else if (e.window.event == SDL_WINDOWEVENT_MAXIMIZED) { + lua_pushstring(L, "maximized"); + return 1; + } else if (e.window.event == SDL_WINDOWEVENT_RESTORED) { + lua_pushstring(L, "restored"); + return 1; } if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { lua_pushstring(L, "focuslost"); @@ -188,8 +253,8 @@ static int f_set_window_title(lua_State *L) { } -static const char *window_opts[] = { "normal", "maximized", "fullscreen", 0 }; -enum { WIN_NORMAL, WIN_MAXIMIZED, WIN_FULLSCREEN }; +static const char *window_opts[] = { "normal", "minimized", "maximized", "fullscreen", 0 }; +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); @@ -197,6 +262,27 @@ static int f_set_window_mode(lua_State *L) { n == WIN_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); if (n == WIN_NORMAL) { SDL_RestoreWindow(window); } if (n == WIN_MAXIMIZED) { SDL_MaximizeWindow(window); } + if (n == WIN_MINIMIZED) { SDL_MinimizeWindow(window); } + return 0; +} + + +static int f_set_window_bordered(lua_State *L) { + int bordered = lua_toboolean(L, 1); + SDL_SetWindowBordered(window, bordered); + return 0; +} + + +static int f_set_window_hit_test(lua_State *L) { + if (lua_gettop(L) == 0) { + SDL_SetWindowHitTest(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, hit_test, window_hit_info); return 0; } @@ -231,6 +317,21 @@ static int f_window_has_focus(lua_State *L) { } +static int f_get_window_mode(lua_State *L) { + unsigned flags = SDL_GetWindowFlags(window); + if (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { + lua_pushstring(L, "fullscreen"); + } else if (flags & SDL_WINDOW_MINIMIZED) { + lua_pushstring(L, "minimized"); + } else if (flags & SDL_WINDOW_MAXIMIZED) { + lua_pushstring(L, "maximized"); + } else { + lua_pushstring(L, "normal"); + } + return 1; +} + + static int f_show_fatal_error(lua_State *L) { const char *title = luaL_checkstring(L, 1); const char *msg = luaL_checkstring(L, 2); @@ -441,6 +542,9 @@ static const luaL_Reg lib[] = { { "set_cursor", f_set_cursor }, { "set_window_title", f_set_window_title }, { "set_window_mode", f_set_window_mode }, + { "get_window_mode", f_get_window_mode }, + { "set_window_bordered", f_set_window_bordered }, + { "set_window_hit_test", f_set_window_hit_test }, { "get_window_size", f_get_window_size }, { "set_window_size", f_set_window_size }, { "window_has_focus", f_window_has_focus },