pax_global_header00006660000000000000000000000064122144070640014512gustar00rootroot0000000000000052 comment=7154cd627211d399d26550cb75bf7fb963522ab8 lua-lgi-0.7.2/000077500000000000000000000000001221440706400130525ustar00rootroot00000000000000lua-lgi-0.7.2/.gitignore000066400000000000000000000001001221440706400150310ustar00rootroot00000000000000*.o *.so *.dll *.stackdump .depcheck *.rockspec cairodemo-*.png lua-lgi-0.7.2/LICENSE000066400000000000000000000020531221440706400140570ustar00rootroot00000000000000Copyright (c) 2010, 2011 Pavel Holejsovsky Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lua-lgi-0.7.2/Makefile000066400000000000000000000007601221440706400145150ustar00rootroot00000000000000# # LGI Dynamic GObject introspection binding. # # Author: Pavel Holejsovsky # License: MIT # VERSION = 0.7.2 MAKE ?= make ROCK = lgi-$(VERSION)-1.rockspec .PHONY : rock all clean install check all : $(MAKE) -C lgi rock : $(ROCK) $(ROCK) : rockspec.in Makefile sed 's/%VERSION%/$(VERSION)/' $< >$@ clean : rm -f *.rockspec $(MAKE) -C lgi clean $(MAKE) -C tests clean install : $(MAKE) -C lgi install check : all $(MAKE) -C tests check export VERSION lua-lgi-0.7.2/README.md000066400000000000000000000173041221440706400143360ustar00rootroot00000000000000# LGI LGI is gobject-introspection based dynamic Lua binding to GObject based libraries. It allows using GObject-based libraries directly from Lua. Licensed under [MIT-style](http://www.opensource.org/licenses/mit-license.php) license, see LICENSE file for full text. Home of the project is on [GitHub](http://github.com/pavouk/lgi). LGI is tested and compatible with standard Lua 5.1, Lua 5.2 and LuaJIT2. Compatibility with other Lua implementations is not tested yet. If you need to support pre-gobject-introspection GTK (ancient GTK+ 2.x releases), use [Lua-Gnome](http://sourceforge.net/projects/lua-gnome/). ## Installation: In order to be able to compile native part of lgi, gobject-introspection >= 0.10.8 development package must be installed, although preferred version is >= 1.30. The development package is called `libgirepository1.0-dev` on debian-based systems (like Ubuntu) and `gobject-introspection-devel` on RedHat-based systems (like Fedora). Using LuaRocks: luarocks install lgi Alternatively, use make-based installation: make [sudo] make install [PREFIX=] [DESTDIR=] Please note that on BSD-systems you may need to use 'gmake'. ## Usage See examples in samples/ directory. Documentation is available in doc/ directory in markdown format. Process it with your favorite Markdown processor if you want to read it in HTML. ## Credits List of contributors, in no particular order: - Uli Schlachter - Jasper Lievisse Adriaanse - Ildar Mulyukov - Nils Nordman - Ignas Anikevicius - Craig Barnes - Nicola Fontana - Andreas Stührk Many other people contributed to what lgi is today, in many forms - writing patches, reporting bugs, packaging for distributions, providing ideas, spreading a word... *Many thanks to all of you!* ## History ### 0.7.2 (12-Sep-2013) - fix: improper marshalling of certain APIs passing pointers to records. - fix: cairo.PsSurface.create() had incorrect signature, missing filename. - fix: If GTK initialization fails, raise Lua exception instead of hard-crash of calling process. - fix: when running test in devel tree, prefer lgi from devel tree instead of the installed one. - add: cairo.Status.to_string() API - fix: avoid referencing GdkRGBA in GDk override when targetting Gdk2.0, which does not have GdkRGBA. - fix: replace GStaticRecMutex with GRecMutex to avoid compilation warnings. - fix: Gtk.Container.'child' pseudoproperty works even in Gtk2, where it was shadowed by internal field. - fix: add workaround for improperly parsed g_bytes_get_data() annotation. - fix: add workarounf for incorrect annotation on Pango.Layour.set_attributes(), which caused memory leak. - fix: adapt to Gio.InputStream.[read|read_all|read_async] API change, which does not accept buffer length argument any more (due to the newly added annotations). ### 0.7.1 (4-Mar-2013) - Add support for GStreamer 1.0, while still retaining GStreamer 0.10 compatibility. - fix: crash when trying to to access '_class' attribute of class which does not have public classstruct exposed in typelib - fix: crash when passing 'nil' to transfer=full struct (caused crash of Awesome WM during startup). ### 0.7.0 (23-Feb-2013) - New feature - subclassing. Allows creating GObject subclasses and implementing their virtual methods in Lua. - cairo: add support for most 1.12-specific cairo features - cairo: create hierarchy for Pattern subclasses - cairo: assorted small cairo bugfixes - samples: add GDBus client example - samples: add GnomeKeyring example - samples: GTK: offscreen window demos - samples: libsoup simple http server example - platforms: added support for darwin/macosx platform - platforms: additional fixes for OpenBSD - build: Makefiles now respect `CFLAGS` and `LDFLAGS` env vars values - build: Add Lua version option into Makefile - fix: custom ffi enum/flags handling - fix: more exotic callback-to-Lua marshalling scenarios - fix: do not allow GTK+ and gstreamer to call setlocale() - this might break Lua in some locales - fix: small adjustments, fixes and additions in Gtk override - fix: tons of other small fixes ### 0.6.2 (25-Jun-2012) - Avoid unexpected dependency on cairo-devel, cairo-runtime is now enough - Make `set_resident()` more robust and fix stack leak for Lua 5.2 case, avoid useless warning when `set_resident()` fails (to accomodate for static linking case). - Fix small memory leak (mutex) which occured once per opened `lua_State` using lgi. ### 0.6.1 (19-Jun-2012) - objects and structs: actually implement `_type` property as documented - tests: Fix regression tests for less common platforms - Pango: Add a few missing overrides - cairo: Fix `Context:user_to_device()` family of methods. - GStreamer: Add support for transfer!=none for input objects. This is needed to avoid leaks caused by strange usage of transfer annotations of gstreamer-0.10 - GStreamer: Add more missing overrides - GStreamer: Fix and improve samples - Various fixes for usecase when Lua context with loaded lgi is closed and opened again - Gtk: Add missing `Gtk.Builder:connect_signals()` override ### 0.6 (22-May-2012) - Add cairo bindings, cairo sample and finish some gtk-demo parts which were requiring cairo ### 0.5.1 (not officially released) - Fix a few problems on more exotic architectures (s390x, mips, ia64). - Allow passing `byte.buffer` when UTF8 string is requested. ### 0.5 (15-Apr-2012) - Port gtk3-demo to Lua code. Try running 'lua samples/gtk-demo/main.lua' - Finish override set for Gtk - Extend and document features for interfacing LGI with external libraries (exporting and importing objects and structures via lightuserdata pointers). - Fix: a few bugs with resolving bitflags values - Fix: a few bugs in coroutines-as-callbacks feature - Fix: workaround for crashing bug in gobject-introspection 1.32.0 - Fix: don't try to squeeze `GType` into `lua_Number` any more; this could cause crashes on some 64bit arches. ### 0.4 (4-Jan-2012) - Changed handling of enums and bitflags, switched from marshaling them as numbers to prefering strings for enums and tables (sets or lists) for bitflags. Numeric values still work for Lua->C marshalling, but backward compatibility is broken in C->Lua enum and bitflags marshalling. - Compatible with Lua 5.2 and LuaJIT - Added standardized way for overrides to handle constructor argument table array part. - Existing Gtk overrides reworked and improved, there is now a way to describe and create widget hierarchies in Lua-friendly way. See `docs/gtk.lua`, chapter about `Gtk.Container` for overview and samples. - Various bugfixes and portability fixes. ### 0.3 (28-Nov-2011) - Project hosting moved to GitHub. - Build system switched from `waf` to simple Makefile-based one - Added automatic locking of thread-sensitive libraries (Gdk and Clutter). There is no need to add `Gdk.threads_enter()`, `Gdk.threads_leave()` and `Clutter.threads_enter()`, `Clutter.threads_leave()` pairs into application, lgi handles this automatically. - Added new sample `samples/console.lua`, which implements already quite usable Lua console using Gtk widgets. - Fixes for compatibility with older gobject-introspection 0.10.8 package - Testsuite is not built automatically, because building it can be apparently problematic on some systems, causing installation failure even when testsuite is not needed at all. - Remove `setlocale()` initialization, which could break Lua when used with some regional locales. The downside of this change is that marshaling file names containing non-ASCII characters on systems which define `G_BROKEN_FILENAMES` environment variable (probably only Fedora 15) does not work now. ### 0.2 (7-Nov-2011) First public release lua-lgi-0.7.2/docs/000077500000000000000000000000001221440706400140025ustar00rootroot00000000000000lua-lgi-0.7.2/docs/cairo.md000066400000000000000000000157211221440706400154270ustar00rootroot00000000000000# cairo support Cairo library is an important part of any GTK-based setup, because GTK internally uses cairo exclusively for painting. However, cairo itself is not built using GObject technology and thus imposes quite a problem for any GObject Introspection based binding, such as lgi. ## Basic binding description Although internal implementation is a bit different from other fully introspection-enabled libraries, this difference is not visible to lgi user. cairo must be imported in the same way as other libraries, e.g. local lgi = require 'lgi' local cairo = lgi.cairo Cairo library itself is organized using object-oriented style, using C structures as objects (e.g. `cairo_t`, `cairo_surface_t`) and functions as methods acting upon these objects. lgi exports objects as classes in the `cairo` namespace, e.g. `cairo.Context`, `cairo.Surface` etc. To create new object instance, cairo offers assorted `create` methods, e.g. `cairo_create` or `cairo_pattern_create`, which are mapped as expected to `cairo.Context.create` and `cairo.Pattern.create`. It is also possible to invoke them using lgi's 'constructor' syntax, i.e. to create new context on specified surface, it is possible to use either `local cr = cairo.Context.create(surface)` or `local cr = cairo.Context(surface)`. ### Version checking `cairo.version` and `cairo.version_string` fields contain current runtime cairo library version, as returned by their C counterparts `cairo_version()` and `cairo_version_string()`. Original `CAIRO_VERSION_ENCODE` macro is reimplemented as `cairo.version_encode(major, minor, micro)`. For example, following section shows how to guard code which should be run only when cairo version is at least 1.12: if cairo.version >= cairo.version_encode(1, 12, 0) then -- Cairo 1.12-specific code else -- Fallback to older cairo version code end ### Synthetic properties There are many getter and setter functions for assorted cairo objects. lgi exports them in the form of method calls as the native C interface does, and it also provides property-like access, so that it is possible to query or assign named property of the object. Following example demonstrates two identical ways to set and get line width on cairo.Context instance: local cr = cairo.Context(surface) cr:set_line_width(10) print('line width ', cr:get_line_width()) cr.line_width = 10 print('line width ', cr.line_width) In general, any kind of `get_xxx()` method call on any cairo object can be replaced using `xxx` property on the object, and any `set_xxx()` method can be replaced by setting `xxx` property. ### cairo.Surface hierarchy Cairo provides basic rendering surface object `cairo.Surface`, and a bunch of specialized surfaces implementing rendering to assorted targets, e.g. `cairo.ImageSurface`, `cairo.PdfSurface` etc. These surface provide their own class, which is logically inherited from `cairo.Surface`. lgi fully implements this inheritance, so that calling `cairo.ImageSurface()` actually creates an instance of `cairo.ImageSurface` class, which provides all methods abd properties of `cairo.Surface` and and some specialized methods and properties like `width` and `height`. In addition, lgi always assigns the real type of the surface, so that even when `cairo.Context.get_target()` method (or `cairo.Context.target` property) is designated as returning `cairo.Surface` instance, upon the call the type of the surface is queried and proper kind of surface type is really returned. Following example demonstrates that it is possible to query `cairo.ImageSurface`-specific `width` property directly on the `cairo.Context.target` result. -- Assumes the cr is cairo.Context instance with assigned surface print('width of the surface' cr.target.width) It is also possible to use lgi generic typechecking machinery for checking the type of the surface: if cairo.ImageSurface:is_type_of(cr.target) then print('width of the surface' cr.target.width) else print('unsupported type of the surface') end ### cairo.Pattern hierarchy cairo's pattern API actually hides the inheritance of assorted pattern types. lgi binding brings this hierarchy up in the same way as for surfaces described in previous section. Following hierarchy exists: cairo.Pattern cairo.SolidPattern cairo.SurfacePattern cairo.GradientPattern cairo.LinearPattern cairo.RadialPattern cairo.MeshPattern Patterns can be created using static factory methods on `cairo.Pattern` as documented in cairo documentation. In addition, lgi maps creation methods to specific subclass constructors, so following snippets are equivalent: local pattern = cairo.Pattern.create_linear(0, 0, 10, 10) local pattern = cairo.LinearPattern(0, 0, 10, 10) ### cairo.Context path iteration cairo library offers iteration over the drawing path returned via `cairo.Context.copy_path()` method. Resulting path can be iterated using `pairs()` method of `cairo.Path` class. `pairs()` method returns iterator suitable to be used in Lua 'generic for' construct. Iterator returns type of the path element, optionally followed by 0, 1 or 3 points. Following example shows how to iterate the path. local path = cr:copy_path() for kind, points in path:pairs() do io.write(kind .. ':') for pt in ipairs(points) do io.write((' { %g, %g }'):format(pt.x, pt.y)) end end end ## Impact of cairo on other libraries In addition to cairo itself, there is a bunch of cairo-specific methods inside Gtk, Gdk and Pango libraries. lgi wires them up so that they can be called naturally as if they were built in to the cairo core itself. ### Gdk and Gtk `Gdk.Rectangle` is just a link to `cairo.RectangleInt` (similar to C, where `GdkRectangle` is just a typedef of `cairo_rectangle_int_t`). `gdk_rectangle_union` and `gdk_rectangle_intersect` are wired as a methods of `Gdk.Rectangle` as expected. `Gdk.cairo_create()` is aliased as a method `Gdk.Window.cairo_create()`. `Gdk.cairo_region_create_from_surface()` is aliased as `cairo.Region.create_from_surface()`. `cairo.Context.set_source_rgba()` is overriden so that it also accepts `Gdk.RGBA` instance as an argument. Similarly, `cairo.Context.rectangle()` alternatively accepts `Gdk.Rectangle` as an argument. `cairo.Context` has additional methods `get_clip_rectangle()`, `set_source_color()`, `set_source_pixbuf()`, `set_source_window` and `region`, implemented as calls to appropriate `Gdk.cairo_xxx` functions. Since all these extensions are implemented inside Gdk and Gtk libraries, they are present only when `lgi.Gdk` is loaded. When loading just pure `lgi.cairo`, they are not available. ### PangoCairo Pango library contains namespace `PangoCairo` which implements a bunch of cairo-specific helper functions to integrate Pango use with cairo library. It is of course possible to call them as global methods of PangoCairo interface, however lgi override maps the also to methods and attributes of other classes to which they logically belong. lua-lgi-0.7.2/docs/gtk.md000066400000000000000000000275241221440706400151230ustar00rootroot00000000000000# Gtk support Lgi Gtk support is based on gobject-introspection support. Some extensions are provided to support non-introspectable features and to provide easier and more Lua-like access to some important Gtk features. ## Basic Widget and Container support ### Style properties access To read style property values of the widget, a `style` attribute is implemented. Following example reads `resize-grip-height` style property from Gtk.Window instance: local window = Gtk.Window() print(window.style.resize_grip_height) ### Gtk.Widget width and height properties lgi adds new `width` and `height` properties to Gtk.Widget. Reading them yields allocated size (`Gtk.Widget.get_allocated_size()`), writing them sets new size request (`Gtk.Widget.set_size_request()`). These usages typically means what an application needs - actual allocated size to draw on when reading, and request for specific size when writing them. ### Child properties Child properties are properties of the relation between a container and child. A Lua-friendly access to these properties is implemented by `property` attribute of `Gtk.Container`. Following example illustrates writing and reading of `width` property of `Gtk.Grid` and child `Gtk.Button`: local grid, button = Gtk.Grid(), Gtk.Button() grid:add(button) grid.property[button].width = 2 print(grid.property[button].width) -- prints 2 ### Adding children to container Basic method for adding child widget into container is `Gtk.Container.add()` method. This method is overloaded by Lgi so that it accepts either widget, or table containing widget at index 1 and the rest `name=value` pairs define child properties. Therefore this method is full replacement of unintrospectable `gtk_container_add_with_properties()` function. Example from previous chapter simplified using this technique follows: local grid, button = Gtk.Grid(), Gtk.Button() grid:add { button, width = 2 } print(grid.property[button].width) -- prints 2 Another important feature of containers is that they have extended constructor, and array part of constructor argument table can contain widgets to be added. Therefore, previous example can be written like this: local button = Gtk.Button() local grid = Gtk.Grid { { button, width = 2 } } print(grid.property[button].width) -- prints 2 ### 'id' property of widgets Another important feature is that all widgets support `id` property, which can hold an arbitrary string which is used to identify the widget. `id` is assigned by caller, defaults to `nil`. To look up widget with specified id in the container's widget tree (i.e. not only in direct container children), query `child` property of the container with requested id. Previous example rewritten with this technique would look like this: local grid = Gtk.Grid { { Gtk.Button { id = 'button' }, width = 2 } } print(grid.property[grid.child.button].width) -- prints 2 The advantage of these features is that they allow using Lua's data-description face for describing widget hierarchies in natural way, instead of human-unfriendly `Gtk.Builder`'s XML. A small example follows: Gtk = lgi.Gtk local window = Gtk.Window { title = 'Application', default_width = 640, default_height = 480, Gtk.Grid { orientation = Gtk.Orientation.VERTICAL, Gtk.Toolbar { Gtk.ToolButton { id = 'about', stock_id = Gtk.STOCK_ABOUT }, Gtk.ToolButton { id = 'quit', stock_id = Gtk.STOCK_QUIT }, }, Gtk.ScrolledWindow { Gtk.TextView { id = 'view', expand = true } }, Gtk.Statusbar { id = 'statusbar' } } } local n = 0 function window.child.about:on_clicked() n = n + 1 window.child.view.buffer.text = 'Clicked ' .. n .. ' times' end function window.child.quit:on_clicked() window:destroy() end window:show_all() Run `samples/console.lua`, paste example into entry view and enjoy. The `samples/console.lua` example itself shows more complex usage of this pattern. ## Gtk.Builder Although Lua's declarative style for creating widget hierarchies (as presented in chapter discussing `Gtk.Container` extensions) is generally preferred to builder's XML authoring by hand, `Gtk.Builder` can still be useful when widget hierarchies are designed in some external tool like `glade`. Original `gtk_builder_add_from_file` and `gtk_builder_add_from_string` return `guint` instead of `gboolean`, which would make direct usage from Lua awkward. Lgi overrides these methods to return `boolean` as the first return value, so that typical `assert(builder:add_from_file(filename))` can be used. A new `objects` attribute provides direct access to loaded objects by their identifier, so that instead of `builder:get_object('id')` it is possible to use `builder.objects.id` `Gtk.Builder.connect_signals(handlers)` tries to connect all signals to handlers which are defined in `handlers` table. Functions from `handlers` table are invoked with target object on which is signal defined as first argument, but it is possible to define `object` attribute, in this case the object instance specified in `object` attribute is used. `after` attribute is honored, but `swapped` is completely ignored, as its semantics for lgi is unclear and not very useful. ## Gtk.Action and Gtk.ActionGroup Lgi provides new method `Gtk.ActionGroup:add()` which generally replaces unintrospectable `gtk_action_group_add_actions()` family of functions. `Gtk.ActionGroup:add()` accepts single argument, which may be one of: - an instance of `Gtk.Action` - this is identical with calling `Gtk.Action.add_action()`. - a table containing instance of `Gtk.Action` at index 1, and optionally having attribute `accelerator`; this is a shorthand for `Gtk.ActionGroup.add_action_with_accel()` - a table with array of `Gtk.RadioAction` instances, and optionally `on_change` attribute containing function to be called when the radio group state is changed. All actions or groups can be added by an array part of `Gtk.ActionGroup` constructor, as demonstrated by following example: local group = Gtk.ActionGroup { Gtk.Action { name = 'new', label = "_New" }, { Gtk.Action { name = 'open', label = "_Open" }, accelerator = 'O' }, { Gtk.RadioAction { name = 'simple', label = "_Simple", value = 1 }, { Gtk.RadioAction { name = 'complex', label = "_Complex", value = 2 }, accelerator = 'C' }, on_change = function(action) print("Changed to: ", action.name) end }, } To access specific action from the group, a read-only attribute `action` is added to the group, which allows to be indexed by action name to retrieve. So continuing the example above, we can implement 'new' action like this: function group.action.new:on_activate() print("Action 'New' invoked") end ## Gtk.TextTagTable It is possible to populate new instance of the tag table with tags during the construction, an array part of constructor argument table is expected to contain `Gtk.TextTag` instances which are then automatically added to the table. A new attribute `tag` is added, provides Lua table which can be indexed by string representing tag name and returns the appropriate tag (so it is essentially a wrapper around `Gtk.TextTagTable:lookup()` method). Following example demonstrates both capabilities: local tag_table = Gtk.TextTagTable { Gtk.TextTag { name = 'plain', color = 'blue' }, Gtk.TextTag { name = 'error', color = 'red' }, } assert(tag_table.tag.plain == tag_table:lookup('plain')) ## TreeView and related classes `Gtk.TreeView` and related classes like `Gtk.TreeModel` are one of the most complicated objects in the whole `Gtk`. Lgi adds some overrides to simplify the work with them. ### Gtk.TreeModel Lgi supports direct indexing of treemodel instances by iterators (i.e. `Gtk.TreeIter` instances). To get value at specified column number, index the resulting value again with column number. Note that although `Gtk` uses 0-based column numbers, Lgi remaps them to 1-based numbers, because working with 1-based arrays is much more natural for Lua. Another extension provided by Lgi is `Gtk.TreeModel:pairs([parent_iter])` method for Lua-native iteration of the model. This method returns 3 values suitable to pass to generic `for`, so that standard Lua iteration protocol can be used. See the example in the next chapter which uses this technique. ### Gtk.ListStore and Gtk.TreeStore Standard `Gtk.TreeModel` implementations, `Gtk.ListStore` and `Gtk.TreeStore` extend the concept of indexing model instance with iterators also to writing values. Indexing resulting value with 1-based column number allows writing individual values, while assigning the table containing column-keyed values allows assigning multiple values at once. Following example illustrates all these techniques: local PersonColumn = { NAME = 1, AGE = 2, EMPLOYEE = 3 } local store = Gtk.ListStore.new { [PersonColumn.NAME] = GObject.Type.STRING, [PersonColumn.AGE] = GObject.Type.INT, [PersonColumn.EMPLOYEE] = GObject.Type.BOOLEAN, } local person = store:append() store[person] = { [PersonColumn.NAME] = "John Doe", [PersonColumn.AGE] = 45, [PersonColumn.EMPLOYEE] = true, } assert(store[person][PersonColumn.AGE] == 45) store[person][PersonColumn.AGE] = 42 assert(store[person][PersonColumn.AGE] == 42) -- Print all persons in the store for i, p in store:pairs() do print(p[PersonColumn.NAME], p[PersonColumn.AGE]) end Note that `append` and `insert` methods are overridden and accept additional parameter containing table with column/value pairs, so creation section of previous example can be simplified to: local person = store:append { [PersonColumn.NAME] = "John Doe", [PersonColumn.AGE] = 45, [PersonColumn.EMPLOYEE] = true, } Note that while the example uses `Gtk.ListStore`, similar overrides are provided also for `Gtk.TreeStore`. ### Gtk.TreeView and Gtk.TreeViewColumn Lgi provides `Gtk.TreeViewColumn:set(cell, data)` method, which allows assigning either a set of `cell` renderer attribute->model column pairs (in case that `data` argument is a table), or assigns custom data function for specified cell renderer (when `data` is a function). Note that column must already have assigned cell renderer. See `gtk_tree_view_column_set_attributes()` and `gtk_tree_view_column_set_cell_data_func()` for precise documentation. The override `Gtk.TreeViewColumn:add(def)` composes both adding new cellrenderer and setting attributes or data function. `def` argument is a table, containing cell renderer instance at index 1 and `data` at index 2. Optionally, it can also contain `expand` attribute (set to `true` or `false`) and `align` (set either to `start` or `end`). This method is basically combination of `gtk_tree_view_column_pack_start()` or `gtk_tree_view_column_pack_end()` and `set()` override method. Array part of `Gtk.TreeViewColumn` constructor call is mapped to call `Gtk.TreeViewColumn:add()` method, and array part of `Gtk.TreeView` constructor call is mapped to call `Gtk.TreeView:append_column()`, and this allows composing the whole initialized treeview in a declarative style like in the example below: -- This example reuses 'store' model created in examples in -- Gtk.TreeModel chapter. local view = Gtk.TreeView { model = store, Gtk.TreeViewColumn { title = "Name and age", expand = true, { Gtk.CellRendererText {}, { text = PersonColumn.NAME } }, { Gtk.CellRendererText {}, { text = PersonColumn.AGE } }, }, Gtk.TreeViewColumn { title = "Employee", { Gtk.CellRendererToggle {}, { active = PersonColumn.EMPLOYEE } } }, } lua-lgi-0.7.2/docs/guide.md000066400000000000000000001000511221440706400154160ustar00rootroot00000000000000# lgi User's Guide All lgi functionality is exported through `lgi` module. To access it, use standard `require` construct, e.g.: local lgi = require 'lgi' Note that lgi does not use `module` function, so it does *not* automatically insert itself into globals, the return value from `require` call has to be used. ## 1. Importing libraries To use any introspection-enabled library, it has to be imported first. Simple way to import it is just referencing its name in `lgi` namespace, like this: local GLib = lgi.GLib local GObject = lgi.GObject local Gtk = lgi.Gtk This imports the latest version of the module which can be found. When exact version is requested, use `lgi.require(modulename, version)`: local Gst = lgi.require('Gst', '0.10') ### 1.1. Repository structure Importing library creates table containing all elements which are present in the library namespace - all classes, structures, global functions, constants etc. All those elements are directly accessible, e.g. assert(GLib.PRIORITY_DEFAULT == 0) Note that all elements in the namespace are lazy-loaded to avoid excessive memory overhead and initial loading time. To force eager-loading, all namespaces (and container elements in them, like classes, structures, enums etc) contains `_resolve(deep)` method, which loads all contents eagerly, possibly recursively if `deep` argument is `true`. So e.g. dump(Gtk.Widget:_resolve(true), 3) prints everything available in Gtk.Widget class, and dump(Gio:_resolve(true), 5) dumps the whole contents of Gio package. Note: the `dump` function used in this manual is part of `cli-debugger` Lua package. Of course, you can use any kind of table-dumping facility you are used to instead. ## 2. Mapping of types between GLib and Lua In order to call methods and access properties and fields from Lua, a mapping between GLib types and Lua types is established. * `void` is ignored, does not produce any Lua value * `gboolean` is mapped to Lua's `boolean` type, with `true` and `false` values * All numeric types are mapped to Lua's `number` type * Enumerations are primarily handled as strings with uppercased GType nicks, optionally the direct numeric values are also accepted. * Bitflags are primarily handled as lists or sets of strings with uppercased GType nicks, optionally the direct numeric values are also accepted. * `gchar*` string is mapped to Lua as `string` type, UTF-8 encoded * C array types and `GArray` is mapped to Lua tables, using array part of the table. Note that although in C the arrays are 0-based, when copied to Lua table, they are 1-based (as Lua uses 1-based arrays). * `GList` and `GSList` is also mapped to Lua array part of tables. * `GHashTable` is mapped to Lua table, fully utilizing key-value and GHashTable's key and value pairs. * C arrays of 1-byte-sized elements (i.e. byte buffers) is mapped to Lua `string` instead of tables, although when going Lua->GLib direction, tables are also accepted for this type of arrays. * GObject class, struct or union is mapped to lgi instances of specific class, struct or union. It is also possible to pass `nil`, in which case the `NULL` is passed to C-side (but only if the annotation `(allow-none)` of the original C method allows passing `NULL`). * `gpointer` are mapped to Lua `lightuserdata` type. In Lua->GLib direction, following values are accepted for `gpointer` type: - Lua `string` instances - Instances of lgi classes, structs or unions - Binary buffers (see below) ### 2.1. Modifiable binary buffers Pure Lua lacks native binary modifiable buffer structure, which is a problem for some GObject APIs, for example `Gio.InputStream.read()`, which request pre-allocated buffer which will be modified (filled) during the call. To overcome this problem, lgi adopts the [bytes proposal](http://permalink.gmane.org/gmane.comp.lang.lua.general/79288 "Defining a library for mutable byte arrays"). Since the standalone implementation of this proposal does not seem to be available yet, lgi uses its own implementation which is used when no external `bytes` package can be found. An example of `bytes` buffer usage follows: local lgi = require 'lgi' local bytes = require 'bytes' local Gio = lgi.Gio local stream = assert(Gio.File.new_for_path('foo.txt'):read()) local buffer = bytes.new(50) local size = stream:read(buffer, #buffer) assert(size >= 0) print(tostring(buffer):sub(1, size)) Note that not full `bytes` proposal is currently implemented, 'Derived operations' are not available except creating buffer from string using `bytes.new` function. ### 2.2. Calling functions and methods When calling GLib functions, following conventions apply: * All input arguments are mapped to Lua inputs * Return value is the first Lua return value * All output arguments follow the return value * In/Out arguments are both accepted as input and are also added into Lua returns. * Functions reporting errors through `GError **` as last argument use Lua standard error reporting - they typically return boolean value indicating either success or failure, and if failure occurs, following return values represent error message and error code. #### 2.2.1. Phantom boolean return values GLib based libraries often use boolean return value indicating whether logically-output argument is filled in or not. Typical example is `gboolean gtk_tree_model_get_iter_first(GtkTreeModel *tree_model, GtkTreeIter *iter)`, where `iter` is filled in case of success, and untouched in case of failure. Normal binding of such function feels a bit unnatural in Lua: local ok, iter = model:get_iter_first() -- Even in case of failure, iter contains new 0-initialized -- instance of the iterator, so following line is necessary: if not ok then iter = nil end To ease usage of such method, lgi avoids returning first boolean return. If C function returns `false` in this case, all other output arguments are returned as `nil`. This means that previous example should be instead written simply as: local iter = model:get_iter_first() ### 2.3. Callbacks When some GLib function or method requires callback argument, a Lua function should be provided (or userdata or table implementing `__call` metamethod), and position for callback context (usually called `user_data` in GLib function signature) should be ignored completely. Callbacks are invoked in the context of Lua coroutine which invoked the original call, unless the coroutine is suspended - in this, case a new coroutine is automatically created and callback is invoked in this new context. Callback arguments and return values are governed by the same rules of argument and type conversions as written above. If the Lua callback throws an error, the error is *not* caught by the calling site, instead propagated out (usually terminating unless there is some `pcall` in the call chain). It is also possible to provide coroutine instance as callback argument. In this case, the coroutine is resumed, providing callback arguments as parameters to resume (therefore they are return values of `coroutine.yield()` call which suspended the coroutine passed as callback argument). The callback is in this case considered to return when either coroutine terminates (in this case, callback return value(s) are coroutine final result(s)) or yields again (in this case, callback return value(s) are arguments to `coroutine.yield()` call). This mode of operation is very useful when using Gio-style asynchronous calls; see `samples\giostream.lua` for example usage of this technique. ## 3. Classes Classes are usually derived from `GObject` base class. Classes contain entities like properties, methods and signals and provide inheritance, i.e. entities of ancestor class are also available in all inherited classes. lgi supports Lua-like access to entities using `.` and `:` operators. There is no need to invoke any memory management GObject controls, like `ref` or `unref` methods, because lgi handles reference management transparently underneath. In fact, calling these low-level methods can probably always be considered either as a bug or workaround for possible bug in lgi :-) ### 3.1. Creating instances To create new instance of the class (i.e. new object), call class declaration as if it is a method: local window = Gtk.Window() Optionally, it is possible to pass single argument, table containing entity name mapping to entity value. This way it is possible to initialize properties, fields and even signal handlers in the class construction: local window = Gtk.Window { title = "Title", on_destroy = function() print("Destroyed") end } For some classes, which behave like containers of other things, lgi allows adding also a list of children into the array part of the argument table, which contains children element to be added. A typical example is `Gtk.Container`, which allows adding element in the constructor table, allowing construction of the whole widget hierarchy in Lua-friendly way: local window = Gtk.Window { title = "Title", on_destroy = function() print("Destroyed") end, Gtk.Grid { Gtk.Label { label = "Contents", expand = true }, Gtk.Statusbar {} } } There is also possibility to create instances of classes for which the introspection typelib data is not available, only GType is known. Use `GObject.Object.new()` as illustrated in following sample: local gtype = 'ForeignWidget' local widget = GObject.Object.new(gtype) local window = Gtk.Window { title = 'foreign', widget } ### 3.2. Calling methods Methods are functions grouped inside class (or interface) declarations, accepting pointer to class instance as first argument. Most usual technique to invoke method is using `:` operator, e.g. `window:show_all()`. This is of course identical with `window.show_all(window)`, as is convention in plain Lua. Method declaration itself is also available in the class and it is possible to invoke it without object notation, so previous example can be also rewritten as `Gtk.Window.show_all(window)`. Note that this way of invoking removes dynamic lookup of the method from the object instance type, so it might be marginally faster. However, in case that `window` is actually instance of some `GtkWindow` descendant, lets say `MyWindow`, which also defined `my_window_show_all()` method, there will be a difference: `window:show_all()` will invoke `my_window_show_all(window)`, while `Gtk.Window.show_all(window)` will of course invoke non-specialized `gtk_widget_show_all(window)`. #### 3.2.1. Static methods Static methods (i.e. functions which do not take class instance as first argument) are usually invoked using class namespace, e.g. `Gtk.Window.list_toplevels()`. Very common form of static methods are `new` constructors, e.g. `Gtk.Window.new()`. Note that in most cases, `new` constructors are provided only as convenience for C programmers, in lgi it might be preferable to use `window = Gtk.Window { type = Gtk.WindowType.TOPLEVEL }` instead of `window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)`. ### 3.3. Accessing properties Object properties are accessed simply by using `.` operator. Continuing previous example, we can write `window.title = window.title .. ' - new'`. Note that in GObject system, property and signal names can contain `-` character. Since this character is illegal in Lua identifiers, it is mapped to `_`, so `can-focus` window property is accessed as `window.can_focus`. ### 3.4. Signals Signals are exposed as `on_signalname` entities on the class instances. #### 3.4.1. Connecting signals Assigning Lua function connects that function to the signal. Signal routine gets object as first argument, followed by other arguments of the signal. Simple example: local window = Gtk.Window() window.on_destroy = function(w) assert(w == window) print("Destroyed", w) end Note that because of Lua's syntactic sugar for object access and function definition, it is possible to use signal connection even in following way: local window = Gtk.Window() function window:on_destroy() assert(self == window) print("Destroyed", self) end Reading signal entity provides temporary table which can be used for connecting signal with specification of the signal detail (see GObject documentation on signal detail explanation). An example of handler which is notified whenever window is activated or deactivated follows: local window = Gtk.Window() window.on_notify['is-active'] = function(self, pspec) assert(self == window) assert(pspec.name == 'is-active') print("Window is active:", self.is_active) end Both forms of signal connection connect handler before default signal handler. If connection after default signal handler is wanted (see `G_CONNECT_AFTER` documentation for details), the most generic connection call has to be used: `object.on_signalname:connect(target, detail, after)`. Previous example rewritten using this connection style follows: local window = Gtk.Window() local function notify_handler(self, pspec) assert(self == window) assert(pspec.name == 'is-active') print("Window is active:", self.is_active) end window.on_notify:connect(notify_handler, 'is-active', false) #### 3.4.2 Emitting signals Emitting existing signals is usually needed only when implementing subclasses of existing classes. Simplest method to emit a signal is to 'call' the signal on the class instance: local treemodel = treemodel:on_row_inserted(path, iter) ### 3.5. Dynamic typing of classes lgi assigns real class types to class instances dynamically, using runtime GObject introspection facilities. When new classes instance is passed from C code into Lua, lgi queries the real type of the object, finds the nearest type in the loaded repository and assigns this type to the Lua-side created proxy for the object. This means that there is no casting needed in lgi (and there is also no casting facility available). Hopefully everything can be explained in following example. Assume that `demo.ui` is GtkBuilder file containing definition of `GtkWindow` labeled `window1` and `GtkAction` called `action1` (among others). local builder = Gtk.Builder() builder:add_from_file('demo.ui') local window = builder:get_object('window1') -- Call Gtk.Window-specific method window:iconify() local action = builder:get_object('action1') -- Set Gtk.Action-specific property action.sensitive = false Although `Gtk.Builder.get_object()` method is marked as returning `GObject*`, lgi actually checks the real type of returned object and assigns proper type to it, so `builder:get_object('window1')` returns instance of `Gtk.Window` and `builder:get_object('action1')` returns instance of `Gtk.Action`. Another mechanism which allows complete lack of casting in lgi is automatic interface discovery. If some class implements some interface, the properties and methods of the interface are directly available on the class instance. ### 3.6. Accessing object's class instance GObject has the notion of object class. There are sometimes useful methods defined on objects class, which are accessible to lgi using object instance pseudo-property `_class`. For example, to list all properties registered for object's class, GObject library provides `g_object_class_list_properties()` function. Following sample lists all properties registered for the given object instance. function dump_props(obj) print("Dumping properties of ", obj) for _, pspec in pairs(obj._class:list_properties()) do print(pspec.name, pspec.value_type) end end Running `dump_props(Gtk.Window())` yields following output: Dumping props of lgi.obj 0xe5c070:Gtk.Window(GtkWindow) name gchararray parent GtkContainer width-request gint height-request gint visible gboolean sensitive gboolean ... (and so on) ### 3.7. Querying the type of the object instances To query whether given Lua value is actually an instance of specified class or subclass, class types define `is_type_of` method. This class-method takes one argument and checks, whether given argument as an instance of specified class (or implements specified interface, when called on interface instances). Following examples demonstrate usage of this construct: local window = Gtk.Window() print(Gtk.Window:is_type_of(window)) -- prints 'true' print(Gtk.Widget:is_type_of(window)) -- prints 'true' print(Gtk.Buildable:is_type_of(window)) -- prints 'true' print(Gtk.Action:is_type_of(window)) -- prints 'false' print(Gtk.Window:is_type_of('string')) -- prints 'false' print(Gtk.Window:is_type_of(nil)) -- prints 'false' There is also possibility to query the type-table from instantiated object, using `_type` property. -- Checks, whether 'unknown' conforms to the type of the 'template' -- object. function same_type(template, unknown) local type = template._type return type:is_type_of(unknown) end ### 3.8. Implementing subclasses It is possible to implement subclass of any existing class in pure Lua. The reason to do so is to implement virtual methods of parent class (and possibly one or more interfaces). In order to create subclass, lgi requires to create `package` first, which is basically namespace where the new classes will live. To create a package, use `lgi.package` function: -- Create MyApp package local MyApp = lgi.package 'MyApp' Once the package is created, it is possible to reference it from `lgi` as any other existing namespace: local Gtk = lgi.Gtk local MyApp = lgi.MyApp To create subclass, use package's method `class(name, parent[, ifacelist])`: MyApp:class('MyWidget', Gtk.Widget) MyApp:class('MyModel', GObject.Object, { Gtk.TreeModel }) After that, newly created class behaves exactly the same as classes picked up from GObjectIntrospection namespaces, like shown in following examples: local widget = MyApp.MyWidget() widget:show() Note that it is important to override virtual methods _before_ any instance of the derived class (see chapter about virtual methods below). ### 3.8.1. Overriding virtual methods To make subclass useful, it is needed to override some of its virtual methods. Existing virtual methods are prefixed with `do_`. In order to call inherited virtual methods, it is needed to use an explicit function reference. There is an automatic property called `priv` which is plain Lua table and allows subclass implementation to store some internal status. All these techniques are illustrated in following sample: function MyApp.MyWidget:do_show() if not self.priv.invisible then -- All three lines perform forwarding to inherited virtual: Gtk.Widget.do_show(self) -- or: MyApp.MyWidget._parent.do_show(self) -- or: self._type._parent.do_show(self) end end -- Convenience method for setting MyWidget 'invisible' function MyApp.MyWidget:set_invisible(invisible) self.priv.invisible = invisible end The important fact is that virtual method overrides are picked up only up to the first instantiation of the class or inheriting new subclass from it. After this point, virtual function overrides are ignored. ## 4. Structures and unions Structures and unions are supported in a very similar way to classes. They have only access to methods (in the same way as classes) and fields, which are very similar to the representation of properties on the classes. ### 4.1. Creating instances Structure instances are created by 'calling' structure definition, similar to creating new class: `local color = Gdk.RGBA()`. For simplest structures without constructor methods, the new structure is allocated and zero-initialized. It is also possible to pass table containing fields and values to which the fields should be initialized: `local blue = Gdk.RGBA { blue = 1, alpha = 1 }`. If the structure has defined any constructor named `new`, it is automatically mapped by lgi to the structure creation construct, so calling `local main_loop = GLib.MainLoop(nil, false)` is exactly equivalent with `local main_loop = GLib.MainLoop.new(nil, false)`, and `local color = Clutter.Color(0, 0, 0, 255)` is exactly equivalent with `local color = Clutter.Color.new(0, 0, 0, 255)`. ### 4.2. Calling methods and accessing fields. Structure methods are called in the same way as class methods: `struct:method()`, or `StructType.method()`. For example: local loop = GLib.MainLoop(nil, false) loop:run() -- Following line is equivalent GLib.MainLoop.run(loop) Fields are accessed using `.` operator on structure instance, for example local color = Gdk.RGBA { alpha = 1 } color.green = 0.5 print(color.red, color.green, color.alpha) -- Prints: 0 0.5 1 ## 5. Enums and bitflags, constants lgi primarily maps enumerations to strings containing uppercased nicks of enumeration constant names. Optionally, a direct enumeration value is also accepted. Similarly, bitflags are primarily handled as sets containing uppercased flag nicks, but also lists of these nicks or direct numeric value is accepted. When a numeric value cannot be mapped cleanly to the known set of bitflags, the remaining number is stored in the first array slot of the returned set. Note that this behavior changed in lgi 0.4; up to that alpha release, lgi handled enums and bitmaps exclusively as numbers only. The change is compatible in Lua->C direction, where numbers still can be used, but incompatible in C->Lua direction, where lgi used to return numbers, while now it returns either string with enum value or table with flags. ### 5.1. Accessing numeric values In order to retrieve real enum values from symbolic names, enum and bitflags are loaded into repository as tables mapping symbolic names to numeric constants. Fro example, dumping `Gtk.WindowType` enum yields following output: > dump(Gtk.WindowType) ["table: 0xef9bc0"] = { -- table: 0xef9bc0 TOPLEVEL = 0; POPUP = 1; }; so constants can be referenced using `Gtk.WindowType.TOPLEVEL` construct, or directly using string `'TOPLEVEL'` when a `Gtk.WindowType` is expected. ### 5.2. Backward mapping, getting names from numeric values There is another facility in lgi, which allows backward mapping of numeric constants to symbolic names. Indexing enum table with number actually provides symbolic name to which the specified constant maps: > print(Gtk.WindowType[0]) TOPLEVEL > print(Gtk.WindowType[2]) nil Indexing bitflags table with number provides table containing list of all symbolic names which make up the requested value: > dump(Gtk.RegionFlags) ["table: 0xe5dd10"] = { -- table: 0xe5dd10 ODD = 2; EVEN = 1; SORTED = 32; FIRST = 4; LAST = 8; > dump(Gtk.RegionFlags[34]) ["table: 0xedbba0"] = { -- table: 0xedbba0 SORTED = 32; ODD = 2; }; This way, it is possible to check for presence of specified flag very easily: if Gtk.RegionFlags[flags].ODD then -- Code handling region-odd case endif If the value cannot be cleanly decomposed to known flags, remaining bits are accumulated into number stored at index 1: > dump(Gtk.RegionFlags[51]) ["table: 0x242fb20"] = { -- table: 0x242fb20 EVEN = 1; SORTED = 32; [1] = 16; ODD = 2; }; To construct numeric value which can be passed to a function expecting an enum, it is possible to simply add requested flags. However, there is a danger if some definition contains multiple flags , in which case numeric adding produces incorrect results. Therefore, it is possible to use bitflags pseudoconstructor', which accepts table containing requested flags: > =Gtk.RegionFlags { 'FIRST', 'SORTED' } 36 > =Gtk.RegionFlags { Gtk.RegionFlags.ODD, 16, 'EVEN' } 19 ## 6. Threading and synchronization Lua platform does not allow running real concurrent threads in single Lua state. This rules out any usage of GLib's threading API. However, wrapped libraries can be using threads, and this can lead to situations that callbacks or signals can be invoked from different threads. To avoid corruption which would result from running multiple threads in a single Lua state, lgi implements one internal lock (mutex) which protects access to Lua state. lgi automatically locks (i.e. waits on) this lock when performing C->Lua transition (invoking Lua callback or returning from C call) and unlocks it on Lua->C transition (returning from Lua callback or invoking C call). In a typical GLib-based application, most of the runtime is spent inside mainloop. During this time, lgi lock is unlocked and mainloop can invoke Lua callbacks and signals as needed. This means that lgi-based application does not have to worry about synchronization at all. The only situation which needs intervention is when mainloop is not used or a different form of mainloop is used (e.g. Copas scheduler, Qt UI etc). In this case, lgi lock is locked almost all the time and callbacks and signals are blocked and cannot be delivered. To cope with this situation, a `lgi.yield()` call exists. This call temporarily unlocks the lgi lock, letting other threads to deliver waiting callbacks, and before returning the lock is closed back. This allows code which runs foreign, non-GLib style of mainloop to stick `lgi.yield()` calls to some repeatedly invoked place and thus allowing delivery of callbacks from other threads. ## 7. Logging GLib provides generic logging facility using `g_message` and similar C macros. These utilities are not directly usable in Lua, so lgi provides layer which allows logging messages using GLib logging facilities and controlling behavior of logging methods. All logging is controlled by `lgi.log` table. To allow logging in lgi-enabled code, `lgi.log.domain(name)` method exists. This method returns table containing methods `message`, `warning`, `critical`, `error` and `debug` methods, which take format string optionally followed by inserts and logs specified string. An example of typical usage follows: local lgi = require 'lgi' local log = lgi.log.domain('myapp') -- This is equivalent of C 'g_message("A message %d", 1)' log.message("A message %d", 1) -- This is equivalent to C 'g_warning("Not found")' log.warning("Not found") Note that format string is formatted using Lua's `string.format()`, so the rules for Lua formatting strings apply here. ## 8. Interoperability with native code There might be some scenarios where it is important to either export objects or records created in Lua into C code or vice versa. lgi allows transfers using Lua `lightuserdata` type. To get native pointer to the lgi object, use `_native` attribute of the object. To create lgi object from external pointer, it is possible to pass lightuserdata with object pointer to type constructor. Following example illustrates both techniques: -- Create Lua-side window object. local window = Gtk.Window { title = 'Hello' } -- Get native pointer to this object. local window_ptr = window._native // window_ptr can be now passed to C code, which can use it. GtkWindow *window = lua_touserdata (L, x); char *title; g_object_get (window, "title", &title); g_assert (g_str_equal (title, "Hello")); g_free (title); // Create object on the C side and pass it to Lua GtkButton *button = gtk_button_new_with_label ("Foreign"); lua_pushlightuserdata (L, button); lua_call (L, ...); -- Retrieve button on the Lua side. assert(type(button) == 'userdata') window:add(Gtk.Button(button)) Note that while the example demonstrates objects, the same mechanism works also for structures and unions. ## 9. GObject basic constructs Although GObject library is already covered by gobject-introspection, most of the elements in it are basic object system building blocks and either need or greatly benefit from special handling by lgi. ### 9.1. GObject.Type Contrary to C `GType` representation (which is unsigned number), lgi represents GType by its name, as a string. GType-related constants and methods useful for handling GType are present in `GObject.Type` namespace. Fundamental GType names are imported as constants into GObject.Type namespace, so that it is possible to use for example `GObject.Type.INT` where `G_TYPE_INT` would be used in C code. Following constants are available: > `NONE`, `INTERFACE`, `CHAR`, `UCHAR`, `BOOLEAN`, > `INT`, `UINT`, `LONG`, `ULONG`, `INT64`, `UINT64`, > `ENUM`, `FLAGS`, `FLOAT`, `DOUBLE`, `STRING`, > `POINTER`, `BOXED`, `PARAM`, `OBJECT`, `VARIANT` Moreover, functions operating on `GType` are also present in `GObject.Type` namespace: > `parent`, `depth`, `next_base`, `is_a`, `children`, `interfaces`, > `query`, `fundamental_next`, `fundamental` When transferring `GType` value from Lua to C (e.g. calling function which accepts argument of `GType`), it is possible to use either string with type name, number representing numeric `GType` value, or any loaded component which has its type assigned. Some examples of `GType` usage follow: lgi = require 'lgi' GObject = lgi.GObject Gtk = lgi.Gtk print(GObject.Type.NONE) print(GObject.Type.name(GObject.Type.NONE)) -- prints "void" in both cases print(GObject.Type.name(Gtk.Window)) -- prints "GtkWindow" print(GObject.Type.is_a(Gtk.Window, GObject.Type.OBJECT)) -- prints "true" print(GObject.Type.parent(Gtk.Window)) -- prints "GtkBin" ### 9.2. GObject.Value lgi does not implement any automatic `GValue` boxing or unboxing, because this would involve guessing `GType` from Lua value, which is generally unsafe. Instead, an easy to use and convenient wrappers for accessing `GValue` type and contents are provided. #### 9.2.1. Creation To create new `GObject.Value` instances, use similar method as for creating new structures or classes, i.e. 'call' `GObject.Value` type. The call has two optional arguments, specifying `GType` of newly created `GValue` and optionally also the contents of the value. A few examples for creating new values follow: local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local empty = GObject.Value() local answer = GObject.Value(GObject.Type.INT, 42) local null_window = GObject.Value(Gtk.Window) local window = GObject.Value(Gtk.Window, Gtk.Window()) #### 9.2.2. Boxing and unboxing GObject.Value instances `GObject.Value` adds two new virtual properties, called `gtype` and `value`. `gtype` contains actual type of the value, while `value` provides access to the contents of the value. Both properties are read/write. Reading of them queries current `GObject.Value` state, i.e. reading `value` performs actual `GValue` unboxing. Writing `value` performs value boxing, i.e. the source Lua item is attempted to be stored into the `GObject.Value`. Writing `gtype` attempts to change the type of the value, and in case that value already has a contents, it also converts contents to the new type (using `g_value_transform()`). Examples here continue using the values created in previous section example: assert(empty.gtype == nil) assert(empty.value == nil) assert(answer.gtype == GObject.Type.INT) assert(answer.value == 42) assert(null_window.gtype == 'GtkWindow') assert(null_window.value == nil) empty.gtype = answer.gtype empty.value = 1 assert(empty.gtype == GObject.Type.INT) assert(empty.value == 1) answer.gtype = GObject.Type.STRING) assert(answer.value == '42') Although `GObject.Value` provides most of the GValue documented methods (e.g. `g_value_get_string()` is accessible as `GObject.Value.get_string()` and getting string contents of the value instance can be written as `value:get_string()`), `value` and `gtype` abstract properties are recommended to be used instead. ### 9.3. GObject.Closure Similar to GObject.Value, no automatic GClosure boxing is implemented. To create a new instance of `GClosure`, 'call' closure type and provide Lua function as an argument: closure = GObject.Closure(func) When the closure is emitted, a Lua function is called, getting `GObject.Value` as arguments and expecting to return `GObject.Value` instance. lua-lgi-0.7.2/docs/overview.md000066400000000000000000000105661221440706400162020ustar00rootroot00000000000000# LGI Overview LGI is Lua binding to Gnome platform. It is implemented as dynamic binding using gobject-introspection. This means that all libraries with support for gobject-introspection can be used by LGI without any need to compile/install anything, assuming that proper .typelib file is installed and available. ## Installation ### Dependencies LGI depends on `gobject-introspection >= 1.30` package. To build, gobject-introspection development package must also be installed. Note that required gobject-introspection version is unfortunately rather new, currently mostly available only in unreleased-yet versions of major distributions (part of GNOME-3.2, e.g. Fedora 16). There is planned work to make LGI mostly work also with older gobject-introspection versions, which are part of GNOME-3.0. Pre-3.0 versions are not planned to be supported at all. In order to be able to use assorted gobject-based libraries through LGI, these libraries must have properly installed `.typelib` files. Most, if not all distributions already do this properly. ### Supported platforms LGI is currently tested on Linux (all sane Linux distributions should work fine) and Cygwin. There is no principal obstacle for supporting other platforms, as long as gobject-introspection library (and of course Lua) is ported and working there. ### Installing via LuaRocks The preferred way to install LGI is using luarocks. As of writing this document, LGI is not yet available on public luarocks server, so plain `luarocks install lgi` does not work yet, although it will be preferred way to install LGI in the future. Currently, LGI source must be downloaded, unpacked and installed using `luarocks make`. ### Installing using Makefile Another way to install LGI is using makefiles: make sudo make install [PREFIX=prefix-path] [DESTDIR=destir-path] Default `PREFIX` is `/usr/local` and default `DESTDIR` is empty. ## Quick overview All LGI functionality is available in Lua module lgi, which is loaded by using Lua `require` construct: local lgi = require 'lgi' All gobject-introspection accessible modules are now accessible in lgi table: local Gtk = lgi.Gtk local Gio = lgi.Gio local GLib = lgi.GLib To create instance of the class, simply 'call' the class in the namespace: local window = Gtk.Window() To access object properties and call methods on the object instances, use normal Lua object access notation: window.title = 'I am a window' window:show_all() window.title = window.title .. ' made by Lgi' Note that properties can have `-` (dash) character in them. It is illegal in Lua, so it is translated to `_` (underscore). window.has_resize_grip = true It is also possible to assign properties during object construction: local window = Gtk.Window { title = 'I am a window made by Lgi', has_resize_grip = true } Note that structures and unions are handled similarly to classes, but structure fields are accessed instead of properties. To connect signal to object instance, assign function to be run to `on_signalname` object slot: window.on_destroy = function(object) print('destroying', object) end Note that Lua has nice syntactic sugar for objects, so previous construction can also be written like this: function window:on_destroy() print('destroying', self) end Note that potential dashes in signal names are also translated to underscores to cope well with Lua identifier rules. Enumerations and bitflags are grouped in the enumeration name table, and real names are enumeration nicks uppercased. For example, `GTK_WINDOW_TOPLEVEL` identifier is accessible as `Gtk.WindowType.TOPLEVEL`. There is no need to handle any kind of memory management; LGI handles all reference counting internally in cooperation with Lua's garbage collector. For APIs which use callbacks, provide Lua function which will be called when the callback is invoked. It is also possible to pass coroutine instance as callback argument, in this case, coroutine is resumed and returning `coroutine.yield()` returns all arguments passed to the callback. The callback returns when coroutine yields again or finishes. Arguments passed to `coroutine.yield()` call or exit status of the coroutine are then used as return value from the callback. See examples in `samples` source directory to dive deeper into the LGI features. lua-lgi-0.7.2/docs/reference.md000066400000000000000000000060311221440706400162620ustar00rootroot00000000000000# LGI Core Reference ## Core Core LGI functionality is accessible through `lgi` module, loaded by `require 'lgi'` command. LGI does not install itself into global namespace, caller has to use the return value from `require` call. - `lgi.'module'` - `module` string with module name, e.g.'Gtk' or 'WebKit'. Loads requested module of the latest version found into the repository. - `lgi.require(module, version)` - `module` string with module name, e.g. 'Gtk' or 'WebKit'. - `version` string with exact required version of the module Loads requested module with specified version into the repository. - `lgi.log.domain(name)` - `name` is string denoting logging area name, usually identifying the application or the library - `return` table containing - `message` - `warning` - `critical` - `error` - `debug` methods for logging messages. These methods accept format string and inserts, which are formatted according to Lua's `string.format` conventions. - `lgi.yield()` when called, unlocks LGI state lock, for a while, thus allowing potentially blocked callbacks or signals to enter the Lua state. When using LGI with GLib's MainLoop, this call is not needed at all. ## GObject basic constructs ### GObject.Type - `NONE`, `INTERFACE`, `CHAR`, `UCHAR`, `BOOLEAN`, `INT`, `UINT`, `LONG`, `ULONG`, `INT64`, `UINT64`, `ENUM`, `FLAGS`, `FLOAT`, `DOUBLE`, `STRING`, `POINTER`, `BOXED`, `PARAM`, `OBJECT`, `VARIANT` Constants containing type names of fundamental GObject types. - `parent`, `depth`, `next_base`, `is_a`, `children`, `interfaces`, `query`, `fundamental_next`, `fundamental` Functions for manipulating and querying `GType`. THey are direct mappings of `g_type_xxx()` APIs, e.g. `GObject.Type.parent()` behaves in the same way as `g_type_parent()` in C. ### GObject.Value - `GObject.Value([gtype [, val]])` - `gtype` type of the vlue to create, if not specified, defaults to `GObject.Type.NONE`. - `val` Lua value to initialize GValue with. Creates new GObject.Value of specified type, optionally assigns Lua value to it. For example, `local val = GObject.Value(GObject.Type.INT, 42)` creates GValue of type `G_TYPE_INT` and initializes it to value `42`. - `GObject.Value.gtype` - reading yields the gtype of the value - writing changes the type of the value. Note that if GValue is already initialized with some value, a `g_value_transform` is called to attempt to convert value to target type. - `GObject.Value.value` - reading retrieves Lua-native contents of the referenced Value (i.e. GValue unboxing is performed). - writing stores Lua-native contents to the Value (boxing is performed). ### GObject.Closure - `GObject.Glosure(func)` - `target` is Lua function or anything Lua-callable. Creates new GClosure instance wrapping given Lua callable. When the closure is emitted, `target` function is invoked, getting GObject.Value instances as arguments, and expecting single GObject.Value to be returned. lua-lgi-0.7.2/docs/variant.md000066400000000000000000000136721221440706400160010ustar00rootroot00000000000000# LGI Variant support LGI provides extended overrides for supporting GLib's GVariant type. it supports folloing operations with variants: ## Creation Variants should be created using GLib.Variant(type, value) constructor. Type is either GLib.VariantType or just plain string describing requested type of the variant. Following types are supported: - `b`, `y`, `n`, `q`, `i`, `u`, `q`, `t`, `s`, `d`, `o`, `g` are basic types, see either GVariant documentation or DBus specification for their meaning. `value` argument is expected to contain appropriate string or number for the basic type. - `v` is variant type, `value` should be another GLib.Variant instance. - `m`type is 'maybe' type, `value` should be either `nil` or value acceptable for target type. - `a`type is array of values of specified type, `value` is expected to contain Lua table (array) with values for the array. If the array contains `nil` elements inside, it must contain also `n` field with the real length of the array. - `(typelist)` is tuple of types, `value` is expected to contain Lua table (array) with values for the tuple members. - `{key-value-pair}` is dictionary entry, `value` is expected to contain Lua table (array) with 2 values (key and value) for the entry. There are two convenience exceptions from above rules: - when array of dictionary entries is met (i.e. dictionary), `value` is expected to contain Lua table with keys and values mapping to dictionary keys and values - when array of bytes is met, a bytestring is expected in the form of Lua string, not array of byte numbers. Some examples creating valid variants follow: GLib = require('lgi').Glib local v1 = GLib.Variant('s', 'Hello') local v2 = GLib.Variant('d', 3.14) local v3 = GLib.Variant('ms', nil) local v4 = GLib.Variant('v', v3) local v5 = GLib.Variant('as', { 'Hello', 'world' }) local v6 = GLib.Variant('ami', { 1, nil, 2, n = 3 }) local v7 = GLib.Variant('(is)', { 100, 'title' }) local v8 = GLib.Variant('a{sd}', { pi = 3.14, one = 1 }) local v9 = GLib.Variant('aay', { 'bytetring1', 'bytestring2' }) ## Data access LGI implements following special properties for accessing data stored inside variants - `type` contains read-only string describing type of the variant - `value` unpacks value of the variant. Simple scalar types are unpacked into their corresponding Lua variants, tuples and dictionary entries are unpacked into Lua tables (arrays), child varaints are expanded for `v`-typed variants. Dictionaries return proxy table which can be indexed by dictionary keys to retrieve dictionary values. Generic arrays are __not__ automatically expanded, the source variants are returned are returned instead. - `# operator` Length operator is overriden for GLib.Variants, returning number of child elements. Non-compound variants always return 0, maybe-s return 0 or 1, arrays, tuples and dictionary entries return number of children subvariants. - `[number] operator` Compound variants can be indexed by number, returning n-th subvariant (array entry, n-th field of tuple etc). - `pairs() and ipairs()` Variants support these methods, which behave as standard Lua enumerators. Examples of extracting values from variants created above: assert(v1.type == 's' and v1.value == 'Hello') assert(v2.value == 3.14) assert(v3.value == nil and #v3 = 0) assert(v4.value == nil and #v4 = 1) assert(v5.value == v5 and #v5 == 2 and v5[2] == 'world') assert(#v6 == 3 and v6[2] == nil) assert(v7.value[1] == 100 and v7[1] == 100 and #v7 == 2) assert(v8.value.pi == 3.14 and v8.value['one'] == 1 and #v8 == 2) assert(v9[1] == 'bytestring1') for k, v in v8:pairs() do print(k, v) end ## Serialization To serialize variant into bytestream form, use `data` property, which return Lua string containing serialized variant. Deserialization is done by `Variant.new_from_data` constructor, which is similar to `g_variant_new_from_data`, but it does _not_ accept `destroy_notify` argument. See following serialization example: local v = GLib.Variant('s', 'Hello') local serialized = v.data assert(type(data) == 'string') local newv = GLib.Variant.new_from_data(serialized, true) assert(newv.type == 's' and newv.value == 'Hello') ## Other operations LGI also contains many of the original `g_variant_` APIs, but many of them are not useful because their functionality is covered in more Lua-native way by operations described above. However, there there are still some useful calls, which are enumerated here. All of them can be called using object notation on variant instances, e.g. `local vt = variant:get_type()` See GLib documentation for their closer description. - `print(with_types)` returns textual format of the variant. Note that LGI does not contain opposite operation, i.e. g_variant_parse is not implemented yet - `is_of_type(type)` checks whether variant instance conforms to specified type - `compare(other_variant)` and `equal(other_variant)` allow comparison of variant instances - `byteswap()`, `is_normal_form()` and `get_normal_form()` for affecting the binary representation of variants. - `get_type()` method returns `VariantType` instance representing type of the variant. Seldom useful, `type` property returning type as string is usually better choice. - `GLib.VariantBuilder` although builder is supported, it is seldom useful, because creation of variants using constructors above is usually preferred. The exception may be creating of very large arrays, where creating source Lua table with source array might waste too much memory. Building such array piece-by-piece using builder instance is preferred. Note that VariantBuilder's `end()` method clashes with lua `end` keyword, so it is renamed to `_end()`. - `VARIANT_TYPE_` constants are accessible as `GLib.VariantType.XXX`, e.g. `GLib.VariantType.STRING`. Although there should not be many cases where these constants are needed. lua-lgi-0.7.2/lgi.lua000066400000000000000000000013641221440706400143340ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Lua-side core. -- -- Copyright (c) 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ -- This is simple forwarder to real package 'lgi/init.lua'. Normally, -- lgi/init.lua could suffice, but this file is needed for two -- reasons: -- 1) Running uninstalled, because Lua unfortunately does not contain -- './?/init.lua' component in its package.path -- 2) Upgrading older installations (<0.2), where lgi.lua was the only -- installed file, it would take precedence over 'lgi/init.lua'. return require 'lgi.init' lua-lgi-0.7.2/lgi/000077500000000000000000000000001221440706400136255ustar00rootroot00000000000000lua-lgi-0.7.2/lgi/.gitignore000066400000000000000000000000141221440706400156100ustar00rootroot00000000000000version.lua lua-lgi-0.7.2/lgi/Makefile000066400000000000000000000041321221440706400152650ustar00rootroot00000000000000# # Makefile for compiling lgi core module in standard-Lua variant # # Author: Pavel Holejsovsky # License: MIT # PREFIX = /usr/local LUA_VERSION=5.1 LUA_LIBDIR = $(PREFIX)/lib/lua/$(LUA_VERSION) LUA_SHAREDIR = $(PREFIX)/share/lua/$(LUA_VERSION) GINAME = gobject-introspection-1.0 PKGS = $(GINAME) gmodule-2.0 libffi VERSION_FILE = version.lua ifneq ($(filter CYGWIN%, $(shell uname -s)),) CORE = corelgilua51.dll LIBFLAG = -shared LIBS += -llua else ifeq ($(shell uname -s),Darwin) CORE = corelgilua51.so LIBFLAG = -bundle -undefined dynamic_lookup CCSHARED = -fno-common else CORE = corelgilua51.so LIBFLAG = -shared CCSHARED = -fPIC endif endif OBJS = buffer.o callable.o core.o gi.o marshal.o object.o record.o ifndef CFLAGS ifndef COPTFLAGS CFLAGS = -Wall -Wextra -O2 -g endif endif ALL_CFLAGS = $(CCSHARED) $(COPTFLAGS) $(LUA_CFLAGS) $(shell pkg-config --cflags $(PKGS)) $(CFLAGS) LIBS += $(shell pkg-config --libs $(PKGS)) ALL_LDFLAGS = $(LIBFLAG) $(LDFLAGS) DEPCHECK = .depcheck # Precondition check $(DEPCHECK) : Makefile pkg-config --exists '$(GINAME) >= 0.10.8' --print-errors touch $@ .PHONY : all clean install all : $(CORE) $(VERSION_FILE) clean : rm -f $(CORE) $(OBJS) %.o : %.c $(CC) $(ALL_CFLAGS) -c -o $@ $< $(CORE) : $(OBJS) $(CC) $(ALL_LDFLAGS) -o $@ $(OBJS) $(LIBS) $(VERSION_FILE) : Makefile ../Makefile echo "return '$(VERSION)'" > $@ buffer.o : buffer.c lgi.h $(DEPCHECK) callable.o : callable.c lgi.h $(DEPCHECK) core.o : core.c lgi.h $(DEPCHECK) gi.o : gi.c lgi.h $(DEPCHECK) marshal.o : marshal.c lgi.h $(DEPCHECK) object.o : object.c lgi.h $(DEPCHECK) record.o : record.c lgi.h $(DEPCHECK) OVERRIDES = $(wildcard override/*.lua) CORESOURCES = $(wildcard *.lua) install : $(CORE) $(VERSION_FILE) mkdir -p $(DESTDIR)$(LUA_LIBDIR)/lgi cp $(CORE) $(DESTDIR)$(LUA_LIBDIR)/lgi mkdir -p $(DESTDIR)$(LUA_SHAREDIR) cp ../lgi.lua $(DESTDIR)$(LUA_SHAREDIR) mkdir -p $(DESTDIR)$(LUA_SHAREDIR)/lgi cp $(CORESOURCES) $(VERSION_FILE) $(DESTDIR)$(LUA_SHAREDIR)/lgi mkdir -p $(DESTDIR)$(LUA_SHAREDIR)/lgi/override cp $(OVERRIDES) $(DESTDIR)$(LUA_SHAREDIR)/lgi/override lua-lgi-0.7.2/lgi/buffer.c000066400000000000000000000044221221440706400152440ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010, 2011 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Implementation of writable buffer object. */ #include #include "lgi.h" static int buffer_len (lua_State *L) { luaL_checkudata (L, 1, LGI_BYTES_BUFFER); lua_pushnumber (L, lua_objlen (L, 1)); return 1; } static int buffer_tostring (lua_State *L) { gpointer data = luaL_checkudata (L, 1, LGI_BYTES_BUFFER); lua_pushlstring (L, data, lua_objlen (L, 1)); return 1; } static int buffer_index (lua_State *L) { int index; unsigned char *buffer = luaL_checkudata (L, 1, LGI_BYTES_BUFFER); index = lua_tonumber (L, 2); if (index > 0 && (size_t) index <= lua_objlen (L, 1)) lua_pushnumber (L, buffer[index - 1]); else { luaL_argcheck (L, !lua_isnoneornil (L, 2), 2, "nil index"); lua_pushnil (L); } return 1; } static int buffer_newindex (lua_State *L) { int index; unsigned char *buffer = luaL_checkudata (L, 1, LGI_BYTES_BUFFER); index = luaL_checkint (L, 2); luaL_argcheck (L, index > 0 && (size_t) index <= lua_objlen (L, 1), 2, "bad index"); buffer[index - 1] = luaL_checkint (L, 3) & 0xff; return 0; } static const luaL_Reg buffer_mt_reg[] = { { "__len", buffer_len }, { "__tostring", buffer_tostring }, { "__index", buffer_index }, { "__newindex", buffer_newindex }, { NULL, NULL } }; static int buffer_new (lua_State *L) { size_t size; gpointer *buffer; const char *source = NULL; if (lua_type (L, 1) == LUA_TSTRING) source = lua_tolstring (L, 1, &size); else size = luaL_checknumber (L, 1); buffer = lua_newuserdata (L, size); if (source) memcpy (buffer, source, size); else memset (buffer, 0, size); luaL_getmetatable (L, LGI_BYTES_BUFFER); lua_setmetatable (L, -2); return 1; } static const luaL_Reg buffer_reg[] = { { "new", buffer_new }, { NULL, NULL } }; void lgi_buffer_init (lua_State *L) { /* Register metatables. */ luaL_newmetatable (L, LGI_BYTES_BUFFER); luaL_register (L, NULL, buffer_mt_reg); lua_pop (L, 1); /* Register global API. */ lua_newtable (L); luaL_register (L, NULL, buffer_reg); lua_setfield (L, -2, "bytes"); } lua-lgi-0.7.2/lgi/callable.c000066400000000000000000001160601221440706400155340ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010, 2011, 2012 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * This code deals with calling from Lua to C and vice versa, using * gobject-introspection information and libffi machinery. */ #include "lgi.h" #include #include /* Kinds or Param structure variation. */ typedef enum _ParamKind { /* Ordinary typeinfo (ti)-based parameter. */ PARAM_KIND_TI = 0, /* Foreign record. ti is unused. */ PARAM_KIND_RECORD, /* Foreign enum/flags. ti contains underlying numeric type. */ PARAM_KIND_ENUM } ParamKind; /* Represents single parameter in callable description. */ typedef struct _Param { GITypeInfo *ti; GIArgInfo ai; /* Direction of the argument. */ guint dir : 2; /* Ownership passing rule for output parameters. */ guint transfer : 2; /* Flag indicating whether this parameter is represented by Lua input and/or returned value. Not represented are e.g. callback's user_data, array sizes etc. */ guint internal : 1; /* Flag indicating that this is internal user_data value for the callback. This parameter is supplied automatically, not explicitely from Lua. */ guint internal_user_data : 1; /* Set to nonzero if this argument is user_data for closure which is marked as (scope call). */ guint call_scoped_user_data : 1; /* Number of closures bound to this argument. 0 if this is not user_data for closure. */ guint n_closures : 4; /* Type of the argument, one of ParamKind values. */ guint kind : 2; /* Index into env table attached to the callable, contains repotype table for specified argument. */ guint repotype_index : 4; } Param; /* Structure representing userdata allocated for any callable, i.e. function, method, signal, vtable, callback... */ typedef struct _Callable { /* Stored callable info. */ GICallableInfo *info; /* Address of the function. */ gpointer address; /* Optional, associated 'user_data' context field. */ gpointer user_data; /* Flags with function characteristics. */ guint has_self : 1; guint throws : 1; guint nargs : 6; guint ignore_retval : 1; guint is_closure_marshal : 1; /* Initialized FFI CIF structure. */ ffi_cif cif; /* Param return value and pointer to nargs Param instances. */ Param retval; Param *params; /* ffi_type* array here, contains ffi_type[nargs + 2] entries. */ /* params points here, contains Param[nargs] entries. */ } Callable; /* Address is lightuserdata of Callable metatable in Lua registry. */ static int callable_mt; /* Structure containing basic callback information. */ typedef struct _Callback { /* Thread which created callback and Lua-reference to it (so that it is not GCed). */ lua_State *L; int thread_ref; /* State lock, to be passed to lgi_state_enter() when callback is invoked. */ gpointer state_lock; } Callback; typedef struct _FfiClosureBlock FfiClosureBlock; /* Single element in FFI callbacks block. */ typedef struct _FfiClosure { /* Libffi closure object. */ ffi_closure ffi_closure; /* Pointer to the block to which this closure belongs. */ FfiClosureBlock *block; union { struct { /* Lua reference to associated Callable. */ int callable_ref; /* Callable's target to be invoked (either function, userdata/table with __call metafunction or coroutine (which is resumed instead of called). */ int target_ref; }; /* Closure's entry point, stored only temporarily until closure is created. */ gpointer call_addr; }; /* Flag indicating whether closure should auto-destroy itself after it is called. */ guint autodestroy : 1; /* Flag indicating whether the closure was already created. */ guint created : 1; } FfiClosure; /* Structure containing closure block. This is user_data block for C-side closure arguments. */ struct _FfiClosureBlock { /* 1st closure. */ FfiClosure ffi_closure; /* Target to be invoked. */ Callback callback; /* Number of other closures in the block, excluding the forst one contained already in this header. */ int closures_count; /* Variable-length array of pointers to other closures. Unfortunately libffi does not allow to allocate contiguous block containing more closures, otherwise this array would simply contain FfiClosure instances instead of pointers to dynamically allocated ones. */ FfiClosure *ffi_closures[1]; }; /* lightuserdata key to callable cache table. */ static int callable_cache; /* Gets ffi_type for given tag, returns NULL if it cannot be handled. */ static ffi_type * get_simple_ffi_type (GITypeTag tag) { ffi_type *ffi; switch (tag) { #define HANDLE_TYPE(tag, ffitype) \ case GI_TYPE_TAG_ ## tag: \ ffi = &ffi_type_ ## ffitype; \ break HANDLE_TYPE(VOID, void); HANDLE_TYPE(BOOLEAN, uint); HANDLE_TYPE(INT8, sint8); HANDLE_TYPE(UINT8, uint8); HANDLE_TYPE(INT16, sint16); HANDLE_TYPE(UINT16, uint16); HANDLE_TYPE(INT32, sint32); HANDLE_TYPE(UINT32, uint32); HANDLE_TYPE(INT64, sint64); HANDLE_TYPE(UINT64, uint64); HANDLE_TYPE(FLOAT, float); HANDLE_TYPE(DOUBLE, double); #if GLIB_SIZEOF_SIZE_T == 4 HANDLE_TYPE(GTYPE, uint32); #else HANDLE_TYPE(GTYPE, uint64); #endif #undef HANDLE_TYPE default: ffi = NULL; } return ffi; } /* Gets ffi_type for given Param instance. */ static ffi_type * get_ffi_type(Param *param) { switch (param->kind) { case PARAM_KIND_RECORD: return &ffi_type_pointer; case PARAM_KIND_ENUM: return param->ti ? get_simple_ffi_type (g_type_info_get_tag (param->ti)) : &ffi_type_sint; case PARAM_KIND_TI: break; } /* In case of inout or out parameters, the type is always pointer. */ GITypeTag tag = g_type_info_get_tag (param->ti); ffi_type* ffi = g_type_info_is_pointer(param->ti) ? &ffi_type_pointer : get_simple_ffi_type (tag); if (ffi == NULL) { /* Something more complex. */ if (tag == GI_TYPE_TAG_INTERFACE) { GIBaseInfo *ii = g_type_info_get_interface (param->ti); switch (g_base_info_get_type (ii)) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: ffi = get_simple_ffi_type (g_enum_info_get_storage_type (ii)); break; default: break; } g_base_info_unref (ii); } } return ffi != NULL ? ffi : &ffi_type_pointer; } /* If typeinfo specifies array with length parameter, mark it in specified callable as an internal one. */ static void callable_mark_array_length (Callable *callable, GITypeInfo *ti) { gint arg; if (g_type_info_get_tag (ti) == GI_TYPE_TAG_ARRAY && g_type_info_get_array_type (ti) == GI_ARRAY_TYPE_C) { arg = g_type_info_get_array_length (ti); if (arg >= 0 && arg < callable->nargs) callable->params[arg].internal = TRUE; } } static void callable_param_init (Param *param) { param->ti = NULL; param->internal = FALSE; param->internal_user_data = FALSE; param->n_closures = 0; param->call_scoped_user_data = FALSE; param->kind = PARAM_KIND_TI; param->repotype_index = 0; } static Callable * callable_allocate (lua_State *L, int nargs, ffi_type ***ffi_args) { int argi; /* Create userdata structure. */ luaL_checkstack (L, 2, NULL); Callable *callable = lua_newuserdata (L, sizeof (Callable) + sizeof (ffi_type) * (nargs + 2) + sizeof (Param) * nargs); lua_pushlightuserdata (L, &callable_mt); lua_rawget (L, LUA_REGISTRYINDEX); lua_setmetatable (L, -2); /* Inititialize callable contents. */ *ffi_args = (ffi_type **) &callable[1]; callable->params = (Param *) &(*ffi_args)[nargs + 2]; callable->nargs = nargs; callable->user_data = NULL; callable->info = NULL; callable->has_self = 0; callable->throws = 0; callable->ignore_retval = 0; callable->is_closure_marshal = 0; /* Clear all 'internal' flags inside callable parameters, parameters are then marked as internal during processing of their parents. */ callable_param_init (&callable->retval); for (argi = 0; argi < nargs; argi++) callable_param_init (&callable->params[argi]); return callable; } int lgi_callable_create (lua_State *L, GICallableInfo *info, gpointer addr) { Callable *callable; Param *param; ffi_type **ffi_arg, **ffi_args; ffi_type *ffi_retval; gint nargs, argi, arg; /* Allocate Callable userdata. */ nargs = g_callable_info_get_n_args (info); callable = callable_allocate (L, nargs, &ffi_args); callable->info = g_base_info_ref (info); callable->address = addr; if (GI_IS_FUNCTION_INFO (info)) { /* Get FunctionInfo flags. */ const gchar* symbol; gint flags = g_function_info_get_flags (info); if ((flags & GI_FUNCTION_IS_METHOD) != 0 && (flags & GI_FUNCTION_IS_CONSTRUCTOR) == 0) callable->has_self = 1; if ((flags & GI_FUNCTION_THROWS) != 0) callable->throws = 1; /* Resolve symbol (function address). */ symbol = g_function_info_get_symbol (info); if (!g_typelib_symbol (g_base_info_get_typelib (info), symbol, &callable->address)) /* Fail with the error message. */ return luaL_error (L, "could not locate %s(%s): %s", lua_tostring (L, -3), symbol, g_module_error ()); } else if (GI_IS_SIGNAL_INFO (info)) /* Signals always have 'self', i.e. the object on which they are emitted. */ callable->has_self = 1; /* Process return value. */ callable->retval.ti = g_callable_info_get_return_type (callable->info); callable->retval.dir = GI_DIRECTION_OUT; callable->retval.transfer = g_callable_info_get_caller_owns (callable->info); callable->retval.internal = FALSE; callable->retval.repotype_index = 0; ffi_retval = get_ffi_type (&callable->retval); callable_mark_array_length (callable, callable->retval.ti); /* Process 'self' argument, if present. */ ffi_arg = &ffi_args[0]; if (callable->has_self) *ffi_arg++ = &ffi_type_pointer; /* Process the rest of the arguments. */ param = &callable->params[0]; for (argi = 0; argi < nargs; argi++, param++, ffi_arg++) { g_callable_info_load_arg (callable->info, argi, ¶m->ai); param->ti = g_arg_info_get_type (¶m->ai); param->dir = g_arg_info_get_direction (¶m->ai); param->transfer = g_arg_info_get_ownership_transfer (¶m->ai); *ffi_arg = (param->dir == GI_DIRECTION_IN) ? get_ffi_type (param) : &ffi_type_pointer; /* Mark closure-related user_data fields and possibly destroy_notify fields as internal. */ arg = g_arg_info_get_closure (¶m->ai); if (arg >= 0 && arg < nargs) { callable->params[arg].internal = TRUE; if (arg == argi) callable->params[arg].internal_user_data = TRUE; callable->params[arg].n_closures++; if (g_arg_info_get_scope (¶m->ai) == GI_SCOPE_TYPE_CALL) callable->params[arg].call_scoped_user_data = TRUE; } arg = g_arg_info_get_destroy (¶m->ai); if (arg > 0 && arg < nargs) callable->params[arg].internal = TRUE; /* Similarly for array length field. */ callable_mark_array_length (callable, param->ti); /* In case that we have an out or inout argument and callable returns boolean, mark it as ignore_retval (because we will signalize failure by returning nil instead of extra value). */ if (param->dir != GI_DIRECTION_IN && g_type_info_get_tag (callable->retval.ti) == GI_TYPE_TAG_BOOLEAN) callable->ignore_retval = 1; } /* Manual adjustment of 'GObject.ClosureMarshal' type, which is crucial for lgi but is missing an array annotation in glib/gobject-introspection < 1.30. */ if (!GLIB_CHECK_VERSION (2, 30, 0) && !strcmp (g_base_info_get_namespace (info), "GObject") && !strcmp (g_base_info_get_name (info), "ClosureMarshal")) { callable->is_closure_marshal = 1; callable->params[2].internal = 1; } /* Add ffi info for 'err' argument. */ if (callable->throws) *ffi_arg++ = &ffi_type_pointer; /* Create ffi_cif. */ if (ffi_prep_cif (&callable->cif, FFI_DEFAULT_ABI, callable->has_self + nargs + callable->throws, ffi_retval, ffi_args) != FFI_OK) { lua_concat (L, lgi_type_get_name (L, callable->info)); return luaL_error (L, "ffi_prep_cif for `%s' failed", lua_tostring (L, -1)); } return 1; } static int callable_param_get_kind (lua_State *L) { int kind = -1, top = lua_gettop (L); if (lgi_udata_test (L, -1, LGI_GI_INFO)) kind = PARAM_KIND_TI; else { luaL_checktype (L, -1, LUA_TTABLE); lua_getmetatable (L, -1); if (!lua_isnil (L, -1)) { lua_getfield (L, -1, "_type"); if (!lua_isnil (L, -1)) { const char *type = lua_tostring (L, -1); if (g_strcmp0 (type, "struct") == 0 || g_strcmp0 (type, "union") == 0) kind = PARAM_KIND_RECORD; else if (g_strcmp0 (type, "enum") == 0 || g_strcmp0 (type, "flags") == 0) kind = PARAM_KIND_ENUM; } } } lua_settop (L, top); return kind; } static const char *dirs[] = { "in", "out", "inout", NULL }; /* Parses single 'Param' structure from the table on the top of the stack. Pops the table from the stack. */ static void callable_param_parse (lua_State *L, Param *param) { int kind = callable_param_get_kind (L); /* Initialize parameters to default values. */ param->transfer = GI_TRANSFER_NOTHING; param->ti = NULL; if (kind == -1) { /* Check the direction. */ lua_getfield (L, -1, "dir"); if (!lua_isnil (L, -1)) param->dir = luaL_checkoption (L, -1, dirs[0], dirs); lua_pop (L, 1); /* Get transfer flag, prepare default according to dir. */ lua_getfield (L, -1, "xfer"); param->transfer = lua_toboolean (L, -1) ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING; lua_pop (L, 1); /* Get type, assume record (if not overriden by real giingo type below). */ lua_getfield (L, -1, "type"); if (!lua_isnil (L, -1)) { /* This is actually an enum, and type contains numeric type for this enum. Store it into the ti. */ GITypeInfo **ti = luaL_checkudata (L, -1, LGI_GI_INFO); param->ti = g_base_info_ref (*ti); } lua_pop (L, 1); /* Finally get the type from the table (from index 1) and replace the table with the type. */ lua_rawgeti (L, -1, 1); lua_replace (L, -2); } /* Parse the type. */ if (kind == -1) kind = callable_param_get_kind (L); if (kind == PARAM_KIND_TI) { /* Expect typeinfo. */ GITypeInfo **pti = lua_touserdata (L, -1); param->ti = g_base_info_ref (*pti); param->kind = kind; lua_pop (L, 1); } else if (kind == PARAM_KIND_ENUM || kind == PARAM_KIND_RECORD) { /* Add it to the env table. */ int index = lua_objlen (L, -2) + 1; lua_rawseti (L, -2, index); param->repotype_index = index; param->kind = kind; } else luaL_error (L, "bad efn def"); } /* Parses callable from given table. */ static int callable_parse (lua_State *L, int info) { Callable *callable; int nargs, i; ffi_type **ffi_args; ffi_type *ffi_retval; /* Allocate the raw structure. */ nargs = lua_objlen (L, info); callable = callable_allocate (L, nargs, &ffi_args); /* Create 'env' table. */ lua_newtable (L); /* Add function name to it. */ lua_getfield (L, info, "name"); lua_rawseti (L, -2, 0); /* Get address of the function. */ lua_getfield (L, info, "addr"); callable->address = lua_touserdata (L, -1); lua_pop (L, 1); /* Handle 'return' table. */ lua_getfield (L, info, "ret"); /* Get ignore_retval flag. */ lua_getfield (L, -1, "phantom"); callable->ignore_retval = lua_toboolean (L, -1); lua_pop (L, 1); /* Parse return value param. */ callable->retval.dir = GI_DIRECTION_OUT; callable_param_parse (L, &callable->retval); ffi_retval = get_ffi_type (&callable->retval); /* Parse individual arguments. */ for (i = 0; i < nargs; i++) { lua_rawgeti (L, info, i + 1); callable->params[i].dir = GI_DIRECTION_IN; callable_param_parse (L, &callable->params[i]); ffi_args[i] = (callable->params[i].dir == GI_DIRECTION_IN) ? get_ffi_type (&callable->params[i]) : &ffi_type_pointer; } /* Handle 'throws' flag. */ lua_getfield (L, info, "throws"); callable->throws = lua_toboolean (L, -1); lua_pop (L, 1); if (callable->throws) ffi_args[i] = &ffi_type_pointer; /* Create ffi_cif. */ if (ffi_prep_cif (&callable->cif, FFI_DEFAULT_ABI, nargs + callable->throws, ffi_retval, ffi_args) != FFI_OK) return luaL_error (L, "ffi_prep_cif failed for parsed"); /* Attach env table to the returned callable instance. */ lua_setfenv (L, -2); return 1; } /* Checks whether given argument is Callable userdata. */ static Callable * callable_get (lua_State *L, int narg) { luaL_checkstack (L, 3, ""); if (lua_getmetatable (L, narg)) { lua_pushlightuserdata (L, &callable_mt); lua_rawget (L, LUA_REGISTRYINDEX); if (lua_rawequal (L, -1, -2)) { lua_pop (L, 2); return lua_touserdata (L, narg); } } lua_pushfstring (L, "expected lgi.callable, got %s", lua_typename (L, lua_type (L, narg))); luaL_argerror (L, narg, lua_tostring (L, -1)); return NULL; } static void callable_param_destroy (Param *param) { if (param->ti) g_base_info_unref (param->ti); } static int callable_gc (lua_State *L) { int i; /* Unref embedded 'info' field. */ Callable *callable = callable_get (L, 1); if (callable->info) g_base_info_unref (callable->info); /* Destroy all params. */ for (i = 0; i < callable->nargs; i++) callable_param_destroy (&callable->params[i]); callable_param_destroy (&callable->retval ); return 0; } static int callable_tostring (lua_State *L) { Callable *callable = callable_get (L, 1); if (callable->info) { lua_pushfstring (L, "lgi.%s (%p): ", (GI_IS_FUNCTION_INFO (callable->info) ? "fun" : (GI_IS_SIGNAL_INFO (callable->info) ? "sig" : (GI_IS_VFUNC_INFO (callable->info) ? "vfn" : "cbk"))), callable->address); lua_concat (L, lgi_type_get_name (L, callable->info) + 1); } else { lua_getfenv (L, 1); lua_rawgeti (L, -1, 0); lua_pushfstring (L, "lgi.efn (%p): %s", callable->address, lua_tostring (L, -1)); } return 1; } static int callable_param_2c (lua_State *L, Param *param, int narg, GIArgument *arg, Callable *callable, void **args) { int nret = 0; if (param->kind == PARAM_KIND_ENUM && lua_type (L, narg) != LUA_TNUMBER) { /* Convert enum symbolic value to numeric one. */ lua_getfenv (L, 1); lua_rawgeti (L, -1, param->repotype_index); lua_pushvalue (L, narg); lua_call (L, 1, 1); narg = -1; } if (param->kind != PARAM_KIND_RECORD) { if (param->ti) nret = lgi_marshal_2c (L, param->ti, callable->info ? ¶m->ai : NULL, param->transfer, arg, narg, 0, callable->info, args + callable->has_self); else { union { GIArgument arg; int i; } *u = (gpointer) arg; u->i = lua_tonumber (L, narg); } /* Stack cleanup from enum value conversion. */ if (narg == -1) lua_pop (L, 2); } else { /* Marshal record according to custom information. */ lua_getfenv (L, 1); lua_rawgeti (L, -1, param->repotype_index); lgi_record_2c (L, narg, &arg->v_pointer, FALSE, param->transfer != GI_TRANSFER_NOTHING, TRUE, FALSE); lua_pop (L, 1); } return nret; } static void callable_param_2lua (lua_State *L, Param *param, GIArgument *arg, int parent, Callable *callable, void **args) { if (param->kind != PARAM_KIND_RECORD) { if (param->ti) lgi_marshal_2lua (L, param->ti, callable->info ? ¶m->ai : NULL, param->dir, param->transfer, arg, parent, callable->info, args + callable->has_self); else { union { GIArgument arg; int i; } *u = (gpointer) arg; lua_pushnumber (L, u->i); } } if (param->kind == PARAM_KIND_TI) return; lua_getfenv (L, 1); lua_rawgeti (L, -1, param->repotype_index); if (param->kind == PARAM_KIND_RECORD) { /* Marshal record according to custom information. */ lgi_record_2lua (L, arg->v_pointer, param->transfer != GI_TRANSFER_NOTHING, parent); lua_remove (L, -2); } else { /* Convert enum numeric value to symbolic one. */ lua_pushvalue (L, -3); lua_gettable (L, -2); lua_replace (L, -4); lua_pop (L, 2); } } static int callable_call (lua_State *L) { Param *param; int i, lua_argi, nret, caller_allocated = 0, nargs; GIArgument retval, *args; void **ffi_args, **redirect_out; GError *err = NULL; gpointer state_lock = lgi_state_get_lock (L); Callable *callable = callable_get (L, 1); /* Make sure that all unspecified arguments are set as nil; during marshalling we might create temporary values on the stack, which can be confused with input arguments expected but not passed by caller. */ lua_settop(L, callable->has_self + callable->nargs + 1); /* We cannot push more stuff than count of arguments we have. */ luaL_checkstack (L, callable->nargs, ""); /* Prepare data for the call. */ nargs = callable->nargs + callable->has_self; args = g_newa (GIArgument, nargs); redirect_out = g_newa (void *, nargs + callable->throws); ffi_args = g_newa (void *, nargs + callable->throws); /* Prepare 'self', if present. */ lua_argi = 2; nret = 0; if (callable->has_self) { GIBaseInfo *parent = g_base_info_get_container (callable->info); GIInfoType type = g_base_info_get_type (parent); if (type == GI_INFO_TYPE_OBJECT || type == GI_INFO_TYPE_INTERFACE) { args[0].v_pointer = lgi_object_2c (L, 2, g_registered_type_info_get_g_type (parent), FALSE, FALSE, FALSE); nret++; } else { lgi_type_get_repotype (L, G_TYPE_INVALID, parent); lgi_record_2c (L, 2, &args[0].v_pointer, FALSE, FALSE, FALSE, FALSE); nret++; } ffi_args[0] = &args[0]; lua_argi++; } /* Prepare proper call->ffi_args[] pointing to real args (or redirects in case of inout/out parameters). Note that this loop cannot be merged with following marshalling loop, because during marshalling of closure or arrays marshalling code can read/write values ahead of currently marshalled value. */ param = &callable->params[0]; for (i = 0; i < callable->nargs; i++, param++) { /* Prepare ffi_args and redirection for out/inout parameters. */ int argi = i + callable->has_self; if (param->dir == GI_DIRECTION_IN) ffi_args[argi] = &args[argi]; else { ffi_args[argi] = &redirect_out[argi]; redirect_out[argi] = &args[argi]; } if (param->n_closures > 0) { args[argi].v_pointer = lgi_closure_allocate (L, param->n_closures); if (param->call_scoped_user_data) /* Add guard which releases closure block after the call. */ *lgi_guard_create (L, lgi_closure_destroy) = args[argi].v_pointer; } } /* Process input parameters. */ nret = 0; param = &callable->params[0]; for (i = 0; i < callable->nargs; i++, param++) if (!param->internal) { int argi = i + callable->has_self; if (param->dir != GI_DIRECTION_OUT) nret += callable_param_2c (L, param, lua_argi++, &args[argi], callable, ffi_args); /* Special handling for out/caller-alloc structures; we have to manually pre-create them and store them on the stack. */ else if (callable->info && g_arg_info_is_caller_allocates (¶m->ai) && lgi_marshal_2c_caller_alloc (L, param->ti, &args[argi], 0)) { /* Even when marked as OUT, caller-allocates arguments behave as if they are actually IN from libffi POV. */ ffi_args[argi] = &args[argi]; /* Move the value on the stack *below* any already present temporary values. */ lua_insert (L, -nret - 1); caller_allocated++; } } else if (param->internal_user_data) /* Provide userdata for the callback. */ args[i + callable->has_self].v_pointer = callable->user_data; /* Add error for 'throws' type function. */ if (callable->throws) { redirect_out[nargs] = &err; ffi_args[nargs] = &redirect_out[nargs]; } /* Unlock the state. */ lgi_state_leave (state_lock); /* Call the function. */ ffi_call (&callable->cif, callable->address, &retval, ffi_args); /* Heading back to Lua, lock the state back again. */ lgi_state_enter (state_lock); /* Pop any temporary items from the stack which might be stored there by marshalling code. */ lua_pop (L, nret); /* Handle return value. */ nret = 0; if (!callable->ignore_retval && (callable->retval.ti == NULL || (g_type_info_get_tag (callable->retval.ti) != GI_TYPE_TAG_VOID || g_type_info_is_pointer (callable->retval.ti)))) { callable_param_2lua (L, &callable->retval, &retval, LGI_PARENT_IS_RETVAL, callable, ffi_args); nret++; lua_insert (L, -caller_allocated - 1); } else if (callable->ignore_retval) { /* Make sure that returned boolean is converted according to ffi_call rules. */ union { GIArgument arg; ffi_sarg s; } *ru = (gpointer) &retval; ru->arg.v_boolean = (gboolean) ru->s; } /* Check, whether function threw. */ if (err != NULL) { if (nret == 0) { lua_pushboolean (L, 0); nret = 1; } lua_pushstring (L, err->message); lua_pushnumber (L, err->code); g_error_free (err); return nret + 2; } /* Process output parameters. */ param = &callable->params[0]; for (i = 0; i < callable->nargs; i++, param++) if (!param->internal && param->dir != GI_DIRECTION_IN) { if (callable->info && g_arg_info_is_caller_allocates (¶m->ai) && lgi_marshal_2c_caller_alloc (L, param->ti, NULL, -caller_allocated - nret)) /* Caller allocated parameter is already marshalled and lying on the stack. */ caller_allocated--; else { /* Marshal output parameter. */ callable_param_2lua (L, param, &args[i + callable->has_self], 0, callable, ffi_args); lua_insert (L, -caller_allocated - 1); } /* In case that this callable is in ignore-retval mode and function actually returned FALSE, replace the already marshalled return value with NULL. */ if (callable->ignore_retval && !retval.v_boolean) { lua_pushnil (L); lua_replace (L, -caller_allocated - 2); } nret++; } /* When function can throw and we are not returning anything, be sure to return at least 'true', so that caller can check for error in a usual way (i.e. by Lua's assert() call). */ if (nret == 0 && callable->throws) { lua_pushboolean (L, 1); nret = 1; } g_assert (caller_allocated == 0); return nret; } static int callable_index (lua_State *L) { Callable *callable = callable_get (L, 1); if (g_strcmp0 (lua_tostring (L, 2), "user_data")) return 0; lua_pushlightuserdata (L, callable->user_data); return 1; } static int callable_newindex (lua_State *L) { Callable *callable = callable_get (L, 1); if (g_strcmp0 (lua_tostring (L, 2), "user_data") == 0) callable->user_data = lua_touserdata (L, 3); return 0; } static const struct luaL_Reg callable_reg[] = { { "__gc", callable_gc }, { "__tostring", callable_tostring }, { "__call", callable_call }, { "__index", callable_index }, { "__newindex", callable_newindex }, { NULL, NULL } }; /* Closure callback, called by libffi when C code wants to invoke Lua callback. */ static void closure_callback (ffi_cif *cif, void *ret, void **args, void *closure_arg) { Callable *callable; FfiClosure *closure = closure_arg; FfiClosureBlock *block = closure->block; gint res = 0, npos, i, stacktop; gboolean call; Param *param; (void)cif; /* Get access to proper Lua context. */ lua_State *L = block->callback.L; lgi_state_enter (block->callback.state_lock); lua_rawgeti (L, LUA_REGISTRYINDEX, block->callback.thread_ref); L = lua_tothread (L, -1); call = (closure->target_ref != LUA_NOREF); if (call) { /* We will call target method, prepare context/thread to do it. */ if (lua_status (L) != 0) { /* Thread is not in usable state for us, it is suspended, we cannot afford to resume it, because it is possible that the routine we are about to call is actually going to resume it. Create new thread instead and switch closure to its context. */ L = lua_newthread (L); lua_rawseti (L, LUA_REGISTRYINDEX, block->callback.thread_ref); } lua_pop (block->callback.L, 1); block->callback.L = L; /* Remember stacktop, this is the position on which we should expect return values (note that callback_prepare_call already might have pushed function to be executed to the stack). */ stacktop = lua_gettop (L); /* Store function to be invoked to the stack. */ lua_rawgeti (L, LUA_REGISTRYINDEX, closure->target_ref); } else { /* Cleanup the stack of the original thread. */ lua_pop (block->callback.L, 1); stacktop = lua_gettop (L); if (lua_status (L) == 0) /* Thread is not suspended yet, so it contains initial function at the top of the stack, so count with it. */ stacktop--; } /* Get access to Callable structure. */ lua_rawgeti (L, LUA_REGISTRYINDEX, closure->callable_ref); callable = lua_touserdata (L, -1); lua_pop (L, 1); /* Marshall 'self' argument, if it is present. */ npos = 0; if (callable->has_self) { GIBaseInfo *parent = g_base_info_get_container (callable->info); GIInfoType type = g_base_info_get_type (parent); gpointer addr = ((GIArgument*) args[0])->v_pointer; npos++; if (type == GI_INFO_TYPE_OBJECT || type == GI_INFO_TYPE_INTERFACE) lgi_object_2lua (L, addr, FALSE, FALSE); else if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_UNION) { lgi_type_get_repotype (L, G_TYPE_INVALID, parent); lgi_record_2lua (L, addr, FALSE, 0); } else g_assert_not_reached (); } /* Marshal input arguments to lua. */ param = callable->params; for (i = 0; i < callable->nargs; ++i, ++param) if (!param->internal && param->dir != GI_DIRECTION_OUT) { if (i != 3 || !callable->is_closure_marshal) lgi_marshal_2lua (L, param->ti, callable->info ? ¶m->ai : NULL, param->dir, GI_TRANSFER_NOTHING, args[i + callable->has_self], 0, callable->info, args + callable->has_self); else { /* Workaround incorrectly annotated but crucial ClosureMarshal callback. Its 3rd argument is actually an array of GValue, not a single GValue as missing annotation suggests. */ guint i, nvals = ((GIArgument *)args[2])->v_uint32; GValue* vals = ((GIArgument *)args[3])->v_pointer; lua_createtable (L, nvals, 0); for (i = 0; i < nvals; ++i) { lua_pushnumber (L, i + 1); lgi_type_get_repotype (L, G_TYPE_VALUE, NULL); lgi_record_2lua (L, &vals[i], FALSE, 0); lua_settable (L, -3); } } npos++; } /* Call it. */ if (call) { if (callable->throws) res = lua_pcall (L, npos, LUA_MULTRET, 0); else lua_call (L, npos, LUA_MULTRET); } else { #if LUA_VERSION_NUM >= 502 res = lua_resume (L, NULL, npos); #else res = lua_resume (L, npos); #endif if (res == LUA_YIELD) /* For our purposes is YIELD the same as if the coro really returned. */ res = 0; else if (res == LUA_ERRRUN && !callable->throws) { /* If closure is not allowed to return errors and coroutine finished with error, rethrow the error in the context of the original thread. */ lua_settop (L, stacktop + 1); lua_xmove (L, block->callback.L, 1); lua_error (block->callback.L); } } npos = stacktop + 1; /* Check, whether we can report an error here. */ if (res == 0) { int to_pop; GITypeTag tag; /* Make sure that all unspecified returns and outputs are set as nil; during marshalling we might create temporary values on the stack, which can be confused with output values expected but not passed by caller. */ lua_settop(L, lua_gettop (L) + callable->has_self + callable->nargs + 1); /* Marshal return value from Lua. */ tag = g_type_info_get_tag (callable->retval.ti); if (tag != GI_TYPE_TAG_VOID || g_type_info_is_pointer (callable->retval.ti)) { if (callable->ignore_retval) /* Return value should be ignored on Lua side, so we have to synthesize the return value for C side. We should return FALSE if next output argument is nil. */ *(ffi_sarg *) ret = lua_isnoneornil (L, npos) ? FALSE : TRUE; else { to_pop = lgi_marshal_2c (L, callable->retval.ti, NULL, callable->retval.transfer, ret, npos, LGI_PARENT_IS_RETVAL, callable->info, args + callable->has_self); if (to_pop != 0) { g_warning ("cbk `%s.%s': return (transfer none) %d, unsafe!", g_base_info_get_namespace (callable->info), g_base_info_get_name (callable->info), to_pop); lua_pop (L, to_pop); } npos++; } } /* Marshal output arguments from Lua. */ param = callable->params; for (i = 0; i < callable->nargs; ++i, ++param) if (!param->internal && param->dir != GI_DIRECTION_IN) { gpointer *arg = args[i + callable->has_self]; gboolean caller_alloc = callable->info && g_arg_info_is_caller_allocates (¶m->ai) && g_type_info_get_tag (param->ti) == GI_TYPE_TAG_INTERFACE; to_pop = lgi_marshal_2c (L, param->ti, ¶m->ai, param->transfer, *arg, npos, caller_alloc ? LGI_PARENT_CALLER_ALLOC : 0, callable->info, args + callable->has_self); if (to_pop != 0) { g_warning ("cbk %s.%s: arg `%s' (transfer none) %d, unsafe!", g_base_info_get_namespace (callable->info), g_base_info_get_name (callable->info), g_base_info_get_name (¶m->ai), to_pop); lua_pop (L, to_pop); } npos++; } } else { /* If the function is expected to return errors, create proper error. */ GQuark q = g_quark_from_static_string ("lgi-callback-error-quark"); GError **err = ((GIArgument *) args[callable->has_self + callable->nargs])->v_pointer; g_set_error_literal (err, q, 1, lua_tostring(L, -1)); lua_pop (L, 1); /* Such function should usually return FALSE, so do it. */ if (g_type_info_get_tag (callable->retval.ti) == GI_TYPE_TAG_BOOLEAN) *(gboolean *) ret = FALSE; } /* If the closure is marked as autodestroy, destroy it now. Note that it is unfortunately not possible to destroy it directly here, because we would delete the code under our feet and crash and burn :-(. Instead, we create marshal guard and leave it to GC to destroy the closure later. */ if (closure->autodestroy) *lgi_guard_create (L, lgi_closure_destroy) = block; /* This is NOT called by Lua, so we better leave the Lua stack we used pretty much tidied. */ lua_settop (L, stacktop); /* Going back to C code, release the state synchronization. */ lgi_state_leave (block->callback.state_lock); } /* Destroys specified closure. */ void lgi_closure_destroy (gpointer user_data) { FfiClosureBlock* block = user_data; lua_State *L = block->callback.L; FfiClosure *closure; int i; for (i = block->closures_count - 1; i >= -1; --i) { closure = (i < 0) ? &block->ffi_closure : block->ffi_closures[i]; if (closure->created) { luaL_unref (L, LUA_REGISTRYINDEX, closure->callable_ref); luaL_unref (L, LUA_REGISTRYINDEX, closure->target_ref); } if (i < 0) luaL_unref (L, LUA_REGISTRYINDEX, block->callback.thread_ref); ffi_closure_free (closure); } } /* Creates container block for allocated closures. Returns address of the block, suitable as user_data parameter. */ gpointer lgi_closure_allocate (lua_State *L, int count) { gpointer call_addr; int i; /* Allocate header block. */ FfiClosureBlock *block = ffi_closure_alloc (offsetof (FfiClosureBlock, ffi_closures) + (--count * sizeof (FfiClosure*)), &call_addr); block->ffi_closure.created = 0; block->ffi_closure.call_addr = call_addr; block->ffi_closure.block = block; block->closures_count = count; /* Allocate all additional closures. */ for (i = 0; i < count; ++i) { block->ffi_closures[i] = ffi_closure_alloc (sizeof (FfiClosure), &call_addr); block->ffi_closures[i]->created = 0; block->ffi_closures[i]->call_addr = call_addr; block->ffi_closures[i]->block = block; } /* Store reference to target Lua thread. */ block->callback.L = L; lua_pushthread (L); block->callback.thread_ref = luaL_ref (L, LUA_REGISTRYINDEX); /* Retrieve and remember state lock. */ block->callback.state_lock = lgi_state_get_lock (L); return block; } /* Creates closure from Lua function to be passed to C. */ gpointer lgi_closure_create (lua_State *L, gpointer user_data, GICallableInfo *ci, int target, gboolean autodestroy) { FfiClosureBlock* block = user_data; FfiClosure *closure; Callable *callable; gpointer call_addr; int i; /* Find pointer to target FfiClosure. */ for (closure = &block->ffi_closure, i = 0; closure->created; ++i) { g_assert (i < block->closures_count); closure = block->ffi_closures[i]; } /* Prepare callable and store reference to it. */ lgi_callable_create (L, ci, NULL); callable = lua_touserdata (L, -1); call_addr = closure->call_addr; closure->created = 1; closure->autodestroy = autodestroy; closure->callable_ref = luaL_ref (L, LUA_REGISTRYINDEX); if (!lua_isthread (L, target)) { lua_pushvalue (L, target); closure->target_ref = luaL_ref (L, LUA_REGISTRYINDEX); } else { /* Switch thread_ref to actual target thread. */ lua_pushvalue (L, target); lua_rawseti (L, LUA_REGISTRYINDEX, block->callback.thread_ref); closure->target_ref = LUA_NOREF; } /* Create closure. */ if (ffi_prep_closure_loc (&closure->ffi_closure, &callable->cif, closure_callback, closure, call_addr) != FFI_OK) { lua_concat (L, lgi_type_get_name (L, ci)); luaL_error (L, "failed to prepare closure for `%'", lua_tostring (L, -1)); return NULL; } return call_addr; } /* Creates new Callable instance according to given gi.info. Lua prototype: callable = callable.new(callable_info) or callable = callable.new(description_table) */ static int callable_new (lua_State *L) { if (lua_istable (L, 1)) return callable_parse (L, 1); else return lgi_callable_create (L, *(GICallableInfo **) luaL_checkudata (L, 1, LGI_GI_INFO), NULL); } /* Callable module public API table. */ static const luaL_Reg callable_api_reg[] = { { "new", callable_new }, { NULL, NULL } }; void lgi_callable_init (lua_State *L) { /* Register callable metatable. */ lua_pushlightuserdata (L, &callable_mt); lua_newtable (L); luaL_register (L, NULL, callable_reg); lua_rawset (L, LUA_REGISTRYINDEX); /* Create cache for callables. */ lgi_cache_create (L, &callable_cache, NULL); /* Create public api for callable module. */ lua_newtable (L); luaL_register (L, NULL, callable_api_reg); lua_setfield (L, -2, "callable"); } lua-lgi-0.7.2/lgi/class.lua000066400000000000000000000362061221440706400154440ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Support for generic GType objects and interfaces -- -- Copyright (c) 2010, 2011, 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local type, tostring, rawget, rawset, pairs, select, getmetatable, setmetatable, error, assert = type, tostring, rawget, rawset, pairs, select, getmetatable, setmetatable, error, assert local string = require 'string' local core = require 'lgi.core' local gi = core.gi local component = require 'lgi.component' local record = require 'lgi.record' local ffi = require 'lgi.ffi' local ti = ffi.types local GObject = gi.require 'GObject' -- Implementation of class and interface component loading. local class = { class_mt = component.mt:clone( 'class', { '_virtual', '_property', '_signal', '_method', '_constant', '_field' }), interface_mt = component.mt:clone( 'interface', { '_virtual', '_property', '_signal', '_method', '_constant' }), } local type_class_peek = core.callable.new { addr = GObject.resolve.g_type_class_peek, ret = ti.ptr, ti.GType } local type_interface_peek = core.callable.new { addr = GObject.resolve.g_type_interface_peek, ret = ti.ptr, ti.ptr, ti.GType } local type_class = component.create(nil, record.struct_mt) ffi.load_fields(type_class, { { 'g_type', ti.GType } }) local type_instance = component.create(nil, record.struct_mt) ffi.load_fields(type_instance, { { 'g_class', type_class, ptr = true } }) -- Checks whether given argument is type of this class. function class.class_mt:is_type_of(instance) if type(instance) == 'userdata' then local instance_type = core.object.query(instance, 'repo') while instance_type do if instance_type == self or instance_type._implements[self._name] == self then return true end instance_type = rawget(instance_type, '_parent') end end return false end class.interface_mt.is_type_of = class.class_mt.is_type_of local function load_signal_name(name) name = name:match('^on_(.+)$') return name and name:gsub('_', '-') end local function load_signal_name_reverse(name) return 'on_' .. name:gsub('%-', '_') end local function load_vfunc_name(name) return name:match('^do_(.+)$') end local function load_vfunc_name_reverse(name) return 'do_' .. name end local function load_method(mi) local flags = mi.flags if not flags.is_getter and not flags.is_setter then return core.callable.new(mi) end end local function load_properties(info) return component.get_category( info.properties, nil, function(name) return string.gsub(name, '_', '-') end, function(name) return string.gsub(name, '%-', '_') end) end local function find_constructor(info) local name = info.name:gsub('([%d%l])(%u)', '%1_%2'):lower() local ctor = gi[info.namespace][name] -- Check that return value conforms to info type. if ctor then local ret = ctor.return_type.interface for walk in function(_, c) return c.parent end, nil, info do if ret and walk == ret then ctor = core.callable.new(ctor) return function(self, ...) return ctor(...) end end end end end -- Resolver for classes, recursively resolves also all parents and -- implemented interfaces. function class.class_mt:_resolve(recursive) -- Resolve itself using inherited implementation. component.mt._resolve(self) -- Go to parent and implemented interfaces and resolve them too. if recursive then for _, iface in pairs(self._implements or {}) do iface:_resolve(recursive) end if self._parent then self._parent:_resolve(recursive) end end return self end -- _element implementation for objects, checks parent and implemented -- interfaces if element cannot be found in current typetable. local internals = { _native = true, _type = true, _gtype = true, _class = true, class = true } function class.class_mt:_element(instance, symbol) -- Special handling of internal symbols. if instance and internals[symbol] then return symbol, symbol end -- Check default implementation. local element, category = component.mt._element(self, instance, symbol) if element then return element, category end -- Check parent and all implemented interfaces. local parent = rawget(self, '_parent') if parent then element, category = parent:_element(instance, symbol) if element then return element, category end end local implements = rawget(self, '_implements') or {} for _, implemented in pairs(implements or {}) do element, category = implemented:_element(instance, symbol) if element then return element, category end end end -- Implementation of field accessor. Note that compound fields are -- not supported in classes (because they are not seen in the wild and -- I'm lazy). function class.class_mt:_access_field(instance, field, ...) return core.object.field(instance, field, ...) end -- Add accessor '_native' handling. function class.class_mt:_access_native(instance) return core.object.query(instance, 'addr') end -- Add accessor '_type' handling. function class.class_mt:_access_type(instance) return core.object.query(instance, 'repo') end -- Add accessor '_gtype' handling. function class.class_mt:_access_gtype(instance) -- Cast address of the instance to TypeInstance to get to type info. local ti = core.record.new(type_instance, core.object.query(instance, 'addr')) return ti.g_class.g_type end -- Add accessor '_class' handling. function class.class_mt:_access_class(instance) local gtype = class.class_mt._access_gtype(self, instance) return core.record.new(self._class, type_class_peek(gtype)) end class.class_mt._accessclass = class.class_mt._access_class -- Add accessor '_virtual' handling. function class.class_mt:_access_virtual(instance, vfi) local class_struct local container = vfi.container if container.is_interface then local gtype = class.class_mt._access_gtype(self, instance) local ptr = type_interface_peek(type_class_peek(gtype), container.gtype) class_struct = core.record.new(core.index[container.gtype]._class, ptr) else class_struct = class.class_mt._access_class(self, instance) end -- Retrieve proper method from the class struct. return class_struct[vfi.name] end -- Add __index for _virtual handling. Convert vfi baseinfo into real -- callable pointer according to the target type. function class.class_mt:_index_virtual(vfi) -- Get proper class struct, either from class or interface. local ptr, class_struct = type_class_peek(self._gtype) if not ptr then return nil end local container = vfi.container if container.is_interface then local gtype = container._gtype local ptr = type_interface_peek(ptr, gtype) class_struct = core.record.new(core.index[gtype]._class, ptr) else class_struct = core.record.new(self._class, ptr) end -- Retrieve proper method from the class struct. return class_struct[vfi.name] end function class.load_interface(namespace, info) -- Load all components of the interface. local interface = component.create(info, class.interface_mt) interface._property = load_properties(info) interface._method = component.get_category(info.methods, load_method) interface._signal = component.get_category( info.signals, nil, load_signal_name, load_signal_name_reverse) interface._constant = component.get_category(info.constants, core.constant) local type_struct = info.type_struct if type_struct then interface._virtual = component.get_category( info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse) interface._class = record.load(type_struct) interface._class._parent = core.repo.GObject.TypeInterface end interface._new = find_constructor(info) return interface end function class.load_class(namespace, info) -- Find parent record, if available. local parent_info, parent = info.parent if parent_info then local ns, name = parent_info.namespace, parent_info.name if ns ~= namespace._name or name ~= info.name then parent = core.repo[ns][name] end end -- Create class instance, copy mt from parent, if parent exists, -- otherwise defaults to class_mt. local class = component.create( info, parent and getmetatable(parent) or class.class_mt) class._parent = parent class._property = load_properties(info) class._method = component.get_category(info.methods, load_method) class._signal = component.get_category( info.signals, nil, load_signal_name, load_signal_name_reverse) class._constant = component.get_category(info.constants, core.constant) class._field = component.get_category(info.fields) local type_struct = info.type_struct if type_struct then class._virtual = component.get_category( info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse) class._class = record.load(type_struct) class._class._parent = parent and parent._class or core.repo.GObject.TypeClass end -- Populate inheritation information (_implements and _parent fields). local interfaces, implements = info.interfaces, {} for i = 1, #interfaces do local iface = interfaces[i] implements[iface.fullname] = core.repo[iface.namespace][iface.name] end class._implements = implements class._new = find_constructor(info) return class end local register_static = core.callable.new(GObject.type_register_static) local type_query = core.callable.new(GObject.type_query) local type_add_interface_static = core.callable.new( GObject.type_add_interface_static) function class.class_mt:derive(typename, ifaces) -- Prepare repotable for newly registered class. local new_class = setmetatable( { _parent = self, _override = {}, _guard = {}, _implements = {}, _element = class.derived_mt._element, _class = self._class, _name = typename }, class.derived_mt) -- Create class-initialization closure, which assigns pointers to -- all known overriden virtual methods. local function class_init(class_addr) -- Create instance of real class. local class_struct = core.record.new(new_class._class, class_addr) -- Iterate through all overrides and assign to the virtual callbacks. for name, addr in pairs(new_class._override) do if type(addr) == 'userdata' then class_struct[name] = addr end end -- If type specified _class_init method, invoke it. local _class_init = rawget(new_class, '_class_init') if _class_init then _class_init(new_class) end end local class_init_guard, class_init_addr = core.marshal.callback( GObject.ClassInitFunc, class_init) new_class._guard._class_init = class_init_guard -- Create instance initialization function. Note that we do not -- pass directly user's method, because user will probably set it -- later after the type is already created, but we need to pass its -- address right now during type initialization. Therefore, a stub -- which looks up the init method of the type dynamically is used -- instead. local function instance_init(instance) local _init = rawget(new_class, '_init') if _init then -- Convert instance to real type and call init with it. _init(core.object.new(core.record.query(instance, 'addr'), false, true)) end end local instance_init_guard, instance_init_addr = core.marshal.callback( GObject.InstanceInitFunc, instance_init) new_class._guard._instance_init = instance_init_guard -- Prepare GTypeInfo with the registration. local parent_info = type_query(self._gtype) local type_info = core.repo.GObject.TypeInfo { class_size = parent_info.class_size, class_init = class_init_addr, instance_size = parent_info.instance_size, instance_init = instance_init_addr, } -- Register new type with GType system. local gtype = register_static(self._gtype, typename:gsub('%.', ''), type_info, {}) rawset(new_class, '_gtype', core.gtype(gtype)) if not new_class._gtype then error(("failed to derive `%s' from `%s'"):format(typename, self._name)) end -- Add newly registered type into the lgi type index. core.index[new_class._gtype] = new_class -- Create interface initialization closures. for _, iface in pairs(ifaces or {}) do local override = {} new_class._override[iface._name] = override new_class._implements[iface._name] = iface -- Prepare interface initialization closure. local function iface_init(iface_addr) local iface_struct = core.record.new(iface._class, iface_addr) -- Iterate through all interface overrides and assign to the -- virtual callbacks. for name, addr in pairs(override) do iface_struct[name] = addr end end local iface_init_guard, iface_init_addr = core.marshal.callback( GObject.InterfaceInitFunc, iface_init) new_class._guard['_iface_init_' .. iface._name] = iface_init_guard -- Hook up interface to the registered class. local iface_info = core.repo.GObject.InterfaceInfo { interface_init = iface_init_addr, } type_add_interface_static(new_class, iface, iface_info) end return new_class end class.derived_mt = class.class_mt:clone('derived', {}) -- Support for 'priv' pseudomember, holding table with user -- implementation data. function class.derived_mt:_element(instance, symbol) -- Special handling of 'priv' attribute. if instance and symbol == 'priv' then return symbol, '_priv' end -- Check default implementation. local element, category = class.class_mt._element(self, instance, symbol) if element then return element, category end end function class.derived_mt:_access_priv(instance, name, ...) if select('#', ...) > 0 then error(("%s: cannot assign `%s'"):format(self._name), name, 5) end return core.object.env(instance) end -- Overload __newindex to catch assignment to virtual - this causes -- installation of new virtual method function class.derived_mt:__newindex(name, target) -- Use _element method to get category to write to. local _element = (rawget(self, '_element') or rawget(getmetatable(self), '_element')) local value, category = _element(self, nil, name) if category == '_virtual' then -- Overriding virtual method. Prepare callback to the target and -- store it to the _override type helper subtable. name = load_vfunc_name(name) local container = value.container local class_struct, override if container.is_interface then class_struct = core.index[container.gtype] override = self._override[class_struct._name] class_struct = class_struct._class else class_struct = self._class override = self._override end local guard, vfunc = core.marshal.callback( class_struct[name].typeinfo.interface, target) override[name] = vfunc self._guard[container.name .. ':' .. name] = guard else -- Simply assign to type. This most probably means adding new -- member function to the class (or some static member). rawset(self, name, target) end end return class lua-lgi-0.7.2/lgi/component.lua000066400000000000000000000243051221440706400163360ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Basic repo type component implementation -- -- Copyright (c) 2010, 2011, 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local assert, pcall, setmetatable, getmetatable, pairs, next, rawget, rawset, type, select, error = assert, pcall, setmetatable, getmetatable, pairs, next, rawget, rawset, type, select, error local table = require 'table' local string = require 'string' local core = require 'lgi.core' -- Generic component metatable. Component is any entity in the repo, -- e.g. record, object, enum, etc. local component = { mt = {} } -- Creates new component table by cloning all contents and setting -- Gets table for category of compound (i.e. _field of struct or _property -- for class etc). Installs metatable which performs on-demand lookup of -- symbols. function component.get_category(children, xform_value, xform_name, xform_name_reverse) -- Either none or both transform methods must be provided. assert(not xform_name or xform_name_reverse) -- Early shortcircuit; no elements, no table needed at all. if #children == 0 then return nil end -- Index contains array of indices which were still not retrieved -- from 'children' table, and table part contains name->index -- mapping. local index, mt = {}, {} for i = 1, #children do index[i] = i end -- Fully resolves the category (i.e. loads everything remaining to -- be loaded in given category) and disconnects on-demand loading -- metatable. local function resolve(category) -- Load al values from unknown indices. local ei, en, val local function xvalue(arg) if not xform_value then return arg end if arg then local ok, res = pcall(xform_value, arg) return ok and res end end while #index > 0 do ei = children[table.remove(index)] val = xvalue(ei) if val then en = ei.name en = not xform_name_reverse and en or xform_name_reverse(en) if en then category[en] = val end end end -- Load all known indices. for en, idx in pairs(index) do val = xvalue(children[idx]) en = not xform_name_reverse and en or xform_name_reverse(en) if en then category[en] = val end end -- Metatable is no longer needed, disconnect it. return setmetatable(category, nil) end function mt:__index(requested_name) -- Check if closure for fully resolving the category is needed. if requested_name == '_resolve' then return resolve end -- Transform name by transform function. local name = not xform_name and requested_name or xform_name(requested_name) if not name then return end -- Check, whether we already know its index. local idx, val = index[name] if idx then -- We know at least the index, so get info directly. val = children[idx] index[name] = nil else -- Not yet, go through unknown indices and try to find the -- name. while #index > 0 do idx = table.remove(index) val = children[idx] local en = val.name if en == name then break end val = nil index[en] = idx end end -- If there is nothing in the index, we can disconnect -- metatable, because everything is already loaded. if not next(index) then setmetatable(self, nil) end -- Transform found value and store it into the category (self) -- table. if not val then return nil end if xform_value then val = xform_value(val) end if not val then return nil end self[requested_name] = val return val end return setmetatable({}, mt) end -- Creates new component table by cloning all contents and setting -- categories table. function component.mt:clone(type, categories) local new_component = {} for key, value in pairs(self) do new_component[key] = value end new_component._type = type if categories then table.insert(categories, 1, '_attribute') new_component._categories = categories end return new_component end -- __call implementation, uses _new method to create new instance of -- component type. function component.mt:__call(...) return self:_new(...) end -- Fully resolves the whole typetable, i.e. load all symbols normally -- loaded on-demand at once. Returns self, so that resolve can be -- easily chained for the caller. function component.mt:_resolve() local categories = self._categories or {} for i = 1, #categories do -- Invoke '_resolve' function for all category tables, if they have it. local category = rawget(self, categories[i]) local resolve = type(category) == 'table' and category._resolve if resolve then resolve(category) end end return self end -- Implementation of _access method, which is called by _core when -- repo instance is accessed for reading or writing. function component.mt:_access(instance, symbol, ...) -- Invoke _element, which converts symbol to element and category. local element, category = self:_element(instance, symbol) if not element then error(("%s: no `%s'"):format(self._name, tostring(symbol)), 3) end return self:_access_element(instance, category, symbol, element, ...) end -- Internal worker of access, which works over already resolved element. function component.mt:_access_element(instance, category, symbol, element, ...) -- Get category handler to be used, and invoke it. if category then local handler = self['_access' .. category] if handler then return handler(self, instance, element, ...) end end -- If specific accessor does not exist, consider the element to be -- 'static const' attribute of the class. This works well for -- methods, constants and assorted other elements added manually -- into the class by overrides. if select('#', ...) > 0 then error(("%s: `%s' is not writable"):format(self._name, symbol), 4) end return element end -- Keyword translation dictionary. Used for translating Lua keywords -- which might appear as symbols in typelibs into Lua-neutral identifiers. local keyword_dictionary = { _end = 'end', _do = 'do', _then = 'then', _elseif = 'elseif', _in = 'in', _local = 'local', _function = 'function', _nil = 'nil', _false = 'false', _true = 'true', _and = 'and', _or = 'or', _not = 'not', } -- Retrieves (element, category) pair from given componenttable and -- instance for given symbol. function component.mt:_element(instance, symbol) -- This generic version can work only with strings. Refuse -- everything other, hoping that some more specialized _element -- implementation will handle it. if type(symbol) ~= 'string' then return end -- Check keyword translation dictionary. If the symbol can be -- found there, try to lookup translated symbol. symbol = keyword_dictionary[symbol] or symbol -- Check whether symbol is directly accessible in the component. local element = rawget(self, symbol) if element then return element end -- Decompose symbol name, in case that it contains category prefix -- (e.g. '_field_name' when requesting explicitely field called -- name). local category, name = string.match(symbol, '^(_.-)_(.*)$') if category and name and category ~= '_access' then -- Check requested category. local cat = rawget(self, category) element = cat and cat[name] elseif string.sub(symbol, 1, 1) ~= '_' then -- Check all available categories. local categories = self._categories or {} for i = 1, #categories do category = categories[i] local cat = rawget(self, category) element = cat and cat[symbol] if element then break end end end if element then -- Make sure that table-based attributes have symbol name, so -- that potential errors contain the name of referenced -- attribute. if type(element) == 'table' and category == '_attribute' then element._name = element._name or symbol end return element, category end end -- __index implementation, uses _element method to perform lookup. function component.mt:__index(key) -- First try to invoke our own _element method. local _element, mt = rawget(self, '_element') if not _element then mt = getmetatable(self) _element = rawget(mt, '_element') end local value, category = _element(self, nil, key) if value then if category then -- Mangle the result by type-specific '_index_' -- method, if present. local index_name = '_index' .. category local index = rawget(self, index_name) if not index then if not mt then mt = getmetatable(self) end if mt then index = rawget(mt, index_name) end end if index then value = index(self, value) end end return value end -- If not found as object element, examine the metatable itself. return rawget(mt or getmetatable(self), key) end -- Implementation of attribute accessor. Attribute is either function -- to be directly invoked, or table containing set and get functions. function component.mt:_access_attribute(instance, element, ...) -- If element is a table, assume that this table contains 'get' and -- 'set' methods. Dispatch to them, and error out if they are -- missing. if type(element) == 'table' then local mode = select('#', ...) == 0 and 'get' or 'set' if not element[mode] then error(("%s: cannot %s `%s'"):format( self._name, mode == 'get' and 'read' or 'write', element._name or ''), 5) end element = element[mode] end -- Invoke attribute access function. return element(instance, ...) end -- Creates new component and sets up common parts according to given -- info. function component.create(info, mt, name) local gtype if core.gi.isinfo(info) then gtype = info.gtype name = info.fullname else gtype = info and core.gtype(info) end -- Fill in meta of the compound. local component = { _name = name } if gtype then -- Bind component in repo, make the relation using GType. component._gtype = gtype core.index[gtype] = component end return setmetatable(component, mt) end return component lua-lgi-0.7.2/lgi/core.c000066400000000000000000000422411221440706400147240ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010, 2011, 2012 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Core C utility API. */ #include #include "lgi.h" /* GLib 2.32 deprecated GStaticRecMutex in favor of GRecMutex. For older GLib versions, use still older version. */ #if !GLIB_CHECK_VERSION(2, 32, 0) #define GRecMutex GStaticRecMutex #define G_REC_MUTEX_INIT = G_STATIC_REC_MUTEX_INIT #define g_rec_mutex_init g_static_rec_mutex_init #define g_rec_mutex_lock g_static_rec_mutex_lock #define g_rec_mutex_unlock g_static_rec_mutex_unlock #define g_rec_mutex_clear g_static_rec_mutex_free #else #define G_REC_MUTEX_INIT #endif #ifndef NDEBUG const char *lgi_sd (lua_State *L) { int i; static gchar *msg = 0; g_free (msg); msg = g_strdup (""); int top = lua_gettop (L); for (i = 1; i <= top; i++) { int t = lua_type (L, i); gchar *item, *nmsg; switch (t) { case LUA_TSTRING: item = g_strdup_printf ("`%s'", lua_tostring (L, i)); break; case LUA_TBOOLEAN: item = g_strdup_printf (lua_toboolean (L, i) ? "true" : "false"); break; case LUA_TNUMBER: item = g_strdup_printf ("%g", lua_tonumber (L, i)); break; default: item = g_strdup_printf ("%s(%p)", lua_typename (L, t), lua_topointer (L, i)); break; } nmsg = g_strconcat (msg, " ", item, NULL); g_free (msg); g_free (item); msg = nmsg; } return msg; } #endif /* lightuserdata of this address is a key in LUA_REGISTRYINDEX table to repo table. */ static int repo; /* lightuserdata of this address is a key in LUA_REGISTRYINDEX table to index table mapping lightuserdata-gtype -> repotable. */ static int repo_index; void * lgi_udata_test (lua_State *L, int narg, const char *name) { void *udata = NULL; luaL_checkstack (L, 2, ""); lgi_makeabs (L, narg); if (lua_getmetatable (L, narg)) { luaL_getmetatable (L, name); if (lua_equal (L, -1, -2)) udata = lua_touserdata (L, narg); lua_pop (L, 2); } return udata; } void lgi_cache_create (lua_State *L, gpointer key, const char *mode) { lua_pushlightuserdata (L, key); lua_newtable (L); if (mode) { lua_newtable (L); lua_pushstring (L, mode); lua_setfield (L, -2, "__mode"); lua_setmetatable (L, -2); } lua_rawset (L, LUA_REGISTRYINDEX); } int lgi_type_get_name (lua_State *L, GIBaseInfo *info) { GSList *list = NULL, *i; int n = 1; lua_pushstring (L, g_base_info_get_namespace (info)); /* Add names on the whole path, but in reverse order. */ for (; info != NULL; info = g_base_info_get_container (info)) if (!GI_IS_TYPE_INFO (info)) list = g_slist_prepend (list, info); for (i = list; i != NULL; i = g_slist_next (i)) { if (g_base_info_get_type (i->data) != GI_INFO_TYPE_TYPE) { lua_pushstring (L, "."); lua_pushstring (L, g_base_info_get_name (i->data)); n += 2; } } g_slist_free (list); return n; } void lgi_type_get_repotype (lua_State *L, GType gtype, GIBaseInfo *info) { luaL_checkstack (L, 4, ""); /* Get repo-index table. */ lua_pushlightuserdata (L, &repo_index); lua_rawget (L, LUA_REGISTRYINDEX); /* Prepare gtype, if not given directly. */ if (gtype == G_TYPE_INVALID && info && GI_IS_REGISTERED_TYPE_INFO (info)) { gtype = g_registered_type_info_get_g_type (info); if (gtype == G_TYPE_NONE) gtype = G_TYPE_INVALID; } /* First of all, check direct indexing of repo-index by gtype, should be fastest. */ if (gtype != G_TYPE_INVALID) { lua_pushlightuserdata (L, (gpointer) gtype); lua_rawget (L, -2); } else lua_pushnil (L); if (lua_isnil (L, -1)) { /* Not indexed yet. Try to lookup by name - this works when lazy-loaded repo tables are not loaded yet. */ if (!info) { info = g_irepository_find_by_gtype (NULL, gtype); lgi_gi_info_new (L, info); } else /* Keep stack balanced as in the previous 'if' branch. */ lua_pushnil (L); if (info) { lua_pushlightuserdata (L, &repo); lua_rawget (L, LUA_REGISTRYINDEX); lua_getfield (L, -1, g_base_info_get_namespace (info)); lua_getfield (L, -1, g_base_info_get_name (info)); lua_replace (L, -5); lua_pop (L, 3); } else lua_pop (L, 1); } lua_replace (L, -2); } GType lgi_type_get_gtype (lua_State *L, int narg) { /* Handle simple cases natively, forward to Lua implementation for the rest. */ switch (lua_type (L, narg)) { case LUA_TNIL: case LUA_TNONE: return G_TYPE_INVALID; case LUA_TNUMBER: return lua_tonumber (L, narg); case LUA_TLIGHTUSERDATA: return (GType) lua_touserdata (L, narg); case LUA_TSTRING: return g_type_from_name (lua_tostring (L, narg)); case LUA_TTABLE: { GType gtype; lgi_makeabs (L, narg); lua_pushstring (L, "_gtype"); lua_rawget (L, narg); gtype = lgi_type_get_gtype (L, -1); lua_pop (L, 1); return gtype; } default: return luaL_error (L, "GType expected, got %s", lua_typename (L, lua_type (L, narg))); } } typedef struct _Guard { gpointer data; GDestroyNotify destroy; } Guard; #define UD_GUARD "lgi.guard" static int guard_gc (lua_State *L) { Guard *guard = lua_touserdata (L, 1); if (guard->data != NULL) guard->destroy (guard->data); return 0; } gpointer * lgi_guard_create (lua_State *L, GDestroyNotify destroy) { Guard *guard = lua_newuserdata (L, sizeof (Guard)); g_assert (destroy != NULL); luaL_getmetatable (L, UD_GUARD); lua_setmetatable (L, -2); guard->data = NULL; guard->destroy = destroy; return &guard->data; } /* Converts any allowed GType kind to lightuserdata form. */ static int core_gtype (lua_State *L) { lua_pushlightuserdata (L, (gpointer) lgi_type_get_gtype (L, 1)); return 1; } /* Converts either GType or gi.info into repotype table. */ static int core_repotype (lua_State *L) { GType gtype = G_TYPE_INVALID; GIBaseInfo **info = lgi_udata_test (L, 1, LGI_GI_INFO); if (!info) gtype = lgi_type_get_gtype (L, 1); lgi_type_get_repotype (L, gtype, info ? *info : NULL); return 1; } /* Instantiate constant from given gi_info. */ static int core_constant (lua_State *L) { /* Get typeinfo of the constant. */ GIArgument val; GIConstantInfo *ci = *(GIConstantInfo **) luaL_checkudata (L, 1, LGI_GI_INFO); GITypeInfo *ti = g_constant_info_get_type (ci); lgi_gi_info_new (L, ti); g_constant_info_get_value (ci, &val); lgi_marshal_2lua (L, ti, NULL, GI_DIRECTION_IN, GI_TRANSFER_NOTHING, &val, 0, NULL, NULL); return 1; } typedef struct _LgiStateMutex { /* Pointer to either local state lock (next member of this structure) or to global package lock. */ GRecMutex *mutex; GRecMutex state_mutex; } LgiStateMutex; /* Global package lock (the one used for gdk_threads_enter/clutter_threads_enter) */ static GRecMutex package_mutex G_REC_MUTEX_INIT; /* GC method for GRecMutex structure, which lives inside lua_State. */ static int call_mutex_gc (lua_State* L) { LgiStateMutex *mutex = lua_touserdata (L, 1); g_rec_mutex_unlock (mutex->mutex); g_rec_mutex_clear (&mutex->state_mutex); return 0; } /* MT for CallMutex. */ static int call_mutex_mt; /* lightuserdata of address of this member is key to LUA_REGISTRYINDEX where CallMutex instance for this state resides. */ static int call_mutex; gpointer lgi_state_get_lock (lua_State *L) { gpointer state_lock; lua_pushlightuserdata (L, &call_mutex); lua_gettable (L, LUA_REGISTRYINDEX); state_lock = lua_touserdata (L, -1); lua_pop (L, 1); return state_lock; } void lgi_state_enter (gpointer state_lock) { LgiStateMutex *mutex = state_lock; GRecMutex *wait_on; /* There is a complication with lock switching. During the wait for the lock, someone could call core.registerlock() and thus change the lock protecting the state. Accomodate for this situation. */ for (;;) { wait_on = g_atomic_pointer_get (&mutex->mutex); g_rec_mutex_lock (wait_on); if (wait_on == mutex->mutex) break; /* The lock is changed, unlock this one and wait again. */ g_rec_mutex_unlock (wait_on); } } void lgi_state_leave (gpointer state_lock) { /* Get pointer to the call mutex belonging to this state. */ LgiStateMutex *mutex = state_lock; g_rec_mutex_unlock (mutex->mutex); } static const char* log_levels[] = { "ERROR", "CRITICAL", "WARNING", "MESSAGE", "INFO", "DEBUG", "???", NULL }; static int core_log (lua_State *L) { const char *domain = luaL_checkstring (L, 1); int level = 1 << (luaL_checkoption (L, 2, log_levels[5], log_levels) + 2); const char *message = luaL_checkstring (L, 3); g_log (domain, level, "%s", message); return 0; } static int core_yield (lua_State *L) { /* Perform yield with unlocked mutex; this might force another threads waiting on the mutex to perform what they need to do (i.e. enter Lua with callbacks). */ gpointer state_lock = lgi_state_get_lock (L); lgi_state_leave (state_lock); g_thread_yield (); lgi_state_enter (state_lock); return 0; } static void package_lock_enter (void) { g_rec_mutex_lock (&package_mutex); } static void package_lock_leave (void) { g_rec_mutex_unlock (&package_mutex); } static gpointer package_lock_register[8] = { NULL }; static int core_registerlock (lua_State *L) { void (*set_lock_functions)(GCallback, GCallback); LgiStateMutex *mutex; GRecMutex *wait_on; unsigned i; /* Get registration function. */ luaL_checktype (L, 1, LUA_TLIGHTUSERDATA); set_lock_functions = lua_touserdata (L, 1); luaL_argcheck (L, set_lock_functions != NULL, 1, "NULL function"); /* Check, whether this package was already registered. */ for (i = 0; i < G_N_ELEMENTS (package_lock_register) && package_lock_register[i] != set_lock_functions; i++) { if (package_lock_register[i] == NULL) { /* Register our package lock functions. */ package_lock_register[i] = set_lock_functions; set_lock_functions (package_lock_enter, package_lock_leave); break; } } /* Switch our statelock to actually use packagelock. */ lua_pushlightuserdata (L, &call_mutex); lua_rawget (L, LUA_REGISTRYINDEX); mutex = lua_touserdata (L, -1); wait_on = g_atomic_pointer_get (&mutex->mutex); if (wait_on != &package_mutex) { g_rec_mutex_lock (&package_mutex); g_atomic_pointer_set (&mutex->mutex, &package_mutex); g_rec_mutex_unlock (wait_on); } return 0; } static int core_band (lua_State *L) { lua_pushnumber (L, (unsigned)luaL_checknumber (L, 1) & (unsigned)luaL_checknumber (L, 2)); return 1; } static int core_bor (lua_State *L) { lua_pushnumber (L, (unsigned)luaL_checknumber (L, 1) | (unsigned)luaL_checknumber (L, 2)); return 1; } #define UD_MODULE "lgi.core.module" static int module_gc (lua_State *L) { GModule **module = luaL_checkudata (L, 1, UD_MODULE); g_module_close (*module); return 0; } static int module_index (lua_State *L) { GModule **module = luaL_checkudata (L, 1, UD_MODULE); gpointer address; if (g_module_symbol (*module, luaL_checkstring (L, 2), &address)) { lua_pushlightuserdata (L, address); return 1; } lua_pushnil (L); lua_pushstring (L, g_module_error ()); return 2; } static const struct luaL_Reg module_reg[] = { { "__gc", module_gc }, { "__index", module_index }, { NULL, NULL } }; #if defined(G_WITH_CYGWIN) #define MODULE_NAME_FORMAT_VERSION "cyg%s-%d.dll" #define MODULE_NAME_FORMAT_PLAIN "cyg%s.dll" #elif defined(G_OS_WIN32) #define MODULE_NAME_FORMAT_VERSION "lib%s-%d.dll" #define MODULE_NAME_FORMAT_PLAIN "lib%s.dll" #elif defined(__APPLE__) #define MODULE_NAME_FORMAT_VERSION "lib%s.%d.dylib" #define MODULE_NAME_FORMAT_PLAIN "lib%s.dylib" #else #define MODULE_NAME_FORMAT_VERSION "lib%s.so.%d" #define MODULE_NAME_FORMAT_PLAIN "lib%s.so" #endif /* Creates 'module' object which resolves symbol names to lightuserdata addresses. module, path = core.module(basename[, version]) */ static int core_module (lua_State *L) { char *name; /* If the version is present, combine it with basename. Except on OpenBSD, where libraries are versioned like libfoo.so.0.0 and we will always load the shared object with the highest version number. */ #ifndef __OpenBSD__ if (!lua_isnoneornil (L, 2)) name = g_strdup_printf (MODULE_NAME_FORMAT_VERSION, luaL_checkstring (L, 1), (int) luaL_checkinteger (L, 2)); else #endif name = g_strdup_printf (MODULE_NAME_FORMAT_PLAIN, luaL_checkstring (L, 1)); /* Try to load the module. */ GModule *module = g_module_open (name, 0); if (module == NULL) { lua_pushnil (L); goto end; } /* Embed the module in the userdata for the module. */ *(GModule **) lua_newuserdata (L, sizeof (module)) = module; luaL_getmetatable (L, UD_MODULE); lua_setmetatable (L, -2); end: lua_pushstring (L, name); g_free (name); return 2; } static const struct luaL_Reg lgi_reg[] = { { "log", core_log }, { "gtype", core_gtype }, { "repotype", core_repotype }, { "constant", core_constant }, { "yield", core_yield }, { "registerlock", core_registerlock }, { "band", core_band }, { "bor", core_bor }, { "module", core_module }, { NULL, NULL } }; static void create_repo_table (lua_State *L, const char *name, void *key) { lua_newtable (L); lua_pushlightuserdata (L, key); lua_pushvalue (L, -2); lua_rawset (L, LUA_REGISTRYINDEX); lua_setfield (L, -2, name); } static void set_resident (lua_State *L) { /* Get '_CLIBS' table from the registry (Lua5.2). */ lua_getfield (L, LUA_REGISTRYINDEX, "_CLIBS"); if (!lua_isnil (L, -1)) { /* Remove the very last item in they array part, which is handle to our loaded module used by _CLIBS.gctm to clean modules upon state cleanup. But before removing it, check, that it is really the handle of our module. Our module filename is passed as arg 2. */ lua_pushvalue (L, 2); lua_gettable (L, -2); lua_rawgeti (L, -2, lua_objlen (L, -2)); if (lua_equal (L, -1, -2)) { lua_pushnil (L); lua_rawseti (L, -4, lua_objlen (L, -4)); } lua_pop (L, 3); return; } else { /* This hack tries to enumerate the whole registry table and find 'LOADLIB: path' library. When it detects itself, it just removes pointer to the loaded library, disallowing Lua to close it, thus leaving it resident even when the state is closed. */ /* Note: 'nil' is on the stack from lua_getfield() call above. */ while (lua_next (L, LUA_REGISTRYINDEX)) { if (lua_type (L, -2) == LUA_TSTRING) { const char *str = lua_tostring (L, -2); if (g_str_has_prefix (str, "LOADLIB: ") && strstr (str, "corelgilua5")) { /* NULL the pointer to the loaded library. */ if (lua_type (L, -1) == LUA_TUSERDATA) { gpointer *lib = lua_touserdata (L, -1); *lib = NULL; } /* Clean the stack and return. */ lua_pop (L, 2); return; } } lua_pop (L, 1); } } } int luaopen_lgi_corelgilua51 (lua_State* L) { LgiStateMutex *mutex; /* Try to make itself resident. This is needed because this dynamic module is 'statically' linked with glib/gobject, and these libraries are not designed to be unloaded. Once they are unloaded, they cannot be safely loaded again into the same process. To avoid problems when repeately opening and closing lua_States and loading lgi into them, we try to make the whole 'core' module resident. */ set_resident (L); /* Early GLib initializations. Make sure that following fundamental G_TYPEs are already initialized. */ g_type_init (); volatile GType unused; unused = G_TYPE_DATE; unused = G_TYPE_REGEX; unused = G_TYPE_DATE_TIME; unused = G_TYPE_VARIANT_TYPE; unused = G_TYPE_STRV; unused = unused; /* Register 'guard' metatable. */ luaL_newmetatable (L, UD_GUARD); lua_pushcfunction (L, guard_gc); lua_setfield (L, -2, "__gc"); lua_pop (L, 1); /* Register 'module' metatable. */ luaL_newmetatable (L, UD_MODULE); luaL_register (L, NULL, module_reg); lua_pop (L, 1); /* Register 'call-mutex' metatable. */ lua_pushlightuserdata (L, &call_mutex_mt); lua_newtable (L); lua_pushcfunction (L, call_mutex_gc); lua_setfield (L, -2, "__gc"); lua_rawset (L, LUA_REGISTRYINDEX); /* Create call mutex guard, keep it locked initially (it is unlocked only when we are calling out to GObject-C code) and store it into the registry. */ lua_pushlightuserdata (L, &call_mutex); mutex = lua_newuserdata (L, sizeof (*mutex)); mutex->mutex = &mutex->state_mutex; g_rec_mutex_init (&mutex->state_mutex); g_rec_mutex_lock (&mutex->state_mutex); lua_pushlightuserdata (L, &call_mutex_mt); lua_rawget (L, LUA_REGISTRYINDEX); lua_setmetatable (L, -2); lua_rawset (L, LUA_REGISTRYINDEX); /* Register 'lgi.core' interface. */ lua_newtable (L); luaL_register (L, NULL, lgi_reg); /* Create repo and index table. */ create_repo_table (L, "index", &repo_index); create_repo_table (L, "repo", &repo); /* Initialize modules. */ lgi_buffer_init (L); lgi_gi_init (L); lgi_marshal_init (L); lgi_record_init (L); lgi_object_init (L); lgi_callable_init (L); /* Return registration table. */ return 1; } lua-lgi-0.7.2/lgi/core.lua000066400000000000000000000010631221440706400152600ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Lua-side core module selector -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ -- This module decides what kind of core routines should be loaded. -- Currently only one implementation exists, standard-Lua C-side -- implementation, LuaJIT-FFI-based one is planned. return require 'lgi.corelgilua51' lua-lgi-0.7.2/lgi/enum.lua000066400000000000000000000057361221440706400153070ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Support for enums and bitflags -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local setmetatable, pairs, type = setmetatable, pairs, type local core = require 'lgi.core' local gi = core.gi local component = require 'lgi.component' local band, bor = core.band, core.bor local enum = { enum_mt = component.mt:clone('enum', { '_method' }), bitflags_mt = component.mt:clone('flags', { '_method' }), } function enum.load(info, meta) local enum_type = component.create(info, meta) if info.methods then enum_type._method = component.get_category( info.methods, core.callable.new) else -- Enum.methods was added only in GI1.30; for older gi, simulate -- the access using lookup in the global namespace. local prefix = info.name:gsub('%u+[^%u]+', '%1_'):lower() local namespace = core.repo[info.namespace] enum_type._method = setmetatable( {}, { __index = function(_, name) return namespace[prefix .. name] end }) end -- Load all enum values. local values = info.values for i = 1, #values do local mi = values[i] enum_type[mi.name:upper()] = mi.value end -- Install metatable providing reverse lookup (i.e name(s) by -- value). return enum_type end -- Enum reverse mapping, value->name. function enum.enum_mt:_element(instance, value) if type(value) == 'number' then for name, val in pairs(self) do if val == value then return name end end return value else return component.mt._element(self, instance, value) end end -- Constructs enum number from specified string. function enum.enum_mt:_new(param) if type(param) == 'string' then param = self[param] end return param end -- Resolving arbitrary number to the table containing symbolic names -- of contained bits. function enum.bitflags_mt:_element(instance, value) if type(value) == 'number' then local result, remainder = {}, value for name, flag in pairs(self) do if type(flag) == 'number' and name:sub(1, 1) ~= '_' and band(value, flag) == flag then result[name] = true remainder = remainder - flag end end if remainder > 0 then result[1] = remainder end return result else return component.mt._element(self, instance, value) end end -- 'Constructs' number from specified flags (or accepts just number). function enum.bitflags_mt:_new(param) if type(param) == 'string' then return self[param] elseif type(param) == 'number' then return param else local num = 0 for key, value in pairs(param) do if type(key) == 'string' then value = key end if type(value) == 'string' then value = self[value] end num = bor(num, value) end return num end end return enum lua-lgi-0.7.2/lgi/ffi.lua000066400000000000000000000132751221440706400151040ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Helpers for custom FFI definitions -- -- Copyright (c) 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local pairs, ipairs, setmetatable, getmetatable = pairs, ipairs, setmetatable, getmetatable local math = require 'math' local core = require 'lgi.core' local gi = core.gi local component = require 'lgi.component' local enum = require 'lgi.enum' local record = require 'lgi.record' local ffi = {} local gobject = gi.require('GObject') local glib = gi.require('GLib') -- Gather all basic types. We have to 'steal' them from well-known -- declarations, because girepository API does not allow synthesizing -- GIBaseInfo instances from the air. ffi.types = { void = gobject.Callback.return_type, boolean = glib.Variant.methods.get_boolean.return_type, int8 = gobject.ParamSpecChar.fields.minimum.typeinfo, uint8 = gobject.ParamSpecUChar.fields.minimum.typeinfo, int16 = glib.Variant.methods.get_int16.return_type, uint16 = glib.Variant.methods.get_uint16.return_type, int32 = glib.Variant.methods.get_int32.return_type, uint32 = glib.Variant.methods.get_uint32.return_type, int64 = glib.Variant.methods.get_int64.return_type, uint64 = glib.Variant.methods.get_uint64.return_type, int = gobject.ParamSpecEnum.fields.default_value.typeinfo, uint = gobject.ParamSpecFlags.fields.default_value.typeinfo, long = gobject.ParamSpecLong.fields.default_value.typeinfo, ulong = gobject.ParamSpecULong.fields.default_value.typeinfo, float = gobject.ParamSpecFloat.fields.default_value.typeinfo, double = gobject.ParamSpecDouble.fields.default_value.typeinfo, utf8 = gobject.ParamSpecString.fields.default_value.typeinfo, filename = glib.file_get_contents.args[1].typeinfo, GType = gobject.ParamSpecGType.fields.is_a_type.typeinfo, ptr = glib.CompareDataFunc.args[1].typeinfo, } for name, alias in pairs { char = 'int8', uchar = 'uint8', short = 'int16', ushort = 'uint16' } do ffi.types[name] = ffi.types[alias] end -- Gets gtype from specified resolved and _get_type function name. function ffi.load_gtype(resolver, get_type_name) local addr = resolver[get_type_name] if not addr then return nil, ("`%s' not found"):format(get_type_name) end local get_gtype = core.callable.new( { name = get_type_name, addr = addr, ret = ffi.types.GType }) return get_gtype() end -- Creates new enum/flags table with all values from specified gtype. function ffi.load_enum(gtype, name) local GObject = core.repo.GObject local is_flags = GObject.Type.is_a(gtype, GObject.Type.FLAGS) local enum_component = component.create( gtype, is_flags and enum.bitflags_mt or enum.enum_mt, name) local type_class = GObject.TypeClass.ref(gtype) local enum_class = core.record.cast( type_class, is_flags and GObject.FlagsClass or GObject.EnumClass) for i = 0, enum_class.n_values - 1 do local val = core.record.fromarray(enum_class.values, i) enum_component[val.value_nick:upper():gsub('%-', '_')] = val.value end type_class:unref() return enum_component end -- Aligns offset to specified alignment. local function align(offset, align) return math.modf((offset + align - 1) / align) * align end -- Creates record from the table of the field definitions. function ffi.load_fields(rec, defs) rec._field = {} local offset = 0 local max_align = 1 local max_size = 0 for _, def in ipairs(defs) do local field = {} -- Get size and alignment of this field. local size, alignment if gi.isinfo(def[2]) then field[2] = 0 if def[2].tag == 'interface' then local ii = def[2].interface if ii.type == 'enum' or ii.type == 'flags' then size, alignment = core.marshal.typeinfo(ii.typeinfo) elseif ii.type == 'struct' or ii.type == 'union' then size, alignment = core.marshal.typeinfo(ffi.types.ptr) if not ii.is_pointer then -- Alignment is tricky; ideally we should go through -- the record and find alignment according to the -- largest alignments of the fields, but now we just -- punt and use 'ptr' as alignment. But this might -- be incorrect in case that doubles are used on 32b -- platform. -- Get size from the record descriptor. size = core.repotype(ii)._size end end else -- Basic type. size, alignment = core.marshal.typeinfo(def[2]) end else -- Either record or enum, decide according to repotable. local repotype = getmetatable(def[2])._type if repotype == 'struct' or repotype == 'union' then field[2] = 1 size, alignment = core.marshal.typeinfo(ffi.types.ptr) if not def.ptr then field[2] = 2 size = def[2]._size end elseif repotype == 'enum' or repotype == 'flags' then field[2] = 3 field[4] = def.type or ffi.types.int size, alignment = core.marshal.typeinfo(field[4]) end end -- Adjust offset according to the alignment. offset = align(offset, alignment) max_align = math.max(max_align, alignment) -- Create and add field definition. field[1] = offset field[3] = def[2] rec._field[def[1]] = field if getmetatable(rec)._type == 'union' then -- Remember largest size as the size of the union. max_size = math.max(max_size, align(size, alignment)) else -- Move offset after the field. offset = offset + size end end -- Store the total size of the record. rec._size = ((getmetatable(rec)._type == 'union') and max_size or align(offset, max_align)) end return ffi lua-lgi-0.7.2/lgi/gi.c000066400000000000000000000476631221440706400144100ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010, 2011 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Native Lua wrappers around GIRepository. */ #include #include "lgi.h" typedef GIBaseInfo *(* InfosItemGet)(GIBaseInfo* info, gint item); /* Creates new instance of info from given GIBaseInfo pointer. */ int lgi_gi_info_new (lua_State *L, GIBaseInfo *info) { if (info) { GIBaseInfo **ud_info; if (g_base_info_get_type (info) == GI_INFO_TYPE_INVALID) { g_base_info_unref (info); lua_pushnil (L); } else { ud_info = lua_newuserdata (L, sizeof (info)); *ud_info = info; luaL_getmetatable (L, LGI_GI_INFO); lua_setmetatable (L, -2); } } else lua_pushnil (L); return 1; } gpointer lgi_gi_load_function (lua_State *L, int typetable, const char *name) { GIBaseInfo **info; gpointer symbol = NULL; luaL_checkstack (L, 3, ""); lua_getfield (L, typetable, name); info = lgi_udata_test (L, -1, LGI_GI_INFO); if (info && GI_IS_FUNCTION_INFO (*info)) g_typelib_symbol (g_base_info_get_typelib (*info), g_function_info_get_symbol (*info), &symbol); else if (lua_islightuserdata (L, -1)) symbol = lua_touserdata (L, -1); lua_pop (L, 1); return symbol; } /* Userdata representing single group of infos (e.g. methods on object, fields of struct etc.). Emulates Lua table for access. */ typedef struct _Infos { GIBaseInfo *info; gint count; InfosItemGet item_get; } Infos; #define LGI_GI_INFOS "lgi.gi.infos" static int infos_len (lua_State *L) { Infos* infos = luaL_checkudata (L, 1, LGI_GI_INFOS); lua_pushnumber (L, infos->count); return 1; } static int infos_index (lua_State *L) { Infos* infos = luaL_checkudata (L, 1, LGI_GI_INFOS); gint n; if (lua_type (L, 2) == LUA_TNUMBER) { n = lua_tonumber (L, 2) - 1; luaL_argcheck (L, n >= 0 && n < infos->count, 2, "out of bounds"); return lgi_gi_info_new (L, infos->item_get (infos->info, n)); } else { const gchar *name = luaL_checkstring (L, 2); for (n = 0; n < infos->count; n++) { GIBaseInfo *info = infos->item_get (infos->info, n); if (strcmp (g_base_info_get_name (info), name) == 0) return lgi_gi_info_new (L, info); g_base_info_unref (info); } lua_pushnil (L); return 1; } } static int infos_gc (lua_State *L) { Infos *infos = luaL_checkudata (L, 1, LGI_GI_INFOS); g_base_info_unref (infos->info); return 0; } /* Creates new userdata object representing given category of infos. */ static int infos_new (lua_State *L, GIBaseInfo *info, gint count, InfosItemGet item_get) { Infos *infos = lua_newuserdata (L, sizeof (Infos)); luaL_getmetatable (L, LGI_GI_INFOS); lua_setmetatable (L, -2); infos->info = g_base_info_ref (info); infos->count = count; infos->item_get = item_get; return 1; } static const luaL_Reg gi_infos_reg[] = { { "__gc", infos_gc }, { "__len", infos_len }, { "__index", infos_index }, { NULL, NULL } }; static int info_push_transfer (lua_State *L, GITransfer transfer) { if (0); #define H(n1, n2) \ else if (transfer == GI_TRANSFER_ ## n1) \ { \ lua_pushstring (L, #n2); \ return 1; \ } H(NOTHING, none) H(CONTAINER, container) H(EVERYTHING, full) #undef H return 0; } static int info_index (lua_State *L) { GIBaseInfo **info = luaL_checkudata (L, 1, LGI_GI_INFO); const gchar *prop = luaL_checkstring (L, 2); #define INFOS(n1, n2) \ else if (strcmp (prop, #n2 "s") == 0) \ return infos_new (L, *info, \ g_ ## n1 ## _info_get_n_ ## n2 ## s (*info), \ g_ ## n1 ## _info_get_ ## n2); #define INFOS2(n1, n2, n3) \ else if (strcmp (prop, #n3) == 0) \ return infos_new (L, *info, \ g_ ## n1 ## _info_get_n_ ## n3 (*info), \ g_ ## n1 ## _info_get_ ## n2); if (strcmp (prop, "type") == 0) { switch (g_base_info_get_type (*info)) { #define H(n1, n2) \ case GI_INFO_TYPE_ ## n1: \ lua_pushstring (L, #n2); \ return 1; H(FUNCTION, function) H(CALLBACK, callback) H(STRUCT, struct) H(BOXED, boxed) H(ENUM, enum) H(FLAGS, flags) H(OBJECT, object) H(INTERFACE, interface) H(CONSTANT, constant) H(UNION, union) H(VALUE, value) H(SIGNAL, signal) H(VFUNC, vfunc) H(PROPERTY, property) H(FIELD, field) H(ARG, arg) H(TYPE, type) H(UNRESOLVED, unresolved) #undef H default: g_assert_not_reached (); } } #define H(n1, n2) \ if (strcmp (prop, "is_" #n2) == 0) \ { \ lua_pushboolean (L, GI_IS_ ## n1 ## _INFO (*info)); \ return 1; \ } H(ARG, arg) H(CALLABLE, callable) H(FUNCTION, function) H(SIGNAL, signal) H(VFUNC, vfunc) H(CONSTANT, constant) H(FIELD, field) H(PROPERTY, property) H(REGISTERED_TYPE, registered_type) H(ENUM, enum) H(INTERFACE, interface) H(OBJECT, object) H(STRUCT, struct) H(UNION, union) H(TYPE, type) H(VALUE, value); #undef H if (!GI_IS_TYPE_INFO (*info)) { if (strcmp (prop, "name") == 0) { lua_pushstring (L, g_base_info_get_name (*info)); return 1; } else if (strcmp (prop, "namespace") == 0) { lua_pushstring (L, g_base_info_get_namespace (*info)); return 1; } } if (strcmp (prop, "fullname") == 0) { lua_concat (L, lgi_type_get_name (L, *info)); return 1; } if (strcmp (prop, "deprecated") == 0) { lua_pushboolean (L, g_base_info_is_deprecated (*info)); return 1; } else if (strcmp (prop, "container") == 0) { GIBaseInfo *container = g_base_info_get_container (*info); if (container) g_base_info_ref (container); return lgi_gi_info_new (L, container); } else if (strcmp (prop, "typeinfo") == 0) { GITypeInfo *ti = NULL; if (GI_IS_ARG_INFO (*info)) ti = g_arg_info_get_type (*info); else if (GI_IS_CONSTANT_INFO (*info)) ti = g_constant_info_get_type (*info); else if (GI_IS_PROPERTY_INFO (*info)) ti = g_property_info_get_type (*info); else if (GI_IS_FIELD_INFO (*info)) ti = g_field_info_get_type (*info); if (ti) return lgi_gi_info_new (L, ti); } if (GI_IS_REGISTERED_TYPE_INFO (*info)) { if (strcmp (prop, "gtype") == 0) { GType gtype = g_registered_type_info_get_g_type (*info); if (gtype != G_TYPE_NONE) lua_pushlightuserdata (L, (void *) gtype); else lua_pushnil (L); return 1; } else if (GI_IS_STRUCT_INFO (*info)) { if (strcmp (prop, "is_gtype_struct") == 0) { lua_pushboolean (L, g_struct_info_is_gtype_struct (*info)); return 1; } else if (strcmp (prop, "size") == 0) { lua_pushnumber (L, g_struct_info_get_size (*info)); return 1; } INFOS (struct, field) INFOS (struct, method); } else if (GI_IS_UNION_INFO (*info)) { if (strcmp (prop, "size") == 0) { lua_pushnumber (L, g_struct_info_get_size (*info)); return 1; } INFOS (union, field) INFOS (union, method); } else if (GI_IS_INTERFACE_INFO (*info)) { if (strcmp (prop, "type_struct") == 0) return lgi_gi_info_new (L, g_interface_info_get_iface_struct (*info)); INFOS (interface, prerequisite) INFOS (interface, vfunc) INFOS (interface, method) INFOS (interface, constant) INFOS2 (interface, property, properties) INFOS (interface, signal); } else if (GI_IS_OBJECT_INFO (*info)) { if (strcmp (prop, "parent") == 0) return lgi_gi_info_new (L, g_object_info_get_parent (*info)); else if (strcmp (prop, "type_struct") == 0) return lgi_gi_info_new (L, g_object_info_get_class_struct (*info)); INFOS (object, interface) INFOS (object, field) INFOS (object, vfunc) INFOS (object, method) INFOS (object, constant) INFOS2 (object, property, properties) INFOS (object, signal); } } if (GI_IS_CALLABLE_INFO (*info)) { if (strcmp (prop, "return_type") == 0) return lgi_gi_info_new (L, g_callable_info_get_return_type (*info)); else if (strcmp (prop, "return_transfer") == 0) return info_push_transfer (L, g_callable_info_get_caller_owns (*info)); INFOS (callable, arg); if (GI_IS_SIGNAL_INFO (*info)) { if (strcmp (prop, "flags") == 0) { GSignalFlags flags = g_signal_info_get_flags (*info); lua_newtable (L); #define H(n1, n2) \ if ((flags & G_SIGNAL_ ## n1) != 0) \ { \ lua_pushboolean (L, 1); \ lua_setfield (L, -2, #n2); \ } H(RUN_FIRST, run_first) H(RUN_LAST, run_last) H(RUN_CLEANUP, run_cleanup) H(NO_RECURSE, no_recurse) H(DETAILED, detailed) H(ACTION, action) H(NO_HOOKS, no_hooks); #undef H return 1; } } if (GI_IS_FUNCTION_INFO (*info)) { if (strcmp (prop, "flags") == 0) { GIFunctionInfoFlags flags = g_function_info_get_flags (*info); lua_newtable (L); if (0); #define H(n1, n2) \ else if ((flags & GI_FUNCTION_ ## n1) != 0) \ { \ lua_pushboolean (L, 1); \ lua_setfield (L, -2, #n2); \ } H(IS_METHOD, is_method) H(IS_CONSTRUCTOR, is_constructor) H(IS_GETTER, is_getter) H(IS_SETTER, is_setter) H(WRAPS_VFUNC, wraps_vfunc) H(THROWS, throws); #undef H return 1; } } } if (GI_IS_ENUM_INFO (*info)) { if (strcmp (prop, "storage") == 0) { GITypeTag tag = g_enum_info_get_storage_type (*info); lua_pushstring (L, g_type_tag_to_string (tag)); return 1; } #if GLIB_CHECK_VERSION (2, 30, 0) INFOS (enum, method) #endif INFOS (enum, value); } if (GI_IS_VALUE_INFO (*info)) { if (strcmp (prop, "value") == 0) { lua_pushnumber (L, g_value_info_get_value (*info)); return 1; } } if (GI_IS_ARG_INFO (*info)) { if (strcmp (prop, "direction") == 0) { GIDirection dir = g_arg_info_get_direction (*info); if (dir == GI_DIRECTION_OUT) lua_pushstring (L, g_arg_info_is_caller_allocates (*info) ? "out-caller-alloc" : "out"); else lua_pushstring (L, dir == GI_DIRECTION_IN ? "in" : "inout"); return 1; } if (strcmp (prop, "transfer") == 0) return info_push_transfer (L, g_arg_info_get_ownership_transfer (*info)); if (strcmp (prop, "optional") == 0) { lua_pushboolean (L, g_arg_info_is_optional (*info) || g_arg_info_may_be_null (*info)); return 1; } } if (GI_IS_PROPERTY_INFO (*info)) { if (strcmp (prop, "flags") == 0) { lua_pushnumber (L, g_property_info_get_flags (*info)); return 1; } else if (strcmp (prop, "transfer") == 0) return info_push_transfer (L, g_property_info_get_ownership_transfer (*info)); } if (GI_IS_FIELD_INFO (*info)) { if (strcmp (prop, "flags") == 0) { GIFieldInfoFlags flags = g_field_info_get_flags (*info); lua_newtable (L); if (0); #define H(n1, n2) \ else if ((flags & GI_FIELD_ ## n1) != 0) \ { \ lua_pushboolean (L, 1); \ lua_setfield (L, -2, #n2); \ } H(IS_READABLE, is_readable) H(IS_WRITABLE, is_writable) #undef H return 1; } else if (strcmp (prop, "size") == 0) { lua_pushnumber (L, g_field_info_get_size (*info)); return 1; } else if (strcmp (prop, "offset") == 0) { lua_pushnumber (L, g_field_info_get_offset (*info)); return 1; } } if (GI_IS_TYPE_INFO (*info)) { GITypeTag tag = g_type_info_get_tag (*info); if (strcmp (prop, "tag") == 0) { lua_pushstring (L, g_type_tag_to_string (tag)); return 1; } else if (strcmp (prop, "is_basic") == 0) { lua_pushboolean (L, G_TYPE_TAG_IS_BASIC (tag)); return 1; } else if (strcmp (prop, "params") == 0) { if (tag == GI_TYPE_TAG_ARRAY || tag == GI_TYPE_TAG_GLIST || tag == GI_TYPE_TAG_GSLIST || tag == GI_TYPE_TAG_GHASH) { lua_newtable (L); lgi_gi_info_new (L, g_type_info_get_param_type (*info, 0)); lua_rawseti (L, -2, 1); if (tag == GI_TYPE_TAG_GHASH) { lgi_gi_info_new (L, g_type_info_get_param_type (*info, 1)); lua_rawseti (L, -2, 2); } return 1; } } else if (strcmp (prop, "interface") == 0 && tag == GI_TYPE_TAG_INTERFACE) { lgi_gi_info_new (L, g_type_info_get_interface (*info)); return 1; } else if (strcmp (prop, "array_type") == 0 && tag == GI_TYPE_TAG_ARRAY) { switch (g_type_info_get_array_type (*info)) { #define H(n1, n2) \ case GI_ARRAY_TYPE_ ## n1: \ lua_pushstring (L, #n2); \ return 1; H(C, c) H(ARRAY, array) H(PTR_ARRAY, ptr_array) H(BYTE_ARRAY, byte_array) #undef H default: g_assert_not_reached (); } } else if (strcmp (prop, "is_zero_terminated") == 0 && tag == GI_TYPE_TAG_ARRAY) { lua_pushboolean (L, g_type_info_is_zero_terminated (*info)); return 1; } else if (strcmp (prop, "array_length") == 0) { int len = g_type_info_get_array_length (*info); if (len >= 0) { lua_pushnumber (L, len); return 1; } } else if (strcmp (prop, "fixed_size") == 0) { int size = g_type_info_get_array_fixed_size (*info); if (size >= 0) { lua_pushnumber (L, size); return 1; } } else if (strcmp (prop, "is_pointer") == 0) { lua_pushboolean (L, g_type_info_is_pointer (*info)); return 1; } } lua_pushnil (L); return 1; #undef INFOS #undef INFOS2 } static int info_eq (lua_State *L) { GIBaseInfo **i1 = luaL_checkudata (L, 1, LGI_GI_INFO); GIBaseInfo **i2 = luaL_checkudata (L, 2, LGI_GI_INFO); lua_pushboolean (L, g_base_info_equal (*i1, *i2)); return 1; } static int info_gc (lua_State *L) { GIBaseInfo **info = luaL_checkudata (L, 1, LGI_GI_INFO); g_base_info_unref (*info); return 0; } static const luaL_Reg gi_info_reg[] = { { "__gc", info_gc }, { "__index", info_index }, { "__eq", info_eq }, { NULL, NULL } }; /* Userdata representing symbol resolver of the namespace. */ #define LGI_GI_RESOLVER "lgi.gi.resolver" static int resolver_index (lua_State *L) { gpointer address; GITypelib **typelib = luaL_checkudata (L, 1, LGI_GI_RESOLVER); if (g_typelib_symbol (*typelib, luaL_checkstring (L, 2), &address)) { lua_pushlightuserdata (L, address); return 1; } return 0; } static const luaL_Reg gi_resolver_reg[] = { { "__index", resolver_index }, { NULL, NULL } }; /* Userdata representing namespace in girepository. */ #define LGI_GI_NAMESPACE "lgi.gi.namespace" static int namespace_len (lua_State *L) { const gchar *ns = luaL_checkudata (L, 1, LGI_GI_NAMESPACE); lua_pushnumber (L, g_irepository_get_n_infos (NULL, ns)); return 1; } static int namespace_index (lua_State *L) { const gchar *ns = luaL_checkudata (L, 1, LGI_GI_NAMESPACE); const gchar *prop; if (lua_type (L, 2) == LUA_TNUMBER) { GIBaseInfo *info = g_irepository_get_info (NULL, ns, lua_tointeger (L, 2) - 1); return lgi_gi_info_new (L, info); } prop = luaL_checkstring (L, 2); if (strcmp (prop, "dependencies") == 0) { gchar **deps = g_irepository_get_dependencies (NULL, ns); if (deps == NULL) lua_pushnil (L); else { int index; gchar **dep; lua_newtable (L); for (index = 1, dep = deps; *dep; dep++, index++) { const gchar *sep = strchr (*dep, '-'); lua_pushlstring (L, *dep, sep - *dep); lua_pushstring (L, sep + 1); lua_settable (L, -3); } g_strfreev (deps); } return 1; } else if (strcmp (prop, "version") == 0) { lua_pushstring (L, g_irepository_get_version (NULL, ns)); return 1; } else if (strcmp (prop, "name") == 0) { lua_pushstring (L, ns); return 1; } else if (strcmp (prop, "resolve") == 0) { GITypelib **udata = lua_newuserdata (L, sizeof (GITypelib *)); luaL_getmetatable (L, LGI_GI_RESOLVER); lua_setmetatable (L, -2); *udata = g_irepository_require (NULL, ns, NULL, 0, NULL); return 1; } else /* Try to lookup the symbol. */ return lgi_gi_info_new (L, g_irepository_find_by_name (NULL, ns, prop)); } static int namespace_new (lua_State *L, const gchar *namespace) { gchar *ns = lua_newuserdata (L, strlen (namespace) + 1); luaL_getmetatable (L, LGI_GI_NAMESPACE); lua_setmetatable (L, -2); strcpy (ns, namespace); return 1; } static const luaL_Reg gi_namespace_reg[] = { { "__index", namespace_index }, { "__len", namespace_len }, { NULL, NULL } }; /* Lua API: core.gi.require(namespace[, version[, typelib_dir]]) */ static int gi_require (lua_State *L) { GError *err = NULL; const gchar *namespace = luaL_checkstring (L, 1); const gchar *version = luaL_optstring (L, 2, NULL); const gchar *typelib_dir = luaL_optstring (L, 3, NULL); GITypelib *typelib; if (typelib_dir == NULL) typelib = g_irepository_require (NULL, namespace, version, 0, &err); else typelib = g_irepository_require_private (NULL, typelib_dir, namespace, version, 0, &err); if (!typelib) { lua_pushboolean (L, 0); lua_pushstring (L, err->message); lua_pushnumber (L, err->code); g_error_free (err); return 3; } return namespace_new (L, namespace); } /* Lua API: boolean = core.gi.isinfo(info) */ static int gi_isinfo (lua_State *L) { if (lua_getmetatable (L, 1)) { luaL_getmetatable (L, LGI_GI_INFO); lua_pushboolean (L, lua_rawequal (L, -1, -2)); } else lua_pushboolean (L, 0); return 1; } static int gi_index (lua_State *L) { if (lua_type (L, 2) == LUA_TLIGHTUSERDATA) { GType gtype = (GType) lua_touserdata (L, 2); GIBaseInfo *info = (gtype != G_TYPE_INVALID) ? g_irepository_find_by_gtype (NULL, gtype) : NULL; return lgi_gi_info_new (L, info); } else { const gchar *ns = luaL_checkstring (L, 2); if (g_irepository_is_registered (NULL, ns, NULL)) return namespace_new (L, ns); } lua_pushnil (L); return 0; } typedef struct _Reg { const gchar *name; const luaL_Reg* reg; } Reg; static const Reg gi_reg[] = { { LGI_GI_INFOS, gi_infos_reg }, { LGI_GI_INFO, gi_info_reg }, { LGI_GI_NAMESPACE, gi_namespace_reg }, { LGI_GI_RESOLVER, gi_resolver_reg }, { NULL, NULL } }; static const luaL_Reg gi_api_reg[] = { { "require", gi_require }, { "isinfo", gi_isinfo }, { NULL, NULL } }; void lgi_gi_init (lua_State *L) { const Reg *reg; /* Register metatables for userdata objects. */ for (reg = gi_reg; reg->name; reg++) { luaL_newmetatable (L, reg->name); luaL_register (L, NULL, reg->reg); lua_pop (L, 1); } /* Register global API. */ lua_newtable (L); luaL_register (L, NULL, gi_api_reg); lua_newtable (L); lua_pushcfunction (L, gi_index); lua_setfield (L, -2, "__index"); lua_setmetatable (L, -2); lua_setfield (L, -2, "gi"); } #if !GLIB_CHECK_VERSION(2, 30, 0) /* Workaround for broken g_struct_info_get_size() for GValue, see https://bugzilla.gnome.org/show_bug.cgi?id=657040 */ static GIStructInfo *parameter_info = NULL; static GIFieldInfo *parameter_value_info = NULL; #undef g_struct_info_get_size gsize lgi_struct_info_get_size (GIStructInfo *info) { if (parameter_info == NULL) parameter_info = g_irepository_find_by_name (NULL, "GObject", "Parameter"); if (g_registered_type_info_get_g_type (info) == G_TYPE_VALUE) return sizeof (GValue); else if (parameter_info && g_base_info_equal (info, parameter_info)) return sizeof (GParameter); return g_struct_info_get_size (info); } #undef g_field_info_get_offset gint lgi_field_info_get_offset (GIFieldInfo *info) { if (parameter_value_info == NULL) { if (parameter_info == NULL) parameter_info = g_irepository_find_by_name (NULL, "GObject", "Parameter"); parameter_value_info = g_struct_info_get_field (parameter_info, 1); } if (parameter_value_info && g_base_info_equal (info, parameter_value_info)) return G_STRUCT_OFFSET (GParameter, value); return g_field_info_get_offset (info); } #endif lua-lgi-0.7.2/lgi/init.lua000066400000000000000000000046671221440706400153100ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Lua-side core. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local assert, require, pcall, setmetatable, pairs = assert, require, pcall, setmetatable, pairs local package = require 'package' -- Require core lgi utilities, used during bootstrap. local core = require 'lgi.core' -- Create lgi table, containing the module. local lgi = { _NAME = 'lgi', _VERSION = require 'lgi.version' } -- Forward 'yield' functionality into external interface. lgi.yield = core.yield -- If global package 'bytes' does not exist (i.e. not provided -- externally), use our internal (although incomplete) implementation. local ok, bytes = pcall(require, 'bytes') if not ok or not bytes then package.loaded.bytes = core.bytes end -- Prepare logging support. 'log' is module-exported table, containing all -- functionality related to logging wrapped around GLib g_log facility. lgi.log = require 'lgi.log' -- For the rest of bootstrap, prepare logging to lgi domain. local log = lgi.log.domain('lgi') -- Repository, table with all loaded namespaces. Its metatable takes care of -- loading on-demand. Created by C-side bootstrap. local repo = core.repo local namespace = require 'lgi.namespace' lgi.require = namespace.require -- Install 'lgi.package' method. lgi.package = require('lgi.package').ensure -- Install metatable into repo table, so that on-demand loading works. setmetatable(repo, { __index = function(_, name) return lgi.require(name) end }) -- Create lazy-loading components for base gobject entities. assert(core.gi.require ('GLib', '2.0')) assert(core.gi.require ('GObject', '2.0')) repo.GObject._precondition = {} for _, name in pairs { 'Type', 'Value', 'Closure', 'Object' } do repo.GObject._precondition[name] = 'GObject-' .. name end repo.GObject._precondition.InitiallyUnowned = 'GObject-Object' -- Create lazy-loading components for variant stuff. repo.GLib._precondition = {} for _, name in pairs { 'Variant', 'VariantType', 'VariantBuilder' } do repo.GLib._precondition[name] = 'GLib-Variant' end repo.GLib._precondition.Timer = 'GLib-Timer' -- Access to module proxies the whole repo, so that lgi.'namespace' -- notation works. return setmetatable(lgi, { __index = repo }) lua-lgi-0.7.2/lgi/lgi.h000066400000000000000000000200401221440706400145450ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Author: Pavel Holejsovsky (pavel.holejsovsky@gmail.com) * * License: MIT. */ #define G_LOG_DOMAIN "Lgi" #include #include /* Lua 5.2 compatibility stuff. */ #if LUA_VERSION_NUM >= 502 #define luaL_register(L, null, regs) luaL_setfuncs (L, regs, 0) #define lua_equal(L, p1, p2) lua_compare (L, p1, p2, LUA_OPEQ) #define lua_objlen(L, p) lua_rawlen (L, p) #define lua_setfenv(L, p) lua_setuservalue (L, p) #define lua_getfenv(L, p) lua_getuservalue (L, p) #endif #include #include #include #include #include /* Makes sure that Lua stack offset is absolute one, not relative. */ #define lgi_makeabs(L, x) do { if (x < 0) x += lua_gettop (L) + 1; } while (0) /* Puts parts of the name to the stack, to be concatenated by lua_concat. Returns number of pushed elements. */ int lgi_type_get_name (lua_State *L, GIBaseInfo *info); /* Stores repo type table associated with specified gtype (or BaseInfo if gtype is invalid). to the stack, or nil if no such table can be found in the repo. */ void lgi_type_get_repotype (lua_State *L, GType gtype, GIBaseInfo *info); /* Gets GType from Lua index narg. Accepts number and when it is other type, invokes Lua helper to convert. */ GType lgi_type_get_gtype (lua_State *L, int narg); /* Allocates guard, a pointer-size userdata with associated destroy handler. Returns pointer to user_data stored inside guard. */ gpointer *lgi_guard_create (lua_State *L, GDestroyNotify destroy); /* Creates cache table (optionally with given table __mode), stores it into registry to specified userdata address. */ void lgi_cache_create (lua_State *L, gpointer key, const char *mode); /* Initialization of modules. */ void lgi_marshal_init (lua_State *L); void lgi_record_init (lua_State *L); void lgi_object_init (lua_State *L); void lgi_callable_init (lua_State *L); void lgi_gi_init (lua_State *L); void lgi_buffer_init (lua_State *L); /* Checks whether given argument is of specified udata - similar to luaL_testudata, which is missing in Lua 5.1 */ void * lgi_udata_test (lua_State *L, int narg, const char *name); /* Metatable name of userdata for 'bytes' extension; see http://permalink.gmane.org/gmane.comp.lang.lua.general/79288 */ #define LGI_BYTES_BUFFER "bytes.bytearray" /* Metatable name of userdata - gi wrapped 'GIBaseInfo*' */ #define LGI_GI_INFO "lgi.gi.info" /* Creates new instance of info from given GIBaseInfo pointer. */ int lgi_gi_info_new (lua_State *L, GIBaseInfo *info); /* Assumes that 'typetable' can hold field 'name' which contains wrapped LGI_GI_INFO of function. Returns address of this function, NULL if table does not contain such field. */ gpointer lgi_gi_load_function(lua_State *L, int typetable, const char *name); /* Retrieve synchronization state, which can be used for entering and leaving the state using lgi_state_enter() and lgi_state_leave(). */ gpointer lgi_state_get_lock (lua_State *L); /* Enters/leaves Lua state. */ void lgi_state_enter (gpointer left_state); void lgi_state_leave (gpointer state_lock); /* Special value for 'parent' argument of marshal_2c/lua. When parent is set to this value, marshalling takes place always into pointer on the C side. This isuseful when marshalling value from/to lists, arrays and hashtables. */ #define LGI_PARENT_FORCE_POINTER G_MAXINT /* Another special value for 'parent' argument, meaning that the value should be handled as return value, according to ffi_call retval requirements. */ #define LGI_PARENT_IS_RETVAL (G_MAXINT - 1) /* Yet another special value for 'parent' argument, meaning that the value already contains address of caller-allocated space into which the result should be marshalled. */ #define LGI_PARENT_CALLER_ALLOC (G_MAXINT - 2) /* Marshalls single value from Lua to GLib/C. Returns number of temporary entries pushed to Lua stack, which should be popped before function call returns. */ int lgi_marshal_2c (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GITransfer xfer, gpointer target, int narg, int parent, GICallableInfo *ci, void **args); /* If given parameter is out:caller-allocates, tries to perform special 2c marshalling. If not needed, returns FALSE, otherwise stores single value with value prepared to be returned to C. */ gboolean lgi_marshal_2c_caller_alloc (lua_State *L, GITypeInfo *ti, GIArgument *target, int pos); /* Marshalls single value from GLib/C to Lua. If parent is non-0, it is stack index of parent structure/array in which this C value resides. */ void lgi_marshal_2lua (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GIDirection dir, GITransfer xfer, gpointer source, int parent, GICallableInfo *ci, void **args); /* Marshalls field to/from given memory (struct, union or object). Returns number of results pushed to the stack (0 or 1). */ int lgi_marshal_field (lua_State *L, gpointer object, gboolean getmode, int parent_arg, int field_arg, int val_arg); /* Implementation of object/record _access invocation. */ int lgi_marshal_access (lua_State *L, gboolean getmode, int compound_arg, int element_arg, int val_arg); /* Parses given GICallableInfo, creates new userdata for it and stores it to the stack. Uses cache, so already parsed callable held in the cache is reused if possible. */ int lgi_callable_create (lua_State *L, GICallableInfo *ci, gpointer addr); /* Creates container block for allocated closures. Returns address of the block, suitable as user_data parameter. */ gpointer lgi_closure_allocate (lua_State *L, int count); /* Allocates n-th closure in the closure block for specified Lua function (or callable table or userdata). Returns executable address for the closure. */ gpointer lgi_closure_create (lua_State* L, gpointer user_data, GICallableInfo* ci, int target, gboolean autodestroy); /* GDestroyNotify-compatible callback for destroying closure. */ void lgi_closure_destroy (gpointer user_data); /* Allocates and creates new record instance. Assumes that repotype table is on the stack, replaces it with newly created proxy. */ gpointer lgi_record_new (lua_State *L, int count); /* Creates Lua-side part of given record. Assumes that repotype table is on the stack, replaces it with newly created proxy. If parent not zero, it is stack index of record parent (i.e. record of which the arg record is part of). */ void lgi_record_2lua (lua_State *L, gpointer addr, gboolean own, int parent); /* Gets pointer to C-structure from given Lua-side object, or copies record to specified address. Expects repo typetable of expected argument pushed on the top of the stack, removes it. */ void lgi_record_2c (lua_State *L, gint narg, gpointer target, gboolean by_value, gboolean own, gboolean optional, gboolean nothrow); /* Creates Lua-side part (proxy) of given object. If the object is not owned (own == FALSE), an ownership is automatically acquired. Returns number of elements pushed to the stack, i.e. always 1. */ int lgi_object_2lua (lua_State *L, gpointer obj, gboolean own, gboolean no_sink); /* Gets pointer to C-side object represented by given Lua proxy. If gtype is not G_TYPE_INVALID, the real type is checked to conform to requested type. */ gpointer lgi_object_2c (lua_State *L, int narg, GType gtype, gboolean optional, gboolean nothrow, gboolean transfer); #if !GLIB_CHECK_VERSION(2, 30, 0) /* Workaround for broken g_struct_info_get_size() for GValue, see https://bugzilla.gnome.org/show_bug.cgi?id=657040 */ gsize lgi_struct_info_get_size (GIStructInfo *info); #define g_struct_info_get_size lgi_struct_info_get_size int lgi_field_info_get_offset (GIFieldInfo *info); #define g_field_info_get_offset lgi_field_info_get_offset #endif /* Workaround method for broken g_object_info_get_*_function_pointer() in GI 1.32.0. (see https://bugzilla.gnome.org/show_bug.cgi?id=673282) */ gpointer lgi_object_get_function_ptr (GIObjectInfo *info, const gchar *(*getter)(GIObjectInfo *)); lua-lgi-0.7.2/lgi/log.lua000066400000000000000000000020751221440706400151150ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI support for GLib-based logging. -- -- Copyright (c) 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local pcall, ipairs = pcall, ipairs local string = require 'string' local core = require 'lgi.core' local log = {} -- Creates table containing methods 'message', 'warning', 'critical', 'error', -- 'debug' methods which log to specified domain. function log.domain(name) local domain = log[name] or {} for _, level in ipairs { 'message', 'warning', 'critical', 'error', 'debug' } do if not domain[level] then domain[level] = function(format, ...) local ok, msg = pcall(string.format, format, ...) if not ok then msg = ("BAD FMT: `%s', `%s'"):format(format, msg) end core.log(name, level:upper(), msg) end end end log[name] = domain return domain end return log lua-lgi-0.7.2/lgi/marshal.c000066400000000000000000001372671221440706400154400ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010-2012 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Implements marshalling, i.e. transferring values between Lua and GLib/C. */ #include #include #include "lgi.h" /* Checks whether given argument contains number which fits given constraints. If yes, returns it, otherwise throws Lua error. */ static lua_Number check_number (lua_State *L, int narg, lua_Number val_min, lua_Number val_max) { lua_Number val = luaL_checknumber (L, narg); if (val < val_min || val > val_max) { lua_pushfstring (L, "%f is out of <%f, %f>", val, val_min, val_max); luaL_argerror (L, narg, lua_tostring (L, -1)); } return val; } typedef union { GIArgument arg; ffi_arg u; ffi_sarg s; } ReturnUnion; /* Marshals integral types to C. If requested, makes sure that the value is actually marshalled into val->v_pointer no matter what the input type is. */ static void marshal_2c_int (lua_State *L, GITypeTag tag, GIArgument *val, int narg, gboolean optional, int parent) { (void) optional; switch (tag) { #define HANDLE_INT(nameup, namelow, ptrconv, pct, val_min, val_max, ut) \ case GI_TYPE_TAG_ ## nameup: \ val->v_ ## namelow = check_number (L, narg, val_min, val_max); \ if (parent == LGI_PARENT_FORCE_POINTER) \ val->v_pointer = \ G ## ptrconv ## _TO_POINTER ((pct) val->v_ ## namelow); \ else if (sizeof (g ## namelow) <= sizeof (long) \ && parent == LGI_PARENT_IS_RETVAL) \ { \ ReturnUnion *ru = (ReturnUnion *) val; \ ru->ut = ru->arg.v_ ## namelow; \ } \ break #define HANDLE_INT_NOPTR(nameup, namelow, val_min, val_max, ut) \ case GI_TYPE_TAG_ ## nameup: \ val->v_ ## namelow = check_number (L, narg, val_min, val_max); \ g_assert (parent != LGI_PARENT_FORCE_POINTER); \ if (sizeof (g ## namelow) <= sizeof (long) \ && parent == LGI_PARENT_IS_RETVAL) \ { \ ReturnUnion *ru = (ReturnUnion *) val; \ ru->ut = ru->arg.v_ ## namelow; \ } \ break HANDLE_INT(INT8, int8, INT, gint, -0x80, 0x7f, s); HANDLE_INT(UINT8, uint8, UINT, guint, 0, 0xff, u); HANDLE_INT(INT16, int16, INT, gint, -0x8000, 0x7fff, s); HANDLE_INT(UINT16, uint16, UINT, guint, 0, 0xffff, u); HANDLE_INT(INT32, int32, INT, gint, -0x80000000LL, 0x7fffffffLL, s); HANDLE_INT(UINT32, uint32, UINT, guint, 0, 0xffffffffUL, u); HANDLE_INT(UNICHAR, uint32, UINT, guint, 0, 0x7fffffffLL, u); HANDLE_INT_NOPTR(INT64, int64, ((lua_Number) -0x7f00000000000000LL) - 1, 0x7fffffffffffffffLL, s); HANDLE_INT_NOPTR(UINT64, uint64, 0, 0xffffffffffffffffULL, u); #undef HANDLE_INT #undef HANDLE_INT_NOPTR case GI_TYPE_TAG_GTYPE: { #if GLIB_SIZEOF_SIZE_T == 4 val->v_uint32 = #else val->v_uint64 = #endif lgi_type_get_gtype (L, narg); break; } default: g_assert_not_reached (); } } /* Marshals integral types from C to Lua. */ static void marshal_2lua_int (lua_State *L, GITypeTag tag, GIArgument *val, int parent) { switch (tag) { #define HANDLE_INT(nameupper, namelower, ptrconv, ut) \ case GI_TYPE_TAG_ ## nameupper: \ if (sizeof (g ## namelower) <= sizeof (long) \ && parent == LGI_PARENT_IS_RETVAL) \ { \ ReturnUnion *ru = (ReturnUnion *) val; \ ru->arg.v_ ## namelower = (g ## namelower) ru->ut; \ } \ lua_pushnumber (L, parent == LGI_PARENT_FORCE_POINTER \ ? GPOINTER_TO_ ## ptrconv (val->v_pointer) \ : val->v_ ## namelower); \ break; HANDLE_INT(INT8, int8, INT, s); HANDLE_INT(UINT8, uint8, UINT, u); HANDLE_INT(INT16, int16, INT, s); HANDLE_INT(UINT16, uint16, UINT, u); HANDLE_INT(INT32, int32, INT, s); HANDLE_INT(UINT32, uint32, UINT, u); HANDLE_INT(UNICHAR, uint32, UINT, u); HANDLE_INT(INT64, int64, INT, s); HANDLE_INT(UINT64, uint64, UINT, u); #undef HANDLE_INT case GI_TYPE_TAG_GTYPE: lua_pushstring (L, g_type_name ( #if GLIB_SIZEOF_SIZE_T == 4 val->v_uint32 #else val->v_uint64 #endif )); break; default: g_assert_not_reached (); } } /* Gets or sets the length of the array. */ static void array_get_or_set_length (GITypeInfo *ti, gssize *get_length, gssize set_length, GICallableInfo *ci, void **args) { gint param = g_type_info_get_array_length (ti); if (param >= 0 && ci != NULL && param < g_callable_info_get_n_args (ci)) { GIArgInfo ai; GITypeInfo eti; GIArgument *val; g_callable_info_load_arg (ci, param, &ai); g_arg_info_load_type (&ai, &eti); if (g_arg_info_get_direction (&ai) == GI_DIRECTION_IN) /* For input parameters, value is directly pointed do by args table element. */ val = (GIArgument *) args[param]; else /* For output arguments, args table element points to pointer to value. */ val = *(GIArgument **) args[param]; switch (g_type_info_get_tag (&eti)) { #define HANDLE_ELT(tag, field) \ case GI_TYPE_TAG_ ## tag: \ if (get_length != NULL) \ *get_length = val->v_ ## field; \ else \ val->v_ ## field = set_length; \ break HANDLE_ELT(INT8, int8); HANDLE_ELT(UINT8, uint8); HANDLE_ELT(INT16, int16); HANDLE_ELT(UINT16, uint16); HANDLE_ELT(INT32, int32); HANDLE_ELT(UINT32, uint32); HANDLE_ELT(INT64, int64); HANDLE_ELT(UINT64, uint64); #undef HANDLE_ELT default: g_assert_not_reached (); } } } /* Retrieves pointer to GIArgument in given array, given that array contains elements of type ti. */ static gssize array_get_elt_size (GITypeInfo *ti) { gssize size = sizeof (gpointer); if (!g_type_info_is_pointer (ti)) { switch (g_type_info_get_tag (ti)) { #define HANDLE_ELT(nameupper, nametype) \ case GI_TYPE_TAG_ ## nameupper: \ return sizeof (nametype); HANDLE_ELT(BOOLEAN, gboolean); HANDLE_ELT(INT8, gint8); HANDLE_ELT(UINT8, guint8); HANDLE_ELT(INT16, gint16); HANDLE_ELT(UINT16, guint16); HANDLE_ELT(INT32, gint32); HANDLE_ELT(UINT32, guint32); HANDLE_ELT(UNICHAR, guint32); HANDLE_ELT(INT64, gint64); HANDLE_ELT(UINT64, guint64); HANDLE_ELT(FLOAT, gfloat); HANDLE_ELT(DOUBLE, gdouble); HANDLE_ELT(GTYPE, GType); #undef HANDLE_ELT case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info = g_type_info_get_interface (ti); GIInfoType type = g_base_info_get_type (info); if (type == GI_INFO_TYPE_STRUCT) size = g_struct_info_get_size (info); else if (type == GI_INFO_TYPE_UNION) size = g_union_info_get_size (info); g_base_info_unref (info); break; } default: break; } } return size; } /* Marshalls array from Lua to C. Returns number of temporary elements pushed to the stack. */ static int marshal_2c_array (lua_State *L, GITypeInfo *ti, GIArrayType atype, gpointer *out_array, gssize *out_size, int narg, gboolean optional, GITransfer transfer) { GITypeInfo* eti; gssize objlen, esize; gint index, vals = 0, to_pop, eti_guard; GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); gboolean zero_terminated; GArray *array = NULL; /* Represent nil as NULL array. */ if (optional && lua_isnoneornil (L, narg)) { *out_size = 0; *out_array = NULL; } else { /* Get element type info, create guard for it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); esize = array_get_elt_size (eti); /* Check the type. If this is C-array of byte-sized elements, we can try special-case and accept strings or buffers. */ *out_array = NULL; if (lua_type (L, narg) != LUA_TTABLE && esize == 1 && atype == GI_ARRAY_TYPE_C) { size_t size = 0; *out_array = lgi_udata_test (L, narg, LGI_BYTES_BUFFER); if (*out_array) size = lua_objlen (L, narg); else *out_array = (gpointer *) lua_tolstring (L, narg, &size); if (transfer != GI_TRANSFER_NOTHING) *out_array = g_memdup (*out_array, size); *out_size = size; } if (!*out_array) { /* Otherwise, we allow only tables. */ luaL_checktype (L, narg, LUA_TTABLE); /* Find out how long array should we allocate. */ zero_terminated = g_type_info_is_zero_terminated (ti); objlen = lua_objlen (L, narg); *out_size = g_type_info_get_array_fixed_size (ti); if (atype != GI_ARRAY_TYPE_C || *out_size < 0) *out_size = objlen; else if (*out_size < objlen) objlen = *out_size; /* Allocate the array and wrap it into the userdata guard, if needed. */ if (*out_size > 0 || zero_terminated) { array = g_array_sized_new (zero_terminated, TRUE, esize, *out_size); g_array_set_size (array, *out_size); *lgi_guard_create (L, (GDestroyNotify) g_array_unref) = array; vals = 1; } /* Iterate through Lua array and fill GArray accordingly. */ for (index = 0; index < objlen; index++) { lua_pushnumber (L, index + 1); lua_gettable (L, narg); /* Marshal element retrieved from the table into target array. */ to_pop = lgi_marshal_2c (L, eti, NULL, exfer, array->data + index * esize, -1, 0, NULL, NULL); /* Remove temporary element from the stack. */ lua_remove (L, - to_pop - 1); /* Remember that some more temp elements could be pushed. */ vals += to_pop; } /* Return either GArray or direct pointer to the data, according to the array type. */ *out_array = (atype == GI_ARRAY_TYPE_ARRAY || array == NULL) ? (void *) array : (void *) array->data; } lua_remove (L, eti_guard); } return vals; } static void marshal_2lua_array (lua_State *L, GITypeInfo *ti, GIDirection dir, GIArrayType atype, GITransfer transfer, gpointer array, gssize size, int parent) { GITypeInfo *eti; gssize len = 0, esize; gint index, eti_guard; char *data = NULL; /* Avoid propagating return value marshaling flag to array elements. */ if (parent == LGI_PARENT_IS_RETVAL) parent = 0; /* First of all, find out the length of the array. */ if (atype == GI_ARRAY_TYPE_ARRAY) { if (array) { len = ((GArray *) array)->len; data = ((GArray *) array)->data; } } else { data = array; if (g_type_info_is_zero_terminated (ti)) len = -1; else { len = g_type_info_get_array_fixed_size (ti); if (len == -1) /* Length of the array is dynamic, get it from other argument. */ len = size; } } /* Get array element type info, wrap it in the guard so that we don't leak it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); esize = array_get_elt_size (eti); /* Note that we ignore is_pointer check for uint8 type. Although it is not exactly correct, we probably would not handle uint8* correctly anyway, this is strange type to use, and moreover this is workaround for g-ir-scanner bug which might mark elements of uint8 arrays as gconstpointer, thus setting is_pointer=true on it. See https://github.com/pavouk/lgi/issues/57 */ if (g_type_info_get_tag (eti) == GI_TYPE_TAG_UINT8) { /* UINT8 arrays are marshalled as 'bytes' instances. */ if (len < 0) len = data ? strlen(data) : 0; memcpy (lua_newuserdata (L, len), data, len); luaL_getmetatable (L, LGI_BYTES_BUFFER); lua_setmetatable (L, -2); } else { if (array == NULL) { /* NULL array is represented by empty table for C arrays, nil for other types. */ if (atype == GI_ARRAY_TYPE_C) lua_newtable (L); else lua_pushnil (L); lua_remove (L, eti_guard); return; } /* Create Lua table which will hold the array. */ lua_createtable (L, len > 0 ? len : 0, 0); /* Iterate through array elements. */ for (index = 0; len < 0 || index < len; index++) { /* Get value from specified index. */ GIArgument *eval = (GIArgument *) (data + index * esize); /* If the array is zero-terminated, terminate now and don't include NULL entry. */ if (len < 0 && eval->v_pointer == NULL) break; /* Store value into the table. */ lgi_marshal_2lua (L, eti, NULL, dir, (transfer == GI_TRANSFER_EVERYTHING) ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, eval, parent, NULL, NULL); lua_rawseti (L, -2, index + 1); } } /* If needed, free the original array. */ if (transfer != GI_TRANSFER_NOTHING) { if (atype == GI_ARRAY_TYPE_ARRAY) g_array_free (array, TRUE); else g_free (array); } lua_remove (L, eti_guard); } /* Marshalls GSList or GList from Lua to C. Returns number of temporary elements pushed to the stack. */ static int marshal_2c_list (lua_State *L, GITypeInfo *ti, GITypeTag list_tag, gpointer *list, int narg, GITransfer transfer) { GITypeInfo *eti; GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); gint index, vals = 0, to_pop, eti_guard; GSList **guard = NULL; /* Allow empty list to be expressed also as 'nil', because in C, there is no difference between NULL and empty list. */ if (lua_isnoneornil (L, narg)) index = 0; else { luaL_checktype (L, narg, LUA_TTABLE); index = lua_objlen (L, narg); } /* Get list element type info, create guard for it so that we don't leak it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); /* Go from back and prepend to the list, which is cheaper than appending. */ guard = (GSList **) lgi_guard_create (L, list_tag == GI_TYPE_TAG_GSLIST ? (GDestroyNotify) g_slist_free : (GDestroyNotify) g_list_free); while (index > 0) { /* Retrieve index-th element from the source table and marshall it as pointer to arg. */ GIArgument eval; lua_pushnumber (L, index--); lua_gettable (L, narg); to_pop = lgi_marshal_2c (L, eti, NULL, exfer, &eval, -1, LGI_PARENT_FORCE_POINTER, NULL, NULL); /* Prepend new list element and reassign the guard. */ if (list_tag == GI_TYPE_TAG_GSLIST) *guard = g_slist_prepend (*guard, eval.v_pointer); else *guard = (GSList *) g_list_prepend ((GList *) *guard, eval.v_pointer); lua_remove (L, - to_pop - 1); vals += to_pop; } /* Marshalled value is kept inside the guard. */ *list = *guard; lua_remove (L, eti_guard); return vals; } static int marshal_2lua_list (lua_State *L, GITypeInfo *ti, GIDirection dir, GITypeTag list_tag, GITransfer xfer, gpointer list) { GSList *i; GITypeInfo *eti; gint index, eti_guard; /* Get element type info, guard it so that we don't leak it. */ eti = g_type_info_get_param_type (ti, 0); lgi_gi_info_new (L, eti); eti_guard = lua_gettop (L); /* Create table to which we will deserialize the list. */ lua_newtable (L); /* Go through the list and push elements into the table. */ for (i = list, index = 0; i != NULL; i = g_slist_next (i)) { /* Get access to list item. */ GIArgument *eval = (GIArgument *) &i->data; /* Store it into the table. */ lgi_marshal_2lua (L, eti, NULL, dir, (xfer == GI_TRANSFER_EVERYTHING) ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, eval, LGI_PARENT_FORCE_POINTER, NULL, NULL); lua_rawseti(L, -2, ++index); } /* Free the list, if we got its ownership. */ if (xfer != GI_TRANSFER_NOTHING) { if (list_tag == GI_TYPE_TAG_GSLIST) g_slist_free (list); else g_list_free (list); } lua_remove (L, eti_guard); return 1; } /* Marshalls hashtable from Lua to C. Returns number of temporary elements pushed to the stack. */ static int marshal_2c_hash (lua_State *L, GITypeInfo *ti, GHashTable **table, int narg, gboolean optional, GITransfer transfer) { GITypeInfo *eti[2]; GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); gint i, vals = 0, guard; GHashTable **guarded_table; GHashFunc hash_func; GEqualFunc equal_func; /* Represent nil as NULL table. */ if (optional && lua_isnoneornil (L, narg)) *table = NULL; else { /* Check the type; we allow tables only. */ luaL_checktype (L, narg, LUA_TTABLE); /* Get element type infos, create guard for it. */ guard = lua_gettop (L) + 1; for (i = 0; i < 2; i++) { eti[i] = g_type_info_get_param_type (ti, i); lgi_gi_info_new (L, eti[i]); } /* Create the hashtable and guard it so that it is destroyed in case something goes wrong during marshalling. */ guarded_table = (GHashTable **) lgi_guard_create (L, (GDestroyNotify) g_hash_table_destroy); vals++; /* Find out which hash_func and equal_func should be used, according to the type of the key. */ switch (g_type_info_get_tag (eti[0])) { case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: hash_func = g_str_hash; equal_func = g_str_equal; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: hash_func = g_int64_hash; equal_func = g_int64_equal; break; case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: return luaL_error (L, "hashtable with float or double is not " "supported"); default: /* For everything else, use direct hash of stored pointer. */ hash_func = NULL; equal_func = NULL; } *guarded_table = *table = g_hash_table_new (hash_func, equal_func); /* Iterate through Lua table and fill hashtable. */ lua_pushnil (L); while (lua_next (L, narg)) { GIArgument eval[2]; int key_pos = lua_gettop (L) - 1; /* Marshal key and value from the table. */ for (i = 0; i < 2; i++) vals += lgi_marshal_2c (L, eti[i], NULL, exfer, &eval[i], key_pos + i, LGI_PARENT_FORCE_POINTER, NULL, NULL); /* Insert newly marshalled pointers into the table. */ g_hash_table_insert (*table, eval[0].v_pointer, eval[1].v_pointer); /* The great stack suffle; remove value completely and leave key on the top of the stack. Complicated by the fact that both are burried under key_pop + val_pop elements created by marshalling. */ lua_remove (L, key_pos + 1); lua_pushvalue (L, key_pos); lua_remove (L, key_pos); } /* Remove guards for element types. */ lua_remove (L, guard); lua_remove (L, guard); } return vals; } static void marshal_2lua_hash (lua_State *L, GITypeInfo *ti, GIDirection dir, GITransfer xfer, GHashTable *hash_table) { GHashTableIter iter; GITypeInfo *eti[2]; gint i, guard; GIArgument eval[2]; /* Check for 'NULL' table, represent it simply as nil. */ if (hash_table == NULL) lua_pushnil (L); else { /* Get key and value type infos, guard them so that we don't leak it. */ guard = lua_gettop (L) + 1; for (i = 0; i < 2; i++) { eti[i] = g_type_info_get_param_type (ti, i); lgi_gi_info_new (L, eti[i]); } /* Create table to which we will deserialize the hashtable. */ lua_newtable (L); /* Go through the hashtable and push elements into the table. */ g_hash_table_iter_init (&iter, hash_table); while (g_hash_table_iter_next (&iter, &eval[0].v_pointer, &eval[1].v_pointer)) { /* Marshal key and value to the stack. */ for (i = 0; i < 2; i++) lgi_marshal_2lua (L, eti[i], NULL, dir, GI_TRANSFER_NOTHING, &eval[i], LGI_PARENT_FORCE_POINTER, NULL, NULL); /* Store these two elements to the table. */ lua_settable (L, -3); } /* Free the table, if requested. */ if (xfer != GI_TRANSFER_NOTHING) g_hash_table_unref (hash_table); lua_remove (L, guard); lua_remove (L, guard); } } static void marshal_2lua_error (lua_State *L, GITransfer xfer, GError *err) { if (err == NULL) lua_pushnil (L); else { /* Create Lua table with duplicated error information. */ lua_newtable (L); lua_pushstring (L, g_quark_to_string (err->domain)); lua_setfield (L, -2, "domain"); lua_pushstring (L, err->message); lua_setfield (L, -2, "message"); lua_pushnumber (L, err->code); lua_setfield (L, -2, "code"); /* If the ownership is transferred, free the original error. */ if (xfer != GI_TRANSFER_NOTHING) g_error_free (err); } } /* Marshalls given callable from Lua to C. */ static int marshal_2c_callable (lua_State *L, GICallableInfo *ci, GIArgInfo *ai, gpointer *callback, int narg, gboolean optional, GICallableInfo *argci, void **args) { int nret = 0; GIScopeType scope; gpointer user_data = NULL; /* Check 'nil' in optional case. In this case, return NULL as callback. */ if (optional && lua_isnoneornil (L, narg)) { *callback = NULL; return 0; } /* Check lightuserdata case; simply use that data if provided. */ if (lua_islightuserdata (L, narg)) { *callback = lua_touserdata (L, narg); return 0; } if (argci != NULL) { gint nargs = g_callable_info_get_n_args (argci); gint arg = g_arg_info_get_closure (ai); /* user_data block is already preallocated from function call. */ g_assert (args != NULL); if (arg >= 0 && arg < nargs) { user_data = ((GIArgument *) args[arg])->v_pointer; arg = g_arg_info_get_destroy (ai); if (arg >= 0 && arg < nargs) ((GIArgument *) args[arg])->v_pointer = lgi_closure_destroy; } } scope = g_arg_info_get_scope (ai); if (user_data == NULL) { /* Closure without user_data block. Create new data block, setup destruction according to scope. */ user_data = lgi_closure_allocate (L, 1); if (scope == GI_SCOPE_TYPE_CALL) { *lgi_guard_create (L, lgi_closure_destroy) = user_data; nret++; } else g_assert (scope == GI_SCOPE_TYPE_ASYNC); } /* Create the closure. */ *callback = lgi_closure_create (L, user_data, ci, narg, scope == GI_SCOPE_TYPE_ASYNC); return nret; } /* Marshalls single value from Lua to GLib/C. */ int lgi_marshal_2c (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GITransfer transfer, gpointer target, int narg, int parent, GICallableInfo *ci, void **args) { int nret = 0; gboolean optional = (parent == LGI_PARENT_CALLER_ALLOC) || (ai == NULL || (g_arg_info_is_optional (ai) || g_arg_info_may_be_null (ai))); GITypeTag tag = g_type_info_get_tag (ti); GIArgument *arg = target; /* Convert narg stack position to absolute one, because during marshalling some temporary items might be pushed to the stack, which would disrupt relative stack addressing of the value. */ lgi_makeabs(L, narg); switch (tag) { case GI_TYPE_TAG_BOOLEAN: { gboolean result; result = lua_toboolean (L, narg) ? TRUE : FALSE; if (parent == LGI_PARENT_FORCE_POINTER) arg->v_pointer = GINT_TO_POINTER (result); else if (parent == LGI_PARENT_IS_RETVAL) { ReturnUnion *ru = (ReturnUnion *) arg; ru->s = result; } else arg->v_boolean = result; break; } case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: { /* Retrieve number from given position. */ lua_Number num = (optional && lua_isnoneornil (L, narg)) ? 0 : luaL_checknumber (L, narg); /* Marshalling float/double into pointer target is not possible. */ g_return_val_if_fail (parent != LGI_PARENT_FORCE_POINTER, 0); /* Store read value into chosen target. */ if (tag == GI_TYPE_TAG_FLOAT) arg->v_float = (float) num; else arg->v_double = (double) num; break; } case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: { gchar *str = NULL; int type = lua_type (L, narg); if (type == LUA_TLIGHTUSERDATA) str = lua_touserdata (L, narg); else if (!optional || (type != LUA_TNIL && type != LUA_TNONE)) { if (type == LUA_TUSERDATA) str = (gchar *) lgi_udata_test (L, narg, LGI_BYTES_BUFFER); if (str == NULL) str = (gchar *) luaL_checkstring (L, narg); } if (tag == GI_TYPE_TAG_FILENAME) { /* Convert from UTF-8 to filename encoding. */ if (str) { str = g_filename_from_utf8 (str, -1, NULL, NULL, NULL); if (transfer != GI_TRANSFER_EVERYTHING) { /* Create temporary object on the stack which will destroy the allocated temporary filename. */ *lgi_guard_create (L, g_free) = (gpointer) str; nret = 1; } } } else if (transfer == GI_TRANSFER_EVERYTHING) str = g_strdup (str); if (parent == LGI_PARENT_FORCE_POINTER) arg->v_pointer = str; else arg->v_string = str; } break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info = g_type_info_get_interface (ti); GIInfoType type = g_base_info_get_type (info); int info_guard; lgi_gi_info_new (L, info); info_guard = lua_gettop (L); switch (type) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: /* If the argument is not numeric, convert to number first. Use enum/flags 'constructor' to do this. */ if (lua_type (L, narg) != LUA_TNUMBER) { lgi_type_get_repotype (L, G_TYPE_INVALID, info); lua_pushvalue (L, narg); lua_call (L, 1, 1); narg = -1; } /* Directly store underlying value. */ marshal_2c_int (L, g_enum_info_get_storage_type (info), arg, narg, optional, parent); /* Remove the temporary value, to keep stack balanced. */ if (narg == -1) lua_pop (L, 1); break; case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { /* Ideally the g_type_info_is_pointer() should be sufficient here, but there is some gobject-introspection quirk that some struct arguments might not be marked as pointers (e.g. g_variant_equals(), which has ctype of gconstpointer, and thus logic in girparser.c which sets is_pointer attribute fails). Workaround it by checking also argument type - structs as C function arguments are always passed as pointers. */ gboolean by_value = parent != LGI_PARENT_FORCE_POINTER && ((!g_type_info_is_pointer (ti) && ai == NULL) || parent == LGI_PARENT_CALLER_ALLOC); lgi_type_get_repotype (L, G_TYPE_INVALID, info); lgi_record_2c (L, narg, target, by_value, transfer != GI_TRANSFER_NOTHING, optional, FALSE); break; } case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: { arg->v_pointer = lgi_object_2c (L, narg, g_registered_type_info_get_g_type (info), optional, FALSE, transfer != GI_TRANSFER_NOTHING); break; } case GI_INFO_TYPE_CALLBACK: nret = marshal_2c_callable (L, info, ai, &arg->v_pointer, narg, optional, ci, args); break; default: g_assert_not_reached (); } lua_remove (L, info_guard); } break; case GI_TYPE_TAG_ARRAY: { gssize size; GIArrayType atype = g_type_info_get_array_type (ti); nret = marshal_2c_array (L, ti, atype, &arg->v_pointer, &size, narg, optional, transfer); /* Fill in array length argument, if it is specified. */ if (atype == GI_ARRAY_TYPE_C) array_get_or_set_length (ti, NULL, size, ci, args); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: nret = marshal_2c_list (L, ti, tag, &arg->v_pointer, narg, transfer); break; case GI_TYPE_TAG_GHASH: nret = marshal_2c_hash (L, ti, (GHashTable **) &arg->v_pointer, narg, optional, transfer); break; case GI_TYPE_TAG_VOID: if (g_type_info_is_pointer (ti)) { /* Check and marshal according to real Lua type. */ if (lua_isnoneornil (L, narg)) /* nil -> NULL. */ arg->v_pointer = NULL; if (lua_type (L, narg) == LUA_TSTRING) /* Use string directly. */ arg->v_pointer = (gpointer) lua_tostring (L, narg); else { int type = lua_type (L, narg); if (type == LUA_TLIGHTUSERDATA) /* Generic pointer. */ arg->v_pointer = lua_touserdata (L, narg); else { /* Check memory buffer. */ arg->v_pointer = lgi_udata_test (L, narg, LGI_BYTES_BUFFER); if (!arg->v_pointer) { /* Check object. */ arg->v_pointer = lgi_object_2c (L, narg, G_TYPE_INVALID, FALSE, TRUE, FALSE); if (!arg->v_pointer) { /* Check any kind of record. */ lua_pushnil (L); lgi_record_2c (L, narg, &arg->v_pointer, FALSE, FALSE, FALSE, TRUE); } } } } } break; default: marshal_2c_int (L, tag, arg, narg, optional, parent); } return nret; } gboolean lgi_marshal_2c_caller_alloc (lua_State *L, GITypeInfo *ti, GIArgument *val, int pos) { gboolean handled = FALSE; switch (g_type_info_get_tag (ti)) { case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *ii = g_type_info_get_interface (ti); GIInfoType type = g_base_info_get_type (ii); if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_UNION) { if (pos == 0) { lgi_type_get_repotype (L, G_TYPE_INVALID, ii); val->v_pointer = lgi_record_new (L, 1); } handled = TRUE; } g_base_info_unref (ii); break; } case GI_TYPE_TAG_ARRAY: { if (g_type_info_get_array_type (ti) == GI_ARRAY_TYPE_C) { gpointer *array_guard; if (pos == 0) { gssize elt_size, size; /* Currently only fixed-size arrays are supported. */ elt_size = array_get_elt_size (g_type_info_get_param_type (ti, 0)); size = g_type_info_get_array_fixed_size (ti); g_assert (size > 0); /* Allocate underlying array. It is temporary, existing only for the duration of the call. */ array_guard = lgi_guard_create (L, (GDestroyNotify) g_array_unref); *array_guard = g_array_sized_new (FALSE, FALSE, elt_size, size); g_array_set_size (*array_guard, size); } else { /* Convert the allocated array into Lua table with contents. We have to do it in-place. */ /* Make sure that pos is absolute, so that stack shuffling below does not change the element it points to. */ if (pos < 0) pos += lua_gettop (L) + 1; /* Get GArray from the guard and unmarshal it as a full GArray into Lua. */ array_guard = lua_touserdata (L, pos); marshal_2lua_array (L, ti, GI_DIRECTION_OUT, GI_ARRAY_TYPE_ARRAY, GI_TRANSFER_EVERYTHING, *array_guard, -1, pos); /* Deactivate old guard, everything was marshalled into the newly created and marshalled table. */ *array_guard = NULL; /* Switch old value with the new data. */ lua_replace (L, pos); } handled = TRUE; } break; } default: break; } return handled; } /* Marshalls single value from GLib/C to Lua. Returns 1 if something was pushed to the stack. */ void lgi_marshal_2lua (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GIDirection dir, GITransfer transfer, gpointer source, int parent, GICallableInfo *ci, void **args) { gboolean own = (transfer != GI_TRANSFER_NOTHING); GITypeTag tag = g_type_info_get_tag (ti); GIArgument *arg = source; /* Make sure that parent is absolute index so that it is fixed even when we add/remove from the stack. */ lgi_makeabs (L, parent); switch (tag) { case GI_TYPE_TAG_VOID: if (g_type_info_is_pointer (ti)) /* Marshal pointer to simple lightuserdata. */ lua_pushlightuserdata (L, arg->v_pointer); else lua_pushnil (L); break; case GI_TYPE_TAG_BOOLEAN: if (parent == LGI_PARENT_IS_RETVAL) { ReturnUnion *ru = (ReturnUnion *) arg; ru->arg.v_boolean = ru->s; } lua_pushboolean (L, arg->v_boolean); break; case GI_TYPE_TAG_FLOAT: case GI_TYPE_TAG_DOUBLE: g_return_if_fail (parent != LGI_PARENT_FORCE_POINTER); lua_pushnumber (L, (tag == GI_TYPE_TAG_FLOAT) ? arg->v_float : arg->v_double); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: { gchar *str = (parent == LGI_PARENT_FORCE_POINTER) ? arg->v_pointer : arg->v_string; if (tag == GI_TYPE_TAG_FILENAME && str != NULL) { gchar *utf8 = g_filename_to_utf8 (str, -1, NULL, NULL, NULL); lua_pushstring (L, utf8); g_free (utf8); } else lua_pushstring (L, str); if (transfer == GI_TRANSFER_EVERYTHING) g_free (str); break; } case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info = g_type_info_get_interface (ti); GIInfoType type = g_base_info_get_type (info); int info_guard; lgi_gi_info_new (L, info); info_guard = lua_gettop (L); switch (type) { case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: /* Prepare repotable of enum/flags on the stack. */ lgi_type_get_repotype (L, G_TYPE_INVALID, info); /* Unmarshal the numeric value. */ marshal_2lua_int (L, g_enum_info_get_storage_type (info), arg, parent); /* Get symbolic value from the table. */ lua_gettable (L, -2); /* Remove the table from the stack. */ lua_remove (L, -2); break; case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: lgi_type_get_repotype (L, G_TYPE_INVALID, info); lgi_record_2lua (L, parent == LGI_PARENT_FORCE_POINTER || g_type_info_is_pointer (ti) ? arg->v_pointer : source, own, parent); break; case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: /* Avoid sinking for input arguments, because it wreaks havoc to input arguments of vfunc callbacks during InitiallyUnowned construction phase. */ lgi_object_2lua (L, arg->v_pointer, own, dir == GI_DIRECTION_IN); break; case GI_INFO_TYPE_CALLBACK: if (arg->v_pointer == NULL) lua_pushnil (L); else { lgi_callable_create (L, info, arg->v_pointer); if (ai != NULL && args != NULL) { gint closure = g_arg_info_get_closure (ai); if (closure >= 0) { /* Store context associated with the callback to the callback object. */ GIArgument *arg = args[closure]; lua_pushlightuserdata (L, arg->v_pointer); lua_setfield (L, -2, "user_data"); } } } break; default: g_assert_not_reached (); } lua_remove (L, info_guard); } break; case GI_TYPE_TAG_ARRAY: { GIArrayType atype = g_type_info_get_array_type (ti); gssize size = -1; array_get_or_set_length (ti, &size, 0, ci, args); marshal_2lua_array (L, ti, dir, atype, transfer, arg->v_pointer, size, parent); } break; case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GLIST: marshal_2lua_list (L, ti, dir, tag, transfer, arg->v_pointer); break; case GI_TYPE_TAG_GHASH: marshal_2lua_hash (L, ti, dir, transfer, arg->v_pointer); break; case GI_TYPE_TAG_ERROR: marshal_2lua_error (L, transfer, arg->v_pointer); break; default: marshal_2lua_int (L, tag, arg, parent); } } int lgi_marshal_field (lua_State *L, gpointer object, gboolean getmode, int parent_arg, int field_arg, int val_arg) { GITypeInfo *ti; int to_remove, nret; /* Check the type of the field information. */ if (lgi_udata_test (L, field_arg, LGI_GI_INFO)) { GIFieldInfo **fi = lua_touserdata (L, field_arg); GIFieldInfoFlags flags; /* Check, whether field is readable/writable. Turn off this check for class structures, because we need to read/write their virtual function pointers. */ if (!g_struct_info_is_gtype_struct (g_base_info_get_container (*fi))) { flags = g_field_info_get_flags (*fi); if ((flags & (getmode ? GI_FIELD_IS_READABLE : GI_FIELD_IS_WRITABLE)) == 0) { /* Prepare proper error message. */ lua_concat (L, lgi_type_get_name (L, g_base_info_get_container (*fi))); return luaL_error (L, "%s: field `%s' is not %s", lua_tostring (L, -1), g_base_info_get_name (*fi), getmode ? "readable" : "writable"); } } /* Map GIArgument to proper memory location, get typeinfo of the field and perform actual marshalling. */ object = (char *) object + g_field_info_get_offset (*fi); ti = g_field_info_get_type (*fi); lgi_gi_info_new (L, ti); to_remove = lua_gettop (L); } else { /* Consult field table, get kind of field and offset. */ int kind; lgi_makeabs (L, field_arg); luaL_checktype (L, field_arg, LUA_TTABLE); lua_rawgeti (L, field_arg, 1); object = (char *) object + lua_tointeger (L, -1); lua_rawgeti (L, field_arg, 2); kind = lua_tonumber (L, -1); lua_pop (L, 2); /* Load type information from the table and decide how to handle it according to 'kind' */ lua_rawgeti (L, field_arg, 3); switch (kind) { case 0: /* field[3] contains typeinfo, load it and fall through. */ ti = *(GITypeInfo **) luaL_checkudata (L, -1, LGI_GI_INFO); to_remove = lua_gettop (L); break; case 1: case 2: { GIArgument *arg = (GIArgument *) object; if (getmode) { if (kind == 1) { object = arg->v_pointer; parent_arg = 0; } lgi_record_2lua (L, object, FALSE, parent_arg); return 1; } else { g_assert (kind == 1); lgi_record_2c (L, val_arg, arg->v_pointer, FALSE, FALSE, FALSE, FALSE); return 0; } break; } case 3: { /* Get the typeinfo for marshalling the numeric enum value. */ lua_rawgeti (L, field_arg, 4); ti = *(GITypeInfo **) luaL_checkudata (L, -1, LGI_GI_INFO); if (getmode) { /* Use typeinfo to unmarshal numeric value. */ lgi_marshal_2lua (L, ti, NULL, GI_DIRECTION_OUT, GI_TRANSFER_NOTHING, object, 0, NULL, NULL); /* Replace numeric field with symbolic value. */ lua_gettable (L, -3); lua_replace (L, -3); lua_pop (L, 1); return 1; } else { /* Convert enum symbol to numeric value. */ if (lua_type (L, val_arg != LUA_TNUMBER)) { lua_pushvalue (L, -1); lua_pushvalue (L, val_arg); lua_call (L, 1, 1); lua_replace (L, val_arg); } /* Use typeinfo to marshal the numeric value. */ lgi_marshal_2c (L, ti, NULL, GI_TRANSFER_NOTHING, object, val_arg, 0, NULL, NULL); lua_pop (L, 2); return 0; } } default: return luaL_error (L, "field has bad kind %d", kind); } } if (getmode) { lgi_marshal_2lua (L, ti, NULL, GI_DIRECTION_OUT, GI_TRANSFER_NOTHING, object, parent_arg, NULL, NULL); nret = 1; } else { lgi_marshal_2c (L, ti, NULL, GI_TRANSFER_NOTHING, object, val_arg, 0, NULL, NULL); nret = 0; } lua_remove (L, to_remove); return nret; } int lgi_marshal_access (lua_State *L, gboolean getmode, int compound_arg, int element_arg, int val_arg) { lua_getfield (L, -1, "_access"); lua_pushvalue (L, -2); lua_pushvalue (L, compound_arg); lua_pushvalue (L, element_arg); if (getmode) { lua_call (L, 3, 1); return 1; } else { lua_pushvalue (L, val_arg); lua_call (L, 4, 0); return 0; } } /* Container marshaller function. */ static int marshal_container_marshaller (lua_State *L) { GValue *value; GITypeInfo **ti; GITypeTag tag; GITransfer transfer; gpointer data; int nret = 0; gboolean get_mode = lua_isnone (L, 3); /* Get GValue to operate on. */ lgi_type_get_repotype (L, G_TYPE_VALUE, NULL); lgi_record_2c (L, 1, &value, FALSE, FALSE, FALSE, FALSE); /* Get raw pointer from the value. */ if (get_mode) { if (G_VALUE_TYPE (value) == G_TYPE_POINTER) data = g_value_get_pointer (value); else data = g_value_get_boxed (value); } /* Get info and transfer from upvalue. */ ti = lua_touserdata (L, lua_upvalueindex (1)); tag = g_type_info_get_tag (*ti); transfer = lua_tointeger (L, lua_upvalueindex (2)); switch (tag) { case GI_TYPE_TAG_ARRAY: { GIArrayType atype = g_type_info_get_array_type (*ti); gssize size = -1; if (get_mode) { if (lua_type (L, 2) == LUA_TTABLE) { lua_getfield (L, 2, "length"); size = luaL_optinteger (L, -1, -1); lua_pop (L, 1); } marshal_2lua_array (L, *ti, GI_DIRECTION_OUT, atype, transfer, data, size, 0); } else { nret = marshal_2c_array (L, *ti, atype, &data, &size, 3, FALSE, transfer); if (lua_type (L, 2) == LUA_TTABLE) { lua_pushnumber (L, size); lua_setfield (L, 2, "length"); } } break; } case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GLIST: if (get_mode) marshal_2lua_list (L, *ti, GI_DIRECTION_OUT, tag, transfer, data); else nret = marshal_2c_list (L, *ti, tag, &data, 3, transfer); break; case GI_TYPE_TAG_GHASH: if (get_mode) marshal_2lua_hash (L, *ti, GI_DIRECTION_OUT, transfer, data); else nret = marshal_2c_hash (L, *ti, (GHashTable **) &data, 3, FALSE, transfer); break; default: g_assert_not_reached (); } /* Store result pointer to the value. */ if (!get_mode) { if (G_VALUE_TYPE (value) == G_TYPE_POINTER) g_value_set_pointer (value, data); else g_value_set_boxed (value, data); } /* If there are any temporary objects, try to store them into attrs.keepalive table, if it is present. */ if (!lua_isnoneornil (L, 2)) { lua_getfield (L, 2, "keepalive"); if (!lua_isnil (L, -1)) for (lua_insert (L, -nret - 1); nret > 0; nret--) { lua_pushnumber (L, lua_objlen (L, -nret - 1)); lua_insert (L, -2); lua_settable (L, -nret - 3); lua_pop (L, 1); } else lua_pop (L, nret); lua_pop (L, 1); } else lua_pop (L, nret); return get_mode ? 1 : 0; } static const char* const transfers[] = { "none", "container", "full", NULL }; /* Creates container (array, list, slist, hash) marshaller for specified container typeinfo. Signature is: marshaller = marshal.container(typeinfo, transfer) */ static int marshal_container (lua_State *L) { GIBaseInfo **info = luaL_checkudata (L, 1, LGI_GI_INFO); GITypeTag tag = g_type_info_get_tag (*info); GITransfer transfer = luaL_checkoption (L, 2, transfers[0], transfers); if (tag == GI_TYPE_TAG_ARRAY || tag == GI_TYPE_TAG_GHASH || tag == GI_TYPE_TAG_GSLIST || tag == GI_TYPE_TAG_GLIST) { lua_pushvalue (L, 1); lua_pushnumber (L, transfer); lua_pushcclosure (L, marshal_container_marshaller, 2); } else lua_pushnil (L); return 1; } /* Fundamental marshaller closure. */ static int marshal_fundamental_marshaller (lua_State *L) { gpointer obj; gboolean get_mode = lua_isnone (L, 3); GValue *value; lgi_type_get_repotype (L, G_TYPE_VALUE, NULL); lgi_record_2c (L, 1, &value, FALSE, FALSE, FALSE, FALSE); if (get_mode) { /* Get fundamental from value. */ GIObjectInfoGetValueFunction get_value = lua_touserdata (L, lua_upvalueindex (1)); obj = get_value (value); lgi_object_2lua (L, obj, FALSE, FALSE); return 1; } else { /* Set fundamental to value. */ GIObjectInfoSetValueFunction set_value = lua_touserdata (L, lua_upvalueindex (2)); obj = lgi_object_2c (L, 3, G_TYPE_INVALID, FALSE, FALSE, FALSE); set_value (value, obj); return 0; } } /* Creates marshaller closure for specified fundamental object type. If specified object does not have custom setvalue/getvalue functions registered, returns nil. Signature is: marshaller = marshal.fundamental(gtype) */ static int marshal_fundamental (lua_State *L) { /* Find associated baseinfo. */ GIBaseInfo *info = g_irepository_find_by_gtype (NULL, lgi_type_get_gtype (L, 1)); if (info) { lgi_gi_info_new (L, info); if (GI_IS_OBJECT_INFO (info) && g_object_info_get_fundamental (info)) { GIObjectInfoGetValueFunction get_value = lgi_object_get_function_ptr (info, g_object_info_get_get_value_function); GIObjectInfoSetValueFunction set_value = lgi_object_get_function_ptr (info, g_object_info_get_set_value_function); if (get_value && set_value) { lua_pushlightuserdata (L, get_value); lua_pushlightuserdata (L, set_value); lua_pushcclosure (L, marshal_fundamental_marshaller, 2); return 1; } } } lua_pushnil (L); return 1; } /* Creates or marshalls content of GIArgument to/from lua according to specified typeinfo. arg, ptr = marshal.argument() value = marshal.argument(arg, typeinfo, transfer) marshal.argument(arg, typeinfo, transfer, value) */ static int marshal_argument (lua_State *L) { GITypeInfo **info; GITransfer transfer; GIArgument *arg; if (lua_isnone (L, 1)) { /* Create new argument userdata. */ GIArgument *arg = lua_newuserdata (L, sizeof (*arg)); memset (arg, 0, sizeof (*arg)); lua_pushlightuserdata (L, arg); return 2; } arg = lua_touserdata (L, 1); info = luaL_checkudata (L, 2, LGI_GI_INFO); transfer = luaL_checkoption (L, 3, transfers[0], transfers); if (lua_isnone (L, 4)) { lgi_marshal_2lua (L, *info, NULL, GI_DIRECTION_IN, transfer, arg, 0, NULL, NULL); return 1; } else { lua_pop (L, lgi_marshal_2c (L, *info, NULL, transfer, arg, 4, 0, NULL, NULL)); return 0; } } static int marshal_callback (lua_State *L) { gpointer user_data, addr; GICallableInfo **ci; ci = lgi_udata_test (L, 1, LGI_GI_INFO); user_data = lgi_closure_allocate (L, 1); *lgi_guard_create (L, lgi_closure_destroy) = user_data; addr = lgi_closure_create (L, user_data, *ci, 2, FALSE); lua_pushlightuserdata (L, addr); return 2; } static void gclosure_destroy (gpointer user_data, GClosure *closure) { (void) closure; lgi_closure_destroy (user_data); } /* This is workaround for missing glib function, which should look like this: void g_closure_set_marshal_with_data (GClosure *closure, GClosureMarshal marshal, gpointer user_data, GDestroyNotify destroy_notify); Such method would be introspectable. */ static int marshal_closure_set_marshal (lua_State *L) { GClosure *closure; gpointer user_data; GClosureMarshal marshal; GIBaseInfo *ci; ci = g_irepository_find_by_name (NULL, "GObject", "ClosureMarshal"); lgi_type_get_repotype (L, G_TYPE_CLOSURE, NULL); lgi_record_2c (L, 1, &closure, FALSE, FALSE, FALSE, FALSE); user_data = lgi_closure_allocate (L, 1); marshal = lgi_closure_create (L, user_data, ci, 2, FALSE); g_closure_set_marshal (closure, marshal); g_closure_add_invalidate_notifier (closure, user_data, gclosure_destroy); return 0; } /* Calculates size and alignment of specified type. size, align = marshal.typeinfo(tiinfo) */ static int marshal_typeinfo (lua_State *L) { GIBaseInfo **info = luaL_checkudata (L, 1, LGI_GI_INFO); switch (g_type_info_get_tag (*info)) { #define HANDLE_INT(upper, type) \ case GI_TYPE_TAG_ ## upper: \ { \ struct Test { char offender; type examined; }; \ lua_pushnumber (L, sizeof (type)); \ lua_pushnumber (L, G_STRUCT_OFFSET (struct Test, examined)); \ } \ break HANDLE_INT (VOID, gpointer); HANDLE_INT (BOOLEAN, gboolean); HANDLE_INT (INT8, gint8); HANDLE_INT (UINT8, guint8); HANDLE_INT (INT16, gint16); HANDLE_INT (UINT16, guint16); HANDLE_INT (INT32, gint32); HANDLE_INT (UINT32, guint32); HANDLE_INT (INT64, gint64); HANDLE_INT (UINT64, guint64); HANDLE_INT (FLOAT, gfloat); HANDLE_INT (DOUBLE, gdouble); HANDLE_INT (GTYPE, GType); HANDLE_INT (UTF8, const gchar *); HANDLE_INT (FILENAME, const gchar *); HANDLE_INT (UNICHAR, gunichar); #undef HANDLE_INT default: return luaL_argerror (L, 1, "bad typeinfo"); } return 2; } static const struct luaL_Reg marshal_api_reg[] = { { "container", marshal_container }, { "fundamental", marshal_fundamental }, { "argument", marshal_argument }, { "callback", marshal_callback }, { "closure_set_marshal", marshal_closure_set_marshal }, { "typeinfo", marshal_typeinfo }, { NULL, NULL } }; void lgi_marshal_init (lua_State *L) { /* Create 'marshal' API table in main core API table. */ lua_newtable (L); luaL_register (L, NULL, marshal_api_reg); lua_setfield (L, -2, "marshal"); } lua-lgi-0.7.2/lgi/namespace.lua000066400000000000000000000132471221440706400162730ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Support for repository namespace -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local type, rawget, next, pairs, require, pcall, setmetatable, assert = type, rawget, next, pairs, require, pcall, setmetatable, assert local package = require 'package' local core = require 'lgi.core' local enum = require 'lgi.enum' local component = require 'lgi.component' local record = require 'lgi.record' local class = require 'lgi.class' -- Table containing loaders for various GI types, indexed by -- gi.InfoType constants. local typeloader = {} typeloader['function'] = function(namespace, info) return core.callable.new(info), '_function' end function typeloader.constant(namespace, info) return core.constant(info), '_constant' end function typeloader.enum(namespace, info) return enum.load(info, enum.enum_mt), '_enum' end function typeloader.flags(namespace, info) return enum.load(info, enum.bitflags_mt), '_enum' end function typeloader.struct(namespace, info) -- Avoid exposing internal structs created for object implementations. if not info.is_gtype_struct then return record.load(info), '_struct' end end function typeloader.union(namespace, info) return record.load(info), '_union' end function typeloader.interface(namespace, info) return class.load_interface(namespace, info), '_interface' end function typeloader.object(namespace, info) return class.load_class(namespace, info), '_class' end -- Repo namespace metatable. local namespace = { mt = { _categories = { '_class', '_interface', '_struct', '_union', '_enum', '_function', '_constant', } } } -- Gets symbol of the specified namespace, if not present yet, tries to load it -- on-demand. function namespace.mt:__index(symbol) -- Check whether symbol is present in the metatable. local val = namespace.mt[symbol] if val then return val end -- Check, whether there is some precondition in the lazy-loading table. local preconditions = rawget(self, '_precondition') local precondition = preconditions and preconditions[symbol] if precondition then local package = preconditions[symbol] if not preconditions[package] then preconditions[package] = true require('lgi.override.' .. package) preconditions[package] = nil end preconditions[symbol] = nil if not next(preconditions) then self._precondition = nil end end -- Check, whether symbol is already loaded. val = component.mt._element(self, nil, symbol, namespace.mt._categories) if val then return val end -- Lookup baseinfo of requested symbol in the GIRepository. local info = core.gi[self._name][symbol] if not info then return nil end -- Decide according to symbol type what to do. local loader = typeloader[info.type] if loader then local category val, category = loader(self, info) -- Cache the symbol in specified category in the namespace. if val then local cat = rawget(self, category) if not cat then cat = {} self[category] = cat end -- Store symbol into the repo, but only if it is not already -- there. It could by added to repo as byproduct of loading -- other symbol. if not cat[symbol] then cat[symbol] = val end elseif info.is_gtype_struct then -- If we have XxxClass name, try to lookup class structure of -- the Xxx object. local class = (symbol:match('^(%w+)Class$') or symbol:match('^(%w+)Iface$') or symbol:match('^(%w+)Interface$')) if class then class = self[class] if class then val = class._class end end end else val = info end return val end -- Resolves everything in the namespace by iterating through it. function namespace.mt:_resolve(recurse) -- Iterate through all items in the namespace and dereference them, -- which causes them to be loaded in and cached inside the namespace -- table. local gi_ns = core.gi[self._name] for i = 1, #gi_ns do local ok, component = pcall(function() return self[gi_ns[i].name] end) if ok and recurse and type(component) == 'table' then local resolve = component._resolve if resolve then resolve(component, recurse) end end end return self end -- Makes sure that the namespace (optionally with requested version) -- is properly loaded. function namespace.require(name, version) -- Load the namespace info for GIRepository. This also verifies -- whether requested version can be loaded. local ns_info = assert(core.gi.require(name, version)) -- If the repository table does not exist yet, create it. local ns = rawget(core.repo, name) if not ns then ns = setmetatable({ _name = name, _version = ns_info.version, _dependencies = ns_info.dependencies }, namespace.mt) core.repo[name] = ns -- Make sure that all dependent namespaces are also loaded. for name, version in pairs(ns._dependencies or {}) do namespace.require(name, version) end -- Try to load override, if it is present. local override_name = 'lgi.override.' .. ns._name local ok, msg = pcall(require, override_name) if not ok then -- Try parsing message; if it is something different than -- "module xxx not found", then attempt to load again and let -- the exception fly out. if not msg:find("module '" .. override_name .. "' not found:", 1, true) then package.loaded[override_name] = nil require(override_name) end end end return ns end return namespace lua-lgi-0.7.2/lgi/object.c000066400000000000000000000402441221440706400152430ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010, 2011 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * GObject and GTypeInstance handling. */ #include #include "lgi.h" /* lightuserdata key to registry, containing table representing weak cache of known objects. */ static int cache; /* lightuserdata key to registry for metatable of objects. */ static int object_mt; /* lightuserdata key to registry, containing 'env' table, which maps lightuserdata(obj-addr) -> obj-env-table. */ static int env; /* Keys in 'env' table containing quark used as object's qdata for env and thread which is used from qdata destroy callback. */ enum { OBJECT_QDATA_ENV = 1, OBJECT_QDATA_THREAD }; /* Structure stored in GObject's qdata at OBJECT_QDATA_ENV. */ typedef struct _ObjectData { gpointer object; gpointer state_lock; lua_State *L; } ObjectData; /* lightuserdata key to registry, containing metatable for object env guard. */ static int env_mt; /* Structure containing object_env_guard userdata. */ typedef struct _ObjectEnvGuard { gpointer object; GQuark id; } ObjectEnvGuard; /* Checks that given narg is object type and returns pointer to type instance representing it. */ static gpointer object_check (lua_State *L, int narg) { gpointer *obj = lua_touserdata (L, narg); luaL_checkstack (L, 3, ""); if (!lua_getmetatable (L, narg)) return NULL; lua_pushlightuserdata (L, &object_mt); lua_rawget (L, LUA_REGISTRYINDEX); if (!lua_equal (L, -1, -2)) obj = NULL; lua_pop (L, 2); g_assert (obj == NULL || *obj != NULL); return obj ? *obj : NULL; } /* Walks given type and tries to find the closest known match of the object present in the repo. If found, leaves found type table on the stack and returns real found gtype, otherwise returns G_TYPE_INVALID. */ static GType object_type (lua_State *L, GType gtype) { for (; gtype != G_TYPE_INVALID; gtype = g_type_parent (gtype)) { /* Get appropriate repo table, if present. */ lgi_type_get_repotype (L, gtype, NULL); if (!lua_isnil (L, -1)) break; lua_pop (L, 1); } return gtype; } /* Throws type error for object at given argument, gtype can optionally contain name of requested type. */ static int object_type_error (lua_State *L, int narg, GType gtype) { GType found_gtype; /* Look up type table and get name from it. */ luaL_checkstack (L, 4, ""); found_gtype = object_type (L, gtype); if (found_gtype != G_TYPE_INVALID) { lua_getfield (L, -1, "_name"); lua_pushfstring (L, gtype == found_gtype ? "%s" : "%s(%s)", lua_tostring (L, -1), g_type_name (gtype)); } else { if (gtype == G_TYPE_INVALID) lua_pushliteral (L, "lgi.object"); else lua_pushstring (L, g_type_name (gtype)); } /* Create error message. */ lua_pushstring (L, lua_typename (L, lua_type (L, narg))); lua_pushfstring (L, "%s expected, got %s", lua_tostring (L, -2), lua_tostring (L, -1)); return luaL_argerror (L, narg, lua_tostring (L, -1)); } static gpointer object_get (lua_State *L, int narg) { gpointer obj = object_check (L, narg); if (G_UNLIKELY (!obj)) object_type_error (L, narg, G_TYPE_INVALID); return obj; } /* This is workaround method for broken g_object_info_get_*_function_pointer() in GI 1.32.0. (see https://bugzilla.gnome.org/show_bug.cgi?id=673282) */ gpointer lgi_object_get_function_ptr (GIObjectInfo *info, const gchar *(*getter)(GIObjectInfo *)) { gpointer func = NULL; g_base_info_ref (info); while (info != NULL) { GIBaseInfo *parent; const gchar *func_name; /* Try to get the name and the symbol. */ func_name = getter (info); if (func_name && g_typelib_symbol (g_base_info_get_typelib (info), func_name, &func)) { g_base_info_unref (info); break; } /* Iterate to the parent info. */ parent = g_object_info_get_parent (info); g_base_info_unref (info); info = parent; } return func; } /* Retrieves requested typetable function for the object. */ static gpointer object_load_function (lua_State *L, GType gtype, const gchar *name) { gpointer func = NULL; if (object_type (L, gtype) != G_TYPE_INVALID) { func = lgi_gi_load_function (L, -1, name); lua_pop (L, 1); } return func; } /* Adds one reference to the object, returns TRUE if succeded. */ static gboolean object_refsink (lua_State *L, gpointer obj, gboolean no_sink) { GType gtype = G_TYPE_FROM_INSTANCE (obj); if (G_TYPE_IS_OBJECT (gtype)) { if (G_UNLIKELY (no_sink)) g_object_ref (obj); else g_object_ref_sink (obj); return TRUE; } /* Check whether object has registered fundamental 'ref' function. */ GIObjectInfo *info = g_irepository_find_by_gtype (NULL, gtype); if (info == NULL) info = g_irepository_find_by_gtype (NULL, G_TYPE_FUNDAMENTAL (gtype)); if (info != NULL && g_object_info_get_fundamental (info)) { GIObjectInfoRefFunction ref = lgi_object_get_function_ptr (info, g_object_info_get_ref_function); g_base_info_unref (info); if (ref != NULL) { ref (obj); return TRUE; } } /* Finally check custom _refsink method in typetable. */ gpointer (*refsink_func)(gpointer) = object_load_function (L, gtype, "_refsink"); if (refsink_func) { refsink_func (obj); return TRUE; } /* There is no known wasy how to ref this kind of object. But this typically appears when handling GParamSpec, and GParamSpec handling generally works fine even without ref/unref, so the warnings produced are generally junk, so disabled until a way to handle ParamSpec properly is found. */ #if 0 g_warning ("no way to ref type `%s'", g_type_name (gtype)); #endif return FALSE; } /* Removes one reference from the object. */ static void object_unref (lua_State *L, gpointer obj) { GType gtype = G_TYPE_FROM_INSTANCE (obj); if (G_TYPE_IS_OBJECT (gtype)) { g_object_unref (obj); return; } /* Some other fundamental type, check, whether it has registered custom unref method. */ GIObjectInfo *info = g_irepository_find_by_gtype (NULL, gtype); if (info == NULL) info = g_irepository_find_by_gtype (NULL, G_TYPE_FUNDAMENTAL (gtype)); if (info != NULL && g_object_info_get_fundamental (info)) { GIObjectInfoUnrefFunction unref = lgi_object_get_function_ptr (info, g_object_info_get_unref_function); g_base_info_unref (info); if (unref != NULL) { unref (obj); return; } } void (*unref_func)(gpointer) = object_load_function (L, gtype, "_unref"); if (unref_func) { unref_func (obj); return; } #if 0 g_warning ("no way to unref type `%s'", g_type_name (gtype)); #endif } static int object_gc (lua_State *L) { object_unref (L, object_get (L, 1)); return 0; } static int object_tostring (lua_State *L) { gpointer obj = object_get (L, 1); GType gtype = G_TYPE_FROM_INSTANCE (obj); lua_getfenv (L, 1); if (!lua_isnil (L, -1)) lua_getfield (L, -1, "_name"); else lua_pushliteral (L, ""); lua_pushfstring (L, "lgi.obj %p:%s(%s)", obj, lua_tostring (L, -1), g_type_name (gtype)); return 1; } gpointer lgi_object_2c (lua_State *L, int narg, GType gtype, gboolean optional, gboolean nothrow, gboolean transfer) { gpointer obj; /* Check for nil. */ if (optional && lua_isnoneornil (L, narg)) return NULL; /* Get instance and perform type check. */ obj = object_check (L, narg); if (!nothrow && (!obj || (gtype != G_TYPE_INVALID && !g_type_is_a (G_TYPE_FROM_INSTANCE (obj), gtype)))) object_type_error (L, narg, gtype); if (transfer) object_refsink (L, obj, FALSE); return obj; } int lgi_object_2lua (lua_State *L, gpointer obj, gboolean own, gboolean no_sink) { /* NULL pointer results in nil. */ if (!obj) { lua_pushnil (L); return 1; } /* Check, whether the object is already created (in the cache). */ luaL_checkstack (L, 6, ""); lua_pushlightuserdata (L, &cache); lua_rawget (L, LUA_REGISTRYINDEX); lua_pushlightuserdata (L, obj); lua_rawget (L, -2); if (!lua_isnil (L, -1)) { /* Use the object from the cache. */ lua_replace (L, -2); /* If the object was already owned, remove one reference, because our proxy always keeps only one reference, which we already have. */ if (own) object_unref (L, obj); return 1; } /* Create new userdata object. */ *(gpointer *) lua_newuserdata (L, sizeof (obj)) = obj; lua_pushlightuserdata (L, &object_mt); lua_rawget (L, LUA_REGISTRYINDEX); lua_setmetatable (L, -2); object_type (L, G_TYPE_FROM_INSTANCE (obj)); lua_setfenv (L, -2); /* Store newly created userdata proxy into cache. */ lua_pushlightuserdata (L, obj); lua_pushvalue (L, -2); lua_rawset (L, -5); /* Stack cleanup, remove unnecessary cache and nil under userdata. */ lua_replace (L, -3); lua_pop (L, 1); /* If we don't own the object, take its ownership (and also remove floating reference if there is any). */ if (!own) object_refsink (L, obj, no_sink); return 1; } /* Worker method for __index and __newindex implementation. */ static int object_access (lua_State *L) { gboolean getmode = lua_isnone (L, 3); /* Check that 1st arg is an object and invoke one of the forms: result = type:_access(objectinstance, name) type:_access(objectinstance, name, val) */ object_get (L, 1); lua_getfenv (L, 1); return lgi_marshal_access (L, getmode, 1, 2, 3); } /* Registration table. */ static const luaL_Reg object_mt_reg[] = { { "__gc", object_gc }, { "__tostring", object_tostring }, { "__index", object_access }, { "__newindex", object_access }, { NULL, NULL } }; static const char *const query_mode[] = { "addr", "repo", NULL }; /* Queries for assorted instance properties. Lua-side prototype: res = object.query(objectinstance, mode [, iface-gtype]) Supported mode strings are: 'repo': returns repotable for this instance. 'addr': returns lightuserdata with pointer to the object. */ static int object_query (lua_State *L) { gpointer object = object_check (L, 1); if (object) { int mode = luaL_checkoption (L, 2, query_mode[0], query_mode); if (mode == 0) lua_pushlightuserdata (L, object); else lua_getfenv (L, 1); return 1; } return 0; } /* Object field accessor. Lua-side prototypes: res = object.field(objectinstance, gi.fieldinfo) object.field(objectinstance, gi.fieldinfo, newvalue) */ static int object_field (lua_State *L) { /* Check, whether we are doing set or get operation. */ gboolean getmode = lua_isnone (L, 3); /* Get object instance. */ gpointer object = object_get (L, 1); /* Call field marshalling worker. */ return lgi_marshal_field (L, object, getmode, 1, 2, 3); } static void object_data_destroy (gpointer user_data) { ObjectData *data = user_data; lua_State *L = data->L; lgi_state_enter (data->state_lock); luaL_checkstack (L, 4, NULL); /* Release 'obj' entry from 'env' table. */ lua_pushlightuserdata (L, &env); lua_rawget (L, LUA_REGISTRYINDEX); /* Deactivate env_destroy, to avoid double destruction. */ lua_pushlightuserdata (L, data->object); lua_rawget (L, -2); if (!lua_isnil (L, -1)) *(gpointer **) lua_touserdata (L, -1) = NULL; lua_pushlightuserdata (L, data->object); lua_pushnil (L); lua_rawset (L, -4); lua_pop (L, 2); /* Leave the context and destroy data structure. */ lgi_state_leave (data->state_lock); g_free (data); } static int object_env_guard_gc (lua_State *L) { ObjectEnvGuard *guard = lua_touserdata (L, -1); g_free (g_object_steal_qdata (G_OBJECT (guard->object), guard->id)); return 0; } /* Object environment table accessor. Lua-side prototype: env = object.env(objectinstance) */ static int object_env (lua_State *L) { ObjectData *data; gpointer obj = object_get (L, 1); if (!G_IS_OBJECT (obj)) /* Only GObject instances can have environment. */ return 0; /* Lookup 'env' table. */ lua_pushlightuserdata (L, &env); lua_rawget (L, LUA_REGISTRYINDEX); lua_pushlightuserdata (L, obj); lua_rawget (L, -2); if (!lua_isnil (L, -1)) /* Object's env table for the object is attached to the controlling userdata in the 'env' table. */ lua_getfenv (L, -1); else { ObjectEnvGuard *guard; /* Create new table which will serve as an object env table. */ lua_newtable (L); /* Create userdata guard, which disconnects env when the state dies. Attach the actual env table as env table to the guard udata. */ guard = lua_newuserdata (L, sizeof (ObjectEnvGuard)); guard->object = obj; lua_rawgeti (L, -4, OBJECT_QDATA_ENV); guard->id = lua_tonumber (L, -1); lua_pop (L, 1); lua_pushvalue (L, -2); lua_setfenv (L, -2); /* Store it to the 'env' table. */ lua_pushlightuserdata (L, obj); lua_pushvalue (L, -2); lua_rawset (L, -6); /* Create and fill new ObjectData structure, to attach it to object's qdata. */ data = g_new (ObjectData, 1); data->object = obj; lua_rawgeti (L, -4, OBJECT_QDATA_THREAD); data->L = lua_tothread (L, -1); data->state_lock = lgi_state_get_lock (data->L); /* Attach ObjectData to the object. */ g_object_set_qdata_full (G_OBJECT (obj), guard->id, data, object_data_destroy); lua_pop (L, 2); } return 1; } /* Creates new object. Lua-side prototypes: res = object.new(luserdata-ptr[, already_own[, no_sink]]) res = object.new(gtype, { GParameter }) */ static int object_new (lua_State *L) { if (lua_islightuserdata (L, 1)) /* Create object from the given pointer. */ return lgi_object_2lua (L, lua_touserdata (L, 1), lua_toboolean (L, 2), lua_toboolean (L, 3)); else { /* Normally Lua code uses GObject.Object.new(), which maps directly to g_object_newv(), but for some reason GOI < 1.0 does not export this method in the typelib. */ /* Get GType - 1st argument. */ GParameter *params; size_t size, i; GIBaseInfo *gparam_info; GType gtype = lgi_type_get_gtype (L, 1); luaL_checktype (L, 2, LUA_TTABLE); /* Find BaseInfo of GParameter. */ gparam_info = g_irepository_find_by_name (NULL, "GObject", "Parameter"); *lgi_guard_create (L, (GDestroyNotify) g_base_info_unref) = gparam_info; /* Prepare array of GParameter structures. */ size = lua_objlen (L, 2); params = g_newa (GParameter, size); for (i = 0; i < size; ++i) { lua_pushnumber (L, i + 1); lua_gettable (L, 2); lgi_type_get_repotype (L, G_TYPE_INVALID, gparam_info); lgi_record_2c (L, -2, ¶ms[i], TRUE, FALSE, FALSE, FALSE); lua_pop (L, 1); } /* Create the object and return it. */ return lgi_object_2lua (L, g_object_newv (gtype, size, params), TRUE, FALSE); } } /* Object API table. */ static const luaL_Reg object_api_reg[] = { { "query", object_query }, { "field", object_field }, { "new", object_new }, { "env", object_env }, { NULL, NULL } }; void lgi_object_init (lua_State *L) { char *id; /* Register metatable. */ lua_pushlightuserdata (L, &object_mt); lua_newtable (L); luaL_register (L, NULL, object_mt_reg); lua_rawset (L, LUA_REGISTRYINDEX); /* Initialize object cache. */ lgi_cache_create (L, &cache, "v"); /* Create table for 'env' tables. */ lua_pushlightuserdata (L, &env); lua_newtable (L); /* Add OBJECT_QDATA_ENV quark to env table. */ id = g_strdup_printf ("lgi:%p", L); lua_pushnumber (L, g_quark_from_string (id)); g_free (id); lua_rawseti (L, -2, OBJECT_QDATA_ENV); /* Add OBJECT_QDATA_THREAD to env table. */ lua_newthread (L); lua_rawseti (L, -2, OBJECT_QDATA_THREAD); /* Add 'env' table to the registry. */ lua_rawset (L, LUA_REGISTRYINDEX); /* Register env_mt table. */ lua_pushlightuserdata (L, &env_mt); lua_newtable (L); lua_pushcfunction (L, object_env_guard_gc); lua_setfield (L, -2, "__gc"); lua_rawset (L, LUA_REGISTRYINDEX); /* Create object API table and set it to the parent. */ lua_newtable (L); luaL_register (L, NULL, object_api_reg); lua_setfield (L, -2, "object"); } lua-lgi-0.7.2/lgi/override/000077500000000000000000000000001221440706400154445ustar00rootroot00000000000000lua-lgi-0.7.2/lgi/override/Clutter.lua000066400000000000000000000027011221440706400175710ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Clutter override module. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local select, type, pairs, setmetatable, error = select, type, pairs, setmetatable, error local lgi = require 'lgi' local core = require 'lgi.core' local Clutter = lgi.Clutter Clutter.Container._attribute = {} function Clutter.Container:add(...) local args = { ... } for i = 1, #args do Clutter.Container.add_actor(self, args[i]) end end -- Provides pseudo-attribute 'meta' for accessing container's -- child-meta elements. local container_child_meta_mt = {} function container_child_meta_mt:__index(child) return self._container:get_child_meta(child) end Clutter.Container._attribute.meta = {} function Clutter.Container._attribute.meta:get() return setmetatable({ _container = self }, container_child_meta_mt) end -- Take over internal Clutter synchronization lock and initialize -- Clutter's threading. core.registerlock(core.gi.Clutter.resolve.clutter_threads_set_lock_functions) Clutter.threads_init() -- Automatically initialize clutter, avoid continuing if -- initialization fails. local status = Clutter.init() if status ~= 'SUCCESS' then error(("Clutter initialization failed: %s"):format(status)) end lua-lgi-0.7.2/lgi/override/GLib-Timer.lua000066400000000000000000000017321221440706400200450ustar00rootroot00000000000000------------------------------------------------------------------------------- -- -- LGI GLib Timer support implementation. -- -- Copyright (c) 2013 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------- local pairs = pairs local lgi = require 'lgi' local core = require 'lgi.core' local record = require 'lgi.record' local ffi = require 'lgi.ffi' local ti = ffi.types local Timer = lgi.GLib.Timer:_resolve(true) local module = core.gi.GLib.resolve for name, def in pairs { new = { ret = { Timer, xfer = true } }, elapsed = { ret = ti.double, { Timer }, { ti.ulong, dir = 'out' } }, } do local _ = Timer[name] def.addr = module['g_timer_' .. name] Timer._method[name] = core.callable.new(def) end Timer._free = core.gi.GLib.Timer.methods.destroy Timer._method.destroy = nil Timer._new = function(_, ...) return Timer.new(...) end lua-lgi-0.7.2/lgi/override/GLib-Variant.lua000066400000000000000000000254271221440706400204000ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI GLib Variant support implementation. -- -- Copyright (c) 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local select, type, pairs, tostring, setmetatable, error, assert = select, type, pairs, tostring, setmetatable, error, assert local lgi = require 'lgi' local core = require 'lgi.core' local bytes = require 'bytes' local gi = core.gi local GLib = lgi.GLib local Variant = GLib.Variant local variant_info = gi.GLib.Variant -- Add custom methods for variant handling. Variant._refsink = variant_info.methods.ref_sink Variant._free = variant_info.methods.unref Variant._setvalue = gi.GObject.Value.methods.set_variant Variant._getvalue = gi.GObject.Value.methods.get_variant -- Add 'type' property to variant, an alias to get_type(). Variant._attribute = { type = { get = Variant.get_type_string } } local VariantBuilder = GLib.VariantBuilder local VariantType = GLib.VariantType -- VariantBuilder and VariantType are boxed only in glib-2.29 and -- newer, add custom _free recipe for older glibs. if not VariantBuilder._gtype then VariantBuilder._free = gi.GLib.VariantBuilder.methods.unref end if not VariantType._gtype then VariantBuilder._free = gi.GLib.VariantType.methods.free end -- Add constants containing basic variant types. for k, v in pairs { BOOLEAN = 'b', BYTE = 'y', INT16 = 'n', UINT16 = 'q', INT32 = 'i', UINT32 = 'u', INT64 = 'x', UINT64 = 't', DOUBLE = 'd', STRING = 's', OBJECT_PATH = 'o', SIGNATURE = 'g', VARIANT = 'v', ANY = '*', BASIC = '?', MAYBE = 'm*', ARRAY = 'a*', TUPLE = 'r', UNIT = '()', DICT_ENTRY = '{?*}', DICTIONARY = 'a{?*}', STRING_ARRAY = 'as', BYTESTRING = 'ay', BYTESTRING_ARRAY = 'aay', } do VariantType[k] = VariantType.new(v) end -- g_variant_get_type() is hidden by g-i (because scanner thinks that -- this is GType getter), so provide manual override. function Variant:get_type() return VariantType.new(Variant.get_type_string(self)) end -- Implementation of Variant.new() from type and value. local variant_new local variant_basic_typemap = { b = 'boolean', y = 'byte', n = 'int16', q = 'uint16', i = 'int32', u = 'uint32', x = 'int64', t = 'uint64', d = 'double', s = 'string', o = 'object_path', g = 'signature', } -- Checks validity of variant type format beginning at pos, return -- position in format string after end of valid part. Returns nil -- when format is not valid. local function read_format(format, pos, basic) local t = format:sub(pos, pos) pos = pos + 1 if variant_basic_typemap[t] then return pos elseif basic then return nil elseif t =='v' then return pos elseif t == 'a' or t == 'm' then return read_format(format, pos) elseif t == '{' then pos = read_format(format, pos, true) if pos then pos = read_format(format, pos) end if not pos or format:sub(pos, pos) ~= '}' then return nil end return pos + 1 elseif t == '(' then while format:sub(pos, pos) ~= ')' do pos = read_format(format, pos) if not pos then return nil end end return pos + 1 end end local function variant_new_basic(format, val) local func = variant_basic_typemap[format] if not func then return end local v = Variant['new_' .. func](val) if not v then error(("Variant.new(`%s') - invalid source value"):format(format)) end return v end function variant_new(format, pos, val) local t = format:sub(pos, pos) pos = pos + 1 local variant = variant_new_basic(t, val) if variant then return variant, pos elseif t == 'v' then return Variant.new_variant(val), pos elseif t == 'm' then local epos if val then variant, epos = variant_new(format, pos, val) else epos = read_format(format, pos) if not epos then return nil end end return Variant.new_maybe(VariantType.new(format:sub(pos, epos - 1)), variant), epos elseif t == 'a' then if format:sub(pos, pos) == 'y' then -- Bytestring is just simple Lua string. return Variant.new_bytestring(val), pos + 1 end local epos = read_format(format, pos) if not epos then return nil end local et = VariantType.new(format:sub(pos, epos - 1)) local builder = VariantBuilder.new(VariantType.new_array(et)) if et:is_subtype_of(VariantType.DICT_ENTRY) then -- Map dictionary to Lua table directly. for k, v in pairs(val) do builder:add_value(Variant.new_dict_entry( variant_new(format, pos + 1, k), variant_new(format, pos + 2, v))) end else -- We have an issue with 'array with holes'. An attempt is -- made here to work around it with 'n' field, if present. for i = 1, val.n or #val do builder:add_value(variant_new(format, pos, val[i])) end end return builder:_end(), epos elseif t == '(' or t == '{' then -- Extract and check whole tuple or entry format. local epos = read_format(format, pos -1) if not epos then return nil end -- Prepare builder with specified format. local builder = VariantBuilder.new( VariantType.new(format:sub(pos - 1, epos - 1))) -- Loop through provided value array and build variant using -- prepared builder. local i = 1 while not format:sub(pos, pos):match('^[%)}]') do local v, epos = variant_new(format, pos, val[i]) if not v then return nil end builder:add_value(v) pos = epos i = i + 1 end return builder:_end(), pos + 1 end end -- Variant.new() is just a facade over variant_new backend. function Variant.new(vt, val) if type(vt) ~= 'string' then vt = vt:dup_string() end local v, epos = variant_new(vt, 1, val) if not v or epos ~= #vt + 1 then error(("Variant.new(`%s') - invalid type"):format(vt)) end return v end function Variant:_new(...) return Variant.new(...) end -- Implement VariantBuilder:add() using the same facade. function VariantBuilder:add(type, val) VariantBuilder.add_value(Variant.new(type, val)) end -- Converts variant to nearest possible Lua value, but leaves arrays -- intact (use indexing and/or iterators for handling arrays). local simple_unpack_map = { b = 'boolean', y = 'byte', n = 'int16', q = 'uint16', i = 'int32', u = 'uint32', x = 'int64', t = 'uint64', d = 'double', s = 'string', o = 'string', g = 'string', v = 'variant' } local function variant_get(v) local type = v:get_type_string() local func = simple_unpack_map[type] if func then return Variant['get_' .. func](v) elseif type:match('^m') then return v:n_children() == 1 and variant_get(v:get_child_value(0)) or nil elseif type:match('^[{(r]') then -- Unpack dictionary entry or tuple into array. local array = { n = v:n_children() } for i = 1, array.n do array[i] = variant_get(v:get_child_value(i - 1)) end return array elseif Variant.is_of_type(v, VariantType.BYTESTRING) then return tostring(Variant.get_bytestring(v)) elseif Variant.is_of_type(v, VariantType.DICTIONARY) then -- Return proxy table which dynamically looks up items in the -- target variant. local meta = {} if Variant.is_of_type(v, VariantType.new('a{s*}')) then -- Use g_variant_lookup_value. function meta:__index(key) local found = Variant.lookup_value(v, key) return found and variant_get(found) end else -- Custom search, walk key-by-key. Cache key positions in -- the meta table. function meta:__index(key) for i = 0, Variant.n_children(v) - 1 do local entry = Variant.get_child_value(v, i) local vkey = variant_get(Variant.get_child_value(entry, 0)) if vkey == key then local found = Variant.get_child_value(entry, 1) return found and variant_get(found) end end end end return setmetatable({}, meta) end -- No simple unpacking is possible, return just self. Complex -- compound types are meant to be accessed by indexing or -- iteration, implemented below. return v end -- Map simple unpacking to reading 'value' property. Variant._attribute.value = { get = variant_get } -- Define meaning of # and number-indexing to children access. Note -- that GVariant g_asserts when these methods are invoked on variants -- of inappropriate type, so we have to check manually before. function Variant:_len() return self:is_container() and self:n_children() or 0 end local variant_element = Variant._element function Variant:_element(variant, name) -- If number is requested, consider it a special operation, -- indexing a variant. if type(name) == 'number' then return name, '_index' end return variant_element(self, variant, name) end function Variant:_access_index(variant, index, ...) assert(select('#', ...) == 0, 'GLib.Variant is not writable') if (Variant.is_container(variant) and Variant.n_children(variant) >= index) then return Variant.get_child_value(variant, index - 1).value end end -- Implementation of iterators over compound variant (simulating -- standard Lua pairs() and ipairs() methods). local function variant_inext(parent, index) index = index + 1 if index <= #parent then return index, parent[index] end end function Variant:ipairs() return variant_inext, self, 0 end function Variant:pairs() if self:is_of_type(VariantType.DICTIONARY) then -- For dictionaries, provide closure iterator which goes through -- all key-value pairs of the parent. local index = 0 return function() index = index + 1 if index <= #self then local child = self[index] return child[1], child[2] end end end -- For non-dictionaries, pairs() is the same as ipairs(). return self:ipairs() end -- Serialization support. Override Variant:get_data() with safer -- method which fills size to the resulting ref. Variant._attribute.data = {} function Variant._attribute.data:get() local buffer = bytes.new(Variant.get_size(self)) Variant.store(self, buffer) return buffer end -- Map get_data to read-only 'data' property. -- Override for new_from_data. Takes care mainly about tricky -- DestroyNotify handling. local variant_new_from_data = Variant.new_from_data function Variant.new_from_data(vt, data, trusted) if type(vt) == 'string' then vt = VariantType.new(vt) end if trusted == nil then trusted = true end return variant_new_from_data( vt, data, trusted, -- DestroyNotify implemented as closure which holds 'data' value -- as an upvalue. The 'notify' argument is scope-async, which -- means that closure together with its upvalue will be -- destroyed after called. Up to that time 'data' is safely -- held in upvalue for this closure. function() data = nil end) end lua-lgi-0.7.2/lgi/override/GLib.lua000066400000000000000000000010551221440706400167650ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI GLib root override module. -- -- Copyright (c) 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local select, type, pairs = select, type, pairs local core = require 'lgi.core' local GLib = core.repo.GLib GLib._constant = GLib._constant or {} GLib._constant.SOURCE_CONTINUE = true GLib._constant.SOURCE_REMOVE = false lua-lgi-0.7.2/lgi/override/GObject-Closure.lua000066400000000000000000000225431221440706400211040ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI GClosure handling and marshalling of callables in GValues -- arrays as arguments. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local type, pairs, ipairs, unpack = type, pairs, ipairs, unpack or table.unpack local core = require 'lgi.core' local gi = core.gi local repo = core.repo local Type, Value = repo.GObject.Type, repo.GObject.Value -- Implementation of closure support, together with marshalling. local Closure = repo.GObject.Closure local closure_info = gi.GObject.Closure -- CallInfo is object based on GICallable, allowing marshalling -- from/to GValue arrays. local CallInfo = {} CallInfo.__index = CallInfo -- Compile callable_info into table which allows fast marshalling function CallInfo.new(callable_info, to_lua) local self = setmetatable( { has_self = (callable_info.is_signal or callable_info.is_virtual) }, CallInfo) local argc, gtype = 0 -- If this is a C array with explicit length argument, mark it. local function mark_array_length(cell, ti) local len = ti.array_length if len then cell.len_index = 1 + len + (self.has_self and 1 or 0) if not self[cell.len_index] then self[cell.len_index] = {} end self[cell.len_index].internal = true end end -- Fill in 'self' argument. if self.has_self then argc = 1 gtype = callable_info.container.gtype self[1] = { dir = 'in', gtype = gtype, [to_lua and 'to_lua' or 'to_value'] = Value.find_marshaller(gtype) } end -- Go through arguments. local phantom_return for i = 1, #callable_info.args do local ai = callable_info.args[i] local ti = ai.typeinfo -- Prepare parameter cell in self array. argc = argc + 1 if not self[argc] then self[argc] = {} end local cell = self[argc] -- Fill in marshaller(s) for the cell. cell.dir = ai.direction if cell.dir == 'in' then -- Direct marshalling into value. cell.gtype = Type.from_typeinfo(ti) local marshaller = Value.find_marshaller(cell.gtype, ti, ti.transfer) cell[to_lua and 'to_lua' or 'to_value'] = marshaller else -- Indirect marshalling, value contains just pointer to the -- real storage pointer. Used for inout and out arguments. cell.gtype = Type.POINTER local marshaller = Value.find_marshaller(cell.gtype) if to_lua then if cell.dir == 'inout' then function cell.to_lua(value, params) local arg = marshaller(value, nil) return core.marshal.argument(arg, ti, ti.transfer) end end function cell.to_value(value, params, val) local arg = marshaller(value, nil) core.marshal.argument(arg, ti, ti.transfer, val) end else function cell.to_value(value, params, val) local arg, ptr = core.marshal.argument() params[cell] = arg marshaller(value, nil, ptr) if cell.dir == 'inout' then -- Marshal input to the argument. core.marshal.argument(arg, ti, ti.transfer, val) else -- Returning true indicates that input argument should -- actually not be consumed, because we are just -- preparing slot for the output value. return true end end function cell.to_lua(value, params) local arg = params[cell] return core.marshal.argument(arg, ti, ti.transfer) end end end mark_array_length(cell, ti) -- Check for output parameters; if present, enable -- phantom-return heuristics. phantom_return = phantom_return or cell.dir == 'out' end -- Prepare retval marshalling. local ti = callable_info.return_type if ti.tag ~= 'void' or ti.is_pointer then gtype = Type.from_typeinfo(ti) local ret = { dir = 'out', gtype = gtype, to_value = Value.find_marshaller( gtype, ti, callable_info.return_transfer) } mark_array_length(ret, ti) if phantom_return and ti.tag == 'gboolean' then self.phantom = ret else self.ret = ret end end return self end -- Marshal single call_info cell (either input or output). local function marshal_cell( call_info, cell, direction, args, argc, marshalling_params, value, params, retval) local marshaller = cell[direction] if not marshaller or cell.internal then return argc end argc = argc + 1 local length_marshaller if cell.len_index then -- Prepare length argument marshaller. length_marshaller = call_info[cell.len_index][direction] if direction == 'to_lua' then marshalling_params.length = length_marshaller( params[cell.len_index], {}) end end if direction == 'to_lua' then -- Marshal from GValue to Lua args[argc] = marshaller(value, marshalling_params) else -- Marshal from Lua to GValue if marshaller(value, marshalling_params, args[argc]) then -- When true is returned, we were just preparing slot for the -- output value, so do not consume the argument. argc = argc - 1 end -- Marshal array length output, if applicable. if length_marshaller then length_marshaller(params[cell.len_index], {}, marshalling_params.length) end -- Marshal phantom return, if applicable. if retval and call_info.phantom and args[argc] == nil then call_info.phantom.to_value(retval, marshalling_params, false) end end return argc end -- Creates GClosure marshaller based on compiled CallInfo. function CallInfo:get_closure_marshaller(target) return function(closure, retval, params) local marshalling_params = { keepalive = {} } local args, argc = {}, 0 -- Marshal input arguments. for i = 1, #self do argc = marshal_cell( self, self[i], 'to_lua', args, argc, marshalling_params, params[i], params) end -- Do the call. args = { target(unpack(args, 1, argc)) } argc = 0 marshalling_params.keepalive = {} -- Marshall the return value. if self.ret and retval then argc = marshal_cell( self, self.ret, 'to_value', args, argc, marshalling_params, retval, params) end -- Prepare 'true' into phantom return, will be reset to 'false' -- when some output argument is returned as 'nil'. if self.phantom and retval then self.phantom.to_value(retval, marshalling_params, true) end -- Marshal output arguments. for i = 1, #self do argc = marshal_cell( self, self[i], 'to_value', args, argc, marshalling_params, params[i], params, retval) end end end -- Marshalls Lua arguments into Values suitable for invoking closures -- and signals. Returns Value (for retval), array of Value (for -- params) and keepalive value (which must be kept alive during the -- call) function CallInfo:pre_call(...) -- Prepare array of param values and initialize them with correct type. local params = {} for i = 1, #self do params[#params + 1] = Value(self[i].gtype) end local marshalling_params = { keepalive = {} } -- Marshal input values. local args, argc = { ... }, 0 for i = 1, #self do argc = marshal_cell( self, self[i], 'to_value', args, argc, marshalling_params, params[i], params) end -- Prepare return value. local retval = Value() if self.ret then retval.type = self.ret.gtype end if self.phantom then retval.type = self.phantom.gtype end return retval, params, marshalling_params end -- Unmarshalls Lua restuls from Values after invoking closure or -- signal. Returns all unmarshalled Lua values. function CallInfo:post_call(params, retval, marshalling_params) marshalling_params.keepalive = {} local args, argc = {}, 0 -- Check, whether phantom return exists and returned 'false'. If -- yes, return just nil. if (self.phantom and not self.phantom.to_lua(retval, marshalling_params)) then return nil end -- Unmarshal return value. if self.ret and retval then argc = marshal_cell( self, self.ret, 'to_lua', args, argc, marshalling_params, retval, params) end -- Unmarshal output arguments. for i = 1, #self do argc = marshal_cell( self, self[i], 'to_lua', args, argc, marshalling_params, params[i], params) end -- Return all created Lua values. return unpack(args, 1, argc) end -- Create new closure invoking Lua target function (or anything else -- that can be called). Optionally callback_info specifies detailed -- information about how to marshal signals. function Closure:_new(target, callback_info) local closure = Closure._method.new_simple(closure_info.size, nil) if target then local marshaller if callback_info then -- Create marshaller based on callinfo. local call_info = CallInfo.new(callback_info, true) marshaller = call_info:get_closure_marshaller(target) else -- Create marshaller based only on Value types. function marshaller(closure, retval, params) local args = {} for i, val in ipairs(params) do args[i] = val.value end local ret = target(unpack(args, 1, #params)) if retval then retval.value = ret end end end core.marshal.closure_set_marshal(closure, marshaller) end Closure.ref(closure) Closure.sink(closure) return closure end -- Export CallInfo as field of Closure. Closure.CallInfo = CallInfo lua-lgi-0.7.2/lgi/override/GObject-Object.lua000066400000000000000000000221711221440706400206730ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Object handling. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local pairs, select, setmetatable, error, type = pairs, select, setmetatable, error, type local core = require 'lgi.core' local gi = core.gi local repo = core.repo local Value = repo.GObject.Value local Type = repo.GObject.Type local Closure = repo.GObject.Closure local Object = repo.GObject.Object -- Object constructor, 'param' contains table with properties/signals -- to initialize. local parameter_repo = repo.GObject.Parameter local object_new = gi.GObject.Object.methods.new if object_new then object_new = core.callable.new(object_new) else -- Unfortunately, older GI (<1.30) does not export g_object_newv() -- in the typelib, so we have to workaround here with manually -- implemented C version. object_new = core.object.new end -- Generic construction method. function Object:_construct(gtype, param, owns) local object if type(param) == 'userdata' then -- Wrap existing GObject instance in the lgi proxy. object = core.object.new(param, owns) gtype = object._gtype end -- Check that gtype fits. if not Type.is_a(gtype, self._gtype) then error(("`%s' is not subtype of `%s'"):format( Type.name(gtype), self._name), 3) end -- In 'wrap' mode, just return the created object. if object then return object end -- Process 'args' table, separate properties from other fields. local parameters, others, safe = {}, {}, {} for name, arg in pairs(param or {}) do if type(name) == 'string' then local argtype = self[name] if gi.isinfo(argtype) and argtype.is_property then local parameter = core.record.new(parameter_repo) name = argtype.name -- Store the name string in some safe Lua place ('safe' -- table), because param is GParameter, which contains -- only non-owning pointer to the string, and it could be -- Lua-GC'ed while still referenced by GParameter -- instance. safe[#safe + 1] = name parameter.name = name local gtype = Type.from_typeinfo(argtype.typeinfo) Value.init(parameter.value, gtype) local marshaller = Value.find_marshaller(gtype, argtype.typeinfo) marshaller(parameter.value, nil, arg) parameters[#parameters + 1] = parameter else others[name] = arg end end end -- Create the object. object = object_new(gtype, parameters) -- Attach arguments previously filtered out from creation. for name, value in pairs(others) do if type(name) == 'string' then object[name] = value end end -- In case that type has _container_add() method, use it to process -- array part of the args. local add = self._container_add if add and param then for i = 1, #param do add(object, param[i]) end end return object end function Object:_new(...) -- Invoke object's construct method which does the work. return self:_construct(self._gtype, ...) end -- Override normal 'new' constructor, to allow creating objects with -- specified GType. function Object.new(gtype, params, owns) -- Find proper repo instance for gtype. local self = core.repotype(gtype) return self:_construct(gtype, params, owns) end -- Initially unowned creation is similar to normal GObject creation, -- but we have to ref_sink newly created object. local InitiallyUnowned = repo.GObject.InitiallyUnowned function InitiallyUnowned:_construct(...) local object = Object._construct(self, ...) return Object.ref_sink(object) end -- Reading 'class' yields real instance of the object class. Object._attribute = { _type = {} } function Object._attribute._type:get() return core.object.query(self, 'repo') end -- Custom _element implementation, checks dynamically inherited -- interfaces and dynamic properties. local inherited_element = Object._element function Object:_element(object, name) local element, category = inherited_element(self, object, name) if element then return element, category end -- Everything else works only if we have object instance. if not object then return nil end -- List all interfaces implemented by this object and try whether -- they can handle specified _element request. local interfaces = Type.interfaces(object._gtype) for i = 1, #interfaces do local info = gi[core.gtype(interfaces[i])] local iface = info and repo[info.namespace][info.name] if iface then element, category = iface:_element(object, name) end if element then return element, category end end -- Element not found in the repo (typelib), try whether dynamic -- property of the specified name exists. local property = Object._class.find_property( object._class, name:gsub('_', '-')) if property then return property, '_paramspec' end end -- Sets/gets property using specified marshaller attributes. local function marshal_property(obj, name, flags, gtype, marshaller, ...) -- Check access rights of the property. local mode = select('#', ...) > 0 and 'WRITABLE' or 'READABLE' if not flags[mode] then error(("%s: `%s' not %s"):format(core.object.query(obj, 'repo')._name, name, mode:lower())) end local value = Value(gtype) if mode == 'WRITABLE' then marshaller(value, nil, ...) Object.set_property(obj, name, value) else Object.get_property(obj, name, value) return marshaller(value) end end -- GI property accessor. function Object:_access_property(object, property, ...) local typeinfo = property.typeinfo local gtype = Type.from_typeinfo(typeinfo) local marshaller = Value.find_marshaller(gtype, typeinfo, property.transfer) return marshal_property(object, property.name, repo.GObject.ParamFlags[property.flags], gtype, marshaller, ...) end -- GLib property accessor (paramspec). function Object:_access_paramspec(object, pspec, ...) return marshal_property(object, pspec.name, pspec.flags, pspec.value_type, Value.find_marshaller(pspec.value_type), ...) end local quark_from_string = repo.GLib.quark_from_string local signal_lookup = repo.GObject.signal_lookup local signal_connect_closure_by_id = repo.GObject.signal_connect_closure_by_id local signal_emitv = repo.GObject.signal_emitv -- Connects signal to specified object instance. local function connect_signal(obj, gtype, name, closure, detail, after) return signal_connect_closure_by_id( obj, signal_lookup(name, gtype), detail and quark_from_string(detail) or 0, closure, after or false) end -- Emits signal on specified object instance. local function emit_signal(obj, gtype, info, detail, ...) -- Compile callable info. local call_info = Closure.CallInfo.new(info) -- Marshal input arguments. local retval, params, marshalling_params = call_info:pre_call(obj, ...) -- Invoke the signal. signal_emitv(params, signal_lookup(info.name, gtype), detail and quark_from_string(detail) or 0, retval) -- Unmarshal results. return call_info:post_call(params, retval, marshalling_params) end -- Signal accessor. function Object:_access_signal(object, info, ...) local gtype = self._gtype if select('#', ...) > 0 then -- Assignment means 'connect signal without detail'. connect_signal(object, gtype, info.name, Closure((...), info)) else -- Reading yields table with signal operations. local mt = {} local pad = setmetatable({}, mt) function pad:connect(target, detail, after) return connect_signal(object, gtype, info.name, Closure(target, info), detail, after) end function pad:emit(...) return emit_signal(object, gtype, info, nil, ...) end function mt:__call(_, ...) return emit_signal(object, gtype, info, nil, ...) end -- If signal supports details, add metatable implementing -- __newindex for connecting in the 'on_signal['detail'] = -- handler' form. if not info.is_signal or info.flags.detailed then function pad:emit(detail, ...) return emit_signal(object, gtype, info, detail, ...) end function mt:__newindex(detail, target) connect_signal(object, gtype, info.name, Closure(target, info), detail) end end -- Return created signal pad. return pad end end -- GOI<1.30 does not export 'Object.on_notify' signal from the -- typelib. Work-around this problem by implementing custom on_notify -- attribute. if not gi.GObject.Object.signals.notify then local notify_info = gi.GObject.ObjectClass.fields.notify.typeinfo.interface function Object._attribute.on_notify(object, ...) local repotable = core.object.query(object, 'repo') return Object._access_signal(repotable, object, notify_info, ...) end end -- Bind property implementation. For some strange reason, GoI<1.30 -- exports it only on GInitiallyUnowned and not on GObject. Oh -- well... for _, name in pairs { 'bind_property', 'bind_property_full' } do if not Object[name] then Object._method[name] = InitiallyUnowned[name] end end lua-lgi-0.7.2/lgi/override/GObject-Type.lua000066400000000000000000000046321221440706400204100ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI GObject.Type facilities. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local assert, pairs, ipairs = assert, pairs, ipairs local core = require 'lgi.core' local repo = core.repo -- Add synthetic GObject.Type, containing well-known GType constants -- and grouping some type_xxx methods. local Type = { STRV = 'GStrv', ARRAY = 'GArray', BYTE_ARRAY = 'GByteArray', PTR_ARRAY = 'GPtrArray', HASH_TABLE = 'GHashTable', ERROR = 'GError', GTYPE = 'GType' } repo.GObject._struct = { Type = Type } for _, name in pairs { 'name', 'qname', 'from_name', 'parent', 'depth', 'next_base', 'is_a', 'children', 'interfaces', 'query', 'fundamental_next', 'fundamental'} do Type[name] = repo.GObject['type_' .. name] end for num, name in ipairs { 'NONE', 'INTERFACE', 'CHAR', 'UCHAR', 'BOOLEAN', 'INT', 'UINT', 'LONG', 'ULONG', 'INT64', 'UINT64', 'ENUM', 'FLAGS', 'FLOAT', 'DOUBLE', 'STRING', 'POINTER', 'BOXED', 'PARAM', 'OBJECT', 'VARIANT' } do Type[name] = Type.name(num * 4) end -- Map of basic typeinfo tags to GType. local type_tag_map = { gboolean = Type.BOOLEAN, gint8 = Type.CHAR, guint8 = Type.UCHAR, gint16 = Type.INT, guint16 = Type.UINT, gint32 = Type.INT, guint32 = Type.UINT, gint64 = Type.INT64, guint64 = Type.UINT64, gunichar = Type.UINT, gfloat = Type.FLOAT, gdouble = Type.DOUBLE, GType = Type.GTYPE, utf8 = Type.STRING, filename = Type.STRING, ghash = Type.HASH_TABLE, glist = Type.POINTER, gslist = Type.POINTER, error = Type.ERROR } -- Gets GType corresponding to specified typeinfo. function Type.from_typeinfo(ti) local gtype = type_tag_map[ti.tag] if not gtype then if ti.tag == 'interface' then gtype = Type.name(ti.interface.gtype) elseif ti.tag == 'array' then local atype = ti.array_type if atype == 'c' then gtype = Type.POINTER -- Check for Strv. local etag = ti.params[1].tag if ((etag == 'utf8' or etag == 'filename') and ti.is_zero_terminated) then gtype = Type.STRV end else gtype = ({ array = Type.ARRAY, byte_array = Type.BYTE_ARRAY, ptr_array = Type.PTR_ARRAY })[atype] end end end return gtype end lua-lgi-0.7.2/lgi/override/GObject-Value.lua000066400000000000000000000155071221440706400205460ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI GObject.Value support. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local assert, pairs, select, type, tostring, error = assert, pairs, select, type, tostring, error local lgi = require 'lgi' local core = require 'lgi.core' local repo = core.repo local gi = core.gi local Type = repo.GObject.Type -- Value is constructible from any kind of source Lua value, and the -- type of the value can be hinted by type name. local Value = repo.GObject.Value local log = lgi.log.domain('Lgi') -- Workaround for incorrect annotations - g_value_set_xxx are missing -- (allow-none) annotations in glib < 2.30. for _, name in pairs { 'set_object', 'set_variant', 'set_string' } do if not gi.GObject.Value.methods[name].args[1].optional then log.message("g_value_%s() is missing (allow-none)", name) local setter = Value[name] Value._method[name] = function(value, val) if not val then Value.reset(value) else setter(value, val) end end end end -- Do not allow direct access to fields. local value_field_gtype = Value._field.g_type Value._field = nil -- Register _uninit function, to avoid memory leaks from values which -- are inline-allocated by core.record.new. Value._uninit = core.record.value_unset Value._copy = core.record.value_copy -- 'type' property controls gtype of the property. Value._attribute = { gtype = {} } function Value._attribute.gtype.get(value) return core.record.field(value, value_field_gtype) end function Value._attribute.gtype.set(value, newtype) local gtype = core.record.field(value, value_field_gtype) if gtype then if newtype then -- Try converting old value to new one. local dest = core.record.new(Value) Value.init(dest, newtype) if not Value.transform(value, dest) then error(("GObject.Value: cannot convert `%s' to `%s'"):format( gtype, core.record.field(dest, value_field_gtype))) end Value.unset(value) Value.init(value, newtype) Value.copy(dest, value) else Value.unset(value) end elseif newtype then -- No value was set and some is requested, so set it. Value.init(value, newtype) end end local value_marshallers = {} for name, gtype in pairs(Type) do local get = Value._method['get_' .. name:lower()] local set = Value._method['set_' .. name:lower()] if get and set then value_marshallers[gtype] = function(value, params, ...) return (select('#', ...) > 0 and set or get)(value, ...) end end end -- Interface marshaller is the same as object marshaller. value_marshallers[Type.INTERFACE] = value_marshallers[Type.OBJECT] -- Override 'boxed' marshaller, default one marshalls to gpointer -- instead of target boxed type. value_marshallers[Type.BOXED] = function(value, params, ...) local repotype = core.repotype(core.record.field(value, value_field_gtype)) if select('#', ...) > 0 then Value.set_boxed(value, core.record.query((...), 'addr', repotype)) else return core.record.new(repotype, Value.get_boxed(value)) end end -- Override marshallers for enums and bitmaps, marshal them as strings -- or sets of string flags. for name, gtype in pairs { ENUM = Type.ENUM, FLAGS = Type.FLAGS } do local get = Value._method['get_' .. name:lower()] local set = Value._method['set_' .. name:lower()] value_marshallers[gtype] = function(value, params, ...) local rtype if select('#', ...) > 0 then local param = ... if type(param) ~= 'number' then rtype = core.repotype(core.record.field(value, value_field_gtype)) param = rtype(param) end set(value, param) else rtype = core.repotype(core.record.field(value, value_field_gtype)) return rtype[get(value)] end end end -- Create GStrv marshaller, implement it using typeinfo marshaller -- with proper null-terminated-array-of-utf8 typeinfo 'stolen' from -- g_shell_parse_argv(). value_marshallers[Type.STRV] = core.marshal.container( gi.GLib.shell_parse_argv.args[3].typeinfo) -- Finds marshaller closure which can marshal type described either by -- gtype or typeinfo/transfer combo. function Value._method.find_marshaller(gtype, typeinfo, transfer) -- Check whether we can have marshaller for typeinfo, if the -- typeinfo is container. local marshaller if typeinfo then marshaller = core.marshal.container(typeinfo, transfer) if marshaller then return marshaller end end -- Special case for non-gtype records. if not gtype and typeinfo and typeinfo.tag == 'interface' then -- Workaround for GoI < 1.30; it does not know that GLib structs are -- boxed, so it does not assign them GType; moreover it incorrectly -- considers GParamSpec as GType-less struct instead of the class. local function marshal_record_no_gtype(value, params, ...) -- Check actual gtype of the real value. local gtype = core.record.field(value, value_field_gtype) if Type.is_a(gtype, Type.PARAM) then return value_marshallers[Type.PARAM](value, ...) end -- Find out proper getter/setter method for the value. local get, set if Type.is_a(gtype, Type.BOXED) then get, set = Value.get_boxed, Value.set_boxed else get, set = Value.get_pointer, Value.set_pointer end -- Do GValue<->record transfer. local record_repo = core.repotype(typeinfo.interface) if select('#', ...) > 0 then set(value, core.record.query((...), 'addr', record_repo)) else return core.record.new(record_repo, get(value)) end end return marshal_record_no_gtype end local gt = gtype if type(gt) == 'userdata' then gt = Type.name(gt) end -- Special marshaller, allowing only 'nil'. if not gt then return function() end end -- Find marshaller according to gtype of the value. while gt do -- Check simple and/or fundamental marshallers. marshaller = value_marshallers[gt] or core.marshal.fundamental(gt) if marshaller then return marshaller end gt = Type.parent(gt) end error(("GValue marshaller for `%s' not found"):format(tostring(gtype))) end -- Value 'value' property provides access to GValue's embedded data. function Value._attribute:value(...) local marshaller = Value._method.find_marshaller( core.record.field(self, value_field_gtype)) return marshaller(self, nil, ...) end -- Implement custom 'constructor', taking optionally two values (type -- and value). The reason why it is overriden is that the order of -- initialization is important, and standard record intializer cannot -- enforce the order. function Value:_new(gtype, value) local v = core.record.new(Value) if gtype then v.gtype = gtype end if value then v.value = value end return v end lua-lgi-0.7.2/lgi/override/Gdk.lua000066400000000000000000000070311221440706400166550ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Gdk3 override module. -- -- Copyright (c) 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local select, type, pairs, unpack, rawget = select, type, pairs, unpack, rawget local lgi = require 'lgi' local core = require 'lgi.core' local ffi = require 'lgi.ffi' local ti = ffi.types local Gdk = lgi.Gdk local cairo = lgi.cairo -- Take over internal GDK synchronization lock. core.registerlock(core.gi.Gdk.resolve.gdk_threads_set_lock_functions) Gdk.threads_init() -- Gdk.Rectangle does not exist at all, because it is aliased to -- cairo.RectangleInt. Make sure that we have it exists, because it -- is very commonly used in API documentation. Gdk.Rectangle = lgi.cairo.RectangleInt Gdk.Rectangle._method = rawget(Gdk.Rectangle, '_method') or {} Gdk.Rectangle._method.intersect = Gdk.rectangle_intersect Gdk.Rectangle._method.union = Gdk.rectangle_union -- Declare GdkAtoms which are #define'd in Gdk sources and not -- introspected in gir. local _ = Gdk.KEY_0 for name, val in pairs { SELECTION_PRIMARY = 1, SELECTION_SECONDARY = 2, SELECTION_CLIPBOARD = 69, TARGET_BITMAP = 5, TARGET_COLORMAP = 7, TARGET_DRAWABLE = 17, TARGET_PIXMAP = 20, TARGET_STRING = 31, SELECTION_TYPE_ATOM = 4, SELECTION_TYPE_BITMAP = 5, SELECTION_TYPE_COLORMAP = 7, SELECTION_TYPE_DRAWABLE = 17, SELECTION_TYPE_INTEGER = 19, SELECTION_TYPE_PIXMAP = 20, SELECTION_TYPE_WINDOW = 33, SELECTION_TYPE_STRING = 31, } do Gdk._constant[name] = Gdk.Atom(val) end -- Easier-to-use Gdk.RGBA.parse() override. if Gdk.RGBA then local parse = Gdk.RGBA.parse function Gdk.RGBA._method.parse(arg1, arg2) if Gdk.RGBA:is_type_of(arg1) then -- Standard member method. return parse(arg1, arg2) else -- Static constructor variant. local rgba = Gdk.RGBA() return parse(rgba, arg1) and rgba or nil end end end -- Gdk.Window.destroy() actually consumes 'self'. Prepare workaround -- with override doing ref on input arg first. local destroy = Gdk.Window.destroy local ref = core.callable.new { addr = core.gi.GObject.resolve.g_object_ref, ret = ti.ptr, ti.ptr } function Gdk.Window._method:destroy() ref(self._native) destroy(self) end -- Better integrate Gdk cairo helpers. Gdk.Window._method.cairo_create = Gdk.cairo_create cairo.Region._method.create_from_surface = Gdk.cairo_region_create_from_surface local cairo_set_source_rgba = cairo.Context._method.set_source_rgba function cairo.Context._method:set_source_rgba(...) if select('#', ...) == 1 then return Gdk.cairo_set_source_rgba(self, ...) else return cairo_set_source_rgba(self, ...) end end local cairo_rectangle = cairo.Context._method.rectangle function cairo.Context._method:rectangle(...) if select('#', ...) == 1 then return Gdk.cairo_rectangle(self, ...) else return cairo_rectangle(self, ...) end end for _, name in pairs { 'get_clip_rectangle', 'set_source_color', 'set_source_pixbuf', 'set_source_window', 'region' } do cairo.Context._method[name] = Gdk['cairo_' .. name] end for _, name in pairs { 'clip_rectangle', 'source_color', 'source_pixbuf', 'source_window' } do cairo.Context._attribute[name] = { get = cairo.Context._method['get_' .. name], set = cairo.Context._method['set_' .. name], } end lua-lgi-0.7.2/lgi/override/Gio.lua000066400000000000000000000026161221440706400166720ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Gio2 override module. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local select, type, pairs = select, type, pairs local lgi = require 'lgi' local Gio = lgi.Gio local GObject = lgi.GObject local core = require 'lgi.core' local gi = core.gi -- GOI < 1.30 did not map static factory method into interface -- namespace. The prominent example of this fault was that -- Gio.File.new_for_path() had to be accessed as -- Gio.file_new_for_path(). Create a compatibility layer to mask this -- flaw. for _, name in pairs { 'path', 'uri', 'commandline_arg' } do if not Gio.File['new_for_' .. name] then Gio.File._method['new_for_' .. name] = Gio['file_new_for_' .. name] end end -- Older versions of gio did not annotate input stream methods as -- taking an array. Apply workaround. -- https://github.com/pavouk/lgi/issues/59 for _, name in pairs { 'read', 'read_all', 'read_async' } do local raw_read = Gio.InputStream._method[name] if gi.Gio.InputStream.methods[name].args[1].typeinfo.tag ~= 'array' then Gio.InputStream._method[name] = function(self, buffer, ...) return raw_read(self, buffer, #buffer, ...) end end end lua-lgi-0.7.2/lgi/override/Gst.lua000066400000000000000000000045111221440706400167050ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Gst override module. -- -- Copyright (c) 2010-2013 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local ipairs, tonumber = ipairs, tonumber local os = require 'os' local lgi = require 'lgi' local gi = require('lgi.core').gi local GLib = lgi.GLib local Gst = lgi.Gst if tonumber(Gst._version) < 1.0 then -- GstObject has special ref_sink mechanism, make sure that lgi -- core is aware of it, otherwise refcounting is screwed. Gst.Object._refsink = gi.Gst.Object.methods.ref_sink end -- Gst.Element; GstElement uses ugly macro accessors instead of proper -- GObject properties, so add attributes for assorted Gst.Element -- properties. Gst.Element._attribute = {} for _, name in ipairs { 'name', 'parent', 'bus', 'clock', 'base_time', 'start_time', 'factory', 'index', 'state' } do Gst.Element._attribute[name] = { get = Gst.Element['get_' .. name], set = Gst.Element['set_' .. name], } end function Gst.Element._method:link_many(...) local target = self for _, source in ipairs {...} do if not target:link(source) then return false end target = source end return true end -- Gst.Bin adjustments if tonumber(Gst._version) < 1.0 then function Gst.Bus._method:add_watch(priority, callback) if not callback then callback = priority priority = GLib.PRIORITY_DEFAULT end return self:add_watch_full(priority, callback) end end function Gst.Bin._method:add_many(...) local args = {...} for i = 1, #args do self:add(args[i]) end end -- Gst.TagList adjustments if not Gst.TagList.copy_value then Gst.TagList._method.copy_value = Gst.tag_list_copy_value end function Gst.TagList:get(tag) local gvalue = self:copy_value(tag) return gvalue and gvalue.value end -- Load additional Gst modules. if tonumber(Gst._version) < 1.0 then local GstInterfaces = lgi.require('GstInterfaces', Gst._version) end -- Initialize gstreamer. Gst.init() -- Undo unfortunate gstreamer's setlocale(LC_ALL, ""), which breaks -- Lua's tonumber() implementation for some locales (e.g. pl_PL, pt_BR -- and probably many others). os.setlocale ('C', 'numeric') lua-lgi-0.7.2/lgi/override/Gtk.lua000066400000000000000000000470271221440706400167060ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Gtk3 override module. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local select, type, pairs, ipairs, unpack, setmetatable, error, next, rawget = select, type, pairs, ipairs, unpack, setmetatable, error, next, rawget local lgi = require 'lgi' local core = require 'lgi.core' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local GObject = lgi.GObject local cairo = lgi.cairo local log = lgi.log.domain('lgi.Gtk') -- Initialize GTK. Gtk.disable_setlocale() assert(Gtk.init_check()) -- Gtk.Allocation is just an alias to Gdk.Rectangle. Gtk.Allocation = Gdk.Rectangle -------------------------------- Gtk.Widget overrides. Gtk.Widget._attribute = { width = { get = Gtk.Widget.get_allocated_width }, height = { get = Gtk.Widget.get_allocated_height }, events = {}, style = {}, } -- Add widget attributes for some get/set method combinations not covered by -- native widget properties. for _, name in pairs { 'allocation', 'direction', 'settings', 'realized', 'mapped', 'display', 'screen', 'window', 'root_window', 'has_window', 'style_context' } do if not Gtk.Widget._property[name] then local attr = { get = Gtk.Widget['get_' .. name], set = Gtk.Widget['set_' .. name] } if next(attr) then Gtk.Widget._attribute[name] = attr end end end function Gtk.Widget._attribute.width:set(width) self.width_request = width end function Gtk.Widget._attribute.height:set(height) self.height_request = height end -- gtk_widget_intersect is missing an (out caller-allocates) annotation if core.gi.Gtk.Widget.methods.intersect.args[2].direction == 'in' then local real_intersect = Gtk.Widget.intersect function Gtk.Widget._method:intersect(area) local intersection = Gdk.Rectangle() local notempty = real_intersect(self, area, intersection) return notempty and intersection or nil end end function Gtk.Widget._attribute.events:get() return Gdk.EventMask[self:get_events()] end function Gtk.Widget._attribute.events:set(events) self:set_events(Gdk.EventMask(events)) end -- Accessing style properties is preferrably done by accessing 'style' -- property. In case that caller wants deprecated 'style' property, it -- must be accessed by '_property_style' name. local widget_style_mt = {} function widget_style_mt:__index(name) name = name:gsub('_', '-') local pspec = self._widget._class:find_style_property(name) if not pspec then error(("%s: no style property `%s'"):format( self._widget.type._name, name:gsub('%-', '_')), 2) end local value = GObject.Value(pspec.value_type) self._widget:style_get_property(name, value) return value.value end function Gtk.Widget._attribute.style:get() return setmetatable({ _widget = self }, widget_style_mt) end -- Get/Set widget from Gdk.Window function Gdk.Window:get_widget() return core.object.new(self:get_user_data(), false) end function Gdk.Window:set_widget(widget) self:set_user_data(widget) end Gdk.Window._attribute = rawget(Gdk.Window, '_attribute') or {} Gdk.Window._attribute.widget = { set = Gdk.Window.set_widget, get = Gdk.Window.get_widget, } -------------------------------- Gtk.Buildable overrides. Gtk.Buildable._attribute = { id = {}, child = {} } -- Create custom 'id' property, mapped to buildable name. function Gtk.Buildable._attribute.id:set(id) core.object.env(self).id = id end function Gtk.Buildable._attribute.id:get() return core.object.env(self).id end -- Custom 'child' property, which returns widget in the subhierarchy -- with specified id. local buildable_child_mt = {} function buildable_child_mt:__index(id) return self._buildable.id == id and self._buildable or nil end function Gtk.Buildable._attribute.child:get() return setmetatable({ _buildable = self }, buildable_child_mt) end -------------------------------- Gtk.Container overrides. Gtk.Container._attribute = {} -- Extand add() functionality to allow adding child properties. function Gtk.Container:add(widget, props) if type(widget) == 'table' then props = widget widget = widget[1] end Gtk.Container._method.add(self, widget) if props then local properties = self.property[widget] for name, value in pairs(props) do if type(name) == 'string' then properties[name] = value end end end end -- Map 'add' method also to '_container_add', so that ctor can use it -- for adding widgets from the array part. Gtk.Container._container_add = Gtk.Container.add -- Accessing child properties is preferrably done by accessing -- 'property' attribute. Gtk.Container._attribute.property = {} local container_property_item_mt = {} function container_property_item_mt:__index(name) name = name:gsub('_', '-') local pspec = self._container._class:find_child_property(name) if not pspec then error(("%s: no child property `%s'"):format( self._container.type._name, name:gsub('%-', '_')), 2) end local value = GObject.Value(pspec.value_type) self._container:child_get_property(self._child, name, value) return value.value end function container_property_item_mt:__newindex(name, val) name = name:gsub('_', '-') local pspec = self._container._class:find_child_property(name) if not pspec then error(("%s: no child property `%s'"):format( self._container.type._name, name:gsub('%-', '_')), 2) end local value = GObject.Value(pspec.value_type, val) self._container:child_set_property(self._child, name, value) end local container_property_mt = {} function container_property_mt:__index(child) if type(child) == 'string' then child = self._container.child[child] end return setmetatable({ _container = self._container, _child = child }, container_property_item_mt) end function Gtk.Container._attribute.property:get() return setmetatable({ _container = self }, container_property_mt) end -- Override 'child' attribute; writing allows adding child with -- children properties (similarly as add() override), reading provides -- table which can lookup subchildren by Gtk.Buildable.id. Gtk.Container._attribute.child = {} local container_child_mt = {} function container_child_mt:__index(id) local found = (core.object.env(self._container).id == id and self._container) if not found then for _, child in ipairs(self) do found = child.child[id] if found then break end end end return found or nil end function Gtk.Container._attribute.child:get() local children = self:get_children() children._container = self return setmetatable(children, container_child_mt) end function Gtk.Container._attribute.child:set(widget) self:add(widget) end -------------------------------- Gtk.Builder overrides. Gtk.Builder._attribute = {} -- Override add_from_ family of functions, their C-signatures are -- completely braindead. local function builder_fix_return(res, e1, e2) if res and res ~= 0 then return true end return false, e1, e2 end function Gtk.Builder:add_from_file(filename) return builder_fix_return(Gtk.Builder._method.add_from_file(self, filename)) end function Gtk.Builder:add_objects_from_file(filename, object_ids) return builder_fix_return(Gtk.Builder._method.add_objects_from_file( self, filename, object_ids)) end function Gtk.Builder:add_from_string(string, len) if not len or len == -1 then len = #string end return builder_fix_return(Gtk.Builder._method.add_from_string( self, string, len)) end function Gtk.Builder:add_objects_from_string(string, len, object_ids) if not len or len == -1 then len = #string end return builder_fix_return(Gtk.Builder._method.add_objects_from_string( self, string, len, object_ids)) end -- Wrapping get_object() using 'objects' attribute. Gtk.Builder._attribute.objects = {} local builder_objects_mt = {} function builder_objects_mt:__index(name) return self._builder:get_object(name) end function Gtk.Builder._attribute.objects:get() return setmetatable({ _builder = self }, builder_objects_mt) end -- Implementation of connect_signals() method. function Gtk.Builder._method:connect_signals(handlers) local unconnected self:connect_signals_full( function(builder, object, signal, handler, connect_object, flags) signal = 'on_' .. signal:gsub('%-', '_') local target = handlers[handler] if not target then unconnected = unconnected or {} unconnected[#unconnected + 1] = handler log.warning("%s: failed to connect to `%s' handler", signal, handler) return end local fun if connect_object then fun = function(_, ...) return target(connect_object, ...) end else fun = target end object[signal]:connect(fun, nil, flags.AFTER) end) return unconnected end -------------------------------- Gtk.TextTagTable overrides. Gtk.TextTagTable._attribute = { tag = {} } local text_tag_table_tag_mt = {} function text_tag_table_tag_mt:__index(id) return self._table:lookup(id) end function Gtk.TextTagTable._attribute.tag:get() return setmetatable({ _table = self }, text_tag_table_tag_mt) end -- Map adding of tags in constructor array part to add() method. Gtk.TextTagTable._container_add = Gtk.TextTagTable.add -------------------------------- Gtk.TreeModel and relatives. Gtk.TreeModel._attribute = {} local tree_model_item_mt = {} function tree_model_item_mt:__index(column) return self._model:get_value(self._iter, column - 1).value end function tree_model_item_mt:__newindex(column, val) column = column - 1 local value = GObject.Value(self._model:get_column_type(column), val) self._model:set_value(self._iter, column, value) end -- Map access of lines to iterators by directly indexing treemodel -- instance values with iterators. local tree_model_element = Gtk.TreeModel._element function Gtk.TreeModel:_element(model, key) if Gtk.TreeIter:is_type_of(key) then return key, '_iter' elseif Gtk.TreePath:is_type_of(key) then return model:get_iter(key), '_iter' end return tree_model_element(self, model, key) end function Gtk.TreeModel:_access_iter(model, iter, ...) if select('#', ...) > 0 then model:set(iter, ...) else -- Return proxy table allowing getting/setting individual columns. return setmetatable({ _model = model, _iter = iter }, tree_model_item_mt) end end local function treemodel_prepare_values(model, values) local cols, vals = {}, {} for column, value in pairs(values) do column = column - 1 cols[#cols + 1] = column vals[#vals + 1] = GObject.Value(model:get_column_type(column), value) end return cols, vals end function Gtk.TreeModel:set(iter, values) -- Set all values provided by the table if Gtk.TreePath:is_type_of(iter) then iter = self:get_iter(iter) end self:set_values(iter, treemodel_prepare_values(self, values)) end -- Implement iteration protocol for model. function Gtk.TreeModel:next(iter) if not iter or type(iter) == 'table' then -- Start iteration. iter = self:iter_children(iter and iter[1]) else -- Continue to the next child. if not self:iter_next(iter) then iter = nil end end return iter, iter and Gtk.TreeModel:_access_iter(self, iter) end function Gtk.TreeModel:pairs(parent) return Gtk.TreeModel.next, self, parent and { parent } end -- Redirect 'set' method to our one inherited from TreeModel, it is -- the preferred one. Rename the original to set_values(). Gtk.ListStore._method.set_values = Gtk.ListStore.set Gtk.ListStore._method.set = nil -- Allow insert() and append() to handle also 'with_values' case. function Gtk.ListStore:insert(position, values) local iter if not values then iter = Gtk.ListStore._method.insert(self, position) else iter = Gtk.ListStore._method.insert_with_valuesv( self, position, treemodel_prepare_values(self, values)) end return iter end if not Gtk.ListStore._method.insert_with_values then Gtk.ListStore._method.insert_with_values = Gtk.ListStore._method.insert_with_valuesv end function Gtk.ListStore:append(values) local iter if not values then iter = Gtk.ListStore._method.append(self) else iter = Gtk.ListStore._method.insert_with_values( self, -1, treemodel_prepare_values(self, values)) end return iter end -- Similar treatment for treestore. Gtk.TreeStore._method.set_values = Gtk.TreeStore.set Gtk.TreeStore._method.set = nil function Gtk.TreeStore:insert(parent, position, values) local iter if not values then iter = Gtk.TreeStore._method.insert(self, parent, position) else iter = Gtk.TreeStore._method.insert_with_values( self, parent, position, treemodel_prepare_values(self, values)) end return iter end function Gtk.TreeStore:append(parent, values) local iter if not values then iter = Gtk.TreeStore._method.append(self, parent) else iter = Gtk.TreeStore._method.insert_with_values( self, parent, -1, treemodel_prepare_values(self, values)) end return iter end -- Add missing constants, defined as anonymous enums in C headers, which -- is not supported by GIR yet. Gtk.TreeSortable.DEFAULT_SORT_COLUMN_ID = -1 Gtk.TreeSortable.UNSORTED_SORT_COLUMN_ID = -2 -------------------------------- Gtk.TreeView and support. -- Array part in constructor specifies columns to add. Gtk.TreeView._container_add = Gtk.TreeView.append_column -- Allow looking up tree column as child of the tree. Gtk.TreeView._attribute = { child = { set = Gtk.TreeView._parent._attribute.child.set } } local treeview_child_mt = {} function treeview_child_mt:__index(id) if self._view.id == id then return self._view end for _, column in ipairs(self._view:get_columns()) do local child = column.child[id] if child then return child end end end function Gtk.TreeView._attribute.child:get() return setmetatable({ _view = self }, treeview_child_mt) end -- Sets attributes for specified cell. function Gtk.CellLayout:set(cell, data) if type(data) == 'table' then for attr, column in pairs(data) do self:add_attribute(cell, attr, column - 1) end else self:set_cell_data_func(cell, data) end end -- Adds new cellrenderer with full definition into the column. function Gtk.CellLayout:add(def) if def.align == 'start' then self:pack_start(def[1], def.expand) else self:pack_end(def[1], def.expand) end -- Set attributes. self:set(def[1], def[2]) if def.data_func then self:set_cell_data_func(def[1], def.data_func) end end -- Unfortunately, CellView is interface often implemented by descendants -- of Gtk.Container, so we cannot reuse generic _container_add here, -- because it is already occupied by implementing container's ctor. So -- instead add attribute 'cells' which can be assigned the list of cell -- data definitions. Gtk.CellLayout._attribute = { cells = {}, child = {} } function Gtk.CellLayout._attribute.cells:set(cells) for _, data in ipairs(cells) do Gtk.CellLayout.add(self, data) end end -- Allow lookuing up rendereres by assigned id. Gtk.CellRenderer._attribute = { id = Gtk.Buildable._attribute.id } local celllayout_child_mt = {} function celllayout_child_mt:__index(id) if id == self._layout.id then return self._layout end for _, renderer in ipairs(self._layout:get_cells()) do if renderer.id == id then return renderer end end end function Gtk.CellLayout._attribute.child:get() return setmetatable({ _layout = self }, celllayout_child_mt) end Gtk.TreeViewColumn._container_add = Gtk.TreeViewColumn.add -------------------------------- Gtk.Action and relatives function Gtk.ActionGroup:add(action) if type(action) == 'table' then if action.accelerator then -- Add with an accelerator. self:add_action_with_accel(action[1], action.accelerator) return action[1] end -- Go through all actions in the table and add them. local first_radio for i = 1, #action do local added = self:add(action[i]) if Gtk.RadioAction:is_type_of(added) then if not first_radio then first_radio = added else added:join_group(first_radio) end end end -- Install callback for on_activate. if first_radio and action.on_change then local on_change = action.on_change function first_radio:on_changed(current) on_change(current) end end else -- Add plain action. self:add_action(action) return action end end Gtk.ActionGroup._container_add = Gtk.ActionGroup.add Gtk.ActionGroup._attribute = { action = {} } local action_group_mt = {} function action_group_mt:__index(name) return self._group:get_action(name) end function Gtk.ActionGroup._attribute.action:get() return setmetatable({ _group = self }, action_group_mt) end -------------------------------- Gtk.Assistant Gtk.Assistant._attribute = { property = {} } function Gtk.Assistant._method:add(child) if type(child) == 'table' then local widget = child[1] self:append_page(widget) for name, value in pairs(child) do if type(name) == 'string' then self['set_page_' .. name](self, widget, value) end end else self:append_page(widget) end end Gtk.Assistant._container_add = Gtk.Assistant.add local assistant_property_mt = {} function assistant_property_mt:__newindex(property_name, value) self._assistant['set_page_' .. property_name]( self._assistant, self._page, value) end function assistant_property_mt:__index(property_name) return self._assistant['get_page_' .. property_name]( self._assistant, self._page) end local assistant_properties_mt = {} function assistant_properties_mt:__index(page) if type(page) == 'string' then page = self._assistant.child[page] end return setmetatable({ _assistant = self._assistant, _page = page }, assistant_property_mt) end function Gtk.Assistant._attribute.property:get() return setmetatable({ _assistant = self }, assistant_properties_mt) end -------------------------------- Gtk.Dialog Gtk.Dialog._attribute = { buttons = {} } function Gtk.Dialog._attribute.buttons:set(buttons) for _, button in ipairs(buttons) do self:add_button(button[1], button[2]) end end -------------------------------- Gtk.InfoBar Gtk.InfoBar._attribute = { buttons = Gtk.Dialog._attribute.buttons } -------------------------------- Gtk.Menu if not Gtk.Menu.popup then Gtk.Menu._method.popup = Gtk.Menu.popup_for_device end -------------------------------- Gtk.MenuItem Gtk.MenuItem._attribute = { child = {} } function Gtk.MenuItem._attribute.child:get() local children = Gtk.Container._attribute.child.get(self) children[#children + 1] = Gtk.MenuItem.get_submenu(self) return children end -------------------------------- Gtk.EntryCompletion -- Workaround for bug in GTK+; text_column accessors don't do an extra -- needed work which is done properly in -- gtk_entry_completion_{set/get}_text_column Gtk.EntryCompletion._attribute = { text_column = { get = Gtk.EntryCompletion.get_text_column, set = Gtk.EntryCompletion.set_text_column } } -------------------------------- Gtk.PrintSettings Gtk._constant = Gtk._constant or {} Gtk._constant.PRINT_OUTPUT_FILE_FORMAT = 'output-file-format' Gtk._constant.PRINT_OUTPUT_URI = 'output-uri' -- Gtk-cairo integration helpers. cairo.Context._method.should_draw_window = Gtk.cairo_should_draw_window --------------------------------- Gtk-2 workarounds if tonumber(Gtk._version) < 3.0 then -- Get rid of Gtk.Bin internal 'child' field, which gets in the way -- of 'child' attribute mechanism introduced in this override. local _ = Gtk.Bin.child Gtk.Bin._field.child = nil end lua-lgi-0.7.2/lgi/override/Pango.lua000066400000000000000000000140151221440706400172140ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Pango override module. -- -- Copyright (c) 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local pairs, rawget = pairs, rawget local table = require 'table' local lgi = require 'lgi' local Pango = lgi.Pango local core = require 'lgi.core' local gi = core.gi local ffi = require 'lgi.ffi' local ti = ffi.types local record = require 'lgi.record' local component = require 'lgi.component' -- Provide defines which are not present in the GIR local _ = Pango.SCALE for name, value in pairs { SCALE_XX_SMALL = 1 / (1.2 * 1.2 * 1.2), SCALE_X_SMALL = 1 / (1.2 * 1.2), SCALE_SMALL = 1 / 1.2, SCALE_MEDIUM = 1, SCALE_LARGE = 1.2, SCALE_X_LARGE = 1.2 * 1.2, SCALE_XX_LARGE = 1.2 * 1.2 * 1.2, } do if not Pango[name] then Pango._constant[name] = value end end -- Because of https://bugzilla.gnome.org/show_bug.cgi?id=672133 Pango -- enums are not gtype based on some platforms. If we detect non-gtype -- enum, reload it using ffi and GEnumInfo machinery. for _, enum in pairs { 'AttrType', 'Underline', 'BidiType', 'Direction', 'CoverageLevel', 'Style', 'Variant', 'Weight', 'Stretch', 'FontMask', 'Gravity', 'GravityHint', 'Alignment', 'WrapMode', 'EllipsizeMode', 'RenderPart', 'Script', 'TabAlign', } do if not Pango[enum]._gtype then local gtype = ffi.load_gtype( core.gi.Pango.resolve, 'pango_' .. enum:gsub('([%l%d])([%u])', '%1_%2'):lower() .. '_get_type') Pango._enum[enum] = ffi.load_enum(gtype, 'Pango.' .. enum) end end local pango_layout_set_text = Pango.Layout.set_text function Pango.Layout._method:set_text(text, len) pango_layout_set_text(self, text, len or -1) end local pango_layout_set_markup = Pango.Layout.set_markup function Pango.Layout._method:set_markup(text, len) pango_layout_set_markup(self, text, len or -1) end -- Pango.Layout:set_attributes() has incorrect transfer-full -- annotation on its attrs argument. Workaround for -- https://github.com/pavouk/lgi/issues/60 if gi.Pango.Layout.methods.set_attributes.args[1].transfer ~= 'none' then local _ = Pango.Layout._method.set_attributes Pango.Layout._method.set_attributes = core.callable.new { addr = core.gi.Pango.resolve.pango_layout_set_attributes, name = 'Pango.Layout.set_attributes', ret = ti.void, gi.Pango.Layout.methods.new.return_type, gi.Pango.Layout.methods.set_attributes.args[1].typeinfo, } end -- Add attributes simulating logically missing properties in Pango classes. for compound, attrs in pairs { [Pango.Layout] = { 'attributes', 'font_description', 'width', 'height', 'wrap', 'context', 'is_wrapped', 'ellipsize', 'is_ellipsized', 'indent', 'spacing', 'justify', 'auto_dir', 'alignment', 'tabs', 'single_paragraph_mode', 'baseline', 'line_count', 'lines', 'log_attrs', 'character_count', 'text', 'markup', }, [Pango.Context] = { 'base_dir', 'base_gravity', 'font_description', 'font_map', 'gravity', 'gravity_hint', 'language', 'matrix', }, [Pango.FontMetrics] = { 'ascent', 'descent', 'approximate_char_width', 'approximate_digit_width', 'underline_thickness', 'underline_position', 'strikethrough_thinkess', 'strikethrough_position', }, } do compound._attribute = rawget(compound, '_attribute') or {} for _, name in pairs(attrs) do if not compound._property or not compound._property[name] then compound._attribute[name] = { get = compound['get_' .. name] or compound[name], set = compound['set_' .. name], } end end end -- Handling of poor-man's OO invented by Pango.Attribute related -- pseudoclasses. Pango.Attribute._free = core.gi.Pango.Attribute.methods.destroy for name, def in pairs { language_new = { Pango.Language }, family_new = { ti.utf8 }, style_new = { Pango.Style }, variant_new = { Pango.Variant }, stretch_new = { Pango.Stretch }, weight_new = { Pango.Weight }, size_new = { ti.int }, size_new_absolute = { ti.int }, desc_new = { Pango.FontDescription }, foreground_new = { ti.uint16, ti.uint16, ti.uint16 }, background_new = { ti.uint16, ti.uint16, ti.uint16 }, strikethrough_new = { ti.boolean }, strikethrough_color_new = { ti.uint16, ti.uint16, ti.uint16 }, underline_new = { Pango.Underline }, underline_color_new = { ti.uint16, ti.uint16, ti.uint16 }, shape_new = { Pango.Rectangle, Pango.Rectangle }, scale_new = { ti.double }, rise_new = { ti.int }, letter_spacing_new = { ti.int }, fallback_new = { ti.boolean }, gravity_new = { Pango.Gravity }, gravity_hint_new = { Pango.GravityHint }, } do def.addr = core.gi.Pango.resolve['pango_attr_' .. name] def.name = 'Pango.Attribute.' .. name def.ret = { Pango.Attribute, xfer = true } Pango.Attribute._method[name] = core.callable.new(def) end -- Adding Pango.Attribute into the Pango.AttrList takes ownership of -- the record. Pfft, crappy API, wrap and handle. for _, name in pairs { 'insert', 'insert_before', 'change' } do local raw_method = Pango.AttrList[name] Pango.AttrList._method[name] = function(list, attr) -- Invoke original method first, then unown the attribute. raw_method(list, attr) core.record.set(attr, false) end end -- Pango.Layout:move_cursor_visually() is missing an (out) annotation -- in older Pango releases. Work around this limitation by creating -- custom ffi definition for this method. if gi.Pango.Layout.methods.move_cursor_visually.args[6].direction ~= 'out' then local _ = Pango.Layout.move_cursor_visually Pango.Layout._method.move_cursor_visually = core.callable.new { addr = core.gi.Pango.resolve.pango_layout_move_cursor_visually, name = 'Pango.Layout.move_cursor_visually', ret = ti.void, gi.Pango.Layout.methods.new.return_type, ti.boolean, ti.int, ti.int, ti.int, { ti.int, dir = 'out' }, { ti.int, dir = 'out' }, } end lua-lgi-0.7.2/lgi/override/PangoCairo.lua000066400000000000000000000030321221440706400201670ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI PangoCairo override module. -- -- Copyright (c) 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local pairs = pairs local lgi = require 'lgi' local PangoCairo = lgi.PangoCairo local cairo = lgi.cairo local Pango = lgi.Pango -- Make assorted PangoCairo global methods taking cairo.Context as first -- argument methods of the cairo.Context (where they logically belong). for _, name in pairs { 'update_context', 'update_layout', 'show_glyph_string', 'show_glyph_item', 'show_layout_line', 'show_layout', 'show_error_underline', 'glyph_string_path', 'layout_line_path', 'layout_path', 'error_underline_path', } do cairo.Context._method[name] = PangoCairo[name] end Pango.Layout._method.create = PangoCairo.create_layout -- Extend Pango.Context with additional methods and attributes coming from -- PangoCairo package. Pango.Context._method.create = PangoCairo.context_create for _, name in pairs { 'get_font_options', 'set_font_options', 'get_resolution', 'set_resolution', 'set_shape_renderer' } do Pango.Context._method[name] = PangoCairo['context_' .. name] end for _, name in pairs { 'font_options', 'resolution', 'shape_renderer' } do Pango.Context._attribute[name] = { get = Pango.Context['get_' .. name] or Pango.Context[name], set = Pango.Context['set_' .. name], } end lua-lgi-0.7.2/lgi/override/cairo.lua000066400000000000000000000725531221440706400172600ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Cairo override module. -- -- Copyright (c) 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local assert, pairs, ipairs, setmetatable, table, rawget, type = assert, pairs, ipairs, setmetatable, table, rawget, type local lgi = require 'lgi' local cairo = lgi.cairo local core = require 'lgi.core' local ffi = require 'lgi.ffi' local component = require 'lgi.component' local record = require 'lgi.record' local enum = require 'lgi.enum' local ti = ffi.types cairo._module = core.module('cairo', 2) local module_gobject = core.gi.cairo.resolve -- Versioning support. function cairo.version_encode(major, minor, micro) return 10000 * major + 100 * minor + micro end cairo.version = core.callable.new { addr = cairo._module.cairo_version, ret = ti.int } () cairo.version_string = core.callable.new { addr = cairo._module.cairo_version_string, ret = ti.utf8 } () -- Load some constants. cairo._constant = { MIME_TYPE_JP2 = 'image/jp2', MIME_TYPE_JPEG = 'image/jpeg', MIME_TYPE_PNG = 'image/png', MIME_TYPE_URI = 'text/x-uri', } -- Load definitions of all enums. cairo._enum = cairo._enum or {} for _, name in pairs { 'Status', 'Content', 'Operator', 'Antialias', 'FillRule', 'LineCap', 'LineJoin', 'TextClusterFlags', 'FontSlant', 'FontWeight', 'SubpixelOrder', 'HintStyle', 'HintMetrics', 'FontType', 'PathDataType', 'DeviceType', 'SurfaceType', 'Format', 'PatternType', 'Extend', 'Filter', 'RegionOverlap', 'PdfVersion', 'PsLevel', 'SvgVersion', } do local lower = name:gsub('([%l%d])([%u])', '%1_%2'):lower() local gtype = ffi.load_gtype( module_gobject, 'cairo_gobject_' .. lower .. '_get_type') if gtype then cairo._enum[name] = ffi.load_enum(gtype, 'cairo.' .. name) else cairo._enum[name] = component.create(nil, enum.enum_mt, 'cairo.' .. name) end end -- Load definitions of all boxed records. cairo._struct = cairo._struct or {} for index, struct in pairs { 'Context', 'Device', 'Surface', 'Rectangle', 'ScaledFont', 'FontFace', 'FontOptions', 'Region', 'RectangleInt', 'Path', 'TextExtents', 'FontExtents', 'Matrix', 'ImageSurface', 'PdfSurface', 'PsSurface', 'RecordingSurface', 'SvgSurface', 'ToyFontFace', 'RectangleList', 'SolidPattern', 'SurfacePattern', 'GradientPattern', 'LinearPattern', 'RadialPattern', MeshPattern = cairo.version_encode(1, 12, 0), } do local since = 0 if type(index) == 'string' then since = struct struct = index end if cairo.version >= since then local lower = struct:gsub('([%l%d])([%u])', '%1_%2'):lower() local gtype = ffi.load_gtype( module_gobject, 'cairo_gobject_' .. lower .. '_get_type') local obj = component.create(gtype, record.struct_mt, 'cairo.' .. struct) cairo._struct[struct] = obj end end local path_data_header = component.create(nil, record.struct_mt) ffi.load_fields(path_data_header, { { 'type', cairo.PathDataType }, { 'length', ti.int } }) local path_data_point = component.create(nil, record.struct_mt) ffi.load_fields(path_data_point, { { 'x', ti.double }, { 'y', ti.double } }) cairo._union = rawget(cairo, '_union') or {} cairo._union.PathData = component.create(nil, record.union_mt, 'cairo.PathData') -- Populate methods into records. for _, info in ipairs { { 'Status', methods = { to_string = { static = true, ret = ti.utf8, cairo.Status } }, }, { 'Rectangle', fields = { { 'x', ti.double }, { 'y', ti.double }, { 'width', ti.double }, { 'height', ti.double }, }, }, { 'RectangleList', fields = { { 'status', cairo.Status }, { 'rectangles', cairo.Rectangle, ptr = true }, { 'num_rectangles', ti.int }, }, }, { 'RectangleInt', fields = { { 'x', ti.int }, { 'y', ti.int }, { 'width', ti.int }, { 'height', ti.int }, }, }, { 'Matrix', fields = { { 'xx', ti.double }, { 'yx', ti.double }, { 'xy', ti.double }, { 'yy', ti.double }, { 'x0', ti.double }, { 'y0', ti.double }, }, methods = { init = { ti.double, ti.double, ti.double, ti.double, ti.double, ti.double }, init_identity = {}, init_translate = { ti.double, ti.double }, init_scale = { ti.double, ti.double }, init_rotate = { ti.double }, translate = { ti.double, ti.double }, scale = { ti.double, ti.double }, rotate = { ti.double }, invert = { ret = cairo.Status }, multiply = { cairo.Matrix, cairo.Matrix }, transform_distance = { { ti.double, dir = 'inout' }, { ti.double, dir = 'inout' } }, transform_point = { { ti.double, dir = 'inout' }, { ti.double, dir = 'inout' } }, }, }, { 'PathData', fields = { { 'header', path_data_header }, { 'point', path_data_point }, }, }, { 'Path', fields = { { 'status', cairo.Status }, { 'data', cairo.PathData, ptr = true }, { 'num_data', ti.int }, }, methods = { extents = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, }, }, { 'FontExtents', fields = { { 'ascent', ti.double }, { 'descent', ti.double }, { 'height', ti.double }, { 'max_x_advance', ti.double }, { 'max_y_advance', ti.double }, }, }, { 'TextExtents', fields = { { 'x_bearing', ti.double }, { 'y_bearing', ti.double }, { 'width', ti.double }, { 'height', ti.double }, { 'x_advance', ti.double }, { 'y_advance', ti.double }, }, }, { 'Context', cprefix = '', methods = { create = { static = true, ret = { cairo.Context, xfer = true }, cairo.Surface }, status = { ret = cairo.Status }, save = {}, restore = {}, get_target = { ret = cairo.Surface}, push_group = {}, push_group_with_content = { cairo.Content }, pop_group = { ret = { cairo.Pattern, xfer = true } }, pop_group_to_source = {}, get_group_target = { ret = cairo.Surface }, set_source_rgb = { ti.double, ti.double, ti.double }, set_source_rgba = { ti.double, ti.double, ti.double, ti.double }, set_source = { cairo.Pattern }, set_source_surface = { cairo.Surface, ti.double, ti.double }, get_source = { ret = cairo.Pattern }, set_antialias = { cairo.Antialias }, get_antialias = { ret = cairo.Antialias }, get_dash_count = { ret = ti.int }, set_fill_rule = { cairo.FillRule }, get_fill_rule = { ret = cairo.FillRule }, set_line_cap = { cairo.LineCap }, get_line_cap = { ret = cairo.LineCap }, set_line_join = { cairo.LineJoin }, get_line_join = { ret = cairo.LineJoin }, set_line_width = { ti.double }, get_line_width = { ret = ti.double }, set_miter_limit = { ti.double }, get_miter_limit = { ret = ti.double }, set_operator = { cairo.Operator }, get_operator = { ret = cairo.Operator }, set_tolerance = { ti.double }, get_tolerance = { ret = ti.double }, clip = {}, clip_preserve = {}, clip_extents = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, in_clip = { ret = ti.boolean, ti.double, ti.double }, reset_clip = {}, copy_clip_rectangle_list = { ret = { cairo.RectangleList, xfer = true } }, fill = {}, fill_preserve = {}, fill_extents = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, in_fill = { ret = ti.boolean, ti.double, ti.double }, mask = { cairo.Pattern }, mask_surface = { cairo.Pattern, ti.double, ti.double }, paint = {}, paint_with_alpha = { ti.double }, stroke = {}, stroke_preserve = {}, stroke_extents = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, in_stroke = { ret = ti.boolean, ti.double, ti.double }, copy_page = {}, show_page = {}, copy_path = { ret = { cairo.Path, xfer = true } }, copy_path_flat = { ret = { cairo.Path, xfer = true } }, append_path = { cairo.Path }, has_current_point = { ret = ti.boolean }, get_current_point = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, new_path = {}, new_sub_path = {}, close_path = {}, arc = { ti.double, ti.double, ti.double, ti.double, ti.double }, arc_negative = { ti.double, ti.double, ti.double, ti.double, ti.double }, curve_to = { ti.double, ti.double, ti.double, ti.double, ti.double, ti.double }, line_to = { ti.double, ti.double }, move_to = { ti.double, ti.double }, rectangle = { ti.double, ti.double, ti.double, ti.double }, -- glyph_path, text_path = { ti.utf8 }, rel_curve_to = { ti.double, ti.double, ti.double, ti.double, ti.double, ti.double }, rel_line_to = { ti.double, ti.double }, rel_move_to = { ti.double, ti.double }, path_extents = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, translate = { ti.double, ti.double }, scale = { ti.double, ti.double }, rotate = { ti.double }, transform = { cairo.Matrix }, set_matrix = { cairo.Matrix }, get_matrix = { cairo.Matrix }, identity_matrix = {}, user_to_device = { { ti.double, dir = 'inout' }, { ti.double, dir = 'inout' } }, user_to_device_distance = { { ti.double, dir = 'inout' }, { ti.double, dir = 'inout' } }, device_to_user = { { ti.double, dir = 'inout' }, { ti.double, dir = 'inout' } }, device_to_user_distance = { { ti.double, dir = 'inout' }, { ti.double, dir = 'inout' } }, select_font_face = { ti.utf8, cairo.FontSlant, cairo.FontWeight }, set_font_size = { ti.double }, set_font_matrix = { cairo.Matrix }, get_font_matrix = { cairo.Matrix }, set_font_options = { cairo.FontOptions }, get_font_options = { cairo.FontOptions }, set_font_face = { cairo.FontFace }, get_font_face = { ret = cairo.FontFace }, set_scaled_font = { cairo.ScaledFont }, get_scaled_font = { ret = cairo.ScaledFont }, show_text = { ti.utf8 }, -- show_glyphs, show_text_glyphs font_extents = { cairo.FontExtents }, text_extents = { ti.utf8, cairo.TextExtents }, -- glyph extents }, properties = { 'status', 'target', 'source', 'antialias', 'fill_rule', 'line_cap', 'line_join', 'line_width', 'miter_limit', 'operator', 'tolerance', 'font_size', 'font_face', 'scaled_font', }, }, { 'Pattern', methods = { status = { ret = cairo.Status }, set_extend = { cairo.Extend }, get_extend = { ret = cairo.Extend }, set_filter = { cairo.Filter }, get_filter = { ret = cairo.Filter }, set_matrix = { cairo.Matrix }, get_matrix = { cairo.Matrix }, get_type = { ret = cairo.PatternType }, }, properties = { 'status', 'extend', 'filter', 'type' }, }, { 'SolidPattern', parent = cairo.Pattern, cprefix = 'pattern_', methods = { create_rgb = { static = true, ret = { cairo.Pattern, xfer = true }, ti.double, ti.double, ti.double }, create_rgba = { static = true, ret = { cairo.Pattern, xfer = true }, ti.double, ti.double, ti.double, ti.double }, get_rgba = { ret = cairo.Status, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, }, }, { 'SurfacePattern', parent = cairo.Pattern, cprefix = 'pattern_', methods = { create = { cname = 'cairo_pattern_create_for_surface', static = true, ret = { cairo.Pattern, xfer = true }, cairo.Surface }, get_surface = { ret = cairo.Status, { cairo.Surface, dir = 'out' } }, }, }, { 'GradientPattern', parent = cairo.Pattern, cprefix = 'pattern_', methods = { add_color_stop_rgb = { ti.double, ti.double, ti.double, ti.double }, add_color_stop_rgba = { ti.double, ti.double, ti.double, ti.double, ti.double }, get_color_stop_count = { ret = cairo.Status, { ti.int, dir = 'out' } }, get_color_stop_rgba = { ret = cairo.Status, ti.int, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, }, }, { 'LinearPattern', parent = cairo.GradientPattern, cprefix = 'pattern_', methods = { create = { cname = 'cairo_pattern_create_linear', static = true, ret = { cairo.Pattern, xfer = true }, ti.double, ti.double, ti.double, ti.double }, get_linear_points = { ret = cairo.Status, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, } }, { 'RadialPattern', parent = cairo.GradientPattern, cprefix = 'pattern_', methods = { create = { cname = 'cairo_pattern_create_radial', static = true, ret = { cairo.Pattern, xfer = true }, ti.double, ti.double, ti.double, ti.double, ti.double, ti.double }, get_radial_circles = { ret = cairo.Status, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, }, }, { 'MeshPattern', parent = cairo.Pattern, since = cairo.version_encode(1, 12, 0), methods = { create = { cname = 'cairo_pattern_create_mesh', static = true, ret = { cairo.Pattern, xfer = true } }, begin_patch = {}, end_patch = {}, move_to = { ti.double, ti.double }, line_to = { ti.double, ti.double }, curve_to = { ti.double, ti.double, ti.double, ti.double, ti.double, ti.double }, set_control_point = { ti.int, ti.double, ti.double }, set_corner_color_rgb = { ti.int, ti.double, ti.double, ti.double }, set_corner_color_rgba = { ti.int, ti.double, ti.double, ti.double, ti.double }, get_patch_count = { ret = cairo.Status, { ti.int, dir = 'out' } }, get_path = { ret = { cairo.Path, xfer = true }, ti.int }, get_control_point = { ret = cairo.Status, ti.int, ti.int, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, get_corner_color_rgba = { ret = cairo.Status, ti.int, ti.int, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, }, }, { 'Device', methods = { status = { ret = cairo.Status }, finish = {}, flush = {}, get_type = { ret = cairo.DeviceType }, acquire = { ret = cairo.Status }, release = {}, }, properties = { 'status' }, }, { 'Format', methods = { stride_for_width = { ret = ti.int, ti.int }, }, }, { 'Surface', methods = { create_similar = { ret = { cairo.Surface, xfer = true }, cairo.Content, ti.int, ti.int }, create_for_rectangle = { ret = { cairo.Surface, xfer = true }, ti.double, ti.double, ti.double, ti.double }, status = { ret = cairo.Status }, finish = {}, flush = {}, get_device = { ret = cairo.Device }, get_font_options = { cairo.FontOptions }, get_content = { ret = cairo.Content }, mark_dirty = {}, mark_dirty_rectangle = { ti.int, ti.int, ti.int, ti.int }, set_device_offset = { ti.double, ti.double }, get_device_offset = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, set_fallback_resolution = { ti.double, ti.double }, get_fallback_resolution = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, get_type = { ret = cairo.SurfaceType }, copy_page = {}, show_page = {}, has_show_text_glyphs = { ret = ti.boolean }, -- set_mime_data, get_mime_data write_to_png = { ret = cairo.Status, ti.filename }, }, properties = { 'status', 'device', 'content', 'type' }, }, { 'ImageSurface', parent = cairo.Surface, methods = { create = { static = true, ret = { cairo.Surface, xfer = true }, cairo.Format, ti.int, ti.int }, create_for_data = { static = true, ret = { cairo.Surface, xfer = true }, ti.ptr, cairo.Format, ti.int, ti.int, ti.int }, create_from_png = { static = true, ret = { cairo.Surface, xfer = true }, ti.filename }, get_data = { ret = ti.ptr }, get_format = { ret = cairo.Format }, get_width = { ret = ti.int }, get_height = { ret = ti.int }, get_stride = { ret = ti.int }, }, properties = { 'data', 'format', 'width', 'height', 'stride' }, }, { 'PdfVersion', values = { ['1_4'] = 0, ['1_5'] = 1, }, }, { 'PdfSurface', parent = cairo.Surface, methods = { create = { static = true, ret = { cairo.Surface, xfer = true }, ti.filename, ti.double, ti.double }, restrict_to_version = { cairo.PdfVersion }, set_size = { ti.double, ti.double }, }, }, { 'PsLevel', values = { ['2'] = 0, ['3'] = 1, }, }, { 'PsSurface', parent = cairo.Surface, methods = { create = { static = true, ret = { cairo.Surface, xfer = true }, ti.filename, ti.double, ti.double }, restrict_to_level = { cairo.PsLevel }, set_eps = { ti.boolean }, get_eps = { ret = ti.boolean }, set_size = { ti.double, ti.double }, dsc_begin_setup = {}, dsc_begin_page_setup = {}, dsc_comment = { ti.utf8 }, }, properties = { 'eps' }, }, { 'RecordingSurface', parent = cairo.Surface, methods = { create = { static = true, ret = { cairo.Surface, xfer = true }, cairo.Content, cairo.Rectangle }, ink_extents = { { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' }, { ti.double, dir = 'out' } }, get_extents = { since = cairo.version_encode(1, 12, 0), ret = ti.boolean, cairo.Rectangle }, }, }, { 'SvgVersion', values = { ['1_1'] = 0, ['1_2'] = 1, }, }, { 'SvgSurface', parent = cairo.Surface, methods = { create = { static = true, ret = { cairo.Surface, xfer = true }, ti.filename, ti.double, ti.double }, restrict_to_version = { cairo.SvgVersion }, }, }, { 'FontFace', methods = { status = { ret = cairo.Status }, get_type = { ret = cairo.FontType }, }, properties = { 'status', 'type' }, }, { 'ToyFontFace', parent = cairo.FontFace, methods = { create = { static = true, ret = { cairo.ToyFontFace, xfer = true }, ti.utf8, cairo.FontSlant, cairo.FontWeight }, get_family = { ret = ti.utf8 }, get_slant = { ret = cairo.Slant }, get_weight = { ret = cairo.Weight }, }, properties = { 'family', 'slant', 'weight' }, }, { 'FontOptions', methods = { create = { static = true, ret = { cairo.FontOptions, xfer = true } }, copy = { ret = { cairo.FontOptions, xfer = true } }, status = { ret = cairo.Status }, merge = { cairo.FontOptions }, hash = { ret = ti.ulong }, equal = { ret = ti.boolean, cairo.FontOptions }, set_antialias = { cairo.Antialias }, get_antialias = { ret = cairo.Antialias }, set_subpixel_order = { cairo.SubpixelOrder }, get_subpixel_order = { ret = cairo.SubpixelOrder }, set_hint_style = { cairo.HintStyle }, get_hint_style = { ret = cairo.HintStyle }, set_hint_metrics = { cairo.HintMetrics }, get_hint_metrics = { ret = cairo.HintMetrics }, }, properties = { 'status', 'antialias', 'subpixel_order', 'hint_style', 'hint_metrics' }, }, { 'ScaledFont', methods = { create = { static = true, ret = { cairo.ScaledFont, xfer = true }, cairo.FontFace, cairo.Matrix, cairo.Matrix, cairo.FontOptions }, status = { ret = cairo.Status }, extents = { cairo.FontExtents }, text_extents = { ti.utf8, cairo.TextExtents }, -- glyph_extents, text_to_glyphs get_font_face = { ret = cairo.FontFace }, get_font_options = { cairo.FontOptions }, get_font_matrix = { cairo.Matrix }, get_ctm = { cairo.Matrix }, get_scale_matrix = { cairo.Matrix }, get_type = { ret = cairo.FontType }, }, properties = { 'status', 'font_face' }, }, { 'Region', methods = { create = { static = true, ret = { cairo.Region, xfer = true } }, create_rectangle = { static = true, ret = { cairo.Region, xfer = true }, cairo.RectangleInt }, copy = { ret = cairo.Region }, status = { ret = cairo.Status }, get_extents = { cairo.RectangleInt }, num_rectangles = { ret = ti.int }, get_rectangle = { ti.int, cairo.RectangleInt }, is_empty = { ret = ti.boolean }, contains_point = { ret = ti.boolean, ti.int, ti.int }, contains_rectangle = { ret = cairo.RegionOverlap, cairo.RectangleInt }, equal = { ret = ti.boolean, cairo.Region }, translate = { ti.int, ti.int }, intersect = { ret = cairo.Status, cairo.Region }, intersect_rectangle = { ret = cairo.Status, cairo.RectangleInt }, subtract = { ret = cairo.Status, cairo.Region }, subtract_rectangle = { ret = cairo.Status, cairo.RectangleInt }, union = { ret = cairo.Status, cairo.Region }, union_rectangle = { ret = cairo.Status, cairo.RectangleInt }, xor = { ret = cairo.Status, cairo.Region }, xor_rectangle = { ret = cairo.Status, cairo.RectangleInt }, }, properties = { 'status', 'extents', }, }, } do if cairo.version >= (info.since or 0) then local name = info[1] local obj = assert(cairo[name], name) obj._parent = info.parent if info.methods then -- Go through description of the methods and create functions -- from them. obj._method = {} local cprefix = 'cairo_' .. (info.cprefix or name:gsub('([%l%d])([%u])', '%1_%2'):lower() .. '_') local self_arg = { obj } for method_name, method_info in pairs(info.methods) do if cairo.version >= (method_info.since or 0) then method_info.name = 'cairo.' .. name .. '.' .. method_name method_info.addr = assert( cairo._module[ method_info.cname or (cprefix .. method_name)]) if not method_info.static then table.insert(method_info, 1, self_arg) end method_info.ret = method_info.ret or ti.void obj._method[method_name] = core.callable.new(method_info) end end end if info.values then -- Fill in addition enum/bitflag values. for n, v in pairs(info.values) do obj[n] = v end end if info.properties then -- Aggregate getters/setters into pseudoproperties -- implemented as attributes. obj._attribute = {} for _, attr in pairs(info.properties) do obj._attribute[attr] = { get = obj._method['get_' .. attr] or obj._method[attr], set = obj._method['set_' .. attr], } end end if info.fields then -- Load record fields definition ffi.load_fields(obj, info.fields) end end end -- Teach non-boxed structs how to destroy itself. cairo.RectangleList._free = cairo._module.cairo_rectangle_list_destroy cairo.Path._free = cairo._module.cairo_path_destroy cairo.FontOptions._free = cairo._module.cairo_font_options_destroy -- Add Matrix creation routines. for _, name in pairs { 'identity', 'scale', 'rotate', 'translate' } do local init = cairo.Matrix._method['init_' .. name] cairo.Matrix._method['create_' .. name] = function(...) local matrix = core.record.new(cairo.Matrix) init(matrix, ...) return matrix end end -- FontOptions can be created only by 'create' method. function cairo.FontOptions._method:_new(props) local font_options = self.create() for k, v in pairs(props or {}) do font_options[k] = v end return font_options end -- Fix all methods using caller-alloc attribute, which is not -- supported by ffi. Emulate it 'by-hand', creating Lua wrapper for -- them. for _, info in pairs { { cairo.Context, 'matrix', cairo.Matrix }, { cairo.Context, 'font_matrix', cairo.Matrix }, { cairo.Context, 'font_options', cairo.FontOptions }, { cairo.Context, 'font_extents', cairo.FontExtents }, { cairo.Context, 'text_extents', cairo.TextExtents, args = 1 }, { cairo.Pattern, 'matrix', cairo.Matrix }, { cairo.Surface, 'font_options', cairo.FontOptions }, { cairo.ScaledFont, 'font_matrix', cairo.Matrix }, { cairo.ScaledFont, 'ctm', cairo.Matrix }, { cairo.ScaledFont, 'scale_matrix', cairo.Matrix }, { cairo.ScaledFont, 'font_options', cairo.FontOptions }, { cairo.ScaledFont, 'extents', cairo.FontExtents }, { cairo.ScaledFont, 'text_extents', cairo.TextExtents, args = 1 }, { cairo.RecordingSurface, 'extents', cairo.Rectangle }, { cairo.Region, 'extents', cairo.RectangleInt }, { cairo.Region, 'get_rectangle', cairo.RectangleInt, args = 1 }, } do local getter_name = 'get_' ..info[2] local raw_getter = info[1]._method[getter_name] if not raw_getter then getter_name = info[2] raw_getter = info[1]._method[getter_name] end if raw_getter then if info.args == 1 then info[1]._method[getter_name] = function(self, arg1) local ret = info[3]() local res = raw_getter(self, arg1, ret) return (res == nil or res) and ret or nil end else info[1]._method[getter_name] = function(self) local ret = info[3]() local res = raw_getter(self, ret) return (res == nil or res) and ret or nil end info[1]._attribute[info[2]] = { get = info[1][getter_name], set = info[1]['set_' .. info[2]], } end end end -- Choose correct 'subclass' of surface on attaching to surface instances. local surface_type_map = { IMAGE = cairo.ImageSurface, PDF = cairo.PdfSurface, PS = cairo.PsSurface, SVG = cairo.SvgSurface, RECORDING = cairo.RecordingSurface, } function cairo.Surface:_attach(surface) local type = cairo.Surface._method.get_type(surface) local repotype = surface_type_map[type] if repotype then core.record.set(surface, repotype) end end -- Also choose correct 'subclass' for patterns. local pattern_type_map = { SOLID = cairo.SolidPattern, SURFACE = cairo.SurfacePattern, LINEAR = cairo.LinearPattern, RADIAL = cairo.RadialPattern, MESH = cairo.MeshPattern } function cairo.Pattern:_attach(pattern) local type = cairo.Pattern._method.get_type(pattern) local repotype = pattern_type_map[type] if repotype then core.record.set(pattern, repotype) end end -- Solid pattern constructor, calling either rgb or rgba variant -- according to the number of arguments. function cairo.SolidPattern._method.create(red, green, blue, alpha) if alpha then return cairo.SolidPattern._method.create_rgba(red, green, blue, alpha) else return cairo.SolidPattern._method.create_rgb(red, green, blue) end end -- For backward compatibility, propagate pattern creation methods from -- specific subpattern types into base cairo.Pattern class. cairo.Pattern._method.create_rgb = cairo.SolidPattern.create_rgb cairo.Pattern._method.create_rgba = cairo.SolidPattern.create_rgba cairo.Pattern._method.create_for_surface = cairo.SurfacePattern.create cairo.Pattern._method.create_linear = cairo.LinearPattern.create cairo.Pattern._method.create_radial = cairo.RadialPattern.create if cairo.MeshPattern then cairo.Pattern._method.create_mesh = cairo.MeshPattern.create end -- Map all 'create' methods to constructors. for _, struct in pairs(cairo._struct) do local create = struct._method and struct._method.create if create then function struct._new(typetable, ...) return create(...) end end end -- Implementation of Context.dash operations. Since ffi does not -- support arrays of doubles, we cheat here and use array of structs -- containing only single 'double' field. local wrapped_double = component.create(nil, record.struct_mt) ffi.load_fields(wrapped_double, { { 'v', ti.double } }) local raw_set_dash = core.callable.new { addr = cairo._module.cairo_set_dash, ret = ti.void, cairo.Context, wrapped_double, ti.int, ti.double } local raw_get_dash = core.callable.new { addr = cairo._module.cairo_get_dash, ret = ti.void, cairo.Context, wrapped_double, { ti.double, dir = 'out' } } function cairo.Context:set_dash(dashes, offset) local count, array = 0 if dashes and #dashes > 0 then -- Convert 'dashes' array into the native array of wrapped_double -- records. count = #dashes array = core.record.new(wrapped_double, nil, count) for i = 1, count do core.record.fromarray(array, i - 1).v = dashes[i] end end raw_set_dash(self, array, count, offset) end function cairo.Context:get_dash() local dashes, offset = {}, 0 local count = self:get_dash_count() if count > 0 then -- Prepare native array of wrapped doubles of specified size. local array = core.record.new(wrapped_double, nil, count) -- Get the dashes. offset = raw_get_dash(self, array) -- Convert output to the table. for i = 1, count do dashes[i] = core.record.fromarray(array, i - 1).v end end return dashes, offset end -- Implementation of iteration protocol over the cairo.Path function cairo.Path:pairs() local index = 0 return function() -- Bounds check, and get appropriate header PathData element. if index >= self.num_data then return nil end local path_data = core.record.fromarray(self.data, index) local type, length = path_data.header.type, path_data.header.length -- Create 'points' table. local points = {} if type ~= 'CLOSE_PATH' then points[1] = core.record.fromarray(self.data, index + 1).point if type == 'CURVE_TO' then points[2] = core.record.fromarray(self.data, index + 2).point points[3] = core.record.fromarray(self.data, index + 3).point end end -- Skip this logical item. index = index + length return type, points end end lua-lgi-0.7.2/lgi/package.lua000066400000000000000000000030671221440706400157310ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Support for repository packages (namespaces with classes -- overriden in lgi) -- -- Copyright (c) 2012 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local rawget, setmetatable, assert, error = rawget, setmetatable, assert, error local core = require 'lgi.core' -- Repo package metatable. local package = { mt = {} } package.mt.__index = package.mt -- There is no lazy-loading, but define _resolve to do nothing to -- achieve API compatibility with GI-based namespaces. function package.mt:_resolve(recurse) return self end -- Defines new class, deriving from existing one. If the class -- already exists, does nothing and returns nil, otherwise returns -- newly created class type. function package.mt:class(name, parent, ...) if self[name] then return nil end local class = parent:derive(self._name .. '.' .. name, ...) self[name] = class return class end -- Makes sure that given package exists, creates it if it does not. function package.ensure(name, version) local ns = rawget(core.repo, name) if not ns then ns = setmetatable({ _name = name, _version = version }, package.mt) core.repo[name] = ns else if version and ns._version and version ~= nv._version then error(("%s-%s: required version %s "):format( ns._name, ns._version, version)) end end return ns end return package lua-lgi-0.7.2/lgi/record.c000066400000000000000000000436621221440706400152620ustar00rootroot00000000000000/* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * * Copyright (c) 2010, 2011, 2012 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Management of structures and unions (i.e. records). */ #include #include "lgi.h" /* Available record store modes. */ typedef enum _RecordStore { /* We do not have ownership of the record. */ RECORD_STORE_EXTERNAL, /* Record is stored in data section of Record proxy itself. */ RECORD_STORE_EMBEDDED, /* Record is placed inside some other (parent) record. In order to keep parent record alive, parent record is stored in parent_cache table. */ RECORD_STORE_NESTED, /* Record is allocated by its GLib means and must be freed (by g_boxed_free). */ RECORD_STORE_ALLOCATED, } RecordStore; /* Userdata containing record reference. Table with record type is attached as userdata environment. */ typedef struct _Record { /* Address of the record memory data. */ gpointer addr; /* Store mode of the record. */ RecordStore store; /* If the record is allocated 'on the stack', its data is here. Anonymous union makes sure that data is properly aligned to hold (hopefully) any structure. */ union { gchar data[1]; double align_double; long align_long; gpointer align_ptr; }; } Record; /* lightuserdata key to LUA_REGISTRYINDEX containing metatable for record. */ static int record_mt; /* lightuserdata key to cache table containing lightuserdata(record->addr) -> weak(record) */ static int record_cache; /* lightuserdata key to cache table containing recordproxy(weak) -> parent */ static int parent_cache; gpointer lgi_record_new (lua_State *L, int count) { Record *record; size_t size; luaL_checkstack (L, 4, ""); /* Calculate size of the record to allocate. */ lua_getfield (L, -1, "_size"); size = G_STRUCT_OFFSET (Record, data) + lua_tonumber (L, -1) * count; lua_pop (L, 1); /* Allocate new userdata for record object, attach proper metatable. */ record = lua_newuserdata (L, size); lua_pushlightuserdata (L, &record_mt); lua_rawget (L, LUA_REGISTRYINDEX); lua_setmetatable (L, -2); record->addr = record->data; memset (record->addr, 0, size - G_STRUCT_OFFSET (Record, data)); record->store = RECORD_STORE_EMBEDDED; /* Get ref_repo table, attach it as an environment. */ lua_pushvalue (L, -2); lua_setfenv (L, -2); /* Store newly created record into the cache. */ lua_pushlightuserdata (L, &record_cache); lua_rawget (L, LUA_REGISTRYINDEX); lua_pushlightuserdata (L, record->addr); lua_pushvalue (L, -3); lua_rawset (L, -3); lua_pop (L, 1); /* Invoke '_attach' method if present on the typetable. */ lua_getfield (L, -2, "_attach"); if (!lua_isnil (L, -1)) { lua_pushvalue (L, -3); lua_pushvalue (L, -3); lua_call (L, 2, 0); } else lua_pop (L, 1); /* Remove refrepo table from the stack. */ lua_remove (L, -2); return record->addr; } void lgi_record_2lua (lua_State *L, gpointer addr, gboolean own, int parent) { Record *record; luaL_checkstack (L, 5, ""); /* NULL pointer results in 'nil'. */ if (addr == NULL) { lua_pop (L, 1); lua_pushnil (L); return; } /* Convert 'parent' index to an absolute one. */ if (parent == LGI_PARENT_IS_RETVAL || parent == LGI_PARENT_FORCE_POINTER) parent = 0; else lgi_makeabs (L, parent); /* Prepare access to cache. */ lua_pushlightuserdata (L, &record_cache); lua_rawget (L, LUA_REGISTRYINDEX); /* Check whether the record is already cached. */ lua_pushlightuserdata (L, addr); lua_rawget (L, -2); if (!lua_isnil (L, -1) && parent == 0) { /* Remove unneeded tables under our requested object. */ lua_replace (L, -3); lua_pop (L, 1); /* In case that we want to own the record, make sure that the ownership is properly updated. */ record = lua_touserdata (L, -1); g_assert (record->addr == addr); if (own && record->store == RECORD_STORE_EXTERNAL) record->store = RECORD_STORE_ALLOCATED; return; } /* Allocate new userdata for record object, attach proper metatable. */ record = lua_newuserdata (L, G_STRUCT_OFFSET (Record, data)); lua_pushlightuserdata (L, &record_mt); lua_rawget (L, LUA_REGISTRYINDEX); lua_setmetatable (L, -2); record->addr = addr; if (parent != 0) { /* Store reference to the parent argument into parent reference cache. */ lua_pushlightuserdata (L, &parent_cache); lua_rawget (L, LUA_REGISTRYINDEX); lua_pushvalue (L, -2); lua_pushvalue (L, parent); lua_rawset (L, -3); lua_pop (L, 1); record->store = RECORD_STORE_NESTED; } else { if (!own) { /* Check, whether refrepo table specifies custom _refsink function. */ void (*refsink_func)(gpointer) = lgi_gi_load_function (L, -4, "_refsink"); if (refsink_func) { refsink_func(addr); own = TRUE; } } record->store = own ? RECORD_STORE_ALLOCATED : RECORD_STORE_EXTERNAL; } /* Assign refrepo table (on the stack when we are called) as environment for our proxy. */ lua_pushvalue (L, -4); lua_setfenv (L, -2); /* Store newly created record into the cache. */ if (parent == 0 && own) { lua_pushlightuserdata (L, addr); lua_pushvalue (L, -2); lua_rawset (L, -5); } /* Invoke '_attach' method if present on the typetable. */ lua_getfield (L, -4, "_attach"); if (!lua_isnil (L, -1)) { lua_pushvalue (L, -5); lua_pushvalue (L, -3); lua_call (L, 2, 0); } else lua_pop (L, 1); /* Clean up the stack; remove cache table from under our result, and remove also typetable which was present when we were called. */ lua_replace (L, -4); lua_pop (L, 2); } /* Checks that given argument is Record userdata and returns pointer to it. Returns NULL if narg has bad type. */ static Record * record_check (lua_State *L, int narg) { /* Check using metatable that narg is really Record type. */ Record *record = lua_touserdata (L, narg); luaL_checkstack (L, 3, ""); if (!lua_getmetatable (L, narg)) return NULL; lua_pushlightuserdata (L, &record_mt); lua_rawget (L, LUA_REGISTRYINDEX); if (!lua_equal (L, -1, -2)) record = NULL; lua_pop (L, 2); return record; } /* Throws error that narg is not of expected type. */ static int record_error (lua_State *L, int narg, const gchar *expected_name) { luaL_checkstack (L, 2, ""); lua_pushstring (L, lua_typename (L, lua_type (L, narg))); lua_pushfstring (L, "%s expected, got %s", expected_name ? expected_name : "lgi.record", lua_tostring (L, -1)); return luaL_argerror (L, narg, lua_tostring (L, -1)); } /* Similar to record_check, but throws in case of failure. */ static Record * record_get (lua_State *L, int narg) { Record *record = record_check (L, narg); if (record == NULL) record_error (L, narg, NULL); return record; } void lgi_record_2c (lua_State *L, int narg, gpointer target, gboolean by_value, gboolean own, gboolean optional, gboolean nothrow) { Record *record = NULL; /* Check for nil. */ if (!optional || !lua_isnoneornil (L, narg)) { /* Get record and check its type. */ lgi_makeabs (L, narg); luaL_checkstack (L, 4, ""); record = record_check (L, narg); if (record) { /* Check, whether type fits. Also take into account possible inheritance. */ lua_getfenv (L, narg); for (;;) { if (lua_equal (L, -1, -2)) break; /* Try to get parent of the real type. */ lua_getfield (L, -1, "_parent"); lua_replace (L, -2); if (lua_isnil (L, -1)) { record = NULL; break; } } lua_pop (L, 1); } if (!nothrow && !record) { const gchar *name = NULL; if (!lua_isnil (L, -1)) { lua_getfield (L, -1, "_name"); name = lua_tostring (L, -1); } record_error (L, narg, name); } } if (G_LIKELY (!by_value)) { *(gpointer *) target = record ? record->addr : NULL; if (record && own) { /* Caller wants to steal ownership from us. */ if (G_LIKELY (record->store == RECORD_STORE_ALLOCATED)) record->store = RECORD_STORE_EXTERNAL; else g_critical ("attempt to steal record ownership from unowned rec"); } } else { gsize size; lua_getfield (L, -1, "_size"); size = lua_tonumber (L, -1); lua_pop (L, 1); if (record) { /* Check, whether custom _copy is registered. */ void (*copy_func)(gpointer, gpointer) = lgi_gi_load_function (L, -1, "_copy"); if (copy_func) copy_func (record->addr, target); else memcpy (target, record->addr, size); } else /* Transferring NULL ptr, simply NULL target. */ memset (target, 0, size); } lua_pop (L, 1); } static int record_gc (lua_State *L) { Record *record = record_get (L, 1); if (record->store == RECORD_STORE_EMBEDDED || record->store == RECORD_STORE_NESTED) { /* Check whether record has registered '_uninit' function, and invoke it if yes. */ lua_getfenv (L, 1); void (*uninit)(gpointer) = lgi_gi_load_function (L, -1, "_uninit"); if (uninit != NULL) uninit (record->addr); } else if (record->store == RECORD_STORE_ALLOCATED) { /* Free the owned record. */ GType gtype; lua_getfenv (L, 1); for (;;) { lua_getfield (L, -1, "_gtype"); gtype = (GType) lua_touserdata (L, -1); lua_pop (L, 1); if (G_TYPE_IS_BOXED (gtype)) { g_boxed_free (gtype, record->addr); break; } else { /* Use custom _free function. */ void (*free_func)(gpointer) = lgi_gi_load_function (L, -1, "_free"); if (free_func) { free_func (record->addr); break; } } /* Try to get parent of the type. */ lua_getfield (L, -1, "_parent"); lua_replace (L, -2); if (lua_isnil (L, -1)) { lua_getfenv (L, 1); lua_getfield (L, -1, "_name"); g_warning ("unable to record_gc %s, leaking it", lua_tostring (L, -1)); lua_pop (L, 2); break; } } } if (record->store == RECORD_STORE_NESTED) { /* Free the reference to the parent. */ lua_pushlightuserdata (L, record); lua_pushnil (L); lua_rawset (L, LUA_REGISTRYINDEX); } return 0; } static int record_tostring (lua_State *L) { Record *record = record_get (L, 1); lua_pushfstring (L, "lgi.rec %p:", record->addr); lua_getfenv (L, 1); lua_getfield (L, -1, "_name"); lua_replace (L, -2); if (!lua_isnil (L, -1)) lua_concat (L, 2); else lua_pop (L, 1); return 1; } /* Worker method for __index and __newindex implementation. */ static int record_access (lua_State *L) { gboolean getmode = lua_isnone (L, 3); /* Check that 1st arg is a record and invoke one of the forms: result = type:_access(recordinstance, name) type:_access(recordinstance, name, val) */ record_get (L, 1); lua_getfenv (L, 1); return lgi_marshal_access (L, getmode, 1, 2, 3); } /* Worker method for __len implementation. */ static int record_len (lua_State *L) { /* Check record, get its typetable and try to invoke _len method. */ record_get (L, 1); lua_getfenv (L, 1); lua_getfield (L, -1, "_len"); if (lua_isnil (L, -1)) { lua_getfield (L, -2, "_name"); return luaL_error (L, "`%s': attempt to get length", lua_tostring (L, -1)); } lua_pushvalue (L, 1); lua_call (L, 1, 1); return 1; } static const struct luaL_Reg record_meta_reg[] = { { "__gc", record_gc }, { "__tostring", record_tostring }, { "__index", record_access }, { "__newindex", record_access }, { "__len", record_len }, { NULL, NULL } }; /* Implements generic record creation. Creates new record instance, unless 'addr' argument (lightuserdata or integer) is specified, in which case wraps specified address as record. Lua prototype: recordinstance = core.record.new(repotable[, nil[, count]]) recordinstance = core.record.new(repotable[, addr[, own]]) own (default false) means whether Lua takes record ownership (i.e. if it tries to deallocate the record when created Lua proxy dies). */ static int record_new (lua_State *L) { if (lua_isnoneornil (L, 2)) { /* Create new record instance. */ luaL_checktype (L, 1, LUA_TTABLE); lua_pushvalue (L, 1); lgi_record_new (L, luaL_optinteger (L, 3, 1)); } else { /* Wrap record at existing address. */ gpointer addr = (lua_type (L, 2) == LUA_TLIGHTUSERDATA) ? addr = lua_touserdata (L, 2) : (gpointer) luaL_checkinteger (L, 2); gboolean own = lua_toboolean (L, 3); lua_pushvalue (L, 1); lgi_record_2lua (L, addr, own, 0); } return 1; } static const char* const query_modes[] = { "gtype", "repo", "addr", NULL }; /* Returns specific information mode about given record. Lua prototype: res = record.query(instance, mode) Supported 'mode' strings are: 'gtype': returns real gtype of this instance, nil when it is not boxed. 'repo': returns repotable of this instance. 'addr': returns address of the object. If 3rd argument is either repotable, checks, whether record conforms to the specs and if not, throws an error. */ static int record_query (lua_State *L) { Record *record; int mode = luaL_checkoption (L, 2, query_modes[0], query_modes); if (mode < 2) { record = record_check (L, 1); if (!record) return 0; lua_getfenv (L, 1); if (mode == 0) { GType gtype; if (lua_isnil (L, -1)) return 0; lua_getfield (L, -1, "_gtype"); gtype = luaL_optinteger (L, -1, G_TYPE_INVALID); lua_pushstring (L, g_type_name (gtype)); } return 1; } else { if (lua_isnoneornil (L, 3)) lua_pushlightuserdata (L, record_check (L, 1)->addr); else { gpointer addr; lua_pushvalue (L, 3); lgi_record_2c (L, 1, &addr, FALSE, FALSE, TRUE, FALSE); lua_pushlightuserdata (L, addr); } return 1; } } /* Implements set/get field operation. Lua prototypes: res = core.record.field(recordinstance, fieldinfo) core.record.field(recordinstance, fieldinfo, newval) */ static int record_field (lua_State *L) { gboolean getmode; Record *record; /* Check, whether we are doing set or get operation. */ getmode = lua_isnone (L, 3); /* Get record instance. */ record = record_get (L, 1); /* Call field marshalling worker. */ return lgi_marshal_field (L, record->addr, getmode, 1, 2, 3); } /* Casts given record to another record type. Lua prototype: res = core.record.cast(recordinstance, targettypetable) */ static int record_cast (lua_State *L) { Record *record = record_get (L, 1); luaL_checktype (L, 2, LUA_TTABLE); lgi_record_2lua (L, record->addr, FALSE, 1); return 1; } /* Assumes that given record is the first of the array of records and fetches record with specified index. Negative indices are allowed, but no boundschecking is made. res = core.record.fromarray(recordinstance, index) */ static int record_fromarray (lua_State *L) { Record *record = record_get (L, 1); int index = luaL_checkinteger (L, 2); int parent = 0; gboolean own = FALSE; int size; /* Find out the size of this record. */ lua_getfenv (L, 1); lua_getfield (L, -1, "_size"); size = lua_tonumber (L, -1); if (record->store == RECORD_STORE_EMBEDDED) /* Parent is actually our embedded record. */ parent = 1; else if (record->store == RECORD_STORE_NESTED) { /* Share parent with the original record. */ lua_pushlightuserdata (L, &parent_cache); lua_rawget (L, LUA_REGISTRYINDEX); lua_pushvalue (L, 1); lua_rawget (L, -2); parent = -2; } lua_getfenv (L, 1); lgi_record_2lua (L, ((guint8 *) record->addr) + size * index, own, parent); return 1; } /* Changes ownership mode or repotable of the record. record.set(recordinstance, true|false) - 'own' if true, changing ownership to owned, otherwise to unowned. record.set(recordinstance, repotable) - 'repotable' record repotable to which this instance should be reassigned. */ static int record_set (lua_State *L) { Record *record = record_get (L, 1); if (lua_type (L, 2) == LUA_TTABLE) { /* Assign new typeinfo to the record instance. */ lua_pushvalue (L, 2); lua_setfenv (L, 1); } else { /* Change ownership type of the record. */ if (lua_toboolean (L, 2)) { if (record->store == RECORD_STORE_EXTERNAL) record->store = RECORD_STORE_ALLOCATED; } else { if (record->store == RECORD_STORE_ALLOCATED) record->store = RECORD_STORE_EXTERNAL; } } return 0; } static const struct luaL_Reg record_api_reg[] = { { "new", record_new }, { "query", record_query }, { "field", record_field }, { "cast", record_cast }, { "fromarray", record_fromarray }, { "set", record_set }, { NULL, NULL } }; /* Workaround for g_value_unset(), which complains when invoked on uninitialized GValue instance. */ static void record_value_unset (GValue *value) { if (G_IS_VALUE (value)) g_value_unset (value); } /* Similar stuff for g_value_copy(), requires target argument to be preinitialized with proper type. */ static void record_value_copy (const GValue *src, GValue *dest) { g_value_init (dest, G_VALUE_TYPE (src)); g_value_copy (src, dest); } void lgi_record_init (lua_State *L) { /* Register record metatable. */ lua_pushlightuserdata (L, &record_mt); lua_newtable (L); luaL_register (L, NULL, record_meta_reg); lua_rawset (L, LUA_REGISTRYINDEX); /* Create caches. */ lgi_cache_create (L, &record_cache, "v"); lgi_cache_create (L, &parent_cache, "k"); /* Create 'record' API table in main core API table. */ lua_newtable (L); luaL_register (L, NULL, record_api_reg); lua_pushlightuserdata (L, record_value_unset); lua_setfield (L, -2, "value_unset"); lua_pushlightuserdata (L, record_value_copy); lua_setfield (L, -2, "value_copy"); lua_setfield (L, -2, "record"); } lua-lgi-0.7.2/lgi/record.lua000066400000000000000000000122741221440706400156140ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- LGI Handling of structs and unions -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local rawget, assert, select, pairs, type, error, setmetatable = rawget, assert, select, pairs, type, error, setmetatable -- Require core lgi utilities, used during bootstrap. local core = require 'lgi.core' local gi = core.gi local component = require 'lgi.component' -- Implementation of record_mt, which is inherited from component -- and provides customizations for structures and unions. local record = { struct_mt = component.mt:clone('struct', { '_method', '_field' }), } -- Checks whether given argument is type of this class. function record.struct_mt:is_type_of(instance) if type(instance) == 'userdata' then local instance_type = core.record.query(instance, 'repo') while instance_type do if instance_type == self then return true end instance_type = rawget(instance_type, '_parent') end end return false end -- Resolver for records, recursively resolves also all parents. function record.struct_mt:_resolve(recursive) -- Resolve itself using inherited implementation. component.mt._resolve(self) -- Go to parent and resolve it too. if recursive and self._parent then self._parent:_resolve(recursive) end return self end function record.struct_mt:_element(instance, symbol) -- First of all, try normal inherited functionality. local element, category = component.mt._element(self, instance, symbol) if element then return element, category end -- Special handling of '_native' attribute. if symbol == '_native' then return symbol, '_internal' elseif symbol == '_type' then return symbol, '_internal' end -- If the record has parent struct, try it there. local parent = rawget(self, '_parent') if parent then return parent:_element(instance, symbol) end end -- Add accessor for handling fields. function record.struct_mt:_access_field(instance, element, ...) -- Check whether we are marshalling subrecord local subrecord if select('#', ...) > 0 then if gi.isinfo(element) and element.is_field then local ii = element.typeinfo.interface if ii and (ii.type == 'struct' or ii.type == 'union') then subrecord = true end else if type(element) == 'table' and (element[2] == 1 or element[2] == 2) then subrecord = true end end end if subrecord then -- Write to nested structure, handle assignment to it by -- assigning separate fields. subrecord = core.record.field(instance, element) for name, value in pairs(...) do subrecord[name] = value end else -- In other cases, just access the instance using given info. return core.record.field(instance, element, ...) end end -- Add accessor for 'internal' fields handling. function record.struct_mt:_access_internal(instance, element, ...) if select('#', ...) ~= 0 then return end if element == '_native' then return core.record.query(instance, 'addr') elseif element == '_type' then return core.record.query(instance, 'repo') end end -- Create structure instance and initialize it with given fields. function record.struct_mt:_new(param, owns) local struct if type(param) == 'userdata' or type(param) == 'number' then -- Wrap existing pointer. struct = core.record.new(self, param, owns) else -- Check that we are allowed to create the record. if not self._size then error(("%s: not directly instantiable"):format(self._name), 2) end -- Create the structure instance. struct = core.record.new(self) -- Set values of fields. for name, value in pairs(param or {}) do struct[name] = value end end return struct end -- Loads structure information into table representing the structure function record.load(info) local record = component.create( info, info.is_struct and record.struct_mt or record.union_mt) record._size = info.size record._method = component.get_category(info.methods, core.callable.new) record._field = component.get_category(info.fields) -- Check, whether global namespace contains 'constructor' method, -- i.e. method which has the same name as our record type (except -- that type is in CamelCase, while method is -- under_score_delimited). If not found, check for 'new' method. local func = info.name:gsub('([%l%d])([%u])', '%1_%2'):lower() local ctor = gi[info.namespace][func] if not ctor then ctor = info.methods.new end -- Check, whether ctor is valid. In order to be valid, it must -- return instance of this record. if (ctor and ctor.return_type.tag =='interface' and ctor.return_type.interface == info) then ctor = core.callable.new(ctor) record._new = function(typetable, ...) return ctor(...) end end return record end -- Union metatable is the same as struct one, but has different name -- to differentiate unions. record.union_mt = record.struct_mt:clone('union') return record lua-lgi-0.7.2/rockspec.in000066400000000000000000000014011221440706400152070ustar00rootroot00000000000000package = 'lgi' version = '%VERSION%-1' description = { summary = "Lua bindings to GObject libraries", detailed = [[ Dynamic Lua binding to any library which is introspectable using gobject-introspection. Allows using GObject-based libraries directly from Lua. ]], license = 'MIT/X11', homepage = 'http://github.com/pavouk/lgi' } supported_platforms = { 'unix' } source = { url = 'git://github.com/pavouk/lgi.git', tag = '%VERSION%' } dependencies = { 'lua >= 5.1' } build = { type = 'make', variables = { PREFIX = '$(PREFIX)', LUA_LIBDIR = '$(LIBDIR)', LUA_SHAREDIR = '$(LUADIR)', LUA_CFLAGS = '$(CFLAGS) -I$(LUA_INCDIR)', LIBFLAG = '$(LIBFLAG)', }, copy_directories = { 'docs', 'samples' } } lua-lgi-0.7.2/samples/000077500000000000000000000000001221440706400145165ustar00rootroot00000000000000lua-lgi-0.7.2/samples/GDbus/000077500000000000000000000000001221440706400155225ustar00rootroot00000000000000lua-lgi-0.7.2/samples/GDbus/list-system-services.lua000066400000000000000000000064571221440706400223570ustar00rootroot00000000000000#! /usr/bin/env lua local help = [[ Usage: lua list-system-services.lua [--session|--system] List services on the system bus (default) or the session bus. ]] --[[ This example is the rewrite of list-system-services.py in Lua. Copyleft (C) 2012 Ildar Mulyukov Original copyright follows: # Copyright (C) 2004-2006 Red Hat Inc. # Copyright (C) 2005-2007 Collabora Ltd. # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, copy, # modify, merge, publish, distribute, sublicense, and/or sell copies # of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. ]] local lgi = require 'lgi' local Gio = lgi.require 'Gio' -- main(argv): local argv = {...} local factory = function() return Gio.bus_get_sync(Gio.BusType.SYSTEM) end if #argv > 1 then print(help) return -1 else if #argv == 1 then if argv[1] == '--session' then factory = function() return Gio.bus_get_sync(Gio.BusType.SESSION) end else if argv[1] ~= '--system' then print(help) return -1 end end end end -- Get a connection to the system or session bus as appropriate -- We're only using blocking calls, so don't actually need a main loop here local bus = factory() -- This could be done by calling bus.list_names(), but here's -- more or less what that means: -- Get a reference to the desktop bus' standard object, denoted -- by the path /org/freedesktop/DBus. -- dbus_object = bus.get_object('org.freedesktop.DBus', -- '/org/freedesktop/DBus') -- The object /org/freedesktop/DBus -- implements the 'org.freedesktop.DBus' interface -- dbus_iface = dbus.Interface(dbus_object, 'org.freedesktop.DBus') -- One of the member functions in the org.freedesktop.DBus interface -- is ListNames(), which provides a list of all the other services -- registered on this bus. Call it, and print the list. -- services = dbus_iface.ListNames() local var, err = bus:call_sync('org.freedesktop.DBus', '/org/freedesktop/DBus', 'org.freedesktop.DBus', 'ListNames', nil, nil, Gio.DBusConnectionFlags.NONE, -1) -- We know that ListNames returns '(as)' local services = var[1].value -- services.sort() - is incorrect as GVariant is immutable for i = 1, #services do print (services[i]) end lua-lgi-0.7.2/samples/GnomeKeyring/000077500000000000000000000000001221440706400171145ustar00rootroot00000000000000lua-lgi-0.7.2/samples/GnomeKeyring/list-keyrings-passwords.lua000066400000000000000000000016561221440706400244560ustar00rootroot00000000000000#! /usr/bin/env lua --[[ This example is the rewrite of Michael Schurter's sample in Lua. Copyleft (C) 2012 Ildar Mulyukov Original python program is [here](http://blog.schmichael.com/2008/10/30/listing-all-passwords-stored-in-gnome-keyring/) ]]-- local lgi = require 'lgi' local GnomeKeyring = lgi.require 'GnomeKeyring' -- main(argv): local _, keyring_names = GnomeKeyring.list_keyring_names_sync() for _, keyring in ipairs(keyring_names) do local _, item_ids = GnomeKeyring.list_item_ids_sync(keyring) for _, id in ipairs(item_ids) do local err, item = GnomeKeyring.item_get_info_sync(keyring, id) if err == 'IO_ERROR' then print ('[' .. keyring .. '] --locked--') break end print ('[' .. keyring .. '] ' .. item:get_display_name() .. ' = ' .. string.gsub(item:get_secret(), ".", "*") ) end if #item_ids == 0 then print ('[' .. keyring .. '] --empty--') end end lua-lgi-0.7.2/samples/cairo.lua000077500000000000000000000142761221440706400163330ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Sample cairo application, based on http://cairographics.org/samples/ -- -- Renders all samples into separate PNG images -- local math = require 'math' local lgi = require 'lgi' local cairo = lgi.cairo local dir = arg[0]:sub(1, arg[0]:find('[^%/\\]+$') - 1):gsub('[/\\]$', '') local imagename = dir .. '/gtk-demo/apple-red.png' local samples = {} function samples.arc(cr) local xc, yc = 128, 128 local radius = 100 local angle1, angle2 = math.rad(45), math.rad(180) cr.line_width = 10 cr:arc(xc, yc, radius, angle1, angle2) cr:stroke() -- draw helping lines cr:set_source_rgba(1, 0.2, 0.2, 0.6) cr.line_width = 6 cr:arc(xc, yc, 10, 0, math.rad(360)) cr:fill() cr:arc(xc, yc, radius, angle1, angle1) cr:line_to(xc, yc) cr:arc(xc, yc, radius, angle2, angle2) cr:line_to(xc, yc) cr:stroke() end function samples.arc_negative(cr) local xc, yc = 128, 128 local radius = 100 local angle1, angle2 = math.rad(45), math.rad(180) cr.line_width = 10 cr:arc_negative(xc, yc, radius, angle1, angle2) cr:stroke() -- draw helping lines cr:set_source_rgba(1, 0.2, 0.2, 0.6) cr.line_width = 6 cr:arc(xc, yc, 10, 0, math.rad(360)) cr:fill() cr:arc(xc, yc, radius, angle1, angle1) cr:line_to(xc, yc) cr:arc(xc, yc, radius, angle2, angle2) cr:line_to(xc, yc) cr:stroke() end function samples.clip(cr) cr:arc(128, 128, 76.8, 0, math.rad(360)) cr:clip() -- current path is not consumed by cairo.Context.clip() cr:new_path() cr:rectangle(0, 0, 256, 256) cr:fill() cr:set_source_rgb(0, 1, 0) cr:move_to(0, 0) cr:line_to(256, 256) cr:move_to(256, 0) cr:line_to(0, 256) cr.line_width = 10 cr:stroke() end function samples.clip_image(cr) cr:arc(128, 128, 76.8, 0, math.rad(360)) cr:clip() cr:new_path() local image = cairo.ImageSurface.create_from_png(imagename) cr:scale(256 / image.width, 256 / image.height) cr:set_source_surface(image, 0, 0) cr:paint() end function samples.dash(cr) cr:set_dash({ 50, 10, 10, 10 }, -50) cr.line_width = 10 cr:move_to(128, 25.6) cr:line_to(230.4, 230.4) cr:rel_line_to(-102.4, 0) cr:curve_to(51.2, 230.4, 51.2, 128, 128, 128) cr:stroke() end function samples.curve_to(cr) local x, y = 25.6, 128 local x1, y1 = 102.4, 230.4 local x2, y2 = 153.6, 25.6 local x3, y3 = 230.4, 128 cr:move_to(x, y) cr:curve_to(x1, y1, x2, y2, x3, y3) cr.line_width = 10 cr:stroke() cr:set_source_rgba(1, 0.2, 0.2, 0.6) cr.line_width = 6 cr:move_to(x, y) cr:line_to(x1, y1) cr:move_to(x2, y2) cr:line_to(x3, y3) cr:stroke() end function samples.fill_and_stroke(cr) cr:move_to(128, 25.6) cr:line_to(230.4, 230.4) cr:rel_line_to(-102.4, 0) cr:curve_to(51.2, 230.4, 51.2, 128, 128, 128) cr:close_path() cr:move_to(64, 25.6) cr:rel_line_to(51.2, 51.2) cr:rel_line_to(-51.2, 51.2) cr:rel_line_to(-51.2, -51.2) cr:close_path() cr.line_width = 10 cr:set_source_rgb(0, 0, 1) cr:fill_preserve() cr:set_source_rgb(0, 0, 0) cr:stroke() end function samples.fill_style(cr) cr.line_width = 6 cr:rectangle(12, 12, 232, 70) cr:new_sub_path() cr:arc(64, 64, 40, 0, math.rad(360)) cr:new_sub_path() cr:arc_negative(192, 64, 40, 0, math.rad(-360)) cr.fill_rule = 'EVEN_ODD' cr:set_source_rgb(0, 0.7, 0) cr:fill_preserve() cr:set_source_rgb(0, 0, 0) cr:stroke() cr:translate(0, 128) cr:rectangle(12, 12, 232, 70) cr:new_sub_path() cr:arc(64, 64, 40, 0, math.rad(360)) cr:new_sub_path() cr:arc_negative(192, 64, 40, 0, math.rad(-360)) cr.fill_rule = 'WINDING' cr:set_source_rgb(0, 0, 0.9) cr:fill_preserve() cr:set_source_rgb(0, 0, 0) cr:stroke() end function samples.gradient(cr) local pat = cairo.Pattern.create_linear(0, 0, 0, 256) pat:add_color_stop_rgba(1, 0, 0, 0, 1) pat:add_color_stop_rgba(0, 1, 1, 1, 1) cr:rectangle(0, 0, 256, 256) cr.source = pat cr:fill() pat = cairo.Pattern.create_radial(115.2, 102.4, 25.6, 102.4, 102.4, 128) pat:add_color_stop_rgba(0, 1, 1, 1, 1); pat:add_color_stop_rgba(1, 0, 0, 0, 0); cr.source = pat cr:arc(128, 128, 76.8, 0, math.rad(360)) cr:fill() end function samples.image(cr) local image = cairo.ImageSurface.create_from_png(imagename) cr:translate(128, 128) cr:rotate(math.rad(45)) cr:scale(256 / image.width, 256 / image.height) cr:translate(-image.width / 2, -image.height / 2) cr:set_source_surface(image, 0, 0) cr:paint() end function samples.imagepattern(cr) local image = cairo.ImageSurface.create_from_png(imagename) local pattern = cairo.Pattern.create_for_surface(image) pattern.extend = 'REPEAT' cr:translate(128, 128) cr:rotate(math.rad(45)) cr:scale(1 / math.sqrt(2), 1 / math.sqrt(2)) cr:translate(-128, -128) pattern.matrix = cairo.Matrix.create_scale(image.width / 256 * 5, image.height / 256 * 5) cr.source = pattern cr:rectangle(0, 0, 256, 256) cr:fill() end function samples.multisegment_caps(cr) cr:move_to(50, 75) cr:line_to(200, 75) cr:move_to(50, 125) cr:line_to(200, 125) cr:move_to(50, 175) cr:line_to(200, 175) cr.line_width = 30 cr.line_cap = 'ROUND' cr:stroke() end function samples.rounded_rectangle(cr) local x, y, width, height = 25.6, 25.6, 204.8, 204.8 local aspect = 1 local corner_radius = height / 10 local radius = corner_radius / aspect cr:new_sub_path() cr:arc(x + width - radius, y + radius, radius, math.rad(-90), math.rad(0)) cr:arc(x + width - radius, y + height - radius, radius, math.rad(0), math.rad(90)) cr:arc(x + radius, y + height - radius, radius, math.rad(90), math.rad(180)) cr:arc(x + radius, y + radius, radius, math.rad(180), math.rad(270)) cr:close_path() cr:set_source_rgb(0.5, 0.5, 1) cr:fill_preserve() cr:set_source_rgba(0.5, 0, 0, 0.5) cr.line_width = 10 cr:stroke() end -- Iterate through all samples and create .png files from them for name, sample in pairs(samples) do local surface = cairo.ImageSurface.create('ARGB32', 256, 256) local cr = cairo.Context.create(surface) sample(cr) surface:write_to_png('cairodemo-' .. name .. '.png') end lua-lgi-0.7.2/samples/clutterdemo.lua000077500000000000000000000032661221440706400175620ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Basic clutter demo. -- local lgi = require('lgi') local Clutter = lgi.require('Clutter', '1.0') local GObject = lgi.require('GObject', '2.0') local Gio = lgi.require('Gio', '2.0') local app = Gio.Application { application_id = 'org.lgi.samples.Clutter' } local stage = Clutter.Stage.get_default() stage.color = Clutter.Color(0, 0, 0, 255) stage.width = 512 stage.height = 512 stage.title = 'LGI Clutter Demo' local rects = {} for i = 1, 6 do rects[i] = Clutter.Rectangle { color = Clutter.Color( 256 / 6 * ((i - 1) % 6), 256 / 6 * ((i + 3) % 6), 256 / 6 * ((-i + 8) % 6), 128), width = 100, height = 100, fixed_x = 200, fixed_y = 200, anchor_x = 128, anchor_y = 64, reactive = true, on_button_press_event = function(rect) rect:raise_top() return true end, } stage:add_actor(rects[i]) rects[i]:show() end local timeline = Clutter.Timeline { duration = 60, loop = true } local rotation, rotation_delta = 0, 0.01 local scale, scale_delta = 1, 0.001 function timeline:on_new_frame(frame_num) rotation = rotation + rotation_delta scale = scale + scale_delta if scale > 2 or scale < 1 then scale_delta = -scale_delta end for i = 1, #rects do rects[i]:set_rotation(Clutter.RotateAxis.Z_AXIS, rotation * (#rects - i), 0, 0, 0) rects[i]:set_scale(scale, 3 - scale) end -- A bug in clutter? If following line is not present, stage stops -- redrawing itself after a while... stage:queue_redraw() end function stage:on_button_press_event(event) app:release() return true end function app:on_activate() self:hold() stage:show() timeline:start() end return app:run { arg[0], ... } lua-lgi-0.7.2/samples/console.lua000077500000000000000000000261671221440706400167020ustar00rootroot00000000000000#! /usr/bin/env lua -- Lua console implemented using Gtk widgets. local lgi = require 'lgi' local Gio = lgi.Gio local Gtk = lgi.require('Gtk', '3.0') local Gdk = lgi.require('Gdk', '3.0') local Pango = lgi.Pango local GtkSource = lgi.GtkSource -- Creates new console instance. local function Console() -- Define console object actions. local actions = { execute = Gtk.Action { name = 'execute', stock_id = Gtk.STOCK_OK, is_important = true, label = "_Execute", tooltip = "Execute", }, multiline = Gtk.ToggleAction { name = 'multiline', stock_id = Gtk.STOCK_JUSTIFY_LEFT, is_important = true, label = "_Multiline", tooltip = "Switches command entry to multiline mode", }, up = Gtk.Action { name = 'up', stock_id = Gtk.STOCK_GO_UP, label = "_Previous", tooltip = "Previous command in history", sensitive = false, }, down = Gtk.Action { name = 'down', stock_id = Gtk.STOCK_GO_DOWN, label = "_Next", tooltip = "Next command in history", sensitive = false, }, clear = Gtk.Action { name = 'clear', stock_id = Gtk.STOCK_CLEAR, label = "_Clear", tooltip = "Clear output window", }, about = Gtk.Action { name = 'about', stock_id = Gtk.STOCK_ABOUT, label = "_About", tooltip = "About", }, quit = Gtk.Action { name = 'quit', stock_id = Gtk.STOCK_QUIT, label = "_Quit", tooltip = "Quit", }, } -- Define the widget tree. local widget = Gtk.Grid { orientation = Gtk.Orientation.VERTICAL, Gtk.Toolbar { Gtk.ToolButton { related_action = actions.clear }, Gtk.SeparatorToolItem {}, Gtk.ToolItem { Gtk.FontButton { id = 'font_button' } }, Gtk.SeparatorToolItem {}, Gtk.ToolButton { related_action = actions.about }, Gtk.ToolButton { related_action = actions.quit }, }, Gtk.Paned { orientation = Gtk.Orientation.VERTICAL, { Gtk.ScrolledWindow { shadow_type = Gtk.ShadowType.IN, Gtk.TextView { id = 'output', expand = true, buffer = Gtk.TextBuffer { tag_table = Gtk.TextTagTable { Gtk.TextTag { name = 'command', foreground = 'blue' }, Gtk.TextTag { name = 'log' }, Gtk.TextTag { name = 'result', style = Pango.Style.ITALIC }, Gtk.TextTag { name = 'error', weight = Pango.Weight.BOLD, foreground = 'red' }, } } } }, resize = true }, { Gtk.Grid { orientation = Gtk.Orientation.HORIZONTAL, { Gtk.ScrolledWindow { shadow_type = Gtk.ShadowType.IN, GtkSource.View { id = 'entry', hexpand = true, wrap_mode = Gtk.WrapMode.CHAR, auto_indent = true, tab_width = 4, buffer = GtkSource.Buffer { language = GtkSource.LanguageManager.get_default(): get_language('lua'), }, } }, height = 2 }, Gtk.Toolbar { orientation = Gtk.Orientation.VERTICAL, toolbar_style = Gtk.ToolbarStyle.ICONS, vexpand = true, Gtk.ToolButton { related_action = actions.execute }, Gtk.ToggleToolButton { related_action = actions.multiline }, Gtk.SeparatorToolItem {}, Gtk.ToolButton { related_action = actions.up }, Gtk.ToolButton { related_action = actions.down }, }, { Gtk.Label { id = 'indicator', label = '1:1', single_line_mode = true, justify = Gtk.Justification.RIGHT, }, left_attach = 1, top_attach = 1 }, }, resize = true } } } -- Cache important widgets in local variables local entry = widget.child.entry local output = widget.child.output local indicator = widget.child.indicator local font_button = widget.child.font_button -- When font changes, apply it to both views. font_button.on_notify['font-name'] = function(button) local desc = Pango.FontDescription.from_string(button.font_name) output:override_font(desc) entry:override_font(desc) end -- Initialize font. Get preferred font from system settings, if -- they are installed. GSettings crash the application if the -- schema is not found, so better check first if we can use it. font_button.font_name = 'Monospace' for _, schema in pairs(Gio.Settings.list_schemas()) do if schema == 'org.gnome.desktop.interface' then font_button.font_name = Gio.Settings( { schema = schema }):get_string('monospace-font-name') break end end -- Change indicator text when position in the entry changes. entry.buffer.on_notify['cursor-position'] = function(buffer) local iter = buffer:get_iter_at_mark(buffer:get_insert()) indicator.label = iter:get_line() + 1 .. ':' .. iter:get_line_offset() + 1 end local output_end_mark = output.buffer:create_mark( nil, output.buffer:get_end_iter(), false) -- Appends text to the output window, optionally with specified tag. local function append_output(text, tag) -- Append the text. local end_iter = output.buffer:get_end_iter() local offset = end_iter:get_offset() output.buffer:insert(end_iter, text, -1) end_iter = output.buffer:get_end_iter() -- Apply proper tag. tag = output.buffer.tag_table.tag[tag] if tag then output.buffer:apply_tag(tag, output.buffer:get_iter_at_offset(offset), end_iter) end -- Scroll so that the end of the buffer is visible, but only in -- case that cursor is at the very end of the view. This avoids -- autoscroll when user tries to select something in the output -- view. local cursor = output.buffer:get_iter_at_mark(output.buffer:get_insert()) if end_iter:get_offset() == cursor:get_offset() then output:scroll_mark_onscreen(output_end_mark) end end -- Define history buffer and operations with it. local history = { '', position = 1 } local function history_select(new_position) history[history.position] = entry.buffer.text history.position = new_position entry.buffer.text = history[history.position] entry.buffer:place_cursor(entry.buffer:get_end_iter()) actions.up.sensitive = history.position > 1 actions.down.sensitive = history.position < #history end -- History navigation actions. function actions.up:on_activate() history_select(history.position - 1) end function actions.down:on_activate() history_select(history.position + 1) end -- Execute Lua command from entry and log result into output. function actions.execute:on_activate() -- Get contents of the entry. local text = entry.buffer.text:gsub('^%s?(=)%s*', 'return ') if text == '' then return end -- Add command to the output view. append_output(text:gsub('\n*$', '\n', 1), 'command') -- Try to execute the command. local chunk, answer = (loadstring or load)(text, '=stdin') local tag = 'error' if not chunk then answer = answer:gsub('\n*$', '\n', 1) else (function(ok, ...) if not ok then answer = tostring(...):gsub('\n*$', '\n', 1) else -- Stringize the results. answer = {} for i = 1, select('#', ...) do answer[#answer + 1] = tostring(select(i, ...)) end answer = #answer > 0 and table.concat(answer, '\t') .. '\n' tag = 'result' end end)(pcall(chunk)) end -- Add answer to the output pane. if answer then append_output(answer, tag) end if tag == 'error' then -- Try to parse the error and find line to place the cursor local line = answer:match('^stdin:(%d+):') if line then entry.buffer:place_cursor(entry.buffer:get_iter_at_line_offset( line - 1, 0)) end else -- Store current text as the last item in the history, but -- avoid duplicating items. history[#history] = (history[#history - 1] ~= text) and text or nil -- Add new empty item to the history, point position to it. history.position = #history + 1 history[history.position] = '' -- Enable/disable history navigation actions. actions.up.sensitive = history.position > 1 actions.down.sensitive = false -- Clear contents of the entry buffer. entry.buffer.text = '' end end -- Intercept assorted keys in order to implement history -- navigation. Ideally, this should be implemented using -- Gtk.BindingKey mechanism, but lgi still lacks possibility to -- derive classes and install new signals, which is needed in order -- to implement this. local keytable = { [Gdk.KEY_Return] = actions.execute, [Gdk.KEY_Up] = actions.up, [Gdk.KEY_Down] = actions.down, } function entry:on_key_press_event(event) -- Lookup action to be activated for specified key combination. local action = keytable[event.keyval] local state = event.state local without_control = not state.CONTROL_MASK if not action or state.SHIFT_MASK or actions.multiline.active == without_control then return false end -- Ask textview whether it still wants to consume the key. if self:im_context_filter_keypress(event) then return true end -- Activate specified action. action:activate() -- Do not continue distributing the signal to the view. return true end function actions.about:on_activate() local about = Gtk.AboutDialog { program_name = 'LGI Lua Console', copyright = '(C) Copyright 2011 Pavel HolejÅ¡ovský', authors = { 'Pavel HolejÅ¡ovský' }, } about.license_type = Gtk.License.MIT_X11 about:run() about:hide() end function actions.clear:on_activate() output.buffer.text = '' end -- Return public object. return { widget = widget, output = output, entry = entry, actions = actions, append_output = append_output } end local old_print = print local old_write = io.write -- On activation, create and wire the whole widget hierarchy. local app = Gtk.Application { application_id = 'org.lgi.gtkconsole' } function app:on_activate() -- Create console. local console = Console() -- Create application window with console widget in it. console.window = Gtk.Window { application = app, title = "LGI Lua Console", default_width = 800, default_height = 600, console.widget } -- Make everything visible console.entry.has_focus = true console.window:show_all() -- Map quit action to window destroy. function console.actions.quit:on_activate() console.window:destroy() end -- Inject 'lgi' symbol into global namespace, for convenience. -- Also add 'console' table containing important elements of this -- console, so that it can be manipulated live. _G.lgi = lgi _G.console = console -- Override global 'print' and 'io.write' handlers, so that output -- goes to our output window (with special text style). function _G.print(...) local outs = {} for i = 1, select('#', ...) do outs[#outs + 1] = tostring(select(i, ...)) end console.append_output(table.concat(outs, '\t') .. '\n', 'log') end function _G.io.write(...) for i = 1, select('#', ...) do console.append_output(select(i, ...), 'log') end end end -- Run the whole application app:run { arg[0], ... } -- Revert to old printing routines. print = old_print io.write = old_write lua-lgi-0.7.2/samples/giostream.lua000077500000000000000000000054561221440706400172300ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Sample LGI application for Gio Streams. -- local lgi = require 'lgi' local bytes = require 'bytes' local GLib = lgi.GLib local Gio = lgi.Gio local app = Gio.Application.new('org.lgi.samples.giostream', 0) local function read_sync(file) local info = assert(file:query_info('standard::size', 0)) local buffer = bytes.new(info:get_size()) local stream = assert(file:read(nil)) local read = assert(stream:read_all(buffer)) return tostring(buffer):sub(1,read) end local function read_async(file) app:hold() file:query_info_async('standard::size', 0, GLib.PRIORITY_DEFAULT, nil, coroutine.running()) local info = assert(file.query_info_finish(coroutine.yield())) file:read_async(GLib.PRIORITY_DEFAULT, nil, coroutine.running()) local stream = assert(file.read_finish(coroutine.yield())) local read_buffers = {} local remaining = info:get_size() while remaining > 0 do local buffer = bytes.new(remaining) stream:read_async(buffer, GLib.PRIORITY_DEFAULT, nil, coroutine.running()) local read_now, err = stream.read_finish(coroutine.yield()) assert(read_now >= 0, err) read_buffers[#read_buffers + 1] = tostring(buffer):sub(1, read_now) remaining = remaining - read_now end app:release() return table.concat(read_buffers) end local function write_sync(file, contents) local stream = assert(file:create(0)) assert(stream:write_all(contents)) end local function write_async(file, contents) file:create_async(0, GLib.PRIORITY_DEFAULT, nil, coroutine.running()) local stream = assert(file.create_finish(coroutine.yield())) local pos = 1 while pos <= #contents do stream:write_async(contents:sub(pos), GLib.PRIORITY_DEFAULT, nil, coroutine.running()) local wrote, err = stream.write_finish(coroutine.yield()) assert(wrote >= 0, err) pos = pos + wrote end end function app:on_activate() local source_file = Gio.File.new_for_commandline_arg(arg[0]) local function perform(read_op, write_op, target_file) app:hold() print('Starting:', target_file:get_basename()) local contents = read_op(source_file) target_file:delete() write_op(target_file, contents) local contents_copied = read_op(target_file) assert(contents == contents_copied) assert(target_file:delete()) print('Success:', target_file:get_basename()) app:release() end -- Perform sync variant of the test. perform(read_sync, write_sync, Gio.File.new_for_path('test-sync')) -- Perform async variant of the test inside the coroutine; start -- more of them. for i = 1, 10 do local coro = coroutine.create(perform) coroutine.resume(coro, read_async, write_async, Gio.File.new_for_path('test-async-' .. i)) end end app:run { arg[0], ... } lua-lgi-0.7.2/samples/gstplaystream.lua000077500000000000000000000022401221440706400201210ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Sample GStreamer application, port of public Vala GStreamer Audio -- Stream Example (http://live.gnome.org/Vala/GStreamerSample) -- local lgi = require 'lgi' local GLib = lgi.GLib local Gst = lgi.Gst local main_loop = GLib.MainLoop() local function bus_callback(bus, message) if message.type.ERROR then print('Error:', message:parse_error().message) main_loop:quit() elseif message.type.EOS then print 'end of stream' main_loop:quit() elseif message.type.STATE_CHANGED then local old, new, pending = message:parse_state_changed() print(string.format('state changed: %s->%s:%s', old, new, pending)) elseif message.type.TAG then message:parse_tag():foreach( function(list, tag) print(('tag: %s = %s'):format(tag, tostring(list:get(tag)))) end) end return true end local play = Gst.ElementFactory.make('playbin', 'play') play.uri = 'http://streamer-dtc-aa02.somafm.com:80/stream/1018' --play.uri = 'http://www.cybertechmedia.com/samples/raycharles.mov' play.bus:add_watch(GLib.PRIORITY_DEFAULT, bus_callback) play.state = 'PLAYING' -- Run the loop. main_loop:run() play.state = 'NULL' lua-lgi-0.7.2/samples/gstvideo.lua000077500000000000000000000062231221440706400170530ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Sample GStreamer application, based on public Vala GStreamer Video -- Example (http://live.gnome.org/Vala/GStreamerSample) -- local lgi = require 'lgi' local GLib = lgi.GLib local Gtk = lgi.Gtk local GdkX11 = lgi.GdkX11 local Gst = lgi.Gst if tonumber(Gst._version) >= 1.0 then local GstVideo = lgi.GstVideo end local app = Gtk.Application { application_id = 'org.lgi.samples.gstvideo' } local window = Gtk.Window { title = "LGI Based Video Player", Gtk.Box { orientation = 'VERTICAL', Gtk.DrawingArea { id = 'video', expand = true, width = 300, height = 150, }, Gtk.ButtonBox { orientation = 'HORIZONTAL', Gtk.Button { id = 'play', use_stock = true, label = Gtk.STOCK_MEDIA_PLAY, }, Gtk.Button { id = 'stop', use_stock = true, sensitive = false, label = Gtk.STOCK_MEDIA_STOP, }, Gtk.Button { id = 'quit', use_stock = true, label = Gtk.STOCK_QUIT, }, }, } } function window.child.quit:on_clicked() window:destroy() end local pipeline = Gst.Pipeline.new('mypipeline') local src = Gst.ElementFactory.make('autovideosrc', 'videosrc') local colorspace = Gst.ElementFactory.make('videoconvert', 'colorspace') or Gst.ElementFactory.make('ffmpegcolorspace', 'colorspace') local scale = Gst.ElementFactory.make('videoscale', 'scale') local rate = Gst.ElementFactory.make('videorate', 'rate') local sink = Gst.ElementFactory.make('xvimagesink', 'sink') pipeline:add_many(src, colorspace, scale, rate, sink) src:link_many(colorspace, scale, rate, sink) function window.child.play:on_clicked() pipeline.state = 'PLAYING' end function window.child.stop:on_clicked() pipeline.state = 'PAUSED' end local function bus_callback(bus, message) if message.type.ERROR then print('Error:', message:parse_error().message) Gtk.main_quit() end if message.type.EOS then print 'end of stream' end if message.type.STATE_CHANGED then local old, new, pending = message:parse_state_changed() print(string.format('state changed: %s->%s:%s', old, new, pending)) -- Set up sensitive state on buttons according to current state. -- Note that this is forwarded to mainloop, because bus callback -- can be called in some side thread and Gtk might not like to -- be controlled from other than main thread on some platforms. GLib.idle_add(GLib.PRIORITY_DEFAULT, function() window.child.play.sensitive = (new ~= 'PLAYING') window.child.stop.sensitive = (new == 'PLAYING') return GLib.SOURCE_REMOVE end) end if message.type.TAG then message:parse_tag():foreach( function(list, tag) print(('tag: %s = %s'):format(tag, tostring(list:get(tag)))) end) end return true end function window.child.video:on_realize() -- Retarget video output to the drawingarea. sink:set_window_handle(self.window:get_xid()) end function app:on_activate() window.application = app pipeline.bus:add_watch(GLib.PRIORITY_DEFAULT, bus_callback) window:show_all() end app:run { arg[0], ... } -- Must always set the pipeline to NULL before disposing it pipeline.state = 'NULL' lua-lgi-0.7.2/samples/gtk-demo/000077500000000000000000000000001221440706400162255ustar00rootroot00000000000000lua-lgi-0.7.2/samples/gtk-demo/alphatest.png000066400000000000000000000636411221440706400207320ustar00rootroot00000000000000‰PNG  IHDR|B‡}>gAMA±Ž|ûQ“ cHRMo?r‡ô$„Ïm_èj<‹W§–mªg,IDATxœbüÿÿ?Ã(£`Œ‚áˆi 0 FÁ(£€> €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 9]:= ¨h´À£`ƒÿþ3Œ–÷£€Z €G[£`Œ‚Q02@¶ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(äàÿ£€R@,í€Q0 F~ÀÈ8Ð.ÃÐh Œ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F –vÀ(C D–,óRî ŒŒÚ@Z›È``dø"€èµŠñÿö¥áŸÚ­£` €büÿÿ?Ý,SLWRÜdhæ$†—7×Ï|4C—Hõÿ¡4Àì UÁˆPvÈãfdd”€Ã3 Ìgm0ø$‡ÄúriUÿR=7 †ˆ(YªŒä^`ÜëÓ8õ ¥FXrøÏð¨¦pIgØñtò(( €èÝÂObm(›Fèò5@ü ˆ›qèE7B+:`ÆeD(·ÒÊ œNˆÂÿ°< $ÿƒuþG©"þ³=X!ÔÜ‹@\ŒÃ?£`àÂ|kûˆn û Õ©èÿÿc€$Fpúÿšª@Í'FF¦ÿ ”Á \S¾ºxIgè*ZùcŒR@Ñ{ ÿƒ È¿Hührÿ‘Ø ú°ujÆ45ÿ°°ÿca£©cüÇ¢ÿ1#ÿ¹‡áúÚi—€UÁQ4}E;D-”T2¨¬ï?È,H΃Îç–Í‹‰U^²$˜&ºþÃÓ,#,Îÿƒ ÿÿÐt¢a|Hÿ”þwÇT¬¶¤™gFÁ( ½ |X!ú—³0F.ÑÅW"™­’øË€¨@þ¢‰c˜)œ‘äÿƒ!L¨±6 ˜aAîFF¨JË™{ÁýIÝe`ëþ*’¸zØÌý .œ½opÆfØÿˆŒ ×ÖN{ äìe\ˆÜ0þVy02BZxŒˆÞh ƒ ‚y¼ÿÿ/Æš:$-À8ÎÆ*¤‚÷òþ‚ óÿÐtñÿ?¬¢‡÷ S<aâÀô![±&„†^£€(@9¤ƒk(½u¿‡¸0º9è½ °¨u)¨ÿ#*F”{h¸†nhR9@+Ѐí_¤–Ü?D•1 ,˜§ŒË5ŒÿÕái…0øÏNà!#\´âø?:¤3APþ\u`¡<A’ÿ¡®ÿ!…5^V²D¨ˆi¸¬&jã024ë‰M ˆþÈj-ðуà]ÛÈö'ˆ`³€½U`a¿”&ž£€D@]à£Ý¶î“`¶ñzlC<ÈG9@ÖIÿG¬¡ÿè’ã,ò¯®™ü˜Ñýg@ÚxkEÂímáðÏ¥¤ú¥9'$W`‡VþÃçZ Ã9¤l’[ÙóˆA‡öõñ§ÿð4ňÎúŒˆ¹H¥3sIghõ}< Fy €rH Ê,[I0¹ Ç×êÇŠaÝpX‹÷X·‡|¦Î?Fä%x£ëðéürgºã­ð\³¾ÁKeaC-ÿa󌈉Wp¯ŒˆI[t°¢'z%P_ Ù4í&Ê!|Hïš dø-í ›E]ߎ‚Q@ Üx…¾Qê$°uÿ–H3`z`‹ßð-Ë„±ajÿ1ÀöÝ@EÀ‹+1ÍÀW€­|мu@ft=>ÔÈ’m"Övê`aï ÷è[”tõzÞ5#R,CS‚ϸdüÏ@z+º£¿0@óèYºÂÉÞ[K»Â¿Pâ§Q0 h h ×á#ï¬ÝN¤È•˜¶XvÛB®}vÿ¾íòQK³A‡ª10ºi.ÈJè=G-–£-|:ßÜnÀh+aüÏôé $p¼CwÃ"n¸ÊýGì‹Å¶—,°¼;âÖùØŠ Øú{ø>ãºWVOþ¤v3ÀV|ÀVû€ON´¥ðË™á ,³‹ áý>.[=Æ6Ì™¬…·#–7 FÁ4PC:È-{ØI‚°3t`×p¶Ö?Rw|”ÎâZõ¨¨ctC[’›±H˜4Ž,ÇnÔ'Ô,ÇZ7ÎÈxýÌÒŽNdufÑ•@ñJh?âMƒèë'7¿!Ùñ$ÇäQ ]ÚÀ°RÒ¢@·,Ø7»ìµsj7踂l Ÿ±ÿ˜Ñ¥·¯!ÃíL1Àä`ƒ+`ÅL Þ¾mÓr‰Ú˜ä—3Ýhn!dîbÚØá5Ðq›ÿÿNŸiOð!¾Âù=§Á¯,ƒ9õîªÞ8ÐÆ-Ðå'@¸ÿ‡;æˆ>Ⱦ]ÁÈÀ¹‹ÙŸŒ°ÅóÅ¡X{±ñ•ëò€f©¡t<À &¤]¼hA9Ͷ]âÆ­³š<· ›^¿Ã(éÃøîèŒpßÞê½ 93µÎù1q@MPÚy ˜ù€NÑrynX÷¹«Ì¤ Y]eÏy üÿjDÈ"4ªá#v8ò4²`sK‘.ú¡Œ#Ð@ éÀ |X|†„Ö=º0€­gÀ"×Òð€ù‰Ø«.¯žôM74T@ùÀLjÿÃÅ Œ"K€£ PµÐnX9 ™Wd„´LÑ#t Š<&¡$Ôy×d¡ElíY v_ÔŒíÌ!Š€Cr;èþVO ­¦pW02,ö ù½³K¿ ýU@75Å‘ï)f‚¬A‡•ê°«$¡ÁÄ[eOð)ÓŒ—‰q“oÎtg ž|FÈYóHe#Rf‡l¸øÿQügD¤ˆ3tUB!R<â@ÁX¸]ÐÝ0w .Äd€Z+ü¡i tý%®aKÐ*#}H‹Q®ƒúLÐzUŽî?HÉsöYL£%Ž5Bò##ríL– ›!@Fd7í» T±XðoÆáNª€’Ž xt2]A X”0Âv ]м ´ˆrꂃ³ØK|ä2‚J^r €z v“hlý4¾–<2@WÎ댈$= Ö$0þªæÔ‰Ô.Ã9L`Yâ ´Â ˜¤¹¡Nø‡p”…µ‡®þ1@/Jeüu,¤ÝldYÆÕ*\v|QÓ7â=€ {Pç ½¿z0ÃþÙ(«¨€…þ—Ôž ³Žtù;lòô?tfÑþEtªÀœÿïÂd+Z`aT›‡4ÿ‚<@ÿ:mÎs2Ø*Dó! Hص 7@F8ÿ#ÍAlù+µ!U2ãx óÙ!ÿU ¬Ô†ž¬óÿ±< ÿÐÂRŽCV¡TbP ð^ ¬ÀþÏ€-ýþ‡êSoB€3tñ¼ÂP²ë€*P¤qJ­– „вÃ6`è퟼Æç…RBFB6Ÿ½Vy;lÊ?¡ ~CªµÎ4Yõ9v² ˆ*J1Q.QðŽ!Âçɦ˜;v2XXðŽàŸ²AÑ¥gNô+Y” éº:”©,Cü [JÔ[ýu/ôÿã~~q÷ß! –¡QRP2áI§˜jƒvo·MgÒD9 N'•yg¯dˆI0-z7ù’lBò,˜z|!}i¦˜8i©¹|¿Ò ['D!s§öfÿ}n{ÐúS´A×ÀÜ7­¯q0‘R-æl ‚Þi°ý!=Ç™¦z"uŠb‰ e52,FËséE݃ŸÉêÚp?;÷­bv+”ˆ ‡úÇ$|oÿç'6é<ȳšñׄÿ€¼+Öi †¡và/˜ØYA0ÁwTêÐ ‰ é$`de@]øª*Hü ;+ƉßKr¢J DjÓëÇιî³ïî/ªtXe³þ¶«³î{öÖŸ¡X;(;èo»æ>ñÙéN4Uì4²ùмpÎ;‰Z©‰(Í€m[#Ò†3–/m’”bç¤ÈwSD|<n^Ÿ†­0ýÓÙí¡³8B•-E¶µÁãÓDìÜþÞjqµèù,/_Îæ÷ió‚ [ÜXkBŽ\‰K\!;nîìSDøæ.a€z¨¿}ï¦Â«&qG\ެÂö&ô•¼@£×"p³uœõ{•D…ÿ&Æb„þs‘F­êšð¹XfËd?8%ÁùĪ|/¥‰Ö.Ë€Öá…gßFÆù¢"nÿãÿS Ô¤í`ëþ™fÀ2,c êÈ?’Šü.øz°$'„K«'~× +¶nÜa‰J?¼(HI2€/º†ÙËI¬ð‹W`Ù© „tÕ±¹üür FD9«$ ³‡ˆ5i@QPWýxìà?c8dÈà?R ^fˆâˆé`VΩ]ÿ÷Î.›‹n°Ð?ìš:r†!l êü8´û÷Ù¸'PÀÖ©Ù BcéœoÎôÿÿ!—’À¦4aSxÐÉ\ئgFjdf6‘ ZÓŸp…`Ø@ ‘¿HóÏŒ°yZ&Øô0¢ü„ÿ¶Tk ŒøŽÎfÏ»þƒE-ÌœÿðZ“á|Á't‰"õÃÖ-eÂRPÂ4QM;p{aY"‚ÔÓñ` ²Àöª@ÍSÀG‰ÃRP«ÿCBÚ)ÿᣨЋi`é Ã-/ 3™“äðÅYÿáXÉ÷>*Iz‹n˜€ä=Â0 …#p$F3,Hœ‰V&ÄÈ à(,&ÄX=Ò$Ïq˯`` [DÚÚ yŸ‹ý †_.äó—sXI[O±lûdžâó±?½›]Ê“e{4oú~_[G܈ •¤.¡§ðÝ”©)Ûæ“.%°Ë%‰hCålD=áþÓ‚ôƫ֫ ÷§ûŽ_m ©òÏ(³uä ¡Âdd~ÓN7“{sî·‹“¿Q…3¨->sÚ ám¥7S³  XVñQ‰+ÂÆ`²˜‚XÊŽ}SÚóWD´èI!±P"1I®` ãhîžlžÝ#¬]éÙOùì„F¶…A…ÂXÂÍåà,ǘL\Šœ Û@‘0UèÏÖ‡n}îm‰ðŸ’4Ÿ#ò²±‰ßÁÄ´„~BVmIdô³~Ô.6`n?ƒdûýþe» @Þµã ÃÐø,ììÌlÜ$vĘXX¹G`D¹ ,åÑøƒRQÁÀ@†ªªÒ4uêgËÏÃ?wÞýíË1¢‚ÅÅ­Åñï=פ-!*ÕGírØ]»ÛO̽QÊÛ.XN}ˆ1*éç D¾›=¿ ´L„dïjÀP²+ÚÏÉcÍHs¬Cç•ðø°¹ ¢´H“ér;¯ {ܯ› úéUñr5(Vtv$[ÄÁÂ&‹ý;ÉäŸË<¥2•Æ%„÷ðøu¬M;¤YÅ*1|ɲ|Ð ž]"I³žÉSžø„¾f}Ú´Ð5Pp–²¯‹’µ0þ§nTdNåÛóõPAþ:w‡®G"3ÞIjµiÜ¿K*»ÉNx°ËÛH o"—¡ê=à£TXŸgHÑö:| ö¹= ïÚq†ah½3p`ggç\€…ÛpŽǪ&yþ´i+$$†ªjIâ†Ç³ýjÿðßIÎo{{6l}t4¥Óçþ•1ÛI»/æõÐàZÏ[/Û)-,±ÊF}~mÒ5êä K)8Á“ 1«9P@{eù›ÅYKw¨$I0…«E @"+T¸]‹÷q<]o—©¯VÐê=÷dzeÝìCL¾p67ÝúTã™IJÊŽŸ2ðôxgbÓŸŒÇ Gß…ŒÓâí}ì!3…É5£t‡Ëg—ÆónköÇo¶òÄ0¢ÆõLÅ}oRÄ™1,qŒšµJë'Ùá^¥mh')!¦ $"»%;)دôš³íû¢,sé$™9(N€•5¡üÔ¤ÑÃ.bC uYýemª×bë‘ìµ´`oxð× ÿ%ygo„0 Ca«#° 4lÀ =;P2 ‹0+q+zO „ðwGƒ«¾sâXÒ'ùÅùµÃ?}I÷µ EîüR‡#½âÈÜŽ!Ü*åK^|A¡žUÃðY6ñ°$êêÕ£[ñÙœI¡B‡úi¦¸ö ñ/Õ$ÃÓÙ£{ž®¶Íµ÷(½Ñ¥B¦h*&á¹ïi·Ó´NæëݲoŒã~SþáÆ˜©Ò7 _Q&` ýv.o•à]ª…S}‘ðÚkfãåHSùC-@º£÷ï;J*W0 ŒCÅ6p%A2¥—ö„–ðp¥-öï@Cú…:J­Õ +yÞøž|³Ú®ÇO&jqíÚ@•’^ѼV|Mž;}/J•ÕÝs`2JêlO‹Ð¦Aý´ƒà2ðým»@ÞÛ ÄÀ÷tôÔHÔ,À”´´0=s°ƒ°9üg;É' „hˆ„D}'¾;_,ýO¿ûÛ–)xü_ÿ„J­)`Émÿç¿ØìgõZ“¸QöS}ÀÒ=IŒSèí;xæðõ‹*!1½k@'-žüIŒ`õ|(æú¤Fýç´hÄíŠ2N,®& ¸3X-W»ã¶tËép­;'}ððe ÀǘÅ'Ð<–)•[T´Ó¨–ƒöæž¶9°À»Ð]€ã¬jûaöÉÐU EÇ2ÌĬ4hWÓU²Bí-.$sϬŸ3„9!±Ù}å±Óéx¢°'—vžÔâ¡@¹;iƒãÄìÈ´£(O4Ñ ãJ$Zðþ{{eK+G­ÿy< ïìq†a(loˆ‰ƒ +ç`cæ œ ‰[!Sšçç±Ð©?Rš¤ýúÅN­ð¿±Ý{ìÞqvê?”r Ø߃¥€Ý‚_ÐQ Z»¢ã¨ÜBÕ™f«m"¸œu6±x-°™{¾Éz{˜gÊÁJ’FUéL<~qŠ"dáþ%…û)öm±ÙåFPúg¹-:§dÄ>°ßfø2F´¸¡oy¹'T;U°osEn@_/|e?ش٠m<>2¸Ëù1V$Pܳû)T°iÝ¥]…vÓ± Ëc»›¬Û¤ôâ ÛqŽFw êÎ2Ëæ$ø¬Wýýñ´Êšh9¿{4$Î)þ:¦pøVµYÓ|„ØÄ3õ1ëý¢u—þ—þßnWÈ»–#bª±Ç«kñj%žíÁ lÀ®wù<Ø,fFoŽ÷ Ùax< üªÁ¯}Fû½7_­ï¦^Èïþ„î熧 'Ú‚04›<„Öä†_Ò?û®’Ã*‰ÈpC8,èZ«´K‘МÈ-ùW«)|F½ÈeB%wf EV³•„m!AØÕ¹3Q¦í4zhKþÛþv<àæÚ†ah4+0ð @ËT4,A†i¨©Œ°#½çÏù’K i’Üq‰PdéYzÒ/:ürõœ|X¸&Rz¡3^É/DÚ‰µäƒ‡íò™A*ézÒ X¬Z¤hºÆh(N”Ꜻp¾9ªÁ'™6=©ÇÛùñRèÆXaÀ& dær“õ‘Ñ£*—¥ûCtúûÞ{×Ó=žž¾}2ëÃ;„„ {Bì¡`2ùèŒâúUäÄWR I{m)€¦ëlG¹¨®K¨R‰¬ù\Á¨EÀ7luî†lw­Â̱*ä Ð@ÚÎûQ&ý”éBÒ‰uÔ•ÿxS1wëÀæC[2î=kTêºáÿDTSapÆZi>Á”þÉY¤dÅÒ§Ø]{#oõ]šû™ÀõÿÇWòÎåa¢Þ&.F”CtD=Ž[ZI&8a¸1á”É!1!Ò>},þÑáïQüž ÄKà½ðN?. §u{iDF›+A’ö;=¯’lË£{Á4þ­«_Còœš^ P1Sƒkdxž/½<Ã9†÷¡³LÏ.ºIª0=eyyŒ«Ÿ»Nþýö¢¤¿¹)éý£[3« ÔÉÀk ¶¡'½PÌY„óâ_¾‚eˆm#|P\‹ Ò¢£~ÞÓÂôÆVDáƒð‡™¢P0ÏÎáiIð½pýñ+:£Cþž,äZ{/4T£sæ1áavýÅ)fó” PÑIï@ªap#¢Ù–R0ÇN>Œä*E1‰Ó]#Üe :<å¿ ç n†a`úbÄL€XŒÂ“ ˜ø0Jîì‹ä´ðDäW©u¢&9Ÿ/v~ð?‘sæÒ2ï*‰H}¯á¯6‡‘=/ ˜%íɦ"ÛÃ3ÓÔ¨ÛGêf BuD¼ÙóÍLk;. s‡ãŒÔ|'ج ·ÈÃ×È0ÀÎÃpóB"l`èÇZ+)xe»ÞÓ¢Ëi~}ví±ÇÞˆÁz)Ù@2«,Ø”œ02qÇ;0kg¾;ƒ—Z ¯õfÞG3'SQŒ¹ìTLþ{e®&vIøþвõLäEcˆr8^”›a?²GÏ6zX„‹T¾&ÎBI¯SÌg=›’Ë“‰0Ø B‡¹0%&­L›É9 öc{ @Þ!AÒ„ ²Ÿö`–`þ­Ã¿U@ÄÜîÞ†¯#3¼“;2,›»½ã¿fî½N òëÓ‹W:úvsâËR·Hbldi‹H¤ÞáVµÑ4ê{(Ž •@Xa¢\ùjÅYd}jGÛ<ž÷ë{ü ’¼%=> eMògë•“Åþ ©«m×]E29Ÿ.·ckþGýaׯìaX±NfÅ©Ûf)9àríS]ß1Ÿ+ZA¤©ÁØ,tôÎí ÈGˆ&# k‰ÿ(ÅL f©v˜l…ß+Ÿ²ûLÛ)·Ä\ÓPG‚Ûùa 6ç=Q•Tð‰ådᎋÅp‹õ $¬·6LŒòÛvy¨WP>¨~ïë¹ÿô?w7Ã0ÐoÆaø° /FéF¬À™VöÙ—6*UˆN’È2û¡@gá*NNLw¹ _蔇í•Áå¢ÂH½9TAëÿKeŸxa4%ša}÷ߘrH™)”$ID"àØ½ŒŸZD_Î×û¡7ýð¸=7¯·u²ÐcвIü>T¢ÄE"Å÷á+G’,õ²˜7ºI³GÌ+{à÷$¼o"Á×;åÁýûÚ?ŒÓ›Ã"1‚ÿÏ §\1¿ž^)S›ô$Ã>N•Ô´ÀG^b—¨© F+ÖÕ7¦]!kÎ6(Y2.1¹¹>ÿoÇGr®ea†5$øH>áÃRÛé*í†Øi¦e[b×vµáûð;znW4®CN´@JyêE¨oô¥»Ä+ Ÿ-2&Mi™lÙÇ£ MOW§:}[¢Ó{ âóQQþÑô±OLÀ0N ”ÚDXB %h<š¾™žK4áúz¯Mÿz¦Î,Fˆ¶ÙVë.‹"—!Lƒ A¢Õ>+ûë…JüÊîª@ÊY—é–&8tynoùå@ $l >‰½Á«îb5d8´>®þÚ}ÔŠà‘'2N@ÂuO²Íÿ’#¸q‰Ë9بù˜jõ’µUÃS6ÐS)ÅñÝ:ÂOíF§@Ú¼âÖ y¼ ï r†aXóÄ ù&_àE#LIì¸LÀ ÑË4­šÖ¬MœÌî~Õá#²käÞû¦Ïî܉< úb"ø Ï,¤ÚH™‰Ò õ˜)Êž„OS«Mc´eaYCéŠDktL‡muú·õp »à[D—):‡*7¯'ûƒB'ª%ióBEõ<¯íò¹Åƒµ^Eƒ%€ g)ïØ„jJ;€9òֻ¢Fd; EƒhŸ}’4zTÒÉù%1+f ÕCÊESwîG„o,»;gFL=/é’±Õ<ñW/ìÕc]&Þۧ|j¢Zµ­´^Eé( ΢¶Ùm^àëÅ[¯`Sê€3­ûÈ„þ¶= a •hÙ‚(銊è驨žމXÁéÿm‘ Gƒ‹pbÉÒËgËFúu<üoAzsÞëÓRý-Õ•ô;<šøÃŠZy¿ê~QÒ‰€ˆÈÆ™&\-m´qIÜ‘R Õxm¾×AÁýúhèÒúe­‡µ÷Æ 8rN›ò¶œ÷ëÓt±=žŸ…w]-}—œ» ¼&ê€|½“ œ§¨}<[nçÇÝêðW½Ñä¨7 fu×WÃRWØÛÅ– ®Ô.[}(R³iS|šê´ðÄ<µD]È=óІ\}àØ©B.U®ˆø ªGšpRùÐPÛ$åqøHãHÞ`íÉè¢\„¸áÁ:‹4T7¥°G©Ú` Î_ڷפ‰4)‹øù±:i„Ù")ñŽ"Jíþí ÿ.yW„0 ¡¯ð¾Ò—ø/Þ¼øÇˆµ, trÐzrì¥3M É0Ý_üÑG[C  ÚtÕN¨‚û|Q‡;ŒX´`8ÁJ„/"û4Å™¯¸ËÂI3(´ëz<ÜçÛe£^[&rÒ×STvz g#̱ÑŒ½Ì"ºÀ¬ÄÛ¥'Æðø¶ŸAÿ6ƒþùsýxÌ$ÐÆwé¤ý Ê.!Xœ¦ÐÉ’Ýé yÊ2F ÏTW §h E}¸"VI=ª?ª@wŸh„×Ô3Ù½hâìÛ­›Ì³gE©§?3 ÞÆ÷q¬²à¤¼±½–>Ê*®z(±¶®£ò6¥FÁ¥4â•.*+«& !ŠÁÎÿ"Ñ£áª1þ9à @ÞÜ ±d3ž¬Â ŒÁŸ“°âgªÔ¾øªDÀ ¡FªTõÑ&×´ÊÙ>ç_!”®Ž¤à©Qq¨±ôÕþ °{ËF,¹`‹_ ‹Oö¹L©¿ð¸_ÏÏ¥·¥_”n;tfU™Õ  Æ!ô¸KFJ¹Ž§Ë§›jl›”Cî¸H·2íw&¢¦~yÛøJŸ!ø.‡W¯îÌJ—F¤¶JØ9éYLùcs¤WôrfjÓ—6gÐÇ ¬ºöL¥X´â4͹Z´)äcœ”‡¤«Ä»Cn9ê¼`”Ä@ÜEòxbÝDxÑs át Ûht†š¾gZZFÄ蟀õ™Ó8í¢½àîJŽ„a Ô]RJÚI )„.ÒI&PI»"#fÂ#üa†>°W°ÚµÏø\lû²Ìf æ‹ÁyÒÃežÔï|>øòºQUYd"UÃ]8|ØÄ¡—a}ÑÇ</ªÉ©·f«Šˆp?*ûÍþ'¯º‚Üåz»ï›Âú²áÔÃxÅà£È)ï¥7Àü¶Ž>k+ç²y‚V(àýrrªKû¹z¦ßÉ’=2ǃ1Ÿ“u½jññ Tn›:Šá¬´såÏó€R'€p*—Tê/KæYT´×ÿÂŒíg½BÎß”Û"xÿ Mn—*ÞÝ$ÕT‚O°Ûø p=”»9kù@ÞÜ Ã@ûÇl,ÀlÀ¼ƒ?ë ±J ñ/QKûÑG[©UmµîÙNìË/þ\5ÎXvUä|¼—Àƒ†àüƒ+[±‡>r\@Ý] $úR¦Å/ñc»]N÷×áj ÐQÚEºp`¼fYAú'˜üèj…Óa<ï6+ÖÆ®»oë©c±±Æ­âÙÔ U½çæ¿î„, K( &h•:#ÀÈ(wU–%"â>³*ÆrÛKÚy˜†è°lIõ!«µ÷–Åi·ÈØ–’ŽÉ¸ßò\ô‡Ýó_s4£…LNåx‘ìÉÀάÎh[&¨3þû:üIò®ía* °0›ðÁü³[ðϬÀ ­ µï|•Ò¨ýABDÊO+õ‘ºgŸ{vð;Qûâl9 ‹Ä²ƒSã͆`ŸŸàÒuhJÂ’Õ†ªbøê8ž¯û:­}ÛåYW倞do†ulá—Ard¤Wb³5îwW·žV_pVW XdÒ‘R?úLm€)Ÿ§CZìÄ—âÄyg$ºtux½ÊÞ)OAçåšr:‘dV^Èá g(ÐóXRÒ°-R'T4‰„цì\iÚÇŸïX§xï%6µ“±Æÿ‚y!ê·di´Ÿ¢Ï°1Í8G›±çøsV3ºŸ³Ô?oÈ»‚„a(/Á:¼@b žìÁŒÅ—1`…š´¾³(•¢}äÕÖ²’sbû®¿ø=0o§ZE{Û|VÍy0…3çX9‘Õj_)s’y~Évi’Bøöe¶ï·Çs÷G)ôoe¸ «=¢s¡s±¢ÒA#TI !sÀ¶Õ2n§Ën…Ñ9¨±IyÓ^]Zd•À=]ï¬z$ÈŠ}3¤+2ŸÛˆ]"­¿Æ“+¤²… k@žÎ ¢Â`*Î:%£[{ÅNËýÃ#¬{8á)„ÆÈ[€rç„Ò³³®Gþ*Ïß™vø‚°E¦54—*=¦Ì†•ð[´[N* ¡ûö¦W?k¡4o0¦™SVÕÈ -¹¥12JE#jèù ¯µ£‹ÁXg,Tû€ÂºŒ<3GH‘ÓÖ.Œ3WTš´î¸½©ÿ‰zatM.[Źï0ÙlYK0xžö$¬ ;]ÃâH.@ýk´Ì‡Ô]Û Â0 t`>‘‚˜„­˜‡$†@Gkû÷‘¨?è/¨ÄIkÎgûü µg‡žÌ>ˈ~ÞåÚë]Ep„oˆñðƒƒ›‹WìbpÄdÓA‡óu×ÿ†®i,Ñ=/M§lzJ¥S ‘t‹©EAßd="ã"2 å19Ëakö› *!û`Dí:lf,>TÑ1§G‚F‚„c±¶6¨Ò :— 7ñ0ÑéöÔÆ#+ZD8Íû‹Ôd-èhMO?xñ¨ö2çšï!¬þŒfãYè ëê{BÖÕ¿µ°ÑLgÔZþÝP|áz |UÁuî#ÑÍD¿Ù£”RýÒ*õm”W'¾»Jr™Ø\’ð–ü<Ù7®·ä]±Â0 ´ ŽQ( 蘀ž)‚-˜ˆ2%Cä„cé%ë…»t.’ÆDZ-)/éõ‹ÉA;³6Ël¡³žr¿±Ñ€g¯5Á'™'Æ]^ÜQ$³D ¬gcnj§ë}*oxH;ˆÅ«<,¼«×K&ôk‡g}ÿ·Â7cóçdÍ1{ß~,Á–Æ_‚eO(îÎÇãùöدNÈØ;-’E¹Z$c”ÝYÅžaÚGË|ÁÔÀm IÅ&dJƒ…Ô1dRÁjó!¨.øÒr‡&î‘$±|/s§|sz†R.ÀîØ„C=ž¶ˆ–µ0Ke6ƒ™âPhÆ ¼®”'‡ý!wÔ_ð5Ê8о›øS$':ËE1s¥³tæ¡þ²}àa ÜÀÔ B•;† ¥c V`†h)býKq’Ë]:p‘"qìÈŽßÒ[–ðãÏYvj©ÝYfþ´Ì³$=…¾áü¾k…„X)ÐMÞ¬šHû,¬4íçu[~%srñЈ®þU{ÝWÇ˦Ìö¸žÞíºµ¥½0Iš+$,º+züyí{#%w¯{|ë÷í¬`¾[3ÆiÔâÚ%À+òínx"2é i:hÕMÞ ‡@éVJž¸uÁ÷ÃGÁX`%iŠ“/„ú3÷H‰4ÙP…ò!üÿ’a¦º ¼>5á–ZòûSÜårñš”…èÈ{4´tÅA1¬}5I·i,_K’"–’µ;O•ÉìA4ÿŸ>PwÅ8Ã0Ð L¼ˆ…G±ð‰>€03ó&žÀÂÆ2&¶ÏNQ êDBU!MªâÚÎårùG‡ßrö}ÇÞÂõÝ1eYaýŒ\‚wØvq§d°6Ìž¸‘9ä›OäàãYØW{D‘¾æÒê¬5Ö×J/ºq©åf¦òÝRœþK¶½ß¬nRo'W])8ð*œ‚YŒš*Ñ8Nª†.(—q9on–]ʳ6 kW¡dÔ¥PÙ5U˜<£õQƧO1ÃnX*Q 3éÙ82|<›7pðó€€8ìˆÊ\‡«T5m¡_! 4š¦*@(A!±©\G‡ d¦Á˜#1²¡n½8Ëá¨%&©óæ0¦»„ߺ71Çc;¨aaVÿ ®5¢«%{€ý¡Ÿì0 þrÄ”‡Ê>òŒ>¶]Mê  »zÀ$tï?R&…obDO|Œ(™’yÿ#vêR XÇ׃–Zª@&åø 6‰èZƒ°0°pösHîÀ,ôg—¿fÎu@¿|g@«/郚…TèC†þ#Z˜¨“™(•/80z®ýï†Nâ!ÙÛœƒ4© ­LaöÂâèW Êé.Ä$?ôZIøÒOè\Èág°uåЂO@w¶þ‡M¤Â[ì° åð1¤ÞÄÿ`»q sâèn(<¼‚˜[V*ÿ¡sŒ°a)áõ;T?ÂLئFDƒs/#Ü-ȇõaÚ…˜†ÇùȆ5èÊè²O´Epÿ#³ÉØQ?\@ò®Ýa†Êô Á t À TÌ@KËìAÇÔܱ=ÂŽ¬÷D.Îq ‡›¤‰?±-?}žüË¿5©c¨Ÿï4+ÐiûAÉ(ÿ–…Í]°i@ÀaÛH?lvÍŠ®4¤tý òXnöó¼C†Ö;$×,Êp@þ7KŸUlá³ÜÇõj{˜ö¿;w…pv¢4iR¿h;•ŽqË ´/Õœ·I'£ƒ3âÕkÝŒô¡zß -Dƒ@ó@&Ê·æ»ÊÐG5(Bjyh©›•ÁΜÆNÊ¢öÒœaÝ@½îtr~° Y­h§EŽJn6 ¤$#EU­Jî™?8JÞæHÉ(ÿš^¿ˆ}Ö?5k– +8¢‡u•Я²Î’k%ýùƒ ZÙß"ü§ä]ÁÂ0 sF`–àØ…-x³ c°óp&¹X²Ò#m'øÑG>I›DqËþÀÇDnq÷‹ö ¥33å¿¶º+Ÿ9ŽÂéXtAÐÓé’ÿ¥ f-to¯.·cíó ºª¤w=7rð4-j‚›Õõ9ýk‹NzÀ+ôæH‡ÔÉG÷ùC´I÷˜ÒxŽž$=Hrë•qEõ¥­oÂîxI=üEŒÔŠKZ‚Âu Ji…F(…ªÔ~þ§Hið‚ˆ(j_âr:´Sá•EZñ°© ‚óVáƱðÂw|¬»µB:z·@€·‡:ŽJ[G*ÒI^Cÿ>!‚{õ.©Š«{Ó’¶OrÔÚFª‚ÓÎr³›§®‚njºóÜ1‹p‚P³ãsÞœ³ô\´¾OBÿ‰Ðè‚wõqSÔK^ÀQ°œBøóœÅ >ðs½,L½¹÷8ëhŒFf+ Tgòw':‚™/÷r‚a³úÁ»¨×©ß{ÜM¡òÄ$‡ ª ,í`àêUIø ï°öœ¶Ö5!P.æ)¹ë©Z§ˆµèºüÀ*Þo×·ôÞ1ÈËÂ'ï5Q€ìˆ`ÊÝ”4>V\?Å­6o mnA2k·ÎŸ–‡ä]1Â0 4 /aeGB0ð6žÀ„ÄÎÆÎ x;?`gbd¦&Â>û@-T0!*U’(Nj_ì³ó« ŸðKGéM„×ÒÚÿRáúsÀää$M~sÒ2äëâCô1˜.»EÙ˘}(øM=^šÚzucªÑ¶K vGÉÚ›ÌV£º>v›ù±|öáÊ 9M¦.OÆ øxç׳íÀ_míÌ7Ÿ§*Ë‚ªHö÷:-,dŸvkíôpBò—Q>Y&â7´M§–ˆ34"Ìî²54.¿Jú§Á0K×—O¨,©\¨•jæØ1ˆ u¸Z j§¾¼Ö‹á©4Ûzÿ<Ÿ«³PUõ1Öbüï>‰{ÊeJ{5–›Ï A-8¬þWÝ‹Ü ïÚmb¨o:X‚"53P1¢§É ”°% ˆIs‰ý|9¢ Ñ ¨ ‚(ÎÏ~Ï~ùŀ߽y$ÄíLæ²ej/û-ç|(ÿú‹?&vY%¸gpµÈô >þ+NëqÜ÷<¾¹ãª¾w›û»ß$d‚2e}r&³å¶Èí§ úñûWYŒTaAT;x®¯d–z-ü6ÂGÿ³FaT1„~l±v¼3ihaSŸÉçeP¾X͇$¦±¯ä€ÐŠ«’-˜Ö¨ CŸHÌžæR‘TzeAÿ9@ïG 4PfÛ³´‘eìä:¼ö"`bÀ^CH:Œ÷ W¹*NñBï™ì9Éjûàl¥dàcâz\š“HšIEð™«dwî€=Ÿþ5‡ÿ@C±ÀǿܒpE€PElU§Îr-`¡˜¨ž“%ãÿÿH­>ØnÂÐeŒ‘ŒÂ>v‰˜ÇÖ([öî@]& e”ÿë”á-ö;G4ÇkÐð$è_èzkèšmHë :, +ør=%`¡oͨݳJí¿‰âOèò;˜» ã¸ÐzæûØ>†OÛ¦å¾!àuþÂç`”02Àþ‚‡/¤wÛ ]eƒ:D0—ZþGI;ÐÖø´‚å/¢`…o*ƒ 7à‰[èxùXEi”À—b2 sèä+t²¾Ê >y‹Õä9è’L´óäÿÃZ@TÈ›ºð ³àý•Ög€vÍ2Ÿ0ÀZøùѳýÛ«€Ø¿€ @þvv|XˆÕä5ù£cø@@C±ÀG/ıµèÑ+\•´… ß!K5L¶çæÂÆóa¥Õ Ëè°3ÈŽÅ$ºç:tó˜jQóØj}‹ØO 9 cø~€·– …ÓÿãG6œ$èPðâçÿðSa¬‹ü¶"„~ï(¨SrNíÒÄfÜî™ÅG€Ô-Ä89ìhÄP¬ÕË€Ôõ†vÑv/˜@Ĭ¥ [Ø\òø3ìþSø†&HK’¨Ø†*Bž—@:Ú—Q0þ‡¥EØå"ˆ^¢‡ƒÓSÐÊqÞ të¼ðEZñòÒ€ô”¡n@ZŠáè+DˆzA|h„‘çŽ ôUY=ë«´š4oÐÄï`À†ßàË,‘—G3üEº Óˆ‰éˆÍ[ð zhú…¯½GêEY®9b[ø4T¯8„öðÀ‘ÇÈ€˜m…E$#j¤2¢‰C¯Œ0>#Ô@ª%`+ÿ·AxÑ1 ‰ú@k$`%ÌåðÑ#äË8ÿói+ÓèJ{¾]÷r…¨Ï½ü v¤G»<æ‡ÿ_^;stQ#±p€-Ñ;Œ0w1 …9ý?ÒvÆÀBÿ×ÞÙeÃE»gqMëcj—ƒºð»F‘ÂÁ†t-mŸžó°s!…5Ä-`Ç1BîVd„vV@A„ÿ{$ÁFXã9ðøÐ ü*@P‘»‡8Œ 0yèÄ…e°Ëñµð C9ÿ!÷½Â® þ6ÈùL°ä¿ñ:ò=ã{ú…ކ’Ô!Ã\`ÇCæÌa×þg„Ì“@̇,2€'²@o¥åÞâŽãGf€V…a¦Ãâq;2,£ˆ*X:…Ä5ø¢øµ¢pÏ"¹Ýጠ”xd€Š>¬öG.ä°G.’Š8t ,ãÿGÕBpaeßo uÆ0¼Xh´ èÂH1*Ça™º~Ù6ô¼/F ›ÉQpC®ÇeBì †ÝIÍÀpH]?¶¨ñ7ÑŽ„T};Ia×´B,…Þz-ía¢ˆ¢¤ÄÜ%µûÿžÙ¥÷Ðj~ûŸIV3A+®ÿÐâj"ìNÖÿï€üÃć,¸e ±2$Ä)j™ ÆÁ [x™º†ú€'²j‡µð™ Ë« E;ŠnÈUªr˜Z%£7&ðoªƒ Çü‡"ÁªZXÁc3@ëúÿ0—ÀëRFœ ÈJ"D¥ -]`u4,@¶2AMb€ÕiÈÕ4E™£·Â´új/—tœ­4˜/þs Vb„œËrˇÿ áP _0À–ØBÝ‹fXámÃÁ†ælÀÛ ¡\àƒ#ýM4y#_,ý’ÁhtÞù•½÷ #J^™ aqD+f'Ä-Ð w4¢˜…¥s¨û¡ û?¼1Úùz娢¦¤º Ú®ú÷Ñ "ãC‹·°›¸`¥>ü®m3—Ô†=³KP }HA>` Úƒ´ÆaZÿÃ9 ùŽKÛ§åý"ÎÅŒ°1{xÝÇ€ì.hÈý‡99£3B­%¾jg„Í‹ÀúH^€+:…a,´n€vA`aˆ@†q ‘­Ä&3À’ØDh¯ÌfD\ 1kÏ®„VŠŒpwAkD‡‘ÀpOþÇYPz*,ž)&<„‡ì‘ÿð9%DhCãZöÿCÔ{ðü#ºe4\ |\lä–?ZKÞèd€gN¢Û}¤ƒó+z¾©s†¥B@k¥€–É0Âg°r º}ÚÆBjT!õbPF…É{Ç5}"×]¼Z¯ü‡Yü‡7O!N€6ø`-Kˆ”iê’Öý~ϬÒ÷HFËÿ‡Œ£ÃŠ'$§3¼g=ÄÀpsûô¼¯¤¹ø?lh ÞO€¶ç‘‹~”b)ë3B—ª’Ñÿ!³ï°ž¤èa‚µøá/¬)ö*¡-Q¼cà°¹(Ö¤†µÈ!þf„ú°ž!ÐHσ Vb/ð!×2B»8¯l‚˜k,cô þab BK¨¸ý¸Ðp  %ðáM Å?€ÎºßSnö‚#þC÷ @Ý 59ôa‰¥qÄ€=b@ Åÿ1_â’ƒ´à #x³šà¦JÁùÝï€Ô;£ÈÒ@ëAG S¯8¼Ö¶‡¡_Ü.5~ÞYï€øåÉÅÍÄÝàÿÿš{!€lPZÖ¾ªý½cFÁ+ŠÜËÈðhèy¤ÁXïˆ>ubdÞ‘c€÷d°¯YÇ †ÿŸ6œF*a7ÐÆ´¤‡¼ð11XƒÔ x*eÆk@eOàÝ>x'áJø;¼²g@ ºÀš¹LO°þÜ”a„7‡¡E<,œ`Îe„WÇPÅt$¡°ÂŠÚɵÚ5+ ͺ@[9 §´óÔ ü®r³ ¸Ìø’!³oÿáE=@‡ëàþ{¤âšÏFì@‘uo÷( >0‰*ç&FÐx&ïX®—%Œ Ý‹ÀÞãçSKZ)/àGÁ( (j;æL»æÈ£”dès!ͺËM7b3«¢ûœPm"r÷Ÿ Þ/e€MÐ@¬Aïí#·è9-EºóN#ÐPláKpfY'h7,SÖ£``aï ,Zõ KNá]h?Z@C‡¾á]5ݲ®3ÿºÊL6c3º! 1ˆ^ïÀ™‚LùB»2Ƚc4,:r[ø4×á‚Q0 1(l;j ,‰AÇsC×ïÿ‡ì{øÝäÝˆÈøq¨d]=HZ¯¼ëŒc!“Ï H{B GS£ì­a„Q¤ºöþ? î†+ ÑŒ‚Q@5,ìùe«%#|3b“täŒ)І5ÆÿH;pQŽFÀ<¾ÒN‡o¢D*¼á;#|ƒÆ™ø¨›¡sM#Ðh? FÁ( &0O‹CŽo€]tÈdVðBïGÀ(œY­|]SáG)#ìß# ï9À|ûßýŒÚÚo)Òý@Ÿ | €F üQ0 FÕ°ŒUb@:Š‚éˆ Äý°–?âP;ø×ð#$d1 GŒ¹"vm(d¸ù2t˜™XŽRa¸O‡`´ €F'mGÁ(T­GØy gÝ@7ÃWùB7s£l/„¯@ý¶…̪‚{èW]þ‡ ÝuÀÝl…¼Šô?|÷æ2Rÿõ}>t@ø£`ŒêFØf»ÿˆÕîðeñŒÈœÿð…óð£p ÇA‹lŒ܇ï&`€E“CT#(kí‘¶Û@À%jzy¨€-ðGÁ(TÐ3yþÁO8‚´é¡Å9ü ¤P Ðcø™à»äà§&`Ü4b€ï:†«àv"¯ÃGY“ÿ¸¥H—äãG† ÑŒ‚Q@ð1n™žù?´iÜ*;=±{<ÆyÜb•B)üàR´ƒ°ƒ»ŽÐÀÛC Ðh? FÁ( x½ qôØ%øÉŒÈ[ba­xÐÚè¸ûØñv ¨á z Ð?`ÚÁ@EnÌcÙiûÿZK‘ú±,#Ðè*Q0 FUÀ„j›_À‚tføHøMaŒÐûœáà0@oì_὎Οފ>ôÂÆ€|CÖØæ*ˆ™ÿ‘×ÞÃWúÀð Ø~:Å 4Zà‚Q0 ¨þ3>e@¹) roñøê È÷Ï¢^. AªÑ—OJB–b2@6o1¢ßó ½Qí?|Í=ìÞjÐ)µ›[ŠtÒ// ÑŒ‚Q@5l™ßþ¿r|#ìÚDøšyX ÒZ‡ÜÕËÞy‹8‘‘ýp3uÄ1Òðݶÿ¡w3Âv×2"] ,ìrk€…=‘·¿ @£þ(£€j`B•õs`áûºØùð&,Fø l·,ürqpkrçí¥ÎRcø…8ÝçÔ€úX w/@6UÁÔÃ7WÁ þÿHÃ8 ë…ý†Q4Zà‚Q0 ¨  Þïÿ‘‡\ ýø!f»”açÛü‡ ó€†òAsga•weªµ@ž éü‡ ýg„W*ТTi€ÎÕ_5ZØc€=Œ‚Q@uPØvLX˜Û q^øŽ(ÈŽ,Äñøhgã©÷@Æá®rÓw0s*ºÎÕ 1Àç l¯Ÿ†¸+†ñÿ¦«­Eº˜wâŽ0 ÑŒ‚Q@PÔ~ Ø:gÐÆêÀB™VVƒRÂï5—Þ_€r÷ºËMá7^•uŸeʘ1þgP/ñD\ªÌ)îÁoø6ñ°µXÿ ]=8@ø£`Œš‚¢öãlÀ¢YÈ–öÜЋt |ÐÕ†/»+Ì_¢ë)ë:Ã,Ïy`Ë둚õ¿ÚK ß¡«Ä€-ðGÁ(£`„€´£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚pwm·Ä Øë&u¤‡H©ñºbÖ10 ‘"å7'ù¼Àðð~ígþ¬xõù|9»uÐå~Ç>}¾ßÝ~$ùéRØÛ¥Â±Å]Ê'åc<…ëÝNÊ7ÛOœÓ0ÝTÑù 5MÖÎ߱qÜk´¸$ŸëÈ¢mË ¹òš=o;m ›=3OdÎ!§ú ú,È5cN\œã,ǹP·ãÐc.çÂ,ë.ÏϽvÎì•ñ. ÇófŒô*Àƒ RÉQã9ß ˆS„ÂIuê(p!¢J¶¡öRÆ«Ÿô~¿ÕG9`làxÛ_²öùˆjg¡üÓ™Ñm~li‘Êôów>k¬¸xª£‡–øy–YkÌÇZ½z®6€2ï– 6 CÍüYåÚ±öß#öd?ðà^fLŸe®œ8\®ÄFÞ`Ẇ³Ä[öÕØÝyê_‰díåA ÿ…}Ûì÷7ùo¿/Ø»‚€A¦ÿ´Ûa…%©xÙe‚Èl›¶i…ô‹?üçɱ#;\y4¸»> ¯®Ye™Â©ÜPo’lÁ·òÇy%(c»E3É—Î'ã!îçäâO£ãp‘n—Ç6*VWKÔSÜr\¨ëêŸú¾ãùô¬8¼d§buÜ«¨=¬¿êß9Þ=‚~'ÿ•÷¸ · v€`ÿÿÓN’¥ißHÄ…‹Ó*Ê+çï‡6Æmv¨±îr^25øÄ±38Âvu墜Næ×94–Æ;,§¯jå4"¼d0éÁ½¡ižÖ­ù´®“Þá·Š»C'})FýÄQ?CjÊ[ãºGε铖r¿,SòË €„ÿÿµWBÚ¡rðâ› U4e|øi íÔœFÓ}s¹n‡7ÕMH_éª&…‹ë¯#²é#Us}VõÍ+Ьú´_´äW÷Ñuç5ÿ ݼÔÔú’¡Øý¶0Ö½Óþ}üGnÌÿÿµkCਓ‰]µŠ©öUKgFku¸ynŒÚ$ôåOÎÕá¥\%#u¾DŠî\í±'œIë%ÂJ‚pëX'†³w9Ž´7õu÷oswk¤¨xÝš‰Œ[½è÷Õê¥û%| {GÖ‰DUƒjuk8¾#9V‚úÿ«;µ9†@uèG3Ór ½úÒY:Õ1û”П[s ÉâPdœÍD ÓÝNK(ÎÚ¡NR÷Ö©0‚Ã&óEÒU“CÛ)‰U¿]]±’úݦ5Žnm žOZ»¨WÓZº·Þ©›h¾þ)€bHY [«åJL¡L(Ñ[ñàêv£«!”q™‹«õ‡«åƒÞ3@6‹P!F¨òDWOí./¡4±W8!ÛM_<áK;Ĥ\[!ãã‹/|-yrÜ€-ì±¥%R¾Ê››ð¹ŸpžÀ¥™F¯Øq¹‹Úi{È€ÜšÛ Cÿÿ¯{•áæ¡‚ ^¢©Û¢Wÿð«ÃQæ—‚(90q$'£m“ÔOû¹dE’‘Ø»…Ĥ:{ðÕºÓ½:¦NXawªbšãI‚ÜoZ›?!ÙâX¶®ˆM"¤í€ÞõŸÝe À}¹£Â0Tïi'¡”$MtÄ¿‰y/ Ÿ]n…`ޱ"››žTÝÁõݦDtŠîÝì¤'çãB}˜p• •¡#óÌÔÃÖè€H“·Á#©ÂBî_oµ6eì¨T4Ç>@¥E´Ÿ9ð\q‡”:„ÆÉÑÙ÷e @Žä‚ õÿOwjc;tÉSkÖJÁ—=|&¿˜Õ‡€ŒÚÉa…ÆØÅT±\Ë$ÁÁDyÃ<_¥ˆÜžÝÇ&2\ÞcRØ[O>x’Ô«oZ ]rÇu윮óq¦ â±qªÖ0ÆIYb¾bªyEJœúüšáoÈ1ƒ †þÿ_»JÓ·u¸$fÖvóê¿ö$3I²Ïì)a©}“Ò7µEç» u ®**s"ÊD>7@Ú„ÔùGíÕ;hOâì|G™â$ŽÈ÷®:qkG´ÖïöÓ½*¨HßµŠŒO‰Ø½³úQ÷êø»¶`ÇÊqA˜þÿÓN&¤iK™\dóBD)ÅWø €¹Ç3aHn¿IɘŒc%·²! "ÇÆŸ)= Í \]à+€îª36u×¶bÖ.ALî‘% ¦C+ñ}Êvß‹ûØjb‹K$ ¨§ºpÍä¾XŒÕ±ÛÿY=È€œ3ÖB¨ÿÿÕ®†ðàÚÅAÆ+¹+Â-½ùó´–t§®kª ˜œ?ñ8÷Ó¹N)Å+'=?í$(ªa3?J¶nÏZ^Hºž’¨ãئˆ”$µöSc!¸KhrQRÿ\_'“Ü_|áÓŒ•Þ×ôª¥Ï­#-][r­` ýÿ_?:<™ÎíÒ¡ÝŠ’ 37ºõß¾ „„ˆ‰ÂÏëPshu޶º0ŽÜV}(~ Ó¹uW2`œ¿=q‹j¯›Œmâ4Ýø ±6%÷ø¤Èî­: 1É{ÒƒïÇ@=†Ø01-4bZØ2/)ÝWr3 L/:ŸPKT@Nw™Ð©ŸŸB…)µÂ&†¯Uˆ^yâj\`s¾Š WEGŠß LR[ìøäµæñ\~ÇØMèzÐÜP^*60"[÷ €ûrIèýO]ÛA}F4«Ð"ó“΋Ÿ$™KÝ7)$ÊtÂÉîÊÐ5(2Õ;õM¤Á¹b;AU씲Çó]C&÷«>ÆpyÇÈÔ·“¼uˆqËôÔq]1¼îSu6vë˜Ne¯ÊN†µïÖ`õ ¶äœ1 ÿÿk'AÂ%Á.: ÚVl‰ƒ/ËL2ðfŽ6 •”·Iw êæjümÓäobH tÚó†Ú¸´=QLc/]d •Ñ6ðU)ùKj“€ãÌ£[íUª¡VÓ‰l¸u4»ïêgªÚÔ_«:_“‹lB¾jKrÌ€ùÿ«ÓZ# l·RRû ‡Áξt©±‹R]my±›Ê×*»ˆsrñL?E"÷?}ÒèKlôs´‘E*&uqC“ËÙ4bÞLi CCÜNÜ“ºw°åo…{ÆSd«r_ŸöiŠøúöœH¤õ,é_¸9ƒ€a¶ÿÿtO°8³-=ê-Âj0A'—|ñ—ÎnÙ´–o­Ÿ’Q=+SoeþÜó†Jñiÿ¤±g¤g„Ùè´ æ–{ŠkMŒêx^×=‡ã‡¨Ú^ 4ÈSoµ¡œt6¹nù3.ÑÔ¨óޤ.ý ¤™â™5X| ¿µKòË`„ÿÿu×7C—2F‘@Á1Ç—†Ÿ $} cK#o褙ö›€LÈóžQŸQa;ðÈ’A܈¿í mÖ'ª1QÜ4h2sªÅò§þ$ð œôþ3ÎÚ[À8ßc†Œõ—†àfÊvfšMÃóÖ|[Ü6¥ßÅ#9掃ÐûßÚµix€“ƒlm´?Á×_:TL­¼S Õ2Êd¿Á.\*b‰sœX¾ƒRt·~ïi5/Õ<É-ÓMjÍå ©°iß5‡ô8»$ÅÕæÑ¶¥|îÛØš G¡QjŽò')!£Â÷Žb¡“=èdÏ(£`Œ €²…? FÁ(£€Ž €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! ùV0ÂØÿìÁ,Ë$i’âa—íâ¬X ê±_¯†½.·¹æ™Ã.bˆã>ŒÍði»k1ËËrâú³ïNE«Âo¶ç©´F'o·—˜ÃGµ~ƒVgÔÂâOx”^W÷åôŒªduuu2]>†±>«˜ÏÙÙª3-Óy›Œ›ib<¾6ìgß-wgŒ@Aÿÿj¹BËÎ&6°0ÆMP´s|ùÅá×”RÇWðß>ý'ê;S@”«Aû„‡ |ZSzÒNœš)Ž@u•ECuÖi é .ñWÍŽ ã.TÒtþ).#íQÇÌQ[›°‘(.á*j ±‚μ„¾ µ¤³ê8B‰‰¤wB‡ápÖŸýb&~i[òÎ €„¡÷¿µ-“IÂs‹mLå þù‰y ¬¬ê}±EÐ’e#@7wº[S«ôx¶¢˜|r¤}Û¿§õŽ™ûí,-*C;ÙÑsh|hÁnkM–õŒÍ—Vȧ•i9¤ºdúÛ|™ ÷Q>qãgqàæŒq Azÿ[ÿÕ4¥¯ãð ¡eá5Ã'Fn,F¢äÓâ,òÙDÃjØ€‡»¯BS #¦3õ­¶ ôS3N ¡S[bðÉ·#,NwŠC}®y¤ÆGSÝÔÜô?8‘nbþ;’Þqš¬ Ų'qþF>È9c€b†ÞÿÖ•g‚K‡ïV•Z“¸ôÅø›ªKM¦†ÎAt1`´wÖTSkÔ.Gz T{£*/$|QI­ÿFäi;Q_×W€f»twv“ìüunbé»ù"bÛ„B³ͼÃÕž„^KJø¿´Or­e„Õÿÿt§@Öt³K‡¼b5Êע׿tÞ;tœ]> \E»;A¥p1<ÝávsœÉqdÁä$µ8Gu—ÑV·Ò³D­ºçŽtŠUÕ *_`kÝ<%T :Ú¸Ì Y +.Œ ~åÛÛõnÑ@Ìq¬öͰ3|ßÊ€»+FAÿÿu«Ç ‚Ý5äœ0ضôú”d`µq†âf¸·"žˆB’.”x£QN‰H±$Tù’$çžc[˜ÂM×·”¡2®éÕ>çé¡ÃpKη›ë&3ƒ@^äRwÕ™½2·n“Ûðu ïÜqAzÿ[»â{E™ Aù´|õ‰yšÊö¦ìà¦A)Ið)—$O L†÷{ØÀ–±ðSàëqÉOàeïIÊðv!§ó¤vÕgÊÓêD9t£…¹«¡I­ëN [Š91"4©Ç¦³hdò;[[.)€ ½ÿ­[C̯‚6¹ *Tßøøj@]“™<Ùš ÏmZx6[ȩᦙÀœ °ŒÍâ5ì@¡UÎñ¶Æ 0­p(ß\ 8]ÿÛ»Õçü§Ä’å,‰r“k³µ·±wkó… È/ƒa†ýÿ×\«ÊaH\ÈmЉie^ò5ðí€ÒsƒŠ¹DAƒœ4­Ç\ÏœKñ´4½# MS»KTOÉôÝÙKi={ïÚÄbµ©¯)¡4›ýsÙìÿ˜Æ-”mv}rÖ6Þ¦âÔ˜<íÓ/t @~¤Â ÿÿº«ˆ:A‡vªÜ(}áðo`lcuÂHDl’Š’~š›BÍPwç”Ýžxnœ sÛÓ;'‘c<ÆPâÜš…ÛŠ“*'˜)¹¨Ýgú£ö“رp&.óÜÄcçØ1¥aÏU2nÿ{›ù_Ô€{+H„Aÿÿu§`ˆ:½tÈKV´¶å‚^~¼š-" ~Ç¿ýè8î¡Q¸ Ji·É„¤Û§ v6n^HJ#—õß¹›½)…˜Ø+¹p6ŠvM*†is'¶êÆÙ¯MPîÑG’jIE¾SÏiì¨uYâŸ|çӗ8oî8à ½ÿ©Û©Re=°d‰—Hù¢±ròãÕ×R¹–ó, -»d¤5´Göu¶y*Rª°U#SELgw$Sу1EÞ³U.ÿš {s#“ºÝøÕîjR¤}t¾åÜSÌß"!d¿‘ ü]ùÊâ(×]…WîÍ †¡÷¿µ“ Á×$ù`Áj#hÓtðWNíyRdm›éph­Ž”À“™ºâ6‰MÖ"M×ö»Byž%UòÓYbŸ”ZÔ¶ÏÝ)Ýë-Ž#sŤ¸)!ëžÔˆP]ñÕšÎJqO µ^S`ž´%€jãz†"&S R¡î).µØZkø* tsI-¼‰ú@£$ÃÁÌBojÅ“Rx’ÒÛÂð…1²Ð+\qF(Ýáj(à’#§!¦"D–ÃUáJ7¤Æ©€˜|I(âJØÌ!µÇ¬ŸF zo¼B¦alB5=¾V5.>63ˆmáÒœèÐ |]ktw[°j½ÁôRƒl.uÈþ!'ƒàËŒØh\ò0@¨‰.¯EGL/ gx›81ñˆl>® …X?cãS!QC ±½p‰©E¤–¢ •¶‰WÉK« ÒR@è­«@›¤@Bq—‚S+¶ã8vÛ3ã™sÎÞk}—>œ3Á1¾Ä^ª|ÒÖž9ëöÿ¯ïûÖúïµàe{Ù^¶—ítvþy³—_æá¥Tz߇ß} „„¯ŸrçãÞ½ížc§ksëïÞð§M“?pï¿<üp+ÐÿE>ÑâÙ*ܾõÖ§ºúúÜêî W]³ví†Ëfgº½ôvwßûÖÛ>yºv!„›¿·ã'+³_ýŸdéL…·o½m]aûÄD•Ö­ŸÎóG»€¹‹7®îL¯ª«ù#ͯ¾êµ¿Òìü¯>tb»÷þÞW-,.ßñØã{>üä—Eà,ð§&§+Ö¬›hæ â /—–¤Ú³{^Ž>ß„Õçõzàñþ;Þû‰“ÞñàÃ?êÿüû/ ;p·o}ïƒU¦.¹tµ÷—KGŇ«f»Ë6¯)oš]ºäÒÙáE¯Z¼ä²91|î}~÷ö•¶ó ËW--7CàÏÏ4øÎíŸ ;·ö%åáéì”oßzÛ!òí g|a¾•é™NgnMoñàþåé˜,çVºK‹U!†ˆ@0“G¾|ç×¶¼nËæÚ±k5pÍJŸo»éºg&;Wˆ5B8tpaßoùû;[6:à×½ùOü\ œ2¹R wÍ®ér|¡•óΟ¨=Ó÷ÉéZ–—›ÜEBˆâ®|[ŒñaÕ²ÆÝþ,Æê­¿ÿ¡w~÷±û¿xà“½ù¶ VÕmäB)†F§h¡¬šá›ÿñcŽÝ·ó±ù¦üàÏüõÎíŸ}ê\IüŒþàn}G§Sef¶c"º´vÝÔªg÷ï/-þ3Æj"„ø`áówo»gprÛÛ>øŽAØúõ»¿qoÛäwÝò;7¬ª¹¥ŠO ̄ᰠ& ¬AÄXªA۰ضì8pìSî9pßÏMàßâªÙNwnmïØáƒƒja~¨n,‡v„?s÷¶{v}ôú7¼ñò¹ÙO„ÞÛêP ÷€v4!tñõ¯˜™ÜÒéTÔUMŒO¤Éh[(ê ‹0 š:²Ð4ôuÈ¢(­”íí;ú‘'Ÿyn÷9Øú©Û?SÕéc©bùèáጙõ!|'„øé/ýÍßÿø¦Í›7½çÒ+ÿ©Wu_Õ«œN¬H)‚£•‰DÄ^'ªj´FĪBÄ,h.è°%49³ Ãä ­0o…¥fH_ ô¹CóÍû¿ùøSÿv&/Ên¯zÏÂüàhÉ–ÜùtJÕ?ܽížç^¿qãÆÛ6]ñÝ^·»~ºÓ£î&º5³¤‰)†‹G©¨ˆÄ1¢¢!@©Š2Ä ¦ÄºÆÛ–z¢f² ¨rª©\饊6šìœ?7¹ý=¯¿òÃ_ùÞ“wžÕï¿ãÖ·§Š/”¬ùå;¿úw'WüÛ7ßüìyÓÓë'¦ºÌ^°ž¹›˜½æjò±c …ã»wÓz–€CDqbO1£H¡ä!Þ´ÈÀÐa f´î´æ›–c•±P26,dÁh¨RäЀ«¶ïصëŒ0Óh™O~ùίÞ{r¥/¾õ¦»VOM¬ŸìVlØòæ^}½Ù5ä…#„ey_\¤3Ѹ*1‚D7‰­*J­x§*4+DÐÆ¨ªÈ$‘¦Ä"½,õXä’Ùú^àêSxAJüpÇvýpÇž8¹ÂG®Ý×®Y½mº×eÝÆM¬Þ²…zr\ÉÇŽ1œ?LÞÿ ž êN£Éˆqû© X4L IŽzÁ‹!u$Dw¬¨á!P¢!¦X(3J€””⺫~ýÊÅÇw>ýðÉøÎ*æ®;oõç;Ý f®ØLթѦO{è ±ÛAž?ŒMt˜zåèU„:áÁñz47"ƒ’qsHÁÐNDSÀªˆ‡@Ý8Éœn5A7¢‚¡5eÐÏ<¾3øÐ®¿aª—¶têHš`â ÀÜ_ v:,î~‚ J¯;I±–’‡`†U"”* †af˜#æPpÄ wÇD0¬UÕÁSÀ«š˜"Vkaêð`ó9¸zõìÇT‘º5³—^W/…8–žÝOgn‰l‚?ŽÇÆÈ¦P2â ¥àÑQsÌÇå8ž‰;‘–Aܦ TÑÀ"â‚J9%Æ3êô^]ývÝ« )àÓ”¥%°@Û_¢®júBŒxɘ9w'ˆŽfÔTð(ê„0 ªˆº¡-/lp˜aðèˆAìAi¡#äaE¬N­0NKàm7]·©êE’;¡ªétzØ`@~ï$Zɘ`x°¡D‘Ê^1CQŠÌƱoNÉÝ„@Ápu,‚†@¨z¼%º¡j÷S‹ÖÓ¸6ÍÝÔÑ:ઔ¶EÍkñ¾â®àŠÕ©)¨e¢  š"ÇÜа` ®h ¨ š"ä–íT ÍžñFP¡v,GbrJ>5ÎÓèZÀS TP'4QuÜï÷Gñl†«b*-¨+1€8˜ʨ>L UÇ£",*¹±V1,EŠƒ,ä ˆ*Æà‚U;Ή@é&D„ ©"ËÇÑ™š&}a5\ )²"Jò‚F0U°Œ3 s°h Б‡BÄ+¬isaØ©ãè’§+ îœù Ãþ‹ªJ)-M™:&ÚàXɸ‚ "ÁÁŒày4âãd-£ÝÖTr‘•ðD@µ¢#§È°(Þq†ƒ@ªàþ­Sá<ãçܶw½Å§«ŠéÙULÍÌЛYE*J.™D ‰BŒ#À%Cdb¦`# jŠ™0#ÁqZUT)†h¦¡¯…¥¥}7kCPK ÿüý§VŸ“fÿZaoI¹Š@ÓPB iAŠ€ Ö©Á#Á”Ñ  ÁF‚Î Q£¨¢>JdŽPÌ1I‰áPÉ"XTlXæ‘E"iªûµÓa<ãF¶oyð…F §Ð¶}ƒã ó¾´˜g$ª‘ŒHF­àAQW\‚‘%SPpCU ¡ ªä±bQÚ2¤Í-ÍPXj %D OXÁpm÷®Óa<ë‰ÀÞý[‡¦{ êºK/E꺦rÃB¤[9FEŠ©¢2Ág¤ñÕT(>"ÕZ@<£hsaÐŽÂgyÙhC¡ÑL_)Ž ±ŠLMt¿ùîºùtøÎzbö|Ö[{ùvÌÆ0FÔ•*A"E" 'U(ÁG3.¨ƒE–‘lPSZsD %;Ù¡µB¿1¬rch•Ð&3Ô„%$çàDõ9F‘b§ÂwÆ“9€ï<±gϯ¾ìµ¸^aÅPuç€áØX£dœ¢ &dW²Y5CÇIšK!k _œR2m$*¦F ‘,B«…¶iI) 1=zßýO~ è2ÒÇD^Ðg%pÑk.þþª6¼3¤0-È”¡‘Q¡ ¢BGQr0úº‘-­*c…ZAÛ*mCiZ¡´ó€³‡vÙ;ä`˜dòÎH=é ³æÁÎÇö»øúK¾1³TÞ•ºiÚMG ±â¢d7Ä MiQ-´Ái‡™¶("…Á Ý€Ì’9Z”"­&•Ì À°1({ž[ûž]ؼ¸ è+‚¢Ë+º+lÎHâѽ‹›/»ð‰nˆoR·©Ò m„6R bN«ÎòÀö[Z)ô‡™Ö•A¥%¯¬< " 13´€ 2¸ptPرëЉQ2\1þûyFGõÏ­NŽ]r¦±tw<ùÌÂÞ#‹ÏoZ»ê7S7¤vüQ"RȪ´­ÐäB.™Ö„ÖœR mŒL©æŠV¦F6§˜Ñ´‚hFUYÌÂýí?yü0ÆØgt`|8°B 7.6®ÿ3‹ÍÏ{;ydb v˜“XsØ<´2N8á·ö0ÃqY?óŒfza\ï´!þºÞ9¡züTŒr¥;þ¿ðÓÍÒO9ÖÞèø7ƒŒc‚2~Ÿieü…8]¿‘Ÿ†Ñ‰blEËœ ç|µôÿÆþ\އÂÁ—IEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/background.jpg000066400000000000000000000533131221440706400210530ustar00rootroot00000000000000ÿØÿàJFIFHHÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ"ÿÄÿÄ8!1AQ"a2q#B‘R¡3±ÁrÑáðb¢ñ‚C²ÿÄÿÄ1ÿÚ ?ùØT[C ŽGzFÈÜh ÊŽè¤^¶‚¨hÐð|Ó lŒ‹F¤T€{¢æ(Äv×4 ùTQúž|Q •¡KH§Âylém¸Uw$‰¨¦"G¿4©îd€vEL¹ C1ÔÿH¦€‹€2;‘ÞY $É=«¶â3Yø4Àçp€£»V”M•´'UDýkYR#‰¢ŠB@X±ã˜§®X"A™8¦$ërBÁ¨©“ K„ö¥Ð¸dŒˆÖ©Þ1`Nˆ¢ÙpË›ŽMTDL‹î~)‚©oÏŠ%²%ýFQ"™-¢Ã³³ß<šŠÐP Ä\ˆŽ(žÃ@E/¦z––g[}ãST´¨€ùËÀª€ª-¡ˆÉŒ–¥ïpª¸Dìš* ¨„‡$÷¢EÁ‘V¶$~ê7U ›`Ð {ÐU-yZàTê»§ÔkŠ :ÔƒD!7@`5²{~(1`v¿ØÖ²0±™úݤ}«Næ[®åͰP‹b"7"¢Œ¾1—Ð ˆ²rfV ®ÀÁ$O€œîo~ÕP¨e½5'€HÝîq§ñTf÷ËÚ †õþ±’ÈXE–g˜ ¨U27è?½‚)÷7ö¦fôWõ]Û‰?ù¬«mos9ùŸÅ ‹hb$ÈïCÙYQÝ‹ÖÐG‰ –-3€]îÉ:ŠsRH;Õ½ìX¨f$€}ôY­Ú¶B[P£æ‘ºr$žGª NïÍ,ŸT4hx>iƒ…¶FE£R*@=Ñsb;kš|‹*(ýO>(„ÊáP¥€ˆ$S„ ‚a<¶t„6‚Ü*»’DÔS £ßšT÷²@;"¦\!˜ê¤S@EÀÈï@ˆG¬’džÕÛq¬ü`s¸@@ÑÝ«J&ÊÚƪ¢~µ¬ƒ)ÄÑE! ,XñÌS‚×, ̉Su¹!`ÔTÉ…%‡B{Rè\2FDkTï°'DQ ‰l¸eÍÇ&ª ¢&EŽw?ŒÁT·çÅÙþ£(L–ÑaÙÙ‚ïžME!G*@u&cŠe·mT,HÉæ€~(EÅ9#Q@ fëlŸµ=ËÊ! …Ȭ¶ò-î#(š2¨!Ió@¶Ý ÂV0 Áý­n` 9ÆÀÉÐ ™ºÑ¢ [—{KHâ¨ýBÎôOŠKކâ[µp+³Ì[`WEë-›ŽY- H’[ïÞªb¡‚ÌDI;&¤Q˜ÀEQäŠ(Äté’º“î9ôàqãɨ C*•WsÄÒª"c7™,DÁ Ì¶Üì@ù¦Æ@rÅLh ¦@] LQ‘X‚÷îdP’É,<ÿȱP ÐøB&æ Z õP& ˜<ÓûÜcÅ1#Sßâ¤?SÙ$ÀÞµTlf4cÍ'Ð…TnH rŦ8ì)D ÔsF%x"GsºðèqàÀì©Â— žcš¦Á5Í*¶³0#tåÄr?Šbà3*¸ÍJÒÿ˜k÷ ð©n€Ú'æŸÐ{BÒÝ%²Þ*œ}ê FGÀâœ6"ñ €Hó½Ö¡,@-ò8¨¦FÈãïN<šŠ2©UpX÷—Kê”&õïv^*¡¬†ôÝ=„F´­se‹{ˆûÒ]éìtß­îeµ-胯üWeç·ÓÚqÎMû@šæ¿~Ût—{‚ ŠÑÔu-«ÑÒ³µÍqmÛàAä×jõXÚÀ&O„5È@W Úy ÂÕÁp*ʾ;šhrI =èC!ÉýÇ9•æg(Çš ÒÞÐ3X:4™Ÿš6P ³cŠÒË h46ÕPº1:Á¦Hd{ ED†nÇÁ¢H˜ù¨¬å‚Ù:óX¸E‘; P®n-Ç “Oƒ‘îÖZxª…úB¨2Õ‘1·#°ÿµ>H’¨ÒÝÏ1HÓýŽê(3b]î0…H¤é:TêɽԶ(L­¿#É¥¼¢ëZéÆÃ¹ÈÏaÍ{im-ZKP›m?¶«.uèºc­€ʯïRK¾‡T-[¶nÜpX3 éký-¶9\xñ ½C¿SnèDÁS³Ú£Nr—Q¦ê(ù~(`K ¸š·UuQv¯Ü)©aseTžIæƒ2)e§ø+éþaº{$•W>à§;U ••Âߎi€+ðPÊý꣰t=´ :{p8öƒULÚÖ²Z*kÕ$MÅyð Nç_qÕÒÊâ&^MF—¿y:Nšå¶½“±¦¼äŘ0P£ˆÇtUBuÎH=šY’wÏzˆÌˆ%‹)•PzÌpX×!\\'jt9æƒ WÀ\«*øîi¡É$€ ÷¡ ‡'÷ä W™œ Ohl/K{@Í`èÒd~h`Ù@2ÌyŽ)ÿK,- ÐÛUBèÄè˜} ‘ì)»‰ c梳–gdëÍbáDHì)B¹¸·‚@M>G»Yh âª-剃<ÖÂæ^ëe{ŒZgñMmË-ÇHUŸ'¼Pfh ÔPÐÄÚõ#Œ´9õg¶ª; Ù'G½H€’ÀÆØŠ¨Ïe]Š»–V½.’_¥¶%Dk…¹ŸT°ó¨ o€bÇúvh:úÛ`² º¯cûMs\`Ph99ù¤ ~á•°@=ØÇö A[%ÛǸ:ž*)½÷>cE© lFÜÉâ™ÉÍH2æ'À4æ§l—£<¹:+^%m9Æ·LätöU@÷üš”QI™ ŒJ)Ðù »Û ƒÁÚr?Š»=ÛÖú{.© ’Þ?[ ô–ÔÞpÀ˜9©-Æ7’ÏMmn:ÉbÜ]·.Û»ÕYÚ!‚wUã¶ ÉËƒÍ <˜åÿÇÅ]ÑÜzçFÚ¤î*€2'B¢²«2cnÒö˜¬RÞ‹9b7£ýâ…²}Ïí÷HŸ™=ósxðsó@m*-ëW[;“æ½1 ú¬à~ªòðp¡Äò *ûΉòhã¼îX悳¸75,÷4‹$‰âx5FЊˆ¶¤“ÃËPg11ø4 ±ˆ1Þ‹LSöª€ˆ.ÀÉ:í ™> Pˤvu9"t4OdÛ|Ä‹iíÙí®õ†,èHçâŠ"˜Ù=Ϫ1K¶Ö2R{οŠXuö2OôäÄž>k)!8‚wÄTPd yb`Ï5°¹—ºÙ^ã™üS[rËqÒggÉïšÈ4[CkÔŽ2ÐçÔvžÚ¨ì+dLõ FKb*£=•v*îYXD ôºI~–Ú@•A®æ}RÃ΢¼V‹éÙ ëëm‚È‚èb½í5Íq€U@} äçæ5û†VÁ÷cÚl—lKàêx¨¦÷Üú@U¦@-±r7'Šg$h?5 ˘ŸÐSš²\zŒòäèx­x•´äsÝ3‘ÓÙUÜòhQDe&vf‚1(H§Cæ‚ïl6SiÈ@8þ("ì÷o[é캤‚KxüUnƒÒ[SyÃ`椷ÞK=5µ¸ë%‹pvÜh»nïUd h„B ÝTsŒZØ+'.40Lòc—ÿwGqëœj“¸¨È Š,énØ·°[©«—æ>ÂªŠŠ¹bÞuAžà¶¡@‰&;P"©ô˜1P@ˆð*‰"I<®¢—Ó,CL~ŸšGéÿÌuInããk¡ÜÕF·ƒ Ž-±ÁªS)wü §êzfé¬ÚµÓZv ?Wæ¤Èöî0¸XÜb¢š}ØhäI¥KVñ¬ÁГ³6> dOšƒlË@#šKu Ëh€?{öHDH #šÀŸE@*K 11A…»s¶ ÄêˆÀËæY  v, V‡m–ÁPó ÉÇäö®fêl(—Û]»*“?o£\[}:é PÌ;ë-€ª¶­°KK¨A Ô?á‡;—®eFŒIÖ€¯ImäRAPǽrÝ«CñI~àéÖÊçý5p«Y³eíàK‚}Ìg½@ v Ó•BÊ$åªwöª!| ¬¤eÇÔ r1ã½ óŽÜS¤¢›…1v³3ª(* ‰ #±=èåÁb'KSIrÎNɱ‚K¸yø T—nÞŒÖfU"u:¬~(¢ ½[HÒ/šRI2I3â²17)’ÚŠÀb§Oo­Œ`L±ç½{€(µi3¸tk J‡+ä;!Ò´áÑqžýÍ*!yÙ€LÕBÉ+…cÇÚŸ#&Êc*& РÀ±¸ÅGQ@ÚBÀ‚û'¸¬Qša¤0ˆ=«I6t&¶d‘ ÆäЍ,énØ·°[©«—æ>ÂªŠŠ¹bÞuAžà¶¡@‰&;TR*ŸIƒ¨’$“Êê)}2Ä1dÇáyù¤~ŸüÇT–î>6±:ÍTkx0¸âÐ`¨õ2—|; ~§¦nšÍ«]5§`Óõp>jLnã …À&*)§ÝˆöŽDšTµošÌ 0+0#cêDù H6Ì´9 ·P̶ˆ÷¿aT„@D€ ’9¬ ôT x°Ó[·;bÜN¨Œ ¾e˜÷ñJbÊ`vÐlU2 œ~Ojæn¦Áb‰qµÛ²©3ñ1Fú5Å·Ó®• ðñ^²Ø «jÛ´º„ÍAÃþs¹zàFThÄh ô–ÞE$ {Ñ -Ú´?—î`®q?ÓQ§ µ›6^Þ¸'ÜÆ{Ôb ÐÙÝ9T, òNZ§qoj¢ÀªÊX»éÖ¹–Ý`·mæå­É×< v!m®+;ÔzŒmÙw$·üÔUX’˜È˜ÜR[{ª iµ¶.9“Z:‹ªnž‘aŒ‰p¦+§¡±q÷¹Ü#KûG‰ªŠdëxº^=EИTñ\îÖÞ×®¯qîð̇šõz{NÁ˜ÀÅxaÿÚ¼ÁuÖze6Ŷ’qÖ¦¢¥é ÇrO›À*Ûq͹“le5Å\ÙÇÕ(UQƒuÜë|QƒÞµÄK\r} óAƒ(8éî°½¾ô3,˜Êg[ª;„¶GÞ‘WäÓ‘Ž8º €=È=ªÖ:¯M$ “ÆÏGPÁî)vÜ(â›@sÜÍŸ¬ºW °SûGšæ$“=·C1ëÔ$÷Ûfi_—ñUŠM²àmާŠV¦DÿÓºgp-¬dDkÒ5Ì' Aíê(=чý±TqéY$Ö·mî÷ÕØ3ê å Ï ÄóU ‰ŠfvÀ"”qðS¯ÜÞ*`›ìBŽÝ?…‡»ÔOy­ZP=¨cŸ&‚ªg3ˆîh¹« æLE ¶ÅŽ­,•»s‘1âkYó æN¾(6*<˜¬ 7±X sOšÚÛ>É“É'“A-’œ ’EIv oæ+ DóLÌbkâ7S 3¦LA“QL°WÚitÏ„äØö¦! >aI˜ƒÚƒ*ÙéÊ›–=ÍT5¨[ ¡?÷ K’“ð(Œ[ÙÃf{ŠP™)9·ÜÏ?jŠ»éÖ¹–Ý`·mæå­É×< v!m®+;ÔzŒmÙw$·üÐU‰)Œ‰Å%°÷º –˜Û[`ã™5£¨º¦ééÈ— bºz_{‘Â4¿´xš¨¦N·‹¥ãÔ] €õOÎímízê÷ï Àhy¯W§´ìŒ W†ý«Ì]g¦Sl[i'jj*^ Üw$ðì)°|­°GÐk™0ÆPc\P…Íœ}Q€…Uðh0']ηÅØ=ë\@TµÇ GÒ42ƒŽžá; ÛïAÃ2ÉŒ¦uº£±HKaTxéqM9àP‹ È܃ڭcªôÒJ )íà¶A ÃÉmîƒ>¶™þõP f ú{Ñ(¸É^ò>ôÃPHÊ>)L´â<ø¨¥À9Õ²XžAYíÛE_VåÂIúTóT̘ÅŽbiQQ=Øï·z¨æ|,î¨ò2P¤Š*¨P\dR[ÊöûÑy$Nñ⢂(Y$“q»v•ˆE-?Þ¶6Ën\8šÆÒ}^³¦wºoômÉc“ ŒÑ´ŠÜ{y1<·ŠM;’¤°_Š¡KŽL¬5½P¯qÐâ`ö¥°5_Ô?¸™¤[=KtÉt2æäâ„D ¬¡Eç²H/ÉHïUIpI9æh,úsÚháí€ÐO$ Fd´Œå‚¨å›‘iBÁKez›½C„)l/´’'~)S©|¥Ó^aÌâ?ä×_Afå»n€¬î^'.õåæQqÚ%—\Tî„Ôÿ2nÜ{8ûWu¬¯2B†|Wut"ÊÛS÷w¨©1ITªD F§æ³bÙ'˜S†Ú c1.fƒx&w1@'´–O`)‹Æ‚’#°¢$dý¢ªijOon襋EŒ‚ùÙ¥´F;$’IŸÍ1_vY“<ÍE8d™ÀGoµ#31>Õ¸ãuŽ=þO4¶ðíÞ¡Ô¨{Jè81ç{®„'…Ùþk*CNF š¨ô‚‹¬Î¾Ûc‚Üš£„A$•FÔ÷5À½Uà°ªF‡Š•ë¯pÎXž7ÅHµÓÔõÃf׶ߟÝ\6Ðvã‚Kq>)íà¶A ÃÉmîƒ>¶™þõP f ú{Ñ(¸É^ò>ôÃPHÊ>)L´â<ø¨¥À9Õ²XžAYíÛE_VåÂIúTóT̘ÅŽbiQQ=Øï·z¨æ|,î¨ò2P¤Š*¨P\dR[ÊöûÑy$Nñ⢂(Y$“q»v•ˆE-?Þ¶6Ën\8šÆÒ}^³¦wºoômÉc“ ŒÑ´ŠÜ{y1<·ŠM;’¤°_Š¡KŽL¬5½P¯qÐâ`ö¥°5_Ô?¸™¤[=KtÉt2æäâ„D ¬¡Eç²H/ÉHïUP…Ü÷¥w-¨“P!QCƒºÊ¢²µÌf3Tÿ“@ÊŽë‘!WÿwH#d+]c¡@|Õ\¡ !Gj[èâ‡SÀïA’Ù©'#ãµDÙ~ÜP/€(¼ óÉ¥ôÜúŒH;ÐPÈAŽFÍ`Z vyjpél€ž|Ð’Nê)I¹væ6öcm:Z`B«±&Zy¬€¸t/µì?wæ‹Yic &cUq?¨µ< )mÛ‹¢ã6À «ªå1Qd%N4gL)À–c‘h¥u gžP¸:~³©2xdñF×A{¨Qwª|Wœ$Àÿ½5‹g¨ÿE3éôè ž í^ª#»F•&Y›ÅZGôVí'é]¸4:ì *õØnžÕ’×Ã7s&»’ý•Ì-ÀÄ+›§{Vo]{¿¨÷"cŠƒ z‡ÜtjFÚ¿UÒÛ>à\öÿEtõoníÑsÓE§Z©‚ìÏé®*?UGªÈálb¿õRºª.w :Ë÷W%¾²ôD&‡1Q{—z‹Ì ã÷MHµÑw¨wµn8^Z¹æè lóâ)ñ–$ûˆÔÏ5‚¢œˆ“þÔ âZ|S¯?ÿ4€!-+ÉíªV¤Ä( \Ãĉæ„1Y% wâi•-ú›A€‘³LU]¶ax XÒ-¡ãã½+–r}6UOêj£º äöR Viº¾a*¢JÂݲ×OrP%Å Yై‰5@팪b;H@2\" ö e(PHÏzWp"Ú‰1ÅÕt8; ,ª++\Æc5Où4 ¨î¹÷t‚6BµÖ:4ÍUÊrv¥·þŽ(qU<ô- ’r>;Q„M‘'íÅø‹Àß<š_IÝϨÁ‰½õ ”älÖ §g–§–Ì(‰çÍ $›—ncof6Ó¥¦„*»e§šÈ ‡BøÛ^Ã÷~h¹‘P:f5Qqú‰×ûSÀÁØ–ݸº.3l º®QBTásFtœ f9ŠWP–yàEkƒ§é :“'€&Omtº…z§ÅyÂLûÓX¶zñS>ŸN€™àžÕê¢;´iRe™¼U¤q/EnÒ~•Ûƒ@ƒ¡®ÀÒ¯Q†éíY-qL3q÷2k¹/Ù\ÂÜ A⹺wµfõ×»úqò&8¨9¤3,HÏâ²”ÁRäÑgÌ,4ÁUWP\÷ P@B2b`˜¬¨KF_oÿimŸP³/кüÕ†#góA°USX÷<ÐEs9'lR3’Ø) ?{xÈ€ªmƧE¨6#7XZ.ñÿV«Ç÷@ø€©`'#¿jn€£jiäÅ:&µÈ,Ü/Š’@~àшPÄ-»däO4°öžü4Éh#z—}ÍûAàRÜcé ÜÔVP™$±¬@Ä’GŽiÒÜ ˆXüŸµMšÐ0VGe‰ §Gí¼íŽî€gä+Òu bãÜ00öÍy–ДËÒkpu'cñE܈n³ ˆ=¦‚v‘ͼdmÏ'íM‚Ì–2<Ó\!-„š_NB+¹ ïâª&–’àä/e¬ä'`+’&5°Êf"¢” *TòÝé€[i‚‚;±=éCûHTãs©7qbX[>æË€<8fŲI“&g·j ¸¬GÚŽ0YV  ±üÐ U€´P{¨ª2aæ±¶ 2y ÿ5T[]?‚ÞL LÝì†3Åõ$Åæîrú¨ ã; j95PñÐPX2ìÁÖÿš¢ZœÜ3qÈÐ'ŠPÒ°ÛiÔR/¾{{@Ы@HЀ9¡l*— ³@©¢Tæ€ÈfX ŸÅ!e)‚¤É¢2ϘXþi‚ª® ¹ï@ €„*dÄÁ1YP–Œ0,¾ßþÒÛ>¡f_¡uùª$# FÏæƒ`ª¦ ±îy ŠærN>ؤg%°R~öð)‘U 2ÛN‹PlG n°´2,]ãþ­V!îð)RÀ.NG~Ô ÝG:ÕÓÉŠtLkY¸_$€ýÁ£*¡ˆ[vÉÈ$žh aí=ùi’ÐFõ.û›öƒÀ¥¸ÇÓ @'¹¨¬ 02IcX‰$Ó¥¸@ ±ù?j›5 `¬ŽËANÛyÛÝÏÈW¤êÅǸ`aíšó-¡)—¤ÖàêNÇ⋹!Ýf{Mí#›xÈÛžOÚ› ™,dy¦¸B[9?4¾œ„WrAÞ#ÅT#çýé™ñ´Ÿ[÷ð<ÑI,ØÉ ÌÖ²î&ãk]……@Úÿ¥oÇî56b`lÏzir‚AT¾«" Wm šŠ)eTÞ{ ¢î]·’àP. DöŠÓ ±ßµŒY`ix§ ŠˆkBh‚HHÝÚ¹ aìHù¤BC.91<)À" M*ã™n@ì)Š§Ò¤ªù¥:IàŠ×ÜÁvsð)•àP'F¡bÅΦí˾¢€†Dîº.8±Ô½›„¤hD½T)õŽÉOïHKA”“ÿƽ‰ýL|QÌ·=¢€*i¸0 ÚvMf†¸[‡‘ªÁ™î4ÈÑæƒÈ" óÅEb‘qT,À–,x™Àb!Œx§[aÜ<‘D2'Ý(#›%§3Ìê©eZÝ«aS'DÐÌ™÷4fú–}ǹ?ö %ýÝÉæuqö©ÙS\È‚ÿ4ÞÕö)‰÷j˜ S”ƒö©JäB‘äÓ$ð~ kL=b#@’HàÐ9";…$½m®”7ƒ±w+Ø"µÇ¨ÿ“Ú©aíÞéâÛ<¶ò{UC2~iY³.OÕíô­Ô/­m–݆~þ+”•õ• y˜ p…QqNñž)’Ù¶ÅÜU¿ú0S Wžäö£%܄ɀÑ'QXHùÿzGf|m'Öýü4RK62Bó5¬†E{…I¸Ú×aU[kþ•¿¸ÔÙˆe³=é¥Ê Pú¬ˆ%]´€@j(¥”ESxIì‚‹¹vÞJ@¸|Ú+L6Ç~Ô 1e¥âœ6( ­ ¢ " owh<懰I#æ‘ ¸äÄò@§ˆ,@ñ=è°Yh'™Š¨Ìù4¨ Že¹°¦*ŸJ’«æ”é$€j+_sÙÏÀ¦Tt{@…‹:›·.úŠQºè¸âÇRönn‘¡>õP§Ö;%?½!-ROÿvö'õ1ñG0ÜöЍY¦àÀ/iÙ5šànF«g¸Ó#Gš _ ˆ@'Ïå zk¡ñþôª2V·ù¬6ëò;Љ_“@×a”,kÄš/Ì·Qwö7¸&‹…Zá– FFPAÌÜÇÄÏÍbÁ-åŒjÍ4@æb;šê^¨fŒØ1Vœjjã©lŒ^^æ ~£ÅsõÝEGÓ´÷0òßÕRê:‡½qò:èWÆæ†äïñL¬…€¹2 íX7ëfAã·jı8Àv©ººbààn‚¦ŽÔ…”!ð5×3Œ»Ð¶ªí‘"ð<šRT´— èUmo6cŒìÚµ§Å7ošV`·¸|мdÇf"‰Ç†MÑJ9 ûUb9“³=¨-rÖ¡¼)¬`)0&55—‚<5‹É“@]ÔD˜=kp—äl?© -rZ‚ñD†¸RPpuUMÕ#£ú`ÌlÿÅs¢ÂÄkÅ mô‡²Í7¦ʆk’½¼ÔV@5½HΪ 1€<Ö£Ûž$P"Ú–LGv (¬Iv©Í,”<˜¢ 2+9lˆÚŠ>ÂpÇÇ÷ @WC)"ŽKh©›À¦wÁUÐàIk,¶¤1‘ÙÕs¼Ée[P; šÝK×ì±Kމ;dÑì 5„Ußó7¥ÑL[NAù¯^Ò.L)ˆâ­Gš©i•½ÿ2í$p/­Ë ¶ÙA¸ŠëêUÑEë(ªåÂñ :2.ÿ™kÎìÓvûR«•¬Ýf‡¸ª½ÀïL¨6µï&°’IçŠX8ÂÀ¨0$¹Ê‘W×¹EµÛ·üQvy[iõ¾ ½Q“Ó²-[>3?5Q4´—:ëvÙ&Ú&A|šôÂǦ‚Oí¯«5´y"°B×0[Ä즔Eâµ·gk‡Pª€‹é³a‰1Ë+{ÆÈü °dìÖÉs °×iÿŠŠÊp]ýGTÐyß>h[L¦ãižþ(›~øY'ãT qõ€Û588*ª˜4H>¦K—mq@æI¯3?PI¥º“i¶8Qd¾¢ÄyíDÎS"*+³¸N"`ÒÜÂÚ€$ì®ôÂYÄ’q$qYRì´‹käwª†°ˆnƒx ëNLDOsA*\‘î'‰â)ÔBv™QJ¤™}(åh”B/;$Ñ@Ø–h¶ªl@Ñ$·a@@UB˜<‘²híT@ŸÌÓ@ÜÐP(>Aø “–k-솟«’"¸cÀ(­arFºû¬×B¶ýÌ{&rV:ÜQHRˆnæ(ª2²N‚óÍ5±é£»!Mh@ì’qóA¤ÈÀ’DÍ1}ož` þõƒ¸ê£ˆ€4$RìÞ]N¨­¶d¸n>*_ó‘=ò¥´'“³@J;´gm7Ç53iñkÎÇ“ª¶ÔÂÆûòiDYLŒfO}TSçnÂB! NäÔкÛ÷!bL’;U’wpóK‰iÌPášÀ“¨ÝhŸ·j`c‘àhT´A ìrÑïA>™&Ic j¯‚}GCš@¯#µ¶Ð7sN•æ s²ŽÑ^òbmÛì#gtÀ1…âO4ÅËí‰ûT‹aÊ$UCúVä˜ànРð(9:Æ8ÙñQº.ÿ•oLÃs‘íö °!ÜAr#u€%d¿öÝV×øwOg¥7©’¬µÉÙ®{6îÜ›LîY¦()€.ZN¸ÿß4ºÊ&´À‰™>*a²¶² ‘À梪„ãäO4 +¶Õ@Y?šÎ]ä#Hƒµb˜&!'ûÕF°ˆnƒx ëNLDOsA*\‘î'‰â)ÔBv™QJ¤™}(åh”B/;$Ñ@Ø–h¶ªl@Ñ$·a@@UB˜<‘²híT@ŸÌÓ@ÜÐP(>Aø “–k-솟«’"¸cÀ(­arFºû¬×B¶ýÌ{&rV:ÜQHRˆnæ(ª2²N‚óÍ5±é£»!Mh@ì’qóA¤ÈÀ’DÍ1}ož` þõƒ¸ê£ˆ€4$RìÞ]N¨­¶d¸n>*_ó‘=ò¥´'“³@J;´gm7Ç53iñkÎÇ“ª¶ÔÂÆûòiDYLŒfO}TSçnÂB! NäÔкÛ÷!bL’;U’wpóK‰iÌPúÀPKr@£Š¸ Àñ:¬Êp¶Åf}Ü“MŠªª)àwóA;Œmâ¡ò-À#tm#(w{xp o\ºÒÞŸ´Õ™—fw'@ð*¡S6‚Š[„…ÖÉÐÞ™½úøæ™Y\‘­ÅE(¶UàÃTJ£2ûDòiƒŒ¤Œˆ46Ò ¾{UF ŽˆÌV ®Å‰“æf˜*:I“HM¶1ˆgGu×5l"“‘ïFB¨äî¦0Ŷ8Ñ&ÃGbüPJj&fh† ’vbŒp5Å!*ºÐ1¶êù\ƒÚ“CÑR}G$’tfi‚   d™Ù4„Ûc€ftwQMsVÂ)9ôd*ˆþNêc [c€M2l4v Å4¦¢ffH`É'f)ØÇ\R«©Ýn¯•È0= y4='ÔrI'CÅ+ÜcŽjqµ'zÕ'f6'ø¬>")[;öšËi[eN†¨ "-ëy1bF÷ÁŠÊT¡TŸ3DA&hýè°}¶×CB(µaR5õ–ëÁ™ãÅkŒVÑ`Ô§„~ $À$p?4PY˜ÌƒÇÛÿf˜ÈPƒTÌÇ!ˆäÆ©`" >hYsm4IÑOdžIïX’ ýõ?zP$   Í(ÆÕ²@˜˜?ì+*’Ç™žÔQ2Äi~4V.C\=»D*# @1£X¶™;k"’2mРF̬ï@S}‘–§SNÅ·1æ²Ê Pù"a@€;Áaˆ˜‰¦¸ø.õ޳΢•ÈM‚ *¡‰…bÍÞ?µZÕ¯FÑ%}íÍdìíãɬßTO ÌöšÌÊöÐH*ˆš, !Çj¨À¬¢¶'S·¨LÊâ>ÔÁ‚#Ç“Am»ì±EøïQZiîK*¬O>ß!mL ïDœl(ˆüÐSü:×§Òª²êûÉ®ä·vâŸMr?ÿÍyëuìÿ¤åOž&ŠuC†7±aÀíA×zòtÀ-xŸ©¸Âì÷ådž¸Ñšåî±2-§÷4 MÉøˆ %3yk„VÆÑ}¦DZˆÔIf ƒ9KjGjqÄp¤ž8¦xJ)ÜLÎéAuv¢"~‚Ìyn(õ¼˜±#{àÅe*P„*O™¢ “4~ôX¾Ûk¡¡ „Z°©úËõ`ÌñâµÆ+h°jS‹B?P`8š ¨,ÌfAãíÿ³Ld(AªfcÄrcT°H‹4,¹¶š $Æè§²O$÷¬IþúŸ½(’Ðf”cjÙ ÌLö•IcÌÏj(™b4¿Hš«!®Ý€¢† Ѭ[L‰‡5‘I6„hP#fVw )¾ÈËS©§bÛˆ˜óYeP(|ˆ° @à°ÄLDÓ\|zïYçQJä&ÁPƒD±fïÚ­j×£h’¾öæ²HvvqäÖoª'ŠŠQm D‚9èa#q +*;¢‘zÚñ4Ŧp ½Â9'B椑!w«{رPÌIûè³[µl„¶¡GÍ"!täI<ŽT$ßšY>¨hÐð|Ó lŒ‹F¤T€{¢æ(Äv×4 ùTQúž|Q •¡KH§Âylém¸Uw$‰¨¦"G¿4©îd€vEL¹ C1ÔÿH¦€‹€2;‘ÞY $É=«¶â3Yø4Àçp€£»V”M•´'UDýkYR#‰¢ŠB@X±ã˜§®X"A™8¦$ërBÁ¨©“ K„ö¥Ð¸dŒˆÖ©Þ1`Nˆ¢ÙpË›ŽMTDL‹î~)‚©oÏŠ%²%ýFQ"™-¢Ã³³ß<šŠÐP Ä\ˆŽ(žÃ@E/¦z––g[}ãST´¨€ùËÀª€ª-¡ˆÉŒ–¥ïpª¸Dìš* ¨„‡$÷¢EÁ‘V¶$~ê7U ›`Ð {ÐU-yZàTê»§ÔkŠ :ÔƒD!7@`5²{~(1`v¿ØÖ²0±™úݤ}«Næ[®åͰP‹b"7"¢Œ¾1—Ð ˆ²rfV ®ÀÁ$O€œîo~ÕP¨e½5'€HÝîq§ñTf÷ËÚ †õþ±’ÈXE–g˜ ¨U27è?½‚)÷7ö¦fôWõ]Û‰?ù¬«mos9ùŸÅ ‹hb$ÈïCÙYQÝ‹ÖÐG‰ –-3€]îÉ:ŠsRH;Õ½ìX¨f$€}ôY­Ú¶B[P£æ‘ºr$žGª NïÍ,ŸT4hx>iƒ…¶FE£R*@=Ñsb;kš|‹*(ýO>(„ÊáP¥€ˆ$S„ ‚a<¶t„6‚Ü*»’DÔS £ßšT÷²@;"¦\!˜ê¤S@EÀÈï@ˆG¬’džÕÛq¬ü`s¸@@ÑÝ«J&ÊÚƪ¢~µ¬ƒ)ÄÑE! ,XñÌS‚×, ̉Su¹!`ÔTÉ…%‡B{Rè\2FDkTï°'DQ ‰l¸eÍÇ&ª ¢&EŽw?ŒÁT·çÅÙþ£(L–ÑaÙÙ‚ïžME!G*@u&cŠe·mT,HÉæ€~(EÅ9#Q@ fëlŸµ=ËÊ! …Ȭ¶ò-î#(š2¨!Ió@¶Ý ÂV0 Áý­n` 9ÆÀÉÐ ™ºÑ¢ [—{KHâ¨ýBÎôOŠKކâ[µp+³Ì[`WEë-›ŽY- H’[ïÞªb¡‚ÌDI;&¤Q˜ÀEQäŠ(Äté’º“î9ôàqãɨ C*•WsÄÒª"c7™,DÁ Ì¶Üì@ù¦Æ@rÅLh ¦@] LQ‘X‚÷îdP’É,<ÿȱP ÐøB&æ Z õP& ˜<ÓûÜcÅ1#Sßâ¤?SÙ$ÀÞµTlf4cÍ'Ð…TnH rŦ8ì)D ÔsF%x"GsºðèqàÀì©Â— žcš¦Á5Í*¶³0#tåÄr?Šbà3*¸ÍJÒÿ˜k÷ ð©n€Ú'æŸÐ{BÒÝ%²Þ*œ}ê FGÀâœ6"ñ €Hó½Ö¡,@-ò8¨¦FÈãïN<šŠ2©UpX÷—Kê”&õïv^*¡¬†ôÝ=„F´­se‹{ˆûÒ]éìtß­îeµ-胯üWeç·ÓÚqÎMû@šæ¿~Ût—{‚ ŠÑÔu-«ÑÒ³µÍqmÛàAä×jõXÚÀ&O„5È@W Úy ÂÕÁp*ʾ;šhrI =èC!ÉýÇ9•æg(Çš ÒÞÐ3X:4™Ÿš6P ³cŠÒË h46ÕPº1:Á¦Hd{ ED†nÇÁ¢H˜ù¨¬å‚Ù:óX¸E‘; P®n-Ç “Oƒ‘îÖZxª…úB¨2Õ‘1·#°ÿµ>H’¨ÒÝÏ1HÓýŽê(3b]î0…H¤é:TêɽԶ(L­¿#É¥¼¢ëZéÆÃ¹ÈÏaÍ{im-ZKP›m?¶«.uèºc­€ʯïRK¾‡T-[¶nÜpX3 éký-¶9\xñ ½C¿SnèDÁS³Ú£Nr—Q¦ê(ù~(`K ¸š·UuQv¯Ü)©aseTžIæƒ2)e§ø+éþaº{$•W>à§;U ••Âߎi€+ðPÊý꣰t=´ :{p8öƒULÚÖ²Z*kÕ$MÅyð Nç_qÕÒÊâ&^MF—¿y:Nšå¶½“±¦¼äŘ0P£ˆÇtUBuÎH=šY’wÏzˆÌˆ%‹)•PzÌpX×!\\'jt9æƒ WÀ\«*øîi¡É$€ ÷¡ ‡'÷ä W™œ Ohl/K{@Í`èÒd~h`Ù@2ÌyŽ)ÿK,- ÐÛUBèÄè˜} ‘ì)»‰ c梳–gdëÍbáDHì)B¹¸·‚@M>G»Yh âª-剃<ÖÂæ^ëe{ŒZgñMmË-ÇHUŸ'¼Pfh ÔPÐÄÚõ#Œ´9õg¶ª; Ù'G½H€’ÀÆØŠ¨Ïe]Š»–V½.’_¥¶%Dk…¹ŸT°ó¨ o€bÇúvh:úÛ`² º¯cûMs\`Ph99ù¤ ~á•°@=ØÇö A[%ÛǸ:ž*)½÷>cE© lFÜÉâ™ÉÍH2æ'À4æ§l—£<¹:+^%m9Æ·LätöU@÷üš”QI™ ŒJ)Ðù »Û ƒÁÚr?Š»=ÛÖú{.© ’Þ?[ ô–ÔÞpÀ˜9©-Æ7’ÏMmn:ÉbÜ]·.Û»ÕYÚ!‚wUã¶ ÉËƒÍ <˜åÿÇÅ]ÑÜzçFÚ¤î*€2'B¢²«2cnÒö˜¬RÞ‹9b7£ýâ…²}Ïí÷HŸ™=ósxðsó@m*-ëW[;“æ½1 ú¬à~ªòðp¡Äò *ûΉòhã¼îX悳¸75,÷4‹$‰âx5FЊˆ¶¤“ÃËPg11ø4 ±ˆ1Þ‹LSöª€ˆ.ÀÉ:í ™> Pˤvu9"t4OdÛ|Ä‹iíÙí®õ†,èHçâŠ"˜Ù=Ϫ1K¶Ö2R{οŠXuö2OôäÄž>k)!8‚wÄTPd yb`Ï5°¹—ºÙ^ã™üS[rËqÒggÉïšÈ4[CkÔŽ2ÐçÔvžÚ¨ì+dLõ FKb*£=•v*îYXD ôºI~–Ú@•A®æ}RÃ΢¼V‹éÙ ëëm‚È‚èb½í5Íq€U@} äçæ5û†VÁ÷cÚl—lKàêx¨¦÷Üú@U¦@-±r7'Šg$h?5 ˘ŸÐSš²\zŒòäèx­x•´äsÝ3‘ÓÙUÜòhQDe&vf‚1(H§Cæ‚ïl6SiÈ@8þ("ì÷o[é캤‚KxüUnƒÒ[SyÃ`椷ÞK=5µ¸ë%‹pvÜh»nïUd h„B ÝTsŒZØ+'.40Lòc—ÿwGqëœj“¸¨È Š,énØ·°[©«—æ>ÂªŠŠ¹bÞuAžà¶¡@‰&;P"©ô˜1P@ˆð*‰"I<®¢—Ó,CL~ŸšGéÿÌuInããk¡ÜÕF·ƒ Ž-±ÁªS)wü §êzfé¬ÚµÓZv ?Wæ¤Èöî0¸XÜb¢š}ØhäI¥KVñ¬ÁГ³6> dOšƒlË@#šKu Ëh€?{öHDH #šÀŸE@*K 11A…»s¶ ÄêˆÀËæY  v, V‡m–ÁPó ÉÇäö®fêl(—Û]»*“?o£\[}:é PÌ;ë-€ª¶­°KK¨A Ô?á‡;—®eFŒIÖ€¯ImäRAPǽrÝ«CñI~àéÖÊçý5p«Y³eíàK‚}Ìg½@ v Ó•BÊ$åªwöª!| ¬¤eÇÔ r1ã½ óŽÜS¤¢›…1v³3ª(* ‰ #±=èåÁb'KSIrÎNɱ‚K¸yø T—nÞŒÖfU"u:¬~(¢ ½[HÒ/šRI2I3â²17)’ÚŠÀb§Oo­Œ`L±ç½{€(µi3¸tk J‡+ä;!Ò´áÑqžýÍ*!yÙ€LÕBÉ+…cÇÚŸ#&Êc*& РÀ±¸ÅGQ@ÚBÀ‚û'¸¬Qša¤0ˆ=«I6t&¶d‘ ÆäЍ,énØ·°[©«—æ>ÂªŠŠ¹bÞuAžà¶¡@‰&;TR*ŸIƒ¨’$“Êê)}2Ä1dÇáyù¤~ŸüÇT–î>6±:ÍTkx0¸âÐ`¨õ2—|; ~§¦nšÍ«]5§`Óõp>jLnã …À&*)§ÝˆöŽDšTµošÌ 0+0#cêDù H6Ì´9 ·P̶ˆ÷¿aT„@D€ ’9¬ ôT x°Ó[·;bÜN¨Œ ¾e˜÷ñJbÊ`vÐlU2 œ~Ojæn¦Áb‰qµÛ²©3ñ1Fú5Å·Ó®• ðñ^²Ø «jÛ´º„ÍAÃþs¹zàFThÄh ô–ÞE$ {Ñ -Ú´?—î`®q?ÓQ§ µ›6^Þ¸'ÜÆ{Ôb ÐÙÝ9T, òNZ§qoj¢ÀªÊX»éÖ¹–Ý`·mæå­É×< v!m®+;ÔzŒmÙw$·üÔUX’˜È˜ÜR[{ª iµ¶.9“Z:‹ªnž‘aŒ‰p¦+§¡±q÷¹Ü#KûG‰ªŠdëxº^=EИTñ\îÖÞ×®¯qîð̇šõz{NÁ˜ÀÅxaÿÚ¼ÁuÖze6Ŷ’qÖ¦¢¥é ÇrO›À*Ûq͹“le5Å\ÙÇÕ(UQƒuÜë|QƒÞµÄK\r} óAƒ(8éî°½¾ô3,˜Êg[ª;„¶GÞ‘WäÓ‘Ž8º €=È=ªÖ:¯M$ “ÆÏGPÁî)vÜ(â›@sÜÍŸ¬ºW °SûGšæ$“=·C1ëÔ$÷Ûfi_—ñUŠM²àmާŠV¦DÿÓºgp-¬dDkÒ5Ì' Aíê(=чý±TqéY$Ö·mî÷ÕØ3ê å Ï ÄóU ‰ŠfvÀ"”qðS¯ÜÞ*`›ìBŽÝ?…‡»ÔOy­ZP=¨cŸ&‚ªg3ˆîh¹« æLE ¶ÅŽ­,•»s‘1âkYó æN¾(6*<˜¬ 7±X sOšÚÛ>É“É'“A-’œ ’EIv oæ+ DóLÌbkâ7S 3¦LA“QL°WÚitÏ„äØö¦! >aI˜ƒÚƒ*ÙéÊ›–=ÍT5¨[ ¡?÷ K’“ð(Œ[ÙÃf{ŠP™)9·ÜÏ?jŠ»éÖ¹–Ý`·mæå­É×< v!m®+;ÔzŒmÙw$·üÐU‰)Œ‰Å%°÷º –˜Û[`ã™5£¨º¦ééÈ— bºz_{‘Â4¿´xš¨¦N·‹¥ãÔ] €õOÎímízê÷ï Àhy¯W§´ìŒ W†ý«Ì]g¦Sl[i'jj*^ Üw$ðì)°|­°GÐk™0ÆPc\P…Íœ}Q€…Uðh0']ηÅØ=ë\@TµÇ GÒ42ƒŽžá; ÛïAÃ2ÉŒ¦uº£±HKaTxéqM9àP‹ È܃ڭcªôÒJ )íà¶A ÃÉmîƒ>¶™þõP f ú{Ñ(¸É^ò>ôÃPHÊ>)L´â<ø¨¥À9Õ²XžAYíÛE_VåÂIúTóT̘ÅŽbiQQ=Øï·z¨æ|,î¨ò2P¤Š*¨P\dR[ÊöûÑy$Nñ⢂(Y$“q»v•ˆE-?Þ¶6Ën\8šÆÒ}^³¦wºoômÉc“ ŒÑ´ŠÜ{y1<·ŠM;’¤°_Š¡KŽL¬5½P¯qÐâ`ö¥°5_Ô?¸™¤[=KtÉt2æäâ„D ¬¡Eç²H/ÉHïUIpI9æh,úsÚháí€ÐO$ Fd´Œå‚¨å›‘iBÁKez›½C„)l/´’'~)S©|¥Ó^aÌâ?ä×_Afå»n€¬î^'.õåæQqÚ%—\Tî„Ôÿ2nÜ{8ûWu¬¯2B†|Wut"ÊÛS÷w¨©1ITªD F§æ³bÙ'˜S†Ú c1.fƒx&w1@'´–O`)‹Æ‚’#°¢$dý¢ªijOon襋EŒ‚ùÙ¥´F;$’IŸÍ1_vY“<ÍE8d™ÀGoµ#31>Õ¸ãuŽ=þO4¶ðíÞ¡Ô¨{Jè81ç{®„'…Ùþk*CNF š¨ô‚‹¬Î¾Ûc‚Üš£„A$•FÔ÷5À½Uà°ªF‡Š•ë¯pÎXž7ÅHµÓÔõÃf׶ߟÝ\6Ðvã‚Kq>)íà¶A ÃÉmîƒ>¶™þõP f ú{Ñ(¸É^ò>ôÃPHÊ>)L´â<ø¨¥À9Õ²XžAYíÛE_VåÂIúTóT̘ÅŽbiQQ=Øï·z¨æ|,î¨ò2P¤Š*¨P\dR[ÊöûÑy$Nñ⢂(Y$“q»v•ˆE-?Þ¶6Ën\8šÆÒ}^³¦wºoômÉc“ ŒÑ´ŠÜ{y1<·ŠM;’¤°_Š¡KŽL¬5½P¯qÐâ`ö¥°5_Ô?¸™¤[=KtÉt2æäâ„D ¬¡Eç²H/ÉHïUP…Ü÷¥w-¨“P!QCƒºÊ¢²µÌf3Tÿ“@ÊŽë‘!WÿwH#d+]c¡@|Õ\¡ !Gj[èâ‡SÀïA’Ù©'#ãµDÙ~ÜP/€(¼ óÉ¥ôÜúŒH;ÐPÈAŽFÍ`Z vyjpél€ž|Ð’Nê)I¹væ6öcm:Z`B«±&Zy¬€¸t/µì?wæ‹Yic &cUq?¨µ< )mÛ‹¢ã6À «ªå1Qd%N4gL)À–c‘h¥u gžP¸:~³©2xdñF×A{¨Qwª|Wœ$Àÿ½5‹g¨ÿE3éôè ž í^ª#»F•&Y›ÅZGôVí'é]¸4:ì *õØnžÕ’×Ã7s&»’ý•Ì-ÀÄ+›§{Vo]{¿¨÷"cŠƒ z‡ÜtjFÚ¿UÒÛ>à\öÿEtõoníÑsÓE§Z©‚ìÏé®*?UGªÈálb¿õRºª.w :Ë÷W%¾²ôD&‡1Q{—z‹Ì ã÷MHµÑw¨wµn8^Z¹æè lóâ)ñ–$ûˆÔÏ5‚¢œˆ“þÔ âZ|S¯?ÿ4€!-+ÉíªV¤Ä( \Ãĉæ„1Y% wâi•-ú›A€‘³LU]¶ax XÒ-¡ãã½+–r}6UOêj£º äöR Viº¾a*¢JÂݲ×OrP%Å Yై‰5@팪b;H@2\" ö e(PHÏzWp"Ú‰1ÅÕt8; ,ª++\Æc5Où4 ¨î¹÷t‚6BµÖ:4ÍUÊrv¥·þŽ(qU<ô- ’r>;Q„M‘'íÅø‹Àß<š_IÝϨÁ‰½õ ”älÖ §g–§–Ì(‰çÍ $›—ncof6Ó¥¦„*»e§šÈ ‡BøÛ^Ã÷~h¹‘P:f5Qqú‰×ûSÀÁØ–ݸº.3l º®QBTásFtœ f9ŠWP–yàEkƒ§é :“'€&Omtº…z§ÅyÂLûÓX¶zñS>ŸN€™àžÕê¢;´iRe™¼U¤q/EnÒ~•Ûƒ@ƒ¡®ÀÒ¯Q†éíY-qL3q÷2k¹/Ù\ÂÜ A⹺wµfõ×»úqò&8¨9¤3,HÏâ²”ÁRäÑgÌ,4ÁUWP\÷ P@B2b`˜¬¨KF_oÿimŸP³/кüÕ†#góA°USX÷<ÐEs9'lR3’Ø) ?{xÈ€ªmƧE¨6#7XZ.ñÿV«Ç÷@ø€©`'#¿jn€£jiäÅ:&µÈ,Ü/Š’@~àшPÄ-»däO4°öžü4Éh#z—}ÍûAàRÜcé ÜÔVP™$±¬@Ä’GŽiÒÜ ˆXüŸµMšÐ0VGe‰ §Gí¼íŽî€gä+Òu bãÜ00öÍy–ДËÒkpu'cñE܈n³ ˆ=¦‚v‘ͼdmÏ'íM‚Ì–2<Ó\!-„š_NB+¹ ïâª&–’àä/e¬ä'`+’&5°Êf"¢” *TòÝé€[i‚‚;±=éCûHTãs©7qbX[>æË€<8fŲI“&g·j ¸¬GÚŽ0YV  ±üÐ U€´P{¨ª2aæ±¶ 2y ÿ5T[]?‚ÞL LÝì†3Åõ$Åæîrú¨ ã; j95PñÐPX2ìÁÖÿš¢ZœÜ3qÈÐ'ŠPÒ°ÛiÔR/¾{{@Ы@HЀ9¡l*— ³@©¢Tæ€ÈfX ŸÅ!e)‚¤É¢2ϘXþi‚ª® ¹ï@ €„*dÄÁ1YP–Œ0,¾ßþÒÛ>¡f_¡uùª$# FÏæƒ`ª¦ ±îy ŠærN>ؤg%°R~öð)‘U 2ÛN‹PlG n°´2,]ãþ­V!îð)RÀ.NG~Ô ÝG:ÕÓÉŠtLkY¸_$€ýÁ£*¡ˆ[vÉÈ$žh aí=ùi’ÐFõ.û›öƒÀ¥¸ÇÓ @'¹¨¬ 02IcX‰$Ó¥¸@ ±ù?j›5 `¬ŽËANÛyÛÝÏÈW¤êÅǸ`aíšó-¡)—¤ÖàêNÇ⋹!Ýf{Mí#›xÈÛžOÚ› ™,dy¦¸B[9?4¾œ„WrAÞ#ÅTÿÙlua-lgi-0.7.2/samples/gtk-demo/demo-application.lua000066400000000000000000000201541221440706400221570ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local GdkPixbuf = lgi.GdkPixbuf -- Register icon. Gtk.stock_add { Gtk.StockItem { stock_id = 'demo-gtk-logo', label = "_GTK!", } } local logo_pixbuf = GdkPixbuf.Pixbuf.new_from_file( dir:get_child('gtk-logo-rgb.gif'):get_path()) logo_pixbuf = logo_pixbuf and logo_pixbuf:add_alpha(true, 0xff, 0xff, 0xff) local icon_factory = Gtk.IconFactory() icon_factory:add_default() icon_factory:add('demo-gtk-logo', Gtk.IconSet.new_from_pixbuf(logo_pixbuf)) local window = Gtk.Window { title = "Application Window", icon_name = 'document-open', default_width = 200, default_height = 200, } local function activate_action(action) local dialog = Gtk.MessageDialog { transient_for = window, destroy_with_parent = true, message_type = 'INFO', buttons = 'CLOSE', text = ("You activated action: '%s' of type '%s'"):format( action.name, GObject.Type.name(action._type)), on_response = Gtk.Widget.destroy } dialog:show() end local message_label = Gtk.Label() message_label:show() local function change_radio_action(action) if action.active then message_label.label = (("You activated radio action: '%s' of type '%s'." .."\nCurrent value: %d"):format( action.name, GObject.Type.name(action._type), action.value)) window.child.infobar.message_type = action.value window.child.infobar:show() end end local function set_theme(action) local settings = Gtk.Settings.get_default() settings.gtk_application_prefer_dark_theme = action.active end local function about_cb() local about = Gtk.AboutDialog { program_name = "GTK+ Lgi Code Demos", version = ("Running against GTK+ %d.%d.%d, Lgi %s"):format( Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version(), lgi._VERSION), copyright = "(C) 2012 Pavel Holejsovsky", license_type = 'MIT_X11', website = 'http://github.org/pavouk/lgi', comments = "Port of original GTK+ demo, (C) 1997-2009 The GTK+ Team", authors = { "Pavel Holejsovsky", "Peter Mattis", "Spencer Kimball", "Josh MacDonald", "and many more...", }, documenters = { "Owen Taylor", "Tony Gale", "Matthias Clasen ", "and many more...", }, logo = logo_pixbuf, title = "About GTK+ Code Demos", } about:run() about:hide() end local color = { RED = 1, GREEN = 2, BLUE = 3 } local shape = { SQUARE = 1, RECTANGLE = 2, OVAL = 3 } local action_group = Gtk.ActionGroup { name = 'AppWindowActions', Gtk.Action { name = 'FileMenu', label = "_File" }, Gtk.Action { name = 'OpenMenu', label = "_Open" }, Gtk.Action { name = 'PreferencesMenu', label = "_Preferences" }, Gtk.Action { name = 'ColorMenu', label = "_Color" }, Gtk.Action { name = 'ShapeMenu', label = "_Shape" }, Gtk.Action { name = 'HelpMenu', label = "_Help" }, { Gtk.Action { name = 'New', label = "_New", stock_id = Gtk.STOCK_NEW, tooltip = "Create a new file", on_activate = activate_action }, accelerator = 'N' }, Gtk.Action { name = 'File1', label = "File1", tooltip = "Open first file", on_activate = activate_action }, Gtk.Action { name = 'Open', label = "_Open", stock_id = Gtk.STOCK_OPEN, tooltip = "Open a file", on_activate = activate_action }, Gtk.Action { name = 'File1', label = "File1", tooltip = "Open first file", on_activate = activate_action }, { Gtk.Action { name = 'Save', label = "_Save", tooltip = "Save current file", stock_id = Gtk.STOCK_SAVE, on_activate = activate_action }, accelerator = 'S' }, Gtk.Action { name = 'SaveAs', label = "Save _As", tooltip = "Save to a file", stock_id = Gtk.STOCK_SAVE, on_activate = activate_action }, { Gtk.Action { name = 'Quit', label = "_Quit", tooltip = "Quit", stock_id = Gtk.STOCK_QUIT, on_activate = activate_action }, accelerator = 'Q' }, Gtk.Action { name = 'About', label = "_About", tooltip = "About", on_activate = about_cb }, Gtk.Action { name = 'Logo', stock_id = 'demo-gtk-logo', tooltip = "GTK+ on LGI", on_activate = activate_action }, { Gtk.ToggleAction { name = 'Bold', stock_id = Gtk.STOCK_BOLD, label = "_Bold", tooltip = "Bold", on_activate = activate_action, active = true }, accelerator = 'B' }, Gtk.ToggleAction { name = 'DarkTheme', label = "_Prefer dark theme", tooltip = "Prefer dark theme", active = false, on_activate = set_theme }, { { Gtk.RadioAction { name = 'Red', label = "_Red", tooltip = "Blood", value = color.RED, }, accelerator = 'R' }, { Gtk.RadioAction { name = 'Green', label = "_Green", tooltip = "Grass", value = color.GREEN, }, accelerator = 'G' }, { Gtk.RadioAction { name = 'Blue', label = "_Blue", tooltip = "Sky", value = color.BLUE, }, accelerator = 'B' }, on_change = change_radio_action, }, { { Gtk.RadioAction { name = 'Square', label = "_Square", tooltip = "Square", value = shape.SQUARE, }, accelerator = 'S' }, { Gtk.RadioAction { name = 'Rectangle', label = "_Rectangle", tooltip = "Rectangle", value = shape.RECTANGLE, }, accelerator = 'R' }, { Gtk.RadioAction { name = 'Oval', label = "_Oval", tooltip = "Oval", value = shape.OVAL, }, accelerator = 'O' }, on_change = change_radio_action, }, } local merge = Gtk.UIManager {} merge:insert_action_group (action_group, 0) window:add_accel_group(merge:get_accel_group()) assert(merge:add_ui_from_string([[ ]], -1)) local menubar = merge:get_widget('/MenuBar') menubar.halign = 'FILL' local toolbar = merge:get_widget('/ToolBar') toolbar.halign = 'FILL' window.child = Gtk.Grid { orientation = 'VERTICAL', menubar, toolbar, Gtk.InfoBar { id = 'infobar', no_show_all = true, halign = 'FILL', on_response = Gtk.Widget.hide }, Gtk.ScrolledWindow { shadow_type = 'IN', halign = 'FILL', valign = 'FILL', expand = true, Gtk.TextView { id = 'view', }, }, Gtk.Statusbar { id = 'statusbar', halign = 'FILL', }, } local buffer = window.child.view.buffer local statusbar = window.child.statusbar -- Updates statusbar according to the buffer of the view local function update_statusbar() statusbar:pop(0) local iter = buffer:get_iter_at_mark(buffer:get_insert()) local msg = statusbar:push( 0, ("Cursor at row %d column %d - %d chars in document"):format( iter:get_line(), iter:get_line_offset(), buffer:get_char_count())) end function buffer:on_changed() update_statusbar() end function buffer:on_mark_set() update_statusbar() end -- Perform initial statusbar update. update_statusbar() -- Add infobar area. local info_area = window.child.infobar:get_content_area() info_area:add(message_label) window.child.infobar:add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) window:show_all() window.child.view:grab_focus() return window end, "Application main window", [[Demonstrates a typical application window with menubar, toolbar, statusbar.]] lua-lgi-0.7.2/samples/gtk-demo/demo-assistant.lua000066400000000000000000000042471221440706400216720ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local Gtk = lgi.Gtk local assistant = Gtk.Assistant { default_height = 300, { title = "Page 1", type = 'INTRO', Gtk.Grid { id = 'page1', orientation = 'HORIZONTAL', Gtk.Label { label = "You must fill out this entry to continue:" }, Gtk.Entry { vexpand = true, id = 'entry', activates_default = true, }, }, }, { title = "Page 2", complete = true, Gtk.Grid { orientation = 'VERTICAL', Gtk.CheckButton { label = "This is optional data, you may continue " .. "even if you do not check this" } }, }, { title = "Confirmation", type = 'CONFIRM', complete = true, Gtk.Label { label = "This is a confirmation page, press 'Apply' " .. "to apply changes" }, }, { title = "Applying changes", type = 'PROGRESS', Gtk.ProgressBar { id = 'progressbar', halign = 'CENTER', valign = 'CENTER' }, }, } function assistant.child.entry:on_changed() assistant.property.page1.complete = (self.text ~= '') end function assistant:on_cancel() self:destroy() end function assistant:on_close() self:destroy() end function assistant:on_prepare() self.title = ("Sample assistant (%d of %d)"):format( self:get_current_page() + 1, self:get_n_pages()) if self:get_current_page() == 3 then -- The changes are permanent and cannot be revisited. assistant:commit() end end local progressbar = assistant.child.progressbar function assistant:on_apply() GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, function() -- Simulate work. local fraction = progressbar.fraction + 0.05 if fraction < 1 then progressbar.fraction = fraction return true else assistant:destroy() return false end end) end assistant.child.page1:show_all() --assistant:set_screen(parent:get_screen()) assistant:show_all() return assistant end, "Assistant", table.concat { "Demonstrates a sample multi-step assistant.\n", "Assistants are used to divide an operation into several simpler ", "sequential steps, and to guide the user through these steps." } lua-lgi-0.7.2/samples/gtk-demo/demo-builder.lua000066400000000000000000000011131221440706400212740ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local builder = Gtk.Builder() assert(builder:add_from_file(dir:get_child('demo.ui'):get_path())) local ui = builder.objects -- Get top-level window from the builder. local window = ui.window1 -- Connect 'Quit' and 'About' actions. function ui.Quit:on_activate() window:destroy() end function ui.About:on_activate() ui.aboutdialog1:run() ui.aboutdialog1:hide() end window:show_all() return window end, "Builder", table.concat { [[Demonstrates an interface loaded from a XML description.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-buttonboxes.lua000066400000000000000000000026321221440706400222310ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local function create_bbox(orientation, title, spacing, layout) return Gtk.Frame { label = title, Gtk.ButtonBox { orientation = orientation, border_width = 5, layout_style = layout, spacing = spacing, Gtk.Button { use_stock = true, label = Gtk.STOCK_OK }, Gtk.Button { use_stock = true, label = Gtk.STOCK_CANCEL }, Gtk.Button { use_stock = true, label = Gtk.STOCK_HELP } }, } end local window = Gtk.Window { title = "Button Boxes", border_width = 10, Gtk.Box { orientation = 'VERTICAL', Gtk.Frame { label = "Horizontal Button Boxes", Gtk.Box { orientation = 'VERTICAL', border_width = 10, create_bbox('HORIZONTAL', "Spread", 40, 'SPREAD'), create_bbox('HORIZONTAL', "Edge", 40, 'EDGE'), create_bbox('HORIZONTAL', "Start", 40, 'START'), create_bbox('HORIZONTAL', "End", 40, 'END') }, }, Gtk.Frame { label = "Vertical Button Boxes", Gtk.Box { orientation = 'HORIZONTAL', border_width = 10, create_bbox('VERTICAL', "Spread", 30, 'SPREAD'), create_bbox('VERTICAL', "Edge", 30, 'EDGE'), create_bbox('VERTICAL', "Start", 30, 'START'), create_bbox('VERTICAL', "End", 30, 'END') }, }, } } window:show_all() return window end, "Button Boxes", "The Button Box widgets are used to arrange buttons with padding." lua-lgi-0.7.2/samples/gtk-demo/demo-changedisplay.lua000066400000000000000000000201651221440706400224710ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local GObject = lgi.GObject local Gtk = lgi.Gtk local Gdk = lgi.Gdk -- Create main dialog window local window = Gtk.Dialog { title = "Change Screen or Display", transient_for = parent, default_width = 300, default_height = 400, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE }, { "Change", Gtk.ResponseType.OK }, }, } -- Define column names for 'display' model. local DisplayColumn = { NAME = 1, DISPLAY = 2, } -- Define column numbers for 'screens' model. local ScreenColumn = { NUMBER = 1, SCREEN = 2, } -- Add content of the main dialog. window:get_content_area():add( Gtk.Box { orientation = 'VERTICAL', spacing = 5, border_width = 8, Gtk.Frame { label = "Display", Gtk.Box { orientation = 'HORIZONTAL', spacing = 8, border_width = 8, Gtk.ScrolledWindow { shadow_type = 'IN', hscrollbar_policy = 'NEVER', expand = true, Gtk.TreeView { id = 'displays', headers_visible = false, model = Gtk.ListStore.new { [DisplayColumn.NAME] = GObject.Type.STRING, [DisplayColumn.DISPLAY] = Gdk.Display, }, Gtk.TreeViewColumn { title = "Name", { Gtk.CellRendererText(), { text = DisplayColumn.NAME } }, }, }, }, Gtk.Box { id = 'displays_box', orientation = 'VERTICAL', spacing = 5, Gtk.Button { id = 'display_open', label = "_Open...", use_underline = true, }, Gtk.Button { id = 'display_close', label = "Close", use_underline = true, }, }, }, }, Gtk.Frame { label = "Screen", Gtk.Box { orientation = 'HORIZONTAL', spacing = 8, border_width = 8, Gtk.ScrolledWindow { shadow_type = 'IN', hscrollbar_policy = 'NEVER', expand = true, Gtk.TreeView { id = 'screens', headers_visible = false, model = Gtk.ListStore.new { [ScreenColumn.NUMBER] = GObject.Type.INT, [ScreenColumn.SCREEN] = Gdk.Screen, }, Gtk.TreeViewColumn { title = "Number", { Gtk.CellRendererText(), { text = ScreenColumn.NUMBER } }, }, }, }, Gtk.Box { id = 'screens_box', orientation = 'VERTICAL', spacing = 5, }, }, }, }) local current_display, current_screen local display_selection = window.child.displays:get_selection() local screen_selection = window.child.screens:get_selection() display_selection.mode = 'BROWSE' function display_selection:on_changed() local model, iter = self:get_selected() if model then current_display = model[iter][DisplayColumn.DISPLAY] local screens = window.child.screens.model screens:clear() for i = 0, current_display:get_n_screens() - 1 do local iter = screens:append { [ScreenColumn.NUMBER] = i, [ScreenColumn.SCREEN] = current_display:get_screen(i), } if i == 0 then screen_selection:select_iter(iter) end end else current_display = nil end end screen_selection.mode = 'BROWSE' function screen_selection:on_changed() local model, iter = self:get_selected() current_screen = model and model[iter][ScreenColumn.SCREEN] end window.child.display_open:get_child().halign = 'START' window.child.display_close:get_child().halign = 'START' local size_group = Gtk.SizeGroup() size_group:add_widget(window.child.displays_box) size_group:add_widget(window.child.screens_box) function window.child.display_open:on_clicked() local dialog = Gtk.Dialog { title = "Open Display", transient_for = window, modal = true, buttons = { { Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL }, { Gtk.STOCK_OK, Gtk.ResponseType.OK }, }, } dialog:set_default_response(Gtk.ResponseType.OK) local label = Gtk.Label { label = "Please enter the name of\nthe new display\n", } local entry = Gtk.Entry { activates_default = true } local content = dialog:get_content_area() content:add(label) content:add(entry) entry.has_focus = true dialog:show_all() while true do if dialog:run() ~= Gtk.ResponseType.OK then break end local name = entry.text if name ~= '' then local display = Gdk.Display.open(name) if display then break end label.label = ("Can't open display :\n\t%s\n" .. "please try another one\n"):format(name) end end dialog:destroy() end local function change_display() local screen = window:get_screen() local display = screen:get_display() local popup = Gtk.Window { type = 'POPUP', window_position = 'CENTER', modal = true, transient_for = window, Gtk.Frame { shadow_type = 'OUT', Gtk.Label { margin = 10, label = "Please select the toplevel\n" .. "to move to the new screen", }, }, } popup:set_screen(screen) popup:show_all() local cursor = Gdk.Cursor.new_for_display(display, 'CROSSHAIR') local toplevel local device = Gtk.get_current_event_device() local grab_status = device:grab( popup.window, 'APPLICATION', false, 'BUTTON_RELEASE_MASK', cursor, Gdk.CURRENT_TIME) if grab_status == 'SUCCESS' then -- Process events until user clicks. local clicked function popup:on_button_release_event() clicked = true return true end while not clicked do GLib.MainContext.default():iteration(true) end -- Find toplevel at current pointer position. local gdk_window = device:get_window_at_position() local widget = gdk_window and gdk_window:get_widget() toplevel = widget and widget:get_toplevel() if toplevel == popup then toplevel = nil end end popup:destroy() -- Make sure that grab is really broken. Gdk.flush() -- Switch target window to selected screen. if toplevel then toplevel:set_screen(current_screen) else display:beep() end end function window:on_response(response_id) if response_id == Gtk.ResponseType.OK then change_display() else self:destroy() end end -- Adds new display into the list and hooks it do that it is -- automatically removed when the display is closed. local function add_display(display) local store = window.child.displays.model local iter = store:append { [DisplayColumn.NAME] = display:get_name(), [DisplayColumn.DISPLAY] = display, } local path = store:get_path(iter) local handler_id = display.on_closed:connect( function(is_error) store:remove(store:get_iter(path)) end) function window:on_destroy() GObject.signal_handler_disconnect(display, handler_id) end end -- Populate initial list of displays. local display_manager = Gdk.DisplayManager.get() for _, display in ipairs(display_manager:list_displays()) do add_display(display) end local handler_id = display_manager.on_display_opened:connect( function(display) add_display(display) end) function window:on_destroy() GObject.signal_handler_disconnect(display_manager, handler_id) end window:show_all() return window end, "Change Display", table.concat { [[Demonstrates migrating a window between different displays ]], [[and screens. A display is a mouse and keyboard with some number ]], [[of associated monitors. A screen is a set of monitors grouped ]], [[into a single physical work area. The neat thing about having ]], [[multiple displays is that they can be on a completely separate ]], [[computers, as long as there is a network connection to ]], [[the computer where the application is running. ]], [[Only some of the windowing systems where GTK+ runs have the concept ]], [[of multiple displays and screens. (The X Window System is the main ]], [[example.) Other windowing systems can only handle one keyboard ]], [[and mouse, and combine all monitors into a single screen. ]], [[This is a moderately complex example, and demonstrates: - Tracking the currently open displays and screens - Changing the screen for a window - Letting the user choose a window by clicking on it - Using Gtk.ListStore and Gtk.TreeView - Using Gtk.Dialog]] } lua-lgi-0.7.2/samples/gtk-demo/demo-clipboard.lua000066400000000000000000000106241221440706400216140ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local log = lgi.log.domain 'gtk-demo' local function get_image_pixbuf(image) if image.storage_type == 'PIXBUF' then return image.pixbuf elseif image.storage_type == 'STOCK' then return image:render_icon_pixbuf(image.stock, image.icon_size) else log.warning(('Image storage type "%s" not handled'):format( image.storage_type)) end end local function drag_begin(ebox, context) Gtk.drag_set_icon_pixbuf(context, get_image_pixbuf(ebox:get_child()), -2, -2) end local function drag_data_get(ebox, context, selection_data) selection_data:set_pixbuf(get_image_pixbuf(ebox:get_child())) end local function drag_data_received(ebox, context, x, y, selection_data) if selection_data:get_length() > 0 then ebox:get_child().pixbuf = selection_data:get_pixbuf() end end local function button_press(ebox, event_button) if event_button.button ~= 3 then return false end local clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) local image = ebox:get_child() local menu = Gtk.Menu { Gtk.ImageMenuItem { use_stock = true, label = Gtk.STOCK_COPY, on_activate = function() local pixbuf = get_image_pixbuf(image) clipboard:set_image(pixbuf) end }, Gtk.ImageMenuItem { use_stock = true, label = Gtk.STOCK_PASTE, on_activate = function() local pixbuf = clipboard:wait_for_image() if pixbuf then image.pixbuf = pixbuf end end }, } menu:show_all() menu:popup(nil, nil, nil, nil, event_button.button, event_button.time) end local window = Gtk.Window { title = "Clipboard demo", Gtk.Box { orientation = 'VERTICAL', border_width = 8, Gtk.Label { label = "\"Copy\" will copy the text\n" .. "in the entry to the clipboard" }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 4, border_width = 8, Gtk.Entry { id = 'copy_entry', hexpand = true }, Gtk.Button { id = 'copy_button', use_stock = true, label = Gtk.STOCK_COPY }, }, Gtk.Label { label = "\"Paste\" will paste the text from " .. "the clipboard to the entry" }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 4, border_width = 8, Gtk.Entry { id = 'paste_entry', hexpand = true }, Gtk.Button { id = 'paste_button', use_stock = true, label = Gtk.STOCK_PASTE }, }, Gtk.Label { label = "Images can be transferred via the clipboard, too" }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 4, border_width = 8, Gtk.EventBox { id = 'ebox1', on_drag_begin = drag_begin, on_drag_data_get = drag_data_get, on_drag_data_received = drag_data_received, on_button_press_event = button_press, Gtk.Image { stock = Gtk.STOCK_DIALOG_WARNING, icon_size = Gtk.IconSize.BUTTON } }, Gtk.EventBox { id = 'ebox2', on_drag_begin = drag_begin, on_drag_data_get = drag_data_get, on_drag_data_received = drag_data_received, on_button_press_event = button_press, Gtk.Image { stock = Gtk.STOCK_STOP, icon_size = Gtk.IconSize.BUTTON } }, }, } } function window.child.copy_button:on_clicked() local entry = window.child.copy_entry local clipboard = entry:get_clipboard(Gdk.SELECTION_CLIPBOARD) clipboard:set_text(entry.text, -1) end function window.child.paste_button:on_clicked() local entry = window.child.paste_entry local clipboard = entry:get_clipboard(Gdk.SELECTION_CLIPBOARD) clipboard:request_text(function(clipboard, text) if text then entry.text = text end end) end -- Make eboxes drag sources and destinations. for _, ebox in ipairs { window.child.ebox1, window.child.ebox2 } do ebox:drag_source_set('BUTTON1_MASK', nil, 'COPY') ebox:drag_source_add_image_targets() ebox:drag_dest_set('ALL', nil, 'COPY') ebox:drag_dest_add_image_targets(ebox) end -- Tell the clipboard manager to make the data persistent. Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD):set_can_store(nil) window:show_all() return window end, "Clipboard", table.concat { "Gtk.Clipboard is used for clipboard handling. This demo shows how to ", "copy and paste text to and from the clipboard.\n", "It also shows how to transfer images via the clipboard or via ", "drag-and-drop, and how to make clipboard contents persist after ", "the application exits. Clipboard persistence requires a clipboard ", "manager to run." } lua-lgi-0.7.2/samples/gtk-demo/demo-colorselector.lua000066400000000000000000000036371221440706400225420ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local cairo = lgi.cairo local window = Gtk.Window { title = "Color Selection", border_width = 8, Gtk.Box { orientation = 'VERTICAL', spacing = 8, border_width = 8, Gtk.Frame { shadow_type = 'IN', Gtk.DrawingArea { id = 'area', expand = true, width = 200, height = 200, }, }, Gtk.Button { id = 'change', label = "_Change the above color", use_underline = true, halign = 'END', valign = 'CENTER', }, }, } local area = window.child.area area:override_background_color( 0, Gdk.RGBA { red = 0, green = 0, blue = 1, alpha = 1 }) function area:on_draw(cr) cr:set_source_rgba(self.style_context:get_background_color('NORMAL')) cr:paint() return true end function window.child.change:on_clicked() local dialog if Gtk.ColorChooserDialog then dialog = Gtk.ColorChooserDialog { title = "Changing color", transient_for = window, rgba = self.style_context:get_background_color('NORMAL') } function dialog:on_response(response_id) if response_id == Gtk.ResponseType.OK then area:override_background_color(0, self.rgba) end dialog:hide() end else dialog = Gtk.ColorSelectionDialog { title = "Changing color", transient_for = window, } dialog.color_selection.current_rgba = self.style_context:get_background_color('NORMAL') function dialog:on_response(response_id) if response_id == Gtk.ResponseType.OK then area:override_background_color( 0, self.color_selection.current_rgba) end dialog:hide() end end dialog:show_all() end window:show_all() return window end, "Color Selector", table.concat { [[Gtk.ColorSelection lets the user choose a color. ]], [[Gtk.ColorSelectionDialog is a prebuilt dialog containing ]], [[a Gtk.ColorSelection.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-comboboxes.lua000066400000000000000000000121011221440706400220050ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local Gdk = lgi.Gdk local GdkPixbuf = lgi.GdkPixbuf local ComboColumn = { PIXBUF = 1, TEXT = 2, } local function create_stock_icon_store() local cellview = Gtk.CellView {} local store = Gtk.ListStore.new { [ComboColumn.PIXBUF] = GdkPixbuf.Pixbuf, [ComboColumn.TEXT] = GObject.Type.STRING } for _, stock in ipairs { Gtk.STOCK_DIALOG_WARNING, Gtk.STOCK_STOP, Gtk.STOCK_NEW, Gtk.STOCK_CLEAR, '', Gtk.STOCK_OPEN, } do if stock ~= '' then store:append { [ComboColumn.PIXBUF] = cellview:render_icon_pixbuf( stock, Gtk.IconSize.BUTTON), [ComboColumn.TEXT] = Gtk.stock_lookup(stock).label:gsub('_', '') } else store:append { [ComboColumn.TEXT] = 'separator' } end end return store end local function set_sensitive(layout, cell, model, iter) local indices = model:get_path(iter):get_indices() cell.sensitive = (indices[1] ~= 1) end local function create_capital_store() local store = Gtk.TreeStore.new { GObject.Type.STRING } for _, group in ipairs { { name = "A - B", "Albany", "Annapolis", "Atlanta", "Augusta", "Austin", "Baton Rouge", "Bismarck", "Boise", "Boston" }, { name = "C - D", "Carson City", "Charleston", "Cheyenne", "Columbia", "Columbus", "Concord", "Denver", "Des Moines", "Dover" }, { name = "E - J", "Frankfort", "Harrisburg", "Hartford", "Helena", "Honolulu", "Indianapolis", "Jackson", "Jefferson City", "Juneau" }, { name = "K - O", "Lansing", "Lincoln", "Little Rock", "Madison", "Montgomery", "Montpelier", "Nashville", "Oklahoma City", "Olympia" }, { name = "P - S", "Phoenix", "Pierre", "Providence", "Raleigh", "Richmond", "Sacramento", "Salem", "Salt Lake City", "Santa Fe", "Springfield", "St. Paul" }, { name = "T - Z", "Tallahassee", "Topeka", "Trenton" }, } do local gi = store:append(nil, { [1] = group.name }) for _, city in ipairs(group) do store:append(gi, { [1] = city }) end end return store end local function is_capital_sensitive(layout, cell, model, iter) cell.sensitive = not model:iter_has_child(iter) end local window = Gtk.Window { title = "Combo boxes", border_width = 10, Gtk.Box { orientation = 'VERTICAL', spacing = 10, Gtk.Frame { label = "Some stock icons", Gtk.Box { orientation = 'VERTICAL', border_width = 5, Gtk.ComboBox { id = 'icons', model = create_stock_icon_store(), active = 0, cells = { { Gtk.CellRendererPixbuf(), { pixbuf = ComboColumn.PIXBUF }, align = 'start', data_func = set_sensitive, }, { Gtk.CellRendererText(), { text = ComboColumn.TEXT }, align = 'start', data_func = set_sensitive, }, }, }, }, }, Gtk.Frame { label = "Where are we?", Gtk.Box { orientation = 'VERTICAL', border_width = 5, Gtk.ComboBox { id = 'capitals', model = create_capital_store(), cells = { { Gtk.CellRendererText(), { text = 1 }, align = 'start', data_func = is_capital_sensitive, } } }, }, }, Gtk.Frame { label = "Editable", Gtk.Box { orientation = 'VERTICAL', border_width = 5, Gtk.ComboBoxText { id = 'entry', has_entry = true, entry_text_column = 0, }, }, }, Gtk.Frame { label = "String IDs", Gtk.Box { orientation = 'VERTICAL', border_width = 5, Gtk.ComboBoxText { id = 'stringids', entry_text_column = 0, id_column = 1, }, Gtk.Entry { id = 'ids_entry' }, }, }, }, } window.child.icons:set_row_separator_func( function(model, iter) return model:get_path(iter):get_indices()[1] == 4 end) local capitals = window.child.capitals capitals:set_active_iter(capitals.model:get_iter( Gtk.TreePath.new_from_string('0:8'))) for _, label in ipairs { "One", "Two", "2½", "Three" } do window.child.entry:append_text(label) end local entry = window.child.entry:get_child() local allowed = { ["One"] = true, ["Two"] = true, ["2½"] = true, ["Three"] = true } function entry:on_changed() local color if not self.text:match('^[0-9]*$') and not allowed[self.text] then color = Gdk.RGBA { red = 1, green = 0.9, blue = 0.9, alpha = 1 } end self:override_color(0, color) end for id, text in pairs { never = "Not visible", when_active = "Visible when active", always = "Always visible", } do window.child.stringids:append(id, text) end window.child.stringids:bind_property( 'active-id', window.child.ids_entry, 'text', 'BIDIRECTIONAL') window:show_all() return window end, "Combo boxes", table.concat { "The ComboBox widget allows to select one option out of a list. ", "The ComboBoxEntry additionally allows the user to enter a value ", "that is not in the list of options.\n", "How the options are displayed is controlled by cell renderers.", } lua-lgi-0.7.2/samples/gtk-demo/demo-dialogs.lua000066400000000000000000000065731221440706400213070ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local Gdk = lgi.Gdk local GdkPixbuf = lgi.GdkPixbuf local window = Gtk.Window { title = "Dialogs", border_width = 8, Gtk.Frame { label = "Dialogs", Gtk.Box { orientation = 'VERTICAL', border_width = 8, spacing = 8, Gtk.Box { orientation = 'HORIZONTAL', spacing = 8, Gtk.Button { id = 'message_button', label = "_Message Dialog", use_underline = true, }, }, Gtk.Separator { orientation = 'HORIZONTAL' }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 8, Gtk.Box { orientation = 'VERTICAL', Gtk.Button { id = 'interactive_button', label = "_Interactive Dialog", use_underline = true, }, }, Gtk.Grid { row_spacing = 4, column_spacing = 4, { left_attach = 0, top_attach = 0, Gtk.Label { label = "_Entry 1", use_underline = true, }, }, { left_attach = 1, top_attach = 0, Gtk.Entry { id = 'entry1', }, }, { left_attach = 0, top_attach = 1, Gtk.Label { label = "E_ntry 2", use_underline = true, }, }, { left_attach = 1, top_attach = 1, Gtk.Entry { id = 'entry2', }, }, }, }, }, }, } local popup_count = 1 function window.child.message_button:on_clicked() local dialog = Gtk.MessageDialog { transient_for = window, modal = true, destroy_with_parent = true, message_type = 'INFO', buttons = 'OK', text = "This message box has been popped up the following\n" .. "number of times:", secondary_text = ('%d'):format(popup_count), } dialog:run() dialog:destroy() popup_count = popup_count + 1 end function window.child.interactive_button:on_clicked() local dialog = Gtk.Dialog { title = "Interactive Dialog", transient_for = window, modal = true, destroy_with_parent = true, buttons = { { Gtk.STOCK_OK, Gtk.ResponseType.OK }, { "_Non-stock Button", Gtk.ResponseType.CANCEL }, }, } local hbox = Gtk.Box { orientation = 'HORIZONTAL', spacing = 8, border_width = 8, Gtk.Image { stock = Gtk.STOCK_DIALOG_QUESTION, icon_size = Gtk.IconSize.DIALOG, }, Gtk.Grid { row_spacing = 4, column_spacing = 4, { left_attach = 0, top_attach = 0, Gtk.Label { label = "_Entry 1", use_underline = true, }, }, { left_attach = 1, top_attach = 0, Gtk.Entry { id = 'entry1', text = window.child.entry1.text, }, }, { left_attach = 0, top_attach = 1, Gtk.Label { label = "E_ntry 2", use_underline = true, }, }, { left_attach = 1, top_attach = 1, Gtk.Entry { id = 'entry2', text = window.child.entry2.text, }, }, } } dialog:get_content_area():add(hbox) hbox:show_all() if dialog:run() == Gtk.ResponseType.OK then window.child.entry1.text = hbox.child.entry1.text window.child.entry2.text = hbox.child.entry2.text end dialog:destroy() end window:show_all() return window end, "Dialog and Message Boxes", table.concat { "Dialog widgets are used to pop up a transient window for user feedback.", } lua-lgi-0.7.2/samples/gtk-demo/demo-drawingarea.lua000066400000000000000000000100411221440706400221320ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local cairo = lgi.cairo local window = Gtk.Window { title = "Drawing Area", border_width = 8, Gtk.Box { orientation = 'VERTICAL', spacing = 8, border_width = 8, Gtk.Label { use_markup = true, label = "Checkerboard pattern", }, Gtk.Frame { shadow_type = 'IN', expand = true, Gtk.DrawingArea { id = 'checkerboard', width = 100, height = 100, }, }, Gtk.Label { use_markup = true, label = "Scribble area", }, Gtk.Frame { shadow_type = 'IN', expand = true, Gtk.DrawingArea { id = 'scribble', width = 100, height = 100, }, }, }, } -- Handling of checkerboard area. local SPACING = 2 local CHECK_SIZE = 10 function window.child.checkerboard:on_draw(cr) local i = SPACING local xcount = 0 while i < self.width do local j = SPACING local ycount = xcount % 2 while j < self.height do if ycount % 2 ~= 0 then cr:set_source_rgb(0.45777, 0, 0.45777) else cr:set_source_rgb(1, 1, 1) end cr:rectangle(i, j, CHECK_SIZE, CHECK_SIZE) cr:fill() j = j + CHECK_SIZE + SPACING ycount = ycount + 1 end i = i + CHECK_SIZE + SPACING xcount = xcount + 1 end return true end -- Setup and handling of scribble area. local scribble = window.child.scribble local surface function scribble:on_configure_event(event) -- Create new surface of appropriate size to store the scribbles. local allocation = self.allocation surface = self.window:create_similar_surface( 'COLOR', allocation.width, allocation.height) -- Initialize the surface to white. local cr = cairo.Context.create(surface) cr:set_source_rgb(1, 1, 1) cr:paint() return true end function scribble:on_draw(cr) -- Redraw the screen from the buffer. cr:set_source_surface(surface, 0, 0) cr:paint() return true end -- Draw a rectangle on the scribble surface. local function draw_brush(widget, x, y) local update_rect = Gdk.Rectangle { x = x - 3, y = y - 3, width = 6, height = 6 } -- Paint to the scribble surface local cr = cairo.Context(surface) cr:rectangle(update_rect) cr:fill() -- Invalidate affected region of the paint area. widget.window:invalidate_rect(update_rect, false) end function scribble:on_motion_notify_event(event) -- This call is very important; it requests the next motion event. -- If you don't call Gdk.Window.get_pointer() you'll only get -- a single motion event. The reason is that we specified -- Gdk.EventMask.POINTER_MOTION_HINT_MASK to Gtk.Widget.add_events(). -- If we hadn't specified that, we could just use event.x, event.y -- as the pointer location. But we'd also get deluged in events. -- By requesting the next event as we handle the current one, -- we avoid getting a huge number of events faster than we -- can cope. local _, x, y, state = event.window:get_device_position(event.device) if state.BUTTON1_MASK then draw_brush(self, x, y) end return true end function scribble:on_button_press_event(event) if event.button == Gdk.BUTTON_PRIMARY then draw_brush(self, event.x, event.y) end return true end scribble:add_events(Gdk.EventMask { 'LEAVE_NOTIFY_MASK', 'BUTTON_PRESS_MASK', 'POINTER_MOTION_MASK', 'POINTER_MOTION_HINT_MASK' }) window:show_all() return window end, "Drawing Area", table.concat { [[Gtk.DrawingArea is a blank area where you can draw custom displays ]], [[of various kinds. ]], [[This demo has two drawing areas. The checkerboard area shows how ]], [[you can just draw something; all you have to do is write a signal ]], [[handler for expose_event, as shown here. ]], [[The "scribble" area is a bit more advanced, and shows how to handle ]], [[events such as button presses and mouse motion. Click the mouse ]], [[and drag in the scribble area to draw squiggles. Resize the window ]], [[to clear the area.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-entry-buffer.lua000066400000000000000000000014701221440706400222640ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Dialog { title = "Entry Buffer", resizable = false, on_response = Gtk.Widget.destroy, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.NONE }, }, } local buffer = Gtk.EntryBuffer() local content = Gtk.Box { orientation = 'VERTICAL', spacing = 5, border_width = 5, Gtk.Label { label = "Entries share a buffer. " .. "Typing in one is reflected in the other.", use_markup = true, }, Gtk.Entry { buffer = buffer, }, Gtk.Entry { buffer = buffer, visibility = false, }, } window:get_content_area():add(content) window:show_all() return window end, "Entry/Entry Buffer", table.concat { "Gtk.EntryBuffer provides the text content in a Gtk.Entry.", } lua-lgi-0.7.2/samples/gtk-demo/demo-entry-completion.lua000066400000000000000000000020051221440706400231570ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local window = Gtk.Dialog { title = "GtkEntryCompletion", resizable = false, on_response = Gtk.Widget.destroy, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.NONE }, }, } local store = Gtk.ListStore.new { GObject.Type.STRING } for _, name in ipairs { "GNOME", "total", "totally" } do store:append { name } end local content = Gtk.Box { orientation = 'VERTICAL', spacing = 5, border_width = 5, Gtk.Label { label = "Completion demo, try writing total or gnome " .. "for example.", use_markup = true, }, Gtk.Entry { id = 'entry', completion = Gtk.EntryCompletion { model = store, text_column = 0, }, }, } window:get_content_area():add(content) window:show_all() return window end, "Entry/Entry Completion", table.concat { "Gtk.EntryCompletion provides a mechanism for adding support for ", "completion in Gtk.Entry.", } lua-lgi-0.7.2/samples/gtk-demo/demo-entry-search.lua000066400000000000000000000105321221440706400222570ustar00rootroot00000000000000return function(parent, dir) local coroutine = require 'coroutine' local lgi = require 'lgi' local GLib = lgi.GLib local GObject = lgi.GObject local Gtk = lgi.Gtk local window = Gtk.Dialog { title = "Search Entry", resizable = false, on_response = Gtk.Widget.destroy, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.NONE }, }, } local content = Gtk.Box { orientation = 'VERTICAL', spacing = 5, border_width = 5, Gtk.Label { label = "Search entry demo", use_markup = true, }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 10, Gtk.Entry { id = 'entry', secondary_icon_stock = Gtk.STOCK_CLEAR, }, Gtk.Notebook { id = 'buttons', show_tabs = false, show_border = false, Gtk.Button { id = 'button_find', label = "Find", sensitive = false, }, Gtk.Button { id = 'button_cancel', label = "Cancel", }, }, }, } window:get_content_area():add(content) local entry = content.child.entry local search = { { menu = "Search by _name", stock = Gtk.STOCK_FIND, placeholder = "name", tooltip = "Search by name\n" .. "Click here to change the search type", }, { menu = "Search by _description", stock = Gtk.STOCK_EDIT, placeholder = "description", tooltip = "Search by description\n" .. "Click here to change the search type", }, { menu = "Search by _file name", stock = Gtk.STOCK_OPEN, placeholder = "filename", tooltip = "Search by file name\n" .. "Click here to change the search type", }, } local function search_by(method) entry.primary_icon_stock = method.stock entry.primary_icon_tooltip_text = method.tooltip entry.placeholder_text = method.placeholder end search_by(search[1]) local function create_search_menu() local menu = Gtk.Menu { visible = true } for i = 1, #search do menu:append( Gtk.ImageMenuItem { image = Gtk.Image { stock = search[i].stock, icon_size = Gtk.IconSize.MENU }, label = search[i].menu, use_underline = true, visible = true, always_show_image = true, on_activate = function() search_by(search[i]) end, }) end return menu end local menu = create_search_menu() menu:attach_to_widget(entry) function entry:on_populate_popup(menu) for _, item in ipairs { Gtk.SeparatorMenuItem {}, Gtk.MenuItem { label = "C_lear", use_underline = true, visible = true, on_activate = function() entry.text = '' end }, Gtk.MenuItem { label = "Search by", submenu = create_search_menu(), visible = true, }, } do item.visible = true menu:append(item) end end function entry:on_icon_press(position, event) if position == 'PRIMARY' then menu:popup(nil, nil, nil, nil, event.button, event.time) else entry.text = '' end end function entry.on_notify:text(pspec) local has_text = entry.text ~= '' entry.secondary_icon_sensitive = has_text content.child.button_find.sensitive = has_text end local search_progress_id, finish_search_id local function finish_search() content.child.buttons.page = 0 if search_progress_id then GLib.source_remove(search_progress_id) search_progress_id = nil end if finish_search_id then GLib.source_remove(finish_search_id) finish_search_id = nil end entry.progress_fraction = 0 end local function start_search() content.child.buttons.page = 1 search_progress_id = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, function() search_progress_id = GLib.timeout_add( GLib.PRIORITY_DEFAULT, 100, function() entry:progress_pulse() return true end) return false end) finish_search_id = GLib.timeout_add_seconds( GLib.PRIORITY_DEFAULT, 15, finish_search) end function entry:on_activate() if not search_progress_id then start_search() end end function content.child.button_find:on_clicked() start_search() end function content.child.button_cancel:on_clicked() finish_search() end function window:on_destroy() finish_search() end window:show_all() return window end, "Entry/Search Entry", table.concat { "Gtk.Entry allows to display icons and progress information. ", "This demo shows how to use these features in a search entry." } lua-lgi-0.7.2/samples/gtk-demo/demo-expander.lua000066400000000000000000000015071221440706400214630ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Dialog { title = "GtkExpander", transient_for = parent, resizable = false, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.NONE }, }, on_response = Gtk.Widget.destroy, } local content = Gtk.Box { orientation = 'VERTICAL', spacing = 5, border_width = 5, Gtk.Label { label = "Expander demo. Click on the triangle for details.", }, Gtk.Expander { label = "Details", Gtk.Label { label = "Details can be shown or hidden.", } }, } window:get_content_area():add(content) window:show_all() return window end, "Expander", table.concat { [[Gtk.Expander allows to provide additional content that is ]], [[initially hidden. This is also known as "disclosure triangle".]] } lua-lgi-0.7.2/samples/gtk-demo/demo-iconview-basics.lua000066400000000000000000000063721221440706400227470ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local GObject = lgi.GObject local Gio = lgi.Gio local Gtk = lgi.Gtk local GdkPixbuf = lgi.GdkPixbuf local pixbuf = { REGULAR = assert(GdkPixbuf.Pixbuf.new_from_file( dir:get_child('gnome-fs-regular.png'):get_path())), DIRECTORY = assert(GdkPixbuf.Pixbuf.new_from_file( dir:get_child('gnome-fs-directory.png'):get_path())), } local ViewColumn = { PATH = 1, DISPLAY_NAME = 2, PIXBUF = 3, IS_DIRECTORY = 4, } local store = Gtk.ListStore.new { [ViewColumn.PATH] = Gio.File, [ViewColumn.DISPLAY_NAME] = GObject.Type.STRING, [ViewColumn.PIXBUF] = GdkPixbuf.Pixbuf, [ViewColumn.IS_DIRECTORY] = GObject.Type.BOOLEAN, } store:set_default_sort_func( function(model, a, b) -- Sort folders before files. a = model[a] b = model[b] local is_dir_a, is_dir_b = a[ViewColumn.IS_DIRECTORY], b[ViewColumn.IS_DIRECTORY] if not is_dir_a and is_dir_b then return 1 elseif is_dir_a and not is_dir_b then return -1 else return GLib.utf8_collate(a[ViewColumn.DISPLAY_NAME], b[ViewColumn.DISPLAY_NAME]) end end) store:set_sort_column_id(Gtk.TreeSortable.DEFAULT_SORT_COLUMN_ID, 'ASCENDING') local window = Gtk.Window { default_width = 650, default_height = 400, title = "Gtk.IconView demo", Gtk.Box { orientation = 'VERTICAL', Gtk.Toolbar { Gtk.ToolButton { id = 'up_button', stock_id = Gtk.STOCK_GO_UP, is_important = true, sensitive = false, }, Gtk.ToolButton { id = 'home_button', stock_id = Gtk.STOCK_HOME, is_important = true, }, }, Gtk.ScrolledWindow { shadow_type = 'ETCHED_IN', Gtk.IconView { id = 'icon_view', expand = true, selection_mode = 'MULTIPLE', model = store, text_column = ViewColumn.DISPLAY_NAME - 1, pixbuf_column = ViewColumn.PIXBUF - 1, has_focus = true, }, }, }, } local current_dir = Gio.File.new_for_path('/') local function fill_store() store:clear() local enum = current_dir:enumerate_children('standard::*', 'NONE') while true do local info, err = enum:next_file() if not info then assert(not err, err) break end store:append { [ViewColumn.PATH] = current_dir:get_child(info:get_name()), [ViewColumn.DISPLAY_NAME] = info:get_display_name(), [ViewColumn.IS_DIRECTORY] = info:get_file_type() == 'DIRECTORY', [ViewColumn.PIXBUF] = pixbuf[info:get_file_type()], } end window.child.up_button.sensitive = (current_dir:get_parent() ~= nil) end fill_store() function window.child.up_button:on_clicked() current_dir = current_dir:get_parent() fill_store() end function window.child.home_button:on_clicked() current_dir = Gio.File.new_for_path(GLib.get_home_dir()) fill_store() end function window.child.icon_view:on_item_activated(path) local row = store[path] if row[ViewColumn.IS_DIRECTORY] then current_dir = row[ViewColumn.PATH] fill_store() end end window:show_all() return window end, "Icon View/Icon View Basics", table.concat { [[The Gtk.IconView widget is used to display and manipulate icons. ]], [[It uses a Gtk.TreeModel for data storage, so the list store example ]], [[might be helpful.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-iconview-editing.lua000066400000000000000000000032611221440706400231200ustar00rootroot00000000000000return function(parent, dir) local math = require 'math' local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local Gdk = lgi.Gdk local GdkPixbuf = lgi.GdkPixbuf local store = Gtk.ListStore.new { GObject.Type.STRING } for _, name in ipairs { "Red", "Green", "Blue", "Yellow" } do store:append { name } end local function edited(cell, path_string, text) store[Gtk.TreePath.new_from_string(path_string)][1] = text end local function set_cell_color(layout, cell, model, iter) local rgba, pixel = Gdk.RGBA(), 0 local label = model[iter][1] if label and rgba:parse(label) then pixel = math.floor(rgba.red * 255) * (256 * 256 * 256) + math.floor(rgba.green * 255) * (256 * 256) + math.floor(rgba.blue * 255) * 256 end cell.pixbuf = GdkPixbuf.Pixbuf.new('RGB', false, 8, 24, 24) cell.pixbuf:fill(pixel) end local window = Gtk.Window { title = "Editing and Drag-and-Drop", Gtk.IconView { id = 'icon_view', expand = true, model = store, selection_mode = 'SINGLE', item_orientation = 'HORIZONTAL', columns = 2, reorderable = true, cells = { { align = 'start', expand = true, Gtk.CellRendererPixbuf(), set_cell_color, }, { align = 'start', expand = true, Gtk.CellRendererText { editable = true, on_edited = edited, }, { text = 1 } }, }, }, } window:show_all() return window end, "Icon View/Editing and Drag-and-Drop", table.concat { [[The Gtk.IconView widget supports Editing and Drag-and-Drop. ]], [[This example also demonstrates using the generic Gtk.CellLayout ]], [[interface to set up cell renderers in an icon view.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-images.lua000066400000000000000000000076751221440706400211360ustar00rootroot00000000000000return function(parent, dir) local coroutine = require 'coroutine' local lgi = require 'lgi' local bytes = require 'bytes' local GLib = lgi.GLib local Gio = lgi.Gio local Gtk = lgi.Gtk local GdkPixbuf = lgi.GdkPixbuf local window = Gtk.Window { title = 'Images', border_width = 8, Gtk.Box { id = 'vbox', orientation = 'VERTICAL', spacing = 8, border_width = 8, Gtk.Label { label = "Image loaded from a file:", use_markup = true, }, Gtk.Frame { shadow_type = 'IN', halign = 'CENTER', valign = 'CENTER', Gtk.Image { file = dir:get_child('gtk-logo-rgb.gif'):get_path(), }, }, Gtk.Label { label = "Animation loaded from a file:", use_markup = true, }, Gtk.Frame { shadow_type = 'IN', halign = 'CENTER', valign = 'CENTER', Gtk.Image { file = dir:get_child('floppybuddy.gif'):get_path(), }, }, Gtk.Label { label = "Symbolic themed icon", use_markup = true, }, Gtk.Frame { shadow_type = 'IN', halign = 'CENTER', valign = 'CENTER', Gtk.Image { gicon = Gio.ThemedIcon.new_with_default_fallbacks( 'battery-caution-charging-symbolic'), icon_size = Gtk.IconSize.DIALOG, }, }, Gtk.Label { label = "Progressive image loading", use_markup = true, }, Gtk.Frame { shadow_type = 'IN', halign = 'CENTER', valign = 'CENTER', Gtk.Image { id = 'progressive', }, }, Gtk.ToggleButton { id = 'sensitive', label = "_Insensitive", use_underline = true, }, } } function window.child.sensitive:on_toggled() for _, child in ipairs(window.child.vbox.child) do if child ~= self then child.sensitive = not self.active end end end local function do_error(err) local dialog = Gtk.MessageDialog { transient_for = window, destroy_with_parent = true, text = "Failure reading image 'alphatest.png'", secondary_text = err, message_type = 'ERROR', buttons = 'CLOSE', on_response = Gtk.Widget.destroy, } dialog:show_all() end local abort_load, timer_id local load_coro = coroutine.create(function() while not abort_load do local stream, err = dir:get_child('alphatest.png'):read() if not stream then do_error(err) abort_load = true break end -- Create pixbuf loader and register callbacks. local loader = GdkPixbuf.PixbufLoader() function loader:on_area_prepared() local pixbuf = self:get_pixbuf() pixbuf:fill(0xaaaaaaff) window.child.progressive.pixbuf = pixbuf end function loader:on_area_updated() -- Let the image know that the pixbuf changed. window.child.progressive:queue_draw() end while not abort_load do -- Wait for the next timer tick. coroutine.yield(true) -- Load a chunk from the stream. local buffer = bytes.new(256) local read, err = stream:read(buffer) if read < 0 then do_error(err) abort_load = true end if read <= 0 then break end -- Send it to the pixbuf loader. if not loader:write(tostring(buffer):sub(1, read)) then do_error(err) abort_load = true end end loader:close() end -- Make sure that timeout is unregistered when the coroutine does -- not run any more. timer_id = nil return false end) timer_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, load_coro) -- Stop loading when the window is destroyed. function window:on_destroy() abort_load = true if timer_id then GLib.source_remove(timer_id) coroutine.resume(load_coro) end end window:show_all() return window end, "Images", table.concat { [[Gtk.Image is used to display an image; the image can be in ]], [[a number of formats. Typically, you load an image into a Gdk.Pixbuf, ]], [[then display the pixbuf. This demo code shows some of the more obscure cases, in the simple ]], [[case a call to Gtk.Image.new_from_file() is all you need.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-infobar.lua000066400000000000000000000032631221440706400212760ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Window { title = 'Info Bars', border_width = 8, Gtk.Box { orientation = 'VERTICAL', Gtk.InfoBar { id = 'info', message_type = 'INFO', }, Gtk.InfoBar { id = 'warning', message_type = 'WARNING', }, Gtk.InfoBar { id = 'question', buttons = { { Gtk.STOCK_OK, Gtk.ResponseType.OK }, }, message_type = 'QUESTION', }, Gtk.InfoBar { id = 'error', message_type = 'ERROR', }, Gtk.InfoBar { id = 'other', message_type = 'OTHER', }, Gtk.Frame { label = "Info Bars", Gtk.Box { orientation = 'VERTICAL', spacing = 8, border_width = 8, { padding = 8, Gtk.Label { label = "An example of different info bars", }, } }, }, }, } -- Create contents for the infobars. for _, id in ipairs { 'info', 'warning', 'question', 'error', 'other' } do window.child[id]:get_content_area():add( Gtk.Label { label = ("This is an info bar with " .. "message type Gtk.MessageType.%s"):format(id:upper()), }) end function window.child.question:on_response(response_id) local dialog = Gtk.MessageDialog { transient_for = window, modal = true, destroy_with_parent = true, message_type = 'INFO', buttons = 'OK', text = "You clicked a button on an info bar", secondary_text = ("Your response has id %d"):format(response_id) } dialog:run() dialog:destroy() end window:show_all() return window end, "Info bar", table.concat { [[Info bar widgets are used to report important messages to the user.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-links.lua000066400000000000000000000022651221440706400207770ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Window { title = 'Links', border_width = 12, Gtk.Label { id = 'label', label = [[Some text may be marked up as hyperlinks, which can be clicked or activated via keynav]], use_markup = true, }, } function window.child.label:on_activate_link(uri) if uri == 'keynav' then local dialog = Gtk.MessageDialog { transient_for = self:get_toplevel(), destroy_with_parent = true, message_type = 'INFO', buttons = 'OK', use_markup = true, text = [[The term keynav is a shorthand for ]] .. [[keyboard navigation and refers to the process of using ]] .. [[a program (exclusively) via keyboard input.]], on_response = Gtk.Widget.destroy, } dialog:present() return true else return false end end window:show_all() return window end, "Links", table.concat { [[Gtk.Label can show hyperlinks. The default action is to call ]], [[Gtk.show_uri() on their URI, but it is possible to override ]], [[this with a custom handler.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-menus.lua000066400000000000000000000060331221440706400210030ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local function create_menu(depth, tearoff) if depth < 1 then return nil end local menu = Gtk.Menu() if tearoff then menu:append(Gtk.TearoffMenuItem { visible = true }) end local group = nil for i = 1, 5 do local item = Gtk.RadioMenuItem { group = group, label = ("item %2d - %d"):format(depth, i), submenu = create_menu(depth - 1, true), sensitive = (i ~= 4), } if not group then group = item end menu:append(item) end return menu end local window = Gtk.Window { title = "Menus", Gtk.Box { orientation = 'VERTICAL', Gtk.MenuBar { id = 'menubar', Gtk.MenuItem { label = "test\nline2", visible = true, submenu = create_menu(2, true), }, Gtk.MenuItem { label = "foo", visible = true, submenu = create_menu(3), }, Gtk.MenuItem { label = "bar", visible = true, submenu = create_menu(4, true), }, }, Gtk.Box { orientation = 'VERTICAL', spacing = 10, border_width = 10, Gtk.Button { id = 'flip', label = "Flip", }, Gtk.Button { id = 'close', label = "Close", }, }, }, } function window.child.close:on_clicked() window:destroy() end function window.child.flip:on_clicked() local menubar = window.child.menubar local orientation = menubar.parent.orientation orientation = (orientation == 'HORIZONTAL' and 'VERTICAL' or 'HORIZONTAL') menubar.parent.orientation = orientation menubar.pack_direction = (orientation == 'VERTICAL' and 'LTR' or 'TTB') end window:show_all() return window end, "Menus", table.concat { [[There are several widgets involved in displaying menus. ]], [[The Gtk.MenuBar widget is a menu bar, which normally appears ]], [[horizontally at the top of an application, but can also be ]], [[layed out vertically. The Gtk.Menu widget is the actual menu ]], [[that pops up. Both Gtk.MenuBar and Gtk.Menu are subclasses ]], [[of Gtk.MenuShell; a Gtk.MenuShell contains menu items (Gtk.MenuItem). ]], [[Each menu item contains text and/or images and can be selected ]], [[by the user. ]], [[There are several kinds of menu item, including plain ]], [[Gtk.MenuItem, Gtk.CheckMenuItem which can be checked/unchecked, ]], [[Gtk.RadioMenuItem which is a check menu item that's in a mutually ]], [[exclusive group, Gtk.SeparatorMenuItem which is a separator bar, ]], [[Gtk.TearoffMenuItem which allows a Gtk.Menu to be torn off, ]], [[and Gtk.ImageMenuItem which can place a Gtk.Image or other widget ]], [[next to the menu text. ]], [[A Gtk.MenuItem can have a submenu, which is simply a Gtk.Menu ]], [[to pop up when the menu item is selected. Typically, all menu ]], [[items in a menu bar have submenus. ]], [[Gtk.UIManager provides a higher-level interface for creating ]], [[menu bars and menus; while you can construct menus manually, ]], [[most people don't do that. There's a separate demo for ]], [[Gtk.UIManager.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-ofw-mirror.lua000066400000000000000000000177511221440706400217700ustar00rootroot00000000000000return function(parent, dir) local math = require 'math' local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local Gdk = lgi.Gdk local cairo = lgi.cairo local GtkDemo = lgi.GtkDemo local log = lgi.log.domain 'gtk-demo' GtkDemo:class('MirrorBin', Gtk.Bin) function GtkDemo.MirrorBin:_init() self.has_window = true end local function to_child(bin, widget_x, widget_y) return widget_x, widget_y end local function to_parent(bin, offscreen_x, offscreen_y) return offscreen_x, offscreen_y end function GtkDemo.MirrorBin:do_realize() self.realized = true -- Create Gdk.Window and bind it with the widget. local events = self.events events.EXPOSURE_MASK = true events.POINTER_MOTION_MASK = true events.BUTTON_PRESS_MASK = true events.BUTTON_RELEASE_MASK = true events.SCROLL_MASK = true events.ENTER_NOTIFY_MASK = true events.LEAVE_NOTIFY_MASK = true local attributes = Gdk.WindowAttr { x = self.allocation.x + self.border_width, y = self.allocation.y + self.border_width, width = self.allocation.width - 2 * self.border_width, height = self.allocation.height - 2 * self.border_width, window_type = 'CHILD', event_mask = Gdk.EventMask(events), visual = self:get_visual(), wclass = 'INPUT_OUTPUT', } local window = Gdk.Window.new(self:get_parent_window(), attributes, { 'X', 'Y', 'VISUAL' }) self:set_window(window) window.widget = self local bin = self function window:on_pick_embedded_child(widget_x, widget_y) if bin.priv.child and bin.priv.child.visible then local x, y = to_child(bin, widget_x, widget_y) local child_area = bin.allocation if x >= 0 and x < child_area.width and y >= 0 and y < child_area.height then return bin.priv.offscreen_window end end end -- Create and hook up the offscreen window. attributes.window_type = 'OFFSCREEN' local child_requisition = Gtk.Requisition { width = 0, height = 0 } if self.priv.child and self.priv.child.visible then local child_allocation = self.priv.child.allocation attributes.width = child_allocation.width attributes.height = child_allocation.height end self.priv.offscreen_window = Gdk.Window.new(self.root_window, attributes, { 'X', 'Y', 'VISUAL' }) self.priv.offscreen_window.widget = self if self.priv.child then self.priv.child:set_parent_window(bin.priv.offscreen_window) end Gdk.offscreen_window_set_embedder(self.priv.offscreen_window, window) function self.priv.offscreen_window:on_to_embedder(offscreen_x, offscreen_y) return to_parent(bin, offscreen_x, offscreen_y) end function self.priv.offscreen_window:on_from_embedder(parent_x, parent_y) return to_child(bin, parent_x, parent_y) end -- Set background of the windows according to current context. self.style_context:set_background(window) self.style_context:set_background(self.priv.offscreen_window) self.priv.offscreen_window:show() end function GtkDemo.MirrorBin:do_unrealize() -- Destroy offscreen window. self.priv.offscreen_window.widget = nil self.priv.offscreen_window:destroy() self.priv.offscreen_window = nil -- Chain to parent. GtkDemo.MirrorBin._parent.do_unrealize(self) end function GtkDemo.MirrorBin:do_child_type() return self.priv.child and GObject.Type.NONE or Gtk.Widget end function GtkDemo.MirrorBin:do_add(widget) if not self.priv.child then if self.priv.offscreen_window then widget:set_parent_window(self.priv.offscreen_window) end widget:set_parent(self) self.priv.child = widget else log.warning("GtkDemo.MirrorBin cannot have more than one child") end end function GtkDemo.MirrorBin:do_remove(widget) local was_visible = widget.visible if self.priv.child == widget then widget:unparent() self.priv.child = nil if was_visible and self.visible then self:queue_resize() end end end function GtkDemo.MirrorBin:do_forall(include_internals, callback) if self.priv.child then callback(self.priv.child, callback.user_data) end end local function size_request(self) local child_requisition = Gtk.Requisition() if self.priv.child and self.priv.child.visible then child_requisition = self.priv.child:get_preferred_size() end local w = child_requisition.width + 10 + 2 * self.border_width local h = child_requisition.height + 10 + 2 * self.border_width return w, h end function GtkDemo.MirrorBin:do_get_preferred_width() local w, h = size_request(self) return w, w end function GtkDemo.MirrorBin:do_get_preferred_height() local w, h = size_request(self) return h, h end function GtkDemo.MirrorBin:do_size_allocate(allocation) self:set_allocation(allocation) local w = allocation.width - self.border_width * 2 local h = allocation.height - self.border_width * 2 if self.realized then self.window:move_resize(allocation.x + self.border_width, allocation.y + self.border_width, w, h) end if self.priv.child and self.priv.child.visible then local child_requisition = self.priv.child:get_preferred_size() local child_allocation = Gtk.Allocation { height = child_requisition.height, width = child_requisition.width } if self.realized then self.priv.offscreen_window:move_resize(child_allocation.x, child_allocation.y, child_allocation.width, child_allocation.height) end self.priv.child:size_allocate(child_allocation) end end function GtkDemo.MirrorBin:do_damage(event) self.window:invalidate_rect(nil, false) return true end function GtkDemo.MirrorBin:_class_init() -- Unfortunately, damage-event signal does not have virtual -- function associated, so we have to go through following funky -- dance to install default signal handler. GObject.signal_override_class_closure( GObject.signal_lookup('damage-event', Gtk.Widget), GtkDemo.MirrorBin, GObject.Closure(GtkDemo.MirrorBin.do_damage, Gtk.Widget.on_damage_event)) end function GtkDemo.MirrorBin:do_draw(cr) if cr:should_draw_window(self.window) then if self.priv.child and self.priv.child.visible then local surface = Gdk.offscreen_window_get_surface( self.priv.offscreen_window) local height = self.priv.offscreen_window:get_height() -- Paint the offscreen child cr:set_source_surface(surface, 0, 0) cr:paint() local matrix = cairo.Matrix { xx = 1, yx = 0, xy = 0.3, yy = 1, x0 = 0, y0 = 0 } matrix:scale(1, -1) matrix:translate(-10, -3 * height, - 10) cr:transform(matrix) cr:set_source_surface(surface, 0, height) -- Create linear gradient as mask-pattern to fade out the source local mask = cairo.LinearPattern(0, height, 0, 2 * height) mask:add_color_stop_rgba(0, 0, 0, 0, 0) mask:add_color_stop_rgba(0.25, 0, 0, 0, 0.01) mask:add_color_stop_rgba(0.5, 0, 0, 0, 0.25) mask:add_color_stop_rgba(0.75, 0, 0, 0, 0.5) mask:add_color_stop_rgba(1, 0, 0, 0, 1) -- Paint the reflection cr:mask(mask) end elseif cr:should_draw_window(self.priv.offscreen_window) then Gtk.render_background(self.style_context, cr, 0, 0, self.priv.offscreen_window:get_width(), self.priv.offscreen_window:get_height()) if self.priv.child then self:propagate_draw(self.priv.child, cr) end end return false end local window = Gtk.Window { title = "Effects", border_width = 10, Gtk.Box { orientation = 'VERTICAL', expand = true, GtkDemo.MirrorBin { Gtk.Box { orientation = 'HORIZONTAL', spacing = 6, Gtk.Button { Gtk.Image { stock = Gtk.STOCK_GO_BACK, icon_size = 4, }, }, Gtk.Entry { expand = true, }, Gtk.Button { Gtk.Image { stock = Gtk.STOCK_APPLY, icon_size = 4, }, }, }, }, }, } window:show_all() return window end, "Offscreen windows/Effects", table.concat { [[Offscreen windows can be used to render elements multiple times ]], [[to achieve various effects.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-ofw-rotbutton.lua000066400000000000000000000227221221440706400225100ustar00rootroot00000000000000return function(parent, dir) local math = require 'math' local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local Gdk = lgi.Gdk local GtkDemo = lgi.GtkDemo local log = lgi.log.domain 'gtk-demo' GtkDemo:class('RotatedBin', Gtk.Bin) function GtkDemo.RotatedBin:_init() self.has_window = true self.priv.angle = 0 end local function to_child(bin, widget_x, widget_y) local s, c = math.sin(bin.priv.angle), math.cos(bin.priv.angle) local child_area = bin.priv.child.allocation local w = c * child_area.width + s * child_area.height local h = s * child_area.width + c * child_area.height local x = widget_x - w / 2 local y = widget_y - h / 2 local xr = x * c + y * s local yr = y * c - x * s return xr + child_area.width / 2, yr + child_area.height / 2 end local function to_parent(bin, offscreen_x, offscreen_y) local s, c = math.sin(bin.priv.angle), math.cos(bin.priv.angle) local child_area = bin.priv.child.allocation local w = c * child_area.width + s * child_area.height local h = s * child_area.width + c * child_area.height local x = offscreen_x - child_area.width / 2 local y = offscreen_y - child_area.height / 2 local xr = x * c - y * s local yr = x * s + y * c return xr + child_area.width - w / 2, yr + child_area.height - h / 2 end function GtkDemo.RotatedBin:do_realize() self.realized = true -- Create Gdk.Window and bind it with the widget. local events = self.events events.EXPOSURE_MASK = true events.POINTER_MOTION_MASK = true events.BUTTON_PRESS_MASK = true events.BUTTON_RELEASE_MASK = true events.SCROLL_MASK = true events.ENTER_NOTIFY_MASK = true events.LEAVE_NOTIFY_MASK = true local attributes = Gdk.WindowAttr { x = self.allocation.x + self.border_width, y = self.allocation.y + self.border_width, width = self.allocation.width - 2 * self.border_width, height = self.allocation.height - 2 * self.border_width, window_type = 'CHILD', event_mask = Gdk.EventMask(events), visual = self:get_visual(), wclass = 'INPUT_OUTPUT', } local window = Gdk.Window.new(self:get_parent_window(), attributes, { 'X', 'Y', 'VISUAL' }) self:set_window(window) window.widget = self local bin = self function window:on_pick_embedded_child(widget_x, widget_y) if bin.priv.child and bin.priv.child.visible then local x, y = to_child(bin, widget_x, widget_y) local child_area = bin.allocation if x >= 0 and x < child_area.width and y >= 0 and y < child_area.height then return bin.priv.offscreen_window end end end -- Create and hook up the offscreen window. attributes.window_type = 'OFFSCREEN' local child_requisition = Gtk.Requisition { width = 0, height = 0 } if self.priv.child and self.priv.child.visible then local child_allocation = self.priv.child.allocation attributes.width = child_allocation.width attributes.height = child_allocation.height end self.priv.offscreen_window = Gdk.Window.new(self.root_window, attributes, { 'X', 'Y', 'VISUAL' }) self.priv.offscreen_window.widget = self if self.priv.child then self.priv.child:set_parent_window(bin.priv.offscreen_window) end Gdk.offscreen_window_set_embedder(self.priv.offscreen_window, window) function self.priv.offscreen_window:on_to_embedder(offscreen_x, offscreen_y) return to_parent(bin, offscreen_x, offscreen_y) end function self.priv.offscreen_window:on_from_embedder(parent_x, parent_y) return to_child(bin, parent_x, parent_y) end -- Set background of the windows according to current context. self.style_context:set_background(window) self.style_context:set_background(self.priv.offscreen_window) self.priv.offscreen_window:show() end function GtkDemo.RotatedBin:do_unrealize() -- Destroy offscreen window. self.priv.offscreen_window.widget = nil self.priv.offscreen_window:destroy() self.priv.offscreen_window = nil -- Chain to parent. GtkDemo.RotatedBin._parent.do_unrealize(self) end function GtkDemo.RotatedBin:do_child_type() return self.priv.child and GObject.Type.NONE or Gtk.Widget end function GtkDemo.RotatedBin:do_add(widget) if not self.priv.child then if self.priv.offscreen_window then widget:set_parent_window(self.priv.offscreen_window) end widget:set_parent(self) self.priv.child = widget else log.warning("GtkDemo.RotatedBin cannot have more than one child") end end function GtkDemo.RotatedBin:do_remove(widget) local was_visible = widget.visible if self.priv.child == widget then widget:unparent() self.priv.child = nil if was_visible and self.visible then self:queue_resize() end end end function GtkDemo.RotatedBin:do_forall(include_internals, callback) if self.priv.child then callback(self.priv.child, callback.user_data) end end function GtkDemo.RotatedBin:set_angle(angle) self.priv.angle = angle self:queue_resize() self.priv.offscreen_window:geometry_changed() end local function size_request(self) local child_requisition = Gtk.Requisition() if self.priv.child and self.priv.child.visible then child_requisition = self.priv.child:get_preferred_size() end local s, c = math.sin(self.priv.angle), math.cos(self.priv.angle) local w = c * child_requisition.width + s * child_requisition.height local h = s * child_requisition.width + c * child_requisition.height return w + 2 * self.border_width, h + 2 * self.border_width end function GtkDemo.RotatedBin:do_get_preferred_width() local w, h = size_request(self) return w, w end function GtkDemo.RotatedBin:do_get_preferred_height() local w, h = size_request(self) return h, h end function GtkDemo.RotatedBin:do_size_allocate(allocation) self:set_allocation(allocation) local w = allocation.width - self.border_width * 2 local h = allocation.height - self.border_width * 2 if self.realized then self.window:move_resize(allocation.x + self.border_width, allocation.y + self.border_width, w, h) end if self.priv.child and self.priv.child.visible then local s, c = math.sin(self.priv.angle), math.cos(self.priv.angle) local child_requisition = self.priv.child:get_preferred_size() local child_allocation = Gtk.Allocation { height = child_requisition.height } if c == 0 then child_allocation.width = h / s elseif s == 0 then child_allocation.width = w / c else child_allocation.width = math.min( (w - s * child_allocation.height) / c, (h - c * child_allocation.width) / s) end if self.realized then self.priv.offscreen_window:move_resize(child_allocation.x, child_allocation.y, child_allocation.width, child_allocation.height) end child_allocation.x = 0 child_allocation.y = 0 self.priv.child:size_allocate(child_allocation) end end function GtkDemo.RotatedBin:do_damage(event) self.window:invalidate_rect(nil, false) return true end function GtkDemo.RotatedBin:_class_init() -- Unfortunately, damage-event signal does not have virtual -- function associated, so we have to go through following funky -- dance to install default signal handler. GObject.signal_override_class_closure( GObject.signal_lookup('damage-event', Gtk.Widget), GtkDemo.RotatedBin, GObject.Closure(GtkDemo.RotatedBin.do_damage, Gtk.Widget.on_damage_event)) end function GtkDemo.RotatedBin:do_draw(cr) if cr:should_draw_window(self.window) then if self.priv.child and self.priv.child.visible then local surface = Gdk.offscreen_window_get_surface( self.priv.offscreen_window) local child_area = self.priv.child.allocation -- transform local s, c = math.sin(self.priv.angle), math.cos(self.priv.angle) local w = c * child_area.width + s * child_area.height local h = s * child_area.width + c * child_area.height cr:translate((w - child_area.width) / 2, (h - child_area.height) / 2) cr:translate(child_area.width / 2, child_area.height / 2) cr:rotate(self.priv.angle) cr:translate(-child_area.width / 2, -child_area.height / 2) -- clip cr:rectangle(0, 0, self.priv.offscreen_window:get_width(), self.priv.offscreen_window:get_height()) cr:clip() -- paint cr:set_source_surface(surface, 0, 0) cr:paint() end end if cr:should_draw_window(self.priv.offscreen_window) then Gtk.render_background(self.style_context, cr, 0, 0, self.priv.offscreen_window:get_width(), self.priv.offscreen_window:get_height()) if self.priv.child then self:propagate_draw(self.priv.child, cr) end end return false end local window = Gtk.Window { title = "Rotated widget", border_width = 10, Gtk.Box { orientation = 'VERTICAL', Gtk.Scale { id = 'scale', orientation = 'HORIZONTAL', adjustment = Gtk.Adjustment { lower = 0, upper = math.pi / 2, step_increment = 0.01, }, draw_value = false, }, GtkDemo.RotatedBin { id = 'bin', Gtk.Button { label = "A Button", expand = true, }, }, } } function window.child.scale:on_value_changed() window.child.bin:set_angle(self.adjustment.value) end window:override_background_color(0, Gdk.RGBA.parse('black')) window:show_all() return window end, "Offscreen windows/Rotated button", table.concat { [[Offscreen windows can be used to transform parts or a ]], [[widget hierarchy. Note that the rotated button is fully functional.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-paned.lua000066400000000000000000000071711221440706400207470ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Window { title = "Panes", Gtk.Box { orientation = 'VERTICAL', Gtk.Paned { orientation = 'VERTICAL', Gtk.Paned { id = 'paned_top', orientation = 'HORIZONTAL', Gtk.Frame { id = 'paned_left', shadow_type = 'IN', height_request = 60, width_request = 60, Gtk.Button { label = "_Hi there", use_underline = true, }, }, Gtk.Frame { id = 'paned_right', shadow_type = 'IN', height_request = 80, width_request = 60, }, }, Gtk.Frame { id = 'paned_bottom', shadow_type = 'IN', height_request = 60, width_request = 80, }, }, Gtk.Frame { label = "Horizontal", border_width = 4, Gtk.Grid { { left_attach = 0, top_attach = 0, Gtk.Label { label = "Left" }, }, { left_attach = 0, top_attach = 1, Gtk.CheckButton { id = 'resize_left', label = "_Resize", use_underline = true, }, }, { left_attach = 0, top_attach = 2, Gtk.CheckButton { id = 'shrink_left', label = "_Shrink", use_underline = true, }, }, { left_attach = 1, top_attach = 0, Gtk.Label { label = "Right" }, }, { left_attach = 1, top_attach = 1, Gtk.CheckButton { id = 'resize_right', label = "_Resize", use_underline = true, }, }, { left_attach = 1, top_attach = 2, Gtk.CheckButton { id = 'shrink_right', label = "_Shrink", use_underline = true, }, }, }, }, Gtk.Frame { label = "Vertical", border_width = 4, Gtk.Grid { { left_attach = 0, top_attach = 0, Gtk.Label { label = "Top" }, }, { left_attach = 0, top_attach = 1, Gtk.CheckButton { id = 'resize_top', label = "_Resize", use_underline = true, }, }, { left_attach = 0, top_attach = 2, Gtk.CheckButton { id = 'shrink_top', label = "_Shrink", use_underline = true, }, }, { left_attach = 1, top_attach = 0, Gtk.Label { label = "Bottom" }, }, { left_attach = 1, top_attach = 1, Gtk.CheckButton { id = 'resize_bottom', label = "_Resize", use_underline = true, }, }, { left_attach = 1, top_attach = 2, Gtk.CheckButton { id = 'shrink_bottom', label = "_Shrink", use_underline = true, }, }, }, }, }, } -- Connect servicing routines for all toggles. for _, pos in ipairs { 'left', 'right', 'top', 'bottom' } do local child = window.child['paned_' .. pos] local paned = child.parent local resize = window.child['resize_' .. pos] resize.active = paned.property[child].resize function resize:on_clicked() paned.property[child].resize = self.active end local shrink = window.child['shrink_' .. pos] shrink.active = paned.property[child].shrink function shrink:on_clicked() paned.property[child].shrink = self.active end end window:show_all() return window end, "Paned Widgets", table.concat { [[The Gtk.Paned widget divide its content area into two panes ]], [[with a divider in between that the user can adjust. A separate ]], [[child is placed into each pane. ]], [[There are a number of options that can be set for each pane. ]], [[This test contains both a horizontal and a vertical widget, ]], [[and allows you to adjust the options for each side of each widget.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-pickers.lua000066400000000000000000000035131221440706400213140ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Window { title = "Pickers", border_width = 10, Gtk.Grid { border_width = 10, row_spacing = 3, column_spacing = 10, { left_attach = 0, top_attach = 0, Gtk.Label { label = "Color:", halign = 'START', valign = 'CENTER', hexpand = true, }, }, { left_attach = 1, top_attach = 0, Gtk.ColorButton {}, }, { left_attach = 0, top_attach = 1, Gtk.Label { label = "Font:", halign = 'START', valign = 'CENTER', hexpand = true, }, }, { left_attach = 1, top_attach = 1, Gtk.FontButton {}, }, { left_attach = 0, top_attach = 2, Gtk.Label { label = "File:", halign = 'START', valign = 'CENTER', hexpand = true, }, }, { left_attach = 1, top_attach = 2, Gtk.FileChooserButton { title = "Pick a File", action = 'OPEN', }, }, { left_attach = 0, top_attach = 3, Gtk.Label { label = "Folder:", halign = 'START', valign = 'CENTER', hexpand = true, }, }, { left_attach = 1, top_attach = 3, Gtk.FileChooserButton { title = "Pick a Folder", action = 'SELECT_FOLDER', }, }, { left_attach = 0, top_attach = 4, Gtk.Label { label = "Mail:", halign = 'START', valign = 'CENTER', hexpand = true, }, }, { left_attach = 1, top_attach = 4, Gtk.AppChooserButton { content_type = 'x-scheme-handler/mailto', show_dialog_item = true, }, }, } } window:show_all() return window end, "Pickers", table.concat { [[These widgets are mainly intended for use in preference ]], [[dialogs. They allow to select colors, fonts, files, directories ]], [[and applications.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-pixbufs.lua000066400000000000000000000060531221440706400213360ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local Gtk = lgi.Gtk local Gdk = lgi.Gdk local GdkPixbuf = lgi.GdkPixbuf local cairo = lgi.cairo -- Load pixbuf images. local background = assert(GdkPixbuf.Pixbuf.new_from_file( dir:get_child('background.jpg'):get_path())) local back_width, back_height = background.width, background.height local images = {} for _, name in ipairs { 'apple-red.png', 'gnome-applets.png', 'gnome-calendar.png', 'gnome-foot.png', 'gnome-gmush.png', 'gnome-gimp.png', 'gnome-gsame.png', 'gnu-keys.png' } do images[#images + 1] = assert(GdkPixbuf.Pixbuf.new_from_file( dir:get_child(name):get_path())) end local window = Gtk.Window { title = "Pixbufs", resizable = false, Gtk.DrawingArea { id = 'area', width = back_width, height = back_height, }, } local frame = GdkPixbuf.Pixbuf.new('RGB', false, 8, back_width, back_height) local area = window.child.area function area:on_draw(cr) cr:set_source_pixbuf(frame, 0, 0) cr:paint() return true end local FRAME_DELAY = 50 local CYCLE_LEN = 60 local frame_num = 0 local sin, cos, pi, floor, abs, min, max = math.sin, math.cos, math.pi, math.floor, math.abs, math.min, math.max local timeout_id = GLib.timeout_add( GLib.PRIORITY_DEFAULT, FRAME_DELAY, function() background:copy_area(0, 0, back_width, back_height, frame, 0, 0) local f = (frame_num % CYCLE_LEN) / CYCLE_LEN local xmid, ymid = back_width / 2, back_height / 2 local radius = min(xmid, ymid) / 2 local r1 = Gdk.Rectangle() local r2 = Gdk.Rectangle { x = 0, y = 0, width = back_width, height = back_height } for i = 1, #images do local ang = 2 * pi * (i / #images - f) local iw, ih = images[i].width, images[i].height local r = radius + (radius / 3) * sin(2 * pi * f) local xpos = floor(xmid + r * cos(ang) - iw / 2 + 0.5) local ypos = floor(ymid + r * sin(ang) - ih / 2 + 0.5) local k = (i % 2 == 0) and sin(f * 2 * pi) or cos(f * 2 * pi) k = max(2 * k * k, 0.25) r1.x = xpos r1.y = ypos r1.width = iw * k r1.height = ih * k local dest = Gdk.Rectangle.intersect(r1, r2) if dest then local alpha = (i % 1 == 0) and sin(f * 2 * pi) or cos(f * 2 * pi) images[i]:composite(frame, dest.x, dest.y, dest.width, dest.height, xpos, ypos, k, k, 'NEAREST', max(127, abs(alpha))) end end area:queue_draw() frame_num = frame_num + 1 return GLib.SOURCE_CONTINUE end) function window:on_destroy() GLib.source_remove(timeout_id) end window:show_all() return window end, "Pixbufs", table.concat { [[A Gdk.Pixbuf represents an image, normally in RGB or RGBA format. ]], [[Pixbufs are normally used to load files from disk and perform image ]], [[scaling. ]], [[This demo is not all that educational, but looks cool. It was ]], [[written by Extreme Pixbuf Hacker Federico Mena Quintero. It also ]], [[shows off how to use Gtk.DrawingArea to do a simple animation. ]], [[Look at the Image demo for additional pixbuf usage examples.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-printing.lua000066400000000000000000000066441221440706400215160ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local Gio = lgi.Gio local Gtk = lgi.Gtk local Gdk = lgi.Gdk local cairo = lgi.cairo local Pango = lgi.Pango local PangoCairo = lgi.PangoCairo -- Prepare settings. local settings = Gtk.PrintSettings {} local outdir = GLib.get_user_special_dir('DIRECTORY_DOCUMENTS') or GLib.get_home_dir() settings:set(Gtk.PRINT_OUTPUT_URI, 'file://' .. outdir .. '/gtk-demo.' .. (settings:get(Gtk.PRINT_OUTPUT_FILE_FORMAT) or 'pdf')) -- Create the print operation. local operation = Gtk.PrintOperation { use_full_page = true, unit = 'POINTS', embed_page_setup = true, print_settings = settings } local HEADER_HEIGHT = 10 * 72 / 25.4 local HEADER_GAP = 3 * 72 / 25.4 local font_size = 12 local contents function operation:on_begin_print(context) contents = {} local height = context:get_height() - HEADER_HEIGHT - HEADER_GAP contents.lines_per_page = math.floor(height / font_size) -- Parse input stream into lines. local file = dir:get_child('demo-printing.lua') contents.filename = file:query_info( Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, 'NONE'):get_display_name() local input = Gio.DataInputStream { newline_type = 'ANY', base_stream = assert(file:read()), } while true do local line, err = input:read_line_utf8() if not line and err == 0 then break end assert(line, err) contents[#contents + 1] = line end contents.num_pages = math.floor((#contents - 1) / contents.lines_per_page + 1) self:set_n_pages(contents.num_pages) end function operation:on_draw_page(context, page_nr) local cr = context:get_cairo_context() local width = context:get_width() cr:rectangle(0, 0, width, HEADER_HEIGHT) cr:set_source_rgb(0.8, 0.8, 0.8) cr:fill_preserve() cr:set_source_rgb(0, 0, 0) cr.line_width = 1 cr:stroke() local layout = context:create_pango_layout() layout.font_description = Pango.FontDescription.from_string('sans 14') layout.text = contents.filename local text_width, text_height = layout:get_pixel_size() if text_width > width then layout.width = width layout.ellipsize = 'START' text_width, text_height = layout:get_pixel_size() end cr:move_to((width - text_width) / 2, (HEADER_HEIGHT - text_height) / 2) cr:show_layout(layout) layout.text = ("%d/%d"):format(page_nr + 1, contents.num_pages) layout.width = -1 text_width, text_height = layout:get_pixel_size() cr:move_to(width - text_width - 4, (HEADER_HEIGHT - text_height) / 2) cr:show_layout(layout) layout = context:create_pango_layout() layout.font_description = Pango.FontDescription.from_string('monospace') cr:move_to(0, HEADER_HEIGHT + HEADER_GAP) local line = page_nr * contents.lines_per_page for i = 1, math.min(#contents - line, contents.lines_per_page) do layout.text = contents[line + i] cr:show_layout(layout) cr:rel_move_to(0, font_size) end end -- Run the operation local ok, err = operation:run('PRINT_DIALOG', parent) if not ok then local dialog = Gtk.MessageDialog { transient_for = parent, destroy_with_parent = true, message_type = 'ERROR', buttons = 'CLOSE', message = err, on_response = Gtk.Widget.destroy, } dialog:show_all() end end, "Printing", table.concat { [[Gtk.PrintOperation offers a simple API to support printing ]], [[in a cross-platform way.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-rotatedtext.lua000066400000000000000000000102101221440706400222130ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local cairo = lgi.cairo local Pango = lgi.Pango local PangoCairo = lgi.PangoCairo local RADIUS = 150 local N_WORDS = 5 local FONT = 'Serif 18' local HEART = '♥' local TEXT = 'I ♥ GTK+' local window = Gtk.Window { title = "Rotated Text", default_width = 4 * RADIUS, default_height = 2 * RADIUS, Gtk.Box { orientation = 'HORIZONTAL', homogeneous = true, Gtk.DrawingArea { id = 'circle', }, Gtk.Label { id = 'label', angle = 45, label = TEXT, }, } } -- Override background color of circle drawing area. window.child.circle:override_background_color( 'NORMAL', Gdk.RGBA { red = 1, green = 1, blue = 1, alpha = 1 }) local function fancy_shape_renderer(cr, attr, do_path) cr:translate(cr:get_current_point()) cr:scale(attr.ink_rect.width / Pango.SCALE, attr.ink_rect.height / Pango.SCALE) -- Draw the manually. cr:move_to(0.5, 0) cr:line_to(0.9, -0.4) cr:curve_to(1.1, -0.8, 0.5, -0.9, 0.5, -0.5) cr:curve_to(0.5, -0.9, -0.1, -0.8, 0.1, -0.4) cr:close_path() if not do_path then cr:set_source_rgb(1, 0, 0) cr:fill() end end local function create_fancy_attr_list_for_layout(layout) -- Get font metrics and prepare fancy shape size. local ascent = layout.context:get_metrics(layout.font_description).ascent local rect = Pango.Rectangle { x = 0, width = ascent, y = -ascent, height = ascent } -- Create attribute list, add specific shape renderer for every -- occurence of heart symbol. local attrs = Pango.AttrList() local start_index, end_index = 1, 1 while true do start_index, end_index = TEXT:find(HEART, end_index + 1, true) if not start_index then break end local attr = Pango.Attribute.shape_new(rect, rect) attr.start_index = start_index - 1 attr.end_index = end_index attrs:insert(attr) end return attrs end function window.child.circle:on_draw(cr) -- Create a cairo context and set up a transformation matrix so that -- the user space coordinates for the centered square where we draw -- are [-RADIUS, RADIUS], [-RADIUS, RADIUS]. We first center, then -- change the scale. local device_radius = math.min(self.width, self.height) / 2 cr:translate(device_radius + (self.width - 2 * device_radius) / 2, device_radius + (self.height - 2 * device_radius) / 2) cr:scale(device_radius / RADIUS, device_radius / RADIUS) -- Create a subtle gradient source and use it. local pattern = cairo.Pattern.create_linear(-RADIUS, -RADIUS, RADIUS, RADIUS) pattern:add_color_stop_rgb(0, 0.5, 0, 0) pattern:add_color_stop_rgb(1, 0, 0, 0.5) cr:set_source(pattern) -- Create a Pango.Context and set up our shape renderer. local context = self:create_pango_context() context.shape_renderer = fancy_shape_renderer -- Create a Pango.Layout, set the text, font and attributes. local layout = Pango.Layout.new(context) layout.text = TEXT layout.font_description = Pango.FontDescription.from_string(FONT) layout.attributes = create_fancy_attr_list_for_layout(layout) -- Draw the layout N_WORDS times in a circle. for i = 1, N_WORDS do -- Inform Pango to re-layout the text with the new transformation -- matrix. cr:update_layout(layout) local width, height = layout:get_pixel_size() cr:move_to(-width / 2, -RADIUS * 0.9) cr:show_layout(layout) -- Rotate for the next turn. cr:rotate(2 * math.pi / N_WORDS) end end -- Set up fancy stuff on the label. local label = window.child.label local layout = label:get_layout() layout.context.shape_renderer = fancy_shape_renderer label:set_attributes(create_fancy_attr_list_for_layout(layout)) window:show_all() return window end, "Rotated Text", table.concat { [[This demo shows how to use PangoCairo to draw rotated and transformed ]], [[text. The right pane shows a rotated Gtk.Label widget. ]], [[In both cases, a custom PangoCairo shape renderer is installed ]], [[to draw a red heard using cairo drawing operations instead of ]], [[the Unicode heart character.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-sizegroup.lua000066400000000000000000000050441221440706400217040ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Dialog { title = "Gtk.SizeGroup", transient_for = parent, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.NONE }, }, resizable = false, on_response = Gtk.Widget.destroy, } window:get_content_area():add( Gtk.Box { orientation = 'VERTICAL', border_width = 5, spacing = 5, Gtk.Frame { label = "Color Options", Gtk.Grid { id = 'colors', row_spacing = 5, column_spacing = 10, } }, Gtk.Frame { label = "Line Options", Gtk.Grid { id = 'lines', row_spacing = 5, column_spacing = 10, } }, Gtk.CheckButton { id = 'enable_grouping', label = "_Enable grouping", use_underline = true, active = true, }, }) local size_group = Gtk.SizeGroup { mode = 'HORIZONTAL' } local function add_row(grid, row, label, strings) local combo = Gtk.ComboBoxText {} for _, text in ipairs(strings) do combo:append_text(text) end combo.active = 0 size_group:add_widget(combo) grid:add { left_attach = 0, top_attach = row, Gtk.Label { label = label, use_underline = true, halign = 'START', valign = 'END', hexpand = true, mnemonic_widget = combo, } } grid:add { left_attach = 1, top_attach = row, combo } end add_row(window.child.colors, 0, "_Foreground", { "Red", "Green", "Blue", }) add_row(window.child.colors, 1, "_Background", { "Red", "Green", "Blue", }) add_row(window.child.lines, 0, "_Dashing", { "Solid", "Dashed", "Dotted", }) add_row(window.child.lines, 1, "_Line ends", { "Square", "Round", "Arrow", }) function window.child.enable_grouping:on_toggled() size_group.mode = self.active and 'HORIZONTAL' or 'NONE' end window:show_all() return window end, "Size Groups", table.concat { [[Gtk.SizeGroup provides a mechanism for grouping a number of widgets ]], [[together so they all request the same amount of space. This is ]], [[typically useful when you want a column of widgets to have the same ]], [[size, but you can't use a Gtk.Grid widget. ]], [[Note that size groups only affect the amount of space requested, ]], [[not the size that the widgets finally receive. If you want ]], [[the widgets in a Gtk.SizeGroup to actually be the same size, ]], [[you need to pack them in such a way that they get the size they ]], [[request and not more. For example, if you are packing your widgets ]], [[into a grid, you would not include the 'FILL' flag.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-spinner.lua000066400000000000000000000024601221440706400213320ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local window = Gtk.Dialog { title = "Gtk.Spinner", transient_for = parent, buttons = { { Gtk.STOCK_CLOSE, Gtk.ResponseType.NONE }, }, resizable = false, on_response = Gtk.Widget.destroy, } window:get_content_area():add( Gtk.Box { orientation = 'VERTICAL', border_width = 5, spacing = 5, Gtk.Box { orientation = 'HORIZONTAL', spacing = 5, Gtk.Spinner { id = 'sensitive', active = true, }, Gtk.Entry {}, }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 5, Gtk.Spinner { id = 'insensitive', sensitive = false, active = true, }, Gtk.Entry {}, }, Gtk.Button { id = 'play', label = Gtk.STOCK_MEDIA_PLAY, use_stock = true, }, Gtk.Button { id = 'stop', label = Gtk.STOCK_MEDIA_STOP, use_stock = true, }, }) function window.child.play:on_clicked() window.child.sensitive.active = true window.child.insensitive.active = true end function window.child.stop:on_clicked() window.child.sensitive.active = false window.child.insensitive.active = false end window:show_all() return window end, "Spinner", table.concat { [[Gtk.Spinner allows to show that background activity is on-going.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-stockbrowser.lua000066400000000000000000000126431221440706400224070ustar00rootroot00000000000000return function(parent, dir) local table = require 'table' local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local GdkPixbuf = lgi.GdkPixbuf local BrowserColumn = { ID = 1, LABEL = 2, SMALL_ICON = 3, ACCEL_STR = 4, MACRO = 5, } local function create_model() local store = Gtk.ListStore.new { [BrowserColumn.ID] = GObject.Type.STRING, [BrowserColumn.LABEL] = GObject.Type.STRING, [BrowserColumn.SMALL_ICON] = GdkPixbuf.Pixbuf, [BrowserColumn.ACCEL_STR] = GObject.Type.STRING, [BrowserColumn.MACRO] = GObject.Type.STRING, } local ids = Gtk.stock_list_ids() table.sort(ids) local icon_width, icon_height = Gtk.IconSize.lookup(Gtk.IconSize.MENU) for _, id in ipairs(ids) do local item = Gtk.stock_lookup(id) local macro = id:upper():gsub('^GTK%-', 'Gtk.STOCK_'):gsub('%-', '_') local small_icon local icon_set = Gtk.IconFactory.lookup_default(id) if icon_set then -- Prefer menu size if it exists, otherwise take the first -- available size. local sizes = icon_set:get_sizes() local size = sizes[0] for i = 1, #sizes do if sizes[i] == Gtk.IconSize.MENU then size = Gtk.IconSize.MENU break end end small_icon = parent:render_icon_pixbuf(id, size) if size ~= Gtk.IconSize.MENU then -- Make the result proper size for thumbnail. small_icon = small_icon:scale_simple(icon_width, icon_height, 'BILINEAR') end end local accel_str if item and item.keyval ~= 0 then accel_str = Gtk.accelerator_name(item.keyval, item.modifier) end store:append { [BrowserColumn.ID] = id, [BrowserColumn.LABEL] = item and item.label, [BrowserColumn.SMALL_ICON] = small_icon, [BrowserColumn.ACCEL_STR] = accel_str, [BrowserColumn.MACRO] = macro, } end return store end local window = Gtk.Window { title = "Stock Icons and Items", default_height = 500, border_width = 8, Gtk.Box { orientation = 'HORIZONTAL', spacing = 8, Gtk.ScrolledWindow { hscrollbar_policy = 'NEVER', expand = true, Gtk.TreeView { id = 'treeview', model = create_model(), Gtk.TreeViewColumn { title = "Identifier", { Gtk.CellRendererPixbuf {}, align = 'start', { stock_id = BrowserColumn.ID }, }, { Gtk.CellRendererText {}, expand = true, align = 'start', { text = BrowserColumn.MACRO }, }, }, Gtk.TreeViewColumn { title = "Label", { Gtk.CellRendererText {}, { text = BrowserColumn.LABEL }, }, }, Gtk.TreeViewColumn { title = "Accel", { Gtk.CellRendererText {}, { text = BrowserColumn.ACCEL_STR }, }, }, Gtk.TreeViewColumn { title = "ID", { Gtk.CellRendererText {}, { text = BrowserColumn.ID }, }, }, }, }, Gtk.Box { orientation = 'VERTICAL', spacing = 8, border_width = 4, Gtk.Label { id = 'type_label', }, Gtk.Image { id = 'icon_image', }, Gtk.Label { id = 'accel_label', use_underline = true, }, Gtk.Label { id = 'macro_label', }, Gtk.Label { id = 'id_label', }, }, } } local display = { type_label = window.child.type_label, icon_image = window.child.icon_image, accel_label = window.child.accel_label, macro_label = window.child.macro_label, id_label = window.child.id_label, } local selection = window.child.treeview:get_selection() selection.mode = 'BROWSE' function selection:on_changed() local model, iter = self:get_selected() local view = self:get_tree_view() if model and iter then local row = model[iter] if row[BrowserColumn.SMALL_ICON] and row[BrowserColumn.LABEL] then display.type_label.label = "Icon and Item" elseif row[BrowserColumn.SMALL_ICON] then display.type_label.label = "Icon only" elseif row[BrowserColumn.LABEL] then display.type_label.label = "Item Only" else display.type_label.label = '' end display.id_label.label = row[BrowserColumn.ID] display.macro_label.label = row[BrowserColumn.MACRO] if row[BrowserColumn.LABEL] then display.accel_label.label = ("%s %s"):format( row[BrowserColumn.LABEL], row[BrowserColumn.ACCEL_STR] or '') else display.accel_label.label = '' end if row[BrowserColumn.SMALL_ICON] then -- Find the larget available icon size. local best_size, best_pixels = Gtk.IconSize.INVALID, 0 for _, size in ipairs(Gtk.IconFactory.lookup_default( row[BrowserColumn.ID]):get_sizes()) do local width, height = Gtk.IconSize.lookup(size) if width * height > best_pixels then best_pixels = width * height best_size = size end end display.icon_image.stock = row[BrowserColumn.ID] display.icon_image.icon_size = best_size else display.icon_image.pixbuf = nil end else display.type_label.label = "No selected item" display.macro_label.label = '' display.id_label.label = '' display.accel_label.label = '' display.icon_image.pixbuf = nil end end window:show_all() return window end, "Stock Item and Icon Browser", table.concat { [[This source code for this demo doesn't demonstrate anything ]], [[particularly useful in applications. The purpose of the "demo" ]], [[is just to provide a handy place to browse the available stock ]], [[icons and stock items.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-text-hypertext.lua000066400000000000000000000107531221440706400226760ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local Pango = lgi.Pango local window = Gtk.Window { title = "Hypertext", default_width = 450, default_height = 450, Gtk.ScrolledWindow { Gtk.TextView { id = 'textview', wrap_mode = 'WORD', }, }, } -- Sample hypertext content. local content = { intro = [[ Some text to show that simple [hypertext hypertext] can easily be realized with [tags tags]. ]], hypertext = [[ *hypertext:* machine-readable text that is not sequential but is organized so that related items of information are connected. [intro Go back] ]], tags = [[ A tag is an attribute that can be applied to some range of text. For example, a tag might be called "bold" and make the text inside the tag bold. However, the tag concept is more general than that; tags don't have to affect appearance. They can instead affect the behavior of mouse and key presses, "lock" a range of text so the user can't edit it, or countless other things. [intro Go back] ]], } local active_links local handlers = { ['^([^%[%*]+)'] = -- Plaintext. function(text) return text end, ['^%[(%w+) ([^%]]+)%]'] = -- Link. function(link, text) local tag = Gtk.TextTag { foreground = 'blue', underline = Pango.Underline.SINGLE, } active_links[tag] = link return text, tag end, ['^%*([^%*]+)%*'] = -- Bold text. function(text) return text, Gtk.TextTag { weight = Pango.Weight.BOLD, } end, } local function fill_page(page) local buffer = window.child.textview.buffer buffer.text = '' active_links = {} if not page then return end local iter = buffer:get_iter_at_offset(0) local pos = 1 repeat for pattern, handler in pairs(handlers) do local start, stop, m1, m2 = page:find(pattern, pos) if start then -- Extract next part of the text. local text, tag = handler(m1, m2) -- Add text into the buffer. start = iter:get_offset() buffer:insert(iter, text, -1) -- Apply tag, if available. if tag then buffer.tag_table:add(tag) buffer:apply_tag(tag, buffer:get_iter_at_offset(start), iter) end -- Prepare for the next iteration. pos = stop + 1 break end end until pos >= #page end local cursors = { [true] = Gdk.Cursor.new('HAND2'), [false] = Gdk.Cursor.new('XTERM'), } local hovering = false local function set_cursor_if_appropriate(view, x, y) local tags = view:get_iter_at_location(x, y):get_tags() local should_hover = false for i = 1, #tags do if active_links[tags[i]] then should_hover = true break end end if hovering ~= should_hover then hovering = should_hover view:get_window('TEXT'):set_cursor(cursors[hovering]) end end local textview = window.child.textview function textview:on_motion_notify_event(event) set_cursor_if_appropriate( self, self:window_to_buffer_coords('WIDGET', event.x, event.y)) return false end function textview:on_visibility_notify_event(event) local x, y = self.window:get_pointer() if x and y then set_cursor_if_appropriate( self, self:window_to_buffer_coords('WIDGET', x, y)) end return false end local function follow_if_link(view, iter) for _, tag in ipairs(iter:get_tags()) do if active_links[tag] then fill_page(content[active_links[tag]]) break end end end function textview:on_event_after(event) if event.type == 'BUTTON_RELEASE' and event.button.button == 1 then -- Don't follow link if anything is selected. local start, stop = self.buffer:get_selection_bounds() if not start or not stop or start:get_offset() == stop:get_offset() then follow_if_link(self, self:get_iter_at_location( self:window_to_buffer_coords( 'WIDGET', event.button.x, event.button.y))) end end end function textview:on_key_press_event(event) if event.keyval == Gdk.KEY_Return or event.keyval == Gdk.KEY_KP_Enter then follow_if_link( self, self.buffer:get_iter_at_mark(self.buffer:get_insert())) end return false end -- Initially fill the intro page. fill_page(content.intro) window:show_all() return window end, "Text Widget/Hypertext", table.concat { [[Usually, tags modify the appearance of text in the view, ]], [[e.g. making it bold or colored or underlined. But tags are not ]], [[restricted to appearance. They can also affect the behavior of ]], [[mouse and key presses, as this demo shows.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-text-multiview.lua000066400000000000000000000231351221440706400226650ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local Gdk = lgi.Gdk local Pango = lgi.Pango local GdkPixbuf = lgi.GdkPixbuf -- Create shared text buffer. local buffer = Gtk.TextBuffer { tag_table = Gtk.TextTagTable { -- Create a bunch of tags. Gtk.TextTag { name = 'heading', weight = Pango.Weight.BOLD, size = 15 * Pango.SCALE, }, Gtk.TextTag { name = 'italic', style = Pango.Style.ITALIC, }, Gtk.TextTag { name = 'bold', weight = Pango.Weight.BOLD, }, Gtk.TextTag { name = 'big', -- points times the Pango.SCALE factor size = 20 * Pango.SCALE, }, Gtk.TextTag { name = 'xx-small', scale = Pango.SCALE_XX_SMALL, }, Gtk.TextTag { name = 'x-large', scale = Pango.SCALE_X_LARGE, }, Gtk.TextTag { name = 'monospace', family = 'monospace', }, Gtk.TextTag { name = 'blue_foreground', foreground = 'blue', }, Gtk.TextTag { name = 'red_background', background = 'red', }, Gtk.TextTag { name = 'big_gap_before_line', pixels_above_lines = 30, }, Gtk.TextTag { name = 'big_gap_after_line', pixels_below_lines = 30, }, Gtk.TextTag { name = 'double_spaced_line', pixels_inside_wrap = 10, }, Gtk.TextTag { name = 'not_editable', editable = false, }, Gtk.TextTag { name = 'word_wrap', wrap_mode = 'WORD', }, Gtk.TextTag { name = 'char_wrap', wrap_mode = 'CHAR', }, Gtk.TextTag { name = 'no_wrap', wrap_mode = 'NONE', }, Gtk.TextTag { name = 'center', justification = 'CENTER', }, Gtk.TextTag { name = 'right_justify', justification = 'RIGHT', }, Gtk.TextTag { name = 'wide_margins', left_margin = 50, right_margin = 50, }, Gtk.TextTag { name = 'strikethrough', strikethrough = true, }, Gtk.TextTag { name = 'underline', underline = 'SINGLE', }, Gtk.TextTag { name = 'double_underline', underline = 'DOUBLE', }, Gtk.TextTag { name = 'superscript', rise = 10 * Pango.SCALE, -- 10 pixels size = 8 * Pango.SCALE, -- 8 points }, Gtk.TextTag { name = 'subscript', rise = -10 * Pango.SCALE, -- 10 pixels size = 8 * Pango.SCALE, -- 8 points }, Gtk.TextTag { name = 'rtl_quote', wrap_mode = 'WORD', direction = 'RTL', indent = 30, left_margin = 20, right_margin = 20, }, }, } local pixbuf = GdkPixbuf.Pixbuf.new_from_file( dir:get_child('gtk-logo-rgb.gif'):get_path()) pixbuf = pixbuf:scale_simple(32, 32, 'BILINEAR') local anchors = {} local iter = buffer:get_iter_at_offset(0) for _, item in ipairs { { [[ The text widget can display text with all kinds of nifty attributes. It also supports multiple views of the same buffer; this demo is showing the same buffer in two places. ]] }, { [[Font styles. ]], 'heading' }, { [[For example, you can have ]] }, { [[italic]], 'italic' }, { [[, ]] }, { [[bold]], 'bold' }, { [[, or ]] }, { [[monospace (typewriter)]], 'monospace' }, { [[, or ]] }, { [[big]], 'big' }, { [[ text. ]] }, { [[ It's best not to hardcode specific text sizes; you can use relative sizes as with CSS, such as ]] }, { [[xx-small]], 'xx-small' }, { [[ or ]] }, { [[x-large]], 'x-large' }, { [[ to ensure that your program properly adapts if the user changes the default font size. ]] }, { [[Colors. ]], 'heading' }, { [[Colors such as ]] }, { [[a blue foreground]], 'blue_foreground' }, { [[ or ]] }, { [[a red background]], 'red_background' }, { [[ or even ]] }, { [[a blue foreground on red background]], 'blue_foreground', 'red_background' }, { [[ (select that to read it) can be used. ]] }, { [[Underline, strikethrough and rise. ]], 'heading' }, { [[Strikethrough]], 'strikethrough' }, { [[, ]] }, { [[underline]], 'underline' }, { [[, ]] }, { [[double underline]], 'double_underline' }, { [[, ]] }, { [[superscript]], 'superscript' }, { [[, and ]] }, { [[subscript]], 'subscript' }, { [[ are all supported. ]] }, { [[Images. ]], 'heading' }, { [[The buffer can have images in it: ]] }, { pixbuf }, { pixbuf }, { pixbuf }, { [[ for example. ]] }, { [[Spacing. ]], 'heading' }, { [[You can adjust the amount of space before each line. ]] }, { [[This line has a whole lot of space before it. ]], 'big_gap_before_line', 'wide_margins' }, { [[You can also adjust the amount of space after each line; this line has a while lot of space after it ]], 'big_gap_after_line', 'wide_margins' }, { [[You can also adjust the amount of space between wrapped lines; this line has extra space between each wrapped line in the same paragraph. To show off wrapping some filler text: the quick brown fox jumped over the lazy dog. Blah blah blah blah blah blah blah blah blah. ]], 'double_spaced_line', 'wide_margins' }, { [[Editability. ]], 'heading' }, { [[This line is 'locked down' and can't be edited by the user - just try it! You can't delete this line. ]], 'not_editable' }, { [[Wrapping. ]], 'heading' }, { [[This line (and most of the others in this buffer) is word-wrapped, using the proper Unicode algorithm. Word wrap should work in all scripts and languages that GTK+ supports. Let's make this a long paragraph to demonstrate: blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah ]] }, { [[This line has character-based wrapping, and can wrap between any two character glyphs. Let's make this a long paragraph to demonstrate: blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah ]], 'char_wrap' }, { [[This line has all wrapping turned off, so it makes the horizontal scrollbar appear. ]], 'no_wrap' }, { [[Justification. ]], 'heading' }, { [[ This line has center justification ]], 'center' }, { [[This line has right jusitification]], 'right_justify' }, { [[ This line has big wide margins. Text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text ]], 'wide_margins' }, { [[Internationalization. ]], 'heading' }, { [[ You can put all sorts of Unicode text in the buffer. German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew ×©×œ×•× Japanese (日本語) The widget properly handles bidirectional text, word wrapping, DOS/UNIX/Unicode paragraph separators, grapheme boundaries, and so on using the Pango internationalization framework. Here's a word-wrapped quote in a right-to-left language: ]] }, { [[وقد بدأ ثلاث من أكثر المؤسسات تقدما ÙÙŠ شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت ÙÙŠ السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي ÙÙŠ بلدانها، ولكنها تتخصص ÙÙŠ خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« ÙÙŠ بوليÙيا. ]], 'rtl_quote' }, { [[You can put widgets in the buffer: Here s a button: ]] }, function() return Gtk.Button { label = "Click Me", } end, { [[ and a menu: ]] }, function() local combo = Gtk.ComboBoxText {} combo:append_text("Option 1") combo:append_text("Option 2") combo:append_text("Option 3") return combo end, { [[ and a scale: ]] }, function() local scale = Gtk.Scale { adjustment = Gtk.Adjustment { lower = 0, upper = 100, } } scale:set_size_request(70, -1) return scale end, { [[ and an animation: ]] }, function() return Gtk.Image { file = dir:get_child('floppybuddy.gif'):get_path() } end, { [[ finally a text entry: ]] }, function() return Gtk.Entry() end, { [[. This demo does not demonstrate all the Gtk.TextBuffer features; it leaves out, for example: invisible/hidden text, tab stops, application-drawn areas on the sides of the widget for displaying breakpoints and such...]] } } do if type(item) == 'function' then anchors[buffer:create_child_anchor(iter)] = item elseif type(item[1]) == 'string' then local offset = iter:get_offset() buffer:insert(iter, item[1], -1) for i = 2, #item do buffer:apply_tag_by_name( item[i], buffer:get_iter_at_offset(offset), iter) end elseif GdkPixbuf.Pixbuf:is_type_of(item[1]) then buffer:insert_pixbuf(iter, item[1]) end end -- Apply word_wrap tag to the whole buffer. buffer:apply_tag_by_name('word_wrap', buffer:get_bounds()) local window = Gtk.Window { title = "TextView", default_width = 450, default_height = 450, Gtk.Paned { orientation = 'VERTICAL', border_width = 5, Gtk.ScrolledWindow { Gtk.TextView { id = 'view1', buffer = buffer, }, }, Gtk.ScrolledWindow { Gtk.TextView { id = 'view2', buffer = buffer, } }, }, } -- Create and attach widgets to anchors. for _, view in pairs { window.child.view1, window.child.view2 } do for anchor, creator in pairs(anchors) do view:add_child_at_anchor(creator(), anchor) end end window:show_all() return window end, "Text Widget/Multiple Views", table.concat { [[The Gtk.TextView widget displays a Gtk.TextBuffer. One ]], [[Gtk.TextBuffer can be displayed by multiple Gtk.TextViews. ]], [[This demo has two views displaying a single buffer, and shows off ]], [[the widget's text formatting features.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-text-scrolltoend.lua000066400000000000000000000056371221440706400231770ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local Gtk = lgi.Gtk local window = Gtk.Window { title = "Automatic scrolling", default_width = 600, default_height = 400, Gtk.Box { orientation = 'HORIZONTAL', spacing = 6, homogeneous = true, Gtk.ScrolledWindow { Gtk.TextView { id = 'view1', expand = true, } }, Gtk.ScrolledWindow { Gtk.TextView { id = 'view2', expand = true, } }, }, } for i = 1, 2 do local view = window.child['view' .. i] local buffer = view.buffer local timer if i == 1 then -- If we want to scroll to the end, including horizontal -- scrolling, then we just create a mark with right gravity at -- the end of the buffer. It will stay at the end unless -- explicitely moved with Gtk.TextBuffer.move_mark(). local mark = buffer:create_mark(nil, buffer:get_end_iter(), false) local count = 0 timer = GLib.timeout_add( GLib.PRIORITY_DEFAULT, 50, function() -- Insert to the 'end' mark. buffer:insert(buffer:get_iter_at_mark(mark), '\n' .. (' '):rep(count) .. "Scroll to end scroll to end scroll to end " .."scroll to end ", -1) -- Scroll so that the mark is visible onscreen. view:scroll_mark_onscreen(mark) -- Move to the next column, or if we got too far, scroll -- back to left again. count = (count <= 150) and (count + 1) or 0 return true end) else -- If we want to scroll to the bottom, but not scroll -- horizontally, then an end mark won't do the job. Just use -- Gtk.TextView.scroll_mark_onscreen() explicitely when -- needed. local count = 0 local mark = buffer:create_mark(nil, buffer:get_end_iter(), true) timer = GLib.timeout_add( GLib.PRIORITY_DEFAULT, 100, function() -- Insert some text into the buffer. local iter = buffer:get_end_iter() buffer:insert(iter, '\n' .. (' '):rep(count) .. "Scroll to bottom scroll to bottom scroll to bottom " .."scroll to bottom ", -1) -- Move the iterator to the beginning of line, so we don't -- scroll in horizontal direction. iter:set_line_offset(0) -- Place mark at iter. buffer:move_mark(mark, iter) -- Scroll the mark onscreen. view:scroll_mark_onscreen(mark) -- Move to the next column, or if we got too far, scroll -- back to left again. count = (count <= 40) and (count + 1) or 0 return true end) end -- Make sure that the timer is destroyed when the view is destroyed too. function view:on_destroy() GLib.source_remove(timer) end end window:show_all() return window end, "Text Widget/Automatic scrolling", table.concat { [[This example demonstrates how to use the gravity of Gtk.TextMarks ]], [[to keep a text view scrolled to the bottom when appending text.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-treeview-editable.lua000066400000000000000000000102101221440706400232450ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local ItemColumn = { NUMBER = 1, PRODUCT = 2, YUMMY = 3, } local NumberColumn = { TEXT = 1, NUMBER = 2, } -- Fill store with initial items. local item_store = Gtk.ListStore.new { [ItemColumn.NUMBER] = GObject.Type.INT, [ItemColumn.PRODUCT] = GObject.Type.STRING, [ItemColumn.YUMMY] = GObject.Type.INT, } for _, item in ipairs { { [ItemColumn.NUMBER] = 3, [ItemColumn.PRODUCT] = "bottles of coke", [ItemColumn.YUMMY] = 20, }, { [ItemColumn.NUMBER] = 5, [ItemColumn.PRODUCT] = "packages of noodles", [ItemColumn.YUMMY] = 50, }, { [ItemColumn.NUMBER] = 2, [ItemColumn.PRODUCT] = "packages of chocolate chip cookies", [ItemColumn.YUMMY] = 90, }, { [ItemColumn.NUMBER] = 1, [ItemColumn.PRODUCT] = "can vanilla ice cream", [ItemColumn.YUMMY] = 60, }, { [ItemColumn.NUMBER] = 6, [ItemColumn.PRODUCT] = "eggs", [ItemColumn.YUMMY] = 10, }, } do item_store:append(item) end -- Fill store with numbers. local number_store = Gtk.ListStore.new { [NumberColumn.TEXT] = GObject.Type.INT, [NumberColumn.NUMBER] = GObject.Type.STRING, } for i = 1, 10 do number_store:append { [NumberColumn.TEXT] = i, [NumberColumn.NUMBER] = i, } end local window = Gtk.Window { title = "Shopping list", default_width = 320, default_height = 200, border_width = 5, Gtk.Box { orientation = 'VERTICAL', spacing = 5, Gtk.Label { label = "Shopping list (you can edit the cells!)", }, Gtk.ScrolledWindow { shadow_type = 'ETCHED_IN', expand = true, Gtk.TreeView { id = 'view', model = item_store, Gtk.TreeViewColumn { title = "Number", { Gtk.CellRendererCombo { id = 'number_renderer', model = number_store, text_column = NumberColumn.TEXT, has_entry = false, editable = true }, { text = ItemColumn.NUMBER, } }, }, Gtk.TreeViewColumn { title = "Product", { Gtk.CellRendererText { id = 'product_renderer', editable = true, }, { text = ItemColumn.PRODUCT, } } }, Gtk.TreeViewColumn { title = "Yummy", { Gtk.CellRendererProgress {}, { value = ItemColumn.YUMMY, }, } }, }, }, Gtk.Box { orientation = 'HORIZONTAL', spacing = 4, homogeneous = true, Gtk.Button { id = 'add', label = "Add item", }, Gtk.Button { id = 'remove', label = "Remove item", }, }, } } function window.child.number_renderer:on_edited(path_string, new_text) local path = Gtk.TreePath.new_from_string(path_string) item_store[path][ItemColumn.NUMBER] = new_text end function window.child.number_renderer:on_editing_started(editable, path) editable:set_row_separator_func( function(model, iter) return model:get_path(iter):get_indices()[1] == 5 end) end function window.child.product_renderer:on_edited(path_string, new_text) local path = Gtk.TreePath.new_from_string(path_string) item_store[path][ItemColumn.PRODUCT] = new_text end local selection = window.child.view:get_selection() selection.mode = 'SINGLE' function window.child.add:on_clicked() item_store:append { [ItemColumn.NUMBER] = 0, [ItemColumn.PRODUCT] = "Description here", [ItemColumn.YUMMY] = 50, } end function window.child.remove:on_clicked() local model, iter = selection:get_selected() if model and iter then model:remove(iter) end end window:show_all() return window end, "Tree View/Editable Cells", table.concat { [[This demo demonstrates the use of editable cells in a Gtk.TreeView. ]], [[If you're new to the Gtk.TreeView widgets and associates, look into ]], [[the Gtk.ListStore example first. It also shows how to use ]], [[the Gtk.CellRenderer::editing-started signal to do custom setup of ]], [[the editable widget. The cell renderers used in this demo are Gtk.CellRendererText, ]], [[Gtk.CellRendererCombo and GtkCell.RendererProgress.]] } lua-lgi-0.7.2/samples/gtk-demo/demo-treeview-liststore.lua000066400000000000000000000112351221440706400235340ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GLib = lgi.GLib local GObject = lgi.GObject local Gtk = lgi.Gtk local Column = { FIXED = 1, NUMBER = 2, SEVERITY = 3, DESCRIPTION = 4, PULSE = 5, ICON = 6, ACTIVE = 7, SENSITIVE = 8, } -- Create the list store. local store = Gtk.ListStore.new { [Column.FIXED] = GObject.Type.BOOLEAN, [Column.NUMBER] = GObject.Type.UINT, [Column.SEVERITY] = GObject.Type.STRING, [Column.DESCRIPTION] = GObject.Type.STRING, [Column.PULSE] = GObject.Type.UINT, [Column.ICON] = GObject.Type.STRING, [Column.ACTIVE] = GObject.Type.BOOLEAN, [Column.SENSITIVE] = GObject.Type.BOOLEAN, } -- Populate it with sample data. for i, item in ipairs { { false, 60482, "Normal", "scrollable notebooks and hidden tabs" }, { false, 60620, "Critical", "gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe" }, { false, 50214, "Major", "Xft support does not clean up correctly" }, { true, 52877, "Major", "GtkFileSelection needs a refresh method. " }, { false, 56070, "Normal", "Can't click button after setting in sensitive" }, { true, 56355, "Normal", "GtkLabel - Not all changes propagate correctly" }, { false, 50055, "Normal", "Rework width/height computations for TreeView" }, { false, 58278, "Normal", "gtk_dialog_set_response_sensitive () doesn't work" }, { false, 55767, "Normal", "Getters for all setters" }, { false, 56925, "Normal", "Gtkcalender size" }, { false, 56221, "Normal", "Selectable label needs right-click copy menu" }, { true, 50939, "Normal", "Add shift clicking to GtkTextView" }, { false, 6112, "Enhancement","netscape-like collapsable toolbars" }, { false, 1, "Normal", "First bug :=)" }, } do if i == 2 or i == 4 then item[Column.ICON] = 'battery-caution-charging-symbolic' end item[Column.SENSITIVE] = (i ~= 4) store:append(item) end local window = Gtk.Window { title = "Gtk.ListStore demo", default_width = 280, default_height = 250, border_width = 8, Gtk.Box { orientation = 'VERTICAL', spacing = 8, Gtk.Label { label = "This is the bug list (note: not based on real data, " .. "it would be nice to have a nice ODBC interface to bugzilla " .. "or so, though" }, Gtk.ScrolledWindow { shadow_type = 'ETCHED_IN', hscrollbar_policy = 'NEVER', expand = true, Gtk.TreeView { id = 'view', model = store, Gtk.TreeViewColumn { title = "Fixed?", sizing = 'FIXED', fixed_width = 50, { Gtk.CellRendererToggle { id = 'fixed_renderer' }, { active = Column.FIXED }, }, }, Gtk.TreeViewColumn { title = "Bug number", sort_column_id = Column.NUMBER - 1, { Gtk.CellRendererText {}, { text = Column.NUMBER }, }, }, Gtk.TreeViewColumn { title = "Severity", sort_column_id = Column.SEVERITY - 1, { Gtk.CellRendererText {}, { text = Column.SEVERITY }, }, }, Gtk.TreeViewColumn { title = "Description", sort_column_id = Column.DESCRIPTION - 1, { Gtk.CellRendererText {}, { text = Column.DESCRIPTION }, }, }, Gtk.TreeViewColumn { title = "Spinning", sort_column_id = Column.PULSE - 1, { Gtk.CellRendererSpinner {}, { pulse = Column.PULSE, active = Column.ACTIVE }, }, }, Gtk.TreeViewColumn { title = "Symbolic icon", sort_column_id = Column.ICON - 1, { Gtk.CellRendererPixbuf { follow_state = true }, { icon_name = Column.ICON, sensitive = Column.SENSITIVE, }, }, }, }, }, }, } function window.child.fixed_renderer:on_toggled(path_str) local path = Gtk.TreePath.new_from_string(path_str) -- Change current value. store[path][Column.FIXED] = not store[path][Column.FIXED] end -- Add 'animation' for the spinner. local timer = GLib.timeout_add( GLib.PRIORITY_DEFAULT, 80, function() local row = store[store:get_iter_first()] local pulse = row[Column.PULSE] pulse = (pulse > 32768) and 0 or pulse + 1 row[Column.PULSE] = pulse row[Column.ACTIVE] = true return true end) function window:on_destroy() GLib.source_remove(timer) end window:show_all() return window end, "Tree View/List Store", table.concat { [[The Gtk.ListStore is used to store data in list form, to be used later ]], [[on by a Gtk.TreeView to display it. This demo builds a simple ]], [[Gtk.ListStore and displays it. See the Stock Browser demo for a more ]], [[advanced example.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-treeview-treestore.lua000066400000000000000000000137631221440706400235300ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.Gtk local Column = { HOLIDAY_NAME = 1, ALEX = 2, HAVOC = 3, TIM = 4, OWEN = 5, DAVE = 6, VISIBLE = 7, WORLD = 8, } local store = Gtk.TreeStore.new { [Column.HOLIDAY_NAME] = GObject.Type.STRING, [Column.ALEX] = GObject.Type.BOOLEAN, [Column.HAVOC] = GObject.Type.BOOLEAN, [Column.TIM] = GObject.Type.BOOLEAN, [Column.OWEN] = GObject.Type.BOOLEAN, [Column.DAVE] = GObject.Type.BOOLEAN, [Column.VISIBLE] = GObject.Type.BOOLEAN, [Column.WORLD] = GObject.Type.BOOLEAN, } for _, month in ipairs { { "January", { { "New Years Day", true, true, true, true, false, true, }, { "Presidential Inauguration", false, true, false, true, false, false }, {"Martin Luther King Jr. day", false, true, false, true, false, false }, } }, { "February", { { "Presidents' Day", false, true, false, true, false, false }, { "Groundhog Day", false, false, false, false, false, false }, { "Valentine's Day", false, false, false, false, true, true }, } }, { "March", { { "National Tree Planting Day", false, false, false, false, false, false }, { "St Patrick's Day", false, false, false, false, false, true }, } }, { "April", { { "April Fools' Day", false, false, false, false, false, true }, { "Army Day", false, false, false, false, false, false }, { "Earth Day", false, false, false, false, false, true }, { "Administrative Professionals' Day", false, false, false, false, false, false }, } }, { "May", { { "Nurses' Day", false, false, false, false, false, false }, { "National Day of Prayer", false, false, false, false, false, false }, { "Mothers' Day", false, false, false, false, false, true }, { "Armed Forces Day", false, false, false, false, false, false }, { "Memorial Day", true, true, true, true, false, true }, } }, { "June", { { "June Fathers' Day", false, false, false, false, false, true }, { "Juneteenth (Liberation of Slaves)", false, false, false, false, false, false }, { "Flag Day", false, true, false, true, false, false }, } }, { "July", { { "Parents' Day", false, false, false, false, false, true }, { "Independence Day", false, true, false, true, false, false }, } }, { "August", { { "Air Force Day", false, false, false, false, false, false }, { "Coast Guard Day", false, false, false, false, false, false }, { "Friendship Day", false, false, false, false, false, false }, } }, { "September", { { "Grandparents' Day", false, false, false, false, false, true }, { "Citizenship Day or Constitution Day", false, false, false, false, false, false }, { "Labor Day", true, true, true, true, false, true }, } }, { "October", { { "National Children's Day", false, false, false, false, false, false }, { "Bosses' Day", false, false, false, false, false, false }, { "Sweetest Day", false, false, false, false, false, false }, { "Mother-in-Law's Day", false, false, false, false, false, false }, { "Navy Day", false, false, false, false, false, false }, { "Columbus Day", false, true, false, true, false, false }, { "Halloween", false, false, false, false, false, true }, } }, { "November", { { "Marine Corps Day", false, false, false, false, false, false }, { "Veterans' Day", true, true, true, true, false, true }, { "Thanksgiving", false, true, false, true, false, false }, } }, { "December", { { "Pearl Harbor Remembrance Day", false, false, false, false, false, false }, { "Christmas", true, true, true, true, false, true }, { "Kwanzaa", false, false, false, false, false, false }, } }, } do local iter = store:append(nil, { [Column.HOLIDAY_NAME] = month[1] }) for _, holiday in ipairs(month[2]) do store:append(iter, { [Column.HOLIDAY_NAME] = holiday[1], [Column.ALEX] = holiday[2], [Column.HAVOC] = holiday[3], [Column.TIM] = holiday[4], [Column.OWEN] = holiday[5], [Column.DAVE] = holiday[6], [Column.VISIBLE] = true, [Column.WORLD] = holiday[7], }) end end local window = Gtk.Window { title = "Card planning sheet", default_width = 650, default_height = 400, Gtk.Box { orientation = 'VERTICAL', spacing = 8, border_width = 8, Gtk.Label { label = "Jonathan's Holiday Card Planning Sheet", }, Gtk.ScrolledWindow { shadow_type = 'ETCHED_IN', expand = true, Gtk.TreeView { id = 'view', model = store, rules_hint = true, Gtk.TreeViewColumn { title = "Holiday", { Gtk.CellRendererText {}, { text = Column.HOLIDAY_NAME } }, }, }, }, } } local view = window.child.view local selection = view:get_selection() selection.mode = 'MULTIPLE' -- Add columns programmatically. for _, info in ipairs { { Column.ALEX, "Alex", true }, { Column.HAVOC, "Havoc" }, { Column.TIM, "Tim", true }, { Column.OWEN, "Owen" }, { Column.DAVE, "Dave" }, } do -- Prepare renderer and connect its on_toggled signal. local col = info[1] local renderer = Gtk.CellRendererToggle { xalign = 0, } function renderer:on_toggled(path_str) local row = store[Gtk.TreePath.new_from_string(path_str)] row[col] = not row[col] end -- Add new column to the view. view:append_column( Gtk.TreeViewColumn { title = info[2], sizing = 'FIXED', fixed_width = 50, clickable = true, { renderer, { active = col, visible = Column.VISIBLE, activatable = info[3] and Column.WORLD or nil, } } }) end -- Expand all rows after treeview has been realized. view.on_realize = view.expand_all window:show_all() return window end, "Tree View/Tree Store", table.concat { [[The Gtk.TreeStore is used to store data in tree form, to be used later ]], [[on by a Gtk.TreeView to display it. This demo builds a simple ]], [[Gtk.TreeStore and displays it. If you're new to the Gtk.TreeView ]], [[widgets and associates, look into the Gtk.ListStore example first.]], } lua-lgi-0.7.2/samples/gtk-demo/demo-uimanager.lua000066400000000000000000000117201221440706400216230ustar00rootroot00000000000000return function(parent, dir) local lgi = require 'lgi' local Gtk = lgi.Gtk local log = lgi.log.domain('uimanager-demo') local function activate_action(action) log.message('Action "%s" activated', action.name) end local function activate_radio_action(action) log.message('Radio action "%s" selected', action.name) end local COLOR = { RED = 1, GREEN = 2, BLUE = 3 } local SHAPE = { SQUARE = 1, RECTANGLE = 2, OVAL = 3 } local actions = Gtk.ActionGroup { name = 'Actions', Gtk.Action { name = 'FileMenu', label = "_File" }, Gtk.Action { name = 'PreferencesMenu', label = "_Preferences" }, Gtk.Action { name = 'ColorMenu', label = "_Color" }, Gtk.Action { name = 'ShapeMenu', label = "_Shape" }, Gtk.Action { name = 'HelpMenu', label = "_Help" }, { Gtk.Action { name = 'New', stock_id = Gtk.STOCK_NEW, label = "_New", tooltip = "Create a new file", on_activate = activate_action, }, accelerator = 'N', }, { Gtk.Action { name = 'Open', stock_id = Gtk.STOCK_OPEN, label = "_Open", tooltip = "Open a file", on_activate = activate_action, }, accelerator = 'O', }, { Gtk.Action { name = 'Save', stock_id = Gtk.STOCK_SAVE, label = "_Save", tooltip = "Save current file", on_activate = activate_action, }, accelerator = 'S', }, Gtk.Action { name = 'SaveAs', stock_id = Gtk.STOCK_SAVE, label = "Save _As...", tooltip = "Save to a file", on_activate = activate_action, }, { Gtk.Action { name = 'Quit', stock_id = Gtk.STOCK_QUIT, label = "_Quit", tooltip = "Quit", on_activate = activate_action, }, accelerator = 'Q', }, { Gtk.Action { name = 'About', stock_id = Gtk.STOCK_ABOUT, label = "_About", tooltip = "About", on_activate = activate_action, }, accelerator = 'A', }, Gtk.Action { name = 'Logo', stock_id = 'demo-gtk-logo', tooltip = "GTK+", on_activate = activate_action, }, { Gtk.ToggleAction { name = 'Bold', stock_id = Gtk.STOCK_BOLD, label = "_Bold", tooltip = "Bold", active = true, on_activate = activate_action }, accelerator = "B", }, { { Gtk.RadioAction { name = 'Red', label = "_Red", tooltip = "Blood", value = COLOR.RED, active = true, }, accelerator = 'R', }, { Gtk.RadioAction { name = 'Green', label = "_Green", tooltip = "Grass", value = COLOR.GREEN }, accelerator = 'G', }, { Gtk.RadioAction { name = 'Blue', label = "_Blue", tooltip = "Sky", value = COLOR.BLUE }, accelerator = 'B', }, on_change = activate_radio_action, }, { { Gtk.RadioAction { name = 'Square', label = "_Square", tooltip = "Square", value = SHAPE.SQUARE, }, accelerator = 'S', }, { Gtk.RadioAction { name = 'Rectangle', label = "_Rectangle", tooltip = "Rectangle", value = SHAPE.RECTANGLE }, accelerator = 'R', }, { Gtk.RadioAction { name = 'Oval', label = "_Oval", tooltip = "Oval", value = SHAPE.OVAL, active = true }, accelerator = 'O', }, on_change = activate_radio_action, }, } local ui = Gtk.UIManager() ui:insert_action_group(actions, 0) local ok, err = ui:add_ui_from_string( [[ ]], -1) if not ok then log.message('building menus failed: %s', err) end local window = Gtk.Window { title = "UI Manager", Gtk.Box { orientation = 'VERTICAL', ui:get_widget('/MenuBar'), Gtk.Label { id = 'label', label = "Type\n\n to start", halign = 'CENTER', valign = 'CENTER', expand = true, }, Gtk.Separator { orientation = 'HORIZONTAL', }, Gtk.Box { orientation = 'VERTICAL', spacing = 10, border_width = 10, Gtk.Button { id = 'close', label = "close", can_default = true, }, }, }, } window:add_accel_group(ui:get_accel_group()) function window.child.close:on_clicked() window:destroy() end window.child.close:grab_default() window.child.label:set_size_request(200, 200) window:show_all() return window end, "UI Manager", table.concat { [[The Gtk.UIManager object allows the easy creation of menus from ]], [[an array of actions and a description of the menu hierarchy.]], } lua-lgi-0.7.2/samples/gtk-demo/demo.ui000066400000000000000000000276111221440706400175170ustar00rootroot00000000000000 John Doe 25 This is the John Doe row Mary Unknown 50 This is the Mary Unknown row Copy Copy selected object into the clipboard gtk-copy Cut Cut selected object into the clipboard gtk-cut EditMenu _Edit FileMenu _File New Create a new file gtk-new Open Open a file gtk-open Paste Paste object from the Clipboard gtk-paste Quit Quit the program gtk-quit Save True Save a file gtk-save SaveAs Save with a different name gtk-save-as HelpMenu _Help About gtk-about GtkBuilder demo 250 440 GtkBuilder demo True True The menubar False True The toolbar False 1 automatic in True automatic True liststore1 3 Name list A list of person with name, surname and age columns Name 0 Surname 1 Age 2 2 True False 3 lua-lgi-0.7.2/samples/gtk-demo/floppybuddy.gif000066400000000000000000000121401221440706400212530ustar00rootroot00000000000000GIF89aPF÷€  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ãã‚‚‚ƒƒƒ„„„………†††‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’’’“““”””•••–––———˜˜˜™™™ššš›››œœœžžžŸŸŸ   ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦ÿ¨¨¨ÿÿ=v{ÿ«««¬¬¬­­­®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿¸ÂÙÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááâââãããäääåååæææçççèèèéééêêêëëëìììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ!ÿ NETSCAPE2.0è!ù €,L>ü H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²dA(Sª\Ér¥É…NjI“æÌ— cÊ JÏž@ƒöü©ó¦H ‹þŠ2hJ§2rD)@*0£.µšª©O®[µvDÙ•@ª³Xsjjõé×¶lÅ6$æÙ«wÓÒ5¨”mW¯)»ÆÝ9- ½Í¢Í{ø,ÒEgúu8ìÎÇ Ó5|’®b¼‹Œ¼ô­S¯C£J%ˆx3è«|C¿f ™´ÐÛ¸Ic¨¹qhº»q}vmÛB—N­•êÀÏÐóþ-½8çª(U/g»ysêûÖ_þ9¼qáÙµã^?¸9yó³ßï‹>²döëí§¾|pÞó§_Mª6Ó~ÏÁ‡ÖÏ•‡vé(á„Þ„`‚.ä}õ W!*IøØ…¾õçІ£9gßNÀ´èâ‹ÀðÇúAÈškhq¨áƒ®8SŒ)ÁãŒ5ÚHg¡f>$JBÊH£L:×àƒmÜh:‰QIeŠô!I‘–6 $˜0JY$dH¢X‘™'u¹¦“mŠ©Ah긑š*…9åž|j’šB¾è昉aéÑ€x&Úbˆ„âÄåe1aJ„Yzi… véiŠš–J¢§¦¦:*©”©¸êA*=äÒ«°žª­´ç®¹ê𔕽ò,B¼k$±ÃKªO9Ūl}<ëWL%‹*QÉMËÖi¯.WÚ~H¡†šS•;R¸Âáçìvç‘®»Õ¶;îm_2xn~)Á.÷ïµÉåkn¼2zk0Áõê À.9,oÄ[.ºÏf¬ñÆwìñÇ#!ù €,L>ü H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²dA(Sª\Ér¥É…NjI“æÌ— cÊ JÏž@ƒöü©ó&΃EE4eS™Fž„ª@ªTL}ZÅ 4©TƒI»bÍš’ëPª vèX¢(ÍúDËÀÕµj7)Ö©V«U©¨{×nªµ÷*ýÛ4ëYºóR{÷êáœ5Á*ʹ³âÁ ãµ,šh‚q ¶|PJ¨|…’]üx'ÊФsW¾Z÷êË_Sí¬•øÞ™­'[Ö}˜uä«[[Eì%ìØÄ_Où|9s¬ûÏ¥.PøðìÚasÇí½¹sƒ†ÛSW¹½¦ýú¼Æo8yèý’•gÞuhà`ë ´ŸwÔ%¤V€"h röY·]„ìÉ—Öƒ¨ñvÜNÀ„(âˆÀðÇÇ–àd”‘Ö`]&øáL%¦Db‰'¦\~ rуx™vڌԈÒ&¢x!†ÿAjµFd("™ã’6èãDP¾8%JU’˜¤Ž¨q¤E[¢V`‘`)æ•êÁ×eH_Úø¦’qÊy&[kÞx'™¥éQŠGú)"}y~åš`1Uh!…;)ZÞ„”NèNŽfê’¤šv*i„Ú÷éI+¤Ҩšñhꥄ¨–Š«¨Vk‡³Žêjª±*t뎵¶Ê¬›æ*+Od!UÜ_½’D–lÆvÕ§²5†`u]Ñ6”kØŽ4­µ²¡è-·M¡œ²Ôf—Ò·Žyfb²«’¸¢˜nWâJ5ï¹Ó¢æвµù•cøÂ$¯Kì~͵n›­° 7ìðÃG,±T!þ’This GIF file was assembled by CDavis with GIF Construction Set from: Alchemy Mindworks Inc. P.O. Box 500 Beeton, Ontario L0G 1A0 CANADA. !ù €,L>ü H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²dA(Sª\Ér¥É…NjI“æÌ— cÊ JÏž@ƒöü©ó¦H ‹þŠ2hJ§2rD)@*0£.µšª©O®[µvDÙ•@ª³Xsjjõé×¶lÅ6$æÙ«wÓÒ5¨”mW¯)»ÆÝ9- ½Í¢Í{ø,ÒEgúu8ìÎÇ Ó5|’®b¼‹Œ¼ô­S¯C£J%ˆx3è«|C¿f ™´ÐÛ¸Ic¨¹qhº»q}vmÛB—N­•êÀÏÐóþ-½8çª(U/g»ysêûÖ_þ9¼qáÙµã^?¸9yó³ßï‹>²döëí§¾|pÞó§_Mª6Ó~ÏÁ‡ÖÏ•‡vé(á„Þ„`‚.ä}õ W!*IøØ…¾õçІ£9gßNÀ´èâ‹ÀðÇúAÈškhq¨áƒ®8SŒ)ÁãŒ5ÚHg¡f>$JBÊH£L:×àƒmÜh:‰QIeŠô!I‘–6 $˜0JY$dH¢X‘™'u¹¦“mŠ©Ah긑š*…9åž|j’šB¾è昉aéÑ€x&Úbˆ„âÄåe1aJ„Yzi… véiŠš–J¢§¦¦:*©”©¸êA*=äÒ«°žª­´ç®¹ê𔕽ò,B¼k$±ÃKªO9Ūl}<ëWL%‹*QÉMËÖi¯.WÚ~H¡†šS•;R¸Âáçìvç‘®»Õ¶;îm_2xn~)Á.÷ïµÉåkn¼2zk0Áõê À.9,oÄ[.ºÏf¬ñÆwìñÇ#!ù €,L>ü H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²dA(Sª\Ér¥É…NjI“æÌ— cÊ JÏž@ƒöü©ó&΃EE4eS™Fž„ª@ªTL}ZÅ 4©TƒI»bÍš’ëPª vèX¢(ÍúDËÀÕµj7)Ö©V«U©¨{×nªµ÷*ýÛ4ëYºóR{÷êáœ5Á*ʹ³âÁ ãµ,šh‚q ¶|PJ¨|…’]üx'ÊФsW¾Z÷êË_Sí¬•øÞ™­'[Ö}˜uä«[[Eì%ìØÄ_Où|9s¬ûÏ¥.PøðìÚasÇí½¹sƒ†ÛSW¹½¦ýú¼Æo8yèý’•gÞuhà`ë ´ŸwÔ%¤V€"h röY·]„ìÉ—Öƒ¨ñvÜNÀ„(âˆÀðÇÇ–àd”‘Ö`]&øáL%¦Db‰'¦\~ rуx™vڌԈÒ&¢x!†ÿAjµFd("™ã’6èãDP¾8%JU’˜¤Ž¨q¤E[¢V`‘`)æ•êÁ×eH_Úø¦’qÊy&[kÞx'™¥éQŠGú)"}y~åš`1Uh!…;)ZÞ„”NèNŽfê’¤šv*i„Ú÷éI+¤Ҩšñhꥄ¨–Š«¨Vk‡³Žêjª±*t뎵¶Ê¬›æ*+Od!UÜ_½’D–lÆvÕ§²5†`u]Ñ6”kØŽ4­µ²¡è-·M¡œ²Ôf—Ò·Žyfb²«’¸¢˜nWâJ5ï¹Ó¢æвµù•cøÂ$¯Kì~͵n›­° 7ìðÃG,±T!þThis space for rent...!ù €,L>ü H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²dA(Sª\Ér¥É…NjI“æÌ— cÊ JÏž@ƒöü©ó¦H ‹þŠ2hJ§2rD)@*0£.µšª©O®[µvDÙ•@ª³Xsjjõé×¶lÅ6$æÙ«wÓÒ5¨”mW¯)»ÆÝ9- ½Í¢Í{ø,ÒEgúu8ìÎÇ Ó5|’®b¼‹Œ¼ô­S¯C£J%ˆx3è«|C¿f ™´ÐÛ¸Ic¨¹qhº»q}vmÛB—N­•êÀÏÐóþ-½8çª(U/g»ysêûÖ_þ9¼qáÙµã^?¸9yó³ßï‹>²döëí§¾|pÞó§_Mª6Ó~ÏÁ‡ÖÏ•‡vé(á„Þ„`‚.ä}õ W!*IøØ…¾õçІ£9gßNÀ´èâ‹ÀðÇúAÈškhq¨áƒ®8SŒ)ÁãŒ5ÚHg¡f>$JBÊH£L:×àƒmÜh:‰QIeŠô!I‘–6 $˜0JY$dH¢X‘™'u¹¦“mŠ©Ah긑š*…9åž|j’šB¾è昉aéÑ€x&Úbˆ„âÄåe1aJ„Yzi… véiŠš–J¢§¦¦:*©”©¸êA*=äÒ«°žª­´ç®¹ê𔕽ò,B¼k$±ÃKªO9Ūl}<ëWL%‹*QÉMËÖi¯.WÚ~H¡†šS•;R¸Âáçìvç‘®»Õ¶;îm_2xn~)Á.÷ïµÉåkn¼2zk0Áõê À.9,oÄ[.ºÏf¬ñÆwìñÇ#!ù €,L>ü H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²dA(Sª\Ér¥É…NjI“æÌ— cÊ JÏž@ƒöü©ó&΃EE4eS™Fž„ª@ªTL}ZÅ 4©TƒI»bÍš’ëPª vèX¢(ÍúDËÀÕµj7)Ö©V«U©¨{×nªµ÷*ýÛ4ëYºóR{÷êáœ5Á*ʹ³âÁ ãµ,šh‚q ¶|PJ¨|…’]üx'ÊФsW¾Z÷êË_Sí¬•øÞ™­'[Ö}˜uä«[[Eì%ìØÄ_Où|9s¬ûÏ¥.PøðìÚasÇí½¹sƒ†ÛSW¹½¦ýú¼Æo8yèý’•gÞuhà`ë ´ŸwÔ%¤V€"h röY·]„ìÉ—Öƒ¨ñvÜNÀ„(âˆÀðÇÇ–àd”‘Ö`]&øáL%¦Db‰'¦\~ rуx™vڌԈÒ&¢x!†ÿAjµFd("™ã’6èãDP¾8%JU’˜¤Ž¨q¤E[¢V`‘`)æ•êÁ×eH_Úø¦’qÊy&[kÞx'™¥éQŠGú)"}y~åš`1Uh!…;)ZÞ„”NèNŽfê’¤šv*i„Ú÷éI+¤Ҩšñhꥄ¨–Š«¨Vk‡³Žêjª±*t뎵¶Ê¬›æ*+Od!UÜ_½’D–lÆvÕ§²5†`u]Ñ6”kØŽ4­µ²¡è-·M¡œ²Ôf—Ò·Žyfb²«’¸¢˜nWâJ5ï¹Ó¢æвµù•cøÂ$¯Kì~͵n›­° 7ìðÃG,±T!þïThis GIF file was assembled with GIF Construction Set from: Alchemy Mindworks Inc. P.O. Box 500 Beeton, Ontario L0G 1A0 CANADA. This comment block will not appear in files created with a registered version of GIF Construction Set;lua-lgi-0.7.2/samples/gtk-demo/gnome-applets.png000066400000000000000000000060221221440706400215060ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA± üabKGDÿÿÿ ½§“ pHYs``zxEtIMEÐ (–ªŠ IDATxÚíšYŒ×u†¿Ú«»§»g㢤9Ò–dk¡MÑ–I¦@Ó’F² 'P q^b=Fâ ûI6ò”<YÀÉk Iˆ Ã@LÙ¢hQ#ÒÒˆÔˆξw³»ºö5}‹(·‡Ãe˜<)à  =·«þÿžÿœ{î¹#qs—$L.ÜK…¿gK ÷·ü’v\&¬H aùý-'r#äpU˜V¸W csÀ1,'“þoÈg])€6„é˽‘Ï~ „@Ðc±°[â õ: (à&PÌOÝsp÷3_:z|dxèpÉ4È’4'±á:NàØöZ³eM¯®o¾}ú½÷ߘ]XYïóÅ3ãB|üy@.€Ï—Ÿ|ìsû¿ö•§¿yûÞ½_“$‰,ËH’˜(Š ‚ß÷ñ<ϱ±]ÛvX[ßøÉÙ>úÑGç/nÁÉN(×9ó&P*/ÿ»üüÄñíÞ=r¿a–0Œº®£ëŠª **²,!!‘IR–B–¡ªò§†û_쯹³ +baGRR¶/dS*ÿ·?ø«{ïýÄ·+}5Õ,•)•ʦ‰n¨ª†ªj]ðR7² Ò4%Mb’$%NRUS¥/ì®Ì.¬¾ÙCâ–È¥£ç³ÿwóò÷ÆÆö}£Tî£T*S®”)•K覉a訪Š,É¿$’4!‰câ8!Šc’8¤‡ëåÅ•Í;%¡l3ûj>û?øþwÿäÀ»ÿ¼\©R*•)U*”ÊeÌRÃ4Q5EQd².ø$é‚•ð}Ÿ(މã˜8ŽˆÂˆLÊ•Kzk}³}¦^o˜„| ÚÓÇž¿{ß_꺎¦i¦iš˜å åJõŠ™å ¦ib˜š¦Ñ¯‚”¡êЬ )2²¬¢¨ ²,S)›ß®Ò°t+üNö9vôñoišnÊ²Š¢¨hš†¦F Ã,Q*WɃYӻ໱Ð/Ë Š,Q®T”î½$uM–es°¿ï;B¦ê6x®›@±Lкdp°ÿÅî edYñ)Ë2ªªc–úPUýÊwH2ùxI’d Y’»™ª\'Nº*‘$©û2Yz±RÖïr½a/ÈÛ¥Ï'}x"K3²,#ËR²,ƒ,íf–4%ŽC|Ï&ŽÃ+ß!Æåã³4#ÍR$Ecy­I(Wøpz«ã`Ù®RíÓ¿*2Ý {AÞ¦XS«ÕÊ#išt2‰ºEDa@x¾‡çv| ðˆÂ€(êŽKÓ˜$‰IÓ„4MI’Çqyá…xüèqÖ7/Ó±]TM£R.?ôÝŒämô¯jŠüÉ8ê®°QÔøÝ•Öw\§sÅ|×Á÷}¿K" C¢(&ŽºÙÈj5Ñ4z—^z‰;Flj☡¡a\Ï¿è/xAÚ‰®H“dO…A@„¾‹ï{xŽƒëØ¸¶…ݱpm ×±ñß÷|·;>£( ˜››g}}3gÞ£^ïgâ¹ç¨Vð\›,Í€ r£IÝ®úŒ¢Ðô=ïÊ +Ë]¾išE!ªª‘×B¹¼ßÅs=<ÏízÊó‚ÇõHâÿxí ‡wqäÈþú‡/£ëŠ¢*À° X¢àK®g]Ø.`$ÏóƒÀï‚Y_ßä¿Nüš8ΰ;mÛ¢cµéXÝOǶÄ÷Žcã:.žçŠø高øžËüü¿9u’0 ˜xî9ÒTUM€A &d¤]o0÷z ¸äâÜRóàø¾Û$I¢i9œýà<©¤òÈáдnž¿V5êx>—–™_fßþýì“eNœøtާŽ=Í/~þSJ†‰¨ uDµ*]Ë ÊUÖ(ùìCǧ/ÌÜÖ±]‚žxž³gÏ"e]ï¦iJŠ rñ|×qXZ\âÌÔ4—æ?È“?J…LNž& <×feeOßÿ‹ óÆek h 9b3tM]Í)Üq×þÿð…?:ôãþfæù³ïaee…ŸýçëŒÞ¹—O#IRV×6(—L.·ÚX–EÛ² ‚ñxæÙϳ²4χS°´¼€m;ŒŽÞN¬,^âÈçá×_KóŠW”í†À]kû©l³SSSkjæýÙ‰çYZ^å GŸâ¶½{ù‡ü'—ÛL›Æó|6M66[ôUk<ðÀƒ<úØcÿÒãÝSorñâǬo¬awl‚0$cöìÆ45ÖÖ79vü™ìäÉ“«À²ðBGr|-[y ßGËíÍÏOÿ¼Ùl›úxÅÅÆÇ0>>Îî]CܵŒGŽf×®aÂÀ'Í2,Ëbò·y·cÑhlà!žïá{>A!I…ƒÃÃ8V‹™ù¥ö=÷=X6Mó“¾ï¿½Å{Û8Ø*f9 xÿüÅWJ%ýI×q´Öåˬ­®ò¹‡?ÿþäÒ4¦ÝXãö=à I,ÌÏ’¥)aF1AAÅ1iS2M¢8¥¿V#ô¼ìÜôìlËþ÷êÄÄľW_}õN`¦ÐénvC“×C†ï‡Š¥¾ŠyŸë‡È²ÂÚê çΟ'=š–ÕÂî´ñ=? ñÿʪì!q#Ë2%䯯J¥ÆÐàozw}yus©Ùl^[[[«†aø« äëÙR–›­N§Z1ïlµÛ{² &'ß%ŠBÈRü Ä45â$&ŠÅ¬ûq% ’$¡© }• õZZµŠ¦›\º4c>{þ`˲fFFF5‹ÀA (lvnzSo}Í–mÉÄw¾szrÀ¶;¨ªBÿAà¡k*ª"“$ i’"+2Šª ©*¦aP¯Õì¯Ó_¯£éKË«ö/ßšœÎÁ–ã8‹Õju¤Õj'F!³›%{¡T;¶çÊ%IÒUU¦Z­aª*ÓW)£ë:•rÓ0é«”©×ê R«V©Öjhºž½õö鿩ɩ1Ã9ÐnµZoO¿>.´^n(ˆ‹íÁHôpZÀ°FÉFûòm»‡²f£Q¾{l CM쯡j*º¦#ÉJwK©t72ïœy?üÍäÔ\ÇvÛâ™¶ ‘›'´ÿ ðmàõë©…¶# öÐVå,ˆ¦gç C3TEÙsï½uM×ÕáÁ!YQU)#ËÚm+_Üˆææ—Üóæ?%! ¯@ ÓCÀ^>üðãkõ¤ëÈR†(u÷cÀ3À—óâ¥e‘·Õž¼]lðÊÀA¡í¬“ë_x¸)nˆ¢î/€o+Ûuï”›hîZÀQ`Q¼,ï<¸ùlúiŒO®ôŸ›U c‹g“7y³A|52ð”7]èB‡Ð9p¯ ™@xqª ›bç–ÇÆo?ÞÏÞÞÝÚ§Eý~ªp·Ò{ ¸ÂÖ‚tc Řð€5à.àaàÍ[A€‚¾ëÀ}À/ eÇÕäfç bà\„ŠæŠßGÀYàëÀÏÄDí˜@®Å6ð$ðÓ-<ÐE/´E,¼·Eäà=ñ¬<VDâ8q³Å//™¥¯.Ù‹!¾â¦<+d£M`·ÈPV˜³ø<}þðCÑv±wêbÉ}H¤¾ÙB&*za+9Bÿ{€zÀçõ4zó³µQàâ­$Pr8ÓC 7zeÔ^š)|çÀoÕ©ž à²{Ãê‹üü Èy Õ·XÔ~o£$š¹Qá·aáðïjmöÓ¢õÒØ "˜E‘êÜÂB¦b xvœõÄÂP‹ZÔsž|µEkSØŽ%”_‰XòóüÝ{.^å˜52* @ñNÁwBhŸÈJiOýÓ{È]´Xd¡ìZåò­8'ÞîZ† ®O º—¶YG2AdÇÝ;õ@ÔîÑzo—o«þøÿëÿÄõßÄÖAýkåIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnome-calendar.png000066400000000000000000000053031221440706400216100ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA† 1è–_ zIDATxÚí™]lWÇwvvwÖñÆÞÆNvc7ޓ֤¡}ˆB‘òÐ"TDA¨ VT­è‡¢Ò¨¼ òQ Ayªh¥‚à)•BB ŠRˆª>Ñ Tb'µó¹‰¿¿âÙ]Û;wwfîåaïìŽ7N²*ªD®u5³ã™;çÎÿœû¿wàN»Óî´;íNûnân“þ¤·0¨;ôÿ€èÀx½É}â†ë°?&ÃEÚÌx± …ôÍ@tàwßù¦RJ£µ"T!õ@QW …@ a „H Í_(®yJÀ6'C"™"aÛ$ì ËBûuüZ ß÷ ”BiM*ü ¤*=ܪD©;ÀÏweúBB­ E*öãˆÈes8ÝN£Û2H)A6žûÁË/éOïèãù×^Žã˜ÁZãJ)[?J%èíà•#/h´ÆÊl°34ç*Àê€ÒøaH†(­ÄÐω|>Ïêê*¡c76º $2äïÙ'\O6.8y}ìàB‘¹·ßÆ1€¾úÜaá…ŠÕÔ‘Êmãs‡u™'¬X¿ aH B|r÷ן£P(J¥(^)R¯Ô‘R¶¼´€ÔÕòúšD–J”NžDΗ^ä݈¢aîýòc_ÛûõkG-VVW6l ·í¶|êé#bhǶm†!nÅe~y¾e 9Fhfªòƒ¡ÛA^GÎÏ#‹ã”ÆÆ7Ð)rÀpðø¾$^<|˜þîñ]À ÙÞQøJ¡”"“Ìpyò2•• îªK­V£^­oð¸ $ŽíÄʈ†œà C÷;QØ{üI¤ÓÈ¥nÏc‹ë2}ü8ŸÙÚ­ôÎ;¿r€–k€ß ᇠLÙd´Gíàui²ëëÈ ãà8ƃ@ ñ"Z!§Š&7Ú—Ö½@^x¾Oÿì,kÕ*Ëóóœ)-l À]€o[¹€fMöƒ¥Cz8@oäܸ ¯K‰;7ÇÄ™ vïÛÝ(d6LJããxà½h-€œ©`µ¿¿Oèû¬•ËŒ—]í5êMØdU`ÎPHw@…„ª1’c; â9¦âD5#Mœ™@.}@îþ²7¾Övg«)â:Åç?€çyäóyF+CüëÜ ?ùí l÷ÖõSÏKôl ð=ŸÉË“¤R)¶/¢¶fY˜˜àZ©Ä)ßÇJgÈõäDeYZXbbGëFÐíç@oÐ84©ÓÛÛËÞ½¬­­á¤ÓX5ŸååeÖì!Jå:­ÉÌO“àêûïS)—¹¸¶N)‘ ¯¿‘‘òù<‰DËBˆÍ KsIjßb­£3­ukò±ÁénH‚Lƒ£-êÀ¶mÛ¨«:=çÏS­×¹zõ*ÊRìܽ“|`áž=Ët*Eya¹•ÎÙî,ÃCà  è!Z£ ‰˜×o™í‹pݘ´hoT£ã8­óxïvØ}ÏnºººH%möÝ¿ƒŸ=ÈÈÐõ‹çyøÕW©{K®ËDbmé&¿#ÏÀÀéTù]‹8¬X[7Ë뢠…Fk´c;¢¡ã$N·Ó(jAã7@.›kF)“Ì`Û6IÛfïÐ^r¹ 'þJßð0Çßxƒ]<ÂGî 3W®ÒßÛËž={ÈårXV˧ Ñô§h¡o6ëödÖZ£ôƆHŒI)7H Ä”W­5™L†ÕÙz³YæGG™>wŽ3cc¯ûd³Y†v 180Hº+Mm½Ö¢‚@ÄìQ›íNt¥µR|ï™'õÈCÜî^’øé_áéC‘ïïgzt”%×eTk–ì Z«25;…5¿‘ÑIX£ƒÂØ®h¡&û”B¯ûŠrÝçÄ»ÇtÛ[ˆjE“ºZj…c'¸«Ëak*Í®áa1yêK®ËTu]Tõ🰺Æ%o©ñ³€nl(r ñ ò~ض½rCÇ4 „¸Éd'„Æ„:o!:zûçGîc¥XdòÂ&«ëzÂI“ô} !Ò©¤¶–h+ß´Ö-úGº7 ÝI4À[ïÏ=À`зšÅµ $M©³ceΪ_Ü¿ûž'F¾ýÑ{ï1>7wù—ccïÛ€^óž²kž1.Z°\–ÌÒ10ãŨNVdÚÜëfÀº9v)c|tŒ¶=‘Ž<úè 3ccLÎÌ”Ž‹¿1ãE94yÚµ0nzÅ“æz=Duøœ•‡:°3<êQ$" ÖSÞWŸ›¾4;»òûññ×Öjfyš1*À¤Qš‘XócÝ3ï“4‹vËøÛ‰@Ôj1/E†Æ£`Ç€X_9\)—ùÛ•+¯—J3Æø.3æªÑø3ÀŠ3¢†£Mݼ7ê·M!Ñ$h§b/³ã}½R™›™ùÃ_&'OÛͺÖ2ž]®Æt¾jKÒvqúè–NëlË|Ã"ßôDL£Ø±ódlû/º¾Øe¶G2&Ÿ&MÖŒ1A[¹Œz‹NР“m½É¹Ž½È2ƒFjm«+–´«¦ÌÏWqí3m<²íçú¶·×Ûô‡Š½°ý£„µIÔt¬¢”Ly\0×T[ŽÅ›ÚdK]ý·_ht[^´ oð•ÆQaÅPHÝäÓÓÍŽû7²ö1­Xy L2ê[|ôÓ|šh[ÏÞêÃ^Çí? Äž®™ðÄöIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnome-foot.png000066400000000000000000000055441221440706400210150ustar00rootroot00000000000000‰PNG  IHDR/0§#âgAMA† 1è–_ IDATxÚíYkl×y=wfvvf¹»Ü—ø¶)Q¢‡®Ūl#H¬¨qd×mT i›4N A †´(Šnì šþ‹]Ë l´µì<ä§â8vÜ*–#%RDY$MJæŠÏå>¸»Ü÷Ìì¼·?2T ·€,‹T\À0»³çžïÜs¿ ¼_ï×e»/ýׇ Ýóµ»oß>Ð:qj¼Àýþ…^Ú·o߉¡¡m÷Xíæ—pöd åWMËjoô1Wð[â?kll,°cûСT*5â:6ÑM‹•$eW2þobï ð¿xù¥ÑÉ3§ò“Ç}ò3ºÿÆõü›¯}õ–xgô¥­PUÕÑjI´3&–cïò¸ß+øûÆwM&â rÕ¿%vì£{vÝ€ïéîú”$+Œ¥µQ)à˜:ÚšN•¶Æ˜–ýU¿OðdçΑ/ËR³7ODzHKR"ÉxôûÉDb›ªëƒ–!ÍzKéÏAHˆiY0  ïíR»’ºÜedLU©ó(fàyêQŠ–¤ôïûàݵr‘]] Cj6ѪU!É”¶J-Ë€€a³å>—­Áå奂‹JŠ‚zµ‚|q “ççˆEï0Ÿyúçæm{©¦µA=åJ™|¶ã¬7xx#™¿l«ÔuSÛ6Ð}Wz6˜™#gÞ˜%r[%-¹M²«¥ƒ–i|¢Zov,e ˜|óŸçQÀpÀ"zÕÀ}åÃ_¼ëówÔª•âñ_Ÿ¬hšÚU®ÔvycŠª­­ àѦ¬¤Y†|´)ÉB&_‚ã¸Ä; àqÕ«¶ßtÓMb¹\^”¥–÷ÄcÏŽŒØ& ÁGÔ}F+îå8nÿu;·ÿhdhp6ÒZbæew7Û%5¿ÿ“· 3 3Ôjµ`*Íá-ñ賎û¤n˜xÊw€-8pàÀéh$Rwmcg.›#««…\½Ùšm´d몂g ¬•Kdjê,ÍJ(”*Û}–ïðk_zúâÏ~º'žHýíµ×^sk¤£#¥È-¦­Èdzü7vq5_ÏVONžKçÄøÔÌF8Î%5¯*²¸­'ö¹QcŽþêÎ]X„iÙÞõõëÞ÷Ío„<øýëGG¿ïŒÞÐV”Ë4PŠ¥…y°ŒäÃz[¾®Öl}¶Ñ”Nj†™¿Òƽ$ó¯O¾‘?õÛñ)ž#»³…"Ñ ::Bâͪ¦Ï?ôàƒ±OìûøK× îiTËðAªDZõ*ÄpÍz0 m[”6–V 1YQ¿ àO|¹mªÏKO½ø_·gìƒÿ^ªÔ†|Ÿ6“ƒiÙŸðÄ¥âûoå²¹‰ë¯Ù#vDP0Ƕ‰`Y®ëooÌÃÏ<—WšÕ'oûØ-_n˱LƒºA±œYA¦P„iÙòì͘˜¹óK˯êºF M%‘αM,Ë¢§+…Á¾"ƒýä¸å—~yâŸ^=ùú3,ÇÑžAÒOV³×u±V­_\Ùwâ>ïzVY©TÕ?øÀŽ/ÏlË$ŽãÀ²,DÂ!ùM%c¡î-‰”¤¨¯™–ýV0íù¥ÌÌŸÿåçìélV+T‘%drLÌ\€ãº0ày?m¸lÐ’•Úøë'ÇFGîL%“4D2IEMÀ £ÔëM‰F>ûéOÝy3Šõ¨·°ã׳ݽý}±X|wo_oÿÊü,µl ¶ãbi¥ãúåuSÜÆ/#[(=948ðÇ `zz{a[aY᎞GPIg,¾íÚí#ð úúûHu¡^-CmËช¥]XÉ_äÀÄ;ñú+™{¿˜>¾¶V™WU ¶mƒåX0, Ï£4ÚC<‘ЪW©®©`Yº¦"³Fni¥|¹•e̤Pk´Ößû ï$>\é|Þr=×NÆ"·«í6  CJY¦Ç’b!ǶÈZ±@MC#Å\†VË«¤V)cöÂ=vjªn¬çüïøÌ»› Þ[«5ò‚ ìòÜVI’a[xŽƒØÑA¢qD¢1†×¶‰ ŠXYZ¥ Éd2ôÔÙÌgrç[óçAWåfD/Wk3Çý‘G½„iZ„eâyxž'ˆe™„BD1D8–%kkeL›%ÇOOÂõ<øáí²æ^-ðÔõ¼FµÞœ$ 1-;Ñ”dhªF$©EmS'–eQ]Ó‰m0Mƒ,g2xýó8vê,Õ~7ð|Æ/çjf£Š0Ö½%ñÏÑŽÐ^Â0l8$Òî-I° ƒ(J=j;.–²«XÈäˆaZëÞÊbMoÖåÛ;M©C| ð-Q®8΂<‚< ‰‚øð‘.ZÀvÂ9®^ùµ›ç[O|›ãÇæ7ç~ލGQT m[TC´ˆHW"»I¡*xÜ5‡‚ ­÷á9`aaq6ºti—_úÅL>¸ÿ¾»yþ…ç8~ìa®\{¯-•'” €ˆZï ¯+‹D *øÖã€ÖûìŠA¡~6W¯^ãÄS?äч¢ªwoajB§?u”kïÿ…üý¯ˆ¶A0 ~,’SÔ‡5Äk<‚÷¤ªÇ·ÁE[ Â{Ñ`•3øîwžäó?ÂÇ?H3·g[_UUšfžÓg^êrBNv!Ú¦ª"ƒjÈê‚£ª¢ZÑÔBðÎqçQGåïg´Àç?Îþ{ösaál,B «všU•2+«FwQ3ÇžäµDìšq,Íc¹TD&L±`jÀý‡ŽpùoêEŒÐµ¥ˆM+bA /Vxs†5d  D:N‰Tg;Ýè„E]Ôô”öóô´)…ö;1Š GÉŠè4O#]ý0Ù\=AûZÍ+ƘžW‚éÆ$þŸéT;m÷ tí} eïg bU €m„J¾Ÿ(Q¥7·+Åûcb,)g³àÉJ]t÷fR¹DáÊÀí’OxIa¥ ¥%m‹‰2ÈA1Wxigt!ï»2kf«ýi: .çÈ4€$Ôô<‰ä ]9ûŽ0™LhÛ6×ûA;@P‰\.ðÙ•Œ¥ç6ÜL¤#Ó0qŽö\Gs|ÌfS¿ Xëˤ2;óÿV )(VÄ‚-]Ð Ÿ-¡’×0ÀAœ\ˆ!áCfD¥p MûgCƒØàV“+ »}fÊÉK2XÌ{(ŠùiUªUD’﹬™,˜LÓªõ+¼}¶°f!Xçvbã ¨¶$O XšÞ@ Nðê vèï%%•‚V“À˜_t[Ë®;•æaJl-æj`A“Ô{~G|uU¹¬ùÊ9œ«pUÑôL¢IÖ.^x— Þ ÆÁ¥Vhîà5Ñ_|½HÖ÷eùœ·‚Úm–ˆÙ=5‹»®¯š„¥EgÏ9ǙӿµF@n–îö÷O~ÄOL·ûü>p8ìs½ ˜ëMÌ M|¸1ÅT•Ò¹­MŒëBµÝÿç«YC"ÞÜO=Æ6j¼ÚŸ›¶’žoMz œy¡ë} Qsí¾;¸[øèÒo¨&™$J Ä ´X*£U7 tÿEƒIz€ì|í=ÛÿuF©MÖ–¢cÉÁ—W½—ºörÿ›‹Þ¢¶ÙÀô>k«öõαsÜúñ_÷MËÚÛG×CIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnome-fs-regular.png000066400000000000000000000034031221440706400221050ustar00rootroot00000000000000‰PNG  IHDR04Ì“»‘bKGDùC»¸IDATxÚÕšKoWDZCÚ4³Ð*HtEÊ¢,‚RBÃ+ÚO€Ô]Yõ#ðP%XtQ‰Hx4< ‚À’MT‰v”‡`ÄĵöÜÓ…3ž;wî±SPÒ+dß¹w|ÿó?çÌ5Àw€,„«»»ûéúõëúN`u ¹wïžè£P(È|Œb±(cccrôèQ_©õÀ{@*VܺuKDDfffÞŠ@J©†®r¹,ÅbQ¦¦¦dttÔWâ“8%R¼ƒ!"ˆHÃû*• ="“ɰyóf._¾ ðX´Ùä Mlݺu^×G¹\ ££ƒ-[¶044Dkk«S‰Ð—Û·oÏ‹àþ~abb¥™L†M›6qòä :::¬J¤æÃâºÀú~…çy58yžGww77~ÊñãÇM85ÍBsÜ&0ˆ¡ ”J%¦¦¦¸sçccc\½z•R©Ä† Ýœ:u à{`©O±Í&„â”hDh÷Úª ¶y_¡#GŽP,Q¾¡Y±¢‹={ö| ü€Jó¦žu.Ã÷D¥„¾¾>–/_N.—£Xü‡\îãããœ8qÂ߸dF…¦Ù<zl¡P ½½=Qp×ýF¬_]+³Ÿ!•JQ©T˜žžæáäÓiòù<££·8vìÀ.à`ÒÊB.Œ»‚ÏÄrTèãzÀ*¥jó"Uæñ¼Êìž* õô|ÆôtžÞÞ/éééñ·7ùš“,÷6¬`”Š*¨”ªyšŒ5Áý¶¶¶ÈS›u¶mÛ¦YEæ„å8Œ›Êxž2Œ¢´õ¾ðÕ¸(fhnnv—"Âèè(©TÊbéÏd’2Ë&Á=ÏSšð¢Á‰Ð_‰+W.ÓÞþÕtÍ67×ïѬEÄšæ½@ý{ô·õ}I9'¡íÛ¿¨eÂ$,»•±1²qÀ>veOîÞýù|ž„jT¸yóétºXDï)U½|·ûÐðÌD›W³óÕDXLö€Ý2,\kƒ‹ù“I‚5¶¬ޝº $;wîä͛׆2Ñø.Nf´`Â%¬¨X!+"ìÝ»çÏŸ%AH¸~ý:--­šûUH€*Ó(“H„I|hDÆ¥°bºg.\8ϲeËŠ^õ@ÃÆ$f€Û˜M÷€ÉLÅ&@H)¡··—R©T³Š¿Ñ,®¢Êˆ5ù…ƒÜF™6Á%ÂBû÷ —›LNd×®ýÆâÅ‹5H ±B8i™î×á\žÆLññ«N³Zsç†éêZ™ÄzpÚù\êêõBÌ^'‰³Ä¶C’zXH±k×. …£$p?Ôœ”k’³÷qµUUŽxò$!¥ô²ÕUÛç}fr1IØâRc³°ðbíÞDÃÃgYµjM2 éÖò» [ÿj«ƒ\Lb&-[IaÖWîJ !úúv“ÏOÐgwe+äìl$k KýYbbâqR"S\º4Bgç’cø–ðk•(Yæþðš(Da©¯:ÃêÕk“šhÛhòr´­´¹ßÖ¸»˜%êMkÕ!€þþ~^¾|Q³F”“ÅÑ™¹ß8؊ðÁÄ)´/Ç¡Cƒd³'×B##¿²tiFK(n&ÑÝï×6îîMBJ†ë&Sè(„Ξ=Ú5%çàýŒ$ZÛäñ¨«%¶s‹ë«yµŠpÙên)MеCg9n[÷úrpð0'CÈ/[£Ü«×*ÊÊ"ÑžXOnQ|“b"àÌ™_X»v]r°¥ñzP›ÔóvÛž’Ï!B™xß¾ýärO-Ör»}®‚ÛâŵopðkÆÇÿJnêÏŸ?GW× ë›ã(LpÙzh˸[X™Ó§fݺ“=”Ó$0†;‰¹--uŸ34rêȘœœpÔþâÌØs=Ù©WðÇ¿I†ÃÃC¬\¹Ú€L´·¹¿‘à‹Â.~}]rõ©IïeÞ…Å)€û÷ïÂÀÀ!ž<ÉZš”xú{Û¯#55… ”Íf혜œdff†±±ßgON<Òé4 eܽû'Ùl–W¯^YoÁü_¨ÎëG`Õû´Ú÷9ð>ТŸ.À!Àkà)0áŸCõè¾Hÿð€P*MZ0/dÁmŠ(€¶Cžú@eIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnome-gimp.png000066400000000000000000000065221221440706400207770ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA† 1è–_ IDATxÚíYkŒ]ÕuþÖ>¯{ï9wÞ¶gllÏcÌ#¿ ŸÏǯô _Q¬Ü¹ŸuÔ7­êu„p,+çÒ ô÷ˆk,ðËô !Ä]›×?¶ûáíw ˆ ˆ@ôÑïÒu Ü´ryñ™¿ýÓý=>ÙÙ‘/$~IDhxùÀÐm›Æ~¿G‰È±Óþü=fR.êÛùwóÍ'{Ë¡C"_"ÿ#aŸ¢×Ûýð¶¯cv*­KDäv€ €Ü‚ÎõVK’6»žWztçÖïlÚ0úá[Þ;à Á.ô 9ñÿ<ckGn¿çÎß°l¾R;yêì介~¿ &€ð/ûÞxóÔ™ ±µÃÿøí§~w¯ç:¾Â$\"ò:ÖAnçÿ(©EðëFWŽ~ùñž#AcR)Ä­ä4Ÿˆ\‚¥OKs{&¥–Rÿ@*=tÓªåÏüÁWŸ|B$ÈBøDäàp-‹xgp 7züK÷~Ûô”RH©¦™ àÑ¢rW\OBy¤ÑñŸŸžÛóÈöÇ“4+þîå+ÝŸŸüè®ë‰÷~úßxëWQ,øÐZ`ïo·l¼ÅR„Zõ2Þø‰Çß-»Žv´ hÉÐJC ­µžƒg@ 0`Àæì¹éÎOÌ\!°8 3˜™Áv3ûX ëºëÃ0üzE_s]÷^fv™yÚó\ñoÿú£·„<øöÛïЦM›°zÍü „óçÎà¾ñç^¹Ú0´ÖðƒÖo¸–-[‰Ç~ c8—…ÔȤD–IdR!ËÒ,­”êáj­9ûÞÑic´Äêœ_[6#)fÑžçݼaÆïmÞ¼ù!!Dqbb‚§¦¦¾Çñ?=þȶKõF|çþýûñâ‹/b``{öìÁ·Þ5kÇJýûöáðáÃÇ–-[ µÆªÕëP*¡V™µR1ÐZ[ðJçz3ˆWp’d•ŸþÙû™T©M€d† ˜óldS*wx===¿¾mÛ¶GÆÇǽf³Io¾ù&Åq<†¥?öƒÀ­Õªxå•Wh~~ív›™iš ·^{m?â8¦àرcüꫯBJ‰V«Ï©¶“¡•‚R R*(£Á h®Ö’ƱŸ='¥’20I.gN;–ïH¨C ìyÞýQy…Bív»ãr'šœ©Ñ'ó³Ïþ=·Z víÚ…F£3'`õØF´Ûm<óÌ3˜™™Áž={ešÍ&’$A;IÐI¹J(­ò{»Ëf0$©’GŸ¹¤”V (mb 0V:Ÿð@”rhrr‡B£ÑÀìì,„þ_ÄÑ£GP,Å¡ÿ…‰s¿@«>‡áÕq߃aëÖ­\«ÕðÔSO¡Ñh Ýn£R¹Œf}ÚæuÕ™ÚÀ0ÀlÎ#óôÙ©T*­µ-ðuM0·8O*Ü…””²=== fF–ehµZ(•Jˆ¢ˆ¢(9çÏÂÌô9¸Žá€€‰3'0¶nž~úi(¥RJT« 8{ê}°Î ”^ô‚Ö Ã &òØàV’fX &  fg“se×’Ð3Ÿ­×ë|߇ïûâ(B…p ÑhÆPÚ‡çûðáoìÿÊ}+àex~€´ÝÂÔ…SH“Jk´Zm´³ ÆÆÛÔI¶Úš¯ÔUšÉ@BÓfœU€̈¯_éLk½ßqœßaæ¢çyÃða!mU'mhÙ€=Ž`6`f,Ì¥? V¥lÆÉ$æj ApY)å›rðÔ‡s1€„rÍ×í¬è€oÛ}©c}ÓÉž‹i4˲wÇùaE{{zz¢0 Q.GÃ¥bóÏCÉZIÈT¡PÈày>èÚ=µ­erðJkLL]„TŒþ¾¤I¼¸‰q¾3ñôÌ|–´³€fnqTòÉuþxðÊ+ÁŒ€ÖºZ©Tž £(ð…Ja I\C³¾Y”V AAƒ™lI§Hcëš¶Ìp¹Ò‘‡ÁÁ2z˦š Íy5@Œ4“<5}©nÁב˦p•õ®Mëªà?q ‰ãx®^¯Š¢R{dyÿÝZ§…¹™IÌΜG&SH©rk@+©²üÄ„ÔnNõF ³s—qnb–î¹}3ÆV£¸íÕZZk”RæÄÉóÕv;[P!`„iÓfÌ[µºÎü¿`fŠã¸9;;{xýèÐHàêÛÛIS¤iFJ*è¼â Ci©²T¡ÕJ0;WÁôÌ<.^Z@’dèé-“ç»(øBˆå½ú£¡/ÐSt‰zÍÈ@ ´n/ë5̘jgò<€9ëŽþ•ÿ‰Ó]ë` ÀÛ¼qôÑLéß |ï¾,ËHÏ6Œ¸Õ†ì”B T,¢T* ·7BO¡¿¿Ê=ŠÅ"šÍSg±r0äÑ}ÜßS®K0H3‰…z‚jSÖÏUÝÚÁƒÿ¬^¯ŸôuWuú™~NLWņ̃ñëóñ©Žÿ÷0iÿORÑIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnome-gmush.png000066400000000000000000000062541221440706400211700ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA† 1è–_ cIDATxÚí˜[Œ$×YǧNUß{î{õŽ×qŒlb³K¸¯"„1RŒ2QL B âÍ‘xˆKHŒŠà„<8h­„`@‰ÀÂö‚/+lÇ»k{–ÝÙÞ¹ôLwOwuuÕ9U禪U Þ Á ¹¥£ª­©­úÿ¿ïÿ}ßÿ|ðûà÷ÁïÿõO¼/}àáO Ä­Ñh(.]X}îò[W;ÿ§ <öç_^qƜȄX‰ÂÑò02#Lš¡cÅ•+kÿzñìkŸÚèô®\ï³ýïèGÿäw}Ïñ?’³Ç“åp2Á&´N1iFÍ÷¹uùvœµÄñä¾è®Iuvr§;\{ß |å鯭4ëÍÓ‰ŠQ©ÆXƒµ¦dÖK½Rg¶5‹ÖŠV½–£íC‹¿¾ÓþÊûFàϾñ—'Ïø‚C¬L’˜ÌXpŽz½ïWðœGŽÉ¬a0걺&ð=ŸîÎÖY*íÆççš_ô£Kÿ+ý‹ÇŽ¼ç¾“ó­™cì‰Ì˜åI‘(…µ‹c¶9Ë\{k-ã¹)vGCâ$áÍÞÛh­Ù ‡8Ö8Kó_ô£_þ®xåÍWWgæW„'t–-§©"Ñ <çyDKf-&K1YF"ÆŒµøRø{¯BÙŒXÅ€ÂÚƒÿãzãò…æ–¾à oE› c-išbL†6ƒCzRJÖY `¬a4M Œ'!›;Û8OJZÍ6Õ Æh<&Mõ¡¥#s÷ïlì~û¦ œ»üæ±cŽ>.„XÉL†³vïÎb¬Ù+Ng0Æ¢2E–eh‚³8kq´I‰z]T–2Gd6Åó%"È@ÒnµY>| ‰`§ßãóoÌF¿ÀÍXë^=vxþÀóÆšek-Σ·½Ej @f22k±ÖâU|Æaóƒ™s¤Ö <‡Ò÷ñ«5d¢ñ$´Z-ª~@µRcŽFáÏÞ´„Ž,:½¹¹¾üû¿÷Û¼üâ|ßGzÂóðr¹T‚€f³IµZ!|: ç8pð ¹9Æã1·Üùa°¤ž@Jüß—x•+6]æ[³ =Ó¦Ñj>püÀOn_Þþ§÷" ßíb¬’c¾”ö3?Ï›Îíukñ¤O!¨ÂDQ„ÔkuffZlnl±´¸Àîλ½> ÕRiΟy‰¥ Êb« ÒŒÔ¦h“2 GlûŒÂ½Ñ.Ãh„­x÷†Wûü^¼wM‹”Ç„Œ†‚ ¤ï£µ" C¢(Bk š&;;=¶º]œu4š ÖÖ®T*¤:Å“q“fKss´dWºw>?vÛÜ}t™Z­Æ$‰ÙnÓ°RàÕ*?xð£·ýá {!kíÚoþƯ-?ÿܳ{ò‘r¯ËàH…NSßGú’v³I¥Ra8 ŸÌ ~ø¾“ôû#&qL’$øR²¸0ÃÖÆeŽÝr”Üs7Æ¢hÂ$NXö¹°»Å¥Íu”V$J¡µ&Ý®ÿêúWrX._ïMÀ9·ÒÝÚ<ýÙÏ|ß—~€çK)ž‡5–8I˜Lb²,¥Z­Òn·¸ç#ʼn¥iš’$ J©éò}É÷ÝyœÞ`€1†jµÂìÌ ó sÔ*úqÈ·Îýom¬¡RÖ)v{ôÃsÝö‘p°×/øoHœþöß?½ò[~qÊÖX‡µ!RJjÕ*‰RÄqÂOúiA)Åd2A)E’$ÄyŠcµZÁs çÀ9GµZáà%æçX\œgqaŽšðåoþëý.ÎºŽ½<øøøò “·Åñ=í´sît·»µòØ—åâÅ·ñ¥Dú>Rz{ã„D)>tû|üÔŒÇc´ÖDQDE$IB†ŒÇã) ¥Öjl–rôÈ!.-Òh68rè ³³mæææh6ê„:æOŸùþáõ³¸Ì|=|öß?—ƒŸ®kÚ8çV€ÓßøÛ¯óôÓGŽkY–‘$ ¿øK¿Šs‚$I¦ ƒiš2 DQD†(¥Ÿ­ÎAµ0;3ÃÑ#‡8~|™ã·Þ²Gfn–±ŽùüýÝÑ€tµww|±ßLNÀ\“•B<éœ[þÄÏüÜã?~ê+Ïýó?òâ Ïqþ;¯Ñh6xàÁO²¼|| \)…”ß÷‰¢ˆ,ËÇT*¤”cPJ!„G«UG @ÀöNŸI†!Î:”Ò>rC ‹tÃ]¼ƒ­q±ÿÕBÍ€»f3'„蟎G'~à‡~äñï½÷ûOîôº¬wÖ¸cùêõúôÞJ¥B–eH)B0™Lð}ÏóBàœCks‚ápÄÒâFƒ…ùY¸uùfÚmêÏ_ø¯]^!°“t¨ºÇu»ÑÙÖÌàG/®¯­4š­Gî¸ëî“K9”RT*¬µ8çBÐn·§×…!¦·Ö²´´H·»E0Dx<RzD™â¯Ÿ}ž¯½ô,BxX~+~uãË2¬µ¥cò}ƒ™ê˜õœÀ¯U°Â/°dÂôîäÕxkøRº1º˜ë½‘ƒV@µD¿)iš>’eÙd!0 i·Ûh­QJM H)ó°WI§FfëIo§ZGÉnÔÉ&js€µ\*•x-'áçFôÆk ÛížHÓôdš¦$Švéû>išRÎŽ1fZE'2ÆzkôÜ ×Ó9Ph-'PX“ϸ,þíÝàÇ0Okýéb–IL&“½è&É;ˆÙ|7Wœ‹½Ý 9ØÂÔrÉÔóUË£_Ïåm€w#àÏó©$I S Zkâ8ž- Öú$œsÓVëûþ‘ü™2[/HÒ)d$J8®ë«Ä<àgY¶ìyÃáF£A–eÄqŒÖ)åt¹>Œ1SÅ— çÜ<Ð.Ùd›iZ’OZ’_rÑ™#àÏœ9³R´È 9çHÓ”4Mñ}cÌÔJGQôŽVÉ[l4K`MI&|^”êB»¢ˆÀx<ö‹èJ)§¦M›|Puš¦Óm©sn:äòá¦öi¾ú. Ý»ì],`½ë_è4Ã0(¢]¯×ÙÜÜDkM†Xk™L&ÄqÌp8¤ÓéLk¢N^J©/]º•4îçEêçïû:Q±Šì¸É€|衇¾Yg¥R¡×ëÑï÷§rŠã˜ÑhÄÅ‹i·ÛÓùPH¨°qoïÓvP~Oa™óÐùÑäç×ìFž€¿»»ûª”ò^¥Íf“ííí©ßBÐétò=4h­±ÖNmv~ßî[o½µYÚÚ}Eœ•fÃþ•]oþ‘W^yå‰bÒV*¶··I’„(Šèv»¬­­Q¯×ÑZ¿£zžÇ`0¸töìÙs9˜8_ •Î‹ë ˜ä×t©C “׼Т_$•gžyfýþûï¿KJy[–e¬®®N-ÃÕ«WqÎÑh4ÞÑN{½^çõ×_£Óélç ’‰$çD&ÀØÍ­Å(?Nò¥-¯·…–ЬòÔSO™ŸŸïµZ­CµZmáüùó„aH–e4 ºÝîúÕ«W¯¼üò˯¯®®n(¥Æ¥ £\”ƒåÇaiKà‹ÿ›ŠkÌ€WD¾4-›À 0 ,³§NúX†Uç\õÅ_\Ëﯔ²XL¶¤e]’GqŒJ„ÂÒå׈kÌ@ÑŠq^x“VNb.?oæ«^j²”Å2h“Ÿg¥ÂTù=q~-*Iª,«$¿÷š&qÑ!Dþoߥ†Ê^-/£ây*–˺¨-e@åçª$¹"òE¯yOìö “´Ê–¢8É£”\£·¯Mš}ÒÙŸ³Ï²JJà³!PHÿ B*zg@–<++|~’_/À‹Ò+öÝŸ–†—¹î[ïRв4=½}5â—À{eßRÒº.]7¥³ßâ›R´m)Źû $Ý’vÚIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnome-gsame.png000066400000000000000000000102471221440706400211360ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA† 1è–_^IDATxÚíšYŒdWyÇçœ[{UïÓÝÓ3Ó³Ú3Áa0¶Ù+f1FÆ !äHI”üÁÛã7x–,­ígë„~SüÝwžoïéߟkÄ0×ÜØ3×éÖ«6Yžš,ñb×MWrâ?ñ[÷?ð®;Þï—¸j¯ÁÉ1ñª´œS¬|ÛúÕüÙzþüð¯oY®|ì³·S;s%æÔË>sjÈ\3àÒ–Ï\+Aˆ ÃðáÝËø‹{?ù»+%y‰¨2ñ•‚ð P/=Sç .>ÓâÙ˜cƘ2­j;ñ_ùÆã 'VFÿò;ïkä wN;û–÷‹›÷ÏÒnjúY›o9¼£Ê-‡¦ÉdG-ÎʽÍÓ¿¹ï†w?úÓŸ=‰ÂB()¥°ÖÚÒ9  4€&0L“Å÷Ð.~¯•$%KL(KùÕ~âŒ|ð± _ýèѹÏ|þβÕh#B³4§xÛKÜx`©F¼i‘猆¾çíF¨©?òÜIkm«!…ÆqcŒQ%®7 B§Y`ªô¹£xÞ)ÞuJRcñ–Ò|ã'g8Òù½wìò¤Õë :Å{S@Ž‚é‰6Ïs:ë.ª&é­Rœ0 îûÄ=yò;ßýþÀzRJ„üßÜÿ¡[Þ²t_«¥îØ}&Ì[iØ‹.»Y÷ø™­•o<òâó/^ÜØ*¸œà[@è{¥wò«\Ú ?Ýjµ§Ž]`Ì*ósÓÌLÍ1Ñô6GU0!u¸¸òÎ['¸<_çk?vÙ=“·§gÚŸTJ=$„õ¿ùÓ{ï¼ëƒ·}yzjòˆª(´ª¢½@$iŒI‡éååewùÎ÷ÝòÞgÏv7øÖ#O?wn}½ Ð/$3QHm«Ð¯d æ*ÂæÂòȹŽ­M0Qó¹aÏIŒJ˜DpS[1í(”Ðí¾ù=<¶Î³ç3†n$&ñ¥Ôq!„ûÏõù/Ý~Çmïo´[(¥‘J|„SG™”Äi¡j +-êÀ»ë•ù—î¹ûÁÿøù™¯?ü̉B•¦Jv1V%Sr·ú*äéA£5q*éæ‚8™7d*#Ö†õÌ’:5™óÖ%Á·žöyòlVàFŠ(—ÓJ©å¯|é÷îÜ1³Ïë®Xì.ŒQµMp4ƒ`³hL`â˜<Œh©ŒÜ~膉jeòo¿ýÄ3…Ô ÂEAtTH(äUF¼të=éTj i-Ö¤˜<åèNGîh–K§ôÝ?ŒøÑ³ß}jDàG“’ÐZØÛv9s7.ÍîR¢"hÔ µºÂ©+œªÁiÍéhªõ:N»‰”!ëT¤Â˜+jìh;Mdµqêâ†[?¦3/¹Úȯ0ÿ¶~Ñ‘j›cóaÞy¨#öN’$`&Ø4ä›?ùÑ ®"òINfcnžÊ'2k@VDÍÇ‘(åÐìÔ©7« 2!T«jHcäèj$Ø0Æ’¢-쟞\Ûòâµ-7. ×±alà ]¥Bi>Kç°ÕU!Ejg;šÝÓ¶*ðsÍfœ¡ý„ó[)y’@‚ÍEØ ÇÈ^˜“ˆ‹G³Ù ÕL™^˜B6v@£$Ãæ9J@ª¦ÐYJ£¢@¾cŽÖp@hís×;í}òôj·P¥ `¦°ö8V\ÀI‚‡b+~ÛfÕªR9›™¦ïÖ˜®ç¤Æ0r#ž?chŠ„½­˜—ü°EòbÙ5USÁб2wd›Ð™BÌD¶—EœFá(´Õ -•4ƶæÉu†Œ Ýr™œìa·"nR­ÃÎÍœ>¿²Y1U¿ @É2€»Þqà{¡78æ‡aÒsC^,yœræ\Ä£'\ækWÜ!œWbJCäv¸¹Fœd„IJšj²D£SÎ2ÈB Çê¥#lž’‹µòÇè\ƒ­¢S‡8ÍÐIÂM‡–æJ‘¼VŠÔ@]eýðß³ß8ú®3£‘ÿñlu2mu¢°©6¡ŠÅZ‘YÿvWÏë…™‰št”h6jLL´Xœ›{wN±gy–¥=;˜ÛwæŽd»#lm'Yæ,ÕÅ}T [“„¾ Í6Ns‚D:b¤jø¹•Ç^ºt¡äûG…¶®)€“ÇŸž{ìàMoùó™‡îö³Ú{µ¬.[œF–xšt+‘ñ(MÝ ë†AE¡l–ØZE‰ºÕT³'12ÈnFÖ’Þ/"QlÈÒœ02ˆJ+%A³¹¢mÎ ¯D)C~l‰"“oK¥m! õªdn[yǹOõyñÔ£À%!Ä)å‚RjV)5©”jK)kRJØ8ÉL]"† Æi昭ŒnÔil M3"§ÊÒáÝ„±"OZVéöc6F.[ƒ«#7Œ·ÕãïúU¹P‰xSD»qà‹[kSkmbŒ©Œst!Dî@<ߪ´•„Åv¥©:;fª4§êÔêÕZ£G(9 ´åìÏΑ)‡ /Ã#ü$'ÔeZˆ¬bk®Ax>.v^ @^îÖÞ¶Ö¶¬µMkmÍZ+1Ba1™BºIÂT­ÓnÕ+ÌÖ$“:µvg²…jTˆ3p¦$õ(c˜'ähõ‹Ãê3MrÓ&&4à HP¡™iz—6û%ºt ¯Næ®Ä;¥jÈZkó‚èT‘!ª€Xí½…™Úp©55Ýafv†ÙɪVÁhCœE˜4ƒÍMbé"¥ÕŒé‡7N±:!«ÕèÅhk3¬\é JúŸ”r¡øµ$PF;*å µ6|kí˜1ÆL5!D0?9uY>´û…@§1ÃnR”ìIài²Ä’Š:½î6Ü/ʉ㔠Ɉ2Ö¶hQ8¼ôòê¥r®\ÐáÄg¯*h^£Í1b!D`­ÖÚE`Ñ3U” @=vìüÚáÍ÷Þ´øV»0M†Ø "•’¡Ÿ‘IÇ ƒ$ ¢”¨2ÉÔì.f[‚ `uu{¸ý­‹W[Bk­g¡^ ,Ààü’®ÅØhk­B$ÖÚØZ;²ÖŽ„¯$WÖÚà|íáŸ?Ô¬¿§º7æpGj†¹Àè”zôè}“““³½þ ûØ£ÿýàO<ù­,ËümFŸWuòÌ¥ÇO]{lÿ®Å#3íæ-ªR=И˜^Z˜ßéäIÊå+ë~`6tõ– Ôkurã>­Îd³Z«Ö’8ÉŠ3T©Ì¬\3*_;w.6ï¿ï¾ï¿ÿ¾?:p`ïÞf³9—çzïDgân©Ä®µKkß)Ô†€±ÎfBˆXJ©Ý ZÝzÏt‡îïx÷{nÞ¿wï¼5g1IšàT+dy&²,#I‚0À |ò$›[7 ƒn©[ðH^ÀÑ·ßú‡ºóÎ÷Nœ8ÍêÊ%ý>ZqðàÁÏî^Þsw‰ë~)Ñê !z…®v¡b(„pçæd:HÁÌìá(‡4I±yFµRE IµZ¥Q«’=û.T¶Zp¾ZÄ%^+•xå:ò–›¿!I‘f)I’àù>žï3ò\šÍöGŸÝh)cTÖZ)„§cG ýQÐëõÛõz@»Õ¦ÕêÐï­2rG¸¾Kžk¤kHuNž…IAp¥Ôn×Ë…^¹¤R7a@§Ý¡ßâ¹.Q¢uŽ”’ÎôÔ½À¿Ž];vuÝÒZ«„!T¯Û}j¥QûÐÒâN¤RT+U¦f¦°XüÐC›œ Î0&' B?LKÞRns­Ùu¬^\yJ yÇââív‹~¿ÏІ1qáFCà¦bðpq1à !B@K)m!)¥”W.|Ïòž;}?°QS«Ö¼€Í Ò4Ú°–,JÐVŒ†~© o·åk×w£NÅÑÓ33÷^€ëzb8’¤)qœ„±]Y¹x2‚aÑ%¨b Ÿí !¥TV©TRÇqr)eá±ÎÔÄg´ÑÓiš’§9#o$Ò4EaÓ,QØ<ׄQ¬\|ùœÖÆ+eƽ®z@¨®†ÍÉ$‰öGIòÖáÈÃÑßóLæÊú•“ëëë/cÆ&Já~TäNÉÜÜ\^­Vm¥R1Žãh!eê/4šÍO…Qä ]$‰q]_x^Dèh¢µ1'Ž{&ËóÜo f¯@à&Ëò‡ÜÑ`%‰“Ù4ËjÃáàôË.üèòúú)!D§äF“¹…÷ 4Ón·)½4ÍιýÞãJÚ»ã0nú^@–eB'q’Æaú§_|á9?ºRªš5Æ-ö„oL ÅëŒÀªJìökgÑ£©ÄËÀËÀ…â°4­`aaAôû}Õl6fçæÿx¢Ó¾£V«íÜóƒ­n¯ßï_LŽãLçy¾^ì8 œ+Îê½Þ)¥,"à°ì ÕÂ}€MàR±ù ]gÞU/ºmóCöCŽ™Ò€Ãºß/˜² \KÁylAˆ[åÅýø»_ˆ×/MƒÆÞË-u¡Ç½ŸvÉóÄ%õJ©y#òÒ„D‡v @¶tpP¨Ôë™ûŽK×Qq?6Ô6Ð*y¶¨Ä ¯|ÆtKÕRRUÝVe¥ˆœn·×òØÅ~ÍbÕŠ5.e³mmõqA£•I}y`=ëNéù¸«‘m+À_ϾNi Jg”3Þ¤´÷›òW± ¥ùî¯ô÷’´e)q+·|ÌÿÅ%Ķê;Éû^sÏÿÖ1ÐÁaæIEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gnu-keys.png000066400000000000000000000074141221440706400205030ustar00rootroot00000000000000‰PNG  IHDR00Wù‡gAMA± üaÃIDATxœí˜kt]e™Ç゙[rré-MÒ&iÚ4Io´Å¦ ´ÒŽÈÀ¨C;D™gPQ†¼T•²Æê×Tg´ule€‚´¢Pš^Ò¦—¤-msk’æ~9IÎmŸ}y÷|ˆ¸)¢ÂÌ—þÖ:Ÿö~÷yþûyþû}Ÿ.q‰K\âê»ü¬2 àC^‰ÅFíd"弋ÏK´¿t᪵ËUËrL+éÍ·RéuÕóæä-©YVV^ºzÍÚU+W­ —”•(=ݽœoí `˜L-(`Fy9&NÀ•šªaYVü왳Év½°mÛ·íª:ÿ/LÖ/zßeŸ½fÍÕ¯ºúÊB01o2µjyñù_³è²Å8®ÃPÿçšÏ±î¶uÜpà H)B0Äãqm_µòý[úûû¿ È¿VÀ;ñ@V(\{Ãß^¿îº¿¹fr(6¤  IG{ÏîÜÅæÿøÉx‚3¯céKàÕ½¯¢( ª*H$â|ñžÏ)ñT¼4h×?å]È‚òî¹üëeýÇn»eŽ®†©‡š¢Y9œkj¢xú4J¦—bè¶þd+W^y%ÕÕÕ¬ÿ‡õhBÃÐ š›š¸ûîÏÐÔÖL  ’™[³|aåÛýéœù³ßIl2F~~þ‡®¿îƒ+÷¨Õ&OÊGÓ Œ@UÓ©®ªâø‘|àA<×ÃÇç _øŽã 8n†S§Oòõ¯n$I1½¤UÂfV^~î<`wn~®ˆ ÅtÓ4'8ŽÉÉÍž-„Z¦éêXYyñÙÞÞÎTÂ’€÷æßÖª¢ÖÜ{ß½Û¿ô¯_šŽq¸®ŽãÇŽR\RȬŠJŠ I§lÚ[Û8yú%e¥¬^½UQÑ5•M›cÏî_‘•“EVvÏ•xŽK"‘ ¯§ï•y‹«n ƒ•/ï®»ñæßø’ò’iK–,ö55ä4kØ÷ê>+cY­Ï=û\mOwÏ0ð ÐÎxçmÿ×O~ú“/œ¿P „¨Be``}û÷ràÀ!ÊÊŠ)-Á¬Ù 3bÃÃlýÑÙ[»—i%…hšF*™$•Lc†u¬T††c§ÁPðÀôâ’Š;>u{áäÂ)j0Àµ%yyB’Ê` èp㉸õ퇿]WWWwôBç…ÇQ`ô¢òróJnþðÍ'¿ñÐ7†j€B4EÃ4L¤ï³oß«4Ÿk¦§¿‹p$ÂâË/§¿w]»þ‡ÁÁ¦•MÅP5úb$“q¤ëÓÖ|žtÚbáå—±öúkœÒ²r=šeltŒ_=ÿ"GeÓæÇÈÍÍG7t¤¯MÓ0MÓ÷¤×ûäö'ýÃü°þøñãß½¨€ÂÂÂÍ;~¹ãîòòrt]G"ñéIÏAÓ4¡0º®‹ÅhhlàÈázFÆFÈÉ 3:Ã÷$ccc$IFãcœ8zšÊ9ÜzÛG ‡B„B&äMæØ±c<óô.ª««¸é¦›)/+ÇW|Õ¢|f9ápEQP… <ÿÂ.·¾þøÐÓ¿xºúb&ÎÎ8™ÒŠÙøîøîo¨R‘¸ž‹°inm&77JÕÜj–-_Ƽyó9sö4gÎ"•Š“JY8R"}Ÿá¡·ßùqÊʦaè&šj`A4Måà¾ÃlذkÖ\ƒ¦k  ³óéÔ¾ZËÆolDUUt]§¥¥‰_û}ƒ}RL7^L@éG>ú‘2EUPuðéïëãøñÔ××ãù.+®ZJñ´Bz{zùþ¿of$6JEE% Š;î.ß' ÐßÝ˪Õïg΂ùHÏC× ²"Y˜z€@0H__/C±AŽ=Æ¡C‡Ø¹s'K–,aÓc›ض͑#uüÛ}÷ct¦L%O²xɼåÍ@QQQov(»ª­£Gþ&]]]Ì]PÅe‹1µ¨€ìHªªSPXÀ+¯À0LÚšÛhhlॗv“HÅ©¨˜‰c»H–.»ÓÐiiiÆq,²ª*QUáÃí·‚×ΞáÕ½ûÈÍËå¡GbÖÌYƒAžx|;wî$;7‹p(„¦*˜ƒ–æ–ª‹y øÁŒòïËËÏxãÍdá¢ùÍ0 §xþ…Ý öö³ó™_bÛfù»/›ª¨H_ÒÙy_î|І'˜<©‡¾ù¹9¹¨BcÇŽ§8yº¬ìå3Ë™;g¡P×s ˜&¾ªÁpl˜Ç}Œ£G3½´„RKÌ Òv¶5öVý€>3½tZ͆O~¼ìƒ7^/fÌ(£«³—¯=¸‘žž>.\ÄàÀwÜùI à­­áÁa&Mš„/}TM#;+ÏÑ#Çøä§?EQQ¢*ÌŸ;ŸË—ãz’ÎŽN¶oŠd*Iii¾2~nìçË÷}™îÞ.**g‰d‹‘ÉØhšŠ¦+HOjo.¡ˆaè‹ïüÇ 7\±rY…¢¨"޲õ¿ŸàÜÙ&6>¼‘¥55<óì.<×¥­¥•-?Üž÷pÓÍ7QZVŠi˜ öóo=BÝá:’©=Ý=¬X¶Çu°,‹¤›K–ÔpõÊUܱAR{`?ßûîwÉÎÉE 'OP6£ן‚"#±QtM! 12Cúž”Ê›K¨âcëo}ðÖõÿwcñ˜¡)ùùˆ ŽR0u ùù‡#<ú­ïp¾½ƒ“'©YZÃ]ÿt††ùâçîå|{EÓ èëígé’+xtÓ&©8¾ëc;6®çŽÑ„@Ó5BÁ0éLšî®nNŸ:…í¤¸ÐÓAr,M"1F*™&™Jáú.©x ¡Hñ´û† L™2eõº[o½ÉJY†›ñ‘Š ŠŠ§¢é:ŠP‘,²³³ÙýÒnÂá0ªªâã³ûÅ_ñ£-[H¦’L)žŒišDó¢?QÏðÈ3€‡‡çz(BAø8¶Ã`jES˜R0™¡¡!z{»HéáI#`ɤQ…FBz(¾B$’Õý‡Ìše5wÏš5+0!wÃ#Ãlßþs×aÑâ…0ƒø Ÿ[Ö}”P8‚P¶m£h ;žÚÁÖ­?&šeJáD‚x"®©ô ÷ÒÚÒJUUŽ;~Ðó¸¾;nð%Ž'Ñ4 UÅ?‚ø>D"YÃyù¹ßÿêƒ_¹å?·ð³í? —Ï,kšf:Žƒ”oÌ„m[¸ž+¤ç¢k&±¡¹¿öàñöópm÷ØïTTT,›]=[(Šòûº”Þx3޾¯SEŒ_Ï8R©Žë’É88®‡çI‚¦ª*šŽ"@Õâñ³+Ë_ŒF£¿êîêþâÕW\ýÜ=Ÿ½§©¹©ù|v4Û ƒ¨ªŠÀ²,\W MÓÑ ƒó-í郵ugóósîrm÷ù7d m¥½Ý½íšªùB<ÏÃr-¤/ñ<!žôpÜ7¦]Ótð\|O¢j vÆÁóÁ“>¾P@(hB;uáÂ…Ï5?=Èx'uÔ÷ýyjûS_ºöškO¬YµæpÝ¡:+>—š6¾MéËÞî>÷™»Úî«Û¾dù‚;O5ž;üæ’{}#»6//oÃ<°xÝmëòMÓŒ¦’)||×ÁõÜ?ªUUUéì¸Àkgèho#ã8Ø™ –e“N¥q‹3§ZÚ\/ó‰“ g_~K·‚ ÌÖTÏ©¾º²²ryAÁT[QeüÀþƒÁ¶ó­Ï&¶e,û7\dª÷ºÈ>“ÍYðäŽ''UTTT™3šL'ßÒlªªÒ××K}ýA¿³«CøRJ%A ’é”êÄk£Bãöžþg[šÛÿÔŒT²€èïâ˜4«Šhõ¤Ÿz»…o>JhÀBàÎÕkVÏÝúøÖjUSÙLÏóÞ DUUº»;©?vÐëììT¡aYvÆáÈ¡c=gN7==ö'ÿ«yóiT]ÀËm-mÝÛßV 3ÓK¦«ÑìháËqª¢Ò×ßCow·’L&0 ƒŽŽ Ní¾C½‰DüŸûzû·ò.LÞþ\¯“Τ’©Ã/íyÉÚûÛ½ÅݺÝeË—…r²sMÑÐ5ž¾.bÃÃ$ ¿áDcêx}ãk+V.þNg{ÏÏcC#4Ãy/x'³QÈV·¬]»¶êÊ«®œYZZêŒ Y{öìQ~û›WR‰ä¶ínaƒÿž¿ù×ùsÇë âw¿¨®ŽkwD"áß&Éöw?¼K\â—¸Ä{Ìÿê;Ô$Í誂IEND®B`‚lua-lgi-0.7.2/samples/gtk-demo/gtk-logo-rgb.gif000066400000000000000000000144331221440706400212140ustar00rootroot00000000000000GIF89akŒçÿÿÿïûõïô󪫹ÔÄèÔÜÔ˜¸­Æ¹ÅÄ/L”\lÀu’x 4# "7èÕï„x¤:Z¬5d Y$]'+4 ."dª¢Ü»Ò¼-E76Z7nNdlG7]9$7L 5(4…=`Ûëà-LE*48  ; &M–=rá2fÆpˆz$L-M¸>vâ!C‚ÌåÚ %<’/e®o{,D´9MG 'Þõç=WW +T›,[Ÿ’ª¬43\Ç,  7gÓOkw1U» Ã¸DVr¦” ‚¤Œ=!2kFZûîú&Rl #4Td\ھس˜JmÍ ,š~¬ÕÌâ($;DL&p,X%I 5'iU!¤):ÉFA9GDjÓÔÖÕe²)<9 H ØFE‚,)7 ëIKj)%6#&¨89;4P 4E&¶@4˜âÞ•pA àYhPJ,A‡~(Ût,0ñC&Η"ŠCÎwÅa¥…†Œ9ñŽˆÝ Û” @¡ƒƒ¼5¤ÚqGZp¤X@QHñ"\Ö6eS´d–¦Xä–:¼b¥˜R\T¥Ž 2AdvP0CMà  àp%‘õ ‰ƒ„¥ÝpÊRBY±D‡ÞMwÙlBL‘å h6¥l5„¢zP §þÜ10abK%qE‹9JY‚@+ÀªõÂ,Ø6儳æGÁ‚[j7°•¢2YЀët»Vaâ-œ:®ù…›#š,4!*}Ù51‚¬¥a° ü™ë¡šÈ"¶ùmÆB¥Nh[¿•V0…vCú0A ¸†TIZ´p&š:º *ƒLˆ(®¸³"›,¸h: ­‰¼1ÑBùÅ’[àŠ˜?8„[û;B: ¬ÃLÖ­;n|ÃpΗƒ¢$#F*`EÉÂuY ‚>¨C·ãF9âÀB«èCÝJÕ7Ô ôƒC#‰æ(ª¨–áÞ0BB¸ºÂGÉ@­fÍàþœCd6t·uCÞsù®yNDWAš†[ÖÍzv'»%Ô ­ŠÍÖ7\]¼ð凇‰€îœsSѹQTýaÜ[É`hRš"€Œ.ÙYúðÅe-d¦,Ù Ë÷BÓ¡¬âJAÂçqA´v`0@i,ÂUAì½<¶ñ@¿™Ø\b‰â'×^ÊcDÆQÖP†«pò6"˜Áù †ù›zkÖ|¸U)<ŠKô)\ *ÅŠõaI ÀO¿6S³Ø¹ê~EÌJšEêM˜ÃNþU»e-RrÊÁïJÓŠ…(!'€AÐT6 ¬{ZÚŽun7®”è„þ*ªÙ£æÄ›{ÉæC.H`ÐR¸%­Ì¯èŠ@œ0ƒ<1RÀ€ ä¶DMM-NCS| '·4áY?`ÂØ„ðUˆ&Ü[‘ìW4¸ÀBèŠf ƒ#\àjà€âÖ½ïõîY`€Ø‡(@¸½¡h°MØ\0„ïOwK$]œb!‹Ö•`!Ã,† °¡ nxCà ¼qP€_íz'‰Ìn#ãXHG ‰7´€B,j±† Ø!Vàc Ô9ÌlÈbtðAAn Tdî FFüÆjì© ÷¸HF&îm :¸.fÄ |ÈBìðÁ”wþÀCÌt€@ ,\Ц€|u°š½¹Ÿø@׃’±xDœ#o¨°† HF»èD x ìá4àCü€<üpá¢Æ»¬1!Œp] ‹4©ªmljôC別ˆÆ‚ hÀÒP2ôÂ6¸À/:º…#Ðà€DIñ 3¹èÓ4Ÿ§p;Žý€GºØ"Õòƒ–q>è¤ÅL ¤áÀ†\…A‚ #(yÌ B ˆ©â!„‚‹.PƒB”¯§>0\ ƒ&™ön`CøÁ¦bv™`òƒ½ó->`Èà k0ˆA aÜ@ Å@H‘†#ð!ª~Åþ"øY>¨ ôÓRWÛ‚&ÍQ>ÞT™ÝzGÂéJWXÁ†(c´¤%-%JP âÐäxjb[R? áE|@¬$@:·‹\c÷ô‡± @A—åÕÃVpOXÄ€n~I{Œ°i€"NÐ Œ”»xðÃ"PúÇ#`€ X«oü6Á(ÁnKÀ ®¤I¹êVG¸ÁÝç7н@2ˆðA¤REp ñÇI! .X£‰˜ ·`+c,øAC‡Æ?qQàr¯”O~€‹ÖÀ% ÆØotõ«ŒDªAyiÄBÚ‡Ë ^æN ½úŒ@’®ëØþˆ$®$à°¿ÔÁ"ó¥,C¿¤….t™ŸR$$Š Š`¿ dƒÔÀ‡4”á€(Š‚tš&ÖvÒæë Œ°„ Ôµk‰ñ]f¬vÄ^Ć©>¢Ðx ÃS£ùâ#À¡Uõ Í<Ô1±Þ`"7{“N#È SÎ5±‰ñ쌷\pˆÞA•Ð ‡{ÝH$Ћ$ÐKGZáPPÖ I$Ó‡qàyÝå¬8hùáw±um– ÜàW‚Ї~èÐCà ÇP‹K° ·§ƒËVZo!A @ŽæHW¦l˜{À!q` [s –Àâr|ðÜE¸ŒÝµ ‹F·”à øÑ‹K@o2¨}ѵrˆpqö #—<Ƹ÷´ t@~EAM)^ˆÁo`un "ems þ H†œ`а Ýpޤ¥ y|–ŽpÊðqÊЀ~¦0°ø’Û[ßà’€$x_—Hˆ~4à¤7Uƒ` 6Ðr¥ “¨ƒÁ  Ù`6P”r—_#W àtúÕ < ‘3@2›€É7UtPcA”}‚x° !¥„0Uß6Œ¸``†`à §gáW `Ž¥æÇdŒO@2Ü@}YR‘Pc€t&¢ˆj 16„°`|pxð ‹`Oƒž¹ ½È)• l9já 2$ mIZað°0°o± ß@|~… ¬Øš•öG~þ· „p àP×ø ƒ@A€‘æÈ $0oë°“£¶{ê Ëà™ÑUœpñlJ/À nÀ†  X•.²Lmà~ð€à߇¸QrÙ`Yðä™ ÂrÄ  ìUQ™qŽ.Òƒ‘ú)ÎøŸ±õ8˜ÙiJâ@Rt âÙ‹A€™¶G Ý`6P¡%Îð; ]Ê€‚áR ¹ˆbô lÏRÜ  j0ÕmÀ—o€ùväð~â飊@jÊ`‡H¦`à †€ %F‘ùAÈ _hbU†wÉФå› ¥{Xm„ kjt¦Ôr’Pþtʦ ÚAY`žÄ l†b)Z!7¦pqeŒq¬ã"›° µY|‚ ¥ýÈù4Un``pˆ`p¨j™Ž6à fðÌ` ÌÀ ÂU–•ÊC¡`r ¡'ä/ùyH [èW5 O w̉·óh*¤Ê°<„$°ù¨oq‹À«Qð"}PUTJ¬(•F÷”S% `¡ŽZŸdZ¦%œ0޵.Apg2 ÃÍ®OðG›–`›.§ ¢Zl°m÷Ø®K€6¯¤e¿Ù!7° °Î`‘ú£»ð“GWÎÖ¤N:Щ–pþ®.7Á^üX‹v{ZRnpl¦&f²ˆAËp Yà Šͺ­(†ô€²dò",+Å÷ á¢åš®®Ù•Œù®fÙ_Ú!ÎÀ cˆ+äÉ›¹Ø“`ЭõÀI°œŠ° [m3$Š+~@séz]êW‘ðÞ—£¶™BëP™!KàžÉ ¿yÚ€²€&Xäð‹·°VJ ^PkmöW[ìZi ÚZbG‰+4`>š2ð\ô©lëà!GP (+`µEp[hXWR·¥7+[€ÀŠ"y›’f™o 2 !‹¡…g] ¡€²Q þDÛ`Ÿ–|€µ G^Éf7à}Ê ¢ˆ1™Ë›¾ÃÙ–£u¾>š” !•0h}ðj`¹¹km»ËšÉZ|tp­% ¸ù•o¢žŸœ‚&¾Ð…ÑU¤„j a½æu›[m~ /˾Õö ,§ (V$P¦©{`wºº% Á Q 7``ç€ k°»¥qšÌC6pgxv“•¦7Ù‹©[f0²Ê¶ f2%`)Á‚ŇŸ7òb`Å÷Wt A$0Ÿ£f¤â¢·c¦ YYà“&æ `H7p‰ !`&PܲŸçä w…æ êÉŽÂùþØP­ ù›#\)Ç`Æ¤å ¨¢ °vƒÆç ÇêçWTL·3[ûkU˜Pþ lbzˆ•Ðˋ؈÷êT7œ £M…Ð’o å!¾ ÁΜM¡Ç° DMÝrI 7¸¥îà× £ Âç¹Z^h‚%ì “‰× êÀ;º\Xæ;°î°L3íãÙ¬ -ÒËë¡^m¾ k6)ÅÆ!F@ ï GçéíãEè4ÞÇt= 3 then window.has_resize_grip = true end -- Create some more widgets for the window. local status_bar = Gtk.Statusbar() local toolbar = Gtk.Toolbar() local ctx = status_bar:get_context_id('default') status_bar:push(ctx, 'This is statusbar message.') -- When clicking at the toolbar 'quit' button, destroy the main window. toolbar:insert(Gtk.ToolButton { stock_id = 'gtk-quit', on_clicked = function() window:destroy() end, }, -1) -- About button in toolbar and its handling. local about_button = Gtk.ToolButton { stock_id = 'gtk-about' } function about_button:on_clicked() local dlg = Gtk.AboutDialog { program_name = 'LGI Demo', title = 'About...', name = 'LGI Hello', copyright = '(C) Copyright 2010, 2011 Pavel HolejÅ¡ovský', authors = { 'Adrian Perez de Castro', 'Pavel HolejÅ¡ovský', }, } if tonumber(Gtk._version) >= 3 then dlg.license_type = Gtk.License.MIT_X11 end dlg:run() dlg:hide() end toolbar:insert(about_button, -1) -- Pack everything into the window. local vbox = Gtk.VBox() vbox:pack_start(toolbar, false, false, 0) vbox:pack_start(Gtk.Label { label = 'Contents' }, true, true, 0) vbox:pack_end(status_bar, false, false, 0) window:add(vbox) -- Show window and start the loop. window:show_all() Gtk.main() lua-lgi-0.7.2/samples/gtkpad.lua000077500000000000000000000022741221440706400165030ustar00rootroot00000000000000#! /usr/bin/env lua --[[-------------------------------------------------------------------------- Sample GTK Application program, simple notepad implementation. Copyright (c) 2010 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local Gtk = lgi.require('Gtk', '3.0') local Gio = lgi.Gio local app = Gtk.Application.new('org.lgi.GtkPad', Gio.ApplicationFlags.HANDLES_OPEN) local function new_editor(file) local contents = file and file:load_contents() local window = Gtk.Window { type = Gtk.WindowType.TOPLEVEL, default_width = 400, default_height = 300, application = app, title = file and file:get_parse_name() or '', child = Gtk.ScrolledWindow { child = Gtk.TextView { buffer = Gtk.TextBuffer { text = contents and tostring(contents) or '' } } } } window:show_all() return window end function app:on_activate() new_editor() end function app:on_open(files) for i = 1, #files do new_editor(files[i]) end end return app:run {arg[0], ...} lua-lgi-0.7.2/samples/gtkterminal.lua000077500000000000000000000167221221440706400175550ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Lua console using Vte widget. It uses homegrown poor-man's -- Lua-only readline implementation (most of the code of this sample, -- not really related to GLib/Gtk in any way). -- local lgi = require 'lgi' local Gtk = lgi.require('Gtk', '3.0') local Vte = lgi.require('Vte', '2.90') -- Simple readline implementation with asynchronous interface. local ReadLine = {} ReadLine.__index = ReadLine function ReadLine.new() return setmetatable( { insert_mode = true, columns = 80, history = {}, }, ReadLine) end function ReadLine:start_line(prompt) self.input = '' self.pos = 1 self.prompt = prompt or '' self.history_pos = #self.history + 1 self.display(self.prompt) end -- Translates input string position into line/column pair. local function getpos(rl, pos) local full, part = math.modf((pos + #rl.prompt - 1) / rl.columns) return full, math.floor(part * rl.columns + 0.5) end -- Redisplays currently edited line, moves cursor to newpos, assumes -- that rl.input is updated with new contents but rl.pos still holds -- old cursor position. local function redisplay(rl, newpos, modified) if newpos < rl.pos then -- Go back with the cursor local oldl, oldc = getpos(rl, rl.pos) local newl, newc = getpos(rl, newpos) if oldl ~= newl then rl.display(('\27[%dA'):format(oldl - newl)) end if oldc ~= newc then rl.display(('\27[%d%s'):format(math.abs(newc - oldc), oldc < newc and 'C' or 'D')) end elseif newpos > rl.pos then -- Redraw portion between old and new cursor. rl.display(rl.input:sub(rl.pos, newpos - 1)) end rl.pos = newpos if modified then -- Save cursor, redraw the rest of the string, clear the rest of -- the line and screen and restore cursor position back. rl.display('\27[s' .. rl.input:sub(newpos, -1) .. '\27[K\27[J\27[u') end end local bindings = {} function bindings.default(rl, key) if not key:match('%c') then rl.input = rl.input:sub(1, rl.pos - 1) .. key .. rl.input:sub(rl.pos + (rl.insert_mode and 0 or 1), -1) redisplay(rl, rl.pos + 1, rl.insert_mode) end end function bindings.enter(rl) redisplay(rl, #rl.input + 1) rl.display('\n') rl.commit(rl.input) end function bindings.back(rl) if rl.pos > 1 then redisplay(rl, rl.pos - 1) end end function bindings.forward(rl) if rl.pos <= #rl.input then redisplay(rl, rl.pos + 1) end end function bindings.home(rl) if rl.pos ~= 1 then redisplay(rl, 1) end end function bindings.goto_end(rl) if rl.pos ~= #rl.input then redisplay(rl, #rl.input + 1) end end function bindings.backspace(rl) if rl.pos > 1 then rl.input = rl.input:sub(1, rl.pos - 2) .. rl.input:sub(rl.pos, -1) redisplay(rl, rl.pos - 1, true) end end function bindings.delete(rl) if rl.pos <= #rl.input then rl.input = rl.input:sub(1, rl.pos - 1) .. rl.input:sub(rl.pos + 1, -1) redisplay(rl, rl.pos, true) end end function bindings.kill(rl) rl.input = rl.input:sub(1, rl.pos - 1) redisplay(rl, rl.pos, true) end function bindings.clear(rl) rl.input = '' rl.history_pos = #rl.history + 1 redisplay(rl, 1, true) end local function set_history(rl) rl.input = rl.history[rl.history_pos] or '' redisplay(rl, 1, true) redisplay(rl, #rl.input + 1) end function bindings.up(rl) if rl.history_pos > 1 then rl.history_pos = rl.history_pos - 1 set_history(rl) end end function bindings.down(rl) if rl.history_pos <= #rl.history then rl.history_pos = rl.history_pos + 1 set_history(rl) end end -- Real keys are here bound to symbolic names. local function ctrl(char) return string.char(char:byte() - ('a'):byte() + 1) end bindings[ctrl'b'] = bindings.back bindings['\27[D'] = bindings.back bindings[ctrl'f'] = bindings.forward bindings['\27[C'] = bindings.forward bindings[ctrl'a'] = bindings.home bindings['\27OH'] = bindings.home bindings[ctrl'e'] = bindings.goto_end bindings['\27OF'] = bindings.goto_end bindings[ctrl'h'] = bindings.backspace bindings[ctrl'd'] = bindings.delete bindings['\127'] = bindings.delete bindings[ctrl'k'] = bindings.kill bindings[ctrl'c'] = bindings.clear bindings[ctrl'p'] = bindings.up bindings['\27[A'] = bindings.up bindings[ctrl'n'] = bindings.down bindings['\27[B'] = bindings.down bindings['\r'] = bindings.enter function ReadLine:receive(key) (bindings[key] or bindings.default)(self, key) end function ReadLine:add_line(line) -- Avoid duplicating lines in history. if self.history[#self.history] ~= line then self.history[#self.history + 1] = line end end -- Instantiate terminal widget and couple it with our custom readline. local terminal = Vte.Terminal { delete_binding = Vte.TerminalEraseBinding.ASCII_DELETE, } local readline = ReadLine.new() if Vte.Terminal.on_size_allocate then -- 'size_allocate' signal is not present in some older Gtk-3.0.gir files -- due to bug in older GI versions. Make sure that this does not trip us -- completely, it only means that readline will not react on the terminal -- resize events. function terminal:on_size_allocate(rect) readline.columns = self:get_column_count() end end function readline.display(str) -- Make sure that \n is always replaced with \r\n. Also make sure -- that after \n, kill-rest-of-line is always issued, so that -- random garbage does not stay on the screen. str = str:gsub('([^\r]?)\n', '%1\r\n'):gsub('\r\n', '\27[K\r\n') terminal:feed(str, #str) end function terminal:on_commit(str, length) readline.columns = self:get_column_count() readline:receive(str) end function readline.commit(line) -- Try to execute input line. line = line:gsub('^%s?(=)%s*', 'return ') local chunk, answer = (loadstring or load)(line, '=stdin') if chunk then (function(ok, ...) if not ok then answer = tostring(...) else answer = {} for i = 1, select('#', ...) do answer[#answer + 1] = tostring(select(i, ...)) end answer = #answer > 0 and table.concat(answer, '\t') end end)(pcall(chunk)) end if answer then readline.display(answer .. '\n') end -- Store the line into rl history and start reading new line. readline:add_line(line) readline:start_line(_PROMPT or '> ') end -- Create the application. local app = Gtk.Application { application_id = 'org.lgi.samples.gtkconsole' } -- Pack terminal into the window with scrollbar. function app:on_activate() local grid = Gtk.Grid { child = terminal } grid:add(Gtk.Scrollbar { orientation = Gtk.Orientation.VERTICAL, adjustment = terminal.adjustment, }) terminal.expand = true readline.display [[ This is terminal emulation of standard Lua console. Enter Lua commands as in interactive Lua console. The advantage over standard console is that in this context, GMainLoop is running, so this console is ideal for interactive toying with Gtk (and other mainloop-based) components. Try following: Gtk = lgi.Gtk window = Gtk.Window { title = 'Test' } window:show_all() window.title = 'Different' ]] local window = Gtk.Window { application = self, title = 'Lua Terminal', default_width = 640, default_height = 480, has_resize_grip = true, child = grid, } window:show_all() readline.columns = terminal:get_column_count() readline:start_line(_PROMPT or '> ') -- For convenience, propagate 'lgi' into the global namespace. _G.lgi = lgi end -- Start the application. app:run { arg[0], ... } lua-lgi-0.7.2/samples/mxwidgets.lua000077500000000000000000000061441221440706400172440ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Basic MX sample, adapted from Vala code from -- http://live.gnome.org/Vala/MxSample -- local lgi = require('lgi') local GObject = lgi.GObject local Mx = lgi.require('Mx', '1.0') local Clutter = lgi.require('Clutter', '1.0') local app = Mx.Application { application_name = "MX Widget Factory" } local window = app:create_window() window.clutter_stage:set_size(500, 300) local hbox = Mx.BoxLayout() window.toolbar:add_actor(hbox) local button = Mx.Button { label = "Click me", tooltip_text = "Please click this button!", on_clicked = function(self) self.label = "Thank you!" end } local combo = Mx.ComboBox() for _, name in ipairs { "Africa", "Antarctica", "Asia", "Australia", "Europe", "North America", "South America" } do combo:append_text(name) end combo.index = 0 function combo.on_notify:index() print(("Selected continent: %s"):format(self.active_text)) end hbox:add(button, combo) local table = Mx.Table { column_spacing = 24, row_spacing = 24 } local button = Mx.Button { label = "Button" } table:add_actor(button, 0, 0) table.meta[button].y_fill = false local entry = Mx.Entry { text = "Entry" } table:add_actor(entry, 0, 1) table.meta[entry].y_fill = false local combo = Mx.ComboBox { active_text = "Combo Box" } combo:append_text("Hello") combo:append_text("Dave") table:add_actor(combo, 0, 2) table.meta[entry].y_fill = false local scrollbar = Mx.ScrollBar { adjustment = Mx.Adjustment { lower = 0, upper = 10, page_increment = 1, page_size = 1 }, height = 22 } table:add_actor(scrollbar, 1, 0) table.meta[entry].y_fill = false local progressbar = Mx.ProgressBar { progress = 0.7 } table:add_actor(progressbar, 1, 1) table.meta[progressbar].y_fill = false local slider = Mx.Slider() table:add_actor(slider, 1, 2) table.meta[slider].y_fill = false function slider.on_notify:value() progressbar.progress = slider.value end local pathbar = Mx.PathBar() for _, path in ipairs { "", "Path", "Bar" } do pathbar:push(path) end table:add_actor(pathbar, 2, 0) local expander = Mx.Expander { label = "Expander" } table:add_actor(expander, 2, 1) table.meta[expander].y_fill = false expander:add_actor(Mx.Label { text = "Hello" }) local toggle = Mx.Toggle() table:add_actor(toggle, 2, 2) table.meta[toggle].y_fill = false local togglebutton = Mx.Button { label = "Toggle", is_toggle = true } table:add_actor(togglebutton, 3, 0) table.meta[togglebutton].y_fill = false local checkbutton = Mx.Button { is_toggle = true } checkbutton:set_style_class('check-box') table:add_actor(checkbutton, 3, 1) table.meta[checkbutton].y_fill = false table.meta[checkbutton].x_fill = false -- Just for fun, create binding between both kinds of toggles. togglebutton:bind_property('toggled', checkbutton, 'toggled', GObject.BindingFlags.BIDIRECTIONAL) scrollbar = Mx.ScrollBar { adjustment = Mx.Adjustment { lower = 0, upper = 10, page_increment = 1, page_size = 1, }, orientation = Mx.Orientation.VERTICAL, width = 22 } table:add_actor(scrollbar, 0, 3) table.meta[scrollbar].row_span = 3 window.child = Mx.Frame { child = table } window.clutter_stage:show() app:run() lua-lgi-0.7.2/samples/repobrowser.lua000077500000000000000000000071151221440706400176010ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Implementation of simple browser of lgi repository. This is mainly -- treeview usage demonstration. -- local lgi = require 'lgi' local GObject = lgi.GObject local Gtk = lgi.require('Gtk', '3.0') local function RepoBrowser() local self = {} -- Create browser model. local column = { NAME = 1, VALUE = 2, } local model = Gtk.TreeStore.new { [column.NAME] = GObject.Type.STRING, [column.VALUE] = GObject.Type.STRING, } -- Merges repository table into the treemodel as child of given -- iterator. local blacklisted = { _parent = true, _implements = true, __index = true, } local function merge(parent, table) for name, value in pairs(table) do local string_value = '' if type(value) == 'string' then string_value = value elseif type(value) == 'number' then string_value = tonumber(value) elseif name == '_parent' then string_value = value._name end local iter = model:append(parent, { [column.NAME] = name, [column.VALUE] = string_value, }) if type(value) == 'table' and not blacklisted[name] then merge(iter, value) end end end -- Loads specified repo namespace into the model. function self.add(namespace) local iter = model:append(nil, { [column.NAME] = namespace._name, [column.VALUE] = namespace._version, }) merge(iter, namespace:_resolve(true)) end -- Create treeview widget with columns. local sorted = Gtk.TreeModelSort { model = model } sorted:set_sort_func(column.NAME, function(model, a, b) a = model[a][column.NAME] b = model[b][column.NAME] if a == b then return 0 elseif a < b then return -1 else return 1 end end) sorted:set_sort_column_id(column.NAME, Gtk.SortType.ASCENDING) self.view = Gtk.TreeView { model = sorted, Gtk.TreeViewColumn { title = "Name", resizable = true, sort_column_id = column.NAME, { Gtk.CellRendererText(), expand = true, { text = column.NAME } }, }, Gtk.TreeViewColumn { { Gtk.CellRendererText(), { text = column.VALUE } }, }, } return self end -- Create application and its window. local app = Gtk.Application { application_id = 'org.lgi.repobrowser' } function app:on_activate() local browser = RepoBrowser() browser.add(lgi.GObject) -- Global window. local window = Gtk.Window { application = app, title = "LGI Repository Browser", default_width = 800, default_height = 640, Gtk.Grid { row_spacing = 5, column_spacing = 5, margin = 5, { Gtk.Label { label = "Namespace" } }, { Gtk.Entry { id = 'name', hexpand = true }, left_attach = 1 }, { Gtk.Label { label = "Version" }, left_attach = 2 }, { Gtk.Entry { id = 'version', hexpand = true }, left_attach = 3 }, { Gtk.Button { id = 'add', label = Gtk.STOCK_ADD, use_stock = true }, left_attach = 4 }, { Gtk.ScrolledWindow { expand = true, browser.view }, left_attach = 0, top_attach = 1, width = 5 }, } } function window.child.add:on_clicked() local version = window.child.version.text if version == '' then version = nil end local ok, data = pcall(lgi.require, window.child.name.text, version) if ok then browser.add(data) else local message = Gtk.MessageDialog { text = "Failed to load requested namespace", secondary_text = data, message_type = Gtk.MessageType.ERROR, buttons = Gtk.ButtonsType.CLOSE, transient_for = window, } message:run() message:destroy() end end window:show_all() end app:run { arg[0], ... } lua-lgi-0.7.2/samples/soupsvr.lua000066400000000000000000000047771221440706400167610ustar00rootroot00000000000000#! /usr/bin/env lua -- -- Sample server using libsoup library. Listens on 1080 port and serves -- local files from current directory. Allows to be terminated by query -- for /quit file (i.e. curl http://localhost:1080/quit) -- local coroutine = require 'coroutine' local lgi = require 'lgi' local bytes = require 'bytes' local GLib = lgi.GLib local Gio = lgi.Gio local Soup = lgi.Soup local app = Gio.Application { application_id = 'org.lgi.soupsvr' } function app:on_activate() app:hold() local server = Soup.Server { port = 1080 } -- Set up quit handler. server:add_handler('/quit', function(server, msg, path, query, ctx) msg.status_code = 200 msg.response_body:complete() server:quit() app:release() end) -- Set up file retriever handler. server:add_handler('/', function(server, msg, path, query, ctx) local stream = Gio.File.new_for_path(path:sub(2)):read() if stream then -- The whole is send by function running in coroutine. -- Coroutine yields when it waits either for data from the -- disk or signal that chunk was successfully sent. local next_chunk = coroutine.wrap(function() local buffer = bytes.new(4096) while true do -- Read another chunk of data from the source to the -- buffer. stream:read_async(buffer, #buffer, GLib.PRIORITY_DEFAULT, nil, coroutine.running()) local size = stream.read_finish(coroutine.yield()) if size < 0 then -- IO error reading disk, this simply shuts our toy -- server down. server:quit() app:release() return end -- Send the chunk to the message body. msg.response_body:append(tostring(buffer):sub(1, size)) server:unpause_message(msg) -- Wait until soup signalizes that chunk was written. coroutine.yield() if (size < #buffer) then break end end msg.response_body:complete() end) -- Prepare sending using chunked method. msg.status_code = 200 msg.response_headers:set_encoding('CHUNKED') -- When headers are written, start writing body by initial -- resuming of sending coroutine. msg.on_wrote_headers = next_chunk -- When the chunk is sent, resume coroutine so that it starts -- reading and sending another chunk. msg.on_wrote_chunk = next_chunk else -- File was not found, send proper code. msg.status_code = 404 msg.response_body:complete() end end) -- Start the server running asynchronously. server:run_async() end app:run { arg[0], ... } lua-lgi-0.7.2/tests/000077500000000000000000000000001221440706400142145ustar00rootroot00000000000000lua-lgi-0.7.2/tests/.gitignore000066400000000000000000000000201221440706400161740ustar00rootroot00000000000000*.gir *.typelib lua-lgi-0.7.2/tests/Makefile000066400000000000000000000037751221440706400156700ustar00rootroot00000000000000# # Makefile for compiling lgi testsuite support # # Author: Pavel Holejsovsky # License: MIT # ifneq ($(filter CYGWIN%, $(shell uname -s)),) EXT = .dll PFX = cyg LIBFLAG = -shared else ifeq ($(shell uname -s),Darwin) EXT = .so PFX = lib LIBFLAG = -bundle -undefined dynamic_lookup CCSHARED = -fno-common else EXT = .so PFX = lib LIBFLAG = -shared CCSHARED = -fPIC endif endif PKGS = gio-2.0 cairo cairo-gobject gobject-introspection-1.0 gmodule-2.0 libffi LUA = lua ifndef CFLAGS ifndef COPTFLAGS CFLAGS = -Wall -g endif endif ALL_CFLAGS = $(CCSHARED) $(COPTFLAGS) $(LUA_CFLAGS) $(shell pkg-config --cflags $(PKGS)) $(CFLAGS) LIBS += $(shell pkg-config --libs $(PKGS)) ALL_LDFLAGS = $(LIBFLAG) $(LDFLAGS) DEPCHECK = .depcheck # Precondition check $(DEPCHECK) : Makefile pkg-config --exists '$(PKGS) >= 0.10.8' --print-errors touch $@ REGRESS = $(PFX)regress$(EXT) REGRESS_OBJS = regress.o .PHONY : all clean check all : Regress-1.0.typelib clean : rm -f $(REGRESS) $(REGRESS_OBJS) Regress-1.0.gir Regress-1.0.typelib check : all cd .. && LD_LIBRARY_PATH=tests:$$LD_LIBRARY_PATH \ GI_TYPELIB_PATH=tests:$$GI_TYPELIB_PATH \ LUA_PATH=./?.lua\;`$(LUA) -e "print(package.path)"` \ LUA_CPATH=./?.so\;`$(LUA) -e "print(package.cpath)"` \ $(LUA) tests/test.lua $(REGRESS) : regress.o $(CC) $(ALL_LDFLAGS) -o $@ regress.o $(LIBS) GIDATADIR = $(shell pkg-config --variable=gidatadir gobject-introspection-1.0)/tests regress.o : $(GIDATADIR)/regress.c $(GIDATADIR)/regress.h $(DEPCHECK) $(CC) $(ALL_CFLAGS) -c -o $@ $< # Build .gir and .typelib Regress-1.0.gir : $(REGRESS) LDFLAGS="" CFLAGS="" \ g-ir-scanner --warn-all --no-libtool --quiet --output=$@ \ --namespace=Regress --nsversion=1.0 \ --include=cairo-1.0 --include=Gio-2.0 \ --library-path=/usr/lib --library-path=/usr/X11R6/lib \ --library-path=/usr/local/lib \ $(GIDATADIR)/regress.c $(GIDATADIR)/regress.h \ -lregress Regress-1.0.typelib : Regress-1.0.gir g-ir-compiler --output=$@ $< lua-lgi-0.7.2/tests/cairo.lua000066400000000000000000000215741221440706400160250ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, cairo overrides test group. Copyright (c) 2012 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local io = require 'io' local os = require 'os' local lgi = require 'lgi' local check = testsuite.check local checkv = testsuite.checkv local cairo = testsuite.group.new('cairo') function cairo.status() local cairo = lgi.cairo for name, value in pairs(cairo.Status) do if type(name) == 'string' and type(value) == 'number' then checkv(cairo.Status.to_string(name), cairo.Status.to_string(value), 'string') end end end function cairo.matrix() local cairo = lgi.cairo local matrix = cairo.Matrix() checkv(matrix.xx, 0, 'number') checkv(matrix.yx, 0, 'number') checkv(matrix.xy, 0, 'number') checkv(matrix.yy, 0, 'number') checkv(matrix.x0, 0, 'number') checkv(matrix.y0, 0, 'number') matrix = cairo.Matrix { xx = 1, yx =1.5, xy = 2, yy = 2.5, x0 = 3, y0 = 3.5 } checkv(matrix.xx, 1, 'number') checkv(matrix.yx, 1.5, 'number') checkv(matrix.xy, 2, 'number') checkv(matrix.yy, 2.5, 'number') checkv(matrix.x0, 3, 'number') checkv(matrix.y0, 3.5, 'number') end function cairo.matrix_getset() local cairo = lgi.cairo local surface = cairo.ImageSurface('ARGB32', 100, 100) local cr = cairo.Context(surface) local m = cairo.Matrix { xx = 1, yx =1.5, xy = 2, yy = 2.5, x0 = 3, y0 = 3.5 } cr.matrix = m local m2 = cr.matrix check(m.xx == m2.xx) check(m.yx == m2.yx) check(m.xy == m2.xy) check(m.yy == m2.yy) check(m.x0 == m2.x0) check(m.y0 == m2.y0) end function cairo.dash() local cairo = lgi.cairo local surface = cairo.ImageSurface('ARGB32', 100, 100) local cr = cairo.Context(surface) local dash, offset = cr:get_dash() check(type(dash) == 'table') check(next(dash) == nil) cr:set_dash({ 1, 2, math.pi }, 2.22) dash, offset = cr:get_dash() check(#dash == 3) check(dash[1] == 1) check(dash[2] == 2) check(dash[3] == math.pi) check(offset == 2.22) cr:set_dash(nil, 0) dash, offset = cr:get_dash() check(type(dash) == 'table') check(next(dash) == nil) end function cairo.path() local cairo = lgi.cairo local surface = cairo.ImageSurface('ARGB32', 100, 100) local cr = cairo.Context(surface) cr:move_to(10, 11) cr:curve_to(1, 2, 3, 4, 5, 6) cr:close_path() cr:line_to(21, 22) local i = 1 for t, pts in cr:copy_path():pairs() do if i == 1 then checkv(t, 'MOVE_TO', 'string') check(type(pts) == 'table' and #pts == 1) checkv(pts[1].x, 10, 'number') checkv(pts[1].y, 11, 'number') elseif i == 2 then checkv(t, 'CURVE_TO', 'string') check(type(pts) == 'table' and #pts == 3) checkv(pts[1].x, 1, 'number') checkv(pts[1].y, 2, 'number') checkv(pts[2].x, 3, 'number') checkv(pts[2].y, 4, 'number') checkv(pts[3].x, 5, 'number') checkv(pts[3].y, 6, 'number') elseif i == 3 then checkv(t, 'CLOSE_PATH', 'string') check(type(pts) == 'table' and #pts == 0) elseif i == 4 then checkv(t, 'MOVE_TO', 'string') check(type(pts) == 'table' and #pts == 1) checkv(pts[1].x, 10, 'number') checkv(pts[1].y, 11, 'number') elseif i == 5 then checkv(t, 'LINE_TO', 'string') check(type(pts) == 'table' and #pts == 1) checkv(pts[1].x, 21, 'number') checkv(pts[1].y, 22, 'number') else check(false) end i = i + 1 end check(i == 6) end function cairo.surface_type() local cairo = lgi.cairo local surface = cairo.ImageSurface('ARGB32', 100, 100) local cr = cairo.Context(surface) check(cairo.ImageSurface:is_type_of(surface)) check(cairo.Surface:is_type_of(surface)) check(not cairo.RecordingSurface:is_type_of(surface)) local s2 = cr.target check(cairo.ImageSurface:is_type_of(s2)) check(cairo.Surface:is_type_of(s2)) check(not cairo.RecordingSurface:is_type_of(s2)) end function cairo.pattern_type() local cairo = lgi.cairo local pattern pattern = cairo.Pattern.create_rgb(1, 1, 1) check(cairo.SolidPattern:is_type_of(pattern)) check(cairo.Pattern:is_type_of(pattern)) pattern = cairo.SolidPattern(1, 1, 1) check(cairo.SolidPattern:is_type_of(pattern)) pattern = cairo.SolidPattern(1, 1, 1, 1) check(cairo.SolidPattern:is_type_of(pattern)) local surface = cairo.ImageSurface('ARGB32', 100, 100) pattern = cairo.Pattern.create_for_surface(surface) check(select(2, pattern:get_surface()) == surface) check(cairo.SurfacePattern:is_type_of(pattern)) check(cairo.Pattern:is_type_of(pattern)) pattern = cairo.SurfacePattern(surface) check(cairo.SurfacePattern:is_type_of(pattern)) pattern = cairo.Pattern.create_linear(0, 0, 10, 10) check(cairo.LinearPattern:is_type_of(pattern)) check(cairo.GradientPattern:is_type_of(pattern)) check(cairo.Pattern:is_type_of(pattern)) pattern = cairo.LinearPattern(0, 0, 10, 10) check(cairo.LinearPattern:is_type_of(pattern)) pattern = cairo.Pattern.create_radial(0, 0, 5, 10, 10, 5) check(cairo.RadialPattern:is_type_of(pattern)) check(cairo.GradientPattern:is_type_of(pattern)) check(cairo.Pattern:is_type_of(pattern)) pattern = cairo.RadialPattern(0, 0, 5, 10, 10, 5) check(cairo.RadialPattern:is_type_of(pattern)) if cairo.version >= cairo.version_encode(1, 12, 0) then pattern = cairo.Pattern.create_mesh() check(cairo.MeshPattern:is_type_of(pattern)) check(not cairo.GradientPattern:is_type_of(pattern)) check(cairo.Pattern:is_type_of(pattern)) pattern = cairo.MeshPattern() check(cairo.MeshPattern:is_type_of(pattern)) end end function cairo.pattern_mesh() local cairo = lgi.cairo -- Mesh patterns are introduced in cairo 1.12 if cairo.version < cairo.version_encode(1, 12, 0) then return end local mesh = cairo.Pattern.create_mesh() local pattern = cairo.Pattern.create_radial(1, 2, 3, 4, 5, 6) check(cairo.Pattern:is_type_of(mesh)) check(cairo.MeshPattern:is_type_of(mesh)) check(cairo.Pattern:is_type_of(pattern)) check(not cairo.MeshPattern:is_type_of(pattern)) local function check_status(status) checkv(status, 'SUCCESS', 'string') end -- Taken from cairo's pattern-getters test and slightly adapted to use all -- functions of the mesh pattern API local status, count = mesh:get_patch_count() check_status(status) checkv(count, 0, 'number') mesh:begin_patch() mesh:move_to(0, 0) mesh:line_to(0, 3) mesh:line_to(3, 3) mesh:line_to(3, 0) mesh:set_corner_color_rgba(0, 1, 1, 1, 1) mesh:end_patch() local status, count = mesh:get_patch_count() check_status(status) checkv(count, 1, 'number') for k, v in pairs({ { 1, 1 }, { 1, 2 }, { 2, 2 }, { 2, 1 } }) do local status, x, y = mesh:get_control_point(0, k - 1) check_status(status) checkv(x, v[1], 'number') checkv(y, v[2], 'number') end mesh:begin_patch() mesh:move_to(0, 0) mesh:line_to(1, 0) mesh:curve_to(1, 1, 1, 2, 0, 1) mesh:set_corner_color_rgb(0, 1, 1, 1) mesh:set_control_point(2, 0.5, 0.5) mesh:end_patch() local status, count = mesh:get_patch_count() check_status(status) checkv(count, 2, 'number') for k, v in pairs({ 1, 0, 0, 1 }) do local status, r, g, b, a = mesh:get_corner_color_rgba(1, k - 1) check_status(status) checkv(r, v, 'number') checkv(g, v, 'number') checkv(b, v, 'number') checkv(a, v, 'number') end local i = 0 local expected = { { { 0, 1 }, { 0, 2 }, { 0, 3 } }, { { 1, 3 }, { 2, 3 }, { 3, 3 } }, { { 3, 2 }, { 3, 1 }, { 3, 0 } }, { { 2, 0 }, { 1, 0 }, { 0, 0 } }, } for t, pts in mesh:get_path(0):pairs() do if i == 0 then checkv(t, 'MOVE_TO', 'string') check(type(pts) == 'table' and #pts == 1) checkv(pts[1].x, 0, 'number') checkv(pts[1].y, 0, 'number') else -- Mesh patterns turn everything into curves. :-( checkv(t, 'CURVE_TO', 'string') check(type(pts) == 'table' and #pts == 3) for k, v in pairs(expected[i]) do checkv(pts[k].x, v[1], 'number') checkv(pts[k].y, v[2], 'number') end end i = i + 1 end check(i == #expected + 1) end function cairo.context_transform() local cairo = lgi.cairo local surface = cairo.ImageSurface('ARGB32', 100, 100) local cr = cairo.Context(surface) function compare(a, b) check(math.abs(a-b) < 0.1) end cr:rotate(-math.pi / 2) cr:translate(100, 200) local x, y = cr:user_to_device(10, 20) compare(x, 220) compare(y, -110) local x, y = cr:device_to_user(220, -110) compare(x, 10) compare(y, 20) local x, y = cr:user_to_device_distance(10, 20) compare(x, 20) compare(y, -10) local x, y = cr:device_to_user_distance(20, -10) compare(x, 10) compare(y, 20) end lua-lgi-0.7.2/tests/corocbk.lua000066400000000000000000000027261221440706400163500ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, coroutine-targetted callbacks Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local coroutine = require 'coroutine' local lgi = require 'lgi' local check, checkv = testsuite.check, testsuite.checkv -- Basic GObject testing local corocbk = testsuite.group.new('corocbk') function corocbk.resume_suspd() local GLib = lgi.GLib local main_loop = GLib.MainLoop() local coro = coroutine.create( function() coroutine.yield() coroutine.yield(true) main_loop:quit() end) coroutine.resume(coro) GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, coro) main_loop:run() end function corocbk.resume_init() local GLib = lgi.GLib local main_loop = GLib.MainLoop() local coro = coroutine.create( function() coroutine.yield(true) main_loop:quit() end) GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, coro) main_loop:run() end function corocbk.rethrow() local GLib = lgi.GLib local main_loop = GLib.MainLoop() local coro = coroutine.create( function() (function() error('err') end)() end) GLib.idle_add(GLib.PRIORITY_DEFAULT, coro) local ok, err = pcall(main_loop.run, main_loop) checkv(ok, false, 'boolean') checkv(err, 'err', 'string') end lua-lgi-0.7.2/tests/gireg.lua000066400000000000000000001243631221440706400160250ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, GI Regress-based testsuite. Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local bytes = require 'bytes' local fail = testsuite.fail local check = testsuite.check local checkv = testsuite.checkv local gireg = testsuite.group.new('gireg') function gireg.type_boolean() local R = lgi.Regress checkv(R.test_boolean(true), true, 'boolean') checkv(R.test_boolean(false), false, 'boolean') check(select('#', R.test_boolean(true)) == 1) check(select('#', R.test_boolean(false)) == 1) checkv(R.test_boolean(), false, 'boolean') checkv(R.test_boolean(nil), false, 'boolean') checkv(R.test_boolean(0), true, 'boolean') checkv(R.test_boolean(1), true, 'boolean') checkv(R.test_boolean('string'), true, 'boolean') checkv(R.test_boolean({}), true, 'boolean') checkv(R.test_boolean(function() end), true, 'boolean') end function gireg.type_int8() local R = lgi.Regress checkv(R.test_int8(0), 0, 'number') checkv(R.test_int8(1), 1, 'number') checkv(R.test_int8(-1), -1, 'number') checkv(R.test_int8(1.1), 1, 'number') checkv(R.test_int8(-1.1), -1, 'number') checkv(R.test_int8(0x7f), 0x7f, 'number') checkv(R.test_int8(-0x80), -0x80, 'number') check(not pcall(R.test_int8, 0x80)) check(not pcall(R.test_int8, -0x81)) check(not pcall(R.test_int8)) check(not pcall(R.test_int8, nil)) check(not pcall(R.test_int8, 'string')) check(not pcall(R.test_int8, true)) check(not pcall(R.test_int8, {})) check(not pcall(R.test_int8, function() end)) end function gireg.type_uint8() local R = lgi.Regress checkv(R.test_uint8(0), 0, 'number') checkv(R.test_uint8(1), 1, 'number') checkv(R.test_uint8(1.1), 1, 'number') checkv(R.test_uint8(0xff), 0xff, 'number') check(not pcall(R.test_uint8, 0x100)) check(not pcall(R.test_uint8, -1)) check(not pcall(R.test_uint8)) check(not pcall(R.test_uint8, nil)) check(not pcall(R.test_uint8, 'string')) check(not pcall(R.test_uint8, true)) check(not pcall(R.test_uint8, {})) check(not pcall(R.test_uint8, function() end)) end function gireg.type_int16() local R = lgi.Regress checkv(R.test_int16(0), 0, 'number') checkv(R.test_int16(1), 1, 'number') checkv(R.test_int16(-1), -1, 'number') checkv(R.test_int16(1.1), 1, 'number') checkv(R.test_int16(-1.1), -1, 'number') checkv(R.test_int16(0x7fff), 0x7fff, 'number') checkv(R.test_int16(-0x8000), -0x8000, 'number') check(not pcall(R.test_int16, 0x8000)) check(not pcall(R.test_int16, -0x8001)) check(not pcall(R.test_int16)) check(not pcall(R.test_int16, nil)) check(not pcall(R.test_int16, 'string')) check(not pcall(R.test_int16, true)) check(not pcall(R.test_int16, {})) check(not pcall(R.test_int16, function() end)) end function gireg.type_uint16() local R = lgi.Regress checkv(R.test_uint16(0), 0, 'number') checkv(R.test_uint16(1), 1, 'number') checkv(R.test_uint16(1.1), 1, 'number') checkv(R.test_uint16(0xffff), 0xffff, 'number') check(not pcall(R.test_uint16, 0x10000)) check(not pcall(R.test_uint16, -1)) check(not pcall(R.test_uint16)) check(not pcall(R.test_uint16, nil)) check(not pcall(R.test_uint16, 'string')) check(not pcall(R.test_uint16, true)) check(not pcall(R.test_uint16, {})) check(not pcall(R.test_uint16, function() end)) end function gireg.type_int32() local R = lgi.Regress checkv(R.test_int32(0), 0, 'number') checkv(R.test_int32(1), 1, 'number') checkv(R.test_int32(-1), -1, 'number') checkv(R.test_int32(1.1), 1, 'number') checkv(R.test_int32(-1.1), -1, 'number') checkv(R.test_int32(0x7fffffff), 0x7fffffff, 'number') checkv(R.test_int32(-0x80000000), -0x80000000, 'number') check(not pcall(R.test_int32, 0x80000000)) check(not pcall(R.test_int32, -0x80000001)) check(not pcall(R.test_int32)) check(not pcall(R.test_int32, nil)) check(not pcall(R.test_int32, 'string')) check(not pcall(R.test_int32, true)) check(not pcall(R.test_int32, {})) check(not pcall(R.test_int32, function() end)) end function gireg.type_uint32() local R = lgi.Regress checkv(R.test_uint32(0), 0, 'number') checkv(R.test_uint32(1), 1, 'number') checkv(R.test_uint32(1.1), 1, 'number') checkv(R.test_uint32(0xffffffff), 0xffffffff, 'number') check(not pcall(R.test_uint32, 0x100000000)) check(not pcall(R.test_uint32, -1)) check(not pcall(R.test_uint32)) check(not pcall(R.test_uint32, nil)) check(not pcall(R.test_uint32, 'string')) check(not pcall(R.test_uint32, true)) check(not pcall(R.test_uint32, {})) check(not pcall(R.test_uint32, function() end)) end function gireg.type_int64() local R = lgi.Regress checkv(R.test_int64(0), 0, 'number') checkv(R.test_int64(1), 1, 'number') checkv(R.test_int64(-1), -1, 'number') checkv(R.test_int64(1.1), 1, 'number') checkv(R.test_int64(-1.1), -1, 'number') check(not pcall(R.test_int64)) check(not pcall(R.test_int64, nil)) check(not pcall(R.test_int64, 'string')) check(not pcall(R.test_int64, true)) check(not pcall(R.test_int64, {})) check(not pcall(R.test_int64, function() end)) -- Following tests fail because Lua's internal number representation -- is always 'double', and conversion between double and int64 big -- constants is always lossy. Not sure if it can be solved somehow. -- checkv(R.test_int64(0x7fffffffffffffff), 0x7fffffffffffffff, 'number') -- checkv(R.test_int64(-0x8000000000000000), -0x8000000000000000, 'number') -- check(not pcall(R.test_int64, 0x8000000000000000)) -- check(not pcall(R.test_int64, -0x8000000000000001)) end function gireg.type_uint64() local R = lgi.Regress checkv(R.test_uint64(0), 0, 'number') checkv(R.test_uint64(1), 1, 'number') checkv(R.test_uint64(1.1), 1, 'number') check(not pcall(R.test_uint64, -1)) check(not pcall(R.test_uint64)) check(not pcall(R.test_uint64, nil)) check(not pcall(R.test_uint64, 'string')) check(not pcall(R.test_uint64, true)) check(not pcall(R.test_uint64, {})) check(not pcall(R.test_uint64, function() end)) -- See comment above about lossy conversions. -- checkv(R.test_uint64(0xffffffffffffffff), 0xffffffffffffffff, 'number') -- check(not pcall(R.test_uint64, 0x10000000000000000)) end function gireg.type_short() local R = lgi.Regress checkv(R.test_short(0), 0, 'number') checkv(R.test_short(1), 1, 'number') checkv(R.test_short(-1), -1, 'number') checkv(R.test_short(1.1), 1, 'number') checkv(R.test_short(-1.1), -1, 'number') end function gireg.type_ushort() local R = lgi.Regress checkv(R.test_ushort(0), 0, 'number') checkv(R.test_ushort(1), 1, 'number') checkv(R.test_ushort(1.1), 1, 'number') check(not pcall(R.test_ushort, -1)) end function gireg.type_int() local R = lgi.Regress checkv(R.test_int(0), 0, 'number') checkv(R.test_int(1), 1, 'number') checkv(R.test_int(-1), -1, 'number') checkv(R.test_int(1.1), 1, 'number') checkv(R.test_int(-1.1), -1, 'number') end function gireg.type_uint() local R = lgi.Regress checkv(R.test_uint(0), 0, 'number') checkv(R.test_uint(1), 1, 'number') checkv(R.test_uint(1.1), 1, 'number') check(not pcall(R.test_uint, -1)) end function gireg.type_ssize() local R = lgi.Regress checkv(R.test_ssize(0), 0, 'number') checkv(R.test_ssize(1), 1, 'number') checkv(R.test_ssize(-1), -1, 'number') checkv(R.test_ssize(1.1), 1, 'number') checkv(R.test_ssize(-1.1), -1, 'number') end function gireg.type_size() local R = lgi.Regress checkv(R.test_size(0), 0, 'number') checkv(R.test_size(1), 1, 'number') checkv(R.test_size(1.1), 1, 'number') check(not pcall(R.test_size, -1)) end -- Helper, checks that given value has requested type and value, with some -- tolerance because of low precision of gfloat type. local function checkvf(val, exp, tolerance) check(type(val) == 'number', string.format( "got type `%s', expected `number'", type(val)), 2) check(math.abs(val - exp) <= tolerance, string.format("got value `%s', expected `%s'", tostring(val), tostring(exp)), 2) end function gireg.type_float() local R = lgi.Regress local t = 0.0000001 checkvf(R.test_float(0), 0, t) checkvf(R.test_float(1), 1, t) checkvf(R.test_float(1.1), 1.1, t) checkvf(R.test_float(-1), -1, t) checkvf(R.test_float(-1.1), -1.1, t) checkvf(R.test_float(0x8000), 0x8000, t) checkvf(R.test_float(0xffff), 0xffff, t) checkvf(R.test_float(-0x8000), -0x8000, t) checkvf(R.test_float(-0xffff), -0xffff, t) check(not pcall(R.test_float)) check(not pcall(R.test_float, nil)) check(not pcall(R.test_float, 'string')) check(not pcall(R.test_float, true)) check(not pcall(R.test_float, {})) check(not pcall(R.test_float, function() end)) end function gireg.type_double() local R = lgi.Regress checkv(R.test_double(0), 0, 'number') checkv(R.test_double(1), 1, 'number') checkv(R.test_double(1.1), 1.1, 'number') checkv(R.test_double(-1), -1, 'number') checkv(R.test_double(-1.1), -1.1, 'number') checkv(R.test_double(0x80000000), 0x80000000, 'number') checkv(R.test_double(0xffffffff), 0xffffffff, 'number') checkv(R.test_double(-0x80000000), -0x80000000, 'number') checkv(R.test_double(-0xffffffff), -0xffffffff, 'number') check(not pcall(R.test_double)) check(not pcall(R.test_double, nil)) check(not pcall(R.test_double, 'string')) check(not pcall(R.test_double, true)) check(not pcall(R.test_double, {})) check(not pcall(R.test_double, function() end)) end function gireg.type_timet() local R = lgi.Regress checkv(R.test_timet(0), 0, 'number') checkv(R.test_timet(1), 1, 'number') checkv(R.test_timet(10000), 10000, 'number') check(not pcall(R.test_timet)) check(not pcall(R.test_timet, nil)) check(not pcall(R.test_timet, 'string')) check(not pcall(R.test_timet, true)) check(not pcall(R.test_timet, {})) check(not pcall(R.test_timet, function() end)) end function gireg.type_gtype() local R = lgi.Regress checkv(R.test_gtype(), nil, 'nil') checkv(R.test_gtype(nil), nil, 'nil') checkv(R.test_gtype(0), nil, 'nil') checkv(R.test_gtype('void'), 'void', 'string') checkv(R.test_gtype(4), 'void', 'string') checkv(R.test_gtype('GObject'), 'GObject', 'string') checkv(R.test_gtype(80), 'GObject', 'string') checkv(R.test_gtype(R.TestObj), 'RegressTestObj', 'string') check(not pcall(R.test_gtype, true)) check(not pcall(R.test_gtype, function() end)) end function gireg.utf8_const_return() local R = lgi.Regress local utf8_const = 'const \226\153\165 utf8' check(R.test_utf8_const_return() == utf8_const) end function gireg.utf8_nonconst_return() local R = lgi.Regress local utf8_nonconst = 'nonconst \226\153\165 utf8' check(R.test_utf8_nonconst_return() == utf8_nonconst) end function gireg.utf8_const_in() local R = lgi.Regress local utf8_const = 'const \226\153\165 utf8' R.test_utf8_const_in(utf8_const) R.test_utf8_const_in(bytes.new(utf8_const .. '\0')) end function gireg.utf8_out() local R = lgi.Regress local utf8_nonconst = 'nonconst \226\153\165 utf8' check(R.test_utf8_out() == utf8_nonconst) end function gireg.utf8_inout() local R = lgi.Regress local utf8_const = 'const \226\153\165 utf8' local utf8_nonconst = 'nonconst \226\153\165 utf8' check(R.test_utf8_inout(utf8_const) == utf8_nonconst) end function gireg.filename_return() local R = lgi.Regress local fns = R.test_filename_return() check(type(fns) == 'table') check(#fns == 2) check(fns[1] == 'åäö') check(fns[2] == '/etc/fstab') end function gireg.utf8_int_out_utf8() local R = lgi.Regress check(R.test_int_out_utf8('') == 0) check(R.test_int_out_utf8('abc') == 3) local utf8_const = 'const \226\153\165 utf8' check(R.test_int_out_utf8(utf8_const) == 12) end function gireg.multi_double_args() local R = lgi.Regress local o1, o2 = R.test_multi_double_args(1) check(o1 == 2 and o2 == 3) check(#{R.test_multi_double_args(1)} == 2) end function gireg.utf8_out_out() local R = lgi.Regress local o1, o2 = R.test_utf8_out_out() check(o1 == 'first' and o2 == 'second') check(#{R.test_utf8_out_out()} == 2) end function gireg.utf8_out_nonconst_return() local R = lgi.Regress local o1, o2 = R.test_utf8_out_nonconst_return() check(o1 == 'first' and o2 == 'second') check(#{R.test_utf8_out_nonconst_return()} == 2) end function gireg.utf8_null_in() local R = lgi.Regress R.test_utf8_null_in(nil) R.test_utf8_null_in() end function gireg.utf8_null_out() local R = lgi.Regress check(R.test_utf8_null_out() == nil) end function gireg.array_int_in() local R = lgi.Regress check(R.test_array_int_in{1,2,3} == 6) check(R.test_array_int_in{1.1,2,3} == 6) check(R.test_array_int_in{} == 0) check(not pcall(R.test_array_int_in, nil)) check(not pcall(R.test_array_int_in, 'help')) check(not pcall(R.test_array_int_in, {'help'})) end function gireg.array_int_out() local R = lgi.Regress local a = R.test_array_int_out() check(#a == 5) check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) check(#{R.test_array_int_out()} == 1) end function gireg.array_int_inout() local R = lgi.Regress local a = R.test_array_int_inout({1, 2, 3, 4, 5}) check(#a == 4) check(a[1] == 3 and a[2] == 4 and a[3] == 5 and a[4] == 6) check(#{R.test_array_int_inout({1, 2, 3, 4, 5})} == 1) check(not pcall(R.test_array_int_inout, nil)) check(not pcall(R.test_array_int_inout, 'help')) check(not pcall(R.test_array_int_inout, {'help'})) end function gireg.array_gint8_in() local R = lgi.Regress check(R.test_array_gint8_in{1,2,3} == 6) check(R.test_array_gint8_in{1.1,2,3} == 6) check(R.test_array_gint8_in('0123') == 48 + 49 + 50 + 51) check(R.test_array_gint8_in(bytes.new('0123')) == 48 + 49 + 50 + 51) check(R.test_array_gint8_in{} == 0) check(not pcall(R.test_array_gint8_in, nil)) check(not pcall(R.test_array_gint8_in, {'help'})) end function gireg.array_gint16_in() local R = lgi.Regress check(R.test_array_gint16_in{1,2,3} == 6) check(R.test_array_gint16_in{1.1,2,3} == 6) check(R.test_array_gint16_in{} == 0) check(not pcall(R.test_array_gint16_in, nil)) check(not pcall(R.test_array_gint16_in, 'help')) check(not pcall(R.test_array_gint16_in, {'help'})) end function gireg.array_gint32_in() local R = lgi.Regress check(R.test_array_gint32_in{1,2,3} == 6) check(R.test_array_gint32_in{1.1,2,3} == 6) check(R.test_array_gint32_in{} == 0) check(not pcall(R.test_array_gint32_in, nil)) check(not pcall(R.test_array_gint32_in, 'help')) check(not pcall(R.test_array_gint32_in, {'help'})) end function gireg.array_gint64_in() local R = lgi.Regress check(R.test_array_gint64_in{1,2,3} == 6) check(R.test_array_gint64_in{1.1,2,3} == 6) check(R.test_array_gint64_in{} == 0) check(not pcall(R.test_array_gint64_in, nil)) check(not pcall(R.test_array_gint64_in, 'help')) check(not pcall(R.test_array_gint64_in, {'help'})) end function gireg.array_strv_in() local R = lgi.Regress check(R.test_strv_in{'1', '2', '3'}) check(not pcall(R.test_strv_in)) check(not pcall(R.test_strv_in, '1')) check(not pcall(R.test_strv_in, 1)) check(not R.test_strv_in{'3', '2', '1'}) check(not R.test_strv_in{'1', '2', '3', '4'}) end function gireg.array_gtype_in() local R = lgi.Regress local GObject = lgi.GObject local str = R.test_array_gtype_in { lgi.GObject.Value._gtype, lgi.GObject.type_from_name('gchar') } check(str == '[GValue,gchar,]') check(R.test_array_gtype_in({}) == '[]') check(not pcall(R.test_array_gtype_in)) check(not pcall(R.test_array_gtype_in, '')) check(not pcall(R.test_array_gtype_in, 1)) check(not pcall(R.test_array_gtype_in, function() end)) end function gireg.array_strv_out() local R = lgi.Regress local a = R.test_strv_out() check(type(a) == 'table' and #a == 5) check(table.concat(a, ' ') == 'thanks for all the fish') check(#{R.test_strv_out()} == 1) end function gireg.array_strv_out_container() local R = lgi.Regress local a = R.test_strv_out_container() check(type(a) == 'table' and #a == 3) check(table.concat(a, ' ') == '1 2 3') end function gireg.array_strv_outarg() local R = lgi.Regress local a = R.test_strv_outarg() check(type(a) == 'table' and #a == 3) check(table.concat(a, ' ') == '1 2 3') check(#{R.test_strv_outarg()} == 1) end function gireg.array_fixed_size_int_out() local R = lgi.Regress local a = R.test_array_fixed_size_int_out() check(type(a) == 'table' and #a == 5) check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) check(#{R.test_array_fixed_size_int_out()} == 1) end function gireg.array_fixed_size_int_return() local R = lgi.Regress local a = R.test_array_fixed_size_int_return() check(type(a) == 'table' and #a == 5) check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) check(#{R.test_array_fixed_size_int_return()} == 1) end function gireg.array_strv_out_c() local R = lgi.Regress local a = R.test_strv_out_c() check(type(a) == 'table' and #a == 5) check(table.concat(a, ' ') == 'thanks for all the fish') end function gireg.array_int_full_out() local R = lgi.Regress local a = R.test_array_int_full_out() check(type(a) == 'table' and #a == 5) check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) check(#{R.test_array_int_full_out()} == 1) end function gireg.array_int_full_out() local R = lgi.Regress local a = R.test_array_int_full_out() check(type(a) == 'table' and #a == 5) check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) check(#{R.test_array_int_full_out()} == 1) end function gireg.array_int_null_in() local R = lgi.Regress R.test_array_int_null_in() R.test_array_int_null_in(nil) end function gireg.array_int_null_out() local R = lgi.Regress local a = R.test_array_int_null_out() check(type(a) == 'table' and not next(a)) end function gireg.glist_nothing_return() local R = lgi.Regress check(select('#', R.test_glist_nothing_return()) == 1) a = R.test_glist_nothing_return() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_nothing_return2() local R = lgi.Regress check(select('#', R.test_glist_nothing_return2()) == 1) a = R.test_glist_nothing_return2() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_container_return() local R = lgi.Regress check(select('#', R.test_glist_container_return()) == 1) a = R.test_glist_container_return() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_everything_return() local R = lgi.Regress check(select('#', R.test_glist_everything_return()) == 1) a = R.test_glist_everything_return() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_nothing_in() local R = lgi.Regress R.test_glist_nothing_in {'1', '2', '3'} end function gireg.glist_nothing_in2() local R = lgi.Regress R.test_glist_nothing_in2 {'1', '2', '3'} end function gireg.glist_null_in() local R = lgi.Regress R.test_glist_null_in {} R.test_glist_null_in(nil) R.test_glist_null_in() end function gireg.glist_null_out() local R = lgi.Regress check(select('#', R.test_glist_null_out()) == 1) local a = R.test_glist_null_out() check(type(a) == 'table' and #a == 0) end function gireg.gslist_nothing_return() local R = lgi.Regress check(select('#', R.test_gslist_nothing_return()) == 1) a = R.test_gslist_nothing_return() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_nothing_return2() local R = lgi.Regress check(select('#', R.test_gslist_nothing_return2()) == 1) a = R.test_gslist_nothing_return2() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_container_return() local R = lgi.Regress check(select('#', R.test_gslist_container_return()) == 1) a = R.test_gslist_container_return() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_everything_return() local R = lgi.Regress check(select('#', R.test_gslist_everything_return()) == 1) a = R.test_gslist_everything_return() check(type(a) == 'table' and #a == 3) check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_nothing_in() local R = lgi.Regress R.test_gslist_nothing_in {'1', '2', '3'} end function gireg.gslist_nothing_in2() local R = lgi.Regress R.test_gslist_nothing_in2 {'1', '2', '3'} end function gireg.gslist_null_in() local R = lgi.Regress R.test_gslist_null_in {} R.test_gslist_null_in(nil) R.test_gslist_null_in() end function gireg.gslist_null_out() local R = lgi.Regress check(select('#', R.test_gslist_null_out()) == 1) local a = R.test_gslist_null_out() check(type(a) == 'table' and #a == 0) end function gireg.ghash_null_return() local R = lgi.Regress check(select('#', R.test_ghash_null_return()) == 1) check(R.test_ghash_null_return() == nil) end local function size_htab(h) local size = 0 for _ in pairs(h) do size = size + 1 end return size end function gireg.ghash_nothing_return() local R = lgi.Regress local count = 0 check(select('#', R.test_ghash_nothing_return()) == 1) local h = R.test_ghash_nothing_return() check(type(h) == 'table') check(size_htab(h) == 3) check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') end function gireg.ghash_container_return() local R = lgi.Regress local count = 0 check(select('#', R.test_ghash_container_return()) == 1) local h = R.test_ghash_container_return() check(type(h) == 'table') check(size_htab(h) == 3) check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') end function gireg.ghash_everything_return() local R = lgi.Regress local count = 0 check(select('#', R.test_ghash_everything_return()) == 1) local h = R.test_ghash_everything_return() check(type(h) == 'table') check(size_htab(h) == 3) check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') end function gireg.ghash_null_in() local R = lgi.Regress R.test_ghash_null_in(nil) R.test_ghash_null_in() check(not pcall(R.test_ghash_null_in,1)) check(not pcall(R.test_ghash_null_in,'string')) check(not pcall(R.test_ghash_null_in,function() end)) end function gireg.ghash_null_out() local R = lgi.Regress check(R.test_ghash_null_out() == nil) end function gireg.ghash_nothing_in() local R = lgi.Regress R.test_ghash_nothing_in({ foo = 'bar', baz = 'bat', qux = 'quux' }) check(not pcall(R.test_ghash_nothing_in)) check(not pcall(R.test_ghash_nothing_in, 1)) check(not pcall(R.test_ghash_nothing_in, 'test')) check(not pcall(R.test_ghash_nothing_in, function() end)) end function gireg.ghash_nested_everything_return() local R = lgi.Regress check(select('#', R.test_ghash_nested_everything_return) == 1); local a = R.test_ghash_nested_everything_return() check(type(a) == 'table') check(size_htab(a) == 1) check(type(a.wibble) == 'table') check(size_htab(a.wibble) == 3) check(a.wibble.foo == 'bar' and a.wibble.baz == 'bat' and a.wibble.qux == 'quux') end function gireg.enum() local R = lgi.Regress check(R.TestEnum.VALUE1 == 0) check(R.TestEnum.VALUE2 == 1) check(R.TestEnum.VALUE3 == -1) check(R.TestEnum[0] == 'VALUE1') check(R.TestEnum[1] == 'VALUE2') check(R.TestEnum[-1] == 'VALUE3') check(R.TestEnum[43] == 43) check(R.test_enum_param(0) == 'value1') check(R.test_enum_param(1) == 'value2') check(R.test_enum_param(-1) == 'value3') check(R.TestEnumUnsigned.VALUE1 == 1) check(R.TestEnumUnsigned.VALUE2 == 0x80000000) check(R.TestEnumUnsigned[1] == 'VALUE1') check(R.TestEnumUnsigned[0x80000000] == 'VALUE2') check(R.TestEnumUnsigned[-1] == -1) end function gireg.flags() local R = lgi.Regress check(R.TestFlags.FLAG1 == 1) check(R.TestFlags.FLAG2 == 2) check(R.TestFlags.FLAG3 == 4) check(R.TestFlags[7].FLAG1 == true) check(R.TestFlags[7].FLAG2 == true) check(R.TestFlags[7].FLAG3 == true) check(R.TestFlags[3].FLAG1 == true) check(R.TestFlags[3].FLAG2 == true) check(R.TestFlags[3].FLAG3 == nil) check(R.TestFlags[10].FLAG2 == true) check(R.TestFlags[10][1] == 8) checkv(R.TestFlags { 'FLAG1', 'FLAG2' }, 3, 'number') checkv(R.TestFlags { 1, 2, 'FLAG1', R.TestFlags.FLAG2 }, 3, 'number') checkv(R.TestFlags { 10, FLAG2 = 2 }, 10, 'number') checkv(R.TestFlags { 2, 'FLAG2' }, 2, 'number') end function gireg.flags_out() local R = lgi.Regress local out = R.global_get_flags_out() check(type(out) == 'table') check(out.FLAG1 == true) check(out.FLAG2 == nil) check(out.FLAG3 == true) check(#out == 0) end function gireg.const() local R = lgi.Regress checkv(R.INT_CONSTANT, 4422, 'number') checkv(R.DOUBLE_CONSTANT, 44.22, 'number') checkv(R.STRING_CONSTANT, 'Some String', 'string') checkv(R.Mixed_Case_Constant, 4423, 'number') end function gireg.struct_a() local R = lgi.Regress check(select('#', R.TestStructA()) == 1) local a = R.TestStructA() check(type(a) == 'userdata') a.some_int = 42 check(a.some_int == 42) a.some_int8 = 12 check(a.some_int8 == 12) a.some_double = 3.14 check(a.some_double == 3.14) a.some_enum = R.TestEnum.VALUE2 check(a.some_enum == 'VALUE2') a = R.TestStructA { some_int = 42, some_int8 = 12, some_double = 3.14, some_enum = 'VALUE2' } a.some_int = 43 a.some_int8 = 13 check(a.some_int == 43) check(a.some_int8 == 13) check(a.some_double == 3.14) check(a.some_enum == 'VALUE2') a.some_double = 3.15 check(a.some_int == 43) check(a.some_int8 == 13) check(a.some_double == 3.15) check(a.some_enum == 'VALUE2') a.some_enum = R.TestEnum.VALUE3 check(a.some_int == 43) check(a.some_int8 == 13) check(a.some_double == 3.15) check(a.some_enum == 'VALUE3') check(not pcall(function() return a.foo end)) check(not pcall(function() a.foo = 1 end)) check(select('#', (function() a.some_int = 0 end)()) == 0) check(select('#', (function() return a.some_int end)()) == 1) check(select('#', (function() local b = a.some_int end)()) == 0) end function gireg.struct_a_clone() local R = lgi.Regress local a = R.TestStructA { some_int = 42, some_int8 = 12, some_double = 3.14, some_enum = R.TestEnum.VALUE2 } check(a == a) check(select('#', a:clone()) == 1) local b = a:clone() check(type(b) == 'userdata') check(b ~= a) check(b == b) check(b.some_int == 42) check(b.some_int8 == 12) check(b.some_double == 3.14) check(b.some_enum == 'VALUE2') check(a.some_int == 42) check(a.some_int8 == 12) check(a.some_double == 3.14) check(a.some_enum == 'VALUE2') end function gireg.struct_b() local R = lgi.Regress local b = R.TestStructB() -- Basic fields assignments. b.some_int8 = 13 check(b.some_int8 == 13) b.nested_a.some_int = -1 check(b.some_int8 == 13) check(b.nested_a.some_int == -1) b.nested_a.some_int8 = -2 check(b.some_int8 == 13) check(b.nested_a.some_int == -1) check(b.nested_a.some_int8 == -2) -- Whole nested structure assignment. b.nested_a = { some_int = 42, some_int8 = 12, some_double = 3.14, some_enum = R.TestEnum.VALUE2 } check(b.nested_a.some_int == 42) check(b.nested_a.some_int8 == 12) check(b.nested_a.some_double == 3.14) check(b.nested_a.some_enum == 'VALUE2') -- Nested structure construction. b = R.TestStructB { some_int8 = 21, nested_a = { some_int = 42, some_int8 = 12, some_double = 3.14, some_enum = R.TestEnum.VALUE2 } } check(b.some_int8 == 21) check(b.nested_a.some_int == 42) check(b.nested_a.some_int8 == 12) check(b.nested_a.some_double == 3.14) check(b.nested_a.some_enum == 'VALUE2') end function gireg.struct_b_clone() local R = lgi.Regress local b = R.TestStructB { some_int8 = 21, nested_a = { some_int = 42, some_int8 = 12, some_double = 3.14, some_enum = R.TestEnum.VALUE2 } } check(b == b) check(select('#', b:clone()) == 1) local bc = b:clone() check(type(bc) == 'userdata') check(bc ~= b) check(bc == bc) check(bc.some_int8 == 21) check(bc.nested_a.some_int == 42) check(bc.nested_a.some_int8 == 12) check(bc.nested_a.some_double == 3.14) check(bc.nested_a.some_enum == 'VALUE2') check(bc.nested_a.some_int == 42) check(bc.nested_a.some_int8 == 12) check(bc.nested_a.some_double == 3.14) check(bc.nested_a.some_enum == 'VALUE2') check(b.some_int8 == 21) check(b.nested_a.some_int == 42) check(b.nested_a.some_int8 == 12) check(b.nested_a.some_double == 3.14) check(b.nested_a.some_enum == 'VALUE2') check(b.nested_a.some_int == 42) check(b.nested_a.some_int8 == 12) check(b.nested_a.some_double == 3.14) check(b.nested_a.some_enum == 'VALUE2') end function gireg.boxed_a_equals() local R = lgi.Regress check(R.TestSimpleBoxedA({ some_int = 1, some_int8 = 2, some_double = 3.14 }):equals( R.TestSimpleBoxedA({ some_int = 1, some_int8 = 2, some_double = 3.14 }))) check(not R.TestSimpleBoxedA({ some_int = 2, some_int8 = 2, some_double = 3.14 }):equals( R.TestSimpleBoxedA({ some_int = 1, some_int8 = 2, some_double = 3.14 }))) check(R.TestSimpleBoxedA():equals(R.TestSimpleBoxedA())) check(not pcall(R.TestSimpleBoxedA().equals)) check(not pcall(R.TestSimpleBoxedA().equals, nil)) check(not pcall(R.TestSimpleBoxedA().equals, {})) check(not pcall(R.TestSimpleBoxedA().equals, 1)) check(not pcall(R.TestSimpleBoxedA().equals, 'string')) check(not pcall(R.TestSimpleBoxedA().equals, function() end)) end function gireg.boxed_a_const_return() local R = lgi.Regress check(select('#', R.test_simple_boxed_a_const_return()) == 1) local a = R.test_simple_boxed_a_const_return() check(a.some_int == 5) check(a.some_int8 == 6) check(a.some_double == 7) end function gireg.boxed_new() local R = lgi.Regress check(select('#', R.TestBoxed.new()) == 1) local bn = R.TestBoxed.new() local bac1 = R.TestBoxed.new_alternative_constructor1(1) check(bac1.some_int8 == 1) local bac2 = R.TestBoxed.new_alternative_constructor2(1, 2) check(bac2.some_int8 == 3) local bac3 = R.TestBoxed.new_alternative_constructor3('25') check(bac3.some_int8 == 25) end function gireg.boxed_copy() local R = lgi.Regress local b = R.TestBoxed.new() b.some_int8 = 1 b.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } check(select('#', b:copy()) == 1) local bc = b:copy() check(bc ~= b) check(bc.some_int8 == 1) check(bc.nested_a.some_int == 1) check(bc.nested_a.some_int8 == 2) check(bc.nested_a.some_double == 3.14) end function gireg.boxed_equals() local R = lgi.Regress local b1 = R.TestBoxed.new() b1.some_int8 = 1 b1.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } local b2 = R.TestBoxed.new() b2.some_int8 = 1 b2.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } check(b1:equals(b2)) b1.some_int8 = 2 check(not b1:equals(b2)) b1.some_int8 = 1 b1.nested_a.some_int = 2 check(not b1:equals(b2)) b1.nested_a.some_int = 1 check(b1:equals(b2)) end function gireg.closure_simple() local R = lgi.Regress local GObject = lgi.GObject local closure = GObject.Closure(function(...) check(select('#', ...) == 0) return 42 end) checkv(R.test_closure(closure, 42), 42, 'number') local res = GObject.Value('gint') closure:invoke(res, {}, nil) check(res.gtype == 'gint' and res.value == 42) end function gireg.closure_arg() local GObject = lgi.GObject local R = lgi.Regress local closure = GObject.Closure(function(int, ...) check(select('#', ...) == 0) return int end) checkv(R.test_closure_one_arg(closure, 43), 43, 'number') local res = GObject.Value('gint') closure:invoke(res, { GObject.Value('gint', 43) }, nil) check(res.gtype == 'gint' and res.value == 43) end function gireg.gvalue_assign() local GObject = lgi.GObject local V = GObject.Value local v = V() check(v.gtype == nil) check(v.value == nil) v.gtype = 'gchararray' check(v.gtype == 'gchararray') check(v.value == nil) v.value = 'label' check(v.value == 'label') v.value = nil check(v.value == nil) check(v.gtype == 'gchararray') v.value = 'label' v.gtype = nil check(v.gtype == nil) check(v.value == nil) v.gtype = 'gint' v.value = 1 check(v.gtype == 'gint') check(v.value == 1) v.gtype = 'gdouble' check(v.gtype == 'gdouble') check(v.value == 1) v.value = 3.14 v.gtype = 'gint' check(v.gtype == 'gint') check(v.value == 3) end function gireg.gvalue_arg() local GObject = lgi.GObject local R = lgi.Regress checkv(R.test_int_value_arg(GObject.Value('gint', 42)), 42, 'number') end function gireg.gvalue_return() local R = lgi.Regress local v = R.test_value_return(43) checkv(v.value, 43, 'number') check(v.gtype == 'gint', 'incorrect value type') end function gireg.gvalue_date() local GObject = lgi.GObject local GLib = lgi.GLib local R = lgi.Regress local v v = R.test_date_in_gvalue() check(v.gtype == 'GDate') check(v.value:get_day() == 5) check(v.value:get_month() == 'DECEMBER') check(v.value:get_year() == 1984) local d = GLib.Date() d:set_dmy(25, 1, 1975) v = GObject.Value(GLib.Date, d) check(v.gtype == 'GDate') check(v.value:get_day() == 25) check(v.value:get_month() == 'JANUARY') check(v.value:get_year() == 1975) end function gireg.gvalue_strv() local GObject = lgi.GObject local R = lgi.Regress local v = R.test_strv_in_gvalue() check(v.gtype == 'GStrv') check(#v.value == 3) check(v.value[1] == 'one') check(v.value[2] == 'two') check(v.value[3] == 'three') v = GObject.Value('GStrv', { '1', '2', '3' }) check(#v.value == 3) check(v.value[1] == '1') check(v.value[2] == '2') check(v.value[3] == '3') end function gireg.obj_create() local R = lgi.Regress local o = R.TestObj() check(o) check(type(o) == 'userdata') check(select('#', R.TestObj()) == 1) o = R.TestObj.new_from_file('unused') check(type(o) == 'userdata') check(select('#', R.TestObj.new_from_file('unused')) == 1) end function gireg.obj_methods() local R = lgi.Regress if R.TestObj._method.do_matrix then R.TestObj._method.invoke_matrix = R.TestObj._method.do_matrix R.TestObj._method.do_matrix = nil end local o = R.TestObj() check(o:instance_method() == -1) check(o.static_method(42) == 42) local y, z, q = o:torture_signature_0(1, 'foo', 2) check(y == 1) check(z == 2) check(q == 5) local y, z, q = o:torture_signature_1(1, 'foo', 2) check(y == 1) check(z == 2) check(q == 5) local res, msg, code = o:torture_signature_1(1, 'foo', 3) check(not res) check(type(msg) == 'string') check(type(code) == 'number') check(o:invoke_matrix('unused') == 42) end function gireg.obj_null_args() local R = lgi.Regress R.func_obj_null_in(nil) R.func_obj_null_in() check(R.TestObj.null_out() == nil) check(select('#', R.TestObj.null_out()) == 1) end function gireg.obj_virtual_methods() local R = lgi.Regress local o = R.TestObj() check(o:do_matrix('unused') == 42) end function gireg.obj_prop_int() local R = lgi.Regress local o = R.TestObj() check(o.int == 0) o.int = 42 check(o.int == 42) check(not pcall(function() o.int = {} end)) check(not pcall(function() o.int = 'lgi' end)) check(not pcall(function() o.int = nil end)) check(not pcall(function() o.int = function() end end)) end function gireg.obj_prop_float() local R = lgi.Regress local o = R.TestObj() check(o.float == 0) o.float = 42.1 checkvf(o.float, 42.1, 0.00001) check(not pcall(function() o.float = {} end)) check(not pcall(function() o.float = 'lgi' end)) check(not pcall(function() o.float = nil end)) check(not pcall(function() o.float = function() end end)) end function gireg.obj_prop_double() local R = lgi.Regress local o = R.TestObj() check(o.double == 0) o.double = 42.1 checkvf(o.double, 42.1, 0.0000000001) check(not pcall(function() o.double = {} end)) check(not pcall(function() o.double = 'lgi' end)) check(not pcall(function() o.double = nil end)) check(not pcall(function() o.double = function() end end)) end function gireg.obj_prop_string() local R = lgi.Regress local o = R.TestObj() check(o.string == nil) o.string = 'lgi' check(o.string == 'lgi') o.string = nil check(o.string == nil) check(not pcall(function() o.string = {} end)) check(not pcall(function() o.string = function() end end)) end function gireg.obj_prop_bare() local R = lgi.Regress local o = R.TestObj() check(o.bare == nil) local pv = R.TestObj() o.bare = pv check(o.bare == pv) o.bare = nil check(o.bare == nil) o:set_bare(pv) check(o.bare == pv) o.bare = nil check(o.bare == nil) check(not pcall(function() o.bare = {} end)) check(not pcall(function() o.bare = 42 end)) check(not pcall(function() o.bare = 'lgi' end)) check(not pcall(function() o.bare = function() end end)) check(not pcall(function() o.bare = R.TestBoxed() end)) end function gireg.obj_prop_boxed() local R = lgi.Regress local o = R.TestObj() check(o.boxed == nil) local pv = R.TestBoxed() o.boxed = pv check(o.boxed:equals(pv)) o.boxed = nil check(o.boxed == nil) check(not pcall(function() o.boxed = {} end)) check(not pcall(function() o.boxed = 42 end)) check(not pcall(function() o.boxed = 'lgi' end)) check(not pcall(function() o.boxed = function() end end)) check(not pcall(function() o.boxed = R.TestObj() end)) end function gireg.obj_prop_hash() local R = lgi.Regress local o = R.TestObj() check(o.hash_table == nil) o.hash_table = { a = 1, b = 2 } local ov = o.hash_table check(ov.a == 1 and ov.b == 2) check(not pcall(function() o.hash_table = 42 end)) check(not pcall(function() o.hash_table = 'lgi' end)) check(not pcall(function() o.hash_table = function() end end)) check(not pcall(function() o.hash_table = R.TestObj() end)) check(not pcall(function() o.hash_table = R.TestBoxed() end)) end function gireg.obj_prop_list() local R = lgi.Regress local o = R.TestObj() check(o.hash_table == nil) o.list = { 'one', 'two', 'three', } local ov = o.list check(#ov == 3 and ov[1] == 'one' and ov[2] == 'two' and ov[3] == 'three') check(not pcall(function() o.list = 42 end)) check(not pcall(function() o.list = 'lgi' end)) check(not pcall(function() o.list = function() end end)) check(not pcall(function() o.list = R.TestObj() end)) check(not pcall(function() o.list = R.TestBoxed() end)) end function gireg.obj_prop_dynamic() local R = lgi.Regress local o = R.TestObj() -- Remove static property information, force lgi to use dynamic -- GLib property system. local old_prop = R.TestObj.int R.TestObj._property.int = nil check(R.TestObj.int == nil) check(o.int == 0) o.int = 3 check(o.int == 3) check(not pcall(function() o.int = 'string' end)) check(not pcall(function() o.int = {} end)) check(not pcall(function() o.int = true end)) check(not pcall(function() o.int = function() end end)) -- Restore TestObj to work normally. R.TestObj._property.int = old_prop end function gireg.obj_subobj() local R = lgi.Regress local o = R.TestSubObj() local pv = R.TestObj() check(o:instance_method() == 0) o.bare = pv check(o.bare == pv) o:unset_bare() check(o.bare == nil) o = R.TestSubObj.new() o:set_bare(pv) check(o.bare == pv) o:unset_bare() check(o.bare == nil) end function gireg.obj_naming() local R = lgi.Regress local o = R.TestWi8021x() o:set_testbool(true) check(o.testbool == true) o.testbool = false check(o:get_testbool() == false) end function gireg.obj_floating() local R = lgi.Regress local o = R.TestFloating() check(o) o = nil collectgarbage() collectgarbage() end function gireg.obj_fundamental() local R = lgi.Regress local f = R.TestFundamentalSubObject.new('foo-nda-mental') check(f) check(f.data == 'foo-nda-mental') local v = lgi.GObject.Value(R.TestFundamentalSubObject, f) check(v.value == f) f = nil collectgarbage() end function gireg.callback_simple() local R = lgi.Regress check(R.test_callback(function() return 42 end) == 42) check(R.test_callback() == 0) check(R.test_callback(nil) == 0) check(not pcall(R.test_callback, 1)) check(not pcall(R.test_callback, 'foo')) check(not pcall(R.test_callback, {})) check(not pcall(R.test_callback, R)) check(R.test_multi_callback(function() return 22 end) == 44) check(R.test_multi_callback() == 0) end function gireg.callback_data() local R = lgi.Regress local called R.test_simple_callback(function() called = true end) check(called) check(R.test_callback_user_data(function() return 42 end) == 42) called = nil R.TestObj.static_method_callback(function() called = true return 42 end) check(called) local o = R.TestObj() called = nil o.static_method_callback(function() called = true return 42 end) check(called) called = nil o:instance_method_callback(function() called = true return 42 end) check(called) end function gireg.callback_notified() local R = lgi.Regress check(R.test_callback_destroy_notify(function() return 1 end) == 1) check(R.test_callback_destroy_notify(function() return 2 end) == 2) check(R.test_callback_destroy_notify(function() return 3 end) == 3) collectgarbage() collectgarbage() check(R.test_callback_thaw_notifications() == 6) R.TestObj.new_callback(function() return 1 end) collectgarbage() collectgarbage() check(R.test_callback_thaw_notifications() == 1) end function gireg.callback_async() local R = lgi.Regress R.test_callback_async(function() return 1 end) collectgarbage() collectgarbage() check(R.test_callback_thaw_async() == 1) end lua-lgi-0.7.2/tests/glib.lua000066400000000000000000000020611221440706400156330ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, GLib test suite. Copyright (c) 2013 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local check = testsuite.check -- Basic GLib testing local glib = testsuite.group.new('glib') function glib.timer() local Timer = lgi.GLib.Timer check(Timer.new) check(Timer.start) check(Timer.stop) check(Timer.continue) check(Timer.elapsed) check(Timer.reset) check(not Timer.destroy) local timer = Timer() check(Timer:is_type_of(timer)) timer = Timer.new() check(Timer:is_type_of(timer)) local el1, ms1 = timer:elapsed() check(type(el1) == 'number') check(type(ms1) == 'number') for i = 1, 1000000 do end local el2, ms2 = timer:elapsed() check(el1 < el2) timer:stop() el2 = timer:elapsed() for i = 1, 1000000 do end check(timer:elapsed() == el2) end lua-lgi-0.7.2/tests/gobject.lua000066400000000000000000000142001221440706400163310ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, GObject.Object test suite. Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local core = require 'lgi.core' local check = testsuite.check -- Basic GObject testing local gobject = testsuite.group.new('gobject') function gobject.env_base() local GObject = lgi.GObject local obj = GObject.Object() check(type(core.object.env(obj)) == 'table') check(core.object.env(obj) == core.object.env(obj)) check(next(core.object.env(obj)) == nil) end function gobject.env_persist() local Gtk = lgi.Gtk local window = Gtk.Window() local label = Gtk.Label() local env = core.object.env(label) window:_method_add(label) label = nil collectgarbage() label = window:get_child() check(env == core.object.env(label)) end function gobject.object_new() local GObject = lgi.GObject local o = GObject.Object() o = nil collectgarbage() end function gobject.initunk_new() local GObject = lgi.GObject local o = GObject.InitiallyUnowned() -- Simulate sink by external container o:ref_sink() o:unref() o = nil collectgarbage() end function gobject.native() local GObject = lgi.GObject local o = GObject.Object() local p = o._native check(type(p) == 'userdata') check(GObject.Object(p) == o) end function gobject.gtype_create() local GObject = lgi.GObject local Gio = lgi.Gio local m = GObject.Object.new(Gio.ThemedIcon, { name = 'icon' }) check(Gio.ThemedIcon:is_type_of(m)) end function gobject.subclass_derive1() local GObject = lgi.GObject local Derived = GObject.Object:derive('LgiTestDerived1') local der = Derived() check(Derived:is_type_of(der)) check(not Derived:is_type_of(GObject.Object())) end function gobject.subclass_derive2() local GObject = lgi.GObject local Derived = GObject.Object:derive('LgiTestDerived2') local Subderived = Derived:derive('LgiTestSubDerived2') local der = Derived() check(Derived:is_type_of(der)) check(not Subderived:is_type_of(der)) local sub = Subderived() check(Subderived:is_type_of(sub)) check(Derived:is_type_of(sub)) check(GObject.Object:is_type_of(sub)) end function gobject.subclass_override1() local GObject = lgi.GObject local Derived = GObject.Object:derive('LgiTestOverride1') local state = 0 local obj function Derived:do_constructed() obj = self state = state + 1 end function Derived:do_dispose() state = state + 2 end check(state == 0) local der = Derived() check(der == obj) check(state == 1) der = nil obj = nil collectgarbage() check(state == 3) end function gobject.subclass_override2() local GObject = lgi.GObject local state = 0 local Derived = GObject.Object:derive('LgiTestOverride2') function Derived:do_constructed() self.priv.id = 1 state = state + 1 end function Derived:do_dispose() state = state + 2 GObject.Object.do_dispose(self) end function Derived:custom_method() state = state + 8 self.priv.id = self.priv.id + 4 end local Subderived = Derived:derive('LgiTestOverrideSub2') function Subderived:do_constructed() Derived.do_constructed(self) self.priv.id = self.priv.id + 2 state = state + 4 end check(state == 0) local sub = Subderived() check(state == 5) check(sub.priv.id == 3) sub:custom_method() check(state == 13) check(sub.priv.id == 7) sub = nil collectgarbage() check(state == 15) end function gobject.subclass_derive3() local GObject = lgi.GObject local history = {} local Derived = GObject.InitiallyUnowned:derive('LgiTestDerived3') function Derived:_class_init() history[#history + 1] = 'class_init' check(self == Derived) collectgarbage() end function Derived:_init() history[#history + 1] = 'init' collectgarbage() end function Derived:do_constructed() history[#history + 1] = 'constructed' Derived._parent.do_constructed(self) collectgarbage() end -- function Derived:do_dispose() -- history[#history + 1] = 'dispose' -- Derived._parent.do_dispose(self) -- end local obj = Derived() check(history[1] == 'class_init') check(history[2] == 'init') check(history[3] == 'constructed') obj = nil collectgarbage() -- check(history[4] == 'dispose') end function gobject.iface_virtual() local Gio = lgi.Gio local file = Gio.File.new_for_path('hey') check(file:is_native() == file:do_is_native()) check(file:get_basename() == file:do_get_basename()) end function gobject.iface_impl() local GObject = lgi.GObject local Gio = lgi.Gio local FakeFile = GObject.Object:derive('LgiTestFakeFile1', { Gio.File }) function FakeFile:do_get_basename() return self.priv.basename end function FakeFile:set_basename(basename) self.priv.basename = basename end local fakefile = FakeFile() fakefile:set_basename('fakename') check(fakefile:get_basename() == 'fakename') end function gobject.treemodel_impl() local GObject = lgi.GObject local Gtk = lgi.Gtk local Model = GObject.Object:derive('LgiTestModel1', { Gtk.TreeModel }) function Model:do_get_n_columns() return 2 end function Model:do_get_column_type(index) return index == 0 and GObject.Type.STRING or GObject.Type.INT end function Model:do_get_iter(path) local iter = Gtk.TreeIter() iter.user_data = path._native return iter end function Model:do_get_value(iter, column) return GObject.Value(self:get_column_type(column), 1) end local model = Model() check(model:get_n_columns() == 2) check(model:get_column_type(0) == GObject.Type.STRING) check(model:get_column_type(1) == GObject.Type.INT) local p = Gtk.TreePath.new_from_string('0') local i = model:get_iter(p) check(i.user_data == p._native) check(model[Gtk.TreeIter()][1] == '1') check(model[Gtk.TreeIter()][2] == 1) end lua-lgi-0.7.2/tests/gtk.lua000066400000000000000000000301311221440706400155020ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, Gtk overrides test group. Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local io = require 'io' local os = require 'os' local lgi = require 'lgi' local check = testsuite.check local checkv = testsuite.checkv local gtk = testsuite.group.new('gtk') function gtk.widget_style() local Gtk = lgi.Gtk local GObject = lgi.GObject local w = Gtk.ProgressBar() local v = GObject.Value(GObject.Type.INT) w:style_get_property('xspacing', v) checkv(w.style.xspacing, v.value, 'number') check(not pcall(function() return w.style.nonexistent end)) end function gtk.buildable_id() local Gtk = lgi.Gtk local w = Gtk.Label() checkv(w.id, nil, nil) w.id = 'label_id' checkv(w.id, 'label_id', 'string') end function gtk.container_property() local Gtk = lgi.Gtk local GObject = lgi.GObject local c, w, v = Gtk.Grid(), Gtk.Label() c:add(w) c.property[w].left_attach = 1 v = GObject.Value(GObject.Type.INT) c:child_get_property(w, 'left-attach', v) checkv(v.value, 1, 'number') v.value = 2 c:child_set_property(w, 'left-attach', v) checkv(c.property[w].left_attach, 2) check(not pcall(function() c.property[w].notexistent = 1 end)) end function gtk.container_add_method() local Gtk = lgi.Gtk local c, w c, w = Gtk.Grid(), Gtk.Label() c:add(w) check(w.parent == c) c, w = Gtk.Grid(), Gtk.Label() c:add { w, left_attach = 0, width = 2 } check(w.parent == c) checkv(c.property[w].left_attach, 0, 'number') checkv(c.property[w].width, 2, 'number') c, w = Gtk.Grid(), Gtk.Label() c:add(w, { left_attach = 0, width = 2 }) check(w.parent == c) checkv(c.property[w].left_attach, 0, 'number') checkv(c.property[w].width, 2, 'number') end function gtk.container_add_child() local Gtk = lgi.Gtk local c, w c, w = Gtk.Grid(), Gtk.Label() c.child = w check(w.parent == c) c, w = Gtk.Grid(), Gtk.Label() c.child = { w, left_attach = 0, width = 2 } check(w.parent == c) checkv(c.property[w].left_attach, 0, 'number') checkv(c.property[w].width, 2, 'number') end function gtk.container_add_ctor() local Gtk = lgi.Gtk local l1, l2 = Gtk.Label(), Gtk.Label() local c = Gtk.Grid { { l1, width = 2 }, { l2, height = 3 } } check(l1.parent == c) check(l2.parent == c) checkv(c.property[l1].width, 2, 'number') checkv(c.property[l2].height, 3, 'number') end function gtk.container_child_find() local Gtk = lgi.Gtk local l1, l2 = Gtk.Label { id = 'id_l1' }, Gtk.Label { id = 'id_l2' } local c = Gtk.Grid { { l1, width = 2 }, Gtk.Grid { id = 'in_g', { l2, height = 3 } } } check(c.child.id_l1 == l1) check(c.child.id_l2 == l2) check(c.child.id_l2.parent == c.child.in_g) check(c.child.notexistent == nil) end local uidef = [[ False True False True False 0 0 1 1 True False True True label 0 1 1 1 True False vertical 2 0 2 1 1 ]] function gtk.builder_add_from_string() local Gtk = lgi.Gtk local b = Gtk.Builder() local res, e1, e2 = b:add_from_string('syntax error') check(not res and type(e1) == 'string') res, e1, e2 = b:add_from_string(uidef) check(res and not e1 and not e2) check(b:get_object('window1')) end function gtk.builder_add_objects_from_string() local Gtk = lgi.Gtk local b = Gtk.Builder() check(b:add_objects_from_string(uidef, -1, { 'statusbar1', 'label1' })) check(b:get_object('statusbar1') and b:get_object('label1')) check(not b:get_object('window1') and not b:get_object('toolbar1')) end function gtk.builder_add_from_file() local Gtk = lgi.Gtk local tempname = os.tmpname() local tempfile = io.open(tempname, 'w+') tempfile:write(uidef) tempfile:close() local b = Gtk.Builder() local res, e1, e2 = b:add_from_string('syntax error') check(not res and type(e1) == 'string') res, e1, e2 = b:add_from_file(tempname) check(res and not e1 and not e2) check(b:get_object('window1')) os.remove(tempname) end function gtk.builder_add_objects_from_file() local Gtk = lgi.Gtk local tempname = os.tmpname() local tempfile = io.open(tempname, 'w+') tempfile:write(uidef) tempfile:close() local b = Gtk.Builder() check(b:add_objects_from_file(tempname, { 'statusbar1', 'label1' })) check(b:get_object('statusbar1') and b:get_object('label1')) check(not b:get_object('window1') and not b:get_object('toolbar1')) os.remove(tempname) end function gtk.builder_objects() local Gtk = lgi.Gtk local builder = Gtk.Builder() check(builder:add_from_string(uidef)) check(builder.objects.window1 == builder:get_object('window1')) check(builder.objects.statusbar1 == builder:get_object('statusbar1')) check(not builder.objects.notexistent) end function gtk.text_tag_table_ctor() local Gtk = lgi.Gtk local t1, t2 = Gtk.TextTag { name = 'tag1' }, Gtk.TextTag { name = 'tag2' } local t = Gtk.TextTagTable { t1, t2 } check(t:lookup('tag1') == t1) check(t:lookup('tag2') == t2) check(t:lookup('notexist') == nil) end function gtk.text_tag_table_tag() local Gtk = lgi.Gtk local t1, t2 = Gtk.TextTag { name = 'tag1' }, Gtk.TextTag { name = 'tag2' } local t = Gtk.TextTagTable { t1, t2 } check(t.tag.tag1 == t1) check(t.tag.tag2 == t2) check(t.tag.notexist == nil) end function gtk.liststore() local Gtk = lgi.Gtk local GObject = lgi.GObject local cols = { int = 1, string = 2 } local store = Gtk.ListStore.new { GObject.Type.INT, GObject.Type.STRING } local first = store:insert(0, { [cols.int] = 42, [cols.string] = 'hello' }) checkv(store:get_value(first, cols.int - 1).value, 42, 'number') checkv(store[first][cols.int], 42, 'number') checkv(store:get_value(first, cols.string - 1).value, 'hello', 'string') checkv(store[first][cols.string], 'hello', 'string') store[first] = { [cols.string] = 'changed' } checkv(store[first][cols.string], 'changed', 'string') checkv(store[first][cols.int], 42, 'number') store[first][cols.int] = 16 checkv(store[first][cols.string], 'changed', 'string') checkv(store[first][cols.int], 16, 'number') end function gtk.treestore() local Gtk = lgi.Gtk local GObject = lgi.GObject local cols = { int = 1, string = 2 } local store = Gtk.TreeStore.new { GObject.Type.INT, GObject.Type.STRING } local first = store:insert( nil, 0, { [cols.int] = 42, [cols.string] = 'hello' }) checkv(store:get_value(first, cols.int - 1).value, 42, 'number') checkv(store[first][cols.int], 42, 'number') checkv(store:get_value(first, cols.string - 1).value, 'hello', 'string') checkv(store[first][cols.string], 'hello', 'string') store[first] = { [cols.string] = 'changed' } checkv(store[first][cols.string], 'changed', 'string') checkv(store[first][cols.int], 42, 'number') store[first][cols.int] = 16 checkv(store[first][cols.string], 'changed', 'string') checkv(store[first][cols.int], 16, 'number') end function gtk.treeiter() local Gtk = lgi.Gtk local GObject = lgi.GObject local giter = Gtk.TreeIter() giter.user_data = giter._native local Model = GObject.Object:derive('LgiTestModel2', { Gtk.TreeModel }) function Model:do_get_iter(path) return giter end local model = Model() local niter = model:get_iter(Gtk.TreePath.new_from_string('0')) check(giter.user_data == niter.user_data) check(giter ~= niter) end function gtk.treemodel_pairs() local Gtk = lgi.Gtk local GObject = lgi.GObject local cols = { int = 1, string = 2 } local store = Gtk.TreeStore.new { GObject.Type.INT, GObject.Type.STRING } local first = store:append( nil, { [cols.int] = 42, [cols.string] = 'hello' }) local sub1 = store:append( first, { [cols.int] = 100, [cols.string] = 'sub1' }) local sub2 = store:append( first, { [cols.int] = 101, [cols.string] = 'sub2' }) local count = 0 for i, item in store:pairs() do count = count + 1 check(Gtk.TreeIter:is_type_of(i)) check(item[cols.string] == 'hello') end check(count == 1) count = 0 for i, item in store:pairs(first) do count = count + 1 check(Gtk.TreeIter:is_type_of(i)) if (count == 1) then check(item[cols.string] == 'sub1') else check(item[cols.string] == 'sub2') end end check(count == 2) count = 0 for i, item in store:pairs(sub1) do count = count + 1 end check(count == 0) end function gtk.treeview() local Gtk = lgi.Gtk local GObject = lgi.GObject local cols = { int = 1, string = 2 } local store = Gtk.TreeStore.new { GObject.Type.INT, GObject.Type.STRING } local renderer = Gtk.CellRendererText { id = 'renderer' } local column = Gtk.TreeViewColumn { id = 'column', { renderer, { text = cols.int } }, { Gtk.CellRendererText {}, expand = true, pack = 'end', function(column, cell, model, iter) return model[iter][cols.string]:toupper() end }, } local view = Gtk.TreeView { id = 'view', model = store, column } -- Check that column is accessible by its 'id' attribute. check(view.child.view == view) check(view.child.column == column) -- Check that renderer is accessible by its 'id' attribute. check(view.child.renderer == renderer) end function gtk.actiongroup_add() local Gtk = lgi.Gtk -- Adding normal action and action with an accelerator. local ag = Gtk.ActionGroup() local a1, a2 = Gtk.Action { name = 'a1' }, Gtk.Action { name = 'a2' } ag:add(a1) check(#ag:list_actions() == 1) check(ag:get_action('a1') == a1) ag:add { a2, accelerator = 'A' } check(#ag:list_actions() == 2) check(ag:get_action('a2') == a2) -- Adding a group of radio actions, this time inside the group ctor. local chosen a1 = Gtk.RadioAction { name = 'a1', value = 1 } a2 = Gtk.RadioAction { name = 'a2', value = 2 } ag = Gtk.ActionGroup { { a1, { a2, accelerator = 'a' }, on_change = function(action) chosen = action end } } check(#ag:list_actions() == 2) check(ag:get_action('a1') == a1) check(ag:get_action('a2') == a2) check(chosen == nil) a1:activate() check(chosen == a1) a2:activate() check(chosen == a2) end function gtk.actiongroup_index() local Gtk = lgi.Gtk local a1, a2 = Gtk.Action { name = 'a1' }, Gtk.Action { name = 'a2' } local ag = Gtk.ActionGroup { a1, a2 } check(ag.action.a1 == a1) check(ag.action.a2 == a2) end lua-lgi-0.7.2/tests/marshal.lua000066400000000000000000000013731221440706400163520ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, specific marshalling tests Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local check = testsuite.check -- Basic GObject testing local marshal = testsuite.group.new('marshal') function marshal.callback_hidedata() local GLib = lgi.GLib local main_loop = GLib.MainLoop() local argc GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, function(...) argc = select('#', ...) main_loop:quit() end) main_loop:run() check(argc == 0) end lua-lgi-0.7.2/tests/record.lua000066400000000000000000000012201221440706400161700ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, record test suite. Copyright (c) 2012 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local GLib = lgi.GLib local GObject = lgi.GObject local check = testsuite.check -- Basic GObject testing local record = testsuite.group.new('record') function record.native() local c = GObject.EnumValue() local p = c._native check(type(p) == 'userdata') check(GObject.EnumValue(p) == c) end lua-lgi-0.7.2/tests/test.lua000066400000000000000000000102501221440706400156740ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI core testsuite runner. Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- -- Available groups. local groups = {} -- Testing infrastructure, tests are grouped in testgroup instances. testsuite = {} testsuite.group = {} testsuite.group.__index = testsuite.group -- Creates new named testgroup. function testsuite.group.new(name) local group = setmetatable({ name = name, results = { total = 0, failed = 0 } }, testsuite.group) groups[#groups + 1] = name groups[name] = group return group end -- Adds new test. function testsuite.group:__newindex(name, func) assert(not self[name], "test already exists in the group") rawset(self, name, func) rawset(self, #self + 1, name) end -- Runs specified test(s), either by numeric id or by regexp mask. function testsuite.group:run(id) local function runfunc(num) self.results.total = self.results.total + 1 if testsuite.verbose then io.write(('%-8s:%3d:%-35s'):format(self.name, num, self[num])) end local ok, msg local func = self[self[num]] if self.debug then func() ok = true else ok, msg = xpcall(func, debug.traceback) end collectgarbage() if not ok then self.results.failed = self.results.failed + 1 if not testsuite.verbose then io.write(('%-8s:%3d:%-35s'):format(self.name, num, self[num])) end io.write('FAIL\n ' .. tostring(msg) .. '\n') return end if testsuite.verbose then io.write('PASS\n') end end id = id or '' self.results.total = 0 self.results.failed = 0 if type(id) == 'number' then runfunc(id) else for i = 1, #self do if self[i] ~= 'debug' and self[i]:match(id) then runfunc(i) end end if (self.results.failed == 0) then io.write(('%-8s: all %d tests passed.\n'):format( self.name, self.results.total)) else io.write(('%-8s: FAILED %d of %d tests\n'):format( self.name, self.results.failed, self.results.total)) end end end -- Fails given test with error, number indicates how many functions on -- the stack should be skipped when reporting error location. function testsuite.fail(msg, skip) error(msg or 'failure', (skip or 1) + 1) end function testsuite.check(cond, msg, skip) if not cond then testsuite.fail(msg, (skip or 1) + 1) end end -- Helper, checks that given value has requested type and value. function testsuite.checkv(val, exp, exptype) if exptype then testsuite.check(type(val) == exptype, string.format("got type `%s', expected `%s'", type(val), exptype), 2) end testsuite.check(val == exp, string.format("got value `%s', expected `%s'", tostring(val), tostring(exp)), 2) end -- Load all known test source files. local testpath = arg[0]:sub(1, arg[0]:find('[^%/\\]+$') - 1):gsub('[/\\]$', '') for _, sourcefile in ipairs { 'gireg.lua', 'marshal.lua', 'corocbk.lua', 'record.lua', 'gobject.lua', 'glib.lua', 'variant.lua', 'gtk.lua', 'cairo.lua', } do dofile(testpath .. '/' .. sourcefile) end -- Check for debug mode. if tests_debug or package.loaded.debugger then -- Make logs verbose (do not mute DEBUG level). testsuite.verbose = true require('lgi').log.DEBUG = 'verbose' for _, name in ipairs(groups) do groups[name].debug = true _G[name] = groups[name] end end -- Cmdline runner. local failed = false if select('#', ...) == 0 then -- Run everything. for _, group in ipairs(groups) do groups[group]:run() failed = failed or groups[group].results.failed > 0 end else -- Run just those which pass the mask. for _, mask in ipairs { ... } do local group, groupmask = mask:match('^(.-):(.+)$') if not group or not groups[group] then io.write(("No test group for mask `%s' found.\n"):format(mask)) return 2 end groups[group]:run(groupmask) failed = failed or groups[group].results.failed > 0 end end if failed then os.exit(1) end lua-lgi-0.7.2/tests/variant.lua000066400000000000000000000162301221440706400163650ustar00rootroot00000000000000--[[-------------------------------------------------------------------------- LGI testsuite, GLib.Variant test suite. Copyright (c) 2010, 2011 Pavel Holejsovsky Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --]]-------------------------------------------------------------------------- local lgi = require 'lgi' local GLib = lgi.GLib local GObject = lgi.GObject local check = testsuite.check -- Variant testing local variant = testsuite.group.new('variant') function variant.gvalue() local var1, var2 = GLib.Variant.new_string('foo'), GLib.Variant.new_string('bar') local val = GObject.Value(GObject.Type.VARIANT, var1) check(val.gtype == GObject.Type.VARIANT) check(val.value == var1) val.value = var2 check(val.value == var2) val.value = nil check(val.value == nil) check(val.gtype == GObject.Type.VARIANT) end function variant.newv_basic() local V, v = GLib.Variant v = V.new('b', true) check(v.type == 'b' and v:get_boolean() == true) v = V.new('y', 32) check(v.type == 'y' and v:get_byte() == 32) v = V.new('n', 13) check(v.type == 'n' and v:get_int16() == 13) v = V.new('q', 38) check(v.type == 'q' and v:get_uint16() == 38) v = V.new('i', 32) check(v.type == 'i' and v:get_int32() == 32) v = V.new('u', 35) check(v.type == 'u' and v:get_uint32() == 35) v = V.new('x', 39) check(v.type == 'x' and v:get_int64() == 39) v = V.new('t', 987) check(v.type == 't' and v:get_uint64() == 987) v = V.new('d', 3.1415927) check(v.type == 'd' and v:get_double() == 3.1415927) v = V.new('s', 'Hello') check(v.type == 's' and v:get_string() == 'Hello') v = V.new('o', '/object/path') check(v.type == 'o' and v:get_string() == '/object/path') v = V.new('g', "asi") check(v.type == 'g' and v:get_string() == 'asi') local vv = V.new('s', 'inner') v = V.new('v', vv) check(v.type == 'v' and v:get_variant() == vv) v = V.new('ay', 'bytestring') check(v.type == 'ay' and tostring(v:get_bytestring()) == 'bytestring') end function variant.newv_variant() local V, v, vv = GLib.Variant vv = V('i', 14) v = V('v', vv) check(v.type == 'v' and v:n_children() == 1 and v:get_child_value(0) == vv) end function variant.newv_maybe() local V, v = GLib.Variant v = V('mi', 42) check(v.type == 'mi' and v:n_children() == 1 and v:get_child_value(0).type == 'i' and v:get_child_value(0):get_int32() == 42) v = V('mi') check(v.type == 'mi' and v:n_children() == 0) end function variant.newv_tuple() local V, v = GLib.Variant v = V.new('()') check(v.type == '()' and v:n_children() == 0) v = V.new('(i)', {42}) check(v.type == '(i)' and v:n_children() == 1 and v:get_child_value(0).type == 'i' and v:get_child_value(0):get_int32() == 42) v = V.new('(mii)', { nil, 1 }) check(v.type == '(mii)' and v:n_children() == 2 and v:get_child_value(0):n_children() == 0) end function variant.newv_dictentry() local V, v = GLib.Variant v = V('{is}', {42, 'Hello'}) check(v.type == '{is}' and v:n_children() == 2 and v:get_child_value(0).type == 'i' and v:get_child_value(0):get_int32() == 42 and v:get_child_value(1).type == 's' and v:get_child_value(1):get_string() == 'Hello') end function variant.newv_array() local V, v = GLib.Variant v = V('as', { 'Hello', 'world' }) check(v.type == 'as' and v:n_children() == 2 and v:get_child_value(0):get_string() == 'Hello' and v:get_child_value(1):get_string() == 'world') v = V('as', {}) check(v:n_children() == 0) v = V('ams', { 'Hello', nil, 'world', n = 3 }) check(v:n_children() == 3) check(v:get_child_value(0):n_children() == 1 and v:get_child_value(0):get_child_value(0):get_string() == 'Hello') check(v:get_child_value(1):n_children() == 0) check(v:get_child_value(2):n_children() == 1 and v:get_child_value(2):get_child_value(0):get_string() == 'world') end function variant.newv_dictionary() local V, v, vv = GLib.Variant v = V('a{sd}', { PI = 3.14, one = 1 }) check(v:n_children() == 2) vv = v:lookup_value('PI', GLib.VariantType.DOUBLE) check(vv.type == 'd' and vv:get_double() == 3.14) vv = v:lookup_value('one', GLib.VariantType.DOUBLE) check(vv.type == 'd' and vv:get_double() == 1) end function variant.newv_badtype() local V, v = GLib.Variant check(not pcall(V.new, '{vs}')) check(not pcall(V.new, '{s}')) check(not pcall(V.new, '{}')) check(not pcall(V.new, '())')) check(not pcall(V.new, 'a')) check(not pcall(V.new, 'm')) check(not pcall(V.new, '{asi}')) check(not pcall(V.new, '{mdd}')) check(not pcall(V.new, '{is')) check(not pcall(V.new, '{is)')) check(not pcall(V.new, 'r')) check(not pcall(V.new, '*')) check(not pcall(V.new, '?')) check(not pcall(V.new, 'ii')) end function variant.value_simple() local V, v = GLib.Variant check(V('b', true).value == true) check(V('y', 10).value == 10) check(V('n', 11).value == 11) check(V('q', 12).value == 12) check(V('i', 13).value == 13) check(V('u', 14).value == 14) check(V('q', 15).value == 15) check(V('t', 16).value == 16) check(V('s', 'I').value == 'I') check(V('o', '/o/p').value == '/o/p') check(V('g', '(ii)').value == '(ii)') v = V('i', 1) check(V('v', v).value == v) check(V('ay', 'bytestring').value == 'bytestring') end function variant.value_container() local V, v = GLib.Variant check(V('mi', 1).value == 1) check(V('mi', nil).value == nil) local r r = V('{sd}', {'one', 1}).value check(type(r) == 'table' and #r == 2 and r[1] == 'one' and r[2] == 1) r = V('(imii)', {2, nil, 1}).value check(type(r) == 'table' and r.n == 3 and r[1] == 2 and r[2] == nil and r[3] == 1) v = V('as', {}) check(v.value == v) end function variant.value_dictionary() local V, v = GLib.Variant v = V('a{sd}', { one = 1, two = 2 }) check(v.value.one == 1) check(v.value.two == 2) check(v.value.three == nil) check(v.value[1] == nil) v = V('a{is}', { [1] = 'one', [2] = 'two' }) check(v.value[1] == 'one') check(v.value[2] == 'two') check(v.value[3] == nil) check(v.value.three == nil) end function variant.length() local V, v = GLib.Variant check(#V('s', 'Hello') == 0) check(#V('i', 1) == 0) check(#V('v', V('i', 1)) == 1) check(#V('mi', nil) == 0) check(#V('mi', 1) == 1) check(#V('(ii)', {1, 2}) == 2) check(#V('{sd}', { 'one', 1 }) == 2) check(#V('a{sd}', { one = 1 }) == 1) check(#V('ai', {}) == 0) check(#V('ami', { 1, nil, 2, n = 3 }) == 3) end function variant.indexing() local V, v = GLib.Variant v = V('mi', 1) check(v[1] == 1 and v[2] == nil) v = V('{sd}', { 'one', 1 }) check(v[1] == 'one' and v[2] == 1 and v[3] == nil) v = V('a{sd}', { one = 1 }) check(v[1][1] == 'one' and v[1][2] == 1 and v[2] == nil) v = V('(si)', { 'hi', 3 }) check(v[1] == 'hi' and v[2] == 3 and v[3] == nil) check(V('s', 'hello')[1] == nil) end function variant.serialize() local V, v1, v2 = GLib.Variant v1 = V('s', 'Hello') v2 = V.new_from_data(v1.type, v1.data) check(v1:equal(v2)) -- Make sure that new_from_data properly keeps underlying data alive. v1 = nil collectgarbage() local _ = v2:print(true) end lua-lgi-0.7.2/tools/000077500000000000000000000000001221440706400142125ustar00rootroot00000000000000lua-lgi-0.7.2/tools/dump-typelib.lua000077500000000000000000000127431221440706400173420ustar00rootroot00000000000000#! /usr/bin/env lua ------------------------------------------------------------------------------ -- -- LGI tools for dumping typelib fragments into readable text format. -- -- Copyright (c) 2010, 2011 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php -- ------------------------------------------------------------------------------ local lgi_core = require 'lgi.core' local gi = lgi_core.gi require 'debugger' -- Implements BaseInfo object, capable of dump itself. local infos = {} infos.base = { attrs = { 'name', 'namespace', 'type', 'deprecated' }, cats = {}, } infos.base.__index = infos.base -- Creates new info wrapper according to info type. function infos.new(info) if info then return setmetatable({ info = info }, infos[info.type] or infos.base) end end -- Derives new baseinfo subtype. function infos.base:derive(attrs, cats) local new_attrs = {} for _, val in ipairs(self.attrs) do new_attrs[#new_attrs + 1] = val end for _, val in ipairs(attrs or {}) do new_attrs[#new_attrs + 1] = val end local new_cats = {} for _, val in ipairs(self.cats) do new_cats[#new_cats + 1] = val end for _, val in ipairs(cats or {}) do new_cats[#new_cats + 1] = val end local new = setmetatable({ attrs = new_attrs, cats = new_cats }, self) new.__index = new return new end -- Gets given attribute or category. function infos.base:get(name, depth) local item = self.info[name] if gi.isinfo(item) then item = infos.new(item) if depth then item = item:dump(depth) end else for _, cat in pairs(self.cats) do if cat == name then item = infos.category.new(item) end end end return item end -- Dumps all attributes into the target table. function infos.base:dump_attrs(target, depth) for _, attr in ipairs(self.attrs) do target[attr] = self:get(attr, depth - 1) end return attrs end -- Dumps all categories into the target table. function infos.base:dump_cats(target, depth) local cats = {} for _, cat in ipairs(self.cats) do target[cat] = self:get(cat):dump(depth - 1) end return cats end function infos.base:dump(depth) if depth <= 0 then return '...' end local t = {} self:dump_attrs(t, depth) local cats = {} self:dump_cats(cats, depth) if next(cats) then t.cats = cats end return t end -- Implementation of 'subcategory' pseudoinfo. infos.category = infos.base:derive() function infos.category.new(category) return setmetatable({ info = category }, infos.category) end function infos.category:dump(depth) local t = {} for i = 1, #self.info do t[i] = infos.new(self.info[i]):dump(depth) end return t end infos.type = infos.base:derive( { 'tag', 'is_basic', 'interface', 'array_type', 'is_zero_terminated', 'array_length', 'fixed_size', 'is_pointer' }, { 'params' }) function infos.type:dump_cats(target, depth) local params = {} for i, param in ipairs(self.info.params or {}) do params[i] = infos.new(param):dump(depth - 1) end if next(params) then target.params = params end end infos.registered = infos.base:derive({ 'gtype' }, {}) infos.object = infos.registered:derive( { 'parent', 'type_struct', }, { 'interfaces', 'fields', 'vfuncs', 'methods', 'constants', 'properties', 'signals' }) infos.interface = infos.registered:derive( { 'type_struct', }, { 'prerequisites', 'vfuncs', 'methods', 'constants', 'properties', 'signals' }) infos.property = infos.base:derive({ 'typeinfo', 'flags', 'transfer' }) infos.callable = infos.base:derive( { 'return_type', 'return_transfer' }, { 'args' }) infos['function'] = infos.callable:derive({ 'flags' }) infos.signal = infos.callable:derive({ 'flags' }) infos.callback = infos.callable:derive() infos.vfunc = infos.callable:derive() infos.arg = infos.base:derive( { 'typeinfo', 'direction', 'transfer', 'optional', 'typeinfo' } ) infos.struct = infos.registered:derive({ 'is_gtype_struct', 'size' }, { 'fields', 'methods' }) infos.union = infos.registered:derive({ 'size' }, { 'fields', 'methods' }) infos.field = infos.base:derive({ 'typeinfo', 'flags', 'size', 'offset' }) infos.enum = infos.registered:derive({ 'storage' }, { 'values' }) infos.value = infos.base:derive({ 'value' }) infos.constant = infos.base:derive({ 'typeinfo', 'value' }) -- Implementation of info wrapper for namespace pseudoinfo. infos.namespace = infos.base:derive({ 'name', 'version', 'dependencies' }) function infos.namespace:get(name) local item = self.info[name] return item and infos.new(item) end function infos.namespace:dump_cats(target, depth) if depth <= 0 then return '...' end for i = 1, #self.info do local info = self.info[i] target[info.name] = infos.new(info):dump(depth - 1) end end function infos.namespace.new(info) return setmetatable({ info = info }, infos.namespace) end -- Implementation of root element pseudoinfo. infos.root = infos.base:derive() function infos.root:get(name) return infos.namespace.new(gi.require(name)) end -- Commandline processing arg = arg or {} paths = {} depth = 3 for i = 1, #arg do if tonumber(arg[i]) then depth = tonumber(arg[i]) else paths[#paths + 1] = arg[i] end end -- Go through all paths and dump them. for _, path in ipairs(paths) do local info = infos.root for name in path:gmatch('([^%.]+)%.?') do info = info:get(name) if not info then break end end if not info then error(('%s not found'):format(path)) end dump(info:dump(depth), depth * 2) end