initial import --> to head
/CMakeLists.txt
Ignoring non-repository paths: /CMakeLists.txt
Sun Mar 13 20:40:35 CET 2011 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix loading on OSX.
Thanks to Elliott Slaughter
Sat Apr 3 14:34:21 CEST 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Account for possible lisp-object metatype id change when loading an image.
Sat Feb 20 22:04:46 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* cleanup
Sat Feb 20 22:02:38 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Make qt:application cleanup more stable
Sat Feb 20 22:00:30 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* support all from qt:variant conversions.
Mon Feb 15 16:33:05 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Build a shared library not a module.
Fixes a build error on OS X.
Thu Feb 4 16:06:38 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Test building libclsmokeqtcore
Thu Feb 4 10:22:53 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Add qvector.cpp
Sat Jan 30 16:40:15 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Get the QList size using Lisp instead of an external C function.
Tue Jan 26 17:19:51 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix define-qlist-wrapper usage for other modules. (i.e. qt.gui)
Mon Jan 25 20:07:22 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Export delete-app since other modules (qt.gui) might like to add methods to it.
Mon Jan 25 19:53:36 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Use ELT instead of AREF for sequences in vector translations.
Mon Jan 25 19:45:04 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Allow other modules to define QList<Foo*> conversions.
Mon Jan 25 19:43:56 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix error reporting on signal-slot connection failure.
Sat Jan 23 23:17:35 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* QVector<T> translation
Sun Jan 10 09:52:09 CET 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Split up in qt.core.
- Fix qt:with-core-app
- cleanup name prefixes
Sun Dec 13 13:44:37 CET 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Support ASDF instead of Mudballs.
Sun Dec 13 11:50:24 CET 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Install msg-handler also when starting from an image
Sun Dec 13 11:49:35 CET 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Convert C++ exceptions to a qFatal
Wed Sep 9 15:18:08 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Cleanup msg-handler
Wed Sep 2 14:00:35 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Better Lisp vector to QList<*> conversion.
Thu Aug 27 10:37:36 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Update to the new smokegenerator.
Sun Aug 2 13:29:13 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix double space when printing a qt:object.
Sun Aug 2 13:29:02 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* qt:event upcasting cleanup
Sun Aug 2 13:15:21 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Support ownership transfer to non smoke wrapped QObjects & cleanup C++ to Lisp translation.
Mon Jul 27 21:39:43 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix ownership transfer for lambda slot to no Smoke object.
Fri Jul 24 15:40:52 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Remove unnecessary #'cxx:data calls.
Thu Jul 23 00:21:01 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* support packages for symbols as property names.
Wed Jul 8 22:55:24 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* The smoke call stack is now a struct -> adapt.
Fri Jul 3 12:14:09 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix nested #'qt:exec
Thu Jul 2 21:37:42 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix potential lisp-object ID generation overflow for excessive lisp-object creation.
Thu Jul 2 21:12:45 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* move emit slot code to new function ACTIVATE & image startup fix for STATIC-META-OBJECT
Wed Jul 1 12:58:06 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Break API compatibility for qt:with-app and qt:exec & spellcheck
Sun Jun 21 11:29:25 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* *SMOKE-MODULE* must be passed instead of *QT-SMOKE*.
Thu Jun 11 20:50:26 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* The CLISP null pointer is NIL
Thu Jun 11 16:59:48 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* :qt and :qt-impl packages to prevent collision with :cl symbols and fix object with non smoke parent.
Wed Jun 10 14:14:34 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Transfer ownerhip only for smoke classes.
Wed Jun 10 14:02:01 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* more qt:variant conversions
Fri Jun 5 09:45:07 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* get-slot for function with this argument
Thu Jun 4 12:58:29 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Normalize signal and slot names at compile time.
Thu Jun 4 00:02:12 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix QT:APPLICATION cleanup in QT:WITH-APP and add restart to slot invocation.
Mon Jun 1 00:39:13 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* QList<QWidget*>
Mon Jun 1 00:22:22 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* QList<QObject*>
Sun May 31 23:59:55 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* cxx:push undo-stack takes ownership
Sun May 31 19:33:32 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Rework QObject parent ownership transfer
Sat May 30 14:16:53 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* soversion for wrapper
Thu May 28 16:13:57 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* ASDF
Wed May 27 19:18:41 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* QList<QByteArray> and QList<QVariant> conversion & use cxx:operator== and qt:operator== in cxx:=
Wed May 27 14:26:25 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* cleanup
Tue May 26 11:57:44 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Use argument conversion/promotion when emiting signals
Sun May 24 17:02:00 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* *exec-p* allows disabling qt:exec
Sun May 24 16:42:40 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Clozure CL Cmd line args for with-app
Sun May 24 16:40:11 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Use overload resolution instead of static-call
Sun May 24 16:30:31 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Cleanup app in with-app
Sun May 24 13:42:39 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Signal slot finalization fix
Tue May 19 17:16:49 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Search paths in with-translator
Tue May 19 16:32:42 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Clozure CL save-application fixes
Thu May 14 14:11:11 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Lisp image loading
Tue May 12 17:42:35 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Make *qt-smoke* read only
Mon May 11 21:50:13 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* print-object qt:object object-name
Mon May 11 16:15:30 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Cleanup remove unnecessary smoke:: in translation code.
Mon May 11 16:14:14 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix setf value and export variant-boundp.
Mon May 11 14:07:17 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* GCC visibility support for C wrapper symbols
Mon May 11 13:21:14 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* QList translations C wrapper
Mon May 11 13:18:36 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* update marshalling for overload resolution
Mon May 11 13:09:54 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* cleanup variant
Wed Apr 15 10:20:41 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* It is cxx:>= not cxx:=>.
Tue Apr 14 16:25:46 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* License
Tue Apr 14 11:16:21 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Do not use :asdf.
Sun Apr 12 21:56:34 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Add operator Lisp style functions.
Sun Apr 12 21:55:35 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* indent variant.lisp & minor cleanup
Sun Apr 12 15:12:20 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* get rid of &args for "defmethod cxx:"
Thu Apr 9 00:33:55 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix receiving C++ classes by value in a slot
Wed Apr 8 17:16:04 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* Fix receiving C++ arguments in signals
Tue Apr 7 22:07:00 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* delayed initialization macro
Tue Apr 7 11:49:59 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* cmucl support
Mon Apr 6 13:43:59 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* make unit test work & test on darcs record
Sun Apr 5 19:56:16 CEST 2009 Tobias Rautenkranz <tobias@rautenkranz.ch>
* initial import
diff -rN -u old-qt.core/CMakeLists.txt new-qt.core/CMakeLists.txt
--- old-qt.core/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/CMakeLists.txt 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.6)
+
+project(qt)
+
+add_subdirectory(src)
+
+include(UseDoxygen OPTIONAL)
diff -rN -u old-qt.core/COPYING new-qt.core/COPYING
--- old-qt.core/COPYING 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/COPYING 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,676 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff -rN -u old-qt.core/LICENSE new-qt.core/LICENSE
--- old-qt.core/LICENSE 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/LICENSE 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,22 @@
+The software in this package is distributed under the GNU General Public
+License (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version.
diff -rN -u old-qt.core/cl-smoke.qt.core.asd new-qt.core/cl-smoke.qt.core.asd
--- old-qt.core/cl-smoke.qt.core.asd 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/cl-smoke.qt.core.asd 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,42 @@
+(defsystem :cl-smoke.qt.core
+ :name :cl-smoke.qt.core
+ :version (0 0 1)
+ :author "Tobias Rautenkranz"
+ :license "GPL with linking exception"
+ :description "Smoke Qt core bindings."
+ :depends-on (:cl-smoke.smoke :cffi :alexandria)
+
+ :components
+ ((:module "src"
+ :components
+ ((:file "package")
+ (:module "lib" :depends-on ("package"))
+ (:file "qt.core" :depends-on ("package" "lib"))
+ (:file "ownership" :depends-on ("qt.core"))
+ (:file "event" :depends-on ("qt.core"))
+ (:file "object" :depends-on ("qt.core" "signal-slot" "qstring" "event"))
+ (:file "operator" :depends-on ("qt.core" "object"))
+ (:file "application" :depends-on ("qt.core" "properties"))
+ (:file "qstring" :depends-on ("qt.core"))
+ (:file "list" :depends-on ("qt.core"))
+ (:file "vector" :depends-on ("qt.core" "signal-slot"))
+ (:file "msg-handler" :depends-on ("lib" "qt.core"))
+ (:file "timer" :depends-on ("qt.core"))
+ (:file "i18n" :depends-on ("qt.core"))
+ (:file "lisp-object" :depends-on ("qt.core" "lib"))
+ (:module "signal-slot"
+ :serial t
+ :depends-on ("lisp-object")
+ :components
+ ((:file "signal-slot")
+ (:file "translate" :depends-on ("signal-slot"))
+ (:file "signal" :depends-on ("translate"))
+ (:file "slot" :depends-on ("signal"))
+ (:file "connect" :depends-on ("slot"))))
+ (:file "string-list" :depends-on ("qt.core" "lib" "qstring"))
+ (:file "variant" :depends-on ("qt.core" "qstring" "lisp-object"))
+ (:file "properties" :depends-on ("variant"))))))
+
+(defmethod perform ((operation test-op) (c (eql (find-system :cl-smoke.qt.core))))
+ (operate 'asdf:load-op :cl-smoke.qt.tests)
+ (operate 'asdf:test-op :cl-smoke.qt.tests))
diff -rN -u old-qt.core/src/CMakeLists.txt new-qt.core/src/CMakeLists.txt
--- old-qt.core/src/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/CMakeLists.txt 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1 @@
+add_subdirectory(lib)
diff -rN -u old-qt.core/src/application.lisp new-qt.core/src/application.lisp
--- old-qt.core/src/application.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/application.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,103 @@
+(in-package :cl-smoke.qt.core)
+
+(defvar *app*)
+(defvar qt:*exec-p* t
+ "Run exec if true and not otherwise.")
+
+(defun qt:app ()
+ "Returns the APPLICATION (or CORE-APPLICATION) object,
+within a WITH-APP."
+ (assert (qt:app-p)
+ (*app*)
+ "No application.")
+ *app*)
+
+(defun qt:app-p ()
+ "Returns t when the APPLICATION object exists and nil otherwise."
+ (boundp '*app*))
+
+(defun ensure-app (&optional
+ (application 'qt:core-application)
+ (args #+sbcl sb-ext:*posix-argv*
+ #+ccl ccl:*command-line-argument-list*
+ #-(or sbcl ccl) (list (lisp-implementation-type))))
+ "Constructs the global application object, when there is none,
+with the command line arguments ARGS.
+
+Returns the application object a first value and
+true when a new application was created and false otherwise."
+ (assert (not (null args))
+ (args)
+ "No program name supplied.")
+ (if (qt:app-p)
+ (progn
+ (assert (typep (qt:app) (find-class application))
+ (application)
+ "The existing application object ~A is
+not of type ~A." (qt:app) (find-class application))
+ (values (qt:app) nil))
+ (progn
+ (when (not (null-pointer-p (smoke::pointer
+ (qt:core-application.instance))))
+ (cerror (format nil "Delete the active application ~A."
+ (qt:core-application.instance))
+ "Active application not created by QT:WITH-APP.")
+ (smoke::delete-pointer (smoke::pointer (qt:core-application.instance))
+ (find-class 'qt:core-application)))
+ (let* ((argc (smoke:make-auto-pointer
+ (foreign-alloc :int :initial-element (length args))))
+ (argv (smoke:make-auto-pointer
+ (foreign-alloc :string :initial-contents args)))
+ (app (make-instance application :args (list argc argv))))
+ ;; argc and argv must remain valid during the lifetime of APP.
+ (setf (qt:property app 'cmdline-args)
+ (qt:make-lisp-variant (list argc argv)))
+ (tg:cancel-finalization app)
+ (values app t)))))
+
+(defgeneric delete-app (application)
+ (:method (application)
+ (unless (null-pointer-p (smoke:pointer application))
+ (cxx:quit application)
+ ;; Call the destructor; -> destructed callback is called,
+ ;; (~QApplication() is virtual) which takes care of cleanup on the
+ ;; Lisp side.
+ (smoke::delete-pointer (smoke:pointer application) (class-of application)))
+ (makunbound '*app*)))
+
+(defun kill-app ()
+ (delete-app (qt:app)))
+
+(defmacro with-application ((ensure-app remove-app) &body body)
+ (let ((cleanup-p (gensym)))
+ `(multiple-value-bind (*app* ,cleanup-p) ,ensure-app
+ (unwind-protect
+ (progn ,@body)
+ (when ,cleanup-p
+ ,remove-app)))))
+
+(defmacro qt:with-core-app (options &body body)
+ (assert (null options)
+ (options)
+ "Currently no options can be passed to QT:WITH-CORE-APP.")
+ `(with-application ((cl-smoke.qt.core::ensure-app 'qt:core-application) (kill-app))
+ ,@body))
+
+(defun qt:exec ()
+ "Executes APP. When QT:*EXEC-P* is false it returns immediately
+and transfers the ownership of the top-level widgets to the qt:application
+instance."
+ (when qt:*exec-p*
+ (restart-bind ((qt::abort-app #'(lambda ()
+ (cxx:quit (qt:app))
+ (invoke-restart (find-restart 'continue)))
+ :report-function
+ #'(lambda (stream)
+ (format stream "Return from the application event loop."))
+ :test-function
+ #'(lambda (condition)
+ (declare (ignore condition))
+ (and (qt:app-p)
+ (find-restart 'continue)))))
+ (let ((qt:*exec-p* nil))
+ (cxx:exec (qt:app))))))
diff -rN -u old-qt.core/src/event.lisp new-qt.core/src/event.lisp
--- old-qt.core/src/event.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/event.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,10 @@
+(in-package :cl-smoke.qt.core)
+
+(defun cast-event (event)
+ (enum-case (cxx:type event)
+ ((qt:event.+child-added+ qt:event.+child-removed+
+ qt:event.+child-polished+)
+ (setf (slot-value event 'pointer)
+ (upcast event (find-class 'qt:child-event)))
+ (change-class event 'qt:child-event)))
+ event)
diff -rN -u old-qt.core/src/i18n.lisp new-qt.core/src/i18n.lisp
--- old-qt.core/src/i18n.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/i18n.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,57 @@
+(in-package :cl-smoke.qt.core)
+
+(defun qt:tr (message &optional context)
+ "Returns the translated MESSAGE for CONTEXT or
+a string STRING-EQUAL to MESSAGE when no translation was found.
+
+Translations can be loaded with WITH-TRANSLATOR."
+ (qt:core-application.translate (or context "") message))
+
+(defmacro with-installed-translator (translator &body body)
+ `(unwind-protect
+ (progn
+ (cxx:install-translator (qt:app) ,translator)
+ ,@body)
+ (cxx:remove-translator (qt:app) ,translator)))
+
+(defmacro qt:with-translator ((base-name &rest paths) &body body)
+ "Loads the translations in the BASE-NAME_LANGCODE.qm file;
+searching PATHS.
+
+Must be in a WITH-APP."
+ (let ((translator (gensym)))
+ `(let ((,translator (make-instance 'qt:translator)))
+ (unless
+ (find-if #'(lambda (path)
+ (cxx:load ,translator
+ (format nil "~A_~A" ,base-name
+ (cxx:name (qt:locale.system)))
+ (namestring path)))
+ (list ,@paths))
+ (cerror "Ignore" "Loading the translations ~A for ~A failed."
+ ,base-name (cxx:name (qt:locale.system))))
+ (with-installed-translator ,translator
+ ,@body))))
+
+(defmacro qt:with-libqt-translator (&body body)
+ "Loads the translations for the Qt library.
+
+Must be in a WITH-APP."
+ (let ((translator (gensym)))
+ `(let ((,translator (make-instance 'qt:translator)))
+ (unless (cxx:load ,translator (format nil "qt_~A"
+ (cxx:name (qt:locale.system)))
+ (qt:library-info.location qt:library-info.+translations-path+))
+ (cerror "Ignore" "Loading the Qt library translations failed."))
+ (with-installed-translator ,translator
+ ,@body))))
+
+(defun qt:search-file (name &rest paths)
+ "Searches the file NAME in PATHS and returns its path."
+ (let ((file-path (find-if #'(lambda (path)
+ (probe-file (merge-pathnames name path)))
+ paths)))
+ (unless file-path
+ (error "The file ~S not found in the paths ~S" name paths))
+ (merge-pathnames name file-path)))
+
diff -rN -u old-qt.core/src/lib/CMakeLists.txt new-qt.core/src/lib/CMakeLists.txt
--- old-qt.core/src/lib/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/CMakeLists.txt 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,21 @@
+find_package(Qt4)
+set(QT_DONT_USE_QTGUI true)
+include(${QT_USE_FILE})
+
+include(CheckCXXCompilerFlag)
+check_cxx_compiler_flag("-fvisibility=hidden" CXX_VISIBILITY)
+if(CXX_VISIBILITY)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
+endif(CXX_VISIBILITY)
+
+set(QT_SMOKE_SOURCES qt_smoke.cpp
+ qstring.cpp qstringlist.cpp lisp_object.cpp qlist.cpp qvector.cpp)
+
+add_library(clsmokeqtcore SHARED ${QT_SMOKE_SOURCES})
+target_link_libraries(clsmokeqtcore ${QT_LIBRARIES})
+set_target_properties(clsmokeqtcore
+ PROPERTIES
+ SOVERSION "0.0"
+ VERSION "0.0.1")
+
+install(TARGETS clsmokeqtcore LIBRARY DESTINATION lib)
diff -rN -u old-qt.core/src/lib/cl_smoke_qt.h new-qt.core/src/lib/cl_smoke_qt.h
--- old-qt.core/src/lib/cl_smoke_qt.h 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/cl_smoke_qt.h 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,14 @@
+#ifndef CL_SMOKE_QT_H
+#define CL_SMOKE_QT_H
+
+#if defined _WIN32 || defined __CYGWIN__
+ #define CL_SMOKE_QT_EXPORT __declspec(dllexport)
+#else
+ #if __GNUC__ >= 4
+ #define CL_SMOKE_QT_EXPORT __attribute__((visibility("default")))
+ #else
+ #define CL_SMOKE_QT_EXPORT
+ #endif
+#endif
+
+#endif // CL_SMOKE_QT_H
diff -rN -u old-qt.core/src/lib/lisp_object.cpp new-qt.core/src/lib/lisp_object.cpp
--- old-qt.core/src/lib/lisp_object.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/lisp_object.cpp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,181 @@
+#include "lisp_object.h"
+
+#include "cl_smoke_qt.h"
+
+#include <QtGlobal>
+#include <QtDebug>
+#include <QVariant>
+
+namespace cl_smoke {
+namespace qt {
+
+/** @struct lisp_object::data
+ * @internal
+ * Holds a reference ID for a lisp object and calls
+ * the destructor callback when it is deleted.
+ */
+
+/** @typedef lisp_object::destructor
+ * Destructor.
+ * @param id The ID
+ */
+
+lisp_object::destructor lisp_object::destruct = NULL;
+
+
+/** Constructor. */
+lisp_object::data::data()
+: id(id),
+ is_set(false)
+{ }
+
+/** Constructor.
+ * @param id The ID.
+ */
+lisp_object::data::data(unsigned int id)
+: id(id),
+ is_set(true)
+{ }
+
+/** Destructor. */
+lisp_object::data::~data()
+{
+ Q_ASSERT_X(lisp_object::destruct, __func__,
+ "call setup_lisp_object() first.");
+
+ if (this->is_set)
+ (*lisp_object::destruct)(this->id);
+}
+
+/** @class lisp_object
+ * @brief Holds a reference ID to a lisp object.
+ *
+ * The registered destructor callback is called when
+ * the last instance for a specific lisp object is deleted.
+ *
+ * Used for lisp objects in QVariants and signal/slots.
+ */
+
+/** Constructor. */
+lisp_object::lisp_object()
+ : d(new data())
+{ }
+
+/** Constructor.
+ * @param id the ID
+ */
+lisp_object::lisp_object(unsigned int id)
+ : d(new data(id))
+{ }
+
+/** Constructor.
+ * @param other the lisp_object to copy
+ */
+lisp_object::lisp_object(const lisp_object& other)
+ : d(other.d)
+{ }
+
+/** @fn lisp_object::id() const
+ * Gets the ID.
+ *
+ * @return the ID
+ */
+
+/** @fn lisp_object::set() const
+ * Determines werter the ID is set.
+ *
+ * @return @c true when the id is set and @c false otherwise.
+ */
+
+/** Sets a new ID.
+ * @param id the ID
+ */
+void
+lisp_object::set_id(unsigned int id)
+{
+ Q_ASSERT(this->set() ? id != this->id() : true);
+
+ d = new data(id);
+}
+
+} // namespace qt
+} // namespace cl_smoke
+
+using namespace cl_smoke::qt;
+
+/** Initialize the lisp_object.
+ * @relates cl_smoke::qt::lisp_object
+ * @param destruct destructor callback
+ *
+ * @return the QMetaType ID of lisp_object
+ */
+CL_SMOKE_QT_EXPORT int
+cl_smoke_setup_lisp_object(void* destruct)
+{
+ Q_ASSERT(destruct != NULL);
+ lisp_object::destruct = reinterpret_cast<lisp_object::destructor>(destruct);
+
+ return qRegisterMetaType<lisp_object>();
+}
+
+/** Gets the ID of @a object.
+ * @relates cl_smoke::qt::lisp_object
+ * @param object the lisp_object.
+ *
+ * @return the ID
+ */
+CL_SMOKE_QT_EXPORT unsigned int
+cl_smoke_lisp_object_id(const void* object)
+{
+ return static_cast<const lisp_object*>(object)->id();
+}
+
+
+/** Determines werter the ID of @a object is set.
+ * @relates cl_smoke::qt::lisp_object
+ * @param object the object
+ *
+ * @return @c true when the ID is set and @c false otherwise.
+ */
+CL_SMOKE_QT_EXPORT int
+cl_smoke_lisp_object_is_set(const void* object)
+{
+ return static_cast<const lisp_object*>(object)->set();
+}
+
+/** Makes a new lisp_object.
+ * @relates cl_smoke::qt::lisp_object
+ * @param id the ID
+ *
+ * @return A new lisp_object instance.
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_make_lisp_object(unsigned int id)
+{
+ return new lisp_object(id);
+}
+
+/** Deletes a lisp_object.
+ * @relates cl_smoke::qt::lisp_object
+ * @param object the lisp_object
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_free_lisp_object(void* object)
+{
+ delete static_cast<lisp_object*>(object);
+}
+
+/** Gets the lisp_object of a QVariant.
+ * @relates cl_smoke::qt::lisp_object
+ * @param variant the QVariant
+ *
+ * @return a new lisp_object.
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_lisp_object_value(const void* variant)
+{
+ const QVariant* qvariant = static_cast<const QVariant*>(variant);
+ Q_ASSERT(QVariant::UserType == qvariant->type());
+
+ new lisp_object(qvariant->value<lisp_object>());
+}
diff -rN -u old-qt.core/src/lib/lisp_object.h new-qt.core/src/lib/lisp_object.h
--- old-qt.core/src/lib/lisp_object.h 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/lisp_object.h 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,83 @@
+#ifndef LISP_OBJECT_H
+#define LISP_OBJECT_H
+
+#include "cl_smoke_qt.h"
+
+#include <QMetaType>
+#include <QSharedData>
+#include <QExplicitlySharedDataPointer>
+#include <smoke.h>
+
+extern "C"
+{
+ CL_SMOKE_QT_EXPORT int
+ cl_smoke_setup_lisp_object(void* destruct);
+
+ CL_SMOKE_QT_EXPORT unsigned int
+ cl_smoke_lisp_object_id(const void* object);
+
+ CL_SMOKE_QT_EXPORT int
+ cl_smoke_lisp_object_is_set(const void* object);
+
+ CL_SMOKE_QT_EXPORT void*
+ cl_smoke_make_lisp_object(unsigned int id);
+
+ CL_SMOKE_QT_EXPORT void*
+ cl_smoke_free_lisp_object(void* object);
+
+ CL_SMOKE_QT_EXPORT void*
+ cl_smoke_lisp_object_value(const void* variant);
+}
+
+namespace cl_smoke {
+namespace qt {
+
+class lisp_object
+{
+ public:
+ typedef void (*destructor)(unsigned int id);
+
+ lisp_object();
+
+ lisp_object(unsigned int id);
+
+ lisp_object(const lisp_object& other);
+
+ inline unsigned int
+ id() const
+ { Q_ASSERT(this->set()); return d->id; }
+
+ void
+ set_id(unsigned int id);
+
+ inline bool
+ set() const
+ { return d->is_set; }
+
+ friend int
+ ::cl_smoke_setup_lisp_object(void* destruct);
+
+ private:
+ struct data : public QSharedData
+ {
+ data();
+ data(unsigned int id);
+ ~data();
+ unsigned int id;
+ bool is_set;
+
+ private:
+ Q_DISABLE_COPY(data)
+ };
+
+ QExplicitlySharedDataPointer<data> d;
+
+ static destructor destruct;
+};
+
+} // namespace qt
+} // namespace cl_smoke
+
+Q_DECLARE_METATYPE(cl_smoke::qt::lisp_object);
+
+#endif // LISP_OBJECT_H
diff -rN -u old-qt.core/src/lib/qlist.cpp new-qt.core/src/lib/qlist.cpp
--- old-qt.core/src/lib/qlist.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/qlist.cpp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,15 @@
+#include "qlist.h"
+
+/** @file
+ * @brief QList conversions. */
+
+#include <QVariant>
+#include <QByteArray>
+
+extern "C" {
+
+DEFINE_QLIST_WRAPPER(QVariant)
+DEFINE_QLIST_WRAPPER_PTR(void)
+DEFINE_QLIST_WRAPPER(QByteArray)
+
+} // extern "C"
diff -rN -u old-qt.core/src/lib/qlist.h new-qt.core/src/lib/qlist.h
--- old-qt.core/src/lib/qlist.h 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/qlist.h 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,84 @@
+#ifndef CL_SMOKE_QT_QLIST_H
+#define CL_SMOKE_QT_QLIST_H
+
+#include "cl_smoke_qt.h"
+
+#include <QList>
+
+/** @file
+ */
+
+/** Defines a C wrapper for the QList<@a TYPE>.
+ * @param TYPE the type of the elements of the QList
+ */
+#define DEFINE_QLIST_WRAPPER(TYPE) \
+ DEFINE_QLIST_WRAPPER_3(TYPE, TYPE, VALUE)
+
+/** Defines a C wrapper for the QList<@a TYPE*>,
+ * where @a TYPE is the of the pointer.
+ *
+ * @param NAME the name used for the wrapper functions.
+ * @param TYPE the type of the elements
+ */
+#define DEFINE_QLIST_WRAPPER_PTR(TYPE) \
+ DEFINE_QLIST_WRAPPER_3(TYPE, TYPE*, PTR)
+
+/** @internal */
+#define DEFINE_QLIST_WRAPPER_3(NAME, TYPE, PTR_VALUE) \
+ DEFINE_QLIST_WRAPPER_ALL_PART(NAME, TYPE) \
+ DEFINE_QLIST_WRAPPER_ ## PTR_VALUE ## _PART(NAME, TYPE) \
+
+
+/** @internal
+ * size, free and make_list. */
+#define DEFINE_QLIST_WRAPPER_ALL_PART(NAME, TYPE) \
+CL_SMOKE_QT_EXPORT void \
+cl_smoke_free_list_ ## NAME (void* list) \
+{ \
+ delete static_cast<QList< TYPE >*>(list); \
+} \
+ \
+CL_SMOKE_QT_EXPORT void* \
+cl_smoke_make_list_ ## NAME () \
+{ \
+ return new QList< TYPE >(); \
+} \
+ \
+
+/** @internal
+ * At and append for pointer types
+ */
+#define DEFINE_QLIST_WRAPPER_PTR_PART(NAME, TYPE) \
+CL_SMOKE_QT_EXPORT const void* \
+cl_smoke_list_ ## NAME ## _at(const void* list, int index) \
+{ \
+ const QList< TYPE >* qlist = static_cast<const QList< TYPE > *>(list); \
+ return qlist->at(index); \
+} \
+\
+CL_SMOKE_QT_EXPORT void \
+cl_smoke_list_ ## NAME ## _append(void* list, void* data) \
+{ \
+ static_cast<QList< TYPE >*>(list) \
+ ->append(static_cast<TYPE>(data)); \
+} \
+
+/** @internal
+ * At and append for value types.
+ */
+#define DEFINE_QLIST_WRAPPER_VALUE_PART(NAME, TYPE) \
+CL_SMOKE_QT_EXPORT const void* \
+cl_smoke_list_ ## NAME ## _at(const void* list, int index) \
+{ \
+ const QList< TYPE >* qlist = static_cast<const QList< TYPE > *>(list); \
+ return new TYPE(qlist->at(index)); \
+} \
+\
+CL_SMOKE_QT_EXPORT void \
+cl_smoke_list_ ## NAME ## _append(void* list, void* data) \
+{ \
+ static_cast<QList< TYPE >*>(list) \
+ ->append(*static_cast<TYPE*>(data)); \
+} \
+
+#endif // CL_SMOKE_QT_QLIST_H
diff -rN -u old-qt.core/src/lib/qstring.cpp new-qt.core/src/lib/qstring.cpp
--- old-qt.core/src/lib/qstring.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/qstring.cpp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,44 @@
+#include <QString>
+
+#include "cl_smoke_qt.h"
+
+/** @file
+ * @brief QString conversion. */
+
+extern "C" {
+
+/** Converts a QString to a QByteArray.
+ * @param qstring Pointer to a QString
+ *
+ * @return a pointer to a newly allocated char array.
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_qstring_to_byte_array(const void* qstring)
+{
+ const QString* string = static_cast<const QString*>(qstring);
+
+ return new QByteArray(string->toLocal8Bit());
+}
+
+/** Frees an QString.
+ * @param qstring the QString to free
+ */
+CL_SMOKE_QT_EXPORT void
+cl_smoke_free_qstring(void* qstring)
+{
+ delete static_cast<QString*>(qstring);
+}
+
+/** Converts a string to a QString.
+ * @param data a char array
+ * @param length the length of @a data
+ *
+ * @return a newly allocated QString
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_string_to_qstring(const char* data, int length)
+{
+ return new QString(QString::fromLocal8Bit(data, length));
+}
+
+} // extern "C"
diff -rN -u old-qt.core/src/lib/qstringlist.cpp new-qt.core/src/lib/qstringlist.cpp
--- old-qt.core/src/lib/qstringlist.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/qstringlist.cpp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,70 @@
+#include "cl_smoke_qt.h"
+
+#include <QStringList>
+#include <QtDebug>
+
+/** @file
+ * @brief QStringList conversion. */
+
+extern "C" {
+
+/** Returns the number of items of @a string_list.
+ * @param string_list the QStringList
+ *
+ * @return the number of items
+ */
+CL_SMOKE_QT_EXPORT int
+cl_smoke_string_list_size(const void* string_list)
+{
+ Q_ASSERT(string_list);
+ return static_cast<const QStringList*>(string_list)->size();
+}
+
+/** Returns the byte array of @a string_list at position @a index.
+ * @param string_list the QStringList
+ * @param index the index of the string
+ *
+ * @return a new allocated byte-array
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_string_list_at(const void* string_list, int index)
+{
+ Q_ASSERT(string_list);
+ const QStringList* list = static_cast<const QStringList*>(string_list);
+
+ Q_ASSERT(0 <= index && index < list->size());
+
+ return new QByteArray(list->at(index).toLocal8Bit());
+}
+
+/** Free a QStringList.
+ * @param string_list the QStringList to free
+ */
+CL_SMOKE_QT_EXPORT void
+cl_smoke_free_string_list(void* string_list)
+{
+ delete static_cast<QStringList*>(string_list);
+}
+
+/** Allocates a new QStringList.
+ *
+ * @return a new QStringList
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_make_string_list()
+{
+ return new QStringList();
+}
+
+/** Appends @a string to @a string_list
+ * @param string_list the QStringList
+ * @param data the string
+ * @param length the length of @a data
+ */
+CL_SMOKE_QT_EXPORT void
+cl_smoke_string_list_append(void* string_list, const char* data, int length)
+{
+ static_cast<QStringList*>(string_list)->append(QString::fromLocal8Bit(data, length));
+}
+
+} // extern "C"
diff -rN -u old-qt.core/src/lib/qt_smoke.cpp new-qt.core/src/lib/qt_smoke.cpp
--- old-qt.core/src/lib/qt_smoke.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/qt_smoke.cpp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,53 @@
+#include "cl_smoke_qt.h"
+
+#include <qnamespace.h>
+#include <QEvent>
+#include <QtDebug>
+
+/** @file
+ * @brief Qt support functions */
+
+#include <exception>
+
+static void
+terminate()
+{
+ qFatal("caught an exception.");
+}
+
+extern "C" {
+
+/** Registers a callback to be invoked for every QEvent.
+ * @see QCoreApplication::notifyInternal
+ *
+ * @param callback the callback
+ *
+ * @return @c true on success and @c false otherwise
+ */
+CL_SMOKE_QT_EXPORT int
+cl_smoke_register_event_notify(void* callback)
+{
+ Q_ASSERT(callback);
+ std::set_terminate(terminate);
+
+ return QInternal::registerCallback(QInternal::EventNotifyCallback,
+ reinterpret_cast<qInternalCallback>(callback));
+}
+
+/** Returns the most specific QMetaObject of the QObject instance @a object.
+ * Used to determine the actual class of an object. Smoke can not be used since it calls the
+ * metaObject() of the class the method was called for.
+ *
+ * @param object A QObject
+ *
+ * @return QMetaObject
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_meta_object(void* object)
+{
+ Q_ASSERT(object);
+ static_cast<QObject*>(object)->metaObject();
+}
+
+
+} // extern "C"
diff -rN -u old-qt.core/src/lib/qvector.cpp new-qt.core/src/lib/qvector.cpp
--- old-qt.core/src/lib/qvector.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lib/qvector.cpp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,27 @@
+#include "cl_smoke_qt.h"
+
+#include <QVector>
+#include <QPoint>
+
+extern "C" {
+
+/** Construct a 0 sized QVector.
+ * Since the QVectorData is QVectorData::shared_null the template type does not matter.
+ * @return A null QVector
+ */
+CL_SMOKE_QT_EXPORT void*
+cl_smoke_make_qvector()
+{
+ return new QVector<QPoint>();
+}
+
+/** Deletes a null QVector. i.e.: The QVectorData pointer is 0.
+ * @param qvector a null QVector
+ */
+CL_SMOKE_QT_EXPORT void
+cl_smoke_delete_qvector(void* qvector)
+{
+ delete static_cast<QVector<QPoint>*>(qvector);
+}
+
+} // extern "C"
diff -rN -u old-qt.core/src/lisp-object.lisp new-qt.core/src/lisp-object.lisp
--- old-qt.core/src/lisp-object.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/lisp-object.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,67 @@
+(in-package :cl-smoke.qt.core)
+
+(defvar *cxx-lisp-objects* (smoke::make-synchronized-hash-table)
+ "Objects that are currently passed in a C++ class.")
+
+(let ((id 0))
+ (declare (type (smoke::c-integer :unsigned-int) id))
+ (defun gen-cxx-lisp-object-id ()
+ "Returns a new unique ID."
+ (loop do
+ (setf id
+ (logand (1- (expt 2 (* 8 (foreign-type-size :unsigned-int) )))
+ (1+ id)))
+ while (nth-value 1 (gethash id *cxx-lisp-objects*)))
+ id))
+
+(defcfun cl-smoke-setup-lisp-object :int
+ (destruct :pointer))
+
+(defcfun cl-smoke-lisp-object-id :unsigned-int
+ (object :pointer))
+
+(defcfun cl-smoke-lisp-object-is-set :int
+ (object :pointer))
+
+(defcfun cl-smoke-make-lisp-object :pointer
+ (id :unsigned-int))
+
+(defcfun cl-smoke-free-lisp-object :void
+ (object :pointer))
+
+(defcallback destruct-cxx-lisp-object :void
+ ((id :unsigned-int))
+ (remhash id *cxx-lisp-objects*))
+
+(defvar *cxx-lisp-object-metatype* "Metatype ID of the C++ lisp_object.")
+
+(eval-startup ()
+ (setf *cxx-lisp-object-metatype*
+ (cl-smoke-setup-lisp-object (callback destruct-cxx-lisp-object)))
+ (assert (>= *cxx-lisp-object-metatype*
+ (smoke::value qt:meta-type.+user+))
+ (*cxx-lisp-object-metatype*)
+ "setup of lisp-object failed"))
+
+(defun make-cxx-lisp-object (object)
+ "Constructs a C++ object wrapper for OBJECT."
+ (let ((id (gen-cxx-lisp-object-id)))
+ (setf (gethash id *cxx-lisp-objects*) object)
+ (cl-smoke-make-lisp-object id)))
+
+(defun free-cxx-lisp-object (pointer)
+ "Deletes the lisp_object at POINTER."
+ (cl-smoke-free-lisp-object pointer))
+;; (qmetatype.destroy *cxx-lisp-object-metatype* pointer)) ;; FIXME use this?
+
+(defun translate-cxx-lisp-object (pointer)
+ "Returns the object of the cxx-lisp-object at POINTER.
+
+When being received as an argument by a slot,
+the object must not be deallocated."
+ (multiple-value-bind (value present-p)
+ (gethash (cl-smoke-lisp-object-id pointer)
+ *cxx-lisp-objects*)
+ (assert present-p (value present-p)
+ "No object for ~A in ~A" pointer *cxx-lisp-objects*)
+ value))
diff -rN -u old-qt.core/src/list.lisp new-qt.core/src/list.lisp
--- old-qt.core/src/list.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/list.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,117 @@
+(in-package :cl-smoke.qt.core)
+
+(defbitfield qlist-data-flags
+ :sharable)
+
+(defcstruct qlist-data
+ (ref :char :count #.(class-size (find-class 'qt:basic-atomic-int)))
+ (alloc :int)
+ (begin :int)
+ (end :int)
+ (flags qlist-data-flags)
+ (array :pointer))
+
+(defcstruct qlist
+ (data (:pointer qlist-data)))
+
+(defun qlist-size (qlist)
+ (let ((data (foreign-slot-value qlist 'qlist 'data)))
+ (- (foreign-slot-value data 'qlist-data 'end)
+ (foreign-slot-value data 'qlist-data 'begin))))
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (macrolet ((c-name (name)
+ `(nth-value 1 ,name))
+ (fun-names-let (name-pre-post-fixes &body body)
+ `(flet (,@(mapcar
+ #'(lambda (npp)
+ `(,(first npp) (type)
+ (values
+ (intern (string-upcase
+ (concatenate 'string
+ ,(second npp)
+ type
+ ,(third npp)))
+ ,*package*)
+ (concatenate 'string
+ (substitute #\_ #\-
+ ,(second npp))
+ type
+ (substitute #\_ #\-
+ ,(third npp))))))
+ name-pre-post-fixes))
+ ,@body)))
+ (fun-names-let ((list-free "cl-smoke-free-list-")
+ (list-make "cl-smoke-make-list-")
+ (list-at "cl-smoke-list-" "-at")
+ (list-append "cl-smoke-list-" "-append"))
+ (defmacro define-qlist-wrapper (type-name element-type &optional (c-name nil c-name-p)
+ &key def-cfuns)
+ (let* ((c-name (or c-name type-name))
+ (type c-name)
+ (lisp-type (symbolicate 'qlist- element-type)))
+ `(progn
+ ,(when (or (not c-name-p) def-cfuns)
+ `(progn
+ (defcfun ,(c-name (list-free type)) :void
+ "Frees LIST."
+ (list :pointer))
+ (defcfun ,(c-name (list-make type)) :pointer
+ "Makes a list.")
+ (defcfun ,(c-name (list-at type)) :pointer
+ "Returns the a newly constructed copy of the element at
+ position AT of LIST."
+ (list :pointer)
+ (index :int))
+ (defcfun ,(c-name (list-append type)) :pointer
+ "Appends NEW-ELEMENT to LIST."
+ (list :pointer)
+ (new-element :pointer))))
+ ;; To Lisp
+ ,@(loop for type-name in (ensure-list type-name) collect
+ `(defun ,(symbolicate 'from-list- type-name) (list-pointer)
+ (declare (optimize (speed 3)))
+ (let ((vector (make-array (qlist-size
+ list-pointer))))
+ (dotimes (index (length vector) vector)
+ (setf (elt vector index)
+ ;; FIXME the returned object is not wrapped by Smoke
+ ;; -> change this?
+ (object-to-lisp
+ (,(list-at type)
+ list-pointer index)
+ (make-smoke-type ,(symbolicate '*smoke-module*)
+ ,type-name)))))))
+ ,@(loop for type-name in (ensure-list type-name) collect
+ `(define-to-lisp-translation
+ (,(format nil "const QList<~A>&" type-name)
+ ,(format nil "QList<~A>" type-name))
+ ,(symbolicate 'from-list- type-name)
+ ,(list-free type)))
+ ;; From Lisp
+ (defun ,(symbolicate 'coerce- lisp-type) (list)
+ (let ((qlist (,(list-make type))))
+ (loop for element across list do
+ (,(list-append type)
+ qlist (pointer (make-instance ',element-type :args (list element)))))
+ (make-cleanup-pointer
+ qlist
+ (function ,(list-free type)))))
+ (defun ,(symbolicate lisp-type '-p) (list)
+ (every #'(lambda (element)
+ ;(typep element ',element-type))
+ (typep element (find-class ',element-type)))
+ list))
+ ,@(loop for type-name in (ensure-list type-name) collect
+ `(define-from-lisp-translation (,(format nil "const QList<~A>&" type-name)
+ ,(format nil "QList<~A>" type-name))
+ ;; FIXME allow sequence
+ (and (vector );,element-type)
+ (satisfies ,(symbolicate lisp-type '-p)))
+ ,(symbolicate 'coerce- lisp-type)))))))))
+
+(define-qlist-wrapper "QVariant" qt:variant)
+
+(define-qlist-wrapper "QByteArray" qt:byte-array)
+
+(define-qlist-wrapper "QObject*" qt:object "void" :def-cfuns t)
diff -rN -u old-qt.core/src/msg-handler.lisp new-qt.core/src/msg-handler.lisp
--- old-qt.core/src/msg-handler.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/msg-handler.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,24 @@
+(in-package :cl-smoke.qt.core)
+
+;; FIXME Determine the actual size of the QtMsgType enum.
+(cffi:defctype qt-msg-type :int)
+
+;; QtMsgHandler is a typedef for a pointer.
+(define-pointer-typedef "QtMsgHandler" foreign-pointer)
+
+(define-pointer-typedef "void(*)(QtMsgType,const char*)" foreign-pointer)
+(define-pointer-typedef "unsigned char*" foreign-pointer)
+
+(defcallback qt-msg-handler :void
+ ((type qt-msg-type)
+ (message :string))
+ (ecase type
+ (#.(value qt:+qt-debug-msg+)
+ (write-string "qDebug: " *debug-io*)
+ (write-line message *debug-io*))
+ (#.(value qt:+qt-warning-msg+) (warn message))
+ (#.(value qt:+qt-critical-msg+) (cerror "Ignore" "~A" message))
+ (#.(value qt:+qt-fatal-msg+) (error message))))
+
+(eval-startup (:load-toplevel)
+ (qt:q-install-msg-handler (callback qt-msg-handler)))
diff -rN -u old-qt.core/src/object.lisp new-qt.core/src/object.lisp
--- old-qt.core/src/object.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/object.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,247 @@
+(in-package :cl-smoke.qt.core)
+
+;; Smoke always calls the method of the class the object is assumed to
+;; be and not the most specific method like required for virtual
+;; methods. Thus we implement a virtual metaObject() method to
+;; determine the actual class. This is only needed for objects not
+;; constructed by Smoke, since otherwise we would know the most
+;; specific class.
+(defcfun cl-smoke-meta-object :pointer (object :pointer))
+(defun meta-object (object)
+ (make-instance 'qt:meta-object
+ :pointer (cl-smoke-meta-object (pointer object))))
+
+(defmethod cxx:static-meta-object ((class cxx:class))
+ (cxx:static-meta-object (smoke::find-smoke-class class)))
+
+(defmethod documentation :around ((class smoke::smoke-standard-class)
+ (doc-type (eql 't)))
+ (if (and (subtypep class (find-class 'qt:object))
+ (not (subtypep class (find-class 'cxx:class))))
+ (format nil "~@[~A~%~]Properties:~%~T~{~<~%~T~0,75:; ~(~A~)~>~}
+
+Signals:
+~{~T~A~%~}
+Slots:
+~{~T~A~%~}"
+ (call-next-method) (sort (qt:class-direct-properties class) #'string<=)
+ (sort (class-signals class) #'string<=)
+ (sort (class-slots class) #'string<=))
+ (call-next-method)))
+
+(defmethod print-object ((object qt:object) stream)
+ (if (or (not (slot-boundp object 'pointer))
+ (null-pointer-p (pointer object)))
+ (call-next-method)
+ (if (string= "" (cxx:object-name object))
+ (print-unreadable-object (object stream :type t :identity t)
+ (when (smoke::const-p object)
+ (princ "CONST " stream)))
+ (print-unreadable-object (object stream :type t :identity t)
+ (when (smoke::const-p object)
+ (princ "CONST " stream))
+ (princ (cxx:object-name object) stream)))))
+
+(defmethod print-object ((object qt:meta-object) stream)
+ (if (or (not (slot-boundp object 'pointer))
+ (null-pointer-p (pointer object)))
+ (call-next-method)
+ (print-unreadable-object (object stream :type t :identity t)
+ (princ (cxx:class-name object) stream))))
+
+(defun meta-object-methods (meta-object &optional (direct-only nil))
+ (loop for index from (if direct-only (cxx:method-offset meta-object) 0)
+ below (cxx:method-count meta-object)
+ collect (cxx:method meta-object index)))
+
+
+(defun meta-object-signals (meta-object &key all)
+ (mapcar #'cxx:signature
+ (remove-if-not #'(lambda (m) (enum= qt:meta-method.+signal+
+ (cxx:method-type m)))
+ (meta-object-methods meta-object (not all)))))
+
+(defun class-signals (class &key all)
+ (meta-object-signals (cxx:static-meta-object class) :all all))
+
+(defun meta-object-slots (meta-object &key all)
+ (mapcar #'cxx:signature
+ (remove-if-not #'(lambda (m) (enum= qt:meta-method.+slot+
+ (cxx:method-type m)))
+ (meta-object-methods meta-object (not all)))))
+
+
+(defun class-slots (class &key all)
+ (meta-object-slots (cxx:static-meta-object class) :all all))
+
+(defun parent-p (object)
+ (not (null-pointer-p (smoke::pointer-call
+ (smoke::make-smoke-method-from-name
+ (find-class 'qt:object)
+ "parent")
+ (smoke::pointer object)))))
+
+
+;; FIXME this might not be that smart.
+(eval-startup (:compile-toplevel :execute)
+ (defparameter *destroyed-slot* (qt:make-slot
+ #'(lambda (object)
+ (foreign-funcall-pointer
+ (get-callback 'smoke::destructed)
+ () :pointer (smoke:pointer object))))))
+
+(defvar *toplevel-objects* nil)
+
+(defun ensure-smoke-parent (object)
+ (declare (optimize (speed 3)))
+ (let ((parent (cxx:parent object)))
+ (assert (not (null-pointer-p (smoke:pointer parent)))
+ ()
+ "The object ~A has not parent." object)
+ (unless (smoke::has-pointer-p (smoke:pointer parent))
+ ;; Before we ADD-OBJECT PARENT it must know its real class to
+ ;; prevent a clash when the same pointer is returned by a
+ ;; function with a more specific type.
+ (change-class parent
+ ;; Note: there can be classes that are not known
+ ;; to Smoke, like KDE's OxygenStyle that might
+ ;; be seen by the event-notify callback. But
+ ;; it's probably save to assume the user will
+ ;; never use those.
+ (let ((class-name (cxx:class-name (meta-object parent))))
+ (smoke::lispify class-name (ecase (char class-name 0)
+ (#\Q :qt)
+ (#\K :kde)))))
+ (smoke::add-object parent)
+ (qt:connect (qt:get-signal parent "destroyed(QObject*)")
+ *destroyed-slot* qt:+direct-connection+)
+ (tg:cancel-finalization parent)
+ (if (null-pointer-p (smoke:pointer (cxx:parent parent)))
+ (push parent *toplevel-objects*)
+ (smoke::transfer-ownership-to parent (ensure-smoke-parent parent))))
+ parent))
+
+(defmethod initialize-instance :after ((object qt:object)
+ &key (pointer nil pointer-p) &allow-other-keys)
+ "Registers the object to the parent when a parent was set in the constructor
+and the objects metaclass is SMOKE-WRAPPER-CLASS."
+ (declare (optimize (speed 3)))
+ (when (and (not pointer-p)
+ (null-pointer-p (smoke::pointer object)))
+ (error "Object ~A has not been constructed" object))
+ (when (and (null pointer)
+ (not (null-pointer-p (smoke::pointer object)))
+ (parent-p object))
+ (smoke::transfer-ownership-to object
+ (ensure-smoke-parent object))))
+
+(define-condition wrapper-gc (storage-condition)
+ ((object-class :initarg :object-class
+ :documentation "The class of the gc'ed object.")
+ (pointer :initarg :pointer))
+ (:report (lambda (condition stream)
+ (format stream "The object ~A ~A of type cxx:class
+has the parent but got garbage collected."
+ (slot-value condition 'object-class)
+ (slot-value condition 'pointer)))))
+
+(eval-startup (:compile-toplevel :execute)
+ (defparameter *get-parent*
+ (smoke::make-smoke-method-from-name (find-class 'qt:object) "parent"))
+
+ ;; FIXME this leaks memory when QCoreApplication::exec() is never
+ ;; called, beause then, deleteLater() has no effect.
+ (defparameter *delete-later*
+ (smoke::make-smoke-method-from-name (find-class 'qt:object) "deleteLater")))
+
+(defmethod smoke::make-finalize ((object qt:object))
+ "Delete the qt:object OBJECT,
+ by calling cxx:delete-later iff it has no parent."
+ (let ((pointer (pointer object))
+ (class (class-of object))
+ (next (call-next-method)))
+ (declare (function next))
+ (if (typep (class-of object) 'cxx:class)
+ #'(lambda ()
+ (declare (optimize (speed 3)))
+ (handler-case
+ (if (null-pointer-p (smoke::pointer-call *get-parent* pointer))
+ (smoke::pointer-call *delete-later* pointer)
+ (error (make-condition 'wrapper-gc
+ :object-class class
+ :pointer pointer)))
+ (error (condition)
+ (smoke::report-finalize-error condition "qt:object wrap"
+ (name class) pointer))))
+ #'(lambda ()
+ (declare (optimize (speed 3)))
+ (handler-case
+ (if (null-pointer-p (smoke::pointer-call *get-parent* pointer))
+ (funcall next)
+ (cerror "Ignore" "Finalizer for object with a parent called."))
+ (error (condition)
+ (smoke::report-finalize-error condition "qt:object"
+ (name class) pointer)))))))
+
+
+;;;
+;;; The event-notify callback get called by QCoreApplication, on
+;;; notification of an event.
+;;;
+;;; The DATA argument is an array of size three, containing the
+;;; pointers:
+;;;
+;;; void* receiver
+;;; void* event
+;;; void* result
+;;; in that order.
+;;;
+;;; Returning true marks the event as handled; false on the other hand
+;;; leaves the event processing unchanged.
+;;;
+;;; See: QCoreApplication::notifyInternal(QObject *receiver, QEvent
+;;; *event)
+
+(cffi:defcallback event-notify smoke:cxx-bool
+ ((data :pointer))
+ (declare (optimize (speed 3)))
+ (let ((receiver (smoke::get-object (cffi:mem-aref data :pointer 0)))
+ (event (cast-event
+ (make-instance 'qt:event
+ :pointer (cffi:mem-aref data :pointer 1)))))
+ (enum-case (cxx:type event)
+ (qt:event.+child-added+
+ (tg:cancel-finalization (cxx:child event))
+ (when (smoke::has-pointer-p (smoke::pointer (cxx:child event)))
+ (unless receiver
+ (setf receiver (ensure-smoke-parent (cxx:child event))))
+ (smoke::transfer-ownership-to (cxx:child event) receiver)))
+ (qt:event.+child-removed+
+ ;; We receive child removed events for any QObject, whether
+ ;; it was constructed by Smoke or not. Only take ownership of
+ ;; objects that have been constructed by Smoke.
+ (when (smoke::has-pointer-p (smoke::pointer (cxx:child event)))
+ (assert receiver)
+ (smoke::take-ownership (cxx:child event) receiver)))))
+ nil)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (cffi:defcfun cl-smoke-register-event-notify :boolean
+ (event-notify :pointer)))
+
+(defun register-event-notify ()
+ (let ((ret (cl-smoke-register-event-notify (cffi:callback event-notify))))
+ (unless ret
+ (error "Registering event-notify callback failed."))))
+
+(defun check-child-parent-ownership ()
+ (loop for parent being the hash-values of smoke::*object-map* do
+ (loop for child in (smoke::owned-objects parent) do
+ (when (typep child 'qt:object)
+ (assert (eql (cxx:parent child) parent)
+ (child parent)
+ "cl-smoke thinks ~A has the parent ~A, but ~A is its parent."
+ child parent (cxx:parent child))))))
+
+(eval-startup ()
+ (register-event-notify))
diff -rN -u old-qt.core/src/operator.lisp new-qt.core/src/operator.lisp
--- old-qt.core/src/operator.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/operator.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,95 @@
+(in-package :cl-smoke.qt.core)
+
+(defun cxx:= (object &rest more-objects)
+ (if (null more-objects)
+ t
+ (every #'(lambda (o)
+ ;; Consider Class::operator== and operator==
+ ;; FIXME integrate this in the overload resolution
+ (if (typep object 'smoke-standard-object)
+ (handler-case (qt:operator== object o)
+ (no-applicable-cxx-method ()
+ (cxx:operator== object o)))
+ (qt:operator== object o)))
+ more-objects)))
+
+(defun cxx:/= (object &rest more-objects)
+ (if (null more-objects)
+ t
+ (some #'(lambda (o)
+ (qt:operator!= object o))
+ more-objects)))
+
+(defun ordered-p (relation list)
+ "Returns true when LIST is ordered according to RELATION."
+ (if (or (null list) (null (rest list)))
+ t
+ (and (funcall relation (first list)
+ (second list))
+ (ordered-p relation (rest list)))))
+
+(defmacro define-cxx-relation (relation)
+ `(defun ,(intern (symbol-name relation) :cxx) (object &rest more-objects)
+ (ordered-p (symbol-function (quote ,(intern (format nil "OPERATOR~A"
+ relation)
+ :qt)))
+ (cons object more-objects))))
+
+(defmacro define-cxx-relations (&rest relations)
+ `(progn
+ ,@(mapcar #'(lambda (r) `(define-cxx-relation ,r)) relations)))
+
+(define-cxx-relations < <= >= >)
+
+
+(defun cxx:incf (object &optional (delta 1))
+ (cxx:operator+= object delta))
+
+(defun cxx:decf (object &optional (delta 1))
+ (cxx:operator-= object delta))
+
+(defun cxx:+ (&rest args)
+ (if (null args)
+ 0
+ (reduce #'qt:operator+ args)))
+
+(defun cxx:- (object &rest subtrahends)
+ (if (null subtrahends)
+ (cxx:operator- object)
+ (reduce #'qt:operator- (cons object subtrahends))))
+
+(defun cxx:* (&rest args)
+ (if (null args)
+ 1
+ (reduce #'qt:operator- args)))
+
+(defun cxx:/ (object &rest denominators)
+ (if (null denominators)
+ (qt:operator/ 1 object)
+ (qt:operator/ object (apply #'cxx:+ denominators))))
+
+(defun cxx:1+ (object)
+ (qt:operator+ object 1))
+
+(defun cxx:1- (object)
+ (qt:operator- object 1))
+
+(defun cxx:aref (object index)
+ "Returns the element of OBJECT at position INDEX."
+ (declare ((integer 0) index))
+ (assert (< index (cxx:size object))
+ (index)
+ "Index ~A for ~A requested, but the length is ~A"
+ index object (cxx:size object))
+ (cxx:at object index))
+
+
+(defun (setf cxx:aref) (new-value object index)
+ (declare ((integer 0) index))
+ (assert (< index (cxx:size object))
+ (index)
+ "Index ~A for ~A requested, but the length is ~A"
+ index object (cxx:size object))
+ (cxx:operator= (cxx:operator[] object index)
+ new-value)
+ new-value)
diff -rN -u old-qt.core/src/ownership.lisp new-qt.core/src/ownership.lisp
--- old-qt.core/src/ownership.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/ownership.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1 @@
+(in-package :cl-smoke.qt.core)
diff -rN -u old-qt.core/src/package.lisp new-qt.core/src/package.lisp
--- old-qt.core/src/package.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/package.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,57 @@
+(defpackage :cl-smoke.qt.core
+ (:use :cl :smoke :cffi :bordeaux-threads :cxx-support :alexandria)
+ (:export #:define-qvector-translations
+ #:with-application
+ #:delete-app
+ #:ensure-app
+ #:kill-app))
+
+(defpackage :cl-smoke.qt
+ (:use) ;; do not use :cl to prevent collision with TIME and CHAR
+ (:nicknames :qt)
+ (:export #:app
+ #:app-p
+ #:exec
+ #:*exec-p*
+ #:with-app
+ #:with-core-app
+
+ #:with-painter
+ #:single-shot
+ #:do-delayed-initialize
+
+ #:tr
+ #:with-translator
+ #:with-libqt-translator
+
+ #:qmethod
+ #:qsignal
+ #:qslot
+
+ #:property
+ #:property-p
+ #:remove-property
+ #:properties
+ #:class-properties
+ #:class-direct-properties
+
+ #:make-char
+ #:from-char
+
+ #:from-variant
+ #:make-variant
+ #:make-lisp-variant
+ #:value
+ #:variant-boundp
+
+ #:search-file
+
+ #:connect
+ #:disconnect
+ #:disconnect-all
+ #:get-slot
+ #:get-signal
+ #:make-slot
+ #:make-signal
+ #:sender))
+
diff -rN -u old-qt.core/src/properties.lisp new-qt.core/src/properties.lisp
--- old-qt.core/src/properties.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/properties.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,97 @@
+(in-package :cl-smoke.qt.core)
+
+(defun reverse-lispify (symbol)
+ "Converts the name of symbol to C++ style."
+ (if (eq (symbol-package symbol)
+ (find-package :keyword))
+ (smoke::lisp-to-cxx (symbol-name symbol))
+ (concatenate 'string
+ (package-name (symbol-package symbol))
+ "::"
+ (symbol-name symbol))))
+
+(defun property-package (name)
+ (let ((package-end (search "::" name)))
+ (if package-end
+ (values
+ (find-package (intern (subseq name 0 package-end) :keyword))
+ (+ 2 package-end))
+ (values (find-package :keyword) 0))))
+
+(defun lispify-property-name (name)
+ (multiple-value-bind (package name-start)
+ (property-package name)
+ (if (= 0 name-start)
+ (smoke::lispify name package)
+ (intern (subseq name name-start) package))))
+
+(defun property-name (name)
+ "The property name is a string or a to camelCase converted symbol."
+ (typecase name
+ (string name)
+ (symbol (reverse-lispify name))))
+
+(defun qt:property (object name)
+ "Returns the property NAME of OBJECT."
+ (declare (type qt:object object)
+ (type (or string symbol) name))
+ (assert (qt:property-p object name)
+ (object name)
+ "~A has no property ~A." object name)
+ (qt:from-variant (cxx:property object (property-name name))))
+
+(defun (setf qt:property) (new-value object name)
+ (declare (type qt:object object)
+ (type (or string symbol) name))
+ (cxx:set-property object (property-name name)
+ (make-instance 'qt:variant :arg0 new-value))
+ new-value)
+
+(defun qt:remove-property (object name)
+ "Removes the property NAME from OBJECT."
+ (declare (type qt:object object)
+ (type (or string symbol) name))
+ (setf (qt:property object name) (qt:make-variant)))
+
+(defun qt:property-p (object name)
+ "Returns T when NAME is a property of OBJECT and NIL otherwise."
+ (declare (type qt:object object)
+ (type (or string symbol) name))
+ (qt:variant-boundp (cxx:property object (property-name name))))
+
+(defun meta-object-properties (meta-object &optional (all t))
+ "Returns a list of the properties of META-OBJECT."
+ (loop for index from (if all 0 (cxx:property-offset meta-object))
+ below (cxx:property-count meta-object)
+ collect (lispify-property-name (cxx:name (cxx:property meta-object index)))))
+
+(defun sort-symbols (symbols)
+ (sort symbols
+ #'(lambda (a b)
+ (string<= (write-to-string a) (write-to-string b)))))
+
+(defgeneric qt:class-properties (class)
+ (:documentation "Returns a list of the properties of CLASS.")
+ (:method ((class class))
+ (sort-symbols
+ (meta-object-properties (cxx:static-meta-object class))))
+ (:method ((symbol symbol))
+ (qt:class-properties (find-class symbol))))
+
+(defgeneric qt:class-direct-properties (class)
+ (:documentation "Returns a list of the properties of CLASS.")
+ (:method ((class class))
+ (meta-object-properties (cxx:static-meta-object class) nil))
+ (:method ((symbol symbol))
+ (qt:class-direct-properties (find-class symbol))))
+
+(defun dynamic-properties (object)
+ (map 'list (compose #'lispify-property-name #'cxx:data)
+ (cxx:dynamic-property-names object)))
+
+(defun qt:properties (object)
+ "Returns a list of the properties of OBJECT."
+ (declare (type qt:object object))
+ (sort-symbols
+ (nconc (dynamic-properties object)
+ (meta-object-properties (cxx:meta-object object)))))
diff -rN -u old-qt.core/src/qstring.lisp new-qt.core/src/qstring.lisp
--- old-qt.core/src/qstring.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/qstring.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,57 @@
+(in-package :cl-smoke.qt.core)
+
+(defcfun cl-smoke-string-to-qstring :pointer
+ (data :string)
+ (length :int))
+
+(defcfun cl-smoke-free-qstring :void
+ (string :pointer))
+
+(defcfun cl-smoke-qstring-to-byte-array :pointer
+ (qstring :pointer))
+
+;;; make sure, that you have configured slime correctly.
+;;; e.g.:
+;;; (string #\U9999) crashed slime for me. Adding
+;;; (set-language-environment "UTF-8")
+;;; (setq slime-net-coding-system 'utf-8-unix)
+;;; to .emacs helps.
+;;; Use emacs 23 for better unicode support.
+(smoke:eval-startup (:compile-toplevel :execute)
+ (qt:text-codec.set-codec-for-cstrings
+ (qt:text-codec.codec-for-name (string *default-foreign-encoding*)))
+ (qt:text-codec.set-codec-for-locale
+ (qt:text-codec.codec-for-name (string *default-foreign-encoding*))))
+
+(smoke:eval-startup (:compile-toplevel :execute)
+ (let ((method (smoke::make-smoke-method-from-name (find-class 'qt:byte-array)
+ "constData")))
+ (defmethod cxx:const-data ((array qt:byte-array))
+ (values ;; Discharge second return value (length of string)
+ (foreign-string-to-lisp (smoke::pointer-call method
+ (smoke::pointer array))
+ :count (cxx:size array))))))
+
+(defun from-qstring (qstring)
+ (cxx:const-data (make-instance 'qt:byte-array
+ :pointer (cl-smoke-qstring-to-byte-array qstring))))
+
+(define-to-lisp-translation ("QString" "const QString&")
+ from-qstring cl-smoke-free-qstring)
+
+(defun coerce-qstring (string)
+ (make-cleanup-pointer
+ (with-foreign-string ((data length) string :null-terminated-p nil)
+ (cl-smoke-string-to-qstring data length))
+ #'cl-smoke-free-qstring))
+
+(define-from-lisp-translation ("const QString&" "QString") string
+ coerce-qstring)
+
+(defmethod print-object ((object qt:byte-array) stream)
+ (if (null-pointer-p (pointer object))
+ (call-next-method)
+ (print-unreadable-object (object stream :type t :identity t)
+ (when (smoke::const-p object)
+ (princ "CONST " stream))
+ (prin1 (cxx:const-data object) stream))))
diff -rN -u old-qt.core/src/qt.core.lisp new-qt.core/src/qt.core.lisp
--- old-qt.core/src/qt.core.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/qt.core.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,39 @@
+;;; Copyright (C) 2009, 2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
+;;;
+;;; This program is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+;;;
+;;; As a special exception, the copyright holders of this library give you
+;;; permission to link this library with independent modules to produce an
+;;; executable, regardless of the license terms of these independent
+;;; modules, and to copy and distribute the resulting executable under
+;;; terms of your choice, provided that you also meet, for each linked
+;;; independent module, the terms and conditions of the license of that
+;;; module. An independent module is a module which is not derived from or
+;;; based on this library. If you modify this library, you may extend this
+;;; exception to your version of the library, but you are not obligated to
+;;; do so. If you do not wish to do so, delete this exception statement
+;;; from your version.
+
+(in-package :cl-smoke.qt.core)
+
+(eval-when (:load-toplevel :compile-toplevel :execute)
+ (define-smoke-module :cl-smoke.qt libsmokeqtcore
+ (*qt-core-smoke* "qtcore_Smoke")
+ (init-qt-smoke "init_qtcore_Smoke"))
+
+ (define-foreign-library libclsmokeqtcore
+ (:darwin "libclsmokeqtcore.dylib")
+ (:unix "libclsmokeqtcore.so")
+ (t (:default "libclsmokeqtcore")))
+ (use-foreign-library libclsmokeqtcore))
diff -rN -u old-qt.core/src/signal-slot/connect.lisp new-qt.core/src/signal-slot/connect.lisp
--- old-qt.core/src/signal-slot/connect.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/signal-slot/connect.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,202 @@
+(in-package :cl-smoke.qt.core)
+
+(defgeneric qt:connect (qsignal slot &optional type)
+ (:documentation "Connects a signal to a slot."))
+
+(defgeneric qt:disconnect (qsignal slot)
+ (:documentation "Disconnects a connection."))
+
+(defgeneric qt:disconnect-all (qsignal)
+ (:documentation "Disconnects all connections of QSIGNAL."))
+
+(defun check-argument-types (signal-arguments slot-arguments)
+ (assert (= (length signal-arguments) (length slot-arguments)))
+ (loop for signal-arg in signal-arguments
+ for slot-arg in slot-arguments do
+ (if (typep signal-arg 'smoke-type)
+ (assert (smoke-type= signal-arg slot-arg))
+ (assert (subtypep signal-arg slot-arg)))))
+
+;;FIXME check argument-types
+(defmethod qt:connect ((qsignal qsignal) (qslot qslot) &optional type)
+ (assert (or (slot-boundp (signal-object qsignal) 'argument-types)
+ (slot-boundp qslot 'arguments))
+ ((slot-value (signal-object qsignal) 'argument-types)
+ (slot-value qslot 'arguments))
+ "Argument types must be specified for at least on of
+~A and ~A." qsignal qslot)
+ (when (not (slot-boundp (signal-object qsignal) 'argument-types))
+ (setf (argument-types (signal-object qsignal))
+ (arguments qslot)))
+ (when (not (slot-boundp qslot 'arguments))
+ (setf (slot-value qslot 'arguments)
+ (argument-types (signal-object qsignal))))
+ (check-argument-types (argument-types (signal-object qsignal))
+ (arguments qslot))
+ (unless (connect-id (signal-object qsignal) (id (signal-object qsignal))
+ qslot (id qslot)
+ type
+ (types (arguments qslot)))
+ (cerror "Failed to connect ~S to ~S." qsignal qslot)))
+
+(defmethod qt:connect ((sender qsignal) (function function) &optional type)
+ (let ((slot (make-instance 'qslot
+ :arg0 (signal-object sender)
+ :argument-types (argument-types (signal-object sender))
+ :slot-function function)))
+
+ (unless (connect-id (signal-object sender) (id (signal-object sender))
+ slot (id slot)
+ type
+ (types (argument-types (signal-object sender))))
+ (cerror "Failed to connect the function ~S to the signal ~S."
+ function sender))))
+
+(defclass qt-signal-slot-name ()
+ ((name :initarg :name
+ :reader name)))
+
+(defclass qt-signal (qt-signal-slot-name)
+ ((sender :initarg :sender
+ :reader qsender))
+ (:documentation "Qt C++ signal."))
+
+(defclass qt-slot (qt-signal-slot-name)
+ ((receiver :initarg :receiver
+ :reader receiver))
+ (:documentation "Qt C++ slot."))
+
+(defmethod print-object ((qt-signal qt-signal) stream)
+ (print-unreadable-object (qt-signal stream :type t :identity t)
+ (when (slot-boundp qt-signal 'sender)
+ (princ (qsender qt-signal) stream))
+ (princ " " stream)
+ (when (slot-boundp qt-signal 'name)
+ (princ (name qt-signal) stream))))
+
+(defgeneric qt:get-slot (receiver name)
+ (:documentation "Returns the slot of RECEIVER with NAME.")
+ (:method (receiver name)
+ (make-instance 'qt-slot :receiver receiver :name name))
+ (:method (receiver (function function))
+ "Returns a slot for RECEIVER that calls function
+with RECEIVER as the first argument."
+ (make-instance 'qslot
+ :arg0 receiver
+ :slot-function #'(lambda (&rest args)
+ (apply function (cxx:parent *this*)
+ args)))))
+
+(define-compiler-macro qt:get-slot (&whole form receiver name)
+ "Normalize the slot name."
+ (if (stringp name)
+ (let ((normalized-name (cxx:data
+ (qt:meta-object.normalized-signature name))))
+ (if (string= name normalized-name) ;; Avoid infinite recursion
+ form
+ `(qt:get-slot ,receiver ,normalized-name)))
+ form))
+
+(defun qt:get-signal (sender name)
+ "Returns the signal NAME of SENDER."
+ (make-instance 'qt-signal :sender sender :name name))
+
+(define-compiler-macro qt:get-signal (&whole form sender name)
+ "Normalize the signal name."
+ (if (stringp name)
+ (let ((normalized-name (cxx:data
+ (qt:meta-object.normalized-signature name))))
+ (if (string= name normalized-name) ;; Avoid infinite recursion
+ form
+ `(qt:get-signal ,sender ,normalized-name)))
+ form))
+
+(defmethod qt:connect ((qt-signal qt-signal) (qt-slot qt-slot) &optional type)
+ (unless (qt:object.connect (qsender qt-signal) (qt:qsignal (name qt-signal))
+ (receiver qt-slot) (qt:qslot (name qt-slot))
+ (or type qt:+auto-connection+))
+ (cerror "Ignore"
+ "Failed to connect ~A ~A to ~A ~A."
+ (qsender qt-signal) (name qt-signal)
+ (receiver qt-slot) (name qt-slot))))
+
+(defmethod qt:disconnect ((qt-signal qt-signal) (qt-slot qt-slot))
+ (unless (qt:object.disconnect (qsender qt-signal) (qt:qsignal (name qt-signal))
+ (receiver qt-slot) (qt:qslot (name qt-slot)))
+ (cerror "Ignore"
+ "Failed to disconnect ~A ~A from ~A ~A."
+ (receiver qt-slot) (name qt-slot)
+ (qsender qt-signal) (name qt-signal))))
+
+(defmethod qt:disconnect-all ((sender qt:object))
+ (unless (qt:object.disconnect sender 0 0 0)
+ (cerror "Ignore"
+ "Failed to disconnect everything connected to ~A."
+ sender)))
+
+
+(defmethod qt:connect ((qt-signal qt-signal) (function function) &optional type)
+ (let* ((signal-id (find-signal-id (qsender qt-signal) (name qt-signal)))
+ (slot (make-instance 'qslot
+ :arg0 (qsender qt-signal)
+ :slot-function function
+ :argument-types
+ (method-arguments-type (qsender qt-signal)
+ signal-id))))
+ ;; Ensure that the slot is not gc'ed as long as the QT-SIGNAL
+ ;; exists.
+ ;;
+ ;; FIXME: remove on disconnect.
+ ;; This no not critical because the slot
+ ;; object is not accessible to the user,
+ ;; who thus can not connect it to other
+ ;; signals.
+ (if (connect-id (qsender qt-signal) signal-id
+ slot (id slot)
+ type (types (arguments slot)))
+ (cxx:connect-notify (qsender qt-signal)
+ (name qt-signal))
+ (cerror "Ignore" "Failed to connect the signal ~S of ~S to the function ~S."
+ (name qt-signal) (qsender qt-signal) function))))
+
+(defmethod qt:connect ((qt-signal qt-signal) (slot qslot) &optional type)
+ (let ((signal-id (find-signal-id (qsender qt-signal) (name qt-signal))))
+ (if (slot-boundp slot 'arguments)
+ (check-argument-types (method-arguments-type (qsender qt-signal)
+ signal-id)
+ (arguments slot))
+ (setf (slot-value slot 'arguments)
+ (method-arguments-type (qsender qt-signal) signal-id)))
+ (if (connect-id (qsender qt-signal) signal-id
+ slot (id slot)
+ type (types (arguments slot)))
+ (cxx:connect-notify (qsender qt-signal)
+ (name qt-signal))
+ (cerror "Ignore" "Failed to connect the signal ~S of ~S to the slot ~S."
+ (name qt-signal) (qsender qt-signal) slot))))
+
+(defmethod qt:connect ((qsignal qsignal) (slot qt-slot) &optional type)
+ (let ((slot-id (find-slot-id (receiver slot) (name slot))))
+ (if (slot-boundp (signal-object qsignal) 'argument-types)
+ (check-argument-types (argument-types (signal-object slot))
+ (method-arguments-type (receiver slot)
+ slot-id))
+ (setf (argument-types (signal-object qsignal))
+ (method-arguments-type (receiver slot) slot-id)))
+ (unless (connect-id (signal-object qsignal) (id (signal-object qsignal))
+ (receiver slot) slot-id
+ type
+ (types (argument-types (signal-object qsignal))))
+ (cerror "Failed to connect ~S to ~S." qsignal slot))))
+
+
+(defun connect-id (sender signal-id receiver slot-id type types)
+ (qt:meta-object.connect sender signal-id
+ receiver slot-id
+ (if (null type)
+ qt:+auto-connection+
+ type)
+ types))
+
+(defun disconnect-id (sender signal-id receiver slot-id)
+ (qt:meta-object.disconnect sender signal-id receiver slot-id))
diff -rN -u old-qt.core/src/signal-slot/signal-slot.lisp new-qt.core/src/signal-slot/signal-slot.lisp
--- old-qt.core/src/signal-slot/signal-slot.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/signal-slot/signal-slot.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,35 @@
+(in-package :cl-smoke.qt.core)
+
+
+(defclass funcallable-smoke-class (closer-mop:funcallable-standard-class
+ cxx:class)
+ ())
+
+(defmethod closer-mop:validate-superclass ((class funcallable-smoke-class)
+ (superclass closer-mop:funcallable-standard-class))
+ t)
+
+(defgeneric id (method))
+
+(defun munged-name-p (name)
+ "Returns true when NAME is a METHOD, SLOT or SIGNAL."
+ (and (> (length name) 0)
+ (case (aref name 0)
+ ((#\0 #\1 #\2) t)
+ (t nil))))
+
+(defun qt:qmethod (name)
+ "Equivalent of the METHOD(a) CPP macro."
+ (assert (not (munged-name-p name)))
+ (format nil "0~A" name))
+
+(defun qt:qslot (name)
+ "Equivalent of the SLOT(a) CPP macro."
+ (assert (not (munged-name-p name)))
+ (format nil "1~A" name))
+
+(defun qt:qsignal (name)
+ "Equivalent of the SIGNAL(a) CPP macro."
+ (assert (not (munged-name-p name)))
+ (format nil "2~A" name))
+
diff -rN -u old-qt.core/src/signal-slot/signal.lisp new-qt.core/src/signal-slot/signal.lisp
--- old-qt.core/src/signal-slot/signal.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/signal-slot/signal.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,123 @@
+(in-package :cl-smoke.qt.core)
+
+(defclass qsignal-mixin ()
+ ((signal-object :accessor signal-object
+ :initarg :signal-object
+ :initform (make-instance 'signal-object)))
+ (:documentation "in SB-PCL you can not have both
+FUNCALLABLE-STANDARD-CLASS and STANDARD-CLASS,
+thus QSIGNAL is split in three classes.
+
+See:
+ http://www.sbcl.org/manual/Metaobject-Protocol.html#index-validate_002dsuperclass-164"))
+
+(defclass signal-object (qt:object)
+ ((argument-types :accessor argument-types
+ :initarg :argument-types
+ :documentation "List of the argument types"))
+ (:documentation "Qt Signal object.")
+ (:metaclass cxx:class))
+
+#+cmu (defmethod closer-mop:validate-superclass ((class closer-mop:funcallable-standard-class)
+ (superclass standard-class))
+ t)
+
+(defclass qsignal (closer-mop:funcallable-standard-object qsignal-mixin)
+ ()
+ (:metaclass closer-mop:funcallable-standard-class)
+ (:documentation "A funcallable Qt signal.
+The argument types can be supplied by the :METHOD-TYPES initarg.
+Calling an instance emits the signal."))
+
+(defun qt:make-signal (&rest argument-types)
+ "Returns a funcallable signal. When ARGUMENT-TYPES are not
+specified, they are determined when the first connection is made."
+ (if argument-types
+ (make-instance 'qsignal :argument-types argument-types)
+ (make-instance 'qsignal)))
+
+(defmethod id ((qsignal signal-object))
+ (cxx:method-count (cxx:meta-object qsignal)))
+
+(defmethod initialize-instance :after ((object qsignal) &rest initargs
+ &key (argument-types nil arg-types-p)
+ &allow-other-keys)
+ (declare (ignore initargs))
+ (when arg-types-p
+ (setf (argument-types (signal-object object))
+ argument-types))
+ (closer-mop:set-funcallable-instance-function object
+ #'(lambda (&rest args)
+ (apply #'emit (signal-object object) args))))
+
+(defun find-slot-id (receiver slot)
+ "Returns the ID of RECEIVER from SLOT."
+ ;; For efficiency assume that SLOT is normalized and fallback to
+ ;; normalizing when not. (Just like Qt does.)
+ (let ((id (cxx:index-of-slot (cxx:meta-object receiver)
+ slot)))
+ (when (< id 0)
+ (setf id (cxx:index-of-slot (cxx:meta-object receiver)
+ (qt:meta-object.normalized-signature slot))))
+ (when (< id 0)
+ (error "No slot ~S for class ~S.
+The valid slots are: ~{~<~%~T~0,75:;~A ~>~}"
+ slot (class-of receiver)
+ (class-slots (class-of receiver))))
+ id))
+
+
+(defun make-lisp-object (object)
+ (make-cleanup-pointer (make-cxx-lisp-object object)
+ #'cl-smoke-free-lisp-object))
+
+
+(defun convert-arguments (arguments types)
+ "Returns a list of ARGUMENTS converted to TYPES."
+ (mapcar #'(lambda (argument type)
+ (if (typep type 'smoke-type)
+ (smoke:convert-argument argument type)
+ (progn (assert (typep argument type)
+ ()
+ "The argument ~S is not of type ~S."
+ argument type)
+ (make-lisp-object argument))))
+ arguments types))
+
+(defun emit (qsignal &rest arguments)
+ "Emits the signal QSIGNAL."
+ (activate qsignal (id qsignal) (argument-types qsignal) arguments))
+
+(defun activate (object id types arguments)
+ ;;; The first element of args would be used for the return value by
+ ;;; QMetaObject::invokeMethod(), but for signal-slot connection it is
+ ;;; ignored.
+ (smoke::with-stack (stack (convert-arguments arguments types)
+ types)
+ (with-foreign-object (args :pointer (1+ (length arguments)))
+ (loop for i from 1 to (smoke:size stack)
+ for type in types
+ do
+ (setf (mem-aref args :pointer i)
+ (if (or (not (typep type (find-class 'smoke-type)))
+ (= 0 (type-id type))
+ (= 13 (type-id type)))
+ (foreign-slot-value
+ (mem-aref (smoke::call-stack-pointer stack)
+ 'smoke::smoke-stack-item
+ i)
+ 'smoke::smoke-stack-item 'smoke::voidp)
+ (foreign-slot-pointer
+ (mem-aref (smoke::call-stack-pointer stack)
+ 'smoke::smoke-stack-item
+ i)
+ 'smoke::smoke-stack-item 'smoke::voidp))))
+ (setf (mem-aref args :pointer 0)
+ (null-pointer))
+ (qt:meta-object.activate object id args))))
+
+(defmethod qt:disconnect-all ((qsignal qsignal))
+ (unless (disconnect-id (signal-object qsignal)
+ (id (signal-object qsignal))
+ 0
+ 0)))
diff -rN -u old-qt.core/src/signal-slot/slot.lisp new-qt.core/src/signal-slot/slot.lisp
--- old-qt.core/src/signal-slot/slot.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/signal-slot/slot.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,63 @@
+(in-package :cl-smoke.qt.core)
+
+(defclass qslot (qt:object)
+ ((arguments :reader arguments :initarg :argument-types
+ :documentation "List of the argument types for the slot.")
+ (function :reader slot-function :initarg :slot-function
+ :initform (error "no slot function specified")
+ :documentation "The function called when the slot is invoked."))
+ (:metaclass cxx:class)
+ (:documentation "A Qt slot that calls its associated function"))
+
+(defun qt:make-slot (function &optional (arguments nil arguments-p))
+ "Returns a slot that calls FUNCTION when it receives a signal."
+ (if arguments-p
+ (make-instance 'qslot
+ :slot-function function
+ :argument-types arguments)
+ (make-instance 'qslot
+ :slot-function function)))
+
+(defmethod id ((slot qslot))
+ (cxx:method-count (cxx:meta-object slot)))
+
+(defparameter *sender* nil "The sender of the signal.")
+(defparameter *this* nil "The slot that is invoked.")
+(defmacro qt:sender ()
+ "Returns the sender that invoked the slot."
+ `*sender*)
+
+(defmethod cxx:qt-metacall ((slot qslot) call id arguments)
+ "Invoke the slots function when it is called. The return value
+of the invoked slot function is ignored."
+ (declare (ignore id))
+ (let ((id (call-next-method)))
+ (if (< id 0)
+ id
+ (if (enum= call qt:meta-object.+invoke-meta-method+)
+ (progn
+ (ccase id
+ (0 (let ((*sender* (cxx:sender slot))
+ (*this* slot))
+ (with-simple-restart
+ (continue "Skip the function ~A of slot ~A."
+ (slot-function slot) slot)
+ (apply (slot-function slot)
+ (arguments-to-lisp arguments (arguments slot)))))))
+ (1- id))
+ id))))
+
+(defun find-signal-id (sender signal)
+ "Returns the ID of SIGNAL from SENDER."
+ ;; For efficiency assume that SIGNAL is normalized and fallback to
+ ;; normalizing when not. (Just like Qt does.)
+ (let ((id (cxx:index-of-signal (cxx:meta-object sender)
+ signal)))
+ (when (< id 0)
+ (setf id (cxx:index-of-signal (cxx:meta-object sender)
+ (qt:meta-object.normalized-signature signal))))
+ (when (< id 0)
+ (error "No signal ~S for class ~S."
+ signal (class-of sender)))
+ id))
+
diff -rN -u old-qt.core/src/signal-slot/translate.lisp new-qt.core/src/signal-slot/translate.lisp
--- old-qt.core/src/signal-slot/translate.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/signal-slot/translate.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,118 @@
+(in-package :cl-smoke.qt.core)
+
+(defun find-type (smoke-module name &optional start end)
+ (let ((type (make-smoke-type smoke-module (subseq name start end))))
+ (assert (not (zerop (id type)))
+ ()
+ "No type named ~S found in ~A."
+ (subseq name start end) smoke-module)
+ type))
+
+(defun method-arguments-type (object index)
+ "Returns a type name list for the arguments of method INDEX of OBJECTs metaobject."
+ (let* ((metaobject (cxx:meta-object object))
+ (signature (cxx:signature (cxx:method metaobject index)))
+ (arguments (subseq signature (1+ (position #\( signature))
+ (position #\) signature :from-end t)))
+ (argument-types ())
+ (last-pos (length arguments))
+ (smoke-module (smoke (class-of object))))
+ (loop as pos = (position #\, arguments :from-end t :end last-pos)
+ while pos
+ do
+ (push (find-type smoke-module arguments (1+ pos) last-pos) argument-types)
+ (setf last-pos pos))
+ (when (> last-pos 0)
+ (push (find-type smoke-module arguments 0 last-pos) argument-types))))
+
+
+(defun arguments-to-lisp2 (argument types values)
+ (if (null types)
+ values
+ (arguments-to-lisp2 (inc-pointer argument (foreign-type-size :pointer))
+ (rest types)
+ (nconc values
+ (list
+ (typecase (first types)
+ (smoke-type
+ (pointer-to-lisp (mem-ref argument :pointer)
+ (first types)))
+
+ (t
+ (translate-cxx-lisp-object
+ (mem-ref argument :pointer)))))))))
+
+(defun disown-object (object)
+ (tg:cancel-finalization object)
+ (unless (virtual-destructor-p (class-of object))
+ (remove-object (pointer object)))
+ object)
+
+(defun pointer-to-lisp (pointer type)
+ "Returns the lisp value or object at POINTER of type TYPE."
+ (if (class-p type)
+ (if (pointer-p type)
+ (object-to-lisp (mem-ref pointer :pointer) type)
+ ;; By-value means that the object at POINTER is allocated by
+ ;; the C++ signal code and has dynamic extend in the
+ ;; slot. The C++ signal code frees the object when the slot
+ ;; returns.
+ (disown-object (object-to-lisp pointer type)))
+ (ecase (type-id type)
+ (0 (if-let ((translation (gethash (name type) *to-lisp-translations*)))
+ ;; Do not free stack allocated stuff (e.g.: QString); that is the callers
+ ;; responisbility.
+ (funcall (car translation) pointer)
+ (error "Do not know how to convert the type ~A to Lisp." type)))
+ (1 (mem-ref pointer 'cxx-bool))
+ (2 (code-char (mem-ref pointer :char)))
+ (3 (code-char (mem-ref pointer :unsigned-char)))
+ (4 (code-char (mem-ref pointer :short)))
+ (5 (code-char (mem-ref pointer :unsigned-short)))
+ (6 (mem-ref pointer :int))
+ (7 (mem-ref pointer :unsigned-int))
+ (8 (mem-ref pointer :long))
+ (9 (mem-ref pointer :unsigned-long))
+ (10 (mem-ref pointer :float))
+ (11 (mem-ref pointer :double))
+ (12 (make-instance 'enum
+ :value (mem-ref pointer :long)
+ :type type)))))
+
+
+(defun arguments-to-lisp (arguments types)
+ "Returns ARGUMENTS for a slot invocation as lisp objects."
+ (arguments-to-lisp2
+ (inc-pointer arguments ;; index 0 is for the return value
+ (foreign-type-size :pointer))
+ types ()))
+
+
+(defun get-type (smoke-type)
+ "Returns the QMetaType ID for SMOKE-TYPE."
+ (typecase smoke-type
+ (smoke-standard-object
+ (if (pointer-p smoke-type)
+ (error "Not implemented: pointer type.") ;;qmetatype.+voidstar+
+ (let ((type (qt:meta-type.type (name smoke-type))))
+ (assert (/= 0 type)
+ (type)
+ "The type ~S has no QMetaType."
+ (name smoke-type))
+ type)))
+ (t
+ *cxx-lisp-object-metatype*)))
+
+
+(defun types (smoke-types)
+ "Returns a newly allocated array of QMetaType IDs of SMOKE-TYPES."
+ ;; FIXME free TYPES on error.
+ (let ((types (cffi:foreign-alloc :int :count (1+ (length smoke-types))))
+ (index 0))
+ (dolist (type smoke-types)
+ (setf (cffi:mem-aref types :int index)
+ (get-type type))
+ (incf index))
+ (setf (cffi:mem-aref types :int index)
+ 0)
+ types))
diff -rN -u old-qt.core/src/string-list.lisp new-qt.core/src/string-list.lisp
--- old-qt.core/src/string-list.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/string-list.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,49 @@
+(in-package :cl-smoke.qt.core)
+
+(defcfun cl-smoke-string-list-size :int
+ (string-list :pointer))
+
+(defcfun cl-smoke-string-list-at :pointer
+ (string-list :pointer)
+ (index :int))
+
+(defcfun cl-smoke-free-string-list :void
+ (string-list :pointer))
+
+(defcfun cl-smoke-make-string-list :pointer)
+
+(defcfun cl-smoke-string-list-append :void
+ (string-list :pointer)
+ (string :pointer)
+ (length :int))
+
+(defun from-string-list (string-list)
+ (let ((vector (make-array (cl-smoke-string-list-size string-list)
+ :initial-element ""
+ :element-type 'string)))
+ (dotimes (index (length vector) vector)
+ (setf (aref vector index)
+ (cxx:data (make-instance 'qt:byte-array
+ :pointer (cl-smoke-string-list-at
+ string-list index)))))))
+
+(define-to-lisp-translation ("QStringList" "const QStringList&")
+ from-string-list cl-smoke-free-string-list)
+
+(defun coerce-string-list (sequence)
+ (let ((string-list (cl-smoke-make-string-list)))
+ (map nil
+ #'(lambda (string)
+ (with-foreign-string ((data length) string :null-terminated-p nil)
+ (cl-smoke-string-list-append string-list data length)))
+ sequence)
+ (make-cleanup-pointer
+ string-list #'cl-smoke-free-string-list)))
+
+(defun string-list-p (sequence)
+ (every #'stringp sequence))
+
+(define-from-lisp-translation "const QStringList&"
+ (and (vector string)
+ (satisfies string-list-p))
+ coerce-string-list)
diff -rN -u old-qt.core/src/timer.lisp new-qt.core/src/timer.lisp
--- old-qt.core/src/timer.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/timer.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,31 @@
+(in-package :cl-smoke.qt.core)
+
+(defclass single-shot-timer (qt:object)
+ ((function :initarg :function
+ :type function)
+ (timer-id :type integer))
+ (:metaclass cxx:class))
+
+(defvar *single-shot-timers* nil "Pending timers.")
+
+(defun single-shot (function &optional (timeout 0))
+ "Run FUNCTION after TIMEOUT seconds, or as soon as all window events
+have been processed when TIMEOUT is 0. Equivalent to QTimer::singleShot,
+but calls a function instead of a slot."
+ (let ((timer (make-instance 'single-shot-timer
+ :function function)))
+ (setf (slot-value timer 'timer-id)
+ (cxx:start-timer timer (floor timeout 100)))
+ (push timer *single-shot-timers*)))
+
+(defmacro qt:do-delayed-initialize (&body body)
+ "Run body when the event loop starts.
+
+http://techbase.kde.org/Development/Tutorials/Common_Programming_Mistakes#Delayed_Initialization"
+ `(single-shot #'(lambda () ,@body)))
+
+(defmethod cxx:timer-event ((timer single-shot-timer) event)
+ (declare (ignore event))
+ (cxx:kill-timer timer (slot-value timer 'timer-id))
+ (funcall (slot-value timer 'function))
+ (remove timer *single-shot-timers*))
diff -rN -u old-qt.core/src/variant.lisp new-qt.core/src/variant.lisp
--- old-qt.core/src/variant.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/variant.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,139 @@
+(in-package :cl-smoke.qt.core)
+
+(defmethod print-object ((variant qt:variant) stream)
+ "Print the type and value of the variant."
+ (if (or (not (slot-boundp variant 'pointer))
+ (null-pointer-p (pointer variant)))
+ (call-next-method)
+ (print-unreadable-object (variant stream :type t :identity t)
+ (format stream "~A~@[ ~S~]"
+ (cxx:type-name variant)
+ (handler-case (qt:from-variant variant)
+ (error () nil))))))
+
+(defun qt:make-variant (&optional (value nil value-p))
+ "Returns a new VARIANT containing a C++ version of VALUE
+or an empty variant when VALUE is not specified."
+ (if value-p
+ (make-instance 'qt:variant :arg0 value)
+ (make-instance 'qt:variant)))
+
+(defun qt:make-char (character)
+ "Returns a char for a lisp CHARACTER."
+ (let ((octets (babel:string-to-octets (string character))))
+ (case (length octets)
+ (1 (make-instance 'qt:char :arg0 (aref octets 0)))
+ (2 (make-instance 'qt:char :args (list (aref octets 0)
+ (aref octets 1))))
+ (t (error "qt:char requires the character ~A to be encoded
+in one or two octets, but it is using ~A."
+ character (length octets))))))
+
+(defun surrogate-p (char)
+ (or (cxx:is-high-surrogate char)
+ (cxx:is-low-surrogate char)))
+
+(defun qt:from-char (char)
+ "Returns the Lisp character represented by CHAR."
+ (assert (not (surrogate-p char))
+ (char)
+ "The char ~A is part of a surrogate.")
+ (char
+ (babel:octets-to-string (make-array 2 :element-type '(unsigned-byte 8)
+ :initial-contents
+ (list
+ (char-code (cxx:cell char))
+ (char-code (cxx:row char)))))
+ 0))
+
+(defmethod print-object ((char qt:char) stream)
+ (if (or (null-pointer-p (pointer char))
+ (surrogate-p char))
+ (call-next-method)
+ (print-unreadable-object (char stream :type t)
+ (princ (qt:from-char char) stream))))
+
+
+;; FIXME include in MAKE-VARIANT? how??
+(defun qt:make-lisp-variant (value)
+ "Returns a new VARIANT that wraps VALUE.
+
+The variant contains the actual Lisp object VALUE
+and not its C++ value like in MAKE-VARIANT."
+ (let ((object (make-cxx-lisp-object value)))
+ (unwind-protect
+ (make-instance 'qt:variant :args (list *cxx-lisp-object-metatype*
+ object))
+ (free-cxx-lisp-object object))))
+
+(defcfun cl-smoke-lisp-object-value :pointer
+ (variant :pointer))
+
+(defun qt:variant-boundp (variant)
+ "Returns true when VARIANT is valid (has a value) and false otherwise."
+ (cxx:is-valid variant))
+
+(defun copy-object-from-pointer (class pointer)
+ (make-instance class :arg0 (make-instance class :pointer pointer)))
+
+(eval-startup ()
+;; *cxx-lisp-object-metatype* can change when loading an image
+(eval '
+ (macrolet
+ ((variant-conversions ((variant) &body types)
+ (let* ((special-types '(long-long ulong-long map list hash))
+ (exclude-types
+ (append '(63) ;; ColorGroup
+ (mapcar #'(lambda (s)
+ (value
+ (symbol-value
+ (intern (format nil "VARIANT.+~A+" s)
+ :qt))))
+ special-types)))
+ (qt-types (loop for i from 1 to (value qt:variant.+user-type+)
+ when (and (qt:variant.type-to-name i)
+ ;; type-to-name returns longlong but
+ ;; should be LongLong
+ (not (member i exclude-types)))
+ collect
+ (smoke::lispify (qt:variant.type-to-name i)
+ :qt))))
+ `(ecase (cxx:user-type ,variant)
+ ,@(loop for type in (append special-types
+ (remove nil qt-types))
+ collect
+ `(,(value (symbol-value
+ (let ((*package*
+ (find-package :cl-smoke.qt)))
+ (symbolicate 'variant.+ type '+))))
+ ,(if (fboundp (intern (format nil "TO-~A" type) :cxx))
+ `(,(intern (format nil "TO-~A" type) :cxx) ,variant)
+ `(copy-object-from-pointer
+ ;; intern since these types are in
+ ;; qt.gui not qt.core
+ (intern ,(symbol-name type) :qt)
+ (cxx:const-data ,variant)))))
+ ,@(loop for type in types
+ collect
+ `(,(eval (first type))
+ ,@(rest type)))))))
+ (defun qt:from-variant (variant)
+ "Returns the value of VARIANT."
+ (variant-conversions (variant)
+ ((value qt:variant.+invalid+)
+ (cerror "Return (VALUES)" "Type of variant ~A is invalid." variant)
+ (values))
+ (*cxx-lisp-object-metatype*
+ (let* ((lisp-object (cl-smoke-lisp-object-value (pointer variant)))
+ (value))
+ (setf value (translate-cxx-lisp-object lisp-object))
+ (free-cxx-lisp-object lisp-object)
+ value)))))))
+
+(defmethod qt:value ((variant qt:variant))
+ "Returns the value of VARIANT."
+ (qt:from-variant variant))
+
+(defmethod (setf qt:value) (new-value (variant qt:variant))
+ (cxx:operator= variant (qt:make-variant new-value))
+ new-value)
diff -rN -u old-qt.core/src/vector.lisp new-qt.core/src/vector.lisp
--- old-qt.core/src/vector.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/src/vector.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,123 @@
+;; see: "Inside the Qt 4 Containers"
+;; http://doc.trolltech.com/qq/qq19-containers.html#sequentialcontainers
+
+(in-package :cl-smoke.qt.core)
+
+(defcfun cl-smoke-make-qvector :pointer)
+(defcfun cl-smoke-delete-qvector :void
+ (vector :pointer))
+
+(defbitfield qvector-data-flags
+ :sharable
+ :capacity)
+
+(defcstruct qvector-data
+ (ref :char :count #.(class-size (find-class 'qt:basic-atomic-int)))
+ (alloc :int)
+ (size :int)
+ (flags qvector-data-flags))
+
+(defcstruct qvector-type-data
+ (ref :char :count #.(class-size (find-class 'qt:basic-atomic-int)))
+ (alloc :int)
+ (size :int)
+ (flags qvector-data-flags)
+ (array :pointer))
+
+;; FIXME We assume QVector to be a POD struct, which is not
+;; neccesarily the case.
+(defcstruct qvector
+ (data (:pointer qvector-data)))
+
+(defun qvector-size (qvector)
+ (foreign-slot-value (foreign-slot-value qvector 'qvector 'data)
+ 'qvector-data 'size))
+
+(defun qvector-elt (qvector index element-type)
+ (pointer-to-lisp
+ (cffi:inc-pointer
+ (foreign-slot-pointer (foreign-slot-value qvector 'qvector 'data)
+ 'qvector-type-data 'array)
+ (* index (type-size element-type)))
+ element-type))
+
+(defun from-qvector (qvector element-type)
+ (let ((result (make-array (qvector-size qvector))))
+ (dotimes (i (length result) result)
+ (setf (elt result i)
+ (qvector-elt qvector i element-type)))))
+
+(defcfun memcpy :pointer
+ (destination :pointer)
+ (source :pointer)
+ (size :unsigned-int))
+
+(defun make-qvector (element-type elements)
+ (let* ((length (length elements))
+ (element-size (type-size element-type))
+ (data (foreign-alloc :char :count (+ (foreign-type-size 'qvector-data)
+ (* length element-size))))
+ (darray (foreign-slot-pointer data 'qvector-type-data 'array))
+ (vector (cl-smoke-make-qvector)))
+ (unless (stack-p element-type)
+ (error "FIXME: TODO"))
+ (if (class-p element-type)
+ (dotimes (i length)
+ (memcpy (inc-pointer darray (* i element-size))
+ (pointer (elt elements i))
+ element-size))
+ (dotimes (i length)
+ (setf (mem-aref darray (type-foreign-keyword element-type) i)
+ (elt elements i))))
+ (setf (mem-ref data :int) 1) ;; ref count
+ (with-foreign-slots ((ref alloc size flags)
+ data qvector-data)
+ (setf alloc length ;; allocated size
+ size length
+ flags :sharable)
+ (setf (foreign-slot-value vector 'qvector 'data)
+ data))
+ vector))
+
+(defun deref (basic-atomic-int-pointer)
+ ;; decrement and return true when the new value is non-zero
+ (cxx:deref
+ (make-instance 'qt:basic-atomic-int :pointer basic-atomic-int-pointer)))
+
+(defun free-qvector (vector)
+ (unless (null-pointer-p (foreign-slot-value vector 'qvector 'data))
+ (let ((data (foreign-slot-value vector 'qvector 'data)))
+ (unless (deref (foreign-slot-pointer data 'qvector-type-data 'ref))
+ (foreign-free data)))
+ (setf (foreign-slot-value vector 'qvector 'data)
+ (null-pointer)))
+ (cl-smoke-delete-qvector vector))
+
+(defmacro define-qvector-translations (element-type lisp-type)
+ `(progn
+ (defun ,(symbolicate 'from-vector- element-type) (elements)
+ (make-cleanup-pointer
+ (make-qvector (make-smoke-type *smoke-module* ,element-type)
+ elements)
+ #'free-qvector))
+ (defun ,(symbolicate 'vector- element-type '-p) (sequence)
+ (every #'(lambda (element)
+ (typep element ',lisp-type))
+ sequence))
+ (defun ,(symbolicate 'to-vector- element-type) (pointer)
+ (from-qvector pointer (make-smoke-type *smoke-module* ,element-type)))
+ (define-from-lisp-translation (,(format nil "QVector<~A>" element-type)
+ ;; FIXME QImage::setColorTable
+ ;; has an "const QVector<QRgb>"
+ ;; argument!
+ ,(format nil "const QVector<~A>" element-type)
+ ,(format nil "const QVector<~A>&" element-type))
+ (and vector
+ (satisfies ,(symbolicate 'vector- element-type '-p)))
+ ,(symbolicate 'from-vector- element-type))
+ (define-to-lisp-translation (,(format nil "QVector<~A>" element-type)
+ ,(format nil "const QVector<~A>&" element-type))
+ ,(symbolicate 'to-vector- element-type)
+ free-qvector)))
+
+(define-qvector-translations "double" double-float)
diff -rN -u old-qt.core/test.lisp new-qt.core/test.lisp
--- old-qt.core/test.lisp 1970-01-01 01:00:00.000000000 +0100
+++ new-qt.core/test.lisp 2014-10-30 07:34:52.000000000 +0100
@@ -0,0 +1,16 @@
+#|
+v v v v v v v
+cmake ./
+make
+*************
+cmake ./ || exit 1
+make || exit 1
+^ ^ ^ ^ ^ ^ ^
+exec -a "$0" sbcl --noinform --noprint --disable-debugger --load $0 --end-toplevel-options "$@"
+# Used for testing on darcs record.
+|#
+
+(asdf:operate 'asdf:load-op :cl-smoke.qt.core)
+(asdf:operate 'asdf:test-op :cl-smoke.qt.core)
+
+(sb-ext:quit)