Merge pull request #773 from Elv13/add_testing_framework
tests: Add a new GUI testing framework
This commit is contained in:
commit
b1a93e4540
|
@ -299,6 +299,11 @@ set(AWESOME_THEMES_PATH ${AWESOME_DATA_PATH}/themes)
|
||||||
if(GENERATE_DOC)
|
if(GENERATE_DOC)
|
||||||
# Generate some images and examples
|
# Generate some images and examples
|
||||||
include(docs/generate_examples.cmake)
|
include(docs/generate_examples.cmake)
|
||||||
|
|
||||||
|
# Use `include`, rather than `add_subdirectory`, to keep the variables
|
||||||
|
# The file is a valid CMakeLists.txt and can be executed directly if only
|
||||||
|
# the image artefacts are needed.
|
||||||
|
include(tests/examples/CMakeLists.txt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# {{{ Configure files
|
# {{{ Configure files
|
||||||
|
|
|
@ -11,6 +11,7 @@ local capi = { awesome = awesome }
|
||||||
local cairo = require("lgi").cairo
|
local cairo = require("lgi").cairo
|
||||||
local color = nil
|
local color = nil
|
||||||
local gdebug = require("gears.debug")
|
local gdebug = require("gears.debug")
|
||||||
|
local hierarchy = require("wibox.hierarchy")
|
||||||
|
|
||||||
-- Keep this in sync with build-utils/lgi-check.sh!
|
-- Keep this in sync with build-utils/lgi-check.sh!
|
||||||
local ver_major, ver_minor, ver_patch = string.match(require('lgi.version'), '(%d)%.(%d)%.(%d)')
|
local ver_major, ver_minor, ver_patch = string.match(require('lgi.version'), '(%d)%.(%d)%.(%d)')
|
||||||
|
@ -205,6 +206,53 @@ function surface.apply_shape_bounding(draw, shape, ...)
|
||||||
draw.shape_bounding = img._native
|
draw.shape_bounding = img._native
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function no_op() end
|
||||||
|
|
||||||
|
local function run_in_hierarchy(self, cr, width, height)
|
||||||
|
|
||||||
|
local function redraw(h)
|
||||||
|
h:draw({dpi=96}, cr)
|
||||||
|
end
|
||||||
|
|
||||||
|
local h = hierarchy.new({dpi=96}, self, width, height, redraw, no_op, {})
|
||||||
|
|
||||||
|
redraw(h)
|
||||||
|
|
||||||
|
return h
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create an SVG file with this widget content.
|
||||||
|
-- This is dynamic, so the SVG will be updated along with the widget content.
|
||||||
|
-- because of this, the painting may happen hover multiple event loop cycles.
|
||||||
|
-- @tparam widget widget A widget
|
||||||
|
-- @tparam string path The output file path
|
||||||
|
-- @tparam number width The surface width
|
||||||
|
-- @tparam number height The surface height
|
||||||
|
-- @return The cairo surface
|
||||||
|
-- @return The hierarchy
|
||||||
|
function surface.widget_to_svg(widget, path, width, height)
|
||||||
|
local img = cairo.SvgSurface.create(path, width, height)
|
||||||
|
local cr = cairo.Context(img)
|
||||||
|
|
||||||
|
return img, run_in_hierarchy(widget, cr, width, height)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a cairo surface with this widget content.
|
||||||
|
-- This is dynamic, so the SVG will be updated along with the widget content.
|
||||||
|
-- because of this, the painting may happen hover multiple event loop cycles.
|
||||||
|
-- @tparam widget widget A widget
|
||||||
|
-- @tparam number width The surface width
|
||||||
|
-- @tparam number height The surface height
|
||||||
|
-- @param[opt=cairo.Format.ARGB32] format The surface format
|
||||||
|
-- @return The cairo surface
|
||||||
|
-- @return The hierarchy
|
||||||
|
function surface.widget_to_surface(widget, width, height, format)
|
||||||
|
local img = cairo.ImageSurface(format or cairo.Format.ARGB32, width, height)
|
||||||
|
local cr = cairo.Context(img)
|
||||||
|
|
||||||
|
return img, run_in_hierarchy(widget, cr, width, height)
|
||||||
|
end
|
||||||
|
|
||||||
return setmetatable(surface, surface.mt)
|
return setmetatable(surface, surface.mt)
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
-- A container capable of changing the background color, foreground color
|
||||||
|
-- widget shape.
|
||||||
-- @author Uli Schlachter
|
-- @author Uli Schlachter
|
||||||
-- @copyright 2010 Uli Schlachter
|
-- @copyright 2010 Uli Schlachter
|
||||||
-- @release @AWESOME_VERSION@
|
-- @release @AWESOME_VERSION@
|
||||||
|
@ -17,7 +19,7 @@ local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility
|
||||||
|
|
||||||
local background = { mt = {} }
|
local background = { mt = {} }
|
||||||
|
|
||||||
--- Draw this widget
|
-- Draw this widget
|
||||||
function background:draw(context, cr, width, height)
|
function background:draw(context, cr, width, height)
|
||||||
if not self.widget or not self.widget.visible then
|
if not self.widget or not self.widget.visible then
|
||||||
return
|
return
|
||||||
|
@ -67,7 +69,7 @@ function background:after_draw_children(_, cr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Prepare drawing the children of this widget
|
-- Prepare drawing the children of this widget
|
||||||
function background:before_draw_children(_, cr)
|
function background:before_draw_children(_, cr)
|
||||||
if self.foreground then
|
if self.foreground then
|
||||||
cr:set_source(self.foreground)
|
cr:set_source(self.foreground)
|
||||||
|
@ -80,14 +82,14 @@ function background:before_draw_children(_, cr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Layout this widget
|
-- Layout this widget
|
||||||
function background:layout(_, width, height)
|
function background:layout(_, width, height)
|
||||||
if self.widget then
|
if self.widget then
|
||||||
return { base.place_widget_at(self.widget, 0, 0, width, height) }
|
return { base.place_widget_at(self.widget, 0, 0, width, height) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit this widget into the given area
|
-- Fit this widget into the given area
|
||||||
function background:fit(context, width, height)
|
function background:fit(context, width, height)
|
||||||
if not self.widget then
|
if not self.widget then
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
@ -97,6 +99,8 @@ function background:fit(context, width, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the widget that is drawn on top of the background
|
--- Set the widget that is drawn on top of the background
|
||||||
|
-- @tparam widget widget The widget to be disaplayed inside of the background
|
||||||
|
-- area
|
||||||
function background:set_widget(widget)
|
function background:set_widget(widget)
|
||||||
if widget then
|
if widget then
|
||||||
base.check_widget(widget)
|
base.check_widget(widget)
|
||||||
|
@ -105,20 +109,22 @@ function background:set_widget(widget)
|
||||||
self:emit_signal("widget::layout_changed")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the number of children element
|
-- Get children element
|
||||||
-- @treturn table The children
|
-- @treturn table The children
|
||||||
function background:get_children()
|
function background:get_children()
|
||||||
return {self.widget}
|
return {self.widget}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Replace the layout children
|
-- Replace the layout children
|
||||||
-- This layout only accept one children, all others will be ignored
|
-- This layout only accept one children, all others will be ignored
|
||||||
-- @tparam table children A table composed of valid widgets
|
-- @tparam table children A table composed of valid widgets
|
||||||
function background:set_children(children)
|
function background:set_children(children)
|
||||||
self:set_widget(children[1])
|
self:set_widget(children[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the background to use
|
--- Set the background to use.
|
||||||
|
--@DOC_wibox_widget_background_bg_EXAMPLE@
|
||||||
|
-- @param bg A color string, pattern or gradient (see `gears.color`)
|
||||||
function background:set_bg(bg)
|
function background:set_bg(bg)
|
||||||
if bg then
|
if bg then
|
||||||
self.background = color(bg)
|
self.background = color(bg)
|
||||||
|
@ -128,7 +134,9 @@ function background:set_bg(bg)
|
||||||
self:emit_signal("widget::redraw_needed")
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the foreground to use
|
--- Set the foreground to use.
|
||||||
|
--@DOC_wibox_widget_background_fg_EXAMPLE@
|
||||||
|
-- @param fg A color string, pattern or gradient (see `gears.color`)
|
||||||
function background:set_fg(fg)
|
function background:set_fg(fg)
|
||||||
if fg then
|
if fg then
|
||||||
self.foreground = color(fg)
|
self.foreground = color(fg)
|
||||||
|
@ -138,23 +146,29 @@ function background:set_fg(fg)
|
||||||
self:emit_signal("widget::redraw_needed")
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the background shape
|
--- Set the background shape.
|
||||||
-- @param shape A function taking a context, width and height as arguments
|
--
|
||||||
-- Any other arguments will be passed to the shape function
|
-- Any other arguments will be passed to the shape function
|
||||||
|
--@DOC_wibox_widget_background_shape_EXAMPLE@
|
||||||
|
-- @param shape A function taking a context, width and height as arguments
|
||||||
function background:set_shape(shape, ...)
|
function background:set_shape(shape, ...)
|
||||||
self._shape = shape
|
self._shape = shape
|
||||||
self._shape_args = {...}
|
self._shape_args = {...}
|
||||||
self:emit_signal("widget::redraw_needed")
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- When a `shape` is set, also draw a border
|
--- When a `shape` is set, also draw a border.
|
||||||
|
--
|
||||||
|
-- See `wibox.widget.background.set_shape` for an usage example.
|
||||||
-- @tparam number width The border width
|
-- @tparam number width The border width
|
||||||
function background:set_shape_border_width(width)
|
function background:set_shape_border_width(width)
|
||||||
self._shape_border_width = width
|
self._shape_border_width = width
|
||||||
self:emit_signal("widget::redraw_needed")
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- When a `shape` is set, also draw a border
|
--- When a `shape` is set, also draw a border.
|
||||||
|
--
|
||||||
|
-- See `wibox.widget.background.set_shape` for an usage example.
|
||||||
-- @param[opt=self.foreground] fg The border color, pattern or gradient
|
-- @param[opt=self.foreground] fg The border color, pattern or gradient
|
||||||
function background:set_shape_border_color(fg)
|
function background:set_shape_border_color(fg)
|
||||||
self._shape_border_color = fg
|
self._shape_border_color = fg
|
||||||
|
@ -162,6 +176,7 @@ function background:set_shape_border_color(fg)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- When a `shape` is set, make sure nothing is drawn outside of it.
|
--- When a `shape` is set, make sure nothing is drawn outside of it.
|
||||||
|
--@DOC_wibox_widget_background_clip_EXAMPLE@
|
||||||
-- @tparam boolean value If the shape clip is enable
|
-- @tparam boolean value If the shape clip is enable
|
||||||
function background:set_shape_clip(value)
|
function background:set_shape_clip(value)
|
||||||
self._shape_clip = value
|
self._shape_clip = value
|
||||||
|
|
|
@ -182,6 +182,7 @@ function clear_caches(widget)
|
||||||
clear_caches(w)
|
clear_caches(w)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
--- Figure out the geometry in device coordinate space. This gives only tight
|
--- Figure out the geometry in device coordinate space. This gives only tight
|
||||||
|
|
|
@ -0,0 +1,251 @@
|
||||||
|
# This module is designed to allow the Awesome documentation examples to be
|
||||||
|
# tested.
|
||||||
|
#
|
||||||
|
# It shims enough of the Awesome C API to allow code to be executed without an
|
||||||
|
# actual X server or running Awesome process. These tests are not genuine
|
||||||
|
# integration tests, but they are the next best thing.
|
||||||
|
#
|
||||||
|
# # As secondary goals, this module also generates images of the test result where
|
||||||
|
# relevant. Those images are used by the documentation and help the developers
|
||||||
|
# track user interface regressions and glitches. Finally, it also helps to find
|
||||||
|
# broken code.
|
||||||
|
cmake_minimum_required(VERSION 3.0.0)
|
||||||
|
|
||||||
|
# Get and update the LUA_PATH so the scripts can be executed without Awesome.
|
||||||
|
execute_process(COMMAND lua -e print\(package.path\) OUTPUT_VARIABLE "LUA_PATH_")
|
||||||
|
|
||||||
|
# Add the main awesome lua libraries.
|
||||||
|
set(LUA_PATH2_ "\
|
||||||
|
${CMAKE_SOURCE_DIR}/lib/?.lua;\
|
||||||
|
${CMAKE_SOURCE_DIR}/lib/?/init.lua;\
|
||||||
|
${CMAKE_SOURCE_DIR}/lib/?;"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the C API shims.
|
||||||
|
set(LUA_PATH3_ "\
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/examples/shims/?.lua;\
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/examples/shims/?/init.lua;\
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/examples/shims/?;"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Done in 3 variables to avoid CMake from implicitly converting into a list.
|
||||||
|
set(ENV{LUA_PATH} "${LUA_PATH3_}${LUA_PATH2_}${LUA_PATH_}")
|
||||||
|
|
||||||
|
# The documentation images directory
|
||||||
|
set(IMAGE_DIR "${CMAKE_BINARY_DIR}/doc/images")
|
||||||
|
file(MAKE_DIRECTORY "${IMAGE_DIR}")
|
||||||
|
|
||||||
|
# Escape potentially multiline strings to be part of the API doc.
|
||||||
|
# * add "--" in front of each lines
|
||||||
|
# * add a custom prefix in front of each lines
|
||||||
|
# * drop empty lines
|
||||||
|
# * convert " " lines into empty lines
|
||||||
|
# * drop lines ending with "--DOC_SOMETHING", they are handled elsewhere
|
||||||
|
function(escape_string variable content escaped_content line_prefix)
|
||||||
|
# If DOC_HIDE_ALL is present, do nothing
|
||||||
|
if(variable MATCHES "--DOC_HIDE_ALL")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REGEX REPLACE "\n" ";" var_lines "${variable}")
|
||||||
|
|
||||||
|
set(tmp_output ${content})
|
||||||
|
foreach (LINE ${var_lines})
|
||||||
|
if(NOT LINE MATCHES "^.+--DOC_[A-Z]+$")
|
||||||
|
set(tmp_output ${tmp_output}\n--${line_prefix}${LINE})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(${escaped_content} ${tmp_output} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Extract lines with the --DOC_HEADER marker
|
||||||
|
function(extract_header variable pre_output post_output)
|
||||||
|
string(REGEX REPLACE "\n" ";" var_lines "${variable}")
|
||||||
|
|
||||||
|
set(IS_POST 0)
|
||||||
|
|
||||||
|
foreach (LINE ${var_lines})
|
||||||
|
# This function doesn't escape the lines, so make sure they are
|
||||||
|
# already comments.
|
||||||
|
if(LINE MATCHES "^--.*--DOC_HEADER")
|
||||||
|
# Remove the header tag
|
||||||
|
string(REGEX REPLACE "[ ]*--DOC_HEADER" "" LINE "${LINE}")
|
||||||
|
|
||||||
|
# ldoc is picky about what happen after the first --@, so split
|
||||||
|
# the output between all that come before and all that come after.
|
||||||
|
if (NOT IS_POST AND LINE MATCHES "^--[ ]*@")
|
||||||
|
set(IS_POST 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (IS_POST)
|
||||||
|
set(tmp_post_output ${tmp_post_output}\n${line_prefix}${LINE})
|
||||||
|
else()
|
||||||
|
set(tmp_pre_output ${tmp_pre_output}\n${line_prefix}${LINE})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(${post_output} "${tmp_post_output}\n--" PARENT_SCOPE)
|
||||||
|
set(${pre_output} "${tmp_pre_output}\n--" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Read a code file and convert it to ldoc usage example.
|
||||||
|
# * add "--" in front of each lines
|
||||||
|
# * drop empty lines
|
||||||
|
# * convert " " lines into empty lines
|
||||||
|
# * drop lines ending with "--DOC_HIDE"
|
||||||
|
function(escape_code path escaped_content pre_header post_header)
|
||||||
|
file(READ ${path} path)
|
||||||
|
|
||||||
|
escape_string("${path}\n" "" escaped_code "")
|
||||||
|
|
||||||
|
extract_header("${path}" example_pre_header example_post_header)
|
||||||
|
|
||||||
|
set(${escaped_content} ${escaped_code} PARENT_SCOPE)
|
||||||
|
set(${pre_header} ${example_pre_header} PARENT_SCOPE)
|
||||||
|
set(${post_header} ${example_post_header} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Execute a lua file.
|
||||||
|
function(run_test test_path namespace template escaped_content)
|
||||||
|
|
||||||
|
# A template is required to know how to handle the output.
|
||||||
|
if (template STREQUAL " ")
|
||||||
|
message(FATAL_ERROR "No template found for " ${test_path} ", bye")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get the file name without the extension
|
||||||
|
get_filename_component(${test_path} TEST_FILE_NAME NAME)
|
||||||
|
set(IMAGE_PATH "${IMAGE_DIR}/${namespace}_${TEST_FILE_NAME}")
|
||||||
|
|
||||||
|
# Execute the script, leave the image extension decision to the test
|
||||||
|
# SVG is preferred, but PNG is better suited for some tests, like bitmap
|
||||||
|
# patterns.
|
||||||
|
execute_process(
|
||||||
|
COMMAND lua ${template} ${test_path} ${IMAGE_PATH} ${SOURCE_DIR}/.luacov
|
||||||
|
OUTPUT_VARIABLE TEST_OUTPUT
|
||||||
|
ERROR_VARIABLE TEST_ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
# If there is something on stderr, exit
|
||||||
|
if (NOT TEST_ERROR STREQUAL "")
|
||||||
|
message("${TEST_OUTPUT}")
|
||||||
|
message("${TEST_ERROR}")
|
||||||
|
message(FATAL_ERROR ${test_path} " A test failed, bye")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Read the code and turn it into an usage example.
|
||||||
|
escape_code(${test_path} TEST_CODE TEST_PRE_HEADER TEST_POST_HEADER)
|
||||||
|
|
||||||
|
# Build the documentation.
|
||||||
|
set(TEST_DOC_CONTENT "${TEST_PRE_HEADER}")
|
||||||
|
|
||||||
|
# If the image has been created, then add it.
|
||||||
|
if(EXISTS "${IMAGE_PATH}.svg")
|
||||||
|
escape_string(
|
||||||
|
"![Usage example](../images/${namespace}_${TEST_FILE_NAME}.svg)\n"
|
||||||
|
"${TEST_DOC_CONTENT}" TEST_DOC_CONTENT ""
|
||||||
|
)
|
||||||
|
elseif(EXISTS "${IMAGE_PATH}.png")
|
||||||
|
escape_string(
|
||||||
|
"![Usage example](../images/${namespace}_${TEST_FILE_NAME}.png)\n"
|
||||||
|
"${TEST_DOC_CONTENT}" TEST_DOC_CONTENT ""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# If there is an output, assume it is relevant and add it to the
|
||||||
|
# documentation under the image.
|
||||||
|
if(NOT ${TEST_OUTPUT} STREQUAL "")
|
||||||
|
set(TEST_DOC_CONTENT
|
||||||
|
"${TEST_DOC_CONTENT}\n--\n--**Usage example output**:\n--"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Markdown require an empty line before and after + 4 spaces.
|
||||||
|
escape_string(
|
||||||
|
"\n${TEST_OUTPUT}"
|
||||||
|
"${TEST_DOC_CONTENT}" TEST_DOC_CONTENT " "
|
||||||
|
)
|
||||||
|
set(TEST_DOC_CONTENT "${TEST_DOC_CONTENT}\n--")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# If there is some @* content, append it.
|
||||||
|
set(TEST_DOC_CONTENT "${TEST_DOC_CONTENT}${TEST_POST_HEADER}")
|
||||||
|
|
||||||
|
# Only add it if there is something to display.
|
||||||
|
if(NOT ${TEST_CODE} STREQUAL "\n--")
|
||||||
|
escape_string(
|
||||||
|
" @usage"
|
||||||
|
"${TEST_DOC_CONTENT}" TEST_DOC_CONTENT ""
|
||||||
|
)
|
||||||
|
set(TEST_DOC_CONTENT "${TEST_DOC_CONTENT}${TEST_CODE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Export the outout to the parent scope
|
||||||
|
set(${escaped_content} "${TEST_DOC_CONTENT}" PARENT_SCOPE)
|
||||||
|
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Recursive helper function to avoid adding CMakeLists.txt and add_subdirectory
|
||||||
|
# in every sub-directories.
|
||||||
|
function(digg path namespace template)
|
||||||
|
|
||||||
|
# Check if there is a template for this directory, else use the
|
||||||
|
# last known one.
|
||||||
|
if(EXISTS ${path}/template.lua)
|
||||||
|
message(STATUS "Testing code based on ${namespace}")
|
||||||
|
set(template ${path}/template.lua)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get the directory content
|
||||||
|
file(GLOB ex_files RELATIVE "${path}"
|
||||||
|
"${path}/*")
|
||||||
|
|
||||||
|
foreach(ex_file_name ${ex_files})
|
||||||
|
if(IS_DIRECTORY ${path}/${ex_file_name}
|
||||||
|
AND (NOT ${ex_file_name} STREQUAL "shims"))
|
||||||
|
|
||||||
|
digg("${path}/${ex_file_name}" "${namespace}_${ex_file_name}" ${template})
|
||||||
|
|
||||||
|
elseif(${ex_file_name} MATCHES ".lua"
|
||||||
|
AND NOT ${ex_file_name} MATCHES "template.lua")
|
||||||
|
|
||||||
|
# Get the file name without the extension
|
||||||
|
string(REGEX REPLACE "\\.lua" "" TEST_FILE_NAME ${ex_file_name})
|
||||||
|
|
||||||
|
run_test("${path}/${ex_file_name}" "${namespace}" ${template} ESCAPED_CODE_EXAMPLE)
|
||||||
|
|
||||||
|
# Set the test name
|
||||||
|
set(TEST_NAME DOC${namespace}_${TEST_FILE_NAME}_EXAMPLE)
|
||||||
|
|
||||||
|
# Anything called @DOC_`namespace`_EXAMPLE@
|
||||||
|
# in the Lua or C sources will be replaced by the content if that
|
||||||
|
# variable during the pre-processing
|
||||||
|
set(ENV{${TEST_NAME}} "${ESCAPED_CODE_EXAMPLE}" CACHE INTERNAL FORCE)
|
||||||
|
|
||||||
|
# Update the test list
|
||||||
|
set(ENV{EXAMPLE_LIST} "$ENV{EXAMPLE_LIST};${TEST_NAME}")
|
||||||
|
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Start at the top level then recursively explore the sub-directories to locate
|
||||||
|
# the test. In parallel, build a namespace for the global variables. Those
|
||||||
|
# variables will be inserted into the lua source code itself once the examples
|
||||||
|
# are validated.
|
||||||
|
digg("${SOURCE_DIR}/tests/examples" "" " ")
|
||||||
|
|
||||||
|
# This is ugly, but CMake variable scope system totally ignore 50 years of
|
||||||
|
# computer science evolution and only support function local variables.
|
||||||
|
# PARENT_SCOPE is useless in recursive methods and the CMake pre-processor
|
||||||
|
# can't access ENV variables. So the only (insane) way is to set tons of ENV
|
||||||
|
# variables, keep track of them in yet another one and set them in the global
|
||||||
|
# scope once in the "top level" CMakeLists section (it cannot be done from
|
||||||
|
# functions).
|
||||||
|
foreach(vari $ENV{EXAMPLE_LIST})
|
||||||
|
# While at it, replace \" created by CMake by ', " wont work in <code>
|
||||||
|
string(REGEX REPLACE "\\\"" "'" ${vari} $ENV{${vari}})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
message(STATUS "All test passed!")
|
|
@ -0,0 +1,154 @@
|
||||||
|
local file_path, image_path, luacovpath = ...
|
||||||
|
|
||||||
|
local cairo = require("lgi").cairo
|
||||||
|
local pango = require("lgi").Pango
|
||||||
|
local pangocairo = require("lgi").PangoCairo
|
||||||
|
|
||||||
|
-- Set the global shims
|
||||||
|
-- luacheck: globals awesome root tag screen client mouse
|
||||||
|
awesome = require( "awesome" )
|
||||||
|
root = require( "root" )
|
||||||
|
tag = require( "tag" )
|
||||||
|
screen = require( "screen" )
|
||||||
|
client = require( "client" )
|
||||||
|
mouse = require( "mouse" )
|
||||||
|
|
||||||
|
-- Force luacheck to be silent about setting those as unused globals
|
||||||
|
assert(awesome and root and tag and screen and client and mouse)
|
||||||
|
|
||||||
|
-- If luacov is available, use it. Else, do nothing.
|
||||||
|
pcall(function()
|
||||||
|
require("luacov.runner")(luacovpath)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local color = require( "gears.color" )
|
||||||
|
local shape = require( "gears.shape" )
|
||||||
|
local beautiful = require( "beautiful" )
|
||||||
|
|
||||||
|
-- Run the test
|
||||||
|
local args = loadfile(file_path)() or {}
|
||||||
|
|
||||||
|
-- Draw the result
|
||||||
|
local img = cairo.SvgSurface.create(image_path..".svg", screen._get_extents() )
|
||||||
|
|
||||||
|
local cr = cairo.Context(img)
|
||||||
|
|
||||||
|
local pango_crx = pangocairo.font_map_get_default():create_context()
|
||||||
|
local pl = pango.Layout.new(pango_crx)
|
||||||
|
|
||||||
|
-- Draw some text inside of the geometry
|
||||||
|
local function draw_label(geo, text)
|
||||||
|
cr:save()
|
||||||
|
cr:set_source(color(beautiful.fg_normal))
|
||||||
|
cr:translate(geo.x, geo.y)
|
||||||
|
pl.text = text
|
||||||
|
cr:show_layout(pl)
|
||||||
|
cr:restore()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Draw a mouse cursor at [x,y]
|
||||||
|
local function draw_mouse(x, y)
|
||||||
|
cr:move_to(x, y)
|
||||||
|
cr:rel_line_to( 0, 10)
|
||||||
|
cr:rel_line_to( 3, -2)
|
||||||
|
cr:rel_line_to( 3, 4)
|
||||||
|
cr:rel_line_to( 2, 0)
|
||||||
|
cr:rel_line_to(-3, -4)
|
||||||
|
cr:rel_line_to( 4, 0)
|
||||||
|
cr:close_path()
|
||||||
|
cr:fill()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Print an outline for the screens
|
||||||
|
for _, s in ipairs(screen) do
|
||||||
|
cr:save()
|
||||||
|
-- Draw the screen outline
|
||||||
|
cr:set_source(color("#00000044"))
|
||||||
|
cr:set_line_width(1.5)
|
||||||
|
cr:set_dash({10,4},1)
|
||||||
|
cr:rectangle(s.geometry.x+0.75,s.geometry.y+0.75,s.geometry.width-1.5,s.geometry.height-1.5)
|
||||||
|
cr:stroke()
|
||||||
|
|
||||||
|
-- Draw the workarea outline
|
||||||
|
cr:set_source(color("#00000033"))
|
||||||
|
cr:rectangle(s.workarea.x,s.workarea.y,s.workarea.width,s.workarea.height)
|
||||||
|
cr:stroke()
|
||||||
|
|
||||||
|
-- Draw the padding outline
|
||||||
|
--TODO
|
||||||
|
cr:restore()
|
||||||
|
end
|
||||||
|
|
||||||
|
cr:set_line_width(beautiful.border_width)
|
||||||
|
cr:set_source(color(beautiful.border_color))
|
||||||
|
|
||||||
|
-- Loop each clients geometry history and paint it
|
||||||
|
for _, c in ipairs(client.get()) do
|
||||||
|
local pgeo = nil
|
||||||
|
for _, geo in ipairs(c._old_geo) do
|
||||||
|
if not geo._hide then
|
||||||
|
cr:save()
|
||||||
|
cr:translate(geo.x, geo.y)
|
||||||
|
shape.rounded_rect(cr, geo.width, geo.height, args.radius or 5)
|
||||||
|
cr:stroke_preserve()
|
||||||
|
cr:set_source(color(c.color or geo._color or beautiful.bg_normal))
|
||||||
|
cr:fill()
|
||||||
|
cr:restore()
|
||||||
|
|
||||||
|
if geo._label then
|
||||||
|
draw_label(geo, geo._label)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Draw lines between the old and new corners
|
||||||
|
if pgeo and not args.hide_lines then
|
||||||
|
cr:save()
|
||||||
|
cr:set_source_rgba(0,0,0,.1)
|
||||||
|
|
||||||
|
-- Top left
|
||||||
|
cr:move_to(pgeo.x, pgeo.y)
|
||||||
|
cr:line_to(geo.x, geo.y)
|
||||||
|
cr:stroke()
|
||||||
|
|
||||||
|
-- Top right
|
||||||
|
cr:move_to(pgeo.x+pgeo.width, pgeo.y)
|
||||||
|
cr:line_to(geo.x+pgeo.width, geo.y)
|
||||||
|
|
||||||
|
-- Bottom left
|
||||||
|
cr:move_to(pgeo.x, pgeo.y+pgeo.height)
|
||||||
|
cr:line_to(geo.x, geo.y+geo.height)
|
||||||
|
cr:stroke()
|
||||||
|
|
||||||
|
-- Bottom right
|
||||||
|
cr:move_to(pgeo.x+pgeo.width, pgeo.y+pgeo.height)
|
||||||
|
cr:line_to(geo.x+pgeo.width, geo.y+geo.height)
|
||||||
|
cr:stroke()
|
||||||
|
|
||||||
|
cr:restore()
|
||||||
|
end
|
||||||
|
|
||||||
|
pgeo = geo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cr:set_source_rgba(1,0,0,1)
|
||||||
|
cr:set_dash({1,1},1)
|
||||||
|
|
||||||
|
-- Paint the mouse cursor position history
|
||||||
|
for _, h in ipairs(mouse.old_histories) do
|
||||||
|
local pos = nil
|
||||||
|
for _, coords in ipairs(h) do
|
||||||
|
draw_mouse(coords.x, coords.y)
|
||||||
|
cr:fill()
|
||||||
|
|
||||||
|
if pos then
|
||||||
|
cr:move_to(pos.x, pos.y)
|
||||||
|
cr:line_to(coords.x, coords.y)
|
||||||
|
cr:stroke()
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = coords
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
img:finish()
|
|
@ -0,0 +1,60 @@
|
||||||
|
local gears_obj = require("gears.object")
|
||||||
|
|
||||||
|
-- Emulate the C API classes. They differ from C API objects as connect_signal
|
||||||
|
-- doesn't take an object as first argument and they support fallback properties
|
||||||
|
-- handlers.
|
||||||
|
local function _shim_fake_class()
|
||||||
|
local obj = gears_obj()
|
||||||
|
|
||||||
|
local meta = {
|
||||||
|
__index = function()end,
|
||||||
|
__new_index = function()end,
|
||||||
|
}
|
||||||
|
|
||||||
|
obj._connect_signal = obj.connect_signal
|
||||||
|
|
||||||
|
function obj.connect_signal(name, func)
|
||||||
|
return obj._connect_signal(obj, name, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
obj._add_signal = obj.add_signal
|
||||||
|
|
||||||
|
function obj.add_signal(name)
|
||||||
|
return obj._add_signal(obj, name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj.set_index_miss_handler(handler)
|
||||||
|
meta.__index = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj.set_newindex_miss_handler(handler)
|
||||||
|
meta.__new_index = handler
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj.emit_signal(name, c, ...)
|
||||||
|
local conns = obj._signals[name] or {strong={}}
|
||||||
|
for func in pairs(conns.strong) do
|
||||||
|
func(c, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return obj, meta
|
||||||
|
end
|
||||||
|
|
||||||
|
local awesome = _shim_fake_class()
|
||||||
|
awesome._shim_fake_class = _shim_fake_class
|
||||||
|
|
||||||
|
-- Avoid c.screen = acreen.focused() to be called, all tests will fail
|
||||||
|
awesome.startup = true
|
||||||
|
|
||||||
|
function awesome.register_xproperty()
|
||||||
|
end
|
||||||
|
|
||||||
|
awesome.add_signal("refresh")
|
||||||
|
awesome.add_signal("wallpaper_changed")
|
||||||
|
awesome.add_signal("spawn::canceled")
|
||||||
|
awesome.add_signal("spawn::timeout")
|
||||||
|
|
||||||
|
return awesome
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,24 @@
|
||||||
|
local lgi = require("lgi")
|
||||||
|
local Pango = lgi.Pango
|
||||||
|
|
||||||
|
-- Default theme for the documentation examples
|
||||||
|
local module = {
|
||||||
|
fg_normal = "#000000" ,
|
||||||
|
bg_normal = "#6181FF7D",
|
||||||
|
bg_highlight = "#AA00FF7D",
|
||||||
|
border_color = "#6181FF" ,
|
||||||
|
border_width = 1.5 ,
|
||||||
|
|
||||||
|
-- Fake resources handling
|
||||||
|
xresources = require("beautiful.xresources")
|
||||||
|
}
|
||||||
|
|
||||||
|
local f = Pango.FontDescription.from_string("sans 8")
|
||||||
|
|
||||||
|
function module.get_font()
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
|
return module
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,8 @@
|
||||||
|
return {
|
||||||
|
apply_dpi = function(size, _)
|
||||||
|
return size
|
||||||
|
end,
|
||||||
|
get_dpi = function() return 96 end,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,171 @@
|
||||||
|
local gears_obj = require("gears.object")
|
||||||
|
|
||||||
|
local clients = {}
|
||||||
|
|
||||||
|
local client = awesome._shim_fake_class()
|
||||||
|
|
||||||
|
local function add_signals(c)
|
||||||
|
c:add_signal("property::width")
|
||||||
|
c:add_signal("property::height")
|
||||||
|
c:add_signal("property::x")
|
||||||
|
c:add_signal("property::y")
|
||||||
|
c:add_signal("property::screen")
|
||||||
|
c:add_signal("property::geometry")
|
||||||
|
c:add_signal("request::geometry")
|
||||||
|
c:add_signal("swapped")
|
||||||
|
c:add_signal("raised")
|
||||||
|
c:add_signal("property::_label") --Used internally
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Keep an history of the geometry for validation and images
|
||||||
|
local function push_geometry(c)
|
||||||
|
table.insert(c._old_geo, c:geometry())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Undo the last move, but keep it in history
|
||||||
|
-- local function pop_geometry(c)
|
||||||
|
-- CURRENTLY UNUSED
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- Create fake clients to move around
|
||||||
|
function client.gen_fake(args)
|
||||||
|
local ret = gears_obj()
|
||||||
|
ret.type = "normal"
|
||||||
|
ret.valid = true
|
||||||
|
ret.size_hints = {}
|
||||||
|
ret.border_width = 1
|
||||||
|
|
||||||
|
-- Apply all properties
|
||||||
|
for k,v in pairs(args or {}) do
|
||||||
|
ret[k] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tests should always set a geometry, but just in case
|
||||||
|
for _, v in ipairs{"x","y","width","height"} do
|
||||||
|
ret[v] = ret[v] or 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
add_signals(ret)
|
||||||
|
|
||||||
|
-- Emulate capi.client.geometry
|
||||||
|
function ret:geometry(new)
|
||||||
|
if new then
|
||||||
|
for k,v in pairs(new) do
|
||||||
|
ret[k] = v
|
||||||
|
ret:emit_signal("property::"..k, v)
|
||||||
|
end
|
||||||
|
ret:emit_signal("property::geometry", ret:geometry())
|
||||||
|
push_geometry(ret)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
x = ret.x,
|
||||||
|
y = ret.y,
|
||||||
|
width = ret.width,
|
||||||
|
height = ret.height,
|
||||||
|
label = ret._label,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function ret:isvisible()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Used for screenshots
|
||||||
|
function ret:set_label(text)
|
||||||
|
ret._old_geo[#ret._old_geo]._label = text
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Used for screenshots, hide the current client position
|
||||||
|
function ret:_hide()
|
||||||
|
ret._old_geo[#ret._old_geo]._hide = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function ret:get_xproperty()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function ret:tags(new) --FIXME
|
||||||
|
if new then
|
||||||
|
ret._tags = new
|
||||||
|
end
|
||||||
|
|
||||||
|
if ret._tags then
|
||||||
|
return ret._tags
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, t in ipairs(root._tags) do
|
||||||
|
if t.screen == ret.screen then
|
||||||
|
return {t}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Record the geometry
|
||||||
|
ret._old_geo = {}
|
||||||
|
push_geometry(ret)
|
||||||
|
|
||||||
|
-- Set the attributes
|
||||||
|
ret.screen = args.screen or screen[1]
|
||||||
|
|
||||||
|
-- Add to the client list
|
||||||
|
table.insert(clients, ret)
|
||||||
|
|
||||||
|
client.focus = ret
|
||||||
|
|
||||||
|
client.emit_signal("manage", ret)
|
||||||
|
assert(not args.screen or (args.screen == ret.screen))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.get(s)
|
||||||
|
if not s then return clients end
|
||||||
|
|
||||||
|
local s2 = screen[s]
|
||||||
|
|
||||||
|
local ret = {}
|
||||||
|
|
||||||
|
for _,c in ipairs(clients) do
|
||||||
|
if c.screen == s2 then
|
||||||
|
table.insert(ret, c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
client:_add_signal("manage")
|
||||||
|
client:_add_signal("unmanage")
|
||||||
|
client:_add_signal("property::urgent")
|
||||||
|
client:_add_signal("untagged")
|
||||||
|
client:_add_signal("tagged")
|
||||||
|
client:_add_signal("property::shape_client_bounding")
|
||||||
|
client:_add_signal("property::shape_client_clip")
|
||||||
|
client:_add_signal("property::width")
|
||||||
|
client:_add_signal("property::height")
|
||||||
|
client:_add_signal("property::x")
|
||||||
|
client:_add_signal("property::y")
|
||||||
|
client:_add_signal("property::geometry")
|
||||||
|
client:_add_signal("focus")
|
||||||
|
client:_add_signal("new")
|
||||||
|
client:_add_signal("property::size_hints_honor")
|
||||||
|
client:_add_signal("property::struts")
|
||||||
|
client:_add_signal("property::minimized")
|
||||||
|
client:_add_signal("property::maximized_horizontal")
|
||||||
|
client:_add_signal("property::maximized_vertical")
|
||||||
|
client:_add_signal("property::sticky")
|
||||||
|
client:_add_signal("property::fullscreen")
|
||||||
|
client:_add_signal("property::border_width")
|
||||||
|
client:_add_signal("property::hidden")
|
||||||
|
client:_add_signal("property::screen")
|
||||||
|
client:_add_signal("raised")
|
||||||
|
client:_add_signal("lowered")
|
||||||
|
client:_add_signal("list")
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,27 @@
|
||||||
|
local screen = require("screen")
|
||||||
|
|
||||||
|
local coords = {x=100,y=100}
|
||||||
|
|
||||||
|
local mouse = {
|
||||||
|
screen = screen[1],
|
||||||
|
old_histories = {},
|
||||||
|
history = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouse.coords(args)
|
||||||
|
if args then
|
||||||
|
coords.x, coords.y = args.x, args.y
|
||||||
|
table.insert(mouse.history, {x=coords.x, y=coords.y})
|
||||||
|
end
|
||||||
|
|
||||||
|
return coords
|
||||||
|
end
|
||||||
|
|
||||||
|
function mouse.push_history()
|
||||||
|
table.insert(mouse.old_histories, mouse.history)
|
||||||
|
mouse.history = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
return mouse
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,9 @@
|
||||||
|
local root = {_tags={}}
|
||||||
|
|
||||||
|
function root:tags()
|
||||||
|
return root._tags
|
||||||
|
end
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,101 @@
|
||||||
|
local gears_obj = require("gears.object")
|
||||||
|
|
||||||
|
local screen = awesome._shim_fake_class()
|
||||||
|
|
||||||
|
screen.count = 1
|
||||||
|
|
||||||
|
local function create_screen(args)
|
||||||
|
local s = gears_obj()
|
||||||
|
|
||||||
|
s:add_signal("property::workarea")
|
||||||
|
s:add_signal("padding")
|
||||||
|
|
||||||
|
-- Copy the geo in case the args are mutated
|
||||||
|
local geo = {
|
||||||
|
x = args.x ,
|
||||||
|
y = args.y ,
|
||||||
|
width = args.width ,
|
||||||
|
height = args.height,
|
||||||
|
}
|
||||||
|
|
||||||
|
function s._resize(args2)
|
||||||
|
geo.x = args2.x or geo.x
|
||||||
|
geo.y = args2.y or geo.y
|
||||||
|
geo.width = args2.width or geo.width
|
||||||
|
geo.height = args2.height or geo.height
|
||||||
|
end
|
||||||
|
|
||||||
|
local wa = args.workarea_sides or 10
|
||||||
|
|
||||||
|
return setmetatable(s,{ __index = function(_, key)
|
||||||
|
if key == "geometry" then
|
||||||
|
return {
|
||||||
|
x = geo.x or 0,
|
||||||
|
y = geo.y or 0,
|
||||||
|
width = geo.width ,
|
||||||
|
height = geo.height,
|
||||||
|
}
|
||||||
|
elseif key == "workarea" then
|
||||||
|
return {
|
||||||
|
x = (geo.x or 0) + wa ,
|
||||||
|
y = (geo.y or 0) + wa ,
|
||||||
|
width = geo.width - 2*wa,
|
||||||
|
height = geo.height - 2*wa,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local screens = {}
|
||||||
|
|
||||||
|
function screen._add_screen(args)
|
||||||
|
local s = create_screen(args)
|
||||||
|
table.insert(screens, s)
|
||||||
|
s.index = #screens
|
||||||
|
screen[#screen+1] = s
|
||||||
|
screen[s] = s
|
||||||
|
end
|
||||||
|
|
||||||
|
function screen._get_extents()
|
||||||
|
local xmax, ymax
|
||||||
|
for _, v in ipairs(screen) do
|
||||||
|
if not xmax or v.geometry.x+v.geometry.width > xmax.geometry.x+xmax.geometry.width then
|
||||||
|
xmax = v
|
||||||
|
end
|
||||||
|
if not ymax or v.geometry.y+v.geometry.height > ymax.geometry.y+ymax.geometry.height then
|
||||||
|
ymax = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return xmax.geometry.x+xmax.geometry.width, ymax.geometry.y+ymax.geometry.height
|
||||||
|
end
|
||||||
|
|
||||||
|
function screen._clear()
|
||||||
|
for i=1, #screen do
|
||||||
|
screen[screen[i]] = nil
|
||||||
|
screen[i] = nil
|
||||||
|
end
|
||||||
|
screens = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function screen._setup_grid(w, h, rows, args)
|
||||||
|
args = args or {}
|
||||||
|
screen._clear()
|
||||||
|
for i, row in ipairs(rows) do
|
||||||
|
for j=1, row do
|
||||||
|
args.x = (j-1)*w + (j-1)*10
|
||||||
|
args.y = (i-1)*h + (i-1)*10
|
||||||
|
args.width = w
|
||||||
|
args.height = h
|
||||||
|
screen._add_screen(args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
screen._add_screen {width=320, height=240}
|
||||||
|
|
||||||
|
return screen
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
local gears_obj = require("gears.object")
|
||||||
|
|
||||||
|
local tag, meta = awesome._shim_fake_class()
|
||||||
|
|
||||||
|
local function new_tag(_, args)
|
||||||
|
local ret = gears_obj()
|
||||||
|
|
||||||
|
ret:add_signal("property::layout")
|
||||||
|
ret:add_signal("property::name")
|
||||||
|
ret:add_signal("property::geometry")
|
||||||
|
ret:add_signal("property::screen")
|
||||||
|
ret:add_signal("property::mwfact")
|
||||||
|
ret:add_signal("property::ncol")
|
||||||
|
ret:add_signal("property::nmaster")
|
||||||
|
ret:add_signal("property::index")
|
||||||
|
ret:add_signal("property::useless_gap")
|
||||||
|
ret:add_signal("property::_wa_tracker")
|
||||||
|
|
||||||
|
ret.name = args.name or "test"
|
||||||
|
ret.activated = true
|
||||||
|
ret.selected = true
|
||||||
|
|
||||||
|
function ret:clients(_) --TODO handle new
|
||||||
|
local list = {}
|
||||||
|
for _, c in ipairs(client.get()) do
|
||||||
|
if c.screen == (ret.screen or screen[1]) then
|
||||||
|
table.insert(list, c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(root._tags, ret)
|
||||||
|
|
||||||
|
return setmetatable(ret, {
|
||||||
|
__index = function(...) return meta.__index(...) end,
|
||||||
|
__new_index = function(...) return meta.__new_index(...) end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
tag:_add_signal("request::select")
|
||||||
|
tag:_add_signal("property::selected")
|
||||||
|
tag:_add_signal("property::activated")
|
||||||
|
tag:_add_signal("tagged")
|
||||||
|
tag:_add_signal("untagged")
|
||||||
|
|
||||||
|
return setmetatable(tag, {
|
||||||
|
__call = new_tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
local file_path, image_path, luacovpath = ...
|
||||||
|
|
||||||
|
-- Set the global shims
|
||||||
|
-- luacheck: globals awesome client tag
|
||||||
|
awesome = require( "awesome" )
|
||||||
|
client = require( "client" )
|
||||||
|
tag = require( "tag" )
|
||||||
|
|
||||||
|
-- Force luacheck to be silent about setting those as unused globals
|
||||||
|
assert(awesome and client and tag)
|
||||||
|
|
||||||
|
local wibox = require( "wibox" )
|
||||||
|
local surface = require( "gears.surface" )
|
||||||
|
|
||||||
|
-- If luacov is available, use it. Else, do nothing.
|
||||||
|
pcall(function()
|
||||||
|
require("luacov.runner")(luacovpath)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- This is the main widget the tests will use as top level
|
||||||
|
local container = wibox.layout.fixed.vertical()
|
||||||
|
|
||||||
|
-- Let the test request a size and file format
|
||||||
|
local w, h, image_type = loadfile(file_path)(container)
|
||||||
|
image_type = image_type or "svg"
|
||||||
|
|
||||||
|
-- Emulate the event loop for 10 iterations
|
||||||
|
for _ = 1, 10 do
|
||||||
|
awesome:emit_signal("refresh")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the example fallback size (the tests can return a size if the want)
|
||||||
|
local f_w, f_h = container:fit({dpi=96}, 9999, 9999)
|
||||||
|
|
||||||
|
-- There is an overhead that cause testbox "...", add 10 until someone
|
||||||
|
-- figures out the real equation
|
||||||
|
f_w, f_h = f_w+10, f_h+10
|
||||||
|
|
||||||
|
-- Save to the output file
|
||||||
|
local img = surface["widget_to_"..image_type](container, image_path.."."..image_type, w or f_w, h or f_h)
|
||||||
|
img:finish()
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
local parent = ... --DOC_HIDE
|
||||||
|
local wibox = require("wibox") --DOC_HIDE
|
||||||
|
|
||||||
|
local text_widget = {
|
||||||
|
text = "Hello world!",
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
}
|
||||||
|
|
||||||
|
parent : setup {
|
||||||
|
{
|
||||||
|
text_widget,
|
||||||
|
bg = '#ff0000',
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text_widget,
|
||||||
|
bg = '#00ff00',
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text_widget,
|
||||||
|
bg = '#0000ff',
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
spacing = 10,
|
||||||
|
layout = wibox.layout.fixed.vertical
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
local parent = ... --DOC_HIDE
|
||||||
|
local wibox = require("wibox") --DOC_HIDE
|
||||||
|
local gears = {shape = require("gears.shape")} --DOC_HIDE
|
||||||
|
local beautiful = require("beautiful") --DOC_HIDE
|
||||||
|
|
||||||
|
parent : setup {
|
||||||
|
{
|
||||||
|
-- Some content may be outside of the shape
|
||||||
|
{
|
||||||
|
text = "Hello\nworld!",
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
},
|
||||||
|
shape = gears.shape.circle,
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
shape_border_color = beautiful.border_color,
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-- To solve this, clip the content
|
||||||
|
{
|
||||||
|
text = "Hello\nworld!",
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
},
|
||||||
|
shape_clip = true,
|
||||||
|
shape = gears.shape.circle,
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
shape_border_color = beautiful.border_color,
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
spacing = 10,
|
||||||
|
layout = wibox.layout.fixed.vertical
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
local parent = ... --DOC_HIDE
|
||||||
|
local wibox = require("wibox") --DOC_HIDE
|
||||||
|
|
||||||
|
local text_widget = {
|
||||||
|
text = "Hello world!",
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
}
|
||||||
|
|
||||||
|
parent : setup {
|
||||||
|
{
|
||||||
|
text_widget,
|
||||||
|
fg = '#ff0000',
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text_widget,
|
||||||
|
fg = '#00ff00',
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text_widget,
|
||||||
|
fg = '#0000ff',
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
spacing = 10,
|
||||||
|
layout = wibox.layout.fixed.vertical
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
local parent = ... --DOC_HIDE
|
||||||
|
local wibox = require("wibox") --DOC_HIDE
|
||||||
|
local gears = {shape = require("gears.shape")} --DOC_HIDE
|
||||||
|
local beautiful = require("beautiful") --DOC_HIDE
|
||||||
|
|
||||||
|
parent : setup {
|
||||||
|
{
|
||||||
|
-- Adding a shape without margin may result in cropped output
|
||||||
|
{
|
||||||
|
text = "Hello world!",
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
},
|
||||||
|
shape = gears.shape.hexagon,
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
shape_border_color = beautiful.border_color,
|
||||||
|
shape_border_width = beautiful.border_width,
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-- To solve this, use a margin
|
||||||
|
{
|
||||||
|
{
|
||||||
|
text = "Hello world!",
|
||||||
|
widget = wibox.widget.textbox
|
||||||
|
},
|
||||||
|
left = 10,
|
||||||
|
right = 10,
|
||||||
|
top = 3,
|
||||||
|
bottom = 3,
|
||||||
|
widget = wibox.layout.margin
|
||||||
|
},
|
||||||
|
shape = gears.shape.hexagon,
|
||||||
|
bg = beautiful.bg_normal,
|
||||||
|
shape_border_color = beautiful.border_color,
|
||||||
|
shape_border_width = beautiful.border_width,
|
||||||
|
widget = wibox.widget.background
|
||||||
|
},
|
||||||
|
spacing = 10,
|
||||||
|
layout = wibox.layout.fixed.vertical
|
||||||
|
}
|
Loading…
Reference in New Issue