Merge branch 'surface-errors' of https://github.com/psychon/awesome
This commit is contained in:
commit
3793c339ce
15
draw.c
15
draw.c
|
@ -229,23 +229,18 @@ draw_dup_image_surface(cairo_surface_t *surface)
|
||||||
/** Load the specified path into a cairo surface
|
/** Load the specified path into a cairo surface
|
||||||
* \param L Lua state
|
* \param L Lua state
|
||||||
* \param path file to load
|
* \param path file to load
|
||||||
|
* \param error A place to store an error message, if needed
|
||||||
* \return A cairo image surface or NULL on error.
|
* \return A cairo image surface or NULL on error.
|
||||||
*/
|
*/
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
draw_load_image(lua_State *L, const char *path)
|
draw_load_image(lua_State *L, const char *path, GError **error)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
|
||||||
cairo_surface_t *ret;
|
cairo_surface_t *ret;
|
||||||
GdkPixbuf *buf = gdk_pixbuf_new_from_file(path, &error);
|
GdkPixbuf *buf = gdk_pixbuf_new_from_file(path, error);
|
||||||
|
|
||||||
if (!buf) {
|
if (!buf)
|
||||||
luaL_where(L, 1);
|
/* error was set above */
|
||||||
lua_pushstring(L, error->message);
|
|
||||||
lua_concat(L, 2);
|
|
||||||
g_error_free(error);
|
|
||||||
lua_error(L);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
ret = draw_surface_from_pixbuf(buf);
|
ret = draw_surface_from_pixbuf(buf);
|
||||||
g_object_unref(buf);
|
g_object_unref(buf);
|
||||||
|
|
3
draw.h
3
draw.h
|
@ -25,6 +25,7 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
|
#include <glib.h> /* for GError */
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ a_iso2utf8(const char *str, ssize_t len, char **dest, ssize_t *dlen)
|
||||||
|
|
||||||
cairo_surface_t *draw_surface_from_data(int width, int height, uint32_t *data);
|
cairo_surface_t *draw_surface_from_data(int width, int height, uint32_t *data);
|
||||||
cairo_surface_t *draw_dup_image_surface(cairo_surface_t *surface);
|
cairo_surface_t *draw_dup_image_surface(cairo_surface_t *surface);
|
||||||
cairo_surface_t *draw_load_image(lua_State *L, const char *path);
|
cairo_surface_t *draw_load_image(lua_State *L, const char *path, GError **error);
|
||||||
|
|
||||||
xcb_visualtype_t *draw_find_visual(const xcb_screen_t *s, xcb_visualid_t visual);
|
xcb_visualtype_t *draw_find_visual(const xcb_screen_t *s, xcb_visualid_t visual);
|
||||||
xcb_visualtype_t *draw_default_visual(const xcb_screen_t *s);
|
xcb_visualtype_t *draw_default_visual(const xcb_screen_t *s);
|
||||||
|
|
|
@ -558,7 +558,7 @@ function menu.entry(parent, args)
|
||||||
if type(args.cmd) == "table" then
|
if type(args.cmd) == "table" then
|
||||||
if args.theme.submenu_icon then
|
if args.theme.submenu_icon then
|
||||||
submenu = wibox.widget.imagebox()
|
submenu = wibox.widget.imagebox()
|
||||||
submenu:set_image(surface.load(args.theme.submenu_icon))
|
submenu:set_image(args.theme.submenu_icon)
|
||||||
else
|
else
|
||||||
submenu = wibox.widget.textbox()
|
submenu = wibox.widget.textbox()
|
||||||
submenu:set_font(args.theme.font)
|
submenu:set_font(args.theme.font)
|
||||||
|
|
|
@ -107,9 +107,7 @@ function taglist.taglist_label(t, args)
|
||||||
text = text .. "</span>"
|
text = text .. "</span>"
|
||||||
end
|
end
|
||||||
if not taglist_disable_icon then
|
if not taglist_disable_icon then
|
||||||
if tag.geticon(t) and type(tag.geticon(t)) == "image" then
|
if tag.geticon(t) then
|
||||||
icon = tag.geticon(t)
|
|
||||||
elseif tag.geticon(t) then
|
|
||||||
icon = surface.load(tag.geticon(t))
|
icon = surface.load(tag.geticon(t))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,7 @@ local setmetatable = setmetatable
|
||||||
local type = type
|
local type = type
|
||||||
local capi = { awesome = awesome }
|
local capi = { awesome = awesome }
|
||||||
local cairo = require("lgi").cairo
|
local cairo = require("lgi").cairo
|
||||||
|
local gdebug = require("gears.debug")
|
||||||
|
|
||||||
-- 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)')
|
||||||
|
@ -19,13 +20,22 @@ end
|
||||||
local surface = { mt = {} }
|
local surface = { mt = {} }
|
||||||
local surface_cache = setmetatable({}, { __mode = 'v' })
|
local surface_cache = setmetatable({}, { __mode = 'v' })
|
||||||
|
|
||||||
|
local function get_empty_surface()
|
||||||
|
return cairo.ImageSurface(cairo.Format.ARGB32, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
--- Try to convert the argument into an lgi cairo surface.
|
--- Try to convert the argument into an lgi cairo surface.
|
||||||
-- This is usually needed for loading images by file name.
|
-- This is usually needed for loading images by file name.
|
||||||
function surface.load_uncached(_surface)
|
-- @param _surface The surface to load or nil
|
||||||
|
-- @param default The default value to return on error; when nil, then a surface
|
||||||
|
-- in an error state is returned.
|
||||||
|
-- @return The loaded surface, or the replacement default
|
||||||
|
-- @return An error message, or nil on success
|
||||||
|
function surface.load_uncached_silently(_surface, default)
|
||||||
local file
|
local file
|
||||||
-- Nil is not changed
|
-- On nil, return an empty surface
|
||||||
if not _surface then
|
if not _surface then
|
||||||
return nil
|
return get_empty_surface()
|
||||||
end
|
end
|
||||||
-- Remove from cache if it was cached
|
-- Remove from cache if it was cached
|
||||||
surface_cache[_surface] = nil
|
surface_cache[_surface] = nil
|
||||||
|
@ -35,8 +45,15 @@ function surface.load_uncached(_surface)
|
||||||
end
|
end
|
||||||
-- Strings are assumed to be file names and get loaded
|
-- Strings are assumed to be file names and get loaded
|
||||||
if type(_surface) == "string" then
|
if type(_surface) == "string" then
|
||||||
|
local err
|
||||||
file = _surface
|
file = _surface
|
||||||
_surface = capi.awesome.load_image(file)
|
_surface, err = capi.awesome.load_image(file)
|
||||||
|
if not _surface then
|
||||||
|
if type(default) == 'nil' then
|
||||||
|
default = get_empty_surface()
|
||||||
|
end
|
||||||
|
return default, err
|
||||||
|
end
|
||||||
end
|
end
|
||||||
-- Everything else gets forced into a surface
|
-- Everything else gets forced into a surface
|
||||||
_surface = cairo.Surface(_surface, true)
|
_surface = cairo.Surface(_surface, true)
|
||||||
|
@ -47,14 +64,53 @@ function surface.load_uncached(_surface)
|
||||||
return _surface
|
return _surface
|
||||||
end
|
end
|
||||||
|
|
||||||
function surface.load(_surface)
|
--- Try to convert the argument into an lgi cairo surface.
|
||||||
|
-- This is usually needed for loading images by file name and uses a cache.
|
||||||
|
-- In contrast to `load()`, errors are returned to the caller.
|
||||||
|
-- @param _surface The surface to load or nil
|
||||||
|
-- @param default The default value to return on error; when nil, then a surface
|
||||||
|
-- in an error state is returned.
|
||||||
|
-- @return The loaded surface, or the replacement default, or nil if called with
|
||||||
|
-- nil.
|
||||||
|
-- @return An error message, or nil on success
|
||||||
|
function surface.load_silently(_surface, default)
|
||||||
if type(_surface) == "string" then
|
if type(_surface) == "string" then
|
||||||
local cache = surface_cache[_surface]
|
local cache = surface_cache[_surface]
|
||||||
if cache then
|
if cache then
|
||||||
return cache
|
return cache
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return surface.load_uncached(_surface)
|
return surface.load_uncached_silently(_surface, default)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_load_and_handle_errors(_surface, func)
|
||||||
|
if type(_surface) == 'nil' then
|
||||||
|
return get_empty_surface()
|
||||||
|
end
|
||||||
|
local result, err = func(_surface, false)
|
||||||
|
if result then
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
gdebug.print_error("Failed to load '" .. tostring(_surface) .. "': " .. tostring(err))
|
||||||
|
return get_empty_surface()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Try to convert the argument into an lgi cairo surface.
|
||||||
|
-- This is usually needed for loading images by file name. Errors are handled
|
||||||
|
-- via `gears.debug.print_error`.
|
||||||
|
-- @param _surface The surface to load or nil
|
||||||
|
-- @return The loaded surface, or nil
|
||||||
|
function surface.load_uncached(_surface)
|
||||||
|
return do_load_and_handle_errors(_surface, surface.load_uncached_silently)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Try to convert the argument into an lgi cairo surface.
|
||||||
|
-- This is usually needed for loading images by file name. Errors are handled
|
||||||
|
-- via `gears.debug.print_error`.
|
||||||
|
-- @param _surface The surface to load or nil
|
||||||
|
-- @return The loaded surface, or nil
|
||||||
|
function surface.load(_surface)
|
||||||
|
return do_load_and_handle_errors(_surface, surface.load_silently)
|
||||||
end
|
end
|
||||||
|
|
||||||
function surface.mt:__call(...)
|
function surface.mt:__call(...)
|
||||||
|
@ -70,7 +126,6 @@ function surface.get_size(surf)
|
||||||
return w - x, h - y
|
return w - x, h - y
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create a copy of a cairo surface.
|
--- Create a copy of a cairo surface.
|
||||||
-- The surfaces returned by `surface.load` are cached and must not be
|
-- The surfaces returned by `surface.load` are cached and must not be
|
||||||
-- modified to avoid unintended side-effects. This function allows to create
|
-- modified to avoid unintended side-effects. This function allows to create
|
||||||
|
|
|
@ -562,13 +562,7 @@ function naughty.notify(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- is the icon file readable?
|
-- is the icon file readable?
|
||||||
local success, res = pcall(function() return surface.load_uncached(icon) end)
|
local icon = surface.load_uncached(icon)
|
||||||
if success then
|
|
||||||
icon = res
|
|
||||||
else
|
|
||||||
io.stderr:write(string.format("naughty: Couldn't load image '%s': %s\n", tostring(icon), res))
|
|
||||||
icon = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if we have an icon, use it
|
-- if we have an icon, use it
|
||||||
if icon then
|
if icon then
|
||||||
|
|
|
@ -72,17 +72,16 @@ end
|
||||||
--- Set an imagebox' image
|
--- Set an imagebox' image
|
||||||
-- @param image Either a string or a cairo image surface. A string is
|
-- @param image Either a string or a cairo image surface. A string is
|
||||||
-- interpreted as the path to a png image file.
|
-- interpreted as the path to a png image file.
|
||||||
|
-- @return true on success, false if the image cannot be used
|
||||||
function imagebox:set_image(image)
|
function imagebox:set_image(image)
|
||||||
local image = image
|
local image = image
|
||||||
|
|
||||||
if type(image) == "string" then
|
if type(image) == "string" then
|
||||||
local success, result = pcall(surface.load, image)
|
image = surface.load(image)
|
||||||
if not success then
|
if not image then
|
||||||
print("Error while reading '" .. image .. "': " .. result)
|
|
||||||
print(debug.traceback())
|
print(debug.traceback())
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
image = result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
image = surface.load(image)
|
image = surface.load(image)
|
||||||
|
|
16
luaa.c
16
luaa.c
|
@ -147,16 +147,24 @@ luaA_restart(lua_State *L)
|
||||||
/** Load an image from a given path.
|
/** Load an image from a given path.
|
||||||
*
|
*
|
||||||
* @param name The file name.
|
* @param name The file name.
|
||||||
* @return A cairo surface as light user datum.
|
* @return[1] A cairo surface as light user datum.
|
||||||
|
* @return[2] nil
|
||||||
|
* @treturn[2] string Error message
|
||||||
* @function load_image
|
* @function load_image
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
luaA_load_image(lua_State *L)
|
luaA_load_image(lua_State *L)
|
||||||
{
|
{
|
||||||
|
GError *error = NULL;
|
||||||
const char *filename = luaL_checkstring(L, 1);
|
const char *filename = luaL_checkstring(L, 1);
|
||||||
cairo_surface_t *surface = draw_load_image(L, filename);
|
cairo_surface_t *surface = draw_load_image(L, filename, &error);
|
||||||
if (!surface)
|
if (!surface) {
|
||||||
return 0;
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, error->message);
|
||||||
|
g_error_free(error);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* lua has to make sure to free the ref or we have a leak */
|
/* lua has to make sure to free the ref or we have a leak */
|
||||||
lua_pushlightuserdata(L, surface);
|
lua_pushlightuserdata(L, surface);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -124,8 +124,11 @@ drawable_set_geometry(lua_State *L, int didx, area_t geom)
|
||||||
static int
|
static int
|
||||||
luaA_drawable_get_surface(lua_State *L, drawable_t *drawable)
|
luaA_drawable_get_surface(lua_State *L, drawable_t *drawable)
|
||||||
{
|
{
|
||||||
/* Lua gets its own reference which it will have to destroy */
|
if (drawable->surface)
|
||||||
lua_pushlightuserdata(L, cairo_surface_reference(drawable->surface));
|
/* Lua gets its own reference which it will have to destroy */
|
||||||
|
lua_pushlightuserdata(L, cairo_surface_reference(drawable->surface));
|
||||||
|
else
|
||||||
|
lua_pushnil(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue