2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
17 #include <KConfigGroup>
18 #include <KDesktopFile>
19 #include <KStandardDirs>
22 #include "loader/image.h"
23 #include "luaapi/imaging.h"
24 #include "luaapi/loader.h"
25 #include "luaapi/options.h"
29 const luaL_Reg
Loader::lualibs
[] = {
31 {LUA_LOADLIBNAME
, luaopen_package
},
32 {LUA_TABLIBNAME
, luaopen_table
},
33 {LUA_IOLIBNAME
, luaopen_io
},
34 {LUA_OSLIBNAME
, luaopen_os
},
35 {LUA_STRLIBNAME
, luaopen_string
},
36 {LUA_MATHLIBNAME
, luaopen_math
},
37 {LUA_DBLIBNAME
, luaopen_debug
},
38 {LUA_FUNCLIBNAME
, luaopen_func
},
39 {LUA_COLLECTLIBNAME
, luaopen_collect
},
43 Loader::Loader(::Loader::Context
*ctx
)
45 lua_State
* l
= lua_open();
48 for (const luaL_Reg
*lib
= lualibs
; lib
->func
; lib
++) {
49 lua_pushcfunction(l
, lib
->func
);
50 lua_pushstring(l
, lib
->name
);
54 Wrapper
<QRectF
>::register_class(l
);
55 Wrapper
<QPointF
>::register_class(l
);
56 Wrapper
<QColor
>::register_class(l
);
57 Wrapper
<QLinearGradient
>::register_class(l
);
58 Wrapper
<QRadialGradient
>::register_class(l
);
59 Wrapper
<QConicalGradient
>::register_class(l
);
60 Wrapper
<QBrush
>::register_class(l
);
61 Wrapper
<QFont
>::register_class(l
);
62 Wrapper
< ::Loader::Image
>::register_class(l
);
63 Wrapper
< ::Loader::Glyph
>::register_class(l
);
65 Wrapper
<OptList
>::register_class(l
);
66 Wrapper
<BoolOptList
>::register_class(l
);
67 Wrapper
<BoolOptPtr
>::register_class(l
);
68 Wrapper
<IntOptPtr
>::register_class(l
);
69 Wrapper
<StringOptPtr
>::register_class(l
);
70 Wrapper
<UrlOptPtr
>::register_class(l
);
71 Wrapper
<ColorOptPtr
>::register_class(l
);
72 Wrapper
<FontOptPtr
>::register_class(l
);
73 Wrapper
<ComboOptPtr
>::register_class(l
);
74 Wrapper
<SelectOptPtr
>::register_class(l
);
76 lua_pushlightuserdata(l
, ctx
);
77 lua_setfield(l
, LUA_REGISTRYINDEX
, LOADING_CONTEXT
);
79 lua_pushlightuserdata(l
, this);
80 lua_setfield(l
, LUA_REGISTRYINDEX
, API_LOADER
);
82 lua_pushlightuserdata(m_state
, &m_curr_dir
);
83 lua_setfield(m_state
, LUA_REGISTRYINDEX
, CURRENT_DIRECTORY
);
86 lua_setglobal(l
, "theme");
88 lua_pushcfunction(l
, import_func
);
89 lua_setglobal(l
, "import");
91 lua_pushcfunction(l
, read_desktop_file
);
92 lua_setglobal(l
, "desktop_file");
99 bool Loader::runFile(const QString
& file
, bool setdir
) {
101 QString path
= QDir::cleanPath(
102 QDir::isAbsolutePath(file
) ? file
: m_curr_dir
.filePath(file
) );
103 if (!QFile::exists(path
)) {
104 // find it in the scripts dir
105 path
= KStandardDirs::locate("appdata", "scripts/" + file
);
107 if (!QFile::exists(path
)) {
113 QFileInfo
f_info( path
);
114 m_curr_dir
= f_info
.dir();
118 if(luaL_loadfile(m_state
, path
.toAscii().constData()) == 0) {
119 if(lua_pcall(m_state
, 0, LUA_MULTRET
, 0) != 0)
129 m_error_string
= QString(lua_tostring(m_state
, -1));
137 struct Loader::create_value_data
{
140 const LuaValueMap
* args
;
143 create_value_data(const QString
& _key
, int _size
, const LuaValueMap
* _args
, bool _allow_nil
)
147 , allow_nil(_allow_nil
) {
152 T
Loader::getValue(const QString
& key
, int size
, const LuaValueMap
* args
, bool allow_nil
) {
153 StackCheck
s(m_state
);
155 create_value_data
<T
> data(key
, size
, args
, allow_nil
);
156 if(lua_cpcall(m_state
, create_value_func
<T
>, &data
) != 0) {
158 m_error_string
= QString(lua_tostring(m_state
, -1))+"\nsearched key was: "+key
;
165 template ::Loader::Glyph
Loader::getValue
< ::Loader::Glyph
>(const QString
&, int, const LuaValueMap
*, bool);
166 template OptList
Loader::getValue
<OptList
>(const QString
&, int, const LuaValueMap
*, bool);
167 template QString
Loader::getValue
<QString
>(const QString
&, int, const LuaValueMap
*, bool);
168 template QStringList
Loader::getValue
<QStringList
>(const QString
&, int, const LuaValueMap
*, bool);
169 template QImage
Loader::getValue
<QImage
>(const QString
&, int, const LuaValueMap
*, bool);
170 template ImageOrMap
Loader::getValue
<ImageOrMap
>(const QString
&, int, const LuaValueMap
*, bool);
171 template double Loader::getValue
<double>(const QString
&, int, const LuaValueMap
*, bool);
172 template QPointF
Loader::getValue
<QPointF
>(const QString
&, int, const LuaValueMap
*, bool);
173 template QRectF
Loader::getValue
<QRectF
>(const QString
&, int, const LuaValueMap
*, bool);
174 template QColor
Loader::getValue
<QColor
>(const QString
&, int, const LuaValueMap
*, bool);
175 template QBrush
Loader::getValue
<QBrush
>(const QString
&, int, const LuaValueMap
*, bool);
176 template QFont
Loader::getValue
<QFont
>(const QString
&, int, const LuaValueMap
*, bool);
177 template LuaValueMap
Loader::getValue
<LuaValueMap
>(const QString
&, int, const LuaValueMap
*, bool);
180 void Loader::retrieve(create_value_data
<T
>* d
, lua_State
*l
, int pos
) {
181 d
->out
= *Wrapper
<T
>::retrieve(l
, pos
, AssertOk
);
185 void Loader::retrieve
<double>(create_value_data
<double>* d
, lua_State
*l
, int pos
) {
186 d
->out
= lua_tonumber(l
, pos
);
190 void Loader::retrieve
<QString
>(create_value_data
<QString
>* d
, lua_State
*l
, int pos
) {
191 d
->out
= lua_tostring(l
, pos
);
195 void Loader::retrieve
<QColor
>(create_value_data
<QColor
>* d
, lua_State
*l
, int pos
) {
196 d
->out
= Wrapper
<QColor
>::get(l
, pos
);
200 void Loader::retrieve
<QBrush
>(create_value_data
<QBrush
>* d
, lua_State
*l
, int pos
) {
201 d
->out
= Wrapper
<QBrush
>::get(l
, pos
);
205 void Loader::retrieve
<QStringList
>(create_value_data
<QStringList
>* d
, lua_State
*l
, int pos
) {
206 if(lua_isstring(l
, pos
))
207 d
->out
<< QString(lua_tostring(l
, -1));
208 else if(lua_istable(l
, pos
)) {
210 while (lua_next(l
, pos
<0 ? pos
-1 : pos
) != 0) {
211 d
->out
<< QString(lua_tostring(l
, -1));
216 luaL_error(l
, "Can't convert to a QStringList (not string nor table)");
220 void Loader::retrieve
<LuaValueMap
>(create_value_data
<LuaValueMap
>* d
, lua_State
*l
, int pos
) {
221 if(lua_istable(l
, pos
)) {
223 while (lua_next(l
, pos
<0 ? pos
-1 : pos
) != 0) {
224 QString key
= lua_tostring(l
, -2);
225 if(QPointF
*res
= Wrapper
<QPointF
>::retrieve(l
, -1, Check
))
227 else if(QRectF
*res
= Wrapper
<QRectF
>::retrieve(l
, -1, Check
))
230 d
->out
[key
] = lua_tonumber(l
, -1);
235 luaL_error(l
, "Can't convert to a LuaValueMap (not table)");
239 void Loader::retrieve
<QImage
>(create_value_data
<QImage
>* d
, lua_State
*l
, int pos
) {
240 ::Loader::Image
*retv
= Wrapper
< ::Loader::Image
>::retrieve(l
, pos
, AssertOk
);
241 d
->out
= retv
->image();
245 void Loader::retrieve
<ImageOrMap
>(create_value_data
<ImageOrMap
>* d
, lua_State
*l
, int pos
) {
246 if(::Loader::Image
*img
= Wrapper
< ::Loader::Image
>::retrieve(l
, pos
))
247 d
->out
= img
->image();
248 else if(lua_istable(l
, pos
)) {
250 //collect the images in this way to avoid leaking memory if Wrapper::retrieve raises an exception
252 ImageMap
& out
= boost::get
<ImageMap
>(d
->out
);
255 while (lua_next(l
, pos
<0 ? pos
-1 : pos
) != 0) {
256 QRectF
*rect
= Wrapper
<QRectF
>::retrieve(l
, -2, AssertOk
);
257 ::Loader::Image
*img
= Wrapper
< ::Loader::Image
>::retrieve(l
, -1, AssertOk
);
259 QRect r
= rect
->toRect();
260 out
[rect
->toRect()] = img
->image();
266 luaL_error(l
, "Can't convert to a ImageOrMap (not image nor table)");
270 int Loader::create_value_func(lua_State
*l
) {
272 create_value_data
<T
>* data
= reinterpret_cast<create_value_data
<T
>*>(lua_touserdata(l
, -1));
275 lua_getglobal(l
, "theme");
276 lua_getfield(l
, -1, data
->key
.toAscii().constData());
279 /* If it is a function call it, or else try to retrieve directly the value */
280 if(lua_isnil(l
, -1)) {
282 luaL_error(l
, "No such entry: %s", data
->key
.toAscii().constData());
285 if(lua_isfunction(l
, -1)) {
288 lua_pushnumber(l
, data
->size
);
292 lua_pushvaluemap(l
, data
->args
);
295 lua_call(l
, nparams
, 1);
298 retrieve
<T
>(data
, l
, -1);
306 int Loader::import_func(lua_State
*l
) {
307 lua_getfield(l
, LUA_REGISTRYINDEX
, API_LOADER
);
308 Loader
* api
= reinterpret_cast<Loader
*>(lua_touserdata(l
, -1));
311 int n
= lua_gettop(l
);
313 luaL_error(l
, "Wrong argument count for \"import\"");
314 QString
file(lua_tostring(l
, 1));
317 if (!api
->runFile(file
, false)) {
318 luaL_error(l
, "Error importing \"%s\":\n%s", file
.toAscii().constData(),
319 api
->errorString().toAscii().constData() );
325 int Loader::read_desktop_file(lua_State
* l
) {
326 lua_getfield(l
, LUA_REGISTRYINDEX
, API_LOADER
);
327 Loader
* api
= reinterpret_cast<Loader
*>(lua_touserdata(l
, -1));
330 int n
= lua_gettop(l
);
332 luaL_error(l
, "Wrong argument count for \"desktop_file\"");
335 QString filePath
= api
->currDir().filePath("theme.desktop");
336 if (!KDesktopFile::isDesktopFile(filePath
)) {
341 KDesktopFile
theme(filePath
);
343 // set theme fields according to the desktop file
344 lua_getglobal(l
, "theme");
346 QString name
= theme
.readName();
347 if (!name
.isEmpty()) {
348 lua_pushstring(l
, "name");
349 lua_pushstring(l
, qPrintable(name
));
353 QString description
= theme
.readComment();
354 if (!name
.isEmpty()) {
355 description
.replace("|", "\n");
356 lua_pushstring(l
, "description");
357 lua_pushstring(l
, qPrintable(description
));
361 KConfigGroup themeGroup
= theme
.desktopGroup();
362 QString variants
= themeGroup
.readEntry("X-Tagua-Variants");
363 if (!variants
.isEmpty()) {
364 QStringList varlist
= variants
.split(QRegExp("\\s*,\\s*"));
365 lua_pushstring(l
, "variants");
367 for (int i
= 0; i
< varlist
.size(); i
++) {
368 lua_pushnumber(l
, i
+ 1);
369 lua_pushstring(l
, qPrintable(varlist
[i
]));
378 } // namespace LuaLoader