summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gbs.conf2
-rw-r--r--.gitignore9
-rw-r--r--AUTHORS17
-rw-r--r--COPYING482
-rw-r--r--INSTALL31
-rw-r--r--MAINTAINERS4
-rw-r--r--Makefile.am10
-rw-r--r--NEWS487
-rw-r--r--README86
-rw-r--r--at-spi2-atk.desktop6
-rw-r--r--at-spi2-atk.doap33
-rw-r--r--atk-adaptor/Makefile.am53
-rw-r--r--atk-adaptor/Makefile.include21
-rw-r--r--atk-adaptor/accessible-cache.c451
-rw-r--r--atk-adaptor/accessible-cache.h67
-rw-r--r--atk-adaptor/accessible-leasing.c214
-rw-r--r--atk-adaptor/accessible-leasing.h61
-rw-r--r--atk-adaptor/accessible-register.c320
-rw-r--r--atk-adaptor/accessible-register.h80
-rw-r--r--atk-adaptor/accessible-stateset.c208
-rw-r--r--atk-adaptor/accessible-stateset.h51
-rw-r--r--atk-adaptor/adaptors/Makefile.am34
-rw-r--r--atk-adaptor/adaptors/accessible-adaptor.c558
-rw-r--r--atk-adaptor/adaptors/action-adaptor.c257
-rw-r--r--atk-adaptor/adaptors/adaptors.h50
-rw-r--r--atk-adaptor/adaptors/application-adaptor.c156
-rw-r--r--atk-adaptor/adaptors/cache-adaptor.c345
-rw-r--r--atk-adaptor/adaptors/collection-adaptor.c1347
-rw-r--r--atk-adaptor/adaptors/component-adaptor.c499
-rw-r--r--atk-adaptor/adaptors/document-adaptor.c142
-rw-r--r--atk-adaptor/adaptors/editabletext-adaptor.c207
-rw-r--r--atk-adaptor/adaptors/hyperlink-adaptor.c156
-rw-r--r--atk-adaptor/adaptors/hypertext-adaptor.c112
-rw-r--r--atk-adaptor/adaptors/image-adaptor.c140
-rw-r--r--atk-adaptor/adaptors/selection-adaptor.c257
-rw-r--r--atk-adaptor/adaptors/socket-adaptor.c208
-rw-r--r--atk-adaptor/adaptors/streamablecontent-adaptor.c330
-rw-r--r--atk-adaptor/adaptors/table-adaptor.c673
-rw-r--r--atk-adaptor/adaptors/table-cell-adaptor.c191
-rw-r--r--atk-adaptor/adaptors/text-adaptor.c892
-rw-r--r--atk-adaptor/adaptors/value-adaptor.c208
-rw-r--r--atk-adaptor/atk-bridge.h37
-rw-r--r--atk-adaptor/atkbridge.symbols2
-rw-r--r--atk-adaptor/bitarray.h32
-rw-r--r--atk-adaptor/bridge.c1232
-rw-r--r--atk-adaptor/bridge.h97
-rw-r--r--atk-adaptor/event.c1366
-rw-r--r--atk-adaptor/event.h33
-rw-r--r--atk-adaptor/gtk-2.0/Makefile.am5
-rw-r--r--atk-adaptor/gtk-2.0/module.c62
-rw-r--r--atk-adaptor/introspection.c913
-rw-r--r--atk-adaptor/introspection.h55
-rw-r--r--atk-adaptor/object.c504
-rw-r--r--atk-adaptor/object.h63
-rw-r--r--atk-adaptor/spi-dbus.c289
-rw-r--r--atk-adaptor/spi-dbus.h56
-rw-r--r--atk-bridge-2.0.pc.in11
-rwxr-xr-xautogen.sh15
-rw-r--r--configure.ac103
-rw-r--r--droute/Makefile.am30
-rw-r--r--droute/droute-pairhash.c87
-rw-r--r--droute/droute-pairhash.h41
-rw-r--r--droute/droute-test.c308
-rw-r--r--droute/droute-variant.c125
-rw-r--r--droute/droute-variant.h35
-rw-r--r--droute/droute.c742
-rw-r--r--droute/droute.h113
-rw-r--r--packaging/at-spi2-atk.manifest5
-rw-r--r--packaging/at-spi2-atk.spec77
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/cspi/Makefile.am19
-rw-r--r--tests/cspi/key-listener-test.c201
-rw-r--r--tests/cspi/keysynth-test.c65
-rw-r--r--tests/cspi/simple-at.c615
-rw-r--r--tests/cspi/test-simple.c816
75 files changed, 17610 insertions, 0 deletions
diff --git a/.gbs.conf b/.gbs.conf
new file mode 100644
index 0000000..6c76bde
--- /dev/null
+++ b/.gbs.conf
@@ -0,0 +1,2 @@
+[general]
+upstream_tag = AT_SPI2_ATK_2_12_0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5f797c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+Makefile.in
+*Makefile
+ChangeLog
+*.pyc
+aclocal.m4
+autom4te.cache
+config.h.in~
+config
+configure
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..9f0f539
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,17 @@
+
+Authors of AT-SPI D-Bus implementation
+--------------------------------------
+
+Mike Gorse <mgorse@suse.com>
+Mark Doffman <mark.doffman@codethink.co.uk>
+
+
+Authors of AT-SPI spec & implementation in CORBA
+------------------------------------------------
+
+Bill Haneman <bill.haneman@sun.com>
+Marc Mulcahy <marc.mulchay@sun.com>
+Michael Meeks <micheal@ximian.com>
+
+with contributions from:
+Mark McLoughlin <mark@skynet.ie>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..b8f9ad6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,482 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey 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 library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5bf92ee
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,31 @@
+Install procedure
+-----------------
+
+ % gzip -cd at-spi-1.9.0.tar.gz | tar xvf - # unpack the sources
+ % cd at-spi-1.9.0 # change to the toplevel directory
+ % ./configure # run the `configure' script
+ % make # build at-spi
+
+ [ Become root if necessary ]
+ % make install # install at-spi
+
+Requirements
+------------
+
+ GNU make
+ GNU autotools
+
+ pkg-config
+
+ python
+
+ glib
+ gtk+
+ gail
+
+ dbus
+ dbus-glib
+ dbus-python
+
+ X
+ XEVIE (Reccomended)
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644
index 0000000..96801fc
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,4 @@
+
+Mike Gorse <mgorse@novell.com>
+Li Yuan <lee.yuan@oracle.com>
+Mark Doffman <mark.doffman@codethink.co.uk>
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..713fec5
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,10 @@
+SUBDIRS=droute atk-adaptor
+
+gtk_modulesdir = $(libdir)/gnome-settings-daemon-3.0/gtk-modules/
+gtk_modules_DATA = at-spi2-atk.desktop
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = atk-bridge-2.0.pc
+
+EXTRA_DIST = $(gtk_modules_DATA) atk-bridge-2.0.pc.in
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e601543
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,487 @@
+What's new in at-spi2-atk 2.11.92:
+
+* Bump minimum libdbus version needed, since we use a function
+ introduced in 1.5.
+
+What's new in at-spi2-atk 2.11.91:
+
+* Improve compatibility with at-spi2-registryd <= 2.10.
+
+* Collection: Fix an infinite loop when encountering a NULL parent
+
+What's new in at-spi2-atk 2.11.90:
+
+* Add AtspitableCell, tracking the new atk interface
+
+What's new in at-spi2-atk 2.11.5:
+
+* Allow sending of properties with events upon request (BGO#708695).
+
+What's new in at-spi2-atk 2.11.3:
+
+ * Fix atspi_text_get_bounded_ranges
+
+* document: add support to current page and page count (BGO#719508).
+
+What's new in at-spi2-atk 2.11.2:
+
+* Add new roles and states to track atk (BGO#710464, BGO#712608, BGO#712609).
+
+What's new in at-spi2-atk 2.11.1:
+
+* Fix Contains method for components (BGO#710730).
+
+What's new in at-spi2-atk 2.9.92:
+
+* Properly clean up when timing out when motifying keystroke listeners
+ (BGO#707218).
+
+* Allow lists of attribute values when reading collection match rules
+ (BGO#700865).
+
+What's new in at-spi2-atk 2.9.90:
+
+* Implement GetStringAtOffset (BGO#705581).
+
+What's new in at-spi2-atk 2.9.5:
+
+* Fix another crash when we're initialized and shut down repeatedly.
+
+What's new in at-spi2-atk 2.9.4:
+
+* Fix a deadlock for apps that also register AT-SPI key event listeners
+ (ie, the Orca preferences dialog works again).
+
+What's new in at-spi2-atk 2.9.3:
+
+* Fix for BGO#681276 (reentrancy issues with gnome-shell).
+
+What's new in at-spi2-atk 2.9.2:
+
+* Fix a memory leak in the socket adaptor (BGO#696733).
+
+* Fix various DBusError leaks (BGO#698951).
+
+* Fix crash when a main loop is shut down repeatedly (BGO#699554).
+
+* Suppress a warning if an app returns NULL when referencing a child.
+
+What's new in at-spi2-atk 2.7.91:
+
+* Add Locale property (BGO#694368).
+
+What's new in at-spi2-atk 2.7.90:
+
+* Bump atk dependency to 2.7.5 (BGO#693189).
+
+What's new in at-spi2-atk 2.7.5:
+
+* Support ATSPI_ROLE_LEVEL_BAR to correspond to the new atk role.
+
+* Fix various compiler warnings.
+
+What's new in at-spi2-atk 2.7.3:
+
+* re-register if the registry goes away and later returns.
+
+* Stop using deprecated glib functions.
+
+* Fix a few memory leaks.
+
+What's new in at-spi2-atk 2.7.2:
+
+* atk-adaptor: don't emit a critical in case the bridge was not initialized
+ (BGO#684334).
+
+* Remove dbind (it was only used for the droute test).
+
+* Fix a crash in socket_embed_hook if spi_global_register is NULL.
+
+* [droute] Fix memory leak in path cleanup (BGO#688363).
+
+What's new in at-spi2-atk 2.7.1:
+
+* Remove the schema; it was only used to specify the location of the
+ atk-bridge library, which is now installed in the standard path.
+
+* Fix compiler warnings (BGO#678045).
+
+What's new in at-spi2-atk 2.6.0:
+
+* Fix some crashes in atk_bridge_adaptor_cleanup (BGO#684434).
+
+* When the cache is activated, register it on the main D-Bus connection.
+
+What's new in at-spi2-atk 2.5.92:
+
+* Fix atspi_hyperlink_get_uri (BGO#683182).
+
+* Only initialize the cache when an AT is running.
+
+* Fix various memory leaks (BGO#683979, BGO#684077)
+What's new in at-spi2-atk 2.5.91:
+
+* Removed the gtk 3.0 module (BGO#678315).
+
+What's new in at-spi2-atk 2.5.90:
+
+* Don't leak a GError when option parsing fails (BGO#679296)
+
+* Rework some inefficient code when removing clients and events (BGO#679295,
+ BGO#679297).
+
+What's new in at-spi2-atk 2.5.5:
+
+* Implement GetLocalizedName for actions (BGO#680598)
+
+* Allow to build out of source directory (BGO#680280).
+
+What's new in at-spi2-atk 2.5.4:
+
+ Fix for bug #679013 - AtspiCollection should be implemented for
+ all containers
+
+* Don't create a (non-readable) subdirectory for the socket when root.
+
+* Plug ref count leaks (BGO#679285).
+
+* Only create a directory and a socket when requested.
+
+* Only add items to the cache on children-changed if the children are
+ included in the event.
+
+* Only send PropertyChange signals used for caching, absent listeners.
+
+What's new in at-spi2-atk 2.5.3:
+
+* Create a library (libatk-bridge), currently with atk_bridge_adaptor_init()
+ and atk_bridge_adaptor_cleanup() functions, to facilitate linking directly
+ into, ie GTK+ 3.
+
+* Only register events at beginning if an AT is listening (BGO#678475).
+
+* Use XDG_RUNTIME_DIR to hold the socket, rather than a potentially secure
+ directory hard-coded under /tmp (BGO#678348).
+
+* Fix various compiler warnings and build errors.
+
+What's new in at-spi2-atk 2.5.2:
+
+* Fix for bug 677211 - The collection interface's MATCH_ANY fails for states
+
+What's new in at-spi2-atk 2.5.1:
+
+* Updated Norwegian Nynorsk translation
+
+What's new in at-spi2-atk 2.4.0:
+
+* Updated Hindi translation.
+
+What's new in at-spi2-atk 2.3.92:
+
+* Add Khmer and Malayalam translations.
+
+What's new in at-spi2-atk 2.3.91:
+
+* Have GetIndexInParent() return a signed int, per the spec.
+
+* Send a DoAction reply message before invoking atk (works around
+ atk_action_do_action potentially not returning right away for gtk).
+
+
+What's new in at-spi2-atk 2.3.90:
+
+* Have GrabFocus return a bool, per the spec, rather than a uint32.
+
+* Fix a potential crash when emitting a signal if the ATK implementor
+ misbehaves.
+
+What's new in at-spi2-atk 2.3.5:
+
+* Remove the ability to set an accessible's name and description via AT-SPI
+ (it seems wrong to have been exposing this in the first place).
+
+* Fix for BGO#659967: some list API usage fixes.
+
+* Fix for BGO#663967: Don't use /a11y/ as a dconf path.
+
+* Fix for BGO#666371: possible crash when accessibles are created and
+ deleted in rapid succession; eg, in gnome-shell)
+
+* Avoid triggering GLib criticals in a few places.
+
+What's new in at-spi2-atk 2.3.4:
+
+* Fix for BGO#666870: Keystroke listeners do not work unless an event listener
+ is also registered [also needs updated at-spi2-core]
+
+What's new in at-spi2-atk 2.3.3:
+
+* Fix for BGO#664822 - gnome-shell crash when an AT is launched
+
+* Fix a reference leak if a child-added signal has no object value.
+
+* Change a : to a / in the suffix to an event, to allow DBus match rules
+ using arg0path.
+
+* Only deregister objects when they are marked defunct, not when a previously
+ defunct object is marked as no longer defunct.
+
+What's new in at-spi2-atk 2.3.2:
+
+* Have AtkSocket's implementation of ref_state_set to return empty sets
+ instead of NULL
+
+* Fix for BGO#663876: Make sure the a11y hierarchy under an AtkPlug is
+ generated when embedding.
+
+What's new in at-spi2-atk 2.3.1:
+
+* Fix a small coding error that could generate compiler warnings.
+
+What's new in at-spi2-atk 2.2.1:
+
+* Updated Finnish translation.
+
+What's new in at-spi2-atk 2.2.0:
+
+* Really fix BGO#658013: Attach the timeout for a key listener to the
+ appropriate main loop context.
+
+What's new in at-spi2-atk 2.1.92:
+
+* Fix for BGO#658013: Add timeout to check for disconnect on a key listener.
+
+What's new in at-spi2-atk 2.1.91:
+
+* Fix for BGO#645321: Use an array of bytes rather than a string for the
+ atk-bridge location in the schema.
+
+What's new in at-spi2-atk 2.1.90:
+
+* Try to use the new AtkWindow interface to register for window events.
+
+What's new in at-spi2-atk 2.1.5:
+
+* Use libatspi constants rather than keeping duplicate copies of the
+ constants in at-spi2-atk.
+
+* Fixed some problems when shutting down and restarting the module.
+
+What's new in at-spi2-atk 2.1.4:
+
+* Ensure the detail integers are initialized before sending events.
+
+* Map some new atk roles.
+
+What's new in at-spi2-atk 2.1.3:
+
+* Fix for BGO#652797: Remove unused AtkMisc instance.
+
+* Only register events when something is listening. In theory, this should
+ mitigate performance loss that might show up when no ATs are running.
+
+* BGO#652596: Allow setting value via the DBus property again.
+
+* BGO#652858: Deregister objects on state-changed:defunct.
+
+* Add AT-SPI mapping for ATK_RELATION_NODE_PARENT_OF.
+
+What's new in at-spi2-atk 2.0.2:
+
+* Fix matching on attributes for collection methods
+
+* Fix for BGO#650286: Ensure valid UTF-8 from ATK
+
+* Always emit children-changed, property-change, and state-changed events, in
+ order to keep caches synchronized.
+
+* Add GetAtspiVersion to fetch the version of the AT-SPI specification provided
+ by an application.
+
+What's new in at-spi2-atk 2.0.1:
+
+* Fix a memory leak in impl_GetText
+
+What's new in at-spi2-atk 1.91.93:
+
+* Removed dbus-glib-related includes, as they are no longer required.
+
+What's new in at-spi2-atk 1.91.92:
+
+* Handle text-insert and text-removed signals from ATK (BGO#638377).
+
+* Use the new dbus errors when compiled against a version of libdbus that
+ defines them.
+
+* Use libatspi to get the accessibility bus and handle main loop integration.
+ This fixes a crash with some builds of Firefox (FDO#35115).
+ Note that this adds a dependency on libatspi.
+
+* Fix accessibility of applications running as root on Linux.
+
+What's new in at-spi2-atk 1.91.91:
+
+* Fix some missing prototypes.
+
+* Do not exit if the accessibility bus disconnects.
+
+What's new in at-spi2-atk 1.91.90:
+
+* Fix for BGO#641338: Avoid crashing when unable to listen for p2p connections.
+
+* Set /tmp/at-spi2 to be world-writable.
+
+* Fix for BGO#641869: Remove --enable-relocate option.
+
+* Changed accessibility key name as was done in gsettings-desktop-schemas.
+
+* Fixed several memory leaks.
+
+* Fixed some build errors.
+
+What's new in at-spi2-atk 1.91.6:
+
+* Fixed the path in org.a11y.atspi.gschema.xml for lib64.
+
+* Implemented SetPosition, SetExtents, and SetSize for components.
+
+What's new in at-spi2-atk 1.91.5:
+
+* Fixed some memory leaks.
+
+* Fixed a crash if peer-to-peer connections are disabled.
+
+* Fixed setting of GTK_PATH with --enable-relocate (was broken in 1.91.4).
+
+What's new in at-spi2-atk 1.91.4:
+
+* Support direct dbus connections to improve performance if dbus-glib
+ 0.90 or greater is available.
+
+* Added a GSettings key to specify the location of libatk-bridge.so.
+
+* Added a desktop file to load gail and atk-bridge with the new
+ gnome-settings-daemon.
+
+What's new in at-spi2-atk 1.91.3:
+
+* Attributes in a collection match rule are now expected to be sent as a
+ dictionary.
+
+What's new in at-spi2-atk 1.91.2:
+
+* FIxed BGO#563546: Removed the g_atexit hook.
+
+What's new in at-spi2-atk 1.91.1:
+
+ * Fire all events until we receive a reply from GetRegisteredEvents
+
+What's new in at-spi2-atk 1.91.0:
+
+* --disable-relocate is the default again.
+
+What's new in at-spi2-atk 0.3.92:
+
+* Have value methods return 0 on failure rather than fail, as in original pyatspi
+
+What's new in at-spi2-atk 0.3.91.1:
+
+* Fi a build error introduced in 0.3.91.
+
+What's new in at-spi2-atk 0.3.91:
+
+* Default to --enable-relocate for now.
+
+* Fix for FDO#29880: gtk module can't handle reloading.
+
+What's new in at-spi2-atk 0.3.90:
+
+* FDO#29365: Stop using a deprecated glib function.
+
+* Caching fixes--GetItems was completely broken in v0.3.6, and fixed a
+possible crash when it is called.
+
+* Only emit signals when AT-SPI clients are listening for them.
+
+What's new in at-spi2-atk 0.3.6:
+
+* Fixed a problem with dbus introspection.
+
+* Do not block waiting for a response when registering.
+
+What's new in at-spi2-atk 0.3.5:
+
+* Have a socket retrieve its state set from its embedded plug
+
+* Rename AT_SPI_CLIENT to AT_SPI_REENTER_G_MAIN_LOOP, but still check the
+former variable as well for now.
+
+What's new in at-spi2-atk 0.3.4:
+
+* Ref an object while adding it to the message generated by GetItems.
+This prevents a crash if all other references to the objects go away while
+it is being analyzed.
+
+* Add GetChildren to the introspection.
+
+* Fix NSelectedRows and NSelectedColumns.
+
+* Fix the behavior of ChildCount and GetChildAtIndex for sockets with
+embedded plugs.
+
+* Fix extra unref when calling get_row_header or get_column_header on a
+table, or calling atk_hyperlink_get_object.
+
+* Set the /desktop/gnome/interface/at-spi-dbus gconf key to false by default
+(this key is only used when at-spi2 is relocated, which it is not by default).
+
+* Fix a few compiler warnings.
+
+What's new in at-spi2-atk 0.3.3:
+
+* Remove unused gtk build dependency.
+
+* Install a copy of the module into the gtk-3.0 modules directory.
+
+* Correct handling of some children-changed events sent by Firefox.
+
+* Lease objects that send events if they are not cached; fixes some
+tracebacks when handling Firefox events.
+
+What's new in at-spi2-atk 0.3.2:
+
+* Some hyperlink fixes.
+
+* Cache additions are now done in an idle call. This prevents additions
+from being made when an object may not be fully initialized and prevents
+Firefox 3.6 from crashing.
+
+* The cache object has been placed into the org.a11y.atspi namespace.
+
+What's new in at-spi2-atk 0.3.1:
+
+* Added a gconf schema.
+
+* org.freedesktop.DBus.Properties.GetAll now works rather then crashing.
+
+* The position, size, and extents of an AtkSocket are now fetched from the
+corresponding AtkPlug.
+
+* An application is no longer registered if its root is an AtkPlug.
+
+* Fix BGO#538680 - Count ignored in GetMatchesTo
+
+* Fix FDO#27626 - deadlock when registering an application.
+
+* Fix a problem with various hyperlink methods.
+
+* Fix for an AtkPlug sometimes not appearing in the hierarchy.
+
+* Fix a crash if the registry returns an unexpected message while embedding.
+
+* Remove libxml2 dependency since libxml2 is no longer used.
+
+* Fix handling of MATCH_ANY for a stateset in a collection match rule.
+
+* Disabled relocation by default.
diff --git a/README b/README
new file mode 100644
index 0000000..eb23e8a
--- /dev/null
+++ b/README
@@ -0,0 +1,86 @@
+D-Bus AT-SPI
+------------
+
+This version of at-spi is a major break from version 1.x.
+It has been completely rewritten to use D-Bus rather than
+ORBIT / CORBA for its transport protocol.
+
+A page including instructions for testing, project status and
+TODO items is kept up to date at:
+
+ http://www.linuxfoundation.org/en/AT-SPI_on_D-Bus
+
+The mailing list used for general questions is:
+
+ accessibility-atspi@lists.linux-foundation.org
+
+For bug reports, feature requests, patches or enhancements please use
+the AT-SPI project on bugzilla.gnome.org. Use the at-spi2-atk component for
+bugs specific to this module.
+
+ http://bugzilla.gnome.org
+
+A git repository with the latest development code is available at:
+
+ git://git.gnome.org/at-spi2-atk
+
+Code in this repository depends on at-spi2-core resources. The
+at-spi2-core repository can be found at:
+
+ git://git.gnome.org/at-spi2-core
+
+More information
+----------------
+
+The project was started with a D-Bus performance review
+the results of which are available on the GNOME wiki. Keep in
+mind that the D-Bus AT-SPI design documents on this page
+have not been kept up to date.
+
+ http://live.gnome.org/GAP/AtSpiDbusInvestigation/
+
+Other sources of relevant information about AT-SPI and Accessibility
+include:
+
+ http://live.gnome.org/Accessibility
+ http://www.sun.com/software/star/gnome/accessibility/architecture.xml
+ http://accessibility.kde.org/developer/atk.php
+ http://www.gnome.org/~billh/at-spi-idl/html/
+
+
+
+Contents of this package
+------------------------
+
+This package includes libatk-bridge, a library that bridges ATK to the new
+D-Bus based AT-SPI, as well as a corresponding module for gtk+ 2.x. Gtk+ 3.x
+now links against libatk-bridge directly rather than requiring it to be loaded
+as a module.
+
+These libraries depend on the at-spi2-core code that contains the daemon for
+registering applications, D-Bus helper libraries and the AT-SPI D-Bus specifications.
+
+Directory structure
+-------------------
+
+The directories within this package are arranged as follows:
+
+ droute
+
+ Contains a framework for registering objects
+ with a D-Bus connection and for routing messages to
+ the implementing object.
+
+ Used by the ATK adaptor.
+
+ atk-adaptor
+
+ This directory contains code that bridges
+ the at-spi to the GTK+ toolkit, and which is
+ loaded at runtime by GTK+-based Gnome applications.
+ The 'bridge' automatically registers GTK+-2.0
+ applications with the accessibility registry,
+ and relays UI events from application to registry.
+ It is also responsible for servicing requests from
+ the registry to register handlers for specific event
+ types.
diff --git a/at-spi2-atk.desktop b/at-spi2-atk.desktop
new file mode 100644
index 0000000..9b6d2fa
--- /dev/null
+++ b/at-spi2-atk.desktop
@@ -0,0 +1,6 @@
+[GTK Module]
+Name=AT-SPI2 ATK
+Description=Accessibility ToolKit GTK+ Module
+X-GTK-Module-Name=gail:atk-bridge
+X-GTK-Module-Enabled-Schema=org.gnome.desktop.interface
+X-GTK-Module-Enabled-Key=toolkit-accessibility
diff --git a/at-spi2-atk.doap b/at-spi2-atk.doap
new file mode 100644
index 0000000..52837e0
--- /dev/null
+++ b/at-spi2-atk.doap
@@ -0,0 +1,33 @@
+<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+ xmlns:foaf="http://xmlns.com/foaf/0.1/"
+ xmlns:gnome="http://api.gnome.org/doap-extensions#"
+ xmlns="http://usefulinc.com/ns/doap#">
+
+ <name xml:lang="en">at-spi2-atk</name>
+ <shortdesc xml:lang="en">Gtk module for bridging AT-SPI to Atk.</shortdesc>
+ <homepage rdf:resource="http://www.linuxfoundation.org/en/Accessibility/ATK/AT-SPI/AT-SPI_on_D-Bus"/>
+ <mailing-list rdf:resource="https://lists.linux-foundation.org/mailman/listinfo/accessibility-atspi"/>
+
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Mark Doffman</foaf:name>
+ <foaf:mbox rdf:resource="mailto:mark.doffman@codethink.co.uk" />
+ <gnome:userid>markdoffman</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Mike Gorse</foaf:name>
+ <foaf:mbox rdf:resource="mailto:mgorse@suse.com" />
+ <gnome:userid>mgorse</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+ <maintainer>
+ <foaf:Person>
+ <foaf:name>Li Yuan</foaf:name>
+ <foaf:mbox rdf:resource="mailto:lee.yuan@oracle.com" />
+ <gnome:userid>liyuan</gnome:userid>
+ </foaf:Person>
+ </maintainer>
+</Project>
diff --git a/atk-adaptor/Makefile.am b/atk-adaptor/Makefile.am
new file mode 100644
index 0000000..2bb3c6b
--- /dev/null
+++ b/atk-adaptor/Makefile.am
@@ -0,0 +1,53 @@
+SUBDIRS= adaptors . gtk-2.0
+
+lib_LTLIBRARIES = libatk-bridge-2.0.la
+
+libatk_bridge_2_0_la_CFLAGS = \
+ $(DBUS_CFLAGS) \
+ $(ATK_CFLAGS) \
+ $(ATSPI_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/atk-adaptor/adaptors \
+ $(P2P_CFLAGS)
+
+atkbridgeincludedir = $(pkgincludedir)/2.0/
+atkbridgeinclude_HEADERS = atk-bridge.h
+
+libatk_bridge_2_0_la_SOURCES = \
+ accessible-leasing.c \
+ accessible-leasing.h \
+ accessible-cache.c \
+ accessible-cache.h \
+ accessible-register.c \
+ accessible-register.h \
+ accessible-stateset.c \
+ accessible-stateset.h \
+ bitarray.h \
+ introspection.c \
+ introspection.h \
+ bridge.c \
+ bridge.h \
+ object.c \
+ object.h \
+ event.c \
+ event.h \
+ spi-dbus.c \
+ spi-dbus.h \
+ atk-bridge.h
+
+libatk_bridge_2_0_la_LIBADD = \
+ $(DBUS_LIBS) \
+ $(GMODULE_LIBS) \
+ $(ATK_LIBS) \
+ $(ATSPI_LIBS) \
+ $(top_builddir)/droute/libdroute.la \
+ $(top_builddir)/atk-adaptor/adaptors/libatk-bridge-adaptors.la
+
+libatk_bridge_2_0_la_LDFLAGS = \
+ $(LT_VERSION_INFO) \
+ -export-symbols $(srcdir)/atkbridge.symbols \
+ -no-undefined \
+ $(AM_LDFLAGS)
+
+EXTRA_DIST = Makefile.include \
+ atkbridge.symbols
diff --git a/atk-adaptor/Makefile.include b/atk-adaptor/Makefile.include
new file mode 100644
index 0000000..8c47c7b
--- /dev/null
+++ b/atk-adaptor/Makefile.include
@@ -0,0 +1,21 @@
+gtkmodule_LTLIBRARIES = libatk-bridge.la
+
+libatk_bridge_la_CFLAGS = \
+ $(DBUS_CFLAGS) \
+ $(ATK_CFLAGS) \
+ $(ATSPI_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/atk-adaptor/adaptors \
+ -I$(top_srcdir)/atk-adaptor/
+ $(P2P_CFLAGS)
+
+libatk_bridge_la_LDFLAGS = -no-undefined \
+ -module \
+ -avoid-version \
+ -rpath $(gtkmoduledir)
+
+libatk_bridge_la_LIBADD = $(DBUS_LIBS) \
+ $(GMODULE_LIBS) \
+ $(ATK_LIBS) \
+ $(ATSPI_LIBS) \
+ $(top_builddir)/atk-adaptor/libatk-bridge-2.0.la
diff --git a/atk-adaptor/accessible-cache.c b/atk-adaptor/accessible-cache.c
new file mode 100644
index 0000000..5065a00
--- /dev/null
+++ b/atk-adaptor/accessible-cache.c
@@ -0,0 +1,451 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <string.h>
+
+#include "accessible-cache.h"
+#include "accessible-register.h"
+#include "bridge.h"
+
+SpiCache *spi_global_cache = NULL;
+
+static gboolean
+child_added_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data);
+
+static void
+toplevel_added_listener (AtkObject * accessible,
+ guint index, AtkObject * child);
+
+static void
+remove_object (GObject * source, GObject * gobj, gpointer data);
+
+static void
+add_object (SpiCache * cache, GObject * gobj);
+
+static void
+add_subtree (SpiCache *cache, AtkObject * accessible);
+
+static gboolean
+add_pending_items (gpointer data);
+
+/*---------------------------------------------------------------------------*/
+
+static void
+spi_cache_finalize (GObject * object);
+
+/*---------------------------------------------------------------------------*/
+
+enum
+{
+ OBJECT_ADDED,
+ OBJECT_REMOVED,
+ LAST_SIGNAL
+};
+static guint cache_signals[LAST_SIGNAL] = { 0 };
+
+/*---------------------------------------------------------------------------*/
+
+G_DEFINE_TYPE (SpiCache, spi_cache, G_TYPE_OBJECT)
+
+static void spi_cache_class_init (SpiCacheClass * klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ spi_cache_parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ object_class->finalize = spi_cache_finalize;
+
+ cache_signals [OBJECT_ADDED] = \
+ g_signal_new ("object-added",
+ SPI_CACHE_TYPE,
+ G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_OBJECT);
+
+ cache_signals [OBJECT_REMOVED] = \
+ g_signal_new ("object-removed",
+ SPI_CACHE_TYPE,
+ G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_OBJECT);
+}
+
+static void
+spi_cache_init (SpiCache * cache)
+{
+ cache->objects = g_hash_table_new (g_direct_hash, g_direct_equal);
+ cache->add_traversal = g_queue_new ();
+
+#ifdef SPI_ATK_DEBUG
+ if (g_thread_supported ())
+ g_message ("AT-SPI: Threads enabled");
+
+ g_debug ("AT-SPI: Initial Atk tree regisration");
+#endif
+
+ g_signal_connect (spi_global_register,
+ "object-deregistered",
+ (GCallback) remove_object, cache);
+
+ add_subtree (cache, spi_global_app_data->root);
+
+ cache->child_added_listener = atk_add_global_event_listener (child_added_listener,
+ "Gtk:AtkObject:children-changed");
+
+ g_signal_connect (G_OBJECT (spi_global_app_data->root),
+ "children-changed::add",
+ (GCallback) toplevel_added_listener, NULL);
+}
+
+static void
+spi_cache_finalize (GObject * object)
+{
+ SpiCache *cache = SPI_CACHE (object);
+
+ while (!g_queue_is_empty (cache->add_traversal))
+ g_object_unref (G_OBJECT (g_queue_pop_head (cache->add_traversal)));
+ g_queue_free (cache->add_traversal);
+ g_hash_table_unref (cache->objects);
+
+ g_signal_handlers_disconnect_by_func (spi_global_register,
+ (GCallback) remove_object, cache);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (spi_global_app_data->root),
+ (GCallback) toplevel_added_listener, NULL);
+
+ atk_remove_global_event_listener (cache->child_added_listener);
+
+ G_OBJECT_CLASS (spi_cache_parent_class)->finalize (object);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+remove_object (GObject * source, GObject * gobj, gpointer data)
+{
+ SpiCache *cache = SPI_CACHE (data);
+
+ if (spi_cache_in (cache, gobj))
+ {
+#ifdef SPI_ATK_DEBUG
+ g_debug ("CACHE REM - %s - %d - %s\n", atk_object_get_name (ATK_OBJECT (gobj)),
+ atk_object_get_role (ATK_OBJECT (gobj)),
+ spi_register_object_to_path (spi_global_register, gobj));
+#endif
+ g_signal_emit (cache, cache_signals [OBJECT_REMOVED], 0, gobj);
+ g_hash_table_remove (cache->objects, gobj);
+ }
+ else if (g_queue_remove (cache->add_traversal, gobj))
+ {
+ g_object_unref (gobj);
+ }
+}
+
+static void
+add_object (SpiCache * cache, GObject * gobj)
+{
+ g_return_if_fail (G_IS_OBJECT (gobj));
+
+ g_hash_table_insert (cache->objects, gobj, NULL);
+
+#ifdef SPI_ATK_DEBUG
+ g_debug ("CACHE ADD - %s - %d - %s\n", atk_object_get_name (ATK_OBJECT (gobj)),
+ atk_object_get_role (ATK_OBJECT (gobj)),
+ spi_register_object_to_path (spi_global_register, gobj));
+#endif
+
+ g_signal_emit (cache, cache_signals [OBJECT_ADDED], 0, gobj);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static GRecMutex cache_mutex;
+
+#ifdef SPI_ATK_DEBUG
+static GStaticMutex recursion_check_guard = G_STATIC_MUTEX_INIT;
+static gboolean recursion_check = FALSE;
+
+static gboolean
+recursion_check_and_set ()
+{
+ gboolean ret;
+ g_static_mutex_lock (&recursion_check_guard);
+ ret = recursion_check;
+ recursion_check = TRUE;
+ g_static_mutex_unlock (&recursion_check_guard);
+ return ret;
+}
+
+static void
+recursion_check_unset ()
+{
+ g_static_mutex_lock (&recursion_check_guard);
+ recursion_check = FALSE;
+ g_static_mutex_unlock (&recursion_check_guard);
+}
+#endif /* SPI_ATK_DEBUG */
+
+/*---------------------------------------------------------------------------*/
+
+static void
+append_children (AtkObject * accessible, GQueue * traversal)
+{
+ AtkObject *current;
+ guint i;
+ gint count = atk_object_get_n_accessible_children (accessible);
+
+ if (count < 0)
+ count = 0;
+ for (i = 0; i < count; i++)
+ {
+ current = atk_object_ref_accessible_child (accessible, i);
+ if (current)
+ {
+ g_queue_push_tail (traversal, current);
+ }
+ }
+}
+
+/*
+ * Adds a subtree of accessible objects
+ * to the cache at the accessible object provided.
+ *
+ * The leaf nodes do not have their children
+ * registered. A node is considered a leaf
+ * if it has the state "manages-descendants"
+ * or if it has already been registered.
+ */
+static void
+add_subtree (SpiCache *cache, AtkObject * accessible)
+{
+ g_return_if_fail (ATK_IS_OBJECT (accessible));
+
+ g_object_ref (accessible);
+ g_queue_push_tail (cache->add_traversal, accessible);
+ add_pending_items (cache);
+}
+
+static gboolean
+add_pending_items (gpointer data)
+{
+ SpiCache *cache = SPI_CACHE (data);
+ AtkObject *current;
+ GQueue *to_add;
+
+ to_add = g_queue_new ();
+
+ while (!g_queue_is_empty (cache->add_traversal))
+ {
+ AtkStateSet *set;
+
+ /* cache->add_traversal holds a ref to current */
+ current = g_queue_pop_head (cache->add_traversal);
+ set = atk_object_ref_state_set (current);
+
+ if (set && !atk_state_set_contains_state (set, ATK_STATE_TRANSIENT))
+ {
+ /* transfer the ref into to_add */
+ g_queue_push_tail (to_add, current);
+ if (!spi_cache_in (cache, G_OBJECT (current)) &&
+ !atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS) &&
+ !atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
+ {
+ append_children (current, cache->add_traversal);
+ }
+ }
+ else
+ {
+ /* drop the ref for the removed object */
+ g_object_unref (current);
+ }
+
+ if (set)
+ g_object_unref (set);
+ }
+
+ while (!g_queue_is_empty (to_add))
+ {
+ current = g_queue_pop_head (to_add);
+
+ /* Make sure object is registerd so we are notified if it goes away */
+ g_free (spi_register_object_to_path (spi_global_register,
+ G_OBJECT (current)));
+
+ add_object (cache, G_OBJECT(current));
+ g_object_unref (G_OBJECT (current));
+ }
+
+ g_queue_free (to_add);
+ cache->add_pending_idle = 0;
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static gboolean
+child_added_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ SpiCache *cache = spi_global_cache;
+ AtkObject *accessible;
+
+ const gchar *detail = NULL;
+
+ g_rec_mutex_lock (&cache_mutex);
+
+ /*
+ * Ensure that only accessibles already in the cache
+ * have their signals processed.
+ */
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ g_return_val_if_fail (ATK_IS_OBJECT (accessible), TRUE);
+
+ if (spi_cache_in (cache, G_OBJECT(accessible)))
+ {
+#ifdef SPI_ATK_DEBUG
+ if (recursion_check_and_set ())
+ g_warning ("AT-SPI: Recursive use of cache module");
+
+ g_debug ("AT-SPI: Tree update listener");
+#endif
+ if (signal_hint->detail)
+ detail = g_quark_to_string (signal_hint->detail);
+
+ if (detail && !strncmp (detail, "add", 3))
+ {
+ gpointer child;
+ child = g_value_get_pointer (param_values + 2);
+ if (!child)
+ {
+ g_rec_mutex_unlock (&cache_mutex);
+ return TRUE;
+ }
+
+ g_object_ref (child);
+ g_queue_push_tail (cache->add_traversal, child);
+
+ if (cache->add_pending_idle == 0)
+ cache->add_pending_idle = g_idle_add (add_pending_items, cache);
+ }
+#ifdef SPI_ATK_DEBUG
+ recursion_check_unset ();
+#endif
+ }
+
+ g_rec_mutex_unlock (&cache_mutex);
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+toplevel_added_listener (AtkObject * accessible,
+ guint index, AtkObject * child)
+{
+ SpiCache *cache = spi_global_cache;
+
+ g_rec_mutex_lock (&cache_mutex);
+
+ g_return_if_fail (ATK_IS_OBJECT (accessible));
+
+ if (spi_cache_in (cache, G_OBJECT(accessible)))
+ {
+#ifdef SPI_ATK_DEBUG
+ if (recursion_check_and_set ())
+ g_warning ("AT-SPI: Recursive use of registration module");
+
+ g_debug ("AT-SPI: Toplevel added listener");
+#endif
+ if (!ATK_IS_OBJECT (child))
+ {
+ child = atk_object_ref_accessible_child (accessible, index);
+ }
+ else
+ g_object_ref (child);
+
+ g_queue_push_tail (cache->add_traversal, child);
+
+ if (cache->add_pending_idle == 0)
+ cache->add_pending_idle = g_idle_add (add_pending_items, cache);
+#ifdef SPI_ATK_DEBUG
+ recursion_check_unset ();
+#endif
+ }
+
+ g_rec_mutex_unlock (&cache_mutex);
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+spi_cache_foreach (SpiCache * cache, GHFunc func, gpointer data)
+{
+ g_hash_table_foreach (cache->objects, func, data);
+}
+
+gboolean
+spi_cache_in (SpiCache * cache, GObject * object)
+{
+ if (!cache)
+ return FALSE;
+
+ if (g_hash_table_lookup_extended (cache->objects,
+ object,
+ NULL,
+ NULL))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+#ifdef SPI_ATK_DEBUG
+void
+spi_cache_print_info (GObject * obj)
+{
+ char * path = spi_register_object_to_path (spi_global_register, obj);
+
+ if (spi_cache_in (spi_global_cache, obj))
+ g_printf ("%s IC\n", path);
+ else
+ g_printf ("%s NC\n", path);
+
+ if (path)
+ g_free (path);
+}
+#endif
+
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/accessible-cache.h b/atk-adaptor/accessible-cache.h
new file mode 100644
index 0000000..2f5be06
--- /dev/null
+++ b/atk-adaptor/accessible-cache.h
@@ -0,0 +1,67 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ACCESSIBLE_CACHE_H
+#define ACCESSIBLE_CACHE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _SpiCache SpiCache;
+typedef struct _SpiCacheClass SpiCacheClass;
+
+G_BEGIN_DECLS
+
+#define SPI_CACHE_TYPE (spi_cache_get_type ())
+#define SPI_CACHE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPI_CACHE_TYPE, SpiCache))
+#define SPI_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPI_CACHE_TYPE, SpiCacheClass))
+#define SPI_IS_CACHE(o) (G_TYPE_CHECK__INSTANCE_TYPE ((o), SPI_CACHE_TYPE))
+#define SPI_IS_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPI_CACHE_TYPE))
+
+struct _SpiCache
+{
+ GObject parent;
+
+ GHashTable * objects;
+ GQueue *add_traversal;
+ gint add_pending_idle;
+
+ guint child_added_listener;
+};
+
+struct _SpiCacheClass
+{
+ GObjectClass parent_class;
+};
+
+GType spi_cache_get_type (void);
+
+extern SpiCache *spi_global_cache;
+
+void
+spi_cache_foreach (SpiCache * cache, GHFunc func, gpointer data);
+
+gboolean
+spi_cache_in (SpiCache * cache, GObject * object);
+
+G_END_DECLS
+#endif /* ACCESSIBLE_CACHE_H */
diff --git a/atk-adaptor/accessible-leasing.c b/atk-adaptor/accessible-leasing.c
new file mode 100644
index 0000000..dcddb0b
--- /dev/null
+++ b/atk-adaptor/accessible-leasing.c
@@ -0,0 +1,214 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "accessible-leasing.h"
+
+#ifdef SPI_ATK_DEBUG
+#include "accessible-cache.h"
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+SpiLeasing *spi_global_leasing;
+
+typedef struct _ExpiryElement
+{
+ guint expiry_s;
+ GObject *object;
+} ExpiryElement;
+
+static void spi_leasing_dispose (GObject * object);
+
+static void spi_leasing_finalize (GObject * object);
+
+static void add_expiry_timeout (SpiLeasing * leasing);
+
+/*---------------------------------------------------------------------------*/
+
+G_DEFINE_TYPE (SpiLeasing, spi_leasing, G_TYPE_OBJECT)
+
+static void spi_leasing_class_init (SpiLeasingClass * klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ spi_leasing_parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ object_class->finalize = spi_leasing_finalize;
+ object_class->dispose = spi_leasing_dispose;
+}
+
+static void
+spi_leasing_init (SpiLeasing * leasing)
+{
+ leasing->expiry_queue = g_queue_new ();
+ leasing->expiry_func_id = 0;
+}
+
+static void
+spi_leasing_finalize (GObject * object)
+{
+ SpiLeasing *leasing = SPI_LEASING (object);
+
+ if (leasing->expiry_func_id)
+ g_source_remove (leasing->expiry_func_id);
+ g_queue_free (leasing->expiry_queue);
+ G_OBJECT_CLASS (spi_leasing_parent_class)->finalize (object);
+}
+
+static void
+spi_leasing_dispose (GObject * object)
+{
+ SpiLeasing *leasing = SPI_LEASING (object);
+
+ ExpiryElement *head;
+ while ((head = g_queue_pop_head (leasing->expiry_queue)))
+ {
+ g_object_unref (head->object);
+ g_slice_free (ExpiryElement, head);
+ }
+ G_OBJECT_CLASS (spi_leasing_parent_class)->dispose (object);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ End the lease on all objects whose expiry time has passed.
+
+ Check when the next event is and set the next expiry func.
+*/
+static gboolean
+expiry_func (gpointer data)
+{
+ SpiLeasing *leasing = SPI_LEASING (data);
+
+ ExpiryElement *head, *current;
+ GTimeVal t;
+
+ g_get_current_time (&t);
+
+ head = g_queue_peek_head (leasing->expiry_queue);
+ while (head != NULL && head->expiry_s <= t.tv_sec)
+ {
+ current = g_queue_pop_head (leasing->expiry_queue);
+
+#ifdef SPI_ATK_DEBUG
+ g_debug ("REVOKE - ");
+ spi_cache_print_info (current->object);
+#endif
+
+ g_object_unref (current->object);
+ g_slice_free (ExpiryElement, current);
+
+ head = g_queue_peek_head (leasing->expiry_queue);
+ }
+
+ leasing->expiry_func_id = 0;
+ add_expiry_timeout (leasing);
+
+ return FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ Checks if an expiry timeout is already scheduled, if so returns.
+ This is becasue events will always be added to the end of the queue.
+ Events are always later in time to previoulsy added events.
+
+ Otherwise calculate the next wake time using the top of the queue
+ and add the next expiry function.
+
+ This function is called when a lease is added or at the end of the
+ expiry function to add the next expiry timeout.
+*/
+static void
+add_expiry_timeout (SpiLeasing * leasing)
+{
+ ExpiryElement *elem;
+ GTimeVal t;
+ guint next_expiry;
+
+ if (leasing->expiry_func_id != 0)
+ return;
+
+ elem = (ExpiryElement *) g_queue_peek_head (leasing->expiry_queue);
+ if (elem == NULL)
+ return;
+
+ /* The current time is implicitly rounded down here by ignoring the us */
+ g_get_current_time (&t);
+ next_expiry = elem->expiry_s - t.tv_sec;
+ leasing->expiry_func_id = g_timeout_add_seconds (next_expiry,
+ expiry_func, leasing);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ The lease time is expected to be in seconds, the rounding is going to be to
+ intervals of 1 second.
+
+ The lease time is going to be rounded up, as the lease time should be
+ considered a MINIMUM that the object will be leased for.
+*/
+#define LEASE_TIME_S 15
+#define EXPIRY_TIME_S (LEASE_TIME_S + 1)
+
+GObject *
+spi_leasing_take (SpiLeasing * leasing, GObject * object)
+{
+ /*
+ Get the current time.
+ Quantize the time.
+ Add the release event to the queue.
+ Check the next expiry.
+ */
+
+ GTimeVal t;
+ guint expiry_s;
+
+ ExpiryElement *elem;
+
+ g_get_current_time (&t);
+ expiry_s = t.tv_sec + EXPIRY_TIME_S;
+
+ elem = g_slice_new (ExpiryElement);
+ elem->expiry_s = expiry_s;
+ elem->object = g_object_ref (object);
+
+ g_queue_push_tail (leasing->expiry_queue, elem);
+
+ add_expiry_timeout (leasing);
+
+#ifdef SPI_ATK_DEBUG
+ g_debug ("LEASE - ");
+ spi_cache_print_info (object);
+#endif
+
+ return object;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/accessible-leasing.h b/atk-adaptor/accessible-leasing.h
new file mode 100644
index 0000000..af01a78
--- /dev/null
+++ b/atk-adaptor/accessible-leasing.h
@@ -0,0 +1,61 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008, 2009 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ACCESSIBLE_LEASING_H
+#define ACCESSIBLE_LEASING_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _SpiLeasing SpiLeasing;
+typedef struct _SpiLeasingClass SpiLeasingClass;
+
+G_BEGIN_DECLS
+
+#define SPI_LEASING_TYPE (spi_leasing_get_type ())
+#define SPI_LEASING(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPI_LEASING_TYPE, SpiLeasing))
+#define SPI_LEASING_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPI_LEASING_TYPE, SpiLeasingClass))
+#define SPI_IS_LEASING(o) (G_TYPE_CHECK__INSTANCE_TYPE ((o), SPI_LEASING_TYPE))
+#define SPI_IS_LEASING_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPI_LEASING_TYPE))
+
+struct _SpiLeasing
+{
+ GObject parent;
+
+ GQueue *expiry_queue;
+ guint expiry_func_id;
+};
+
+struct _SpiLeasingClass
+{
+ GObjectClass parent_class;
+};
+
+GType spi_leasing_get_type (void);
+
+extern SpiLeasing *spi_global_leasing;
+
+GObject *spi_leasing_take (SpiLeasing * leasing, GObject * object);
+
+G_END_DECLS
+#endif /* ACCESSIBLE_LEASING_H */
diff --git a/atk-adaptor/accessible-register.c b/atk-adaptor/accessible-register.c
new file mode 100644
index 0000000..7ca416f
--- /dev/null
+++ b/atk-adaptor/accessible-register.c
@@ -0,0 +1,320 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008, 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bridge.h"
+#include "accessible-register.h"
+
+/*
+ * This module is responsible for keeping track of all the AtkObjects in
+ * the application, so that they can be accessed remotely and placed in
+ * a client side cache.
+ *
+ * To access an AtkObject remotely we need to provide a D-Bus object
+ * path for it. The D-Bus object paths used have a standard prefix
+ * (SPI_ATK_OBJECT_PATH_PREFIX). Appended to this prefix is a string
+ * representation of an integer reference. So to access an AtkObject
+ * remotely we keep a Hashtable that maps the given reference to
+ * the AtkObject pointer. An object in this hash table is said to be 'registered'.
+ *
+ * The architecture of AT-SPI dbus is such that AtkObjects are not
+ * remotely reference counted. This means that we need to keep track of
+ * object destruction. When an object is destroyed it must be 'deregistered'
+ * To do this lookup we keep a dbus-id attribute on each AtkObject.
+ *
+ */
+
+#define SPI_ATK_PATH_PREFIX_LENGTH 27
+#define SPI_ATK_OBJECT_PATH_PREFIX "/org/a11y/atspi/accessible/"
+#define SPI_ATK_OBJECT_PATH_ROOT "root"
+
+#define SPI_ATK_OBJECT_REFERENCE_TEMPLATE SPI_ATK_OBJECT_PATH_PREFIX "%d"
+
+#define SPI_DBUS_ID "spi-dbus-id"
+
+SpiRegister *spi_global_register = NULL;
+
+static const gchar * spi_register_root_path = SPI_ATK_OBJECT_PATH_PREFIX SPI_ATK_OBJECT_PATH_ROOT;
+
+enum
+{
+ OBJECT_REGISTERED,
+ OBJECT_DEREGISTERED,
+ LAST_SIGNAL
+};
+static guint register_signals[LAST_SIGNAL] = { 0 };
+
+/*---------------------------------------------------------------------------*/
+
+static void
+spi_register_finalize (GObject * object);
+
+/*---------------------------------------------------------------------------*/
+
+G_DEFINE_TYPE (SpiRegister, spi_register, G_TYPE_OBJECT)
+
+static void spi_register_class_init (SpiRegisterClass * klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ spi_register_parent_class = g_type_class_ref (G_TYPE_OBJECT);
+
+ object_class->finalize = spi_register_finalize;
+
+ register_signals [OBJECT_REGISTERED] =
+ g_signal_new ("object-registered",
+ SPI_REGISTER_TYPE,
+ G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_OBJECT);
+
+ register_signals [OBJECT_DEREGISTERED] =
+ g_signal_new ("object-deregistered",
+ SPI_REGISTER_TYPE,
+ G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_OBJECT);
+}
+
+static void
+spi_register_init (SpiRegister * reg)
+{
+ reg->ref2ptr = g_hash_table_new (g_direct_hash, g_direct_equal);
+ reg->reference_counter = 0;
+}
+
+static void
+deregister_object (gpointer data, GObject * gobj)
+{
+ SpiRegister *reg = SPI_REGISTER (data);
+
+ spi_register_deregister_object (reg, gobj, FALSE);
+}
+
+static void
+spi_register_remove_weak_ref (gpointer key, gpointer val, gpointer reg)
+{
+ g_object_weak_unref (val, deregister_object, reg);
+}
+
+static void
+spi_register_finalize (GObject * object)
+{
+ SpiRegister *reg = SPI_REGISTER (object);
+
+ g_hash_table_foreach (reg->ref2ptr, spi_register_remove_weak_ref, reg);
+ g_hash_table_unref (reg->ref2ptr);
+
+ G_OBJECT_CLASS (spi_register_parent_class)->finalize (object);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Each AtkObject must be asssigned a D-Bus path (Reference)
+ *
+ * This function provides an integer reference for a new
+ * AtkObject.
+ *
+ * TODO: Make this reference a little more unique, this is shoddy.
+ */
+static guint
+assign_reference (SpiRegister * reg)
+{
+ reg->reference_counter++;
+ /* Reference of 0 not allowed as used as direct key in hash table */
+ if (reg->reference_counter == 0)
+ reg->reference_counter++;
+ return reg->reference_counter;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Returns the reference of the object, or 0 if it is not registered.
+ */
+static guint
+object_to_ref (GObject * gobj)
+{
+ return GPOINTER_TO_INT (g_object_get_data (gobj, SPI_DBUS_ID));
+}
+
+/*
+ * Converts the Accessible object reference to its D-Bus object path
+ */
+static gchar *
+ref_to_path (guint ref)
+{
+ return g_strdup_printf (SPI_ATK_OBJECT_REFERENCE_TEMPLATE, ref);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Callback for when a registered AtkObject is destroyed.
+ *
+ * Removes the AtkObject from the reference lookup tables, meaning
+ * it is no longer exposed over D-Bus.
+ */
+void
+spi_register_deregister_object (SpiRegister *reg, GObject *gobj, gboolean unref)
+{
+ guint ref;
+
+ ref = object_to_ref (gobj);
+ if (ref != 0)
+ {
+ g_signal_emit (reg,
+ register_signals [OBJECT_DEREGISTERED],
+ 0,
+ gobj);
+ if (unref)
+ g_object_weak_unref (gobj, deregister_object, reg);
+ g_hash_table_remove (reg->ref2ptr, GINT_TO_POINTER (ref));
+
+#ifdef SPI_ATK_DEBUG
+ g_debug ("DEREG - %d", ref);
+#endif
+ }
+}
+
+static void
+register_object (SpiRegister * reg, GObject * gobj)
+{
+ guint ref;
+ g_return_if_fail (G_IS_OBJECT (gobj));
+
+ ref = assign_reference (reg);
+
+ g_hash_table_insert (reg->ref2ptr, GINT_TO_POINTER (ref), gobj);
+ g_object_set_data (G_OBJECT (gobj), SPI_DBUS_ID, GINT_TO_POINTER (ref));
+ g_object_weak_ref (G_OBJECT (gobj), deregister_object, reg);
+
+#ifdef SPI_ATK_DEBUG
+ g_debug ("REG - %d", ref);
+#endif
+
+ g_signal_emit (reg, register_signals [OBJECT_REGISTERED], 0, gobj);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Used to lookup an GObject from its D-Bus path.
+ *
+ * If the D-Bus path is not found this function returns NULL.
+ */
+GObject *
+spi_register_path_to_object (SpiRegister * reg, const char *path)
+{
+ guint index;
+ void *data;
+
+ g_return_val_if_fail (path, NULL);
+
+ if (strncmp (path, SPI_ATK_OBJECT_PATH_PREFIX, SPI_ATK_PATH_PREFIX_LENGTH)
+ != 0)
+ return NULL;
+
+ path += SPI_ATK_PATH_PREFIX_LENGTH; /* Skip over the prefix */
+
+ /* Map the root path to the root object. */
+ if (!g_strcmp0 (SPI_ATK_OBJECT_PATH_ROOT, path))
+ return G_OBJECT (spi_global_app_data->root);
+
+ index = atoi (path);
+ data = g_hash_table_lookup (reg->ref2ptr, GINT_TO_POINTER (index));
+ if (data)
+ return G_OBJECT(data);
+ else
+ return NULL;
+}
+
+GObject *
+spi_global_register_path_to_object (const char * path)
+{
+ return spi_register_path_to_object (spi_global_register, path);
+}
+
+/*
+ * Used to lookup a D-Bus path from the GObject.
+ *
+ * If the objects is not already registered,
+ * this function will register it.
+ */
+gchar *
+spi_register_object_to_path (SpiRegister * reg, GObject * gobj)
+{
+ guint ref;
+
+ if (gobj == NULL)
+ return NULL;
+
+ /* Map the root object to the root path. */
+ if ((void *)gobj == (void *)spi_global_app_data->root)
+ return g_strdup (spi_register_root_path);
+
+ ref = object_to_ref (gobj);
+ if (!ref)
+ {
+ register_object (reg, gobj);
+ ref = object_to_ref (gobj);
+ }
+
+ if (!ref)
+ return NULL;
+ else
+ return ref_to_path (ref);
+}
+
+guint
+spi_register_object_to_ref (GObject * gobj)
+{
+ return object_to_ref (gobj);
+}
+
+/*
+ * Gets the path that indicates the accessible desktop object.
+ * This object is logically located on the registry daemon and not
+ * within any particular application.
+ */
+gchar *
+spi_register_root_object_path ()
+{
+ return g_strdup (SPI_ATK_OBJECT_PATH_PREFIX SPI_ATK_OBJECT_PATH_ROOT);
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/accessible-register.h b/atk-adaptor/accessible-register.h
new file mode 100644
index 0000000..5a62ebb
--- /dev/null
+++ b/atk-adaptor/accessible-register.h
@@ -0,0 +1,80 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008, 2009 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ACCESSIBLE_REGISTER_H
+#define ACCESSIBLE_REGISTER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _SpiRegister SpiRegister;
+typedef struct _SpiRegisterClass SpiRegisterClass;
+
+G_BEGIN_DECLS
+
+#define SPI_REGISTER_TYPE (spi_register_get_type ())
+#define SPI_REGISTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPI_REGISTER_TYPE, SpiRegister))
+#define SPI_REGISTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPI_REGISTER_TYPE, SpiRegisterClass))
+#define SPI_IS_REGISTER(o) (G_TYPE_CHECK__INSTANCE_TYPE ((o), SPI_REGISTER_TYPE))
+#define SPI_IS_REGISTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPI_REGISTER_TYPE))
+
+struct _SpiRegister
+{
+ GObject parent;
+
+ GHashTable * ref2ptr;
+ guint reference_counter;
+};
+
+struct _SpiRegisterClass
+{
+ GObjectClass parent_class;
+};
+
+GType spi_register_get_type (void);
+
+extern SpiRegister *spi_global_register;
+
+/*---------------------------------------------------------------------------*/
+
+GObject *
+spi_register_path_to_object (SpiRegister * reg, const char *path);
+
+GObject *
+spi_global_register_path_to_object (const char * path);
+
+gchar *
+spi_register_object_to_path (SpiRegister * reg, GObject * gobj);
+
+guint
+spi_register_object_to_ref (GObject * gobj);
+
+gchar *
+spi_register_root_object_path ();
+
+void
+spi_register_deregister_object (SpiRegister *reg, GObject *gobj, gboolean unref);
+
+/*---------------------------------------------------------------------------*/
+
+#endif /* ACCESSIBLE_REGISTER_H */
diff --git a/atk-adaptor/accessible-stateset.c b/atk-adaptor/accessible-stateset.c
new file mode 100644
index 0000000..3ab35ca
--- /dev/null
+++ b/atk-adaptor/accessible-stateset.c
@@ -0,0 +1,208 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* stateset.c : implements the StateSet interface */
+
+#include <config.h>
+#include <stdio.h>
+#include "accessible-stateset.h"
+#include "bitarray.h"
+
+
+static AtspiStateType *accessible_state_types = NULL;
+static AtkStateType *atk_state_types = NULL;
+
+
+static gboolean
+spi_init_state_type_tables (void)
+{
+ gint i;
+
+ if (accessible_state_types || atk_state_types)
+ return FALSE;
+ if (!accessible_state_types)
+ accessible_state_types = g_new (AtspiStateType, ATK_STATE_LAST_DEFINED);
+ if (!atk_state_types)
+ atk_state_types = g_new (AtkStateType, ATSPI_STATE_LAST_DEFINED);
+ g_return_val_if_fail (accessible_state_types, FALSE);
+ g_return_val_if_fail (atk_state_types, FALSE);
+
+ for (i = 0; i < ATSPI_STATE_LAST_DEFINED; i++)
+ {
+ atk_state_types[i] = ATK_STATE_INVALID;
+ }
+
+ for (i=0; i < ATK_STATE_LAST_DEFINED; i++)
+ {
+ accessible_state_types[i] = ATSPI_STATE_INVALID;
+ }
+
+ accessible_state_types[ATK_STATE_ACTIVE] = ATSPI_STATE_ACTIVE;
+ atk_state_types[ATSPI_STATE_ACTIVE] = ATK_STATE_ACTIVE;
+ accessible_state_types[ATK_STATE_ARMED] = ATSPI_STATE_ARMED;
+ atk_state_types[ATSPI_STATE_ARMED] = ATK_STATE_ARMED;
+ accessible_state_types[ATK_STATE_BUSY] = ATSPI_STATE_BUSY;
+ atk_state_types[ATSPI_STATE_BUSY] = ATK_STATE_BUSY;
+ accessible_state_types[ATK_STATE_CHECKED] = ATSPI_STATE_CHECKED;
+ atk_state_types[ATSPI_STATE_CHECKED] = ATK_STATE_CHECKED;
+ accessible_state_types[ATK_STATE_DEFUNCT] = ATSPI_STATE_DEFUNCT;
+ atk_state_types[ATSPI_STATE_DEFUNCT] = ATK_STATE_DEFUNCT;
+ accessible_state_types[ATK_STATE_EDITABLE] = ATSPI_STATE_EDITABLE;
+ atk_state_types[ATSPI_STATE_EDITABLE] = ATK_STATE_EDITABLE;
+ accessible_state_types[ATK_STATE_ENABLED] = ATSPI_STATE_ENABLED;
+ atk_state_types[ATSPI_STATE_ENABLED] = ATK_STATE_ENABLED;
+ accessible_state_types[ATK_STATE_EXPANDABLE] = ATSPI_STATE_EXPANDABLE;
+ atk_state_types[ATSPI_STATE_EXPANDABLE] = ATK_STATE_EXPANDABLE;
+ accessible_state_types[ATK_STATE_EXPANDED] = ATSPI_STATE_EXPANDED;
+ atk_state_types[ATSPI_STATE_EXPANDED] = ATK_STATE_EXPANDED;
+ accessible_state_types[ATK_STATE_FOCUSABLE] = ATSPI_STATE_FOCUSABLE;
+ atk_state_types[ATSPI_STATE_FOCUSABLE] = ATK_STATE_FOCUSABLE;
+ accessible_state_types[ATK_STATE_FOCUSED] = ATSPI_STATE_FOCUSED;
+ atk_state_types[ATSPI_STATE_FOCUSED] = ATK_STATE_FOCUSED;
+ accessible_state_types[ATK_STATE_HORIZONTAL] = ATSPI_STATE_HORIZONTAL;
+ atk_state_types[ATSPI_STATE_HORIZONTAL] = ATK_STATE_HORIZONTAL;
+ accessible_state_types[ATK_STATE_ICONIFIED] = ATSPI_STATE_ICONIFIED;
+ atk_state_types[ATSPI_STATE_ICONIFIED] = ATK_STATE_ICONIFIED;
+ accessible_state_types[ATK_STATE_MODAL] = ATSPI_STATE_MODAL;
+ atk_state_types[ATSPI_STATE_MODAL] = ATK_STATE_MODAL;
+ accessible_state_types[ATK_STATE_MULTI_LINE] = ATSPI_STATE_MULTI_LINE;
+ atk_state_types[ATSPI_STATE_MULTI_LINE] = ATK_STATE_MULTI_LINE;
+ accessible_state_types[ATK_STATE_MULTISELECTABLE] = ATSPI_STATE_MULTISELECTABLE;
+ atk_state_types[ATSPI_STATE_MULTISELECTABLE] = ATK_STATE_MULTISELECTABLE;
+ accessible_state_types[ATK_STATE_OPAQUE] = ATSPI_STATE_OPAQUE;
+ atk_state_types[ATSPI_STATE_OPAQUE] = ATK_STATE_OPAQUE;
+ accessible_state_types[ATK_STATE_PRESSED] = ATSPI_STATE_PRESSED;
+ atk_state_types[ATSPI_STATE_PRESSED] = ATK_STATE_PRESSED;
+ accessible_state_types[ATK_STATE_RESIZABLE] = ATSPI_STATE_RESIZABLE;
+ atk_state_types[ATSPI_STATE_RESIZABLE] = ATK_STATE_RESIZABLE;
+ accessible_state_types[ATK_STATE_SELECTABLE] = ATSPI_STATE_SELECTABLE;
+ atk_state_types[ATSPI_STATE_SELECTABLE] = ATK_STATE_SELECTABLE;
+ accessible_state_types[ATK_STATE_SELECTED] = ATSPI_STATE_SELECTED;
+ atk_state_types[ATSPI_STATE_SELECTED] = ATK_STATE_SELECTED;
+ accessible_state_types[ATK_STATE_SENSITIVE] = ATSPI_STATE_SENSITIVE;
+ atk_state_types[ATSPI_STATE_SENSITIVE] = ATK_STATE_SENSITIVE;
+ accessible_state_types[ATK_STATE_SHOWING] = ATSPI_STATE_SHOWING;
+ atk_state_types[ATSPI_STATE_SHOWING] = ATK_STATE_SHOWING;
+ accessible_state_types[ATK_STATE_SINGLE_LINE] = ATSPI_STATE_SINGLE_LINE;
+ atk_state_types[ATSPI_STATE_SINGLE_LINE] = ATK_STATE_SINGLE_LINE;
+ accessible_state_types[ATK_STATE_STALE] = ATSPI_STATE_STALE;
+ atk_state_types[ATSPI_STATE_STALE] = ATK_STATE_STALE;
+ accessible_state_types[ATK_STATE_TRANSIENT] = ATSPI_STATE_TRANSIENT;
+ atk_state_types[ATSPI_STATE_TRANSIENT] = ATK_STATE_TRANSIENT;
+ accessible_state_types[ATK_STATE_VERTICAL] = ATSPI_STATE_VERTICAL;
+ atk_state_types[ATSPI_STATE_VERTICAL] = ATK_STATE_VERTICAL;
+ accessible_state_types[ATK_STATE_VISIBLE] = ATSPI_STATE_VISIBLE;
+ atk_state_types[ATSPI_STATE_VISIBLE] = ATK_STATE_VISIBLE;
+ accessible_state_types[ATK_STATE_MANAGES_DESCENDANTS] = ATSPI_STATE_MANAGES_DESCENDANTS;
+ atk_state_types[ATSPI_STATE_MANAGES_DESCENDANTS] = ATK_STATE_MANAGES_DESCENDANTS;
+ accessible_state_types[ATK_STATE_INDETERMINATE] = ATSPI_STATE_INDETERMINATE;
+ atk_state_types[ATSPI_STATE_INDETERMINATE] = ATK_STATE_INDETERMINATE;
+ accessible_state_types[ATK_STATE_TRUNCATED] = ATSPI_STATE_TRUNCATED;
+ atk_state_types[ATSPI_STATE_TRUNCATED] = ATK_STATE_TRUNCATED;
+ accessible_state_types[ATK_STATE_REQUIRED] = ATSPI_STATE_REQUIRED;
+ atk_state_types[ATSPI_STATE_REQUIRED] = ATK_STATE_REQUIRED;
+ accessible_state_types[ATK_STATE_INVALID_ENTRY] = ATSPI_STATE_INVALID_ENTRY;
+ atk_state_types[ATSPI_STATE_INVALID_ENTRY] = ATK_STATE_INVALID_ENTRY;
+ accessible_state_types[ATK_STATE_SUPPORTS_AUTOCOMPLETION] = ATSPI_STATE_SUPPORTS_AUTOCOMPLETION;
+ atk_state_types[ATSPI_STATE_SUPPORTS_AUTOCOMPLETION] = ATK_STATE_SUPPORTS_AUTOCOMPLETION;
+ accessible_state_types[ATK_STATE_SELECTABLE_TEXT] = ATSPI_STATE_SELECTABLE_TEXT;
+ atk_state_types[ATSPI_STATE_SELECTABLE_TEXT] = ATK_STATE_SELECTABLE_TEXT;
+ accessible_state_types[ATK_STATE_DEFAULT] = ATSPI_STATE_IS_DEFAULT;
+ atk_state_types[ATSPI_STATE_IS_DEFAULT] = ATK_STATE_DEFAULT;
+ accessible_state_types[ATK_STATE_VISITED] = ATSPI_STATE_VISITED;
+ atk_state_types[ATSPI_STATE_VISITED] = ATK_STATE_VISITED;
+ accessible_state_types[ATK_STATE_HAS_POPUP] = ATSPI_STATE_HAS_POPUP;
+ atk_state_types[ATSPI_STATE_HAS_POPUP] = ATK_STATE_HAS_POPUP;
+ accessible_state_types[ATK_STATE_CHECKABLE] = ATSPI_STATE_CHECKABLE;
+ atk_state_types[ATSPI_STATE_CHECKABLE] = ATK_STATE_CHECKABLE;
+
+ return TRUE;
+}
+
+static inline AtkState
+state_spi_to_atk (AtspiStateType state)
+{
+ guint idx = state;
+ if (idx < ATSPI_STATE_LAST_DEFINED)
+ return atk_state_types [idx];
+ else
+ return ATK_STATE_INVALID;
+}
+
+AtkState
+spi_atk_state_from_spi_state (AtspiStateType state)
+{
+ spi_init_state_type_tables ();
+ return state_spi_to_atk (state);
+}
+
+AtkStateSet *
+spi_state_set_cache_from_sequence (GArray *seq)
+{
+ int i;
+ AtkStateSet *set;
+ AtkStateType *states;
+
+ spi_init_state_type_tables ();
+
+ states = g_newa (AtkStateType, seq->len);
+ for (i = 0; i < seq->len; i++)
+ states [i] = state_spi_to_atk (g_array_index (seq, dbus_int32_t, i));
+
+ set = atk_state_set_new ();
+ atk_state_set_add_states (set, states, seq->len);
+
+ g_array_free (seq, TRUE);
+ return set;
+}
+
+void
+spi_atk_state_to_dbus_array (AtkObject * object, dbus_uint32_t * array)
+{
+ AtkStateSet *set = atk_object_ref_state_set (object);
+ spi_atk_state_set_to_dbus_array (set, array);
+ g_object_unref (set);
+}
+
+void
+spi_atk_state_set_to_dbus_array (AtkStateSet * set, dbus_uint32_t * array)
+{
+ int i;
+
+ array[0] = 0;
+ array[1] = 0;
+ if (!set)
+ return;
+ spi_init_state_type_tables ();
+
+ g_assert (ATK_STATE_LAST_DEFINED <= 64);
+ for (i = 0; i < ATK_STATE_LAST_DEFINED; i++)
+ {
+ if (atk_state_set_contains_state (set, i))
+ {
+ int a = accessible_state_types[i];
+ g_assert (a < 64);
+ BITARRAY_SET (array, a);
+ }
+ }
+}
diff --git a/atk-adaptor/accessible-stateset.h b/atk-adaptor/accessible-stateset.h
new file mode 100644
index 0000000..e27e3c5
--- /dev/null
+++ b/atk-adaptor/accessible-stateset.h
@@ -0,0 +1,51 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ACCESSSIBLE_STATE_SET_H_
+#define ACCESSIBLE_STATE_SET_H_
+
+#include <atk/atkstateset.h>
+#include "atspi/atspi.h"
+
+G_BEGIN_DECLS
+
+/* private - internal API to abstract away atk API */
+AtkStateSet *spi_state_set_cache_from_sequence(GArray *seq);
+AtkState spi_atk_state_from_spi_state (AtspiStateType state);
+void spi_atk_state_to_dbus_array (AtkObject * object, dbus_uint32_t * array);
+void spi_atk_state_set_to_dbus_array (AtkStateSet *set, dbus_uint32_t * array);
+#define spi_state_set_cache_ref(s) g_object_ref (s)
+#define spi_state_set_cache_unref(s) g_object_unref (s)
+#define spi_state_set_cache_new(seq) spi_state_set_cache_from_sequence (seq)
+#define spi_state_set_cache_contains(s,a) atk_state_set_contains_state (ATK_STATE_SET (s), \
+ spi_atk_state_from_spi_state (a))
+#define spi_state_set_cache_add(s,a) atk_state_set_add_state (ATK_STATE_SET (s), \
+ spi_atk_state_from_spi_state (a))
+#define spi_state_set_cache_remove(s,a) atk_state_set_remove_state (ATK_STATE_SET (s), \
+ spi_atk_state_from_spi_state (a))
+#define spi_state_set_cache_xor(a,b) atk_state_set_xor_sets (ATK_STATE_SET (a), ATK_STATE_SET (b))
+#define spi_state_set_cache_is_empty(a) atk_state_set_is_empty (ATK_STATE_SET (a))
+
+G_END_DECLS
+
+#endif /* ACCESSIBLE_STATE_SET_H_ */
diff --git a/atk-adaptor/adaptors/Makefile.am b/atk-adaptor/adaptors/Makefile.am
new file mode 100644
index 0000000..7624b57
--- /dev/null
+++ b/atk-adaptor/adaptors/Makefile.am
@@ -0,0 +1,34 @@
+noinst_LTLIBRARIES = libatk-bridge-adaptors.la
+
+libatk_bridge_adaptors_la_CFLAGS =\
+ $(DBUS_CFLAGS) \
+ $(ATK_CFLAGS) \
+ $(ATSPI_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/atk-adaptor \
+ $(P2P_CFLAGS)
+
+libatk_bridge_adaptors_la_LIBADD =\
+ $(DBUS_LIBS) \
+ $(ATK_LIBS) \
+ $(ATSPI_LIBS)
+
+libatk_bridge_adaptors_la_SOURCES =\
+ accessible-adaptor.c \
+ action-adaptor.c \
+ adaptors.h \
+ application-adaptor.c \
+ cache-adaptor.c \
+ collection-adaptor.c \
+ component-adaptor.c \
+ document-adaptor.c \
+ editabletext-adaptor.c \
+ hyperlink-adaptor.c \
+ hypertext-adaptor.c \
+ image-adaptor.c \
+ selection-adaptor.c \
+ socket-adaptor.c \
+ table-adaptor.c \
+ table-cell-adaptor.c \
+ text-adaptor.c \
+ value-adaptor.c
diff --git a/atk-adaptor/adaptors/accessible-adaptor.c b/atk-adaptor/adaptors/accessible-adaptor.c
new file mode 100644
index 0000000..058b116
--- /dev/null
+++ b/atk-adaptor/adaptors/accessible-adaptor.c
@@ -0,0 +1,558 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "atspi/atspi.h"
+#include "spi-dbus.h"
+#include "accessible-stateset.h"
+#include "object.h"
+#include "introspection.h"
+#include <string.h>
+
+static dbus_bool_t
+impl_get_Name (DBusMessageIter * iter, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
+
+ return droute_return_v_string (iter, atk_object_get_name (object));
+}
+
+static dbus_bool_t
+impl_get_Description (DBusMessageIter * iter, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
+
+ return droute_return_v_string (iter, atk_object_get_description (object));
+}
+
+static dbus_bool_t
+impl_get_Locale (DBusMessageIter * iter, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
+
+ return droute_return_v_string (iter, atk_object_get_object_locale (object));
+}
+
+static dbus_bool_t
+impl_get_Parent (DBusMessageIter * iter, void *user_data)
+{
+ AtkObject *obj = (AtkObject *) user_data;
+ AtkObject *parent;
+ DBusMessageIter iter_variant;
+ dbus_uint32_t role;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
+
+ role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
+ &iter_variant);
+
+ parent = atk_object_get_parent (obj);
+ if (parent == NULL)
+ {
+ /* TODO, move in to a 'Plug' wrapper. */
+ if (ATK_IS_PLUG (obj))
+ {
+ char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
+ char *bus_parent;
+ char *path_parent;
+
+ if (id)
+ {
+ bus_parent = g_strdup (id);
+ if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
+ {
+ DBusMessageIter iter_parent;
+ *(path_parent++) = '\0';
+ dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
+ &iter_parent);
+ dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
+ dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
+ dbus_message_iter_close_container (&iter_variant, &iter_parent);
+ }
+ else
+ {
+ spi_object_append_null_reference (&iter_variant);
+ }
+ }
+ else
+ {
+ spi_object_append_null_reference (&iter_variant);
+ }
+ }
+ else if (role != ATSPI_ROLE_APPLICATION)
+ spi_object_append_null_reference (&iter_variant);
+ else
+ spi_object_append_desktop_reference (&iter_variant);
+ }
+ else
+ {
+ spi_object_append_reference (&iter_variant, parent);
+ }
+
+
+ dbus_message_iter_close_container (iter, &iter_variant);
+ return TRUE;
+}
+
+static dbus_bool_t
+impl_get_ChildCount (DBusMessageIter * iter, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ int childCount;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
+
+ childCount = (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)))
+ ? 1
+ : atk_object_get_n_accessible_children (object);
+ return droute_return_v_int32 (iter, childCount);
+}
+
+static DBusMessage *
+impl_GetChildAtIndex (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ DBusMessage *reply;
+ dbus_int32_t i;
+ AtkObject *child;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ if (ATK_IS_SOCKET (object) && atk_socket_is_occupied (ATK_SOCKET (object)) && i == 0)
+ {
+ AtkSocket *socket = ATK_SOCKET (object);
+ gchar *child_name, *child_path;
+ child_name = g_strdup (socket->embedded_plug_id);
+ child_path = g_utf8_strchr (child_name + 1, -1, ':');
+ if (child_path)
+ {
+ DBusMessageIter iter, iter_socket;
+ *(child_path++) = '\0';
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ return NULL;
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_STRUCT, NULL,
+ &iter_socket);
+ dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
+ dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
+ dbus_message_iter_close_container (&iter, &iter_socket);
+ return reply;
+ }
+ g_free (child_name);
+ }
+ child = atk_object_ref_accessible_child (object, i);
+ reply = spi_object_return_reference (message, child);
+ g_object_unref (child);
+
+ return reply;
+}
+
+static DBusMessage *
+impl_GetChildren (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ gint i;
+ gint count;
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ count = atk_object_get_n_accessible_children (object);
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ goto oom;
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
+ goto oom;
+ for (i = 0; i < count; i++)
+ {
+ AtkObject *child = atk_object_ref_accessible_child (object, i);
+ spi_object_append_reference (&iter_array, child);
+ if (child)
+ g_object_unref (child);
+ }
+ if (!dbus_message_iter_close_container (&iter, &iter_array))
+ goto oom;
+ return reply;
+oom:
+ // TODO: handle out-of-memory
+ return reply;
+}
+
+static DBusMessage *
+impl_GetIndexInParent (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ dbus_int32_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_object_get_index_in_parent (object);
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static gboolean
+spi_init_relation_type_table (AtspiRelationType * types)
+{
+ gint i;
+
+ for (i = 0; i < ATK_RELATION_LAST_DEFINED; i++)
+ types[i] = ATSPI_RELATION_NULL;
+
+ types[ATK_RELATION_CONTROLLED_BY] = ATSPI_RELATION_CONTROLLED_BY;
+ types[ATK_RELATION_CONTROLLER_FOR] = ATSPI_RELATION_CONTROLLER_FOR;
+ types[ATK_RELATION_LABEL_FOR] = ATSPI_RELATION_LABEL_FOR;
+ types[ATK_RELATION_LABELLED_BY] = ATSPI_RELATION_LABELLED_BY;
+ types[ATK_RELATION_MEMBER_OF] = ATSPI_RELATION_MEMBER_OF;
+ types[ATK_RELATION_NODE_CHILD_OF] = ATSPI_RELATION_NODE_CHILD_OF;
+ types[ATK_RELATION_FLOWS_TO] = ATSPI_RELATION_FLOWS_TO;
+ types[ATK_RELATION_FLOWS_FROM] = ATSPI_RELATION_FLOWS_FROM;
+ types[ATK_RELATION_SUBWINDOW_OF] = ATSPI_RELATION_SUBWINDOW_OF;
+ types[ATK_RELATION_EMBEDS] = ATSPI_RELATION_EMBEDS;
+ types[ATK_RELATION_EMBEDDED_BY] = ATSPI_RELATION_EMBEDDED_BY;
+ types[ATK_RELATION_POPUP_FOR] = ATSPI_RELATION_POPUP_FOR;
+ types[ATK_RELATION_PARENT_WINDOW_OF] =
+ ATSPI_RELATION_PARENT_WINDOW_OF;
+ types[ATK_RELATION_DESCRIPTION_FOR] =
+ ATSPI_RELATION_DESCRIPTION_FOR;
+ types[ATK_RELATION_DESCRIBED_BY] = ATSPI_RELATION_DESCRIBED_BY;
+ types[ATK_RELATION_NODE_PARENT_OF] = ATSPI_RELATION_NODE_PARENT_OF;
+
+ return TRUE;
+}
+
+static AtspiRelationType
+spi_relation_type_from_atk_relation_type (AtkRelationType type)
+{
+ static gboolean is_initialized = FALSE;
+ static AtspiRelationType
+ spi_relation_type_table[ATK_RELATION_LAST_DEFINED];
+ AtspiRelationType spi_type;
+
+ if (!is_initialized)
+ is_initialized = spi_init_relation_type_table (spi_relation_type_table);
+
+ if (type > ATK_RELATION_NULL && type < ATK_RELATION_LAST_DEFINED)
+ spi_type = spi_relation_type_table[type];
+ else
+ spi_type = ATSPI_RELATION_EXTENDED;
+ return spi_type;
+}
+
+static DBusMessage *
+impl_GetRelationSet (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ DBusMessage *reply;
+ AtkRelationSet *set;
+ DBusMessageIter iter, iter_array, iter_struct, iter_targets;
+ gint count;
+ gint i, j;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ return NULL;
+ set = atk_object_ref_relation_set (object);
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "(ua(so))", &iter_array))
+ {
+ goto oom;
+ }
+ count = 0;
+ if (set)
+ count = atk_relation_set_get_n_relations (set);
+ for (i = 0; i < count; i++)
+ {
+ AtkRelation *r = atk_relation_set_get_relation (set, i);
+ AtkRelationType rt;
+ GPtrArray *target;
+ dbus_uint32_t type;
+ if (!r)
+ continue;
+ rt = atk_relation_get_relation_type (r);
+ type = spi_relation_type_from_atk_relation_type (rt);
+ target = atk_relation_get_target (r);
+ if (!dbus_message_iter_open_container
+ (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
+ {
+ goto oom;
+ }
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &type);
+ if (!dbus_message_iter_open_container
+ (&iter_struct, DBUS_TYPE_ARRAY, "(so)", &iter_targets))
+ {
+ goto oom;
+ }
+ for (j = 0; j < target->len; j++)
+ {
+ AtkObject *obj = target->pdata[j];
+ if (!obj)
+ continue;
+ spi_object_append_reference (&iter_targets, obj);
+ }
+ dbus_message_iter_close_container (&iter_struct, &iter_targets);
+ dbus_message_iter_close_container (&iter_array, &iter_struct);
+ }
+ dbus_message_iter_close_container (&iter, &iter_array);
+oom:
+ if (set)
+ g_object_unref (set);
+ // TODO: handle out of memory */
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRole (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ gint role;
+ dbus_uint32_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ role = atk_object_get_role (object);
+ rv = spi_accessible_role_from_atk_role (role);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRoleName (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ gint role;
+ const char *role_name;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ role = atk_object_get_role (object);
+ role_name = atk_role_get_name (role);
+ if (!role_name)
+ role_name = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetLocalizedRoleName (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ gint role;
+ const char *role_name;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ role = atk_object_get_role (object);
+ role_name = atk_role_get_localized_name (role);
+ if (!role_name)
+ role_name = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &role_name,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetState (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, iter_array;
+
+ dbus_uint32_t states[2];
+
+ guint count;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+
+ spi_atk_state_to_dbus_array (object, states);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array);
+ for (count = 0; count < 2; count++)
+ {
+ dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32,
+ &states[count]);
+ }
+ dbus_message_iter_close_container (&iter, &iter_array);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAttributes (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ AtkAttributeSet *attributes;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+
+ attributes = atk_object_get_attributes (object);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_attribute_set (&iter, attributes);
+
+ atk_attribute_set_free (attributes);
+
+ return reply;
+}
+
+static dbus_bool_t
+impl_get_Attributes (DBusMessageIter * iter, void *user_data)
+{
+ DBusMessageIter iter_variant;
+ AtkObject *object = (AtkObject *) user_data;
+ AtkAttributeSet *attributes;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data), FALSE);
+
+ attributes = atk_object_get_attributes (object);
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "a{ss}", &iter_variant);
+ spi_object_append_attribute_set (&iter_variant, attributes);
+ dbus_message_iter_close_container (iter, &iter_variant);
+
+ atk_attribute_set_free (attributes);
+
+ return TRUE;
+}
+
+static DBusMessage *
+impl_GetApplication (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ return spi_object_return_reference (message, atk_get_root ());
+}
+
+static DBusMessage *
+impl_GetInterfaces (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s",
+ &iter_array);
+ spi_object_append_interfaces (&iter_array, object);
+ dbus_message_iter_close_container (&iter, &iter_array);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetChildAtIndex, "GetChildAtIndex"},
+ {impl_GetChildren, "GetChildren"},
+ {impl_GetIndexInParent, "GetIndexInParent"},
+ {impl_GetRelationSet, "GetRelationSet"},
+ {impl_GetRole, "GetRole"},
+ {impl_GetRoleName, "GetRoleName"},
+ {impl_GetLocalizedRoleName, "GetLocalizedRoleName"},
+ {impl_GetState, "GetState"},
+ {impl_GetAttributes, "GetAttributes"},
+ {impl_GetApplication, "GetApplication"},
+ {impl_GetInterfaces, "GetInterfaces"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_Name, NULL, "Name"},
+ {impl_get_Description, NULL, "Description"},
+ {impl_get_Locale, NULL, "Locale"},
+ {impl_get_Parent, NULL, "Parent"},
+ {impl_get_ChildCount, NULL, "ChildCount"},
+ {impl_get_Attributes, NULL, "Attributes"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_accessible (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_ACCESSIBLE,
+ spi_org_a11y_atspi_Accessible,
+ methods, properties);
+};
diff --git a/atk-adaptor/adaptors/action-adaptor.c b/atk-adaptor/adaptors/action-adaptor.c
new file mode 100644
index 0000000..a6c409d
--- /dev/null
+++ b/atk-adaptor/adaptors/action-adaptor.c
@@ -0,0 +1,257 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_NActions (DBusMessageIter * iter, void *user_data)
+{
+ AtkAction *action = (AtkAction *) user_data;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_action_get_n_actions (action));
+}
+
+static DBusMessage *
+impl_get_description (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkAction *action = (AtkAction *) user_data;
+ DBusMessage *reply;
+ dbus_int32_t index;
+ const char *desc;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ desc = atk_action_get_description (action, index);
+ if (!desc)
+ desc = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &desc,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_get_name (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ DBusMessage *reply;
+ dbus_int32_t index;
+ const char *name;
+ AtkAction *action = (AtkAction *) user_data;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ name = atk_action_get_name (action, index);
+ if (!name)
+ name = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_get_localized_name (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ DBusMessage *reply;
+ dbus_int32_t index;
+ const char *name;
+ AtkAction *action = (AtkAction *) user_data;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ name = atk_action_get_localized_name (action, index);
+ if (!name)
+ name = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_get_keybinding (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ DBusMessage *reply;
+ dbus_int32_t index;
+ const char *kb;
+ AtkAction *action = (AtkAction *) user_data;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ kb = atk_action_get_keybinding (action, index);
+ if (!kb)
+ kb = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &kb,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetActions (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkAction *action = (AtkAction *) user_data;
+ DBusMessage *reply;
+ gint count;
+ gint i;
+ DBusMessageIter iter, iter_array, iter_struct;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data),
+ droute_not_yet_handled_error (message));
+ count = atk_action_get_n_actions (action);
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ goto oom;
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "(sss)", &iter_array))
+ goto oom;
+ for (i = 0; i < count; i++)
+ {
+ const char *name = atk_action_get_name (action, i);
+ const char *lname = atk_action_get_localized_name (action, i);
+ const char *desc = atk_action_get_description (action, i);
+ const char *kb = atk_action_get_keybinding (action, i);
+ if (!name)
+ name = "";
+ if (!lname)
+ lname = "";
+ if (!desc)
+ desc = "";
+ if (!kb)
+ kb = "";
+ if (!dbus_message_iter_open_container
+ (&iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct))
+ goto oom;
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &lname);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &kb);
+ if (!dbus_message_iter_close_container (&iter_array, &iter_struct))
+ goto oom;
+ }
+ if (!dbus_message_iter_close_container (&iter, &iter_array))
+ goto oom;
+ return reply;
+oom:
+ // TODO: handle out-of-memory
+ return reply;
+}
+
+static DBusMessage *
+impl_DoAction (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkAction *action = (AtkAction *) user_data;
+ dbus_int32_t index;
+ dbus_bool_t rv = TRUE;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_ACTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ dbus_connection_send (bus, reply, NULL);
+ dbus_message_unref (reply);
+ atk_action_do_action (action, index);
+ return NULL;
+}
+
+DRouteMethod methods[] = {
+ {impl_get_description, "GetDescription"}
+ ,
+ {impl_get_name, "GetName"}
+ ,
+ {impl_get_localized_name, "GetLocalizedName"}
+ ,
+ {impl_get_keybinding, "GetKeyBinding"}
+ ,
+ {impl_GetActions, "GetActions"}
+ ,
+ {impl_DoAction, "DoAction"}
+ ,
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_NActions, NULL, "NActions"},
+ {NULL, NULL}
+};
+
+void
+spi_initialize_action (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_ACTION,
+ spi_org_a11y_atspi_Action, methods, properties);
+};
diff --git a/atk-adaptor/adaptors/adaptors.h b/atk-adaptor/adaptors/adaptors.h
new file mode 100644
index 0000000..395114b
--- /dev/null
+++ b/atk-adaptor/adaptors/adaptors.h
@@ -0,0 +1,50 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ADAPTORS_H
+#define ADAPTORS_H
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+AtspiRole spi_accessible_role_from_atk_role (AtkRole role);
+
+void spi_initialize_accessible (DRoutePath * path);
+void spi_initialize_action (DRoutePath * path);
+void spi_initialize_application (DRoutePath * path);
+void spi_initialize_collection (DRoutePath * path);
+void spi_initialize_component (DRoutePath * path);
+void spi_initialize_document (DRoutePath * path);
+void spi_initialize_editabletext (DRoutePath * path);
+void spi_initialize_hyperlink (DRoutePath * path);
+void spi_initialize_hypertext (DRoutePath * path);
+void spi_initialize_image (DRoutePath * path);
+void spi_initialize_selection (DRoutePath * path);
+void spi_initialize_socket (DRoutePath * path);
+void spi_initialize_table (DRoutePath * path);
+void spi_initialize_table_cell (DRoutePath * path);
+void spi_initialize_text (DRoutePath * path);
+void spi_initialize_value (DRoutePath * path);
+void spi_initialize_cache (DRoutePath * path);
+
+#endif /* ADAPTORS_H */
diff --git a/atk-adaptor/adaptors/application-adaptor.c b/atk-adaptor/adaptors/application-adaptor.c
new file mode 100644
index 0000000..b74e5be
--- /dev/null
+++ b/atk-adaptor/adaptors/application-adaptor.c
@@ -0,0 +1,156 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+#include "spi-dbus.h"
+#include "introspection.h"
+
+/* for spi_global_app_data is there a better way? */
+#include "../bridge.h"
+
+static dbus_bool_t
+impl_get_ToolkitName (DBusMessageIter * iter, void *user_data)
+{
+ return droute_return_v_string (iter, atk_get_toolkit_name ());
+}
+
+static dbus_bool_t
+impl_get_Version (DBusMessageIter * iter, void *user_data)
+{
+ return droute_return_v_string (iter, atk_get_toolkit_version ());
+}
+
+static dbus_bool_t
+impl_get_AtspiVersion (DBusMessageIter * iter, void *user_data)
+{
+ return droute_return_v_string (iter, "2.0");
+}
+
+static dbus_int32_t id;
+
+static dbus_bool_t
+impl_get_Id (DBusMessageIter * iter, void *user_data)
+{
+ return droute_return_v_int32 (iter, id);
+}
+
+static dbus_bool_t
+impl_set_Id (DBusMessageIter * iter, void *user_data)
+{
+ id = droute_get_v_int32 (iter);
+ return TRUE;
+}
+
+static DBusMessage *
+impl_registerToolkitEventListener (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ return NULL;
+}
+
+static DBusMessage *
+impl_registerObjectEventListener (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ return NULL;
+}
+
+static DBusMessage *
+impl_pause (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ return NULL;
+}
+
+static DBusMessage *
+impl_resume (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ return NULL;
+}
+
+static DBusMessage *
+impl_GetLocale (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ return NULL;
+}
+
+static DBusMessage *
+impl_get_app_bus(DBusConnection *bus, DBusMessage *msg, void *data)
+{
+DBusMessage *reply;
+
+ if (bus == spi_global_app_data->bus)
+ spi_atk_add_client (dbus_message_get_sender (msg));
+
+ if (!spi_global_app_data->app_bus_addr)
+ spi_atk_create_socket (spi_global_app_data);
+
+reply = dbus_message_new_method_return(msg);
+if (reply)
+ {
+ const char *retval = (atspi_is_initialized () ?
+ "":
+ spi_global_app_data->app_bus_addr);
+ if (!retval)
+ retval = "";
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &retval, DBUS_TYPE_INVALID);
+ }
+
+return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_registerToolkitEventListener, "registerToolkitEventListener"},
+ {impl_registerObjectEventListener, "registerObjectEventListener"},
+ {impl_pause, "pause"},
+ {impl_resume, "resume"},
+ {impl_GetLocale, "GetLocale"},
+ {impl_get_app_bus, "GetApplicationBusAddress"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_ToolkitName, NULL, "ToolkitName"},
+ {impl_get_Version, NULL, "Version"},
+ {impl_get_AtspiVersion, NULL, "AtspiVersion"},
+ {impl_get_Id, impl_set_Id, "Id"},
+ {NULL, NULL, NULL}
+};
+
+/*static long
+obj_is_root (const char *path, void *user_data)
+{
+ AtkObject *obj = atk_dbus_get_object (path);
+ return (obj == atk_get_root ());
+}*/
+
+void
+spi_initialize_application (DRoutePath * path)
+{
+ droute_path_add_interface (path,
+ ATSPI_DBUS_INTERFACE_APPLICATION,
+ spi_org_a11y_atspi_Application,
+ methods, properties);
+};
diff --git a/atk-adaptor/adaptors/cache-adaptor.c b/atk-adaptor/adaptors/cache-adaptor.c
new file mode 100644
index 0000000..cad7396
--- /dev/null
+++ b/atk-adaptor/adaptors/cache-adaptor.c
@@ -0,0 +1,345 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ * Copyright 2008, 2009 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+#include "spi-dbus.h"
+#include "accessible-stateset.h"
+#include "accessible-cache.h"
+#include "bridge.h"
+#include "object.h"
+#include "introspection.h"
+
+/* TODO - This should possibly be a common define */
+#define SPI_OBJECT_PREFIX "/org/a11y/atspi"
+#define SPI_CACHE_OBJECT_SUFFIX "/cache"
+#define SPI_CACHE_OBJECT_PATH SPI_OBJECT_PREFIX SPI_CACHE_OBJECT_SUFFIX
+
+#define SPI_OBJECT_REFERENCE_SIGNATURE "(" \
+ DBUS_TYPE_STRING_AS_STRING \
+ DBUS_TYPE_OBJECT_PATH_AS_STRING \
+ ")"
+
+#define SPI_CACHE_ITEM_SIGNATURE "(" \
+ SPI_OBJECT_REFERENCE_SIGNATURE \
+ SPI_OBJECT_REFERENCE_SIGNATURE \
+ SPI_OBJECT_REFERENCE_SIGNATURE \
+ DBUS_TYPE_ARRAY_AS_STRING \
+ SPI_OBJECT_REFERENCE_SIGNATURE \
+ DBUS_TYPE_ARRAY_AS_STRING \
+ DBUS_TYPE_STRING_AS_STRING \
+ DBUS_TYPE_STRING_AS_STRING \
+ DBUS_TYPE_UINT32_AS_STRING \
+ DBUS_TYPE_STRING_AS_STRING \
+ DBUS_TYPE_ARRAY_AS_STRING \
+ DBUS_TYPE_UINT32_AS_STRING \
+ ")"
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Marshals the given AtkObject into the provided D-Bus iterator.
+ *
+ * The object is marshalled including all its client side cache data.
+ * The format of the structure is (o(so)a(so)assusau).
+ */
+static void
+append_cache_item (AtkObject * obj, gpointer data)
+{
+ DBusMessageIter iter_struct, iter_sub_array;
+ dbus_uint32_t states[2];
+ int count;
+ AtkStateSet *set;
+ DBusMessageIter *iter_array = (DBusMessageIter *) data;
+
+ const char *name, *desc;
+ dbus_uint32_t role;
+
+ set = atk_object_ref_state_set (obj);
+ {
+ AtkObject *application, *parent;
+
+ dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL,
+ &iter_struct);
+
+ /* Marshall object path */
+ spi_object_append_reference (&iter_struct, obj);
+
+ role = spi_accessible_role_from_atk_role (atk_object_get_role (obj));
+
+ /* Marshall application */
+ application = spi_global_app_data->root;
+ spi_object_append_reference (&iter_struct, application);
+
+ /* Marshall parent */
+ parent = atk_object_get_parent (obj);
+ if (parent == NULL)
+ {
+ /* TODO, move in to a 'Plug' wrapper. */
+ if (ATK_IS_PLUG (obj))
+ {
+ char *id = g_object_get_data (G_OBJECT (obj), "dbus-plug-parent");
+ char *bus_parent;
+ char *path_parent;
+
+ if (id)
+ {
+ bus_parent = g_strdup (id);
+ if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
+ {
+ DBusMessageIter iter_parent;
+ *(path_parent++) = '\0';
+ dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL,
+ &iter_parent);
+ dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_STRING, &bus_parent);
+ dbus_message_iter_append_basic (&iter_parent, DBUS_TYPE_OBJECT_PATH, &path_parent);
+ dbus_message_iter_close_container (&iter_struct, &iter_parent);
+ }
+ else
+ {
+ spi_object_append_null_reference (&iter_struct);
+ }
+ }
+ else
+ {
+ spi_object_append_null_reference (&iter_struct);
+ }
+ }
+ else if (role != ATSPI_ROLE_APPLICATION)
+ spi_object_append_null_reference (&iter_struct);
+ else
+ spi_object_append_desktop_reference (&iter_struct);
+ }
+ else
+ {
+ spi_object_append_reference (&iter_struct, parent);
+ }
+
+ /* Marshall children */
+ dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "(so)",
+ &iter_sub_array);
+ if (!atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS) &&
+ !atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
+ {
+ gint childcount, i;
+
+ childcount = atk_object_get_n_accessible_children (obj);
+ for (i = 0; i < childcount; i++)
+ {
+ AtkObject *child;
+
+ child = atk_object_ref_accessible_child (obj, i);
+ if (child)
+ {
+ spi_object_append_reference (&iter_sub_array, child);
+ g_object_unref (G_OBJECT (child));
+ }
+ }
+ }
+ if (ATK_IS_SOCKET (obj) && atk_socket_is_occupied (ATK_SOCKET (obj)))
+ {
+ AtkSocket *socket = ATK_SOCKET (obj);
+ gchar *child_name, *child_path;
+ child_name = g_strdup (socket->embedded_plug_id);
+ child_path = g_utf8_strchr (child_name + 1, -1, ':');
+ if (child_path)
+ {
+ DBusMessageIter iter_socket;
+ *(child_path++) = '\0';
+ dbus_message_iter_open_container (&iter_sub_array, DBUS_TYPE_STRUCT, NULL,
+ &iter_socket);
+ dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_STRING, &child_name);
+ dbus_message_iter_append_basic (&iter_socket, DBUS_TYPE_OBJECT_PATH, &child_path);
+ dbus_message_iter_close_container (&iter_sub_array, &iter_socket);
+ }
+ g_free (child_name);
+ }
+
+ dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
+
+ /* Marshall interfaces */
+ dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
+ &iter_sub_array);
+ spi_object_append_interfaces (&iter_sub_array, obj);
+ dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
+
+ /* Marshall name */
+ name = atk_object_get_name (obj);
+ if (!name)
+ name = "";
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
+
+ /* Marshall role */
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role);
+
+ /* Marshall description */
+ desc = atk_object_get_description (obj);
+ if (!desc)
+ desc = "";
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc);
+
+ /* Marshall state set */
+ spi_atk_state_set_to_dbus_array (set, states);
+ dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u",
+ &iter_sub_array);
+ for (count = 0; count < 2; count++)
+ {
+ dbus_message_iter_append_basic (&iter_sub_array, DBUS_TYPE_UINT32,
+ &states[count]);
+ }
+ dbus_message_iter_close_container (&iter_struct, &iter_sub_array);
+ }
+ dbus_message_iter_close_container (iter_array, &iter_struct);
+ g_object_unref (set);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+ref_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
+{
+ g_object_ref (key);
+}
+
+/* For use as a GHFunc */
+static void
+append_accessible_hf (gpointer key, gpointer obj_data, gpointer data)
+{
+ /* Make sure it isn't a hyperlink */
+ if (ATK_IS_OBJECT (key))
+ append_cache_item (ATK_OBJECT (key), data);
+}
+
+static void
+add_to_list_hf (gpointer key, gpointer obj_data, gpointer data)
+{
+ GSList **listptr = data;
+ *listptr = g_slist_prepend (*listptr, key);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+emit_cache_remove (SpiCache *cache, GObject * obj)
+{
+ DBusMessage *message;
+
+ if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
+ ATSPI_DBUS_INTERFACE_CACHE,
+ "RemoveAccessible")))
+ {
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append (message, &iter);
+
+ spi_object_append_reference (&iter, ATK_OBJECT (obj));
+
+ dbus_connection_send (spi_global_app_data->bus, message, NULL);
+
+ dbus_message_unref (message);
+ }
+}
+
+static void
+emit_cache_add (SpiCache *cache, GObject * obj)
+{
+ AtkObject *accessible = ATK_OBJECT (obj);
+ DBusMessage *message;
+
+ if ((message = dbus_message_new_signal (SPI_CACHE_OBJECT_PATH,
+ ATSPI_DBUS_INTERFACE_CACHE,
+ "AddAccessible")))
+ {
+ DBusMessageIter iter;
+
+ dbus_message_iter_init_append (message, &iter);
+ g_object_ref (accessible);
+ append_cache_item (accessible, &iter);
+ g_object_unref (accessible);
+
+ dbus_connection_send (spi_global_app_data->bus, message, NULL);
+
+ dbus_message_unref (message);
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static DBusMessage *
+impl_GetRoot (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ return spi_object_return_reference (message, spi_global_app_data->root);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusMessage *
+impl_GetItems (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+ GSList *pending_unrefs = NULL;
+
+ if (bus == spi_global_app_data->bus)
+ spi_atk_add_client (dbus_message_get_sender (message));
+
+ reply = dbus_message_new_method_return (message);
+
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
+ SPI_CACHE_ITEM_SIGNATURE, &iter_array);
+ spi_cache_foreach (spi_global_cache, ref_accessible_hf, NULL);
+ spi_cache_foreach (spi_global_cache, append_accessible_hf, &iter_array);
+ spi_cache_foreach (spi_global_cache, add_to_list_hf, &pending_unrefs);
+ g_slist_free_full (pending_unrefs, g_object_unref);
+ dbus_message_iter_close_container (&iter, &iter_array);
+ return reply;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DRouteMethod methods[] = {
+ {impl_GetRoot, "GetRoot"},
+ {impl_GetItems, "GetItems"},
+ {NULL, NULL}
+};
+
+void
+spi_initialize_cache (DRoutePath * path)
+{
+ droute_path_add_interface (path, ATSPI_DBUS_INTERFACE_CACHE, spi_org_a11y_atspi_Cache, methods, NULL);
+
+ g_signal_connect (spi_global_cache, "object-added",
+ (GCallback) emit_cache_add, NULL);
+
+ g_signal_connect (spi_global_cache, "object-removed",
+ (GCallback) emit_cache_remove, NULL);
+};
+
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/adaptors/collection-adaptor.c b/atk-adaptor/adaptors/collection-adaptor.c
new file mode 100644
index 0000000..97016b7
--- /dev/null
+++ b/atk-adaptor/adaptors/collection-adaptor.c
@@ -0,0 +1,1347 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2007 IBM Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* collection.c: implements the Collection interface */
+
+#include <string.h>
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "bitarray.h"
+#include "spi-dbus.h"
+#include "accessible-stateset.h"
+
+#include "accessible-register.h"
+#include "object.h"
+#include "introspection.h"
+
+typedef struct _MatchRulePrivate MatchRulePrivate;
+struct _MatchRulePrivate
+{
+ gint *states;
+ AtspiCollectionMatchType statematchtype;
+ AtkAttributeSet *attributes;
+ AtspiCollectionMatchType attributematchtype;
+ gint *roles;
+ AtspiCollectionMatchType rolematchtype;
+ gchar **ifaces;
+ AtspiCollectionMatchType interfacematchtype;
+ gboolean invert;
+};
+
+static gboolean
+child_interface_p (AtkObject * child, gchar * repo_id)
+{
+ if (!strcasecmp (repo_id, "action"))
+ return ATK_IS_ACTION (child);
+ if (!strcasecmp (repo_id, "component"))
+ return ATK_IS_COMPONENT (child);
+ if (!strcasecmp (repo_id, "editabletext"))
+ return ATK_IS_EDITABLE_TEXT (child);
+ if (!strcasecmp (repo_id, "text"))
+ return ATK_IS_TEXT (child);
+ if (!strcasecmp (repo_id, "hypertext"))
+ return ATK_IS_HYPERTEXT (child);
+ if (!strcasecmp (repo_id, "image"))
+ return ATK_IS_IMAGE (child);
+ if (!strcasecmp (repo_id, "selection"))
+ return ATK_IS_SELECTION (child);
+ if (!strcasecmp (repo_id, "table"))
+ return ATK_IS_TABLE (child);
+ if (!strcasecmp (repo_id, "value"))
+ return ATK_IS_VALUE (child);
+ if (!strcasecmp (repo_id, "streamablecontent"))
+ return ATK_IS_STREAMABLE_CONTENT (child);
+ if (!strcasecmp (repo_id, "document"))
+ return ATK_IS_DOCUMENT (child);
+ return FALSE;
+}
+
+#define child_collection_p(ch) (TRUE)
+
+static gboolean
+match_states_all_p (AtkObject * child, gint * set)
+{
+ AtkStateSet *chs;
+ gint i;
+ gboolean ret = TRUE;
+
+ if (set == NULL || set[0] == BITARRAY_SEQ_TERM)
+ return TRUE;
+
+ chs = atk_object_ref_state_set (child);
+
+ // TODO: use atk-state_set_contains_states; would be more efficient
+ for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ if (!atk_state_set_contains_state (chs, set[i]))
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ g_object_unref (chs);
+ return ret;
+}
+
+static gboolean
+match_states_any_p (AtkObject * child, gint * set)
+{
+ AtkStateSet *chs;
+ gint i;
+ gboolean ret = FALSE;
+
+ if (set == NULL || set[0] == BITARRAY_SEQ_TERM)
+ return TRUE;
+
+ chs = atk_object_ref_state_set (child);
+
+ for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ if (atk_state_set_contains_state (chs, set[i]))
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ g_object_unref (chs);
+ return ret;
+}
+
+static gboolean
+match_states_none_p (AtkObject * child, gint * set)
+{
+ AtkStateSet *chs;
+ gint i;
+ gboolean ret = TRUE;
+
+ if (set == NULL || set[0] == BITARRAY_SEQ_TERM)
+ return TRUE;
+
+ chs = atk_object_ref_state_set (child);
+
+ for (i = 0; set[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ if (atk_state_set_contains_state (chs, set[i]))
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ g_object_unref (chs);
+ return ret;
+}
+
+// TODO: need to convert at-spi roles/states to atk roles/states */
+static gboolean
+match_states_lookup (AtkObject * child, MatchRulePrivate * mrp)
+{
+ switch (mrp->statematchtype)
+ {
+ case ATSPI_Collection_MATCH_ALL:
+ if (match_states_all_p (child, mrp->states))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_ANY:
+ if (match_states_any_p (child, mrp->states))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_NONE:
+ if (match_states_none_p (child, mrp->states))
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+// TODO: Map at-spi -> atk roles at mrp creation instead of doing this;
+// would be more efficient
+#define spi_get_role(obj) spi_accessible_role_from_atk_role(atk_object_get_role(obj))
+
+static gboolean
+match_roles_all_p (AtkObject * child, gint * roles)
+{
+ if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
+ return TRUE;
+ else if (roles[1] != BITARRAY_SEQ_TERM)
+ return FALSE;
+
+ return (atk_object_get_role (child) == roles[0]);
+
+}
+
+static gboolean
+match_roles_any_p (AtkObject * child, gint * roles)
+{
+ AtspiRole role;
+ int i;
+
+ if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
+ return TRUE;
+
+ role = spi_accessible_role_from_atk_role (atk_object_get_role (child));
+
+ for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
+ if (role == roles[i])
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+match_roles_none_p (AtkObject * child, gint * roles)
+{
+ AtkRole role;
+ int i;
+
+ if (roles == NULL || roles[0] == BITARRAY_SEQ_TERM)
+ return TRUE;
+
+ role = atk_object_get_role (child);
+
+ for (i = 0; roles[i] != BITARRAY_SEQ_TERM; i++)
+ if (role == roles[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+match_roles_lookup (AtkObject * child, MatchRulePrivate * mrp)
+{
+ switch (mrp->rolematchtype)
+ {
+ case ATSPI_Collection_MATCH_ALL:
+ if (match_roles_all_p (child, mrp->roles))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_ANY:
+ if (match_roles_any_p (child, mrp->roles))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_NONE:
+ if (match_roles_none_p (child, mrp->roles))
+ return TRUE;
+ break;
+
+ default:
+ break;
+
+ }
+ return FALSE;
+}
+
+static gboolean
+match_interfaces_all_p (AtkObject * obj, gchar ** ifaces)
+{
+ gint i;
+
+ if (ifaces == NULL)
+ return TRUE;
+
+ for (i = 0; ifaces[i]; i++)
+ if (!child_interface_p (obj, ifaces[i]))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+match_interfaces_any_p (AtkObject * obj, gchar ** ifaces)
+{
+ gint i;
+
+ if (ifaces == NULL)
+ return TRUE;
+
+
+ for (i = 0; ifaces[i]; i++)
+ if (child_interface_p (obj, ifaces[i]))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+match_interfaces_none_p (AtkObject * obj, gchar ** ifaces)
+{
+ gint i;
+
+ for (i = 0; ifaces[i]; i++)
+ if (child_interface_p (obj, ifaces[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+match_interfaces_lookup (AtkObject * child, MatchRulePrivate * mrp)
+{
+ switch (mrp->interfacematchtype)
+ {
+
+ case ATSPI_Collection_MATCH_ALL:
+ if (match_interfaces_all_p (child, mrp->ifaces))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_ANY:
+ if (match_interfaces_any_p (child, mrp->ifaces))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_NONE:
+ if (match_interfaces_none_p (child, mrp->ifaces))
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+#define split_attributes(attributes) (g_strsplit (attributes, ";", 0))
+
+static gboolean
+match_attributes_all_p (AtkObject * child, AtkAttributeSet * attributes)
+{
+ int i, k;
+ AtkAttributeSet *oa;
+ gint length, oa_length;
+ gboolean flag = FALSE;
+
+ if (attributes == NULL || g_slist_length (attributes) == 0)
+ return TRUE;
+
+ oa = atk_object_get_attributes (child);
+ length = g_slist_length (attributes);
+ oa_length = g_slist_length (oa);
+
+ for (i = 0; i < length; i++)
+ {
+ AtkAttribute *attr = g_slist_nth_data (attributes, i);
+ for (k = 0; k < oa_length; k++)
+ {
+ AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
+ if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
+ !g_ascii_strcasecmp (oa_attr->value, attr->value))
+ {
+ flag = TRUE;
+ break;
+ }
+ else
+ flag = FALSE;
+ }
+ if (!flag)
+ {
+ atk_attribute_set_free (oa);
+ return FALSE;
+ }
+ }
+ atk_attribute_set_free (oa);
+ return TRUE;
+}
+
+static gboolean
+match_attributes_any_p (AtkObject * child, AtkAttributeSet * attributes)
+{
+ int i, k;
+
+ AtkAttributeSet *oa;
+ gint length, oa_length;
+
+ length = g_slist_length (attributes);
+ if (length == 0)
+ return TRUE;
+
+ oa = atk_object_get_attributes (child);
+ oa_length = g_slist_length (oa);
+
+ for (i = 0; i < length; i++)
+ {
+ AtkAttribute *attr = g_slist_nth_data (attributes, i);
+ for (k = 0; k < oa_length; k++)
+ {
+ AtkAttribute *oa_attr = g_slist_nth_data (oa, k);
+ if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
+ !g_ascii_strcasecmp (oa_attr->value, attr->value))
+ {
+ atk_attribute_set_free (oa);
+ return TRUE;
+ }
+ }
+ }
+ atk_attribute_set_free (oa);
+ return FALSE;
+}
+
+static gboolean
+match_attributes_none_p (AtkObject * child, AtkAttributeSet * attributes)
+{
+ int i, k;
+
+ AtkAttributeSet *oa;
+ gint length, oa_length;
+
+ length = g_slist_length (attributes);
+ if (length == 0)
+ return TRUE;
+
+ oa = atk_object_get_attributes (child);
+ oa_length = g_slist_length (oa);
+
+ for (i = 0; i < length; i++)
+ {
+ AtkAttribute *attr = g_slist_nth_data (attributes, i);
+ for (k = 0; k < oa_length; k++)
+ {
+ AtkAttribute *oa_attr = g_slist_nth_data (attributes, i);
+ if (!g_ascii_strcasecmp (oa_attr->name, attr->name) &&
+ !g_ascii_strcasecmp (oa_attr->value, attr->value))
+ {
+ atk_attribute_set_free (oa);
+ return FALSE;
+ }
+ }
+ }
+ atk_attribute_set_free (oa);
+ return TRUE;
+}
+
+static gboolean
+match_attributes_lookup (AtkObject * child, MatchRulePrivate * mrp)
+{
+ switch (mrp->attributematchtype)
+ {
+
+ case ATSPI_Collection_MATCH_ALL:
+ if (match_attributes_all_p (child, mrp->attributes))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_ANY:
+ if (match_attributes_any_p (child, mrp->attributes))
+ return TRUE;
+ break;
+
+ case ATSPI_Collection_MATCH_NONE:
+ if (match_attributes_none_p (child, mrp->attributes))
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static gboolean
+traverse_p (AtkObject * child, const gboolean traverse)
+{
+ if (traverse)
+ return TRUE;
+ else
+ return !child_collection_p (child);
+}
+
+static int
+sort_order_canonical (MatchRulePrivate * mrp, GList * ls,
+ gint kount, gint max,
+ AtkObject * obj, glong index, gboolean flag,
+ AtkObject * pobj, gboolean recurse, gboolean traverse)
+{
+ gint i = index;
+ glong acount = atk_object_get_n_accessible_children (obj);
+ gboolean prev = pobj ? TRUE : FALSE;
+
+ for (; i < acount && (max == 0 || kount < max); i++)
+ {
+ AtkObject *child = atk_object_ref_accessible_child (obj, i);
+
+ g_object_unref (child);
+ if (prev && child == pobj)
+ {
+ return kount;
+ }
+
+ if (flag && match_interfaces_lookup (child, mrp)
+ && match_states_lookup (child, mrp)
+ && match_roles_lookup (child, mrp)
+ && match_attributes_lookup (child, mrp))
+ {
+
+ ls = g_list_append (ls, child);
+ kount++;
+ }
+
+ if (!flag)
+ flag = TRUE;
+
+ if (recurse && traverse_p (child, traverse))
+ kount = sort_order_canonical (mrp, ls, kount,
+ max, child, 0, TRUE,
+ pobj, recurse, traverse);
+ }
+ return kount;
+}
+
+static int
+sort_order_rev_canonical (MatchRulePrivate * mrp, GList * ls,
+ gint kount, gint max,
+ AtkObject * obj, gboolean flag, AtkObject * pobj)
+{
+ AtkObject *nextobj;
+ AtkObject *parent;
+ glong indexinparent;
+
+ /* This breaks us out of the recursion. */
+ if (!obj || obj == pobj)
+ {
+ return kount;
+ }
+
+ /* Add to the list if it matches */
+ if (flag && match_interfaces_lookup (obj, mrp)
+ && match_states_lookup (obj, mrp)
+ && match_roles_lookup (obj, mrp) && match_attributes_lookup (obj, mrp)
+ && (max == 0 || kount < max))
+ {
+ ls = g_list_append (ls, obj);
+ kount++;
+ }
+
+ if (!flag)
+ flag = TRUE;
+
+ /* Get the current nodes index in it's parent and the parent object. */
+ indexinparent = atk_object_get_index_in_parent (obj);
+ parent = atk_object_get_parent (obj);
+
+ if (indexinparent > 0 && (max == 0 || kount < max))
+ {
+ /* there are still some siblings to visit so get the previous sibling
+ and get it's last descendant.
+ First, get the previous sibling */
+ nextobj = atk_object_ref_accessible_child (parent, indexinparent - 1);
+ g_object_unref (nextobj);
+
+ /* Now, drill down the right side to the last descendant */
+ while (atk_object_get_n_accessible_children (nextobj) > 0)
+ {
+ nextobj = atk_object_ref_accessible_child (nextobj,
+ atk_object_get_n_accessible_children
+ (nextobj) - 1);
+ g_object_unref (nextobj);
+ }
+ /* recurse with the last descendant */
+ kount = sort_order_rev_canonical (mrp, ls, kount, max,
+ nextobj, TRUE, pobj);
+ }
+ else if (max == 0 || kount < max)
+ {
+ /* no more siblings so next node must be the parent */
+ kount = sort_order_rev_canonical (mrp, ls, kount, max,
+ parent, TRUE, pobj);
+
+ }
+ return kount;
+}
+
+static int
+query_exec (MatchRulePrivate * mrp, AtspiCollectionSortOrder sortby,
+ GList * ls, gint kount, gint max,
+ AtkObject * obj, glong index,
+ gboolean flag,
+ AtkObject * pobj, gboolean recurse, gboolean traverse)
+{
+ switch (sortby)
+ {
+ case ATSPI_Collection_SORT_ORDER_CANONICAL:
+ kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag,
+ pobj, recurse, traverse);
+ break;
+ case ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL:
+ kount = sort_order_canonical (mrp, ls, 0, max, obj, index, flag,
+ pobj, recurse, traverse);
+ break;
+ default:
+ kount = 0;
+ g_warning ("Sort method not implemented yet");
+ break;
+ }
+
+ return kount;
+}
+
+static gboolean
+bitarray_to_seq (dbus_uint32_t *array, int array_count, int **ret)
+{
+ int out_size = 4;
+ int out_count = 0;
+ int i, j;
+ int *out = (int *) g_malloc (out_size * sizeof (int));
+
+ if (!out)
+ return FALSE;
+ for (i = 0; i < array_count; i++)
+ {
+ for (j = 0; j < 32; j++)
+ {
+ if (array[i] & (1 << j))
+ {
+ if (out_count == out_size - 2)
+ {
+ out_size <<= 1;
+ out = (int *) g_realloc (out, out_size * sizeof (int));
+ if (!out)
+ return FALSE;
+ }
+ out[out_count++] = i * 32 + j;
+ }
+ }
+ }
+ out[out_count] = BITARRAY_SEQ_TERM;
+ *ret = out;
+ return TRUE;
+}
+
+
+static dbus_bool_t
+read_mr (DBusMessageIter * iter, MatchRulePrivate * mrp)
+{
+ DBusMessageIter iter_struct, iter_array, iter_dict, iter_dict_entry;
+ dbus_uint32_t *array;
+ dbus_int32_t matchType;
+ int array_count;
+ AtkAttribute *attr;
+ int i;
+
+ dbus_message_iter_recurse (iter, &iter_struct);
+
+ /* states */
+ dbus_message_iter_recurse (&iter_struct, &iter_array);
+ dbus_message_iter_get_fixed_array (&iter_array, &array, &array_count);
+ bitarray_to_seq (array, array_count, &mrp->states);
+ for (i = 0; mrp->states[i] != BITARRAY_SEQ_TERM; i++)
+ {
+ mrp->states[i] = spi_atk_state_from_spi_state (mrp->states[i]);
+ }
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &matchType);
+ dbus_message_iter_next (&iter_struct);
+ mrp->statematchtype = matchType;;
+
+ /* attributes */
+ mrp->attributes = NULL;
+ dbus_message_iter_recurse (&iter_struct, &iter_dict);
+ while (dbus_message_iter_get_arg_type (&iter_dict) != DBUS_TYPE_INVALID)
+ {
+ const char *key, *val;
+ const char *p, *q;
+ dbus_message_iter_recurse (&iter_dict, &iter_dict_entry);
+ dbus_message_iter_get_basic (&iter_dict_entry, &key);
+ dbus_message_iter_next (&iter_dict_entry);
+ dbus_message_iter_get_basic (&iter_dict_entry, &val);
+ p = q = val;
+ for (;;)
+ {
+ if (*q == '\0' || (*q == ':' && (q == val || q[-1] != '\\')))
+ {
+ char *tmp;
+ attr = g_new (AtkAttribute, 1);
+ attr->name = g_strdup (key);
+ attr->value = g_strdup (p);
+ attr->value[q - p] = '\0';
+ tmp = attr->value;
+ while (*tmp != '\0')
+ {
+ if (*tmp == '\\')
+ memmove (tmp, tmp + 1, strlen (tmp));
+ else
+ tmp++;
+ }
+ mrp->attributes = g_slist_prepend (mrp->attributes, attr);
+ if (*q == '\0')
+ break;
+ else
+ p = ++q;
+ }
+ else
+ q++;
+ }
+ dbus_message_iter_next (&iter_dict);
+ }
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &matchType);
+ mrp->attributematchtype = matchType;;
+ dbus_message_iter_next (&iter_struct);
+
+ /* Get roles and role match */
+ dbus_message_iter_recurse (&iter_struct, &iter_array);
+ dbus_message_iter_get_fixed_array (&iter_array, &array, &array_count);
+ bitarray_to_seq (array, array_count, &mrp->roles);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &matchType);
+ mrp->rolematchtype = matchType;;
+ dbus_message_iter_next (&iter_struct);
+
+ /* Get interfaces and interface match */
+ dbus_message_iter_recurse (&iter_struct, &iter_array);
+ mrp->ifaces = g_new0 (gchar *, 16);
+ i = 0;
+ while (i < 15 && dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+ {
+ char *iface;
+ dbus_message_iter_get_basic (&iter_array, &iface);
+ mrp->ifaces [i] = g_strdup (iface);
+ i++;
+ dbus_message_iter_next (&iter_array);
+ }
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &matchType);
+ mrp->interfacematchtype = matchType;;
+ dbus_message_iter_next (&iter_struct);
+ /* get invert */
+ dbus_message_iter_get_basic (&iter_struct, &mrp->invert);
+ dbus_message_iter_next (iter);
+ return TRUE;
+}
+
+static DBusMessage *
+return_and_free_list (DBusMessage * message, GList * ls)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+ GList *item;
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ return NULL;
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
+ goto oom;
+ for (item = ls; item; item = g_list_next (item))
+ {
+ spi_object_append_reference (&iter_array, ATK_OBJECT (item->data));
+ }
+ if (!dbus_message_iter_close_container (&iter, &iter_array))
+ goto oom;
+ g_list_free (ls);
+ return reply;
+oom:
+ // TODO: Handle out of memory
+ g_list_free (ls);
+ return reply;
+}
+
+static void
+free_mrp_data (MatchRulePrivate * mrp)
+{
+ g_free (mrp->states);
+ atk_attribute_set_free (mrp->attributes);
+ g_free (mrp->roles);
+ g_strfreev (mrp->ifaces);
+}
+
+static DBusMessage *
+GetMatchesFrom (DBusMessage * message,
+ AtkObject * current_object,
+ MatchRulePrivate * mrp,
+ const AtspiCollectionSortOrder sortby,
+ const dbus_bool_t isrestrict,
+ dbus_int32_t count, const dbus_bool_t traverse)
+{
+ GList *ls = NULL;
+ AtkObject *parent;
+ glong index = atk_object_get_index_in_parent (current_object);
+
+ ls = g_list_append (ls, current_object);
+
+ if (!isrestrict)
+ {
+ parent = atk_object_get_parent (current_object);
+ query_exec (mrp, sortby, ls, 0, count, parent, index,
+ FALSE, NULL, TRUE, traverse);
+ }
+ else
+ query_exec (mrp, sortby, ls, 0, count,
+ current_object, 0, FALSE, NULL, TRUE, traverse);
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+/*
+ inorder traversal from a given object in the hierarchy
+*/
+
+static int
+inorder (AtkObject * collection, MatchRulePrivate * mrp,
+ GList * ls, gint kount, gint max,
+ AtkObject * obj,
+ gboolean flag, AtkObject * pobj, dbus_bool_t traverse)
+{
+ int i = 0;
+
+ /* First, look through the children recursively. */
+ kount = sort_order_canonical (mrp, ls, kount, max, obj, 0, TRUE,
+ NULL, TRUE, TRUE);
+
+ /* Next, we look through the right subtree */
+ while ((max == 0 || kount < max) && obj && obj != collection)
+ {
+ AtkObject *parent = atk_object_get_parent (obj);
+ i = atk_object_get_index_in_parent (obj);
+ kount = sort_order_canonical (mrp, ls, kount, max, parent,
+ i + 1, TRUE, FALSE, TRUE, TRUE);
+ obj = parent;
+ }
+
+ if (max == 0 || kount < max)
+ {
+ kount = sort_order_canonical (mrp, ls, kount, max,
+ obj, i + 1, TRUE, FALSE, TRUE, TRUE);
+ }
+
+ return kount;
+}
+
+/*
+ GetMatchesInOrder: get matches from a given object in an inorder traversal.
+*/
+
+static DBusMessage *
+GetMatchesInOrder (DBusMessage * message,
+ AtkObject * current_object,
+ MatchRulePrivate * mrp,
+ const AtspiCollectionSortOrder sortby,
+ const dbus_bool_t recurse,
+ dbus_int32_t count, const dbus_bool_t traverse)
+{
+ GList *ls = NULL;
+ AtkObject *obj;
+
+ ls = g_list_append (ls, current_object);
+
+ obj = ATK_OBJECT(spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
+
+ inorder (obj, mrp, ls, 0, count,
+ current_object, TRUE, NULL, traverse);
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+/*
+ GetMatchesInBackOrder: get matches from a given object in a
+ reverse order traversal.
+*/
+
+static DBusMessage *
+GetMatchesInBackOrder (DBusMessage * message,
+ AtkObject * current_object,
+ MatchRulePrivate * mrp,
+ const AtspiCollectionSortOrder sortby,
+ dbus_int32_t count)
+{
+ GList *ls = NULL;
+ AtkObject *collection;
+
+ ls = g_list_append (ls, current_object);
+
+ collection = ATK_OBJECT(spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
+
+ sort_order_rev_canonical (mrp, ls, 0, count, current_object,
+ FALSE, collection);
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+static DBusMessage *
+GetMatchesTo (DBusMessage * message,
+ AtkObject * current_object,
+ MatchRulePrivate * mrp,
+ const AtspiCollectionSortOrder sortby,
+ const dbus_bool_t recurse,
+ const dbus_bool_t isrestrict,
+ dbus_int32_t count, const dbus_bool_t traverse)
+{
+ GList *ls = NULL;
+ AtkObject *obj;
+ ls = g_list_append (ls, current_object);
+
+ if (recurse)
+ {
+ obj = ATK_OBJECT (atk_object_get_parent (current_object));
+ query_exec (mrp, sortby, ls, 0, count,
+ obj, 0, TRUE, current_object, TRUE, traverse);
+ }
+ else
+ {
+ obj = ATK_OBJECT (spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
+ query_exec (mrp, sortby, ls, 0, count,
+ obj, 0, TRUE, current_object, TRUE, traverse);
+
+ }
+
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby != ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+
+ free_mrp_data (mrp);
+ return return_and_free_list (message, ls);
+}
+
+static DBusMessage *
+impl_GetMatchesFrom (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ char *current_object_path = NULL;
+ AtkObject *current_object;
+ DBusMessageIter iter;
+ MatchRulePrivate rule;
+ dbus_uint32_t sortby;
+ dbus_uint32_t tree;
+ dbus_int32_t count;
+ dbus_bool_t traverse;
+ const char *signature;
+
+ signature = dbus_message_get_signature (message);
+ if (strcmp (signature, "o(aiia{ss}iaiiasib)uuib") != 0)
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_get_basic (&iter, &current_object_path);
+ current_object = ATK_OBJECT (spi_register_path_to_object (spi_global_register, current_object_path));
+ if (!current_object)
+ {
+ // TODO: object-not-found error
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_next (&iter);
+ if (!read_mr (&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_get_basic (&iter, &sortby);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &tree);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &count);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &traverse);
+ dbus_message_iter_next (&iter);
+
+ switch (tree)
+ {
+ case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
+ return GetMatchesFrom (message, current_object,
+ &rule, sortby, TRUE, count, traverse);
+ break;
+ case ATSPI_Collection_TREE_RESTRICT_SIBLING:
+ return GetMatchesFrom (message, current_object,
+ &rule, sortby, FALSE, count, traverse);
+ break;
+ case ATSPI_Collection_TREE_INORDER:
+ return GetMatchesInOrder (message, current_object,
+ &rule, sortby, TRUE, count, traverse);
+ break;
+ default:
+ return NULL;
+ }
+}
+
+static DBusMessage *
+impl_GetMatchesTo (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ char *current_object_path = NULL;
+ AtkObject *current_object;
+ DBusMessageIter iter;
+ MatchRulePrivate rule;
+ dbus_uint32_t sortby;
+ dbus_uint32_t tree;
+ dbus_bool_t recurse;
+ dbus_int32_t count;
+ dbus_bool_t traverse;
+ const char *signature;
+
+ signature = dbus_message_get_signature (message);
+ if (strcmp (signature, "o(aiia{ss}iaiiasib)uubib") != 0)
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_get_basic (&iter, &current_object_path);
+ current_object = ATK_OBJECT (spi_register_path_to_object (spi_global_register, current_object_path));
+ if (!current_object)
+ {
+ // TODO: object-not-found error
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_next (&iter);
+ if (!read_mr (&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_get_basic (&iter, &sortby);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &tree);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &recurse);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &count);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &traverse);
+ dbus_message_iter_next (&iter);
+
+ switch (tree)
+ {
+ case ATSPI_Collection_TREE_RESTRICT_CHILDREN:
+ return GetMatchesTo (message, current_object,
+ &rule, sortby, recurse, TRUE, count, traverse);
+ break;
+ case ATSPI_Collection_TREE_RESTRICT_SIBLING:
+ return GetMatchesTo (message, current_object,
+ &rule, sortby, recurse, FALSE, count, traverse);
+ break;
+ case ATSPI_Collection_TREE_INORDER:
+ return GetMatchesInBackOrder (message, current_object,
+ &rule, sortby, count);
+ break;
+ default:
+ return NULL;
+ }
+}
+
+static void
+append_accessible_properties (DBusMessageIter *iter, AtkObject *obj,
+ GArray *properties)
+{
+ DBusMessageIter iter_struct, iter_dict, iter_dict_entry;
+ AtkStateSet *set;
+ gint i;
+ gint count;
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &iter_struct);
+ spi_object_append_reference (&iter_struct, obj);
+ dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_dict);
+ if (properties && properties->len)
+ {
+ gint i;
+ for (i = 0; i < properties->len; i++)
+ {
+ gchar *prop = g_array_index (properties, char *, i);
+ DRoutePropertyFunction func;
+ GType type;
+ func = _atk_bridge_find_property_func (prop, &type);
+ if (func && G_TYPE_CHECK_INSTANCE_TYPE (obj, type))
+ {
+ dbus_message_iter_open_container (&iter_dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &iter_dict_entry);
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop);
+ func (&iter_dict_entry, obj);
+ dbus_message_iter_close_container (&iter_dict, &iter_dict_entry);
+ }
+ }
+ }
+ else
+ {
+ GHashTableIter hi;
+ gpointer key, value;
+ g_hash_table_iter_init (&hi, spi_global_app_data->property_hash);
+ while (g_hash_table_iter_next (&hi, &key, &value))
+ {
+ const DRouteProperty *prop = value;
+ GType type = _atk_bridge_type_from_iface (key);
+ if (!G_TYPE_CHECK_INSTANCE_TYPE (obj, type))
+ continue;
+ for (;prop->name; prop++)
+ {
+ const char *p = key + strlen (key);
+ gchar *property_name;
+ while (p[-1] != '.')
+ p--;
+ if (!strcmp (p, "Accessible"))
+ property_name = g_strdup (prop->name);
+ else
+ property_name = g_strconcat (p, ".", prop->name, NULL);
+ dbus_message_iter_open_container (&iter_dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &iter_dict_entry);
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &property_name);
+ g_free (property_name);
+ prop->get (&iter_dict_entry, obj);
+ dbus_message_iter_close_container (&iter_dict, &iter_dict_entry);
+ }
+ }
+ }
+ dbus_message_iter_close_container (&iter_struct, &iter_dict);
+ dbus_message_iter_close_container (iter, &iter_struct);
+
+ set = atk_object_ref_state_set (obj);
+ if (set)
+ {
+ gboolean md = atk_state_set_contains_state (set, ATK_STATE_MANAGES_DESCENDANTS);
+ g_object_unref (set);
+ if (md)
+ return;
+ }
+ count = atk_object_get_n_accessible_children (obj);
+ for (i = 0; i < count; i++)
+ {
+ AtkObject *child = atk_object_ref_accessible_child (obj, i);
+ if (child)
+ {
+ append_accessible_properties (iter, child, properties);
+ g_object_unref (child);
+ }
+ }
+}
+
+static void
+skip (const char **p)
+{
+ const char *sig = *p;
+ gint nest = (*sig != 'a');
+
+ sig++;
+ while (*sig)
+ {
+ if (*sig == '(' || *sig == '{')
+ nest++;
+ else if (*sig == ')' || *sig == '}')
+ nest--;
+ sig++;
+ }
+ *p = sig;
+}
+
+static gboolean
+types_match (DBusMessageIter *iter, char c)
+{
+ char t = dbus_message_iter_get_arg_type (iter);
+
+ if (t == 'r' && c == '(')
+ return TRUE;
+ else if (t != c)
+ return FALSE;
+
+ return FALSE;
+}
+
+static void
+walk (DBusMessageIter *iter, const char *sig, gboolean array)
+{
+ while (*sig && *sig != ')' && *sig != '}')
+ {
+ if (array && dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_INVALID)
+ break;
+ if (!types_match (iter, *sig))
+ {
+ g_error ("Expected %s, got %c", sig, dbus_message_iter_get_arg_type (iter));
+ }
+ switch (*sig)
+ {
+ case 's':
+ {
+ const char *str;
+ DBusError error;
+ dbus_error_init (&error);
+ dbus_message_iter_get_basic (iter, &str);
+ g_print ("%s\n", str);
+ if (!dbus_validate_utf8 (str, &error))
+ g_error ("Bad UTF-8 string");
+ }
+ break;
+ case 'a':
+ {
+ DBusMessageIter iter_array;
+ dbus_message_iter_recurse (iter, &iter_array);
+ walk (&iter_array, sig + 1, TRUE);
+ skip (&sig);
+ }
+ break;
+ case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
+ {
+ DBusMessageIter iter_struct;
+ dbus_message_iter_recurse (iter, &iter_struct);
+ walk (&iter_struct, sig + 1, FALSE);
+ skip (&sig);
+ }
+ }
+ dbus_message_iter_next (iter);
+ if (!array)
+ sig++;
+ }
+ if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_INVALID)
+ g_error ("Unexpected data '%c'", dbus_message_iter_get_arg_type (iter));
+}
+
+static void
+walkm (DBusMessage *message)
+{
+ DBusMessageIter iter;
+ const char *sig = dbus_message_get_signature (message);
+
+ g_print ("sig: %s\n", sig);
+ dbus_message_iter_init (message, &iter);
+ walk (&iter, sig, FALSE);
+}
+
+static DBusMessage *
+impl_GetTree (DBusConnection * bus,
+ DBusMessage * message, void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+ MatchRulePrivate rule;
+ GArray *properties;
+
+ g_return_val_if_fail (ATK_IS_OBJECT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (strcmp (dbus_message_get_signature (message), "(aiia{ss}iaiiasib)as") != 0)
+ return droute_invalid_arguments_error (message);
+
+ properties = g_array_new (TRUE, TRUE, sizeof (char *));
+ dbus_message_iter_init (message, &iter);
+ if (!read_mr (&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+
+ dbus_message_iter_recurse (&iter, &iter_array);
+ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+ {
+ const char *prop;
+ dbus_message_iter_get_basic (&iter_array, &prop);
+ g_array_append_val (properties, prop);
+ dbus_message_iter_next (&iter_array);
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_iter_init_append (reply, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "((so)a{sv})",
+ &iter_array);
+ append_accessible_properties (&iter_array, object, properties);
+ dbus_message_iter_close_container (&iter, &iter_array);
+ }
+//walkm (reply);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetMatches (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkObject *obj = ATK_OBJECT (spi_register_path_to_object (spi_global_register, dbus_message_get_path (message)));
+ DBusMessageIter iter;
+ MatchRulePrivate rule;
+ dbus_uint32_t sortby;
+ dbus_int32_t count;
+ dbus_bool_t traverse;
+ GList *ls = NULL;
+ const char *signature;
+
+ signature = dbus_message_get_signature (message);
+ if (strcmp (signature, "(aiia{ss}iaiiasib)uib") != 0)
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ dbus_message_iter_init (message, &iter);
+ if (!read_mr (&iter, &rule))
+ {
+ return spi_dbus_general_error (message);
+ }
+ dbus_message_iter_get_basic (&iter, &sortby);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &count);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &traverse);
+ dbus_message_iter_next (&iter);
+ ls = g_list_prepend (ls, obj);
+ count = query_exec (&rule, sortby, ls, 0, count,
+ obj, 0, TRUE, NULL, TRUE, traverse);
+ ls = g_list_remove (ls, ls->data);
+
+ if (sortby == ATSPI_Collection_SORT_ORDER_REVERSE_CANONICAL)
+ ls = g_list_reverse (ls);
+ free_mrp_data (&rule);
+ return return_and_free_list (message, ls);
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetMatchesFrom, "GetMatchesFrom"},
+ {impl_GetMatchesTo, "GetMatchesTo"},
+ {impl_GetTree, "GetTree"},
+ {impl_GetMatches, "GetMatches"},
+ {NULL, NULL}
+};
+
+void
+spi_initialize_collection (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_COLLECTION, spi_org_a11y_atspi_Collection, methods, NULL);
+};
diff --git a/atk-adaptor/adaptors/component-adaptor.c b/atk-adaptor/adaptors/component-adaptor.c
new file mode 100644
index 0000000..95192e1
--- /dev/null
+++ b/atk-adaptor/adaptors/component-adaptor.c
@@ -0,0 +1,499 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+#include <string.h>
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static DBusMessage *
+impl_Contains (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_int32_t x, y;
+ dbus_uint32_t coord_type;
+ dbus_bool_t retval;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
+ DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ retval =
+ atk_component_contains (component, x, y, (AtkCoordType) coord_type);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAccessibleAtPoint (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_int32_t x, y;
+ dbus_uint32_t coord_type;
+ DBusMessage *reply;
+ AtkObject *child;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
+ DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ child =
+ atk_component_ref_accessible_at_point (component, x, y,
+ (AtkCoordType) coord_type);
+ reply = spi_object_return_reference (message, child);
+ if (child)
+ g_object_unref (child);
+
+ return reply;
+}
+
+static DBusMessage *
+impl_GetExtents (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_uint32_t coord_type;
+ gint ix, iy, iwidth, iheight;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_component_get_extents (component, &ix, &iy, &iwidth, &iheight,
+ (AtkCoordType) coord_type);
+ return spi_dbus_return_rect (message, ix, iy, iwidth, iheight);
+}
+
+static DBusMessage *
+impl_GetPosition (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_uint32_t coord_type;
+ gint ix = 0, iy = 0;
+ dbus_int32_t x, y;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_component_get_position (component, &ix, &iy, (AtkCoordType) coord_type);
+ x = ix;
+ y = iy;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
+ &y, DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetSize (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ gint iwidth = 0, iheight = 0;
+ dbus_int32_t width, height;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ atk_component_get_size (component, &iwidth, &iheight);
+ width = iwidth;
+ height = iheight;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &width,
+ DBUS_TYPE_INT32, &height, DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetLayer (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ AtkLayer atklayer;
+ dbus_uint32_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ atklayer = atk_component_get_layer (component);
+
+ switch (atklayer)
+ {
+ case ATK_LAYER_BACKGROUND:
+ rv = ATSPI_LAYER_BACKGROUND;
+ break;
+ case ATK_LAYER_CANVAS:
+ rv = ATSPI_LAYER_CANVAS;
+ break;
+ case ATK_LAYER_WIDGET:
+ rv = ATSPI_LAYER_WIDGET;
+ break;
+ case ATK_LAYER_MDI:
+ rv = ATSPI_LAYER_MDI;
+ break;
+ case ATK_LAYER_POPUP:
+ rv = ATSPI_LAYER_POPUP;
+ break;
+ case ATK_LAYER_OVERLAY:
+ rv = ATSPI_LAYER_OVERLAY;
+ break;
+ case ATK_LAYER_WINDOW:
+ rv = ATSPI_LAYER_WINDOW;
+ break;
+ default:
+ rv = ATSPI_LAYER_INVALID;
+ break;
+ }
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_UINT32, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetMDIZOrder (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_int16_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_component_get_mdi_zorder (component);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT16, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GrabFocus (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_component_grab_focus (component);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GrabHighlight (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_component_grab_highlight (component);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_ClearHighlight (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_component_clear_highlight (component);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+#if 0
+static DBusMessage *
+impl_registerFocusHandler (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+}
+
+static DBusMessage *
+impl_deregisterFocusHandler (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+}
+#endif
+
+static DBusMessage *
+impl_GetAlpha (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ double rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_component_get_alpha (component);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_DOUBLE, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_SetExtents (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ DBusMessageIter iter, iter_struct;
+ dbus_uint32_t coord_type;
+ dbus_int32_t x, y, width, height;
+ dbus_bool_t ret;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (strcmp (dbus_message_get_signature (message), "(iiii)u") != 0)
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_recurse (&iter, &iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &x);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &y);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &width);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &height);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_next (&iter);
+ dbus_message_iter_get_basic (&iter, &coord_type);
+
+ ret = atk_component_set_extents (component, x, y, width, height, coord_type);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
+
+static DBusMessage *
+impl_SetPosition (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_uint32_t coord_type;
+ dbus_int32_t x, y;
+ dbus_bool_t ret;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
+ DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ ret = atk_component_set_position (component, x, y, coord_type);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
+
+static dbus_bool_t
+impl_get_ScreenExtents (DBusMessageIter * iter, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ DBusMessageIter iter_variant, iter_struct;
+ gint ix = -1, iy = -1, iwidth = -1, iheight = -1;
+ dbus_uint32_t x, y, width, height;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data), FALSE);
+
+ atk_component_get_extents (component, &ix, &iy, &iwidth, &iheight, ATK_XY_SCREEN);
+ x = ix;
+ y = iy;
+ width = iwidth;
+ height = iheight;
+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(uuuu)",
+ &iter_variant);
+ dbus_message_iter_open_container (&iter_variant, DBUS_TYPE_STRUCT, NULL,
+ &iter_struct);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &x);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &y);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &width);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &height);
+ dbus_message_iter_close_container (&iter_variant, &iter_struct);
+ dbus_message_iter_close_container (iter, &iter_variant);
+ return TRUE;
+}
+
+static dbus_bool_t
+impl_get_HighlightIndex (DBusMessageIter * iter, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data), -1);
+ return droute_return_v_int32 (iter, atk_component_get_highlight_index (component));
+}
+
+static DBusMessage *
+impl_SetSize (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkComponent *component = (AtkComponent *) user_data;
+ dbus_int32_t width, height;
+ dbus_bool_t ret;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_COMPONENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32, &height,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ ret = atk_component_set_size (component, width, height);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_Contains, "Contains"},
+ {impl_GetAccessibleAtPoint, "GetAccessibleAtPoint"},
+ {impl_GetExtents, "GetExtents"},
+ {impl_GetPosition, "GetPosition"},
+ {impl_GetSize, "GetSize"},
+ {impl_GetLayer, "GetLayer"},
+ {impl_GetMDIZOrder, "GetMDIZOrder"},
+ {impl_GrabFocus, "GrabFocus"},
+ {impl_GrabHighlight, "GrabHighlight"},
+ {impl_ClearHighlight, "ClearHighlight"},
+ //{impl_registerFocusHandler, "registerFocusHandler"},
+ //{impl_deregisterFocusHandler, "deregisterFocusHandler"},
+ {impl_GetAlpha, "GetAlpha"},
+ {impl_SetExtents, "SetExtents"},
+ {impl_SetPosition, "SetPosition"},
+ {impl_SetSize, "SetSize"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_ScreenExtents, NULL, "ScreenExtents"},
+ {impl_get_HighlightIndex, NULL, "HighlightIndex"},
+ {NULL, NULL, NULL}
+};
+void
+spi_initialize_component (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_COMPONENT, spi_org_a11y_atspi_Component, methods, properties);
+};
diff --git a/atk-adaptor/adaptors/document-adaptor.c b/atk-adaptor/adaptors/document-adaptor.c
new file mode 100644
index 0000000..020512b
--- /dev/null
+++ b/atk-adaptor/adaptors/document-adaptor.c
@@ -0,0 +1,142 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_CurrentPageNumber (DBusMessageIter * iter, void *user_data)
+{
+ AtkDocument *document = (AtkDocument *) user_data;
+ g_return_val_if_fail (ATK_IS_DOCUMENT (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_document_get_current_page_number (document));
+}
+
+static dbus_bool_t
+impl_get_PageCount (DBusMessageIter * iter, void *user_data)
+{
+ AtkDocument *document = (AtkDocument *) user_data;
+ g_return_val_if_fail (ATK_IS_DOCUMENT (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_document_get_page_count (document));
+}
+
+static DBusMessage *
+impl_GetLocale (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkDocument *document = (AtkDocument *) user_data;
+ const gchar *lc;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_DOCUMENT (user_data),
+ droute_not_yet_handled_error (message));
+ lc = atk_document_get_locale (document);
+ if (!lc)
+ lc = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &lc,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAttributeValue (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkDocument *document = (AtkDocument *) user_data;
+ gchar *attributename;
+ const gchar *atr;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_DOCUMENT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_STRING, &attributename, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atr = atk_document_get_attribute_value (document, attributename);
+ if (!atr)
+ atr = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &atr,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAttributes (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkDocument *document = (AtkDocument *) user_data;
+ DBusMessage *reply;
+ AtkAttributeSet *attributes;
+ DBusMessageIter iter;
+
+ g_return_val_if_fail (ATK_IS_DOCUMENT (user_data),
+ droute_not_yet_handled_error (message));
+
+ attributes = atk_document_get_attributes (document);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_attribute_set (&iter, attributes);
+ }
+
+ if (attributes)
+ atk_attribute_set_free (attributes);
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetLocale, "GetLocale"},
+ {impl_GetAttributeValue, "GetAttributeValue"},
+ {impl_GetAttributes, "GetAttributes"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_CurrentPageNumber, NULL, "CurrentPageNumber"},
+ {impl_get_PageCount, NULL, "PageCount"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_document (DRoutePath * path)
+{
+ droute_path_add_interface (path,
+ ATSPI_DBUS_INTERFACE_DOCUMENT, spi_org_a11y_atspi_Document, methods, properties);
+};
diff --git a/atk-adaptor/adaptors/editabletext-adaptor.c b/atk-adaptor/adaptors/editabletext-adaptor.c
new file mode 100644
index 0000000..2e264fc
--- /dev/null
+++ b/atk-adaptor/adaptors/editabletext-adaptor.c
@@ -0,0 +1,207 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+#include "introspection.h"
+
+#include "spi-dbus.h"
+
+static DBusMessage *
+impl_SetTextContents (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkEditableText *editable = (AtkEditableText *) user_data;
+ const char *newContents;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_EDITABLE_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_STRING, &newContents, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_editable_text_set_text_contents (editable, newContents);
+ rv = TRUE;
+ // TODO decide if we really need this return value
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_InsertText (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkEditableText *editable = (AtkEditableText *) user_data;
+ dbus_int32_t position, length;
+ char *text;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+ gint ip;
+
+ g_return_val_if_fail (ATK_IS_EDITABLE_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &position, DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INT32, &length, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ip = position;
+ atk_editable_text_insert_text (editable, text, length, &ip);
+ rv = TRUE;
+ // TODO decide if we really need this return value
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_CopyText (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkEditableText *editable = (AtkEditableText *) user_data;
+ dbus_int32_t startPos, endPos;
+
+ g_return_val_if_fail (ATK_IS_EDITABLE_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &startPos, DBUS_TYPE_INT32, &endPos,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_editable_text_copy_text (editable, startPos, endPos);
+ return dbus_message_new_method_return (message);
+}
+
+static DBusMessage *
+impl_CutText (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkEditableText *editable = (AtkEditableText *) user_data;
+ dbus_int32_t startPos, endPos;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_EDITABLE_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &startPos, DBUS_TYPE_INT32, &endPos,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_editable_text_cut_text (editable, startPos, endPos);
+ rv = TRUE;
+ // TODO decide if we really need this return value
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_DeleteText (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkEditableText *editable = (AtkEditableText *) user_data;
+ dbus_int32_t startPos, endPos;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_EDITABLE_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &startPos, DBUS_TYPE_INT32, &endPos,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_editable_text_delete_text (editable, startPos, endPos);
+ rv = TRUE;
+ // TODO decide if we really need this return value
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_PasteText (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkEditableText *editable = (AtkEditableText *) user_data;
+ dbus_int32_t position;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_EDITABLE_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &position, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_editable_text_paste_text (editable, position);
+ rv = TRUE;
+ // TODO decide if we really need this return value
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_SetTextContents, "SetTextContents"},
+ {impl_InsertText, "InsertText"},
+ {impl_CopyText, "CopyText"},
+ {impl_CutText, "CutText"},
+ {impl_DeleteText, "DeleteText"},
+ {impl_PasteText, "PasteText"},
+ {NULL, NULL}
+};
+
+void
+spi_initialize_editabletext (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_EDITABLE_TEXT, spi_org_a11y_atspi_EditableText, methods, NULL);
+};
diff --git a/atk-adaptor/adaptors/hyperlink-adaptor.c b/atk-adaptor/adaptors/hyperlink-adaptor.c
new file mode 100644
index 0000000..0d0dc37
--- /dev/null
+++ b/atk-adaptor/adaptors/hyperlink-adaptor.c
@@ -0,0 +1,156 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "introspection.h"
+#include "object.h"
+
+static AtkHyperlink *
+get_hyperlink (void *user_data)
+{
+ if (ATK_IS_HYPERLINK (user_data))
+ return ATK_HYPERLINK (user_data);
+ if (ATK_IS_HYPERLINK_IMPL (user_data))
+ return atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (user_data));
+ return NULL;
+}
+
+static dbus_bool_t
+impl_get_NAnchors (DBusMessageIter * iter, void *user_data)
+{
+ AtkHyperlink *link = get_hyperlink (user_data);
+ g_return_val_if_fail (ATK_IS_HYPERLINK (link), FALSE);
+ return droute_return_v_int32 (iter, atk_hyperlink_get_n_anchors (link));
+}
+
+
+static dbus_bool_t
+impl_get_StartIndex (DBusMessageIter * iter, void *user_data)
+{
+ AtkHyperlink *link = get_hyperlink (user_data);
+ g_return_val_if_fail (ATK_IS_HYPERLINK (link), FALSE);
+ return droute_return_v_int32 (iter, atk_hyperlink_get_start_index (link));
+}
+
+static dbus_bool_t
+impl_get_EndIndex (DBusMessageIter * iter, void *user_data)
+{
+ AtkHyperlink *link = get_hyperlink (user_data);
+ g_return_val_if_fail (ATK_IS_HYPERLINK (link), FALSE);
+ return droute_return_v_int32 (iter, atk_hyperlink_get_end_index (link));
+}
+
+static DBusMessage *
+impl_GetObject (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkHyperlink *link = get_hyperlink (user_data);
+ dbus_int32_t i;
+ AtkObject *atk_object;
+
+ g_return_val_if_fail (ATK_IS_HYPERLINK (link),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_object = atk_hyperlink_get_object (link, i);
+ return spi_object_return_reference (message, atk_object);
+}
+
+static DBusMessage *
+impl_GetURI (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkHyperlink *link = get_hyperlink (user_data);
+ dbus_int32_t i;
+ gchar *rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_HYPERLINK (link),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &i, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ rv = atk_hyperlink_get_uri (link, i);
+ if (!rv)
+ rv = g_strdup ("");
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ g_free (rv);
+ return reply;
+}
+
+static DBusMessage *
+impl_IsValid (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkHyperlink *link = get_hyperlink (user_data);
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_HYPERLINK (link),
+ droute_not_yet_handled_error (message));
+
+ rv = atk_hyperlink_is_valid (link);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetObject, "GetObject"},
+ {impl_GetURI, "GetURI"},
+ {impl_IsValid, "IsValid"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_NAnchors, NULL, "NAnchors"},
+ {impl_get_StartIndex, NULL, "StartIndex"},
+ {impl_get_EndIndex, NULL, "EndIndex"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_hyperlink (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_HYPERLINK,
+ spi_org_a11y_atspi_Hyperlink,
+ methods, properties);
+};
diff --git a/atk-adaptor/adaptors/hypertext-adaptor.c b/atk-adaptor/adaptors/hypertext-adaptor.c
new file mode 100644
index 0000000..e31266f
--- /dev/null
+++ b/atk-adaptor/adaptors/hypertext-adaptor.c
@@ -0,0 +1,112 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "object.h"
+
+#include "introspection.h"
+
+static DBusMessage *
+impl_GetNLinks (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkHypertext *hypertext = (AtkHypertext *) user_data;
+ gint rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_HYPERTEXT (user_data),
+ droute_not_yet_handled_error (message));
+ rv = atk_hypertext_get_n_links (hypertext);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetLink (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkHypertext *hypertext = (AtkHypertext *) user_data;
+ dbus_int32_t linkIndex;
+ AtkHyperlink *link;
+
+ g_return_val_if_fail (ATK_IS_HYPERTEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &linkIndex, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ link = atk_hypertext_get_link (hypertext, linkIndex);
+ /*The above line doesn't ref the link, and the next call is going to unref*/
+ if (link)
+ g_object_ref (link);
+ return spi_hyperlink_return_reference (message, link);
+}
+
+static DBusMessage *
+impl_GetLinkIndex (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkHypertext *hypertext = (AtkHypertext *) user_data;
+ dbus_int32_t characterIndex;
+ dbus_int32_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_HYPERTEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &characterIndex, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_hypertext_get_link_index (hypertext, characterIndex);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetNLinks, "GetNLinks"},
+ {impl_GetLink, "GetLink"},
+ {impl_GetLinkIndex, "GetLinkIndex"},
+ {NULL, NULL}
+};
+
+void
+spi_initialize_hypertext (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_HYPERTEXT, spi_org_a11y_atspi_Hypertext, methods, NULL);
+};
diff --git a/atk-adaptor/adaptors/image-adaptor.c b/atk-adaptor/adaptors/image-adaptor.c
new file mode 100644
index 0000000..89ac20f
--- /dev/null
+++ b/atk-adaptor/adaptors/image-adaptor.c
@@ -0,0 +1,140 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_ImageDescription (DBusMessageIter * iter, void *user_data)
+{
+ AtkImage *image = (AtkImage *) user_data;
+ g_return_val_if_fail (ATK_IS_IMAGE (user_data), FALSE);
+ return droute_return_v_string (iter,
+ atk_image_get_image_description (image));
+}
+
+static dbus_bool_t
+impl_get_ImageLocale (DBusMessageIter * iter, void *user_data)
+{
+ AtkImage *image = (AtkImage *) user_data;
+ g_return_val_if_fail (ATK_IS_IMAGE (user_data), FALSE);
+ return droute_return_v_string (iter, atk_image_get_image_locale (image));
+}
+
+static DBusMessage *
+impl_GetImageExtents (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkImage *image = (AtkImage *) user_data;
+ dbus_uint32_t coordType;
+ gint ix, iy, iwidth, iheight;
+
+ g_return_val_if_fail (ATK_IS_IMAGE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_image_get_image_size (image, &iwidth, &iheight);
+ atk_image_get_image_position (image, &ix, &iy, (AtkCoordType) coordType);
+ return spi_dbus_return_rect (message, ix, iy, iwidth, iheight);
+}
+
+static DBusMessage *
+impl_GetImagePosition (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkImage *image = (AtkImage *) user_data;
+ dbus_uint32_t coord_type;
+ gint ix = 0, iy = 0;
+ dbus_int32_t x, y;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_IMAGE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_UINT32, &coord_type, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_image_get_image_position (image, &ix, &iy, (AtkCoordType) coord_type);
+ x = ix;
+ y = iy;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
+ &y, DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetImageSize (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkImage *image = (AtkImage *) user_data;
+ gint iwidth = 0, iheight = 0;
+ dbus_int32_t width, height;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_IMAGE (user_data),
+ droute_not_yet_handled_error (message));
+ atk_image_get_image_size (image, &iwidth, &iheight);
+ width = iwidth;
+ height = iheight;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &width,
+ DBUS_TYPE_INT32, &height, DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetImageExtents, "GetImageExtents"},
+ {impl_GetImagePosition, "GetImagePosition"},
+ {impl_GetImageSize, "GetImageSize"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_ImageDescription, NULL, "ImageDescription"},
+ {impl_get_ImageLocale, NULL, "ImageLocale"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_image (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_IMAGE, spi_org_a11y_atspi_Image, methods, properties);
+};
diff --git a/atk-adaptor/adaptors/selection-adaptor.c b/atk-adaptor/adaptors/selection-adaptor.c
new file mode 100644
index 0000000..4776ebc
--- /dev/null
+++ b/atk-adaptor/adaptors/selection-adaptor.c
@@ -0,0 +1,257 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_NSelectedChildren (DBusMessageIter * iter, void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data), FALSE);
+ return droute_return_v_int32 (iter,
+ atk_selection_get_selection_count
+ (selection));
+}
+
+/*static char *
+impl_get_NSelectedChildren_str (void *datum)
+{
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data), FALSE);
+ return g_strdup_printf ("%d",
+ atk_selection_get_selection_count ((AtkSelection *)
+ datum));
+}*/
+
+static DBusMessage *
+impl_GetSelectedChild (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ DBusMessage *reply;
+ dbus_int32_t selectedChildIndex;
+ AtkObject *atk_object;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &selectedChildIndex,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_object = atk_selection_ref_selection (selection, selectedChildIndex);
+ reply = spi_object_return_reference (message, atk_object);
+ if (atk_object)
+ g_object_unref (atk_object);
+
+ return reply;
+}
+
+static DBusMessage *
+impl_SelectChild (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ dbus_int32_t childIndex;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &childIndex, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_selection_add_selection (selection, childIndex);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_DeselectSelectedChild (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ dbus_int32_t selectedChildIndex;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &selectedChildIndex,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_selection_remove_selection (selection, selectedChildIndex);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_IsChildSelected (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ dbus_int32_t childIndex;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &childIndex, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_selection_is_child_selected (selection, childIndex);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_SelectAll (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ rv = atk_selection_select_all_selection (selection);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_ClearSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ rv = atk_selection_clear_selection (selection);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_DeselectChild (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkSelection *selection = (AtkSelection *) user_data;
+ dbus_int32_t selectedChildIndex;
+ dbus_bool_t rv = FALSE;
+ gint i, nselected;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_SELECTION (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &selectedChildIndex,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ nselected = atk_selection_get_selection_count (selection);
+ for (i = 0; i < nselected; ++i)
+ {
+ AtkObject *selected_obj = atk_selection_ref_selection (selection, i);
+ if (atk_object_get_index_in_parent (selected_obj) == selectedChildIndex)
+ {
+ g_object_unref (G_OBJECT (selected_obj));
+ rv = atk_selection_remove_selection (selection, i);
+ break;
+ }
+ g_object_unref (G_OBJECT (selected_obj));
+ }
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetSelectedChild, "GetSelectedChild"},
+ {impl_SelectChild, "SelectChild"},
+ {impl_DeselectSelectedChild, "DeselectSelectedChild"},
+ {impl_IsChildSelected, "IsChildSelected"},
+ {impl_SelectAll, "SelectAll"},
+ {impl_ClearSelection, "ClearSelection"},
+ {impl_DeselectChild, "DeselectChild"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_NSelectedChildren, NULL, "NSelectedChildren"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_selection (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_SELECTION,
+ spi_org_a11y_atspi_Selection,
+ methods, properties);
+};
diff --git a/atk-adaptor/adaptors/socket-adaptor.c b/atk-adaptor/adaptors/socket-adaptor.c
new file mode 100644
index 0000000..ed6faa3
--- /dev/null
+++ b/atk-adaptor/adaptors/socket-adaptor.c
@@ -0,0 +1,208 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+#include "spi-dbus.h"
+#include "accessible-stateset.h"
+#include "object.h"
+#include "introspection.h"
+#include "bridge.h"
+
+static DBusMessage *
+new_socket_call_message (AtkComponent *component, const char *member)
+{
+ char *id = g_object_get_data (G_OBJECT (component), "dbus-plug-parent");
+ char *bus_parent;
+ char *path_parent;
+
+ if (!id)
+ {
+ g_warning ("new_socket_call_message: no id");
+ return NULL;
+ }
+ bus_parent = g_strdup (id);
+ if (bus_parent && (path_parent = g_utf8_strchr (bus_parent + 1, -1, ':')))
+ {
+ DBusMessage *message;
+ *(path_parent++) = '\0';
+ message = dbus_message_new_method_call (bus_parent, path_parent,
+ ATSPI_DBUS_INTERFACE_COMPONENT,
+ member);
+ g_free (bus_parent);
+ return message;
+ }
+ return NULL;
+}
+
+static void
+atspi_plug_component_get_extents (AtkComponent *component, gint *x, gint *y,
+ gint *width, gint *height,
+ AtkCoordType coord_type)
+{
+ DBusMessage *message = new_socket_call_message (component, "GetExtents");
+ DBusMessage *reply;
+ dbus_uint32_t coord_type_dbus = coord_type;
+ DBusError error;
+ const char *signature;
+ DBusMessageIter iter, iter_struct;
+ dbus_int32_t tmp;
+
+ dbus_error_init (&error);
+ dbus_message_append_args (message, DBUS_TYPE_UINT32, &coord_type_dbus, DBUS_TYPE_INVALID);
+ reply = dbus_connection_send_with_reply_and_block (spi_global_app_data->bus,
+ message, -1, &error);
+ dbus_message_unref (message);
+ if (!reply)
+ return;
+ signature = dbus_message_get_signature (reply);
+ if (g_strcmp0 (signature, "(iiii)") != 0)
+ {
+ g_warning ("Got unexpected signature %s from GetExtents\n", signature);
+ dbus_message_unref (reply);
+ return;
+ }
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &tmp);
+ *x = tmp;
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &tmp);
+ *y = tmp;
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &tmp);
+ *width = tmp;
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &tmp);
+ *height = tmp;
+ dbus_message_unref (reply);
+}
+
+static void
+atspi_plug_component_get_position (AtkComponent *component, gint *x, gint *y,
+ AtkCoordType coord_type)
+{
+ DBusMessage *message = new_socket_call_message (component, "GetPosition");
+ DBusMessage *reply;
+ dbus_uint32_t coord_type_dbus = coord_type;
+ DBusError error;
+ dbus_int32_t x_dbus, y_dbus;
+
+ dbus_error_init (&error);
+ dbus_message_append_args (message, DBUS_TYPE_UINT32, &coord_type_dbus, DBUS_TYPE_INVALID);
+ reply = dbus_connection_send_with_reply_and_block (spi_global_app_data->bus,
+ message, -1, &error);
+ dbus_message_unref (message);
+ if (!reply)
+ return;
+ if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_INT32, &x_dbus,
+ DBUS_TYPE_INT32, &y_dbus, DBUS_TYPE_INVALID))
+ {
+ g_warning ("GetPosition failed: %s", error.message);
+ dbus_error_free (&error);
+ }
+ else
+ {
+ *x = x_dbus;
+ *y = y_dbus;
+ }
+ dbus_message_unref (reply);
+}
+
+static void
+atspi_plug_component_get_size (AtkComponent *component,
+ gint *width, gint *height)
+{
+ DBusMessage *message = new_socket_call_message (component, "GetSize");
+ DBusMessage *reply;
+ DBusError error;
+ dbus_uint32_t width_dbus, height_dbus;
+
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (spi_global_app_data->bus,
+ message, -1, &error);
+ dbus_message_unref (message);
+ if (!reply)
+ return;
+ if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_INT32, &width_dbus,
+ DBUS_TYPE_INT32, &height_dbus, DBUS_TYPE_INVALID))
+ {
+ g_warning ("GetSize failed: %s", error.message);
+ dbus_error_free (&error);
+ }
+ else
+ {
+ *width = width_dbus;
+ *height = height_dbus;
+ }
+ dbus_message_unref (reply);
+}
+
+static DBusMessage *
+impl_Embedded (DBusConnection *bus,
+ DBusMessage *message,
+ void *user_data)
+{
+ AtkObject *object = (AtkObject *) user_data;
+ char *path;
+ gchar *id;
+
+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ id = g_strconcat (dbus_message_get_sender (message), ":", path, NULL);
+ g_object_set_data_full (G_OBJECT (object), "dbus-plug-parent", id, (GDestroyNotify)g_free);
+
+ if (ATK_IS_COMPONENT (object))
+ {
+ AtkComponent *component = ATK_COMPONENT (object);
+ AtkComponentIface *iface = ATK_COMPONENT_GET_IFACE (component);
+ iface->get_extents = atspi_plug_component_get_extents;
+ iface->get_size = atspi_plug_component_get_size;
+ iface->get_position = atspi_plug_component_get_position;
+ }
+
+ /* Retrieve some info about the children, if they exist, when
+ embedding the plug to ensure the a11y subtree is generated.
+ https://bugzilla.gnome.org/show_bug.cgi?id=663876 */
+ atk_object_get_n_accessible_children (object);
+
+ return dbus_message_new_method_return (message);
+}
+
+static DRouteMethod methods[] = {
+ {impl_Embedded, "Embedded"},
+ {NULL, NULL}
+};
+
+void
+spi_initialize_socket (DRoutePath * path)
+{
+ droute_path_add_interface (path,
+ ATSPI_DBUS_INTERFACE_SOCKET,
+ NULL, /* spi_org_a11y_atspi_Socket, */
+ methods, NULL);
+};
diff --git a/atk-adaptor/adaptors/streamablecontent-adaptor.c b/atk-adaptor/adaptors/streamablecontent-adaptor.c
new file mode 100644
index 0000000..8192e1a
--- /dev/null
+++ b/atk-adaptor/adaptors/streamablecontent-adaptor.c
@@ -0,0 +1,330 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* streamablecontent.c : implements the StreamableContent interface */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libspi/component.h>
+#include <libspi/streamablecontent.h>
+
+/* Our parent Gtk object type */
+#define PARENT_TYPE SPI_TYPE_BASE
+
+/* A pointer to our parent object class */
+static GObjectClass *spi_streamable_parent_class;
+
+#define SPI_CONTENT_STREAM_TYPE (spi_content_stream_get_type ())
+#define SPI_CONTENT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPI_CONTENT_STREAM_TYPE, SpiContentStream))
+#define SPI_CONTENT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SPI_CONTENT_STREAM_TYPE, SpiContentStreamClass))
+#define SPI_IS_CONTENT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPI_CONTENT_STREAM_TYPE))
+#define SPI_IS_CONTENT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPI_CONTENT_STREAM_TYPE))
+
+typedef struct _SpiContentStream SpiContentStream;
+typedef struct _SpiContentStreamClass SpiContentStreamClass;
+
+struct _SpiContentStream
+{
+ BonoboObject parent;
+ GIOChannel *gio;
+};
+
+struct _SpiContentStreamClass
+{
+ BonoboObjectClass parent_class;
+ POA_Accessibility_ContentStream__epv epv;
+};
+
+GType spi_content_stream_get_type (void);
+
+static SpiContentStream *
+spi_content_stream_new (GIOChannel * gio)
+{
+ SpiContentStream *new_stream = g_object_new (SPI_CONTENT_STREAM_TYPE, NULL);
+ new_stream->gio = gio;
+ return new_stream;
+}
+
+static void
+spi_content_stream_dispose (GObject * o)
+{
+ if (SPI_IS_CONTENT_STREAM (o))
+ {
+ SpiContentStream *stream = SPI_CONTENT_STREAM (o);
+ if (stream->gio)
+ g_io_channel_unref (stream->gio);
+ }
+}
+
+static CORBA_long
+impl_content_stream_seek (PortableServer_Servant servant,
+ const CORBA_long offset,
+ const Accessibility_ContentStream_SeekType whence,
+ CORBA_Environment * ev)
+{
+ SpiContentStream *stream =
+ SPI_CONTENT_STREAM (bonobo_object_from_servant (servant));
+ if (stream && stream->gio)
+ {
+ GError *err;
+ GSeekType seektype = G_SEEK_SET;
+ switch (whence)
+ {
+ case Accessibility_ContentStream_SEEK_CURRENT:
+ seektype = G_SEEK_CUR;
+ break;
+ case Accessibility_ContentStream_SEEK_END:
+ seektype = G_SEEK_END;
+ break;
+ }
+ if (g_io_channel_seek_position (stream->gio, (gint64) offset,
+ seektype, &err) == G_IO_STATUS_NORMAL)
+ return offset;
+ else
+ return -1;
+ }
+ else
+ return -1;
+}
+
+static CORBA_long
+impl_content_stream_read (PortableServer_Servant servant,
+ const CORBA_long count,
+ Accessibility_ContentStream_iobuf ** buffer,
+ CORBA_Environment * ev)
+{
+ SpiContentStream *stream =
+ SPI_CONTENT_STREAM (bonobo_object_from_servant (servant));
+ CORBA_long realcount = 0;
+
+ if (stream && stream->gio)
+ {
+ gchar *gbuf = NULL;
+ GIOStatus status;
+ GError *err = NULL;
+
+ /* read the giochannel and determine the actual bytes read... */
+ if (count != -1)
+ {
+ gbuf = g_malloc (count + 1);
+ status =
+ g_io_channel_read_chars (stream->gio, gbuf, count, &realcount,
+ &err);
+ }
+ else
+ status =
+ g_io_channel_read_to_end (stream->gio, &gbuf, &realcount, &err);
+
+ if (status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_EOF)
+ {
+ *buffer = Bonobo_Stream_iobuf__alloc ();
+ CORBA_sequence_set_release (*buffer, TRUE);
+
+ (*buffer)->_buffer =
+ CORBA_sequence_CORBA_octet_allocbuf (realcount);
+ (*buffer)->_length = realcount;
+
+ g_memmove ((*buffer)->_buffer, gbuf, realcount);
+ }
+
+ g_free (gbuf);
+ }
+
+ return realcount;
+}
+
+static void
+impl_content_stream_close (PortableServer_Servant servant,
+ CORBA_Environment * ev)
+{
+ GIOStatus status;
+ GError *err;
+ SpiContentStream *stream =
+ SPI_CONTENT_STREAM (bonobo_object_from_servant (servant));
+ if (stream && stream->gio)
+ {
+ status = g_io_channel_shutdown (stream->gio, TRUE, &err);
+ g_io_channel_unref (stream->gio);
+ }
+ if (err)
+ g_free (err);
+}
+
+static void
+spi_content_stream_class_init (SpiContentStreamClass * klass)
+{
+ POA_Accessibility_ContentStream__epv *epv = &klass->epv;
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ epv->seek = impl_content_stream_seek;
+ epv->read = impl_content_stream_read;
+ epv->close = impl_content_stream_close;
+
+ object_class->dispose = spi_content_stream_dispose;
+}
+
+
+static void
+spi_content_stream_init (SpiContentStream * stream)
+{
+}
+
+
+BONOBO_TYPE_FUNC_FULL (SpiContentStream,
+ Accessibility_ContentStream,
+ BONOBO_TYPE_OBJECT, spi_content_stream)
+ static AtkStreamableContent
+ *get_streamable_from_servant (PortableServer_Servant servant)
+{
+ SpiBase *object = SPI_BASE (bonobo_object_from_servant (servant));
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (ATK_IS_STREAMABLE_CONTENT (object->gobj), NULL);
+ return ATK_STREAMABLE_CONTENT (object->gobj);
+}
+
+/*
+ * CORBA Accessibility::StreamableContent::getContentTypes method implementation
+ */
+static Accessibility_StringSeq *
+impl_accessibility_streamable_get_content_types (PortableServer_Servant
+ servant,
+ CORBA_Environment * ev)
+{
+ Accessibility_StringSeq *typelist = Accessibility_StringSeq__alloc ();
+ AtkStreamableContent *streamable = get_streamable_from_servant (servant);
+ int n_types, i;
+
+ typelist->_length = typelist->_maximum = 0;
+
+ g_return_val_if_fail (streamable != NULL, typelist);
+
+ n_types = atk_streamable_content_get_n_mime_types (streamable);
+
+ if (n_types)
+ {
+ typelist->_length = typelist->_maximum = n_types;
+ typelist->_buffer = Accessibility_StringSeq_allocbuf (n_types);
+ for (i = 0; i < n_types; ++i)
+ {
+ const gchar *mimetype =
+ atk_streamable_content_get_mime_type (streamable, i);
+ typelist->_buffer[i] = CORBA_string_dup (mimetype ? mimetype : "");
+ }
+ }
+ return typelist;
+}
+
+/*
+ * CORBA Accessibility::StreamableContent::getContent method implementation
+ */
+static Bonobo_Stream
+impl_accessibility_streamable_get_content (PortableServer_Servant servant,
+ const CORBA_char * content_type,
+ CORBA_Environment * ev)
+{
+ Bonobo_Stream stream;
+ AtkStreamableContent *streamable = get_streamable_from_servant (servant);
+ GIOChannel *gio;
+
+ g_return_val_if_fail (streamable != NULL, NULL);
+
+ gio = atk_streamable_content_get_stream (streamable, content_type);
+
+ stream = CORBA_OBJECT_NIL; /* deprecated,
+ * and it was never implemented,
+ * so don't bother fixing this
+ */
+ return stream;
+}
+
+/*
+ * CORBA Accessibility::StreamableContent::getStream method implementation
+ */
+static Accessibility_ContentStream
+impl_accessibility_streamable_get_stream (PortableServer_Servant servant,
+ const CORBA_char * content_type,
+ CORBA_Environment * ev)
+{
+ SpiContentStream *stream;
+ AtkStreamableContent *streamable = get_streamable_from_servant (servant);
+ GIOChannel *gio;
+
+ g_return_val_if_fail (streamable != NULL, NULL);
+
+ gio = atk_streamable_content_get_stream (streamable, content_type);
+
+ stream = spi_content_stream_new (gio);
+
+ return bonobo_object_dup_ref (BONOBO_OBJREF (stream), ev);
+}
+
+/*
+ * CORBA Accessibility::StreamableContent::GetURI method implementation
+ */
+static CORBA_string
+impl_accessibility_streamable_get_uri (PortableServer_Servant servant,
+ const CORBA_char * content_type,
+ CORBA_Environment * ev)
+{
+ gchar *uri;
+ AtkStreamableContent *streamable = get_streamable_from_servant (servant);
+
+ g_return_val_if_fail (streamable != NULL, NULL);
+
+ uri = atk_streamable_content_get_uri (streamable, content_type);
+
+ return (uri != NULL ? CORBA_string_dup (uri) : CORBA_string_dup (""));
+}
+
+static void
+spi_streamable_class_init (SpiStreamableClass * klass)
+{
+ POA_Accessibility_StreamableContent__epv *epv = &klass->epv;
+ spi_streamable_parent_class = g_type_class_peek_parent (klass);
+
+ epv->getContentTypes = impl_accessibility_streamable_get_content_types;
+ epv->getContent = impl_accessibility_streamable_get_content;
+ epv->getStream = impl_accessibility_streamable_get_stream;
+ epv->GetURI = impl_accessibility_streamable_get_uri;
+}
+
+static void
+spi_streamable_init (SpiStreamable * streamable)
+{
+}
+
+
+SpiStreamable *
+spi_streamable_interface_new (AtkObject * o)
+{
+ SpiStreamable *retval = g_object_new (SPI_STREAMABLE_TYPE, NULL);
+
+ spi_base_construct (SPI_BASE (retval), G_OBJECT (o));
+
+ return retval;
+}
+
+BONOBO_TYPE_FUNC_FULL (SpiStreamable,
+ Accessibility_StreamableContent,
+ PARENT_TYPE, spi_streamable)
diff --git a/atk-adaptor/adaptors/table-adaptor.c b/atk-adaptor/adaptors/table-adaptor.c
new file mode 100644
index 0000000..d3bbba5
--- /dev/null
+++ b/atk-adaptor/adaptors/table-adaptor.c
@@ -0,0 +1,673 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_NRows (DBusMessageIter * iter, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_table_get_n_rows (table));
+}
+
+static dbus_bool_t
+impl_get_NColumns (DBusMessageIter * iter, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_table_get_n_columns (table));
+}
+
+static dbus_bool_t
+impl_get_Caption (DBusMessageIter * iter, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
+ spi_object_append_v_reference (iter, atk_table_get_caption (table));
+ return TRUE;
+}
+
+static dbus_bool_t
+impl_get_Summary (DBusMessageIter * iter, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
+ spi_object_append_v_reference (iter, atk_table_get_summary (table));
+ return TRUE;
+}
+
+static dbus_bool_t
+impl_get_NSelectedRows (DBusMessageIter * iter, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ gint *selected_rows = NULL;
+ int count;
+ g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
+ count = atk_table_get_selected_rows (table, &selected_rows);
+ if (selected_rows)
+ g_free (selected_rows);
+ return droute_return_v_int32 (iter, count);
+}
+
+static dbus_bool_t
+impl_get_NSelectedColumns (DBusMessageIter * iter, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ gint *selected_columns = NULL;
+ int count;
+ g_return_val_if_fail (ATK_IS_TABLE (user_data), FALSE);
+ count = atk_table_get_selected_columns (table, &selected_columns);
+ if (selected_columns)
+ g_free (selected_columns);
+ return droute_return_v_int32 (iter, count);
+}
+
+static DBusMessage *
+impl_GetAccessibleAt (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row, column;
+ DBusMessage *reply;
+ AtkObject *obj;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ obj = atk_table_ref_at (table, row, column);
+ reply = spi_object_return_reference (message, obj);
+ if (obj)
+ g_object_unref (obj);
+
+ return reply;
+}
+
+static DBusMessage *
+impl_GetIndexAt (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row, column;
+ dbus_int32_t index;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ index = atk_table_get_index_at (table, row, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &index,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRowAtIndex (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t index;
+ dbus_int32_t row;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ row = atk_table_get_row_at_index (table, index);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &row,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetColumnAtIndex (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t index;
+ dbus_int32_t column;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ column = atk_table_get_column_at_index (table, index);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &column,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static const gchar *
+validate_unallocated_string (const gchar *str)
+{
+ if (!str)
+ return "";
+ if (!g_utf8_validate (str, -1, NULL))
+ {
+ g_warning ("atk-bridge: received bad UTF-8 string from a table function");
+ return "";
+ }
+ return str;
+}
+
+static DBusMessage *
+impl_GetRowDescription (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ dbus_int32_t row;
+ AtkTable *table = (AtkTable *) user_data;
+ const gchar *description;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ description = atk_table_get_row_description (table, row);
+ description = validate_unallocated_string (description);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetColumnDescription (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t column;
+ const char *description;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ description = atk_table_get_column_description (table, column);
+ description = validate_unallocated_string (description);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &description,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRowExtentAt (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row, column;
+ dbus_int32_t extent;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ extent = atk_table_get_row_extent_at (table, row, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetColumnExtentAt (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row, column;
+ dbus_int32_t extent;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ extent = atk_table_get_column_extent_at (table, row, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &extent,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRowHeader (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row;
+ AtkObject *obj = NULL;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ obj = atk_table_get_row_header (table, row);
+ return spi_object_return_reference (message, obj);
+}
+
+static DBusMessage *
+impl_GetColumnHeader (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t column;
+ AtkObject *obj;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ obj = atk_table_get_column_header (table, column);
+ return spi_object_return_reference (message, obj);
+}
+
+static DBusMessage *
+impl_GetSelectedRows (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ gint *selected_rows = NULL;
+ gint count;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ count = atk_table_get_selected_rows (table, &selected_rows);
+ if (!selected_rows)
+ count = 0;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ /* tbd - figure out if this is safe for a 0-length array */
+ dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
+ &selected_rows, count, DBUS_TYPE_INVALID);
+ }
+ if (selected_rows)
+ g_free (selected_rows);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetSelectedColumns (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ gint *selected_columns = NULL;
+ gint count;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ count = atk_table_get_selected_columns (table, &selected_columns);
+ if (!selected_columns)
+ count = 0;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ /* tbd - figure out if this is safe for a 0-length array */
+ dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
+ &selected_columns, count, DBUS_TYPE_INVALID);
+ }
+ if (selected_columns)
+ g_free (selected_columns);
+ return reply;
+}
+
+static DBusMessage *
+impl_IsRowSelected (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_is_row_selected (table, row);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_IsColumnSelected (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t column;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_is_column_selected (table, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_IsSelected (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row, column;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32, &column,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_is_selected (table, row, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_AddRowSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_add_row_selection (table, row);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_AddColumnSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t column;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_add_column_selection (table, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_RemoveRowSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t row;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &row, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_remove_row_selection (table, row);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_RemoveColumnSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t column;
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &column, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ret = atk_table_remove_column_selection (table, column);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRowColumnExtentsAtIndex (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTable *table = (AtkTable *) user_data;
+ dbus_int32_t index;
+ dbus_int32_t row, column, row_extents, col_extents;
+ dbus_bool_t is_selected;
+ dbus_bool_t ret;
+ DBusMessage *reply;
+ AtkObject *cell;
+ AtkRole role = ATK_ROLE_INVALID;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ column = atk_table_get_column_at_index (table, index);
+ row = atk_table_get_row_at_index (table, index);
+ row_extents = atk_table_get_row_extent_at (table, row, column);
+ col_extents = atk_table_get_column_extent_at (table, row, column);
+ is_selected = atk_table_is_selected (table, row, column);
+ cell = atk_table_ref_at (table, row, column);
+ if (cell)
+ {
+ role = atk_object_get_role (cell);
+ g_object_unref (cell);
+ }
+ ret = (role == ATK_ROLE_TABLE_CELL ? TRUE : FALSE);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &ret,
+ DBUS_TYPE_INT32, &row, DBUS_TYPE_INT32,
+ &column, DBUS_TYPE_INT32, &row_extents,
+ DBUS_TYPE_INT32, &col_extents,
+ DBUS_TYPE_BOOLEAN, &is_selected,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetAccessibleAt, "GetAccessibleAt"},
+ {impl_GetIndexAt, "GetIndexAt"},
+ {impl_GetRowAtIndex, "GetRowAtIndex"},
+ {impl_GetColumnAtIndex, "GetColumnAtIndex"},
+ {impl_GetRowDescription, "GetRowDescription"},
+ {impl_GetColumnDescription, "GetColumnDescription"},
+ {impl_GetRowExtentAt, "GetRowExtentAt"},
+ {impl_GetColumnExtentAt, "GetColumnExtentAt"},
+ {impl_GetRowHeader, "GetRowHeader"},
+ {impl_GetColumnHeader, "GetColumnHeader"},
+ {impl_GetSelectedRows, "GetSelectedRows"},
+ {impl_GetSelectedColumns, "GetSelectedColumns"},
+ {impl_IsRowSelected, "IsRowSelected"},
+ {impl_IsColumnSelected, "IsColumnSelected"},
+ {impl_IsSelected, "IsSelected"},
+ {impl_AddRowSelection, "AddRowSelection"},
+ {impl_AddColumnSelection, "AddColumnSelection"},
+ {impl_RemoveRowSelection, "RemoveRowSelection"},
+ {impl_RemoveColumnSelection, "RemoveColumnSelection"},
+ {impl_GetRowColumnExtentsAtIndex, "GetRowColumnExtentsAtIndex"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_NRows, NULL, "NRows"},
+ {impl_get_NColumns, NULL, "NColumns"},
+ {impl_get_Caption, NULL, "Caption"},
+ {impl_get_Summary, NULL, "Summary"},
+ {impl_get_NSelectedRows, NULL, "NSelectedRows"},
+ {impl_get_NSelectedColumns, NULL, "NSelectedColumns"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_table (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_TABLE, spi_org_a11y_atspi_Table, methods, properties);
+};
diff --git a/atk-adaptor/adaptors/table-cell-adaptor.c b/atk-adaptor/adaptors/table-cell-adaptor.c
new file mode 100644
index 0000000..c557ed5
--- /dev/null
+++ b/atk-adaptor/adaptors/table-cell-adaptor.c
@@ -0,0 +1,191 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2013 SUSE LLC.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_ColumnSpan (DBusMessageIter * iter, void *user_data)
+{
+ AtkTableCell *cell = (AtkTableCell *) user_data;
+ g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_table_cell_get_column_span (cell));
+}
+
+static DBusMessage *
+message_from_object_array (DBusMessage *message, GPtrArray *array)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+ gint len;
+ gint i;
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append (reply, &iter);
+
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "(so)", &iter_array))
+ return reply; /* TODO: handle out of memory */
+ len = (array? array->len: 0);
+ for (i = 0; i < len; i++)
+ {
+ spi_object_append_reference (&iter_array, g_ptr_array_index (array, i));
+ }
+ dbus_message_iter_close_container (&iter, &iter_array);
+ g_ptr_array_unref (array);
+ return message;
+}
+
+static DBusMessage *
+impl_GetColumnHeaderCells (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTableCell *cell = user_data;
+ GPtrArray *array;
+
+ g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data),
+ droute_not_yet_handled_error (message));
+
+ array = atk_table_cell_get_column_header_cells (cell);
+ return message_from_object_array (message, array);
+}
+
+static dbus_bool_t
+impl_get_RowSpan (DBusMessageIter * iter, void *user_data)
+{
+ AtkTableCell *cell = (AtkTableCell *) user_data;
+ g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_table_cell_get_row_span (cell));
+}
+
+static DBusMessage *
+impl_GetRowHeaderCells (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTableCell *cell = user_data;
+ GPtrArray *array;
+
+ g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data),
+ droute_not_yet_handled_error (message));
+
+ array = atk_table_cell_get_row_header_cells (cell);
+ return message_from_object_array (message, array);
+}
+
+static dbus_bool_t
+impl_get_Position (DBusMessageIter * iter, void *user_data)
+{
+ AtkTableCell *cell = (AtkTableCell *) user_data;
+ gint row = -1, column = -1;
+ dbus_int32_t d_row, d_column;
+ DBusMessageIter iter_struct, iter_variant;
+
+ g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
+ if (!atk_table_cell_get_position (cell, &row, &column))
+ return FALSE;
+
+ d_row = row;
+ d_column = column;
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, "(ii)", &iter_variant);
+ dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL, &iter_struct);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &row);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &column);
+ dbus_message_iter_close_container (&iter_variant, &iter_struct);
+ dbus_message_iter_close_container (iter, &iter_variant);
+ return TRUE;
+}
+
+static dbus_bool_t
+impl_get_Table (DBusMessageIter * iter, void *user_data)
+{
+ AtkTableCell *cell = (AtkTableCell *) user_data;
+ AtkObject *table;
+
+ g_return_val_if_fail (ATK_IS_TABLE_CELL (user_data), FALSE);
+
+ table = atk_table_cell_get_table (cell);
+ if (!table)
+ return FALSE;
+ spi_object_append_reference (iter, table);
+ return TRUE;
+}
+
+static DBusMessage *
+impl_GetRowColumnSpan (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkTableCell *cell = (AtkTableCell *) user_data;
+ gint row, column, row_span, column_span;
+ dbus_int32_t d_row, d_column, d_row_span, d_column_span;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TABLE (user_data),
+ droute_not_yet_handled_error (message));
+ atk_table_cell_get_row_column_span (cell, &row, &column, &row_span,
+ &column_span);
+ d_row = row;
+ d_column = column;
+ d_row_span = row_span;
+ d_column_span = column_span;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &d_row, DBUS_TYPE_INT32,
+ &d_column, DBUS_TYPE_INT32, &d_row_span,
+ DBUS_TYPE_INT32, &d_column_span,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetRowHeaderCells, "GetRowHeaderCells"},
+ {impl_GetColumnHeaderCells, "GetColumnHeaderCells"},
+ {impl_GetRowColumnSpan, "GetRowColumnSpan"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_ColumnSpan, NULL, "ColumnSpan"},
+ {impl_get_Position, NULL, "Position"},
+ {impl_get_RowSpan, NULL, "RowSpan"},
+ {impl_get_Table, NULL, "Table"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_table_cell (DRoutePath * path)
+{
+ droute_path_add_interface (path,
+ ATSPI_DBUS_INTERFACE_TABLE_CELL,
+ spi_org_a11y_atspi_TableCell,
+ methods, properties);
+};
diff --git a/atk-adaptor/adaptors/text-adaptor.c b/atk-adaptor/adaptors/text-adaptor.c
new file mode 100644
index 0000000..be10349
--- /dev/null
+++ b/atk-adaptor/adaptors/text-adaptor.c
@@ -0,0 +1,892 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "object.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_CharacterCount (DBusMessageIter * iter, void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_text_get_character_count (text));
+}
+
+static dbus_bool_t
+impl_get_CaretOffset (DBusMessageIter * iter, void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ g_return_val_if_fail (ATK_IS_TEXT (user_data), FALSE);
+ return droute_return_v_int32 (iter, atk_text_get_caret_offset (text));
+}
+
+static gchar *
+validate_allocated_string (gchar *str)
+{
+ if (!str)
+ return g_strdup ("");
+ if (!g_utf8_validate (str, -1, NULL))
+ {
+ g_warning ("atk-bridge: received bad UTF-8 string from a get_text function");
+ g_free (str);
+ return g_strdup ("");
+ }
+ return str;
+}
+
+static DBusMessage *
+impl_GetText (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t startOffset, endOffset;
+ gchar *txt;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
+ &endOffset, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ txt = atk_text_get_text (text, startOffset, endOffset);
+ txt = validate_allocated_string (txt);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
+ DBUS_TYPE_INVALID);
+ }
+ g_free (txt);
+ return reply;
+}
+
+static DBusMessage *
+impl_SetCaretOffset (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_text_set_caret_offset (text, offset);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetTextBeforeOffset (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_uint32_t type;
+ gchar *txt;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset = 0, intend_offset = 0;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ txt =
+ atk_text_get_text_before_offset (text, offset, (AtkTextBoundary) type,
+ &intstart_offset, &intend_offset);
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ txt = validate_allocated_string (txt);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
+ DBUS_TYPE_INT32, &startOffset,
+ DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_INVALID);
+ }
+ g_free (txt);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetTextAtOffset (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset, type;
+ gchar *txt;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset = 0, intend_offset = 0;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ txt =
+ atk_text_get_text_at_offset (text, offset, (AtkTextBoundary) type,
+ &intstart_offset, &intend_offset);
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ txt = validate_allocated_string (txt);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
+ DBUS_TYPE_INT32, &startOffset,
+ DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_INVALID);
+ }
+ g_free (txt);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetTextAfterOffset (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_uint32_t type;
+ gchar *txt;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset = 0, intend_offset = 0;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &type,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ txt =
+ atk_text_get_text_after_offset (text, offset, (AtkTextBoundary) type,
+ &intstart_offset, &intend_offset);
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ txt = validate_allocated_string (txt);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
+ DBUS_TYPE_INT32, &startOffset,
+ DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_INVALID);
+ }
+ g_free (txt);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetCharacterAtOffset (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_int32_t ch;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ ch = atk_text_get_character_at_offset (text, offset);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &ch,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static gchar *
+get_text_for_legacy_implementations(AtkText *text,
+ gint offset,
+ AtkTextGranularity granularity,
+ gint *start_offset,
+ gint *end_offset)
+{
+ gchar *txt = 0;
+ AtkTextBoundary boundary = 0;
+ switch (granularity) {
+ case ATK_TEXT_GRANULARITY_CHAR:
+ boundary = ATK_TEXT_BOUNDARY_CHAR;
+ break;
+
+ case ATK_TEXT_GRANULARITY_WORD:
+ boundary = ATK_TEXT_BOUNDARY_WORD_START;
+ break;
+
+ case ATK_TEXT_GRANULARITY_SENTENCE:
+ boundary = ATK_TEXT_BOUNDARY_SENTENCE_START;
+ break;
+
+ case ATK_TEXT_GRANULARITY_LINE:
+ boundary = ATK_TEXT_BOUNDARY_LINE_START;
+ break;
+
+ case ATK_TEXT_GRANULARITY_PARAGRAPH:
+ /* This is not implemented in previous versions of ATK */
+ txt = g_strdup("");
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ if (!txt)
+ {
+ txt =
+ atk_text_get_text_at_offset (text, offset, boundary,
+ start_offset, end_offset);
+ }
+
+ return txt;
+}
+
+static DBusMessage *
+impl_GetStringAtOffset (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_uint32_t granularity;
+ gchar *txt = 0;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset = 0, intend_offset = 0;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &granularity,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ txt =
+ atk_text_get_string_at_offset (text, offset, (AtkTextGranularity) granularity,
+ &intstart_offset, &intend_offset);
+
+ /* Accessibility layers implementing an older version of ATK (even if
+ * a new enough version of libatk is installed) might return NULL due
+ * not to provide an implementation for get_string_at_offset(), so we
+ * try with the legacy implementation if that's the case. */
+ if (!txt)
+ txt = get_text_for_legacy_implementations(text, offset,
+ (AtkTextGranularity) granularity,
+ &intstart_offset, &intend_offset);
+
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ txt = validate_allocated_string (txt);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &txt,
+ DBUS_TYPE_INT32, &startOffset,
+ DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_INVALID);
+ }
+ g_free (txt);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAttributeValue (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ char *attributeName;
+ dbus_int32_t startOffset, endOffset;
+ dbus_bool_t defined;
+ gint intstart_offset = 0, intend_offset = 0;
+ char *rv = NULL;
+ DBusMessage *reply;
+ AtkAttributeSet *set;
+ GSList *cur_attr;
+ AtkAttribute *at;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_STRING,
+ &attributeName, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ set = atk_text_get_run_attributes (text, offset,
+ &intstart_offset, &intend_offset);
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ defined = FALSE;
+ cur_attr = (GSList *) set;
+ while (cur_attr)
+ {
+ at = (AtkAttribute *) cur_attr->data;
+ if (!strcmp (at->name, attributeName))
+ {
+ rv = at->value;
+ defined = TRUE;
+ break;
+ }
+ cur_attr = cur_attr->next;
+ }
+ if (!rv)
+ rv = "";
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &rv, DBUS_TYPE_INT32,
+ &startOffset, DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_BOOLEAN, &defined,
+ DBUS_TYPE_INVALID);
+ }
+ atk_attribute_set_free (set);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAttributes (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset, intend_offset;
+ DBusMessage *reply;
+ AtkAttributeSet *set;
+ DBusMessageIter iter;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ set = atk_text_get_run_attributes (text, offset,
+ &intstart_offset, &intend_offset);
+
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_attribute_set (&iter, set);
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
+ DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_INVALID);
+ }
+ atk_attribute_set_free (set);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetDefaultAttributes (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ DBusMessage *reply;
+ AtkAttributeSet *set;
+ DBusMessageIter iter;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+
+ set = atk_text_get_default_attributes (text);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_attribute_set (&iter, set);
+ }
+ atk_attribute_set_free (set);
+ return reply;
+}
+
+static DBusMessage *
+impl_GetCharacterExtents (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_uint32_t coordType;
+ dbus_int32_t x, y, width, height;
+ gint ix = 0, iy = 0, iw = 0, ih = 0;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32,
+ &coordType, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ atk_text_get_character_extents (text, offset, &ix, &iy, &iw, &ih,
+ (AtkCoordType) coordType);
+ x = ix;
+ y = iy;
+ width = iw;
+ height = ih;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
+ &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
+ &height, DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetOffsetAtPoint (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t x, y;
+ dbus_uint32_t coordType;
+ dbus_int32_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
+ DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_text_get_offset_at_point (text, x, y, coordType);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetNSelections (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ rv = atk_text_get_n_selections (text);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t selectionNum;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset = 0, intend_offset = 0;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ /* atk_text_get_selection returns gchar * which we discard */
+ g_free (atk_text_get_selection
+ (text, selectionNum, &intstart_offset, &intend_offset));
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &startOffset,
+ DBUS_TYPE_INT32, &endOffset,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_AddSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t startOffset, endOffset;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
+ &endOffset, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_text_add_selection (text, startOffset, endOffset);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_RemoveSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t selectionNum;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_text_remove_selection (text, selectionNum);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_SetSelection (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t selectionNum, startOffset, endOffset;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &selectionNum, DBUS_TYPE_INT32,
+ &startOffset, DBUS_TYPE_INT32, &endOffset, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rv = atk_text_set_selection (text, selectionNum, startOffset, endOffset);
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DBusMessage *
+impl_GetRangeExtents (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t startOffset, endOffset;
+ dbus_uint32_t coordType;
+ AtkTextRectangle rect;
+ dbus_int32_t x, y, width, height;
+ DBusMessage *reply;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &startOffset, DBUS_TYPE_INT32,
+ &endOffset, DBUS_TYPE_UINT32, &coordType, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ memset (&rect, 0, sizeof (rect));
+ atk_text_get_range_extents (text, startOffset, endOffset,
+ (AtkCoordType) coordType, &rect);
+ x = rect.x;
+ y = rect.y;
+ width = rect.width;
+ height = rect.height;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32,
+ &y, DBUS_TYPE_INT32, &width, DBUS_TYPE_INT32,
+ &height, DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+#define MAXRANGELEN 512
+
+static DBusMessage *
+impl_GetBoundedRanges (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t x, y, width, height;
+ dbus_uint32_t coordType, xClipType, yClipType;
+ AtkTextRange **range_list = NULL;
+ AtkTextRectangle rect;
+ DBusMessage *reply;
+ DBusMessageIter iter, array, struc, variant;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
+ DBUS_TYPE_INT32, &height, DBUS_TYPE_INT32, &width, DBUS_TYPE_UINT32,
+ &coordType, DBUS_TYPE_UINT32, &xClipType, DBUS_TYPE_UINT32, &yClipType,
+ DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+
+ range_list =
+ atk_text_get_bounded_ranges (text, &rect, (AtkCoordType) coordType,
+ (AtkTextClipType) xClipType,
+ (AtkTextClipType) yClipType);
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ return NULL;
+ /* This isn't pleasant. */
+ dbus_message_iter_init_append (reply, &iter);
+ if (dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "(iisv)", &array))
+ {
+ int len;
+ int count = (range_list ? MAXRANGELEN : 0);
+ for (len = 0; len < count && range_list[len]; ++len)
+ {
+ if (dbus_message_iter_open_container
+ (&array, DBUS_TYPE_STRUCT, NULL, &struc))
+ {
+ dbus_int32_t val;
+ val = range_list[len]->start_offset;
+ dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
+ val = range_list[len]->end_offset;
+ dbus_message_iter_append_basic (&struc, DBUS_TYPE_INT32, &val);
+ dbus_message_iter_append_basic (&struc, DBUS_TYPE_STRING,
+ &range_list[len]->content);
+ /* The variant is unimplemented in atk, but I don't want to
+ * unilaterally muck with the spec and remove it, so I'll just
+ * throw in a dummy value */
+ if (dbus_message_iter_open_container
+ (&struc, DBUS_TYPE_VARIANT, "i", &variant))
+ {
+ dbus_uint32_t dummy = 0;
+ dbus_message_iter_append_basic (&variant, DBUS_TYPE_INT32,
+ &dummy);
+ dbus_message_iter_close_container (&struc, &variant);
+ }
+ dbus_message_iter_close_container (&array, &struc);
+ g_free (range_list[len]->content);
+ g_free (range_list[len]);
+ }
+ }
+ dbus_message_iter_close_container (&iter, &array);
+ }
+
+ if (range_list)
+ g_free (range_list);
+
+ return reply;
+}
+
+static DBusMessage *
+impl_GetAttributeRun (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ dbus_int32_t offset;
+ dbus_bool_t includeDefaults;
+ dbus_int32_t startOffset, endOffset;
+ gint intstart_offset = 0, intend_offset = 0;
+ DBusMessage *reply;
+ AtkAttributeSet *attributes = NULL;
+ DBusMessageIter iter;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_INT32, &offset, DBUS_TYPE_BOOLEAN,
+ &includeDefaults, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ attributes =
+ atk_text_get_run_attributes (text, offset, &intstart_offset,
+ &intend_offset);
+
+ if (includeDefaults)
+ {
+ attributes = g_slist_concat (attributes,
+ atk_text_get_default_attributes (text));
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_attribute_set (&iter, attributes);
+
+ startOffset = intstart_offset;
+ endOffset = intend_offset;
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &startOffset);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &endOffset);
+
+ atk_attribute_set_free (attributes);
+
+ return reply;
+}
+
+static DBusMessage *
+impl_GetDefaultAttributeSet (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkText *text = (AtkText *) user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ AtkAttributeSet *attributes;
+
+ g_return_val_if_fail (ATK_IS_TEXT (user_data),
+ droute_not_yet_handled_error (message));
+
+ attributes = atk_text_get_default_attributes (text);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_attribute_set (&iter, attributes);
+ }
+
+ if (attributes)
+ atk_attribute_set_free (attributes);
+
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_GetText, "GetText"},
+ {impl_SetCaretOffset, "SetCaretOffset"},
+ {impl_GetTextBeforeOffset, "GetTextBeforeOffset"},
+ {impl_GetTextAtOffset, "GetTextAtOffset"},
+ {impl_GetTextAfterOffset, "GetTextAfterOffset"},
+ {impl_GetStringAtOffset, "GetStringAtOffset"},
+ {impl_GetCharacterAtOffset, "GetCharacterAtOffset"},
+ {impl_GetAttributeValue, "GetAttributeValue"},
+ {impl_GetAttributes, "GetAttributes"},
+ {impl_GetDefaultAttributes, "GetDefaultAttributes"},
+ {impl_GetCharacterExtents, "GetCharacterExtents"},
+ {impl_GetOffsetAtPoint, "GetOffsetAtPoint"},
+ {impl_GetNSelections, "GetNSelections"},
+ {impl_GetSelection, "GetSelection"},
+ {impl_AddSelection, "AddSelection"},
+ {impl_RemoveSelection, "RemoveSelection"},
+ {impl_SetSelection, "SetSelection"},
+ {impl_GetRangeExtents, "GetRangeExtents"},
+ {impl_GetBoundedRanges, "GetBoundedRanges"},
+ {impl_GetAttributeRun, "GetAttributeRun"},
+ {impl_GetDefaultAttributeSet, "GetDefaultAttributeSet"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_CharacterCount, NULL, "CharacterCount"},
+ {impl_get_CaretOffset, NULL, "CaretOffset"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_text (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_TEXT, spi_org_a11y_atspi_Text, methods, properties);
+};
diff --git a/atk-adaptor/adaptors/value-adaptor.c b/atk-adaptor/adaptors/value-adaptor.c
new file mode 100644
index 0000000..9767fc4
--- /dev/null
+++ b/atk-adaptor/adaptors/value-adaptor.c
@@ -0,0 +1,208 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include "bridge.h"
+
+#include "spi-dbus.h"
+#include "introspection.h"
+
+static dbus_bool_t
+impl_get_MinimumValue (DBusMessageIter * iter, void *user_data)
+{
+ AtkValue *value = (AtkValue *) user_data;
+ GValue src = { 0 };
+ GValue dest = { 0 };
+ gdouble dub;
+
+ g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE);
+
+ g_value_init (&src, G_TYPE_DOUBLE);
+ atk_value_get_minimum_value (value, &src);
+ g_value_init (&dest, G_TYPE_DOUBLE);
+
+ if (g_value_transform (&src, &dest))
+ {
+ dub = g_value_get_double (&dest);
+ return droute_return_v_double (iter, dub);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static dbus_bool_t
+impl_get_MaximumValue (DBusMessageIter * iter, void *user_data)
+{
+ AtkValue *value = (AtkValue *) user_data;
+ GValue src = { 0 };
+ GValue dest = { 0 };
+ gdouble dub = 0;
+
+ g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE);
+
+ g_value_init (&src, G_TYPE_DOUBLE);
+ atk_value_get_maximum_value (value, &src);
+ g_value_init (&dest, G_TYPE_DOUBLE);
+
+ if (g_value_transform (&src, &dest))
+ {
+ dub = g_value_get_double (&dest);
+ }
+ return droute_return_v_double (iter, dub);
+}
+
+static dbus_bool_t
+impl_get_MinimumIncrement (DBusMessageIter * iter, void *user_data)
+{
+ AtkValue *value = (AtkValue *) user_data;
+ GValue src = { 0 };
+ GValue dest = { 0 };
+ gdouble dub = 0;
+
+ g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE);
+
+ g_value_init (&src, G_TYPE_DOUBLE);
+ atk_value_get_minimum_increment (value, &src);
+ g_value_init (&dest, G_TYPE_DOUBLE);
+
+ if (g_value_transform (&src, &dest))
+ {
+ dub = g_value_get_double (&dest);
+ }
+ return droute_return_v_double (iter, dub);
+}
+
+static dbus_bool_t
+impl_get_CurrentValue (DBusMessageIter * iter, void *user_data)
+{
+ AtkValue *value = (AtkValue *) user_data;
+ GValue src = { 0 };
+ GValue dest = { 0 };
+ gdouble dub = 0;
+
+ g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE);
+
+ g_value_init (&src, G_TYPE_DOUBLE);
+ atk_value_get_current_value (value, &src);
+ g_value_init (&dest, G_TYPE_DOUBLE);
+
+ if (g_value_transform (&src, &dest))
+ {
+ dub = g_value_get_double (&dest);
+ }
+ return droute_return_v_double (iter, dub);
+}
+
+static dbus_bool_t
+impl_set_CurrentValue (DBusMessageIter * iter, void *user_data)
+{
+ AtkValue *value = (AtkValue *) user_data;
+ GValue src = { 0 };
+ GValue dest = { 0 };
+ gdouble dub;
+ DBusMessageIter iter_variant;
+
+ g_return_val_if_fail (ATK_IS_VALUE (user_data), FALSE);
+
+ dbus_message_iter_recurse (iter, &iter_variant);
+ if (dbus_message_iter_get_arg_type (&iter_variant) != DBUS_TYPE_DOUBLE)
+ {
+ g_warning ("TODO: Support setting value from a non-double");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic (&iter_variant, &dub);
+ g_value_init (&src, G_TYPE_DOUBLE);
+ g_value_set_double (&src, dub);
+
+ atk_value_get_current_value (value, &dest);
+
+ if (g_value_transform (&src, &dest))
+ {
+ atk_value_set_current_value (value, &dest);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* keeping this method around for backwards-compatibility for now; see
+ * * BGO#652596 */
+static DBusMessage *
+impl_SetCurrentValue (DBusConnection * bus, DBusMessage * message,
+ void *user_data)
+{
+ AtkValue *value = (AtkValue *) user_data;
+ dbus_bool_t rv;
+ DBusMessage *reply;
+ gdouble dub = 0;
+ GValue new_value = { 0 };
+
+ g_return_val_if_fail (ATK_IS_VALUE (value),
+ droute_not_yet_handled_error (message));
+
+ if (!dbus_message_get_args
+ (message, NULL, DBUS_TYPE_DOUBLE, &dub, DBUS_TYPE_INVALID))
+ {
+ return droute_invalid_arguments_error (message);
+ }
+
+ g_value_init (&new_value, G_TYPE_DOUBLE);
+ g_value_set_double (&new_value, dub);
+ rv = atk_value_set_current_value (value, &new_value);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &rv,
+ DBUS_TYPE_INVALID);
+ }
+ return reply;
+}
+
+static DRouteMethod methods[] = {
+ {impl_SetCurrentValue, "SetCurrentValue"},
+ {NULL, NULL}
+};
+
+static DRouteProperty properties[] = {
+ {impl_get_MinimumValue, NULL, "MinimumValue"},
+ {impl_get_MaximumValue, NULL, "MaximumValue"},
+ {impl_get_MinimumIncrement, NULL, "MinimumIncrement"},
+ {impl_get_CurrentValue, impl_set_CurrentValue, "CurrentValue"},
+ {NULL, NULL, NULL}
+};
+
+void
+spi_initialize_value (DRoutePath * path)
+{
+ spi_atk_add_interface (path,
+ ATSPI_DBUS_INTERFACE_VALUE, spi_org_a11y_atspi_Value, methods, properties);
+};
diff --git a/atk-adaptor/atk-bridge.h b/atk-adaptor/atk-bridge.h
new file mode 100644
index 0000000..9c0dd0d
--- /dev/null
+++ b/atk-adaptor/atk-bridge.h
@@ -0,0 +1,37 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
+ * Copyright 2001, 2002, 2003 Ximian, Inc.
+ * Copyright 2008, 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ATK_BRIDGE_H
+#define ATK_BRIDGE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+int atk_bridge_adaptor_init (int * argc, char ** argv[]);
+void atk_bridge_adaptor_cleanup (void);
+
+G_END_DECLS
+
+#endif /* ATK_BRIDGE_H */
diff --git a/atk-adaptor/atkbridge.symbols b/atk-adaptor/atkbridge.symbols
new file mode 100644
index 0000000..d90cf94
--- /dev/null
+++ b/atk-adaptor/atkbridge.symbols
@@ -0,0 +1,2 @@
+atk_bridge_adaptor_init
+atk_bridge_adaptor_cleanup
diff --git a/atk-adaptor/bitarray.h b/atk-adaptor/bitarray.h
new file mode 100644
index 0000000..61ed673
--- /dev/null
+++ b/atk-adaptor/bitarray.h
@@ -0,0 +1,32 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BITARRAY_H
+#define _BITARRAY_H
+
+#include "dbus/dbus.h"
+#include "glib.h"
+
+#define BITARRAY_SEQ_TERM 0xffffffff
+
+#define BITARRAY_SET(p, n) ((p)[n>>5] |= (1<<(n&31)))
+#endif /* _BITARRAY_H */
diff --git a/atk-adaptor/bridge.c b/atk-adaptor/bridge.c
new file mode 100644
index 0000000..e542094
--- /dev/null
+++ b/atk-adaptor/bridge.c
@@ -0,0 +1,1232 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008, 2009 Codethink Ltd.
+ * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
+ * Copyright 2001, 2002, 2003 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include<sys/stat.h>
+#include <atk/atk.h>
+
+#include <droute/droute.h>
+#include <atspi/atspi.h>
+#include <atk-bridge.h>
+
+#include "bridge.h"
+#include "event.h"
+#include "adaptors.h"
+#include "object.h"
+#include "accessible-stateset.h"
+
+#include "accessible-register.h"
+#include "accessible-leasing.h"
+#include "accessible-cache.h"
+
+#include "spi-dbus.h"
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data);
+
+SpiBridge *spi_global_app_data = NULL;
+
+static gboolean inited = FALSE;
+
+/*---------------------------------------------------------------------------*/
+
+static event_data *
+add_event (const char *bus_name, const char *event)
+{
+ event_data *evdata;
+ gchar **data;
+
+ spi_atk_add_client (bus_name);
+ evdata = g_new0 (event_data, 1);
+ data = g_strsplit (event, ":", 3);
+ if (!data)
+ {
+ g_free (evdata);
+ return NULL;
+ }
+ evdata->bus_name = g_strdup (bus_name);
+ evdata->data = data;
+ spi_global_app_data->events = g_list_append (spi_global_app_data->events, evdata);
+ return evdata;
+}
+
+static GSList *clients = NULL;
+
+static void
+tally_event_reply ()
+{
+ static int replies_received = 0;
+
+ if (!spi_global_app_data)
+ return;
+
+ replies_received++;
+ if (replies_received == 3)
+ {
+ if (!clients)
+ spi_atk_deregister_event_listeners ();
+ spi_global_app_data->events_initialized = TRUE;
+ }
+}
+
+GType
+_atk_bridge_type_from_iface (const char *iface)
+{
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_ACCESSIBLE))
+ return ATK_TYPE_OBJECT;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_ACTION))
+ return ATK_TYPE_ACTION;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_COMPONENT))
+ return ATK_TYPE_COMPONENT;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_DOCUMENT))
+ return ATK_TYPE_DOCUMENT;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_HYPERTEXT))
+ return ATK_TYPE_HYPERTEXT;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_HYPERLINK))
+ return ATK_TYPE_HYPERLINK;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_IMAGE))
+ return ATK_TYPE_IMAGE;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_SELECTION))
+ return ATK_TYPE_SELECTION;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_TABLE))
+ return ATK_TYPE_TABLE;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_TEXT))
+ return ATK_TYPE_TEXT;
+ if (!strcmp (iface, ATSPI_DBUS_INTERFACE_VALUE))
+ return ATK_TYPE_VALUE;
+ return 0;
+}
+
+DRoutePropertyFunction
+_atk_bridge_find_property_func (const char *property, GType *type)
+{
+ const char *iface;
+ const char *member;
+ DRouteProperty *dp;
+
+ if (!strncasecmp (property, "action.", 7))
+ {
+ iface = ATSPI_DBUS_INTERFACE_ACTION;
+ member = property + 7;
+ }
+ else if (!strncasecmp (property, "component.", 10))
+ {
+ iface = ATSPI_DBUS_INTERFACE_COMPONENT;
+ member = property + 10;
+ }
+ else if (!strncasecmp (property, "selection.", 10))
+ {
+ iface = ATSPI_DBUS_INTERFACE_SELECTION;
+ member = property + 10;
+ }
+ else if (!strncasecmp (property, "table.", 6))
+ {
+ iface = ATSPI_DBUS_INTERFACE_TABLE;
+ member = property + 6;
+ }
+ else if (!strncasecmp (property, "text.", 5))
+ {
+ iface = ATSPI_DBUS_INTERFACE_TEXT;
+ member = property + 5;
+ }
+ else if (!strncasecmp (property, "value.", 6))
+ {
+ iface = ATSPI_DBUS_INTERFACE_VALUE;
+ member = property + 6;
+ }
+ else
+ {
+ iface = ATSPI_DBUS_INTERFACE_ACCESSIBLE;
+ member = property;
+ }
+
+ *type = _atk_bridge_type_from_iface (iface);
+
+ dp = g_hash_table_lookup (spi_global_app_data->property_hash, iface);
+
+ if (!dp)
+ return NULL;
+
+ for (;dp->name; dp++)
+ {
+ if (!strcasecmp (dp->name, member))
+ {
+ return dp->get;
+ }
+ }
+ return NULL;
+}
+
+static void
+add_property_to_event (event_data *evdata, const char *property)
+{
+ AtspiPropertyDefinition *prop = g_new0 (AtspiPropertyDefinition, 1);
+ prop->func = _atk_bridge_find_property_func (property, &prop->type);
+ if (!prop->func)
+ {
+ g_warning ("atk-bridge: Request for unknown property '%s'", property);
+ g_free (prop);
+ return;
+ }
+
+ prop->name = g_strdup (property);
+
+ if (evdata)
+ {
+ evdata->properties = g_slist_append (evdata->properties, prop);
+ }
+}
+
+static void
+add_event_from_iter (DBusMessageIter *iter)
+{
+ const char *bus_name, *event;
+ event_data *evdata;
+
+ dbus_message_iter_get_basic (iter, &bus_name);
+ dbus_message_iter_next (iter);
+ dbus_message_iter_get_basic (iter, &event);
+ dbus_message_iter_next (iter);
+ evdata = add_event (bus_name, event);
+ if (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY)
+ {
+ DBusMessageIter iter_sub_array;
+ dbus_message_iter_recurse (iter, &iter_sub_array);
+ while (dbus_message_iter_get_arg_type (&iter_sub_array) != DBUS_TYPE_INVALID)
+ {
+ const char *property;
+ dbus_message_iter_get_basic (&iter_sub_array, &property);
+ add_property_to_event (evdata, property);
+ dbus_message_iter_next (&iter_sub_array);
+ }
+ }
+}
+
+static void
+get_events_reply (DBusPendingCall *pending, void *user_data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply (pending);
+ DBusMessageIter iter, iter_array, iter_struct;
+
+ if (!reply || !spi_global_app_data)
+ goto done;
+
+ if (strcmp (dbus_message_get_signature (reply), "a(ss)") != 0 &&
+ strcmp (dbus_message_get_signature (reply), "a(ssas)") != 0)
+ {
+ g_warning ("atk-bridge: GetRegisteredEvents returned message with unknown signature");
+ goto done;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_array);
+ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+ {
+ dbus_message_iter_recurse (&iter_array, &iter_struct);
+ add_event_from_iter (&iter_struct);
+ dbus_message_iter_next (&iter_array);
+ }
+
+done:
+ if (reply)
+ dbus_message_unref (reply);
+ if (pending)
+ dbus_pending_call_unref (pending);
+
+ tally_event_reply ();
+}
+
+static void
+get_device_events_reply (DBusPendingCall *pending, void *user_data)
+{
+ DBusMessage *reply = dbus_pending_call_steal_reply (pending);
+ DBusMessageIter iter, iter_array, iter_struct;
+
+ if (!reply)
+ goto done;
+
+ if (strncmp (dbus_message_get_signature (reply), "a(s", 3) != 0)
+ {
+ g_warning ("atk-bridge: get_device_events_reply: unknown signature");
+ goto done;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_array);
+ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+ {
+ char *bus_name;
+ dbus_message_iter_recurse (&iter_array, &iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &bus_name);
+ spi_atk_add_client (bus_name);
+ dbus_message_iter_next (&iter_array);
+ }
+
+done:
+ if (reply)
+ dbus_message_unref (reply);
+ if (pending)
+ dbus_pending_call_unref (pending);
+
+ tally_event_reply ();
+}
+
+static void
+get_registered_event_listeners (SpiBridge *app)
+{
+ DBusMessage *message;
+ DBusPendingCall *pending = NULL;
+
+ message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+ ATSPI_DBUS_PATH_REGISTRY,
+ ATSPI_DBUS_INTERFACE_REGISTRY,
+ "GetRegisteredEvents");
+ if (!message)
+ return;
+
+ dbus_connection_send_with_reply (app->bus, message, &pending, -1);
+ dbus_message_unref (message);
+ if (!pending)
+ {
+ spi_global_app_data->events_initialized = TRUE;
+ return;
+ }
+ dbus_pending_call_set_notify (pending, get_events_reply, NULL, NULL);
+
+ message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+ ATSPI_DBUS_PATH_DEC,
+ ATSPI_DBUS_INTERFACE_DEC,
+ "GetKeystrokeListeners");
+ if (!message)
+ return;
+ pending = NULL;
+ dbus_connection_send_with_reply (app->bus, message, &pending, -1);
+ dbus_message_unref (message);
+ if (!pending)
+ {
+ spi_global_app_data->events_initialized = TRUE;
+ return;
+ }
+ dbus_pending_call_set_notify (pending, get_device_events_reply, NULL, NULL);
+
+ message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+ ATSPI_DBUS_PATH_DEC,
+ ATSPI_DBUS_INTERFACE_DEC,
+ "GetDeviceEventListeners");
+ if (!message)
+ return;
+ pending = NULL;
+ dbus_connection_send_with_reply (app->bus, message, &pending, -1);
+ dbus_message_unref (message);
+ if (!pending)
+ {
+ spi_global_app_data->events_initialized = TRUE;
+ return;
+ }
+ dbus_pending_call_set_notify (pending, get_device_events_reply, NULL, NULL);
+}
+
+static void
+register_reply (DBusPendingCall *pending, void *user_data)
+{
+ DBusMessage *reply;
+ SpiBridge *app = user_data;
+
+ reply = dbus_pending_call_steal_reply (pending);
+ dbus_pending_call_unref (pending);
+
+ if (!spi_global_app_data)
+ {
+ if (reply)
+ dbus_message_unref (reply);
+ return;
+ }
+
+ if (reply)
+ {
+ gchar *app_name, *obj_path;
+
+ if (strcmp (dbus_message_get_signature (reply), "(so)") != 0)
+ {
+ g_warning ("AT-SPI: Could not obtain desktop path or name\n");
+ }
+ else
+ {
+ DBusMessageIter iter, iter_struct;
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &app_name);
+ dbus_message_iter_next (&iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &obj_path);
+
+ g_free (app->desktop_name);
+ app->desktop_name = g_strdup (app_name);
+ g_free (app->desktop_path);
+ app->desktop_path = g_strdup (obj_path);
+ }
+ }
+ else
+ {
+ g_warning ("AT-SPI: Could not embed inside desktop");
+ return;
+ }
+ dbus_message_unref (reply);
+
+ if (!spi_global_app_data->events_initialized)
+ get_registered_event_listeners (spi_global_app_data);
+}
+
+static gboolean
+register_application (SpiBridge * app)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusPendingCall *pending;
+
+ g_free (app->desktop_name);
+ g_free (app->desktop_path);
+
+ /* These will be overridden when we get a reply, but in practice these
+ defaults should always be correct */
+ app->desktop_name = g_strdup (ATSPI_DBUS_NAME_REGISTRY);
+ app->desktop_path = g_strdup (ATSPI_DBUS_PATH_ROOT);
+
+ message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+ ATSPI_DBUS_PATH_ROOT,
+ ATSPI_DBUS_INTERFACE_SOCKET,
+ "Embed");
+
+ dbus_message_iter_init_append (message, &iter);
+ spi_object_append_reference (&iter, app->root);
+
+ if (!dbus_connection_send_with_reply (app->bus, message, &pending, -1)
+ || !pending)
+ {
+ if (pending)
+ dbus_pending_call_unref (pending);
+
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_pending_call_set_notify (pending, register_reply, app, NULL);
+
+ if (message)
+ dbus_message_unref (message);
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+deregister_application (SpiBridge * app)
+{
+ DBusMessage *message;
+ DBusMessageIter iter;
+ const char *uname;
+
+ message = dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+ ATSPI_DBUS_PATH_REGISTRY,
+ ATSPI_DBUS_INTERFACE_REGISTRY,
+ "DeregisterApplication");
+ dbus_message_set_no_reply (message, TRUE);
+
+ uname = dbus_bus_get_unique_name (app->bus);
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &uname);
+ dbus_connection_send (app->bus, message, NULL);
+ if (message)
+ dbus_message_unref (message);
+
+ if (app->app_bus_addr)
+ {
+ unlink (app->app_bus_addr);
+ g_free (app->app_bus_addr);
+ app->app_bus_addr = NULL;
+ }
+
+ if (app->app_tmp_dir)
+ {
+ rmdir (app->app_tmp_dir);
+ g_free (app->app_tmp_dir);
+ app->app_tmp_dir = NULL;
+ }
+
+ g_free (app->desktop_name);
+ app->desktop_name = NULL;
+ g_free (app->desktop_path);
+ app->desktop_path = NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+
+static AtkPlugClass *plug_class;
+static AtkSocketClass *socket_class;
+
+static gchar *
+get_plug_id (AtkPlug * plug)
+{
+ const char *uname = dbus_bus_get_unique_name (spi_global_app_data->bus);
+ gchar *path;
+ GString *str = g_string_new (NULL);
+
+ path = spi_register_object_to_path (spi_global_register, G_OBJECT (plug));
+ g_string_printf (str, "%s:%s", uname, path);
+ g_free (path);
+ return g_string_free (str, FALSE);
+}
+
+AtkStateSet *
+socket_ref_state_set (AtkObject *accessible)
+{
+ char *child_name, *child_path;
+ AtkSocket *socket = ATK_SOCKET (accessible);
+ int count = 0;
+ int j;
+ int v;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, iter_array;
+ AtkStateSet *set;
+
+ set = atk_state_set_new ();
+
+ if (!socket->embedded_plug_id)
+ return set;
+
+ child_name = g_strdup (socket->embedded_plug_id);
+ if (!child_name)
+ return set;
+ child_path = g_utf8_strchr (child_name + 1, -1, ':');
+ if (!child_path)
+ {
+ g_free (child_name);
+ return set;
+ }
+ *(child_path++) = '\0';
+ message = dbus_message_new_method_call (child_name, child_path, ATSPI_DBUS_INTERFACE_ACCESSIBLE, "GetState");
+ g_free (child_name);
+ reply = dbus_connection_send_with_reply_and_block (spi_global_app_data->bus, message, 1, NULL);
+ dbus_message_unref (message);
+ if (reply == NULL)
+ return set;
+ if (strcmp (dbus_message_get_signature (reply), "au") != 0)
+ {
+ dbus_message_unref (reply);
+ return set;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_array);
+ do
+ {
+ dbus_message_iter_get_basic (&iter_array, &v);
+ for (j = 0; j < 32; j++)
+ {
+ if (v & (1 << j))
+ {
+ AtkState state = spi_atk_state_from_spi_state ((count << 5) + j);
+ atk_state_set_add_state (set, state);
+ }
+ }
+ count++;
+ }
+ while (dbus_message_iter_next (&iter_array));
+ dbus_message_unref (reply);
+ return set;
+}
+
+static void
+socket_embed_hook (AtkSocket * socket, gchar * plug_id)
+{
+ g_return_if_fail (spi_global_register != NULL);
+
+ AtkObject *accessible = ATK_OBJECT(socket);
+ gchar *plug_name, *plug_path;
+ AtkObjectClass *klass;
+
+ /* Force registration */
+ gchar *path = spi_register_object_to_path (spi_global_register, G_OBJECT (accessible));
+ /* Let the plug know that it has been embedded */
+ plug_name = g_strdup (plug_id);
+ if (!plug_name)
+ {
+ g_free (path);
+ return;
+ }
+ plug_path = g_utf8_strchr (plug_name + 1, -1, ':');
+ if (plug_path)
+ {
+ DBusMessage *message;
+ *(plug_path++) = '\0';
+ message = dbus_message_new_method_call (plug_name, plug_path, ATSPI_DBUS_INTERFACE_SOCKET, "Embedded");
+ dbus_message_append_args (message, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
+ dbus_connection_send (spi_global_app_data->bus, message, NULL);
+ }
+ g_free (plug_name);
+ g_free (path);
+
+ klass = ATK_OBJECT_GET_CLASS (accessible);
+ klass->ref_state_set = socket_ref_state_set;
+}
+
+static void
+install_plug_hooks ()
+{
+ gpointer data;
+
+ data = g_type_class_ref (ATK_TYPE_PLUG);
+ plug_class = ATK_PLUG_CLASS (data);
+ data = g_type_class_ref (ATK_TYPE_SOCKET);
+ socket_class = ATK_SOCKET_CLASS (data);
+ plug_class->get_object_id = get_plug_id;
+ socket_class->embed = socket_embed_hook;
+}
+
+static guint
+get_ancestral_uid (guint pid)
+{
+ FILE *fp;
+ char buf [80];
+ int ppid = 0;
+ int uid = 0;
+ gboolean got_ppid = 0;
+ gboolean got_uid = 0;
+
+ sprintf (buf, "/proc/%d/status", pid);
+ fp = fopen (buf, "r");
+ if (!fp)
+ return 0;
+ while ((!got_ppid || !got_uid) && fgets (buf, sizeof (buf), fp))
+ {
+ if (sscanf (buf, "PPid:\t%d", &ppid) == 1)
+ got_ppid = TRUE;
+ else if (sscanf (buf, "Uid:\t%d", &uid) == 1)
+ got_uid = TRUE;
+ }
+ fclose (fp);
+
+ if (!got_ppid || !got_uid)
+ return 0;
+ if (uid != 0)
+ return uid;
+ if (ppid == 0 || ppid == 1)
+ return 0;
+ return get_ancestral_uid (ppid);
+}
+
+static dbus_bool_t
+user_check (DBusConnection *bus, unsigned long uid, void *data)
+{
+ if (uid == getuid () || uid == geteuid ())
+ return TRUE;
+ if (getuid () == 0)
+ return get_ancestral_uid (getpid ()) == uid;
+ return FALSE;
+}
+
+static void
+new_connection_cb (DBusServer *server, DBusConnection *con, void *data)
+{
+ dbus_connection_set_unix_user_function (con, user_check, NULL, NULL);
+ dbus_connection_ref(con);
+ atspi_dbus_connection_setup_with_g_main(con, NULL);
+ droute_intercept_dbus (con);
+ droute_context_register (spi_global_app_data->droute, con);
+
+ spi_global_app_data->direct_connections = g_list_append (spi_global_app_data->direct_connections, con);
+}
+
+
+gchar *atspi_dbus_name = NULL;
+static gboolean atspi_no_register = FALSE;
+
+static GOptionEntry atspi_option_entries[] = {
+ {"atspi-dbus-name", 0, 0, G_OPTION_ARG_STRING, &atspi_dbus_name,
+ "D-Bus bus name to register as", NULL},
+ {"atspi-no-register", 0, 0, G_OPTION_ARG_NONE, &atspi_no_register,
+ "Do not register with Registry Daemon", NULL},
+ {NULL}
+};
+
+static gchar *
+introspect_children_cb (const char *path, void *data)
+{
+ if (!strcmp (path, "/org/a11y/atspi/accessible"))
+ {
+ return g_strdup ("<node name=\"root\"/>\n");
+ /* TODO: Should we place the whole hierarchy here? */
+ }
+ return NULL;
+}
+
+static void
+handle_event_listener_registered (DBusConnection *bus, DBusMessage *message,
+ void *user_data)
+{
+ DBusMessageIter iter;
+ const char *signature = dbus_message_get_signature (message);
+
+ if (strcmp (signature, "ssas") != 0 &&
+ strcmp (signature, "ss") != 0)
+ {
+ g_warning ("got RegisterEvent with invalid signature '%s'", signature);
+ return;
+ }
+
+ dbus_message_iter_init (message, &iter);
+ add_event_from_iter (&iter);
+}
+
+static void
+free_property_definition (void *data)
+{
+ AtspiPropertyDefinition *pd = data;
+
+ g_free (pd->name);
+ g_free (pd);
+}
+
+static void
+remove_events (const char *bus_name, const char *event)
+{
+ gchar **remove_data;
+ GList *list;
+
+ remove_data = g_strsplit (event, ":", 3);
+ if (!remove_data)
+ {
+ return;
+ }
+
+ for (list = spi_global_app_data->events; list;)
+ {
+ event_data *evdata = list->data;
+ if (!g_strcmp0 (evdata->bus_name, bus_name) &&
+ spi_event_is_subtype (evdata->data, remove_data))
+ {
+ GList *events = spi_global_app_data->events;
+ g_strfreev (evdata->data);
+ g_free (evdata->bus_name);
+ g_slist_free_full (evdata->properties, free_property_definition);
+ g_free (evdata);
+ if (list->prev)
+ {
+ GList *next = list->next;
+ list->prev = g_list_remove (list->prev, evdata);
+ list = next;
+ }
+ else
+ {
+ spi_global_app_data->events = g_list_remove (events, evdata);
+ list = spi_global_app_data->events;
+ }
+ }
+ else
+ {
+ list = list->next;
+ }
+ }
+
+ g_strfreev (remove_data);
+}
+
+static void
+handle_event_listener_deregistered (DBusConnection *bus, DBusMessage *message,
+ void *user_data)
+{
+ gchar *name;
+ char *sender;
+
+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &sender,
+ DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
+ return;
+
+ remove_events (sender, name);
+}
+
+static void
+handle_device_listener_registered (DBusConnection *bus, DBusMessage *message,
+ void *user_data)
+{
+ char *sender;
+ DBusMessageIter iter, iter_struct;
+
+ if (strncmp (dbus_message_get_signature (message), "(s", 2) != 0)
+ {
+ g_warning ("atk-bridge: handle_device_listener_register: unknown signature");
+ return;
+ }
+
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_recurse (&iter, &iter_struct);
+ dbus_message_iter_get_basic (&iter_struct, &sender);
+ spi_atk_add_client (sender);
+}
+
+static DBusHandlerResult
+signal_filter (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ const char *interface = dbus_message_get_interface (message);
+ const char *member = dbus_message_get_member (message);
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ static gboolean registry_lost = FALSE;
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!strcmp (interface, ATSPI_DBUS_INTERFACE_REGISTRY))
+ {
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ if (!strcmp (member, "EventListenerRegistered"))
+ handle_event_listener_registered (bus, message, user_data);
+ else if (!strcmp (member, "EventListenerDeregistered"))
+ handle_event_listener_deregistered (bus, message, user_data);
+ else
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else if (!strcmp (interface, ATSPI_DBUS_INTERFACE_DEVICE_EVENT_LISTENER))
+ {
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ if (!strcmp (member, "KeystrokeListenerRegistered"))
+ handle_device_listener_registered (bus, message, user_data);
+ else if (!strcmp (member, "DeviceListenerRegistered"))
+ handle_device_listener_registered (bus, message, user_data);
+ else
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ if (!g_strcmp0(interface, DBUS_INTERFACE_DBUS) &&
+ !g_strcmp0(member, "NameOwnerChanged"))
+ {
+ char *name, *old, *new;
+ if (dbus_message_get_args (message, NULL,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_INVALID))
+ {
+ if (!strcmp (name, "org.a11y.atspi.Registry"))
+ {
+ if (registry_lost && !old[0])
+ {
+ register_application (spi_global_app_data);
+ registry_lost = FALSE;
+ }
+ else if (!new[0])
+ registry_lost = TRUE;
+ }
+ else if (*old != '\0' && *new == '\0')
+ spi_atk_remove_client (old);
+ }
+ }
+
+ return result;
+}
+
+int
+spi_atk_create_socket (SpiBridge *app)
+{
+#ifndef DISABLE_P2P
+ DBusServer *server;
+ DBusError error;
+
+ if (getuid () != 0)
+ {
+ app->app_tmp_dir = g_build_filename (g_get_user_runtime_dir (),
+ "at-spi2-XXXXXX", NULL);
+ if (!g_mkdtemp (app->app_tmp_dir))
+ {
+ g_free (app->app_tmp_dir);
+ app->app_tmp_dir = NULL;
+ return FALSE;
+ }
+ }
+
+ if (app->app_tmp_dir)
+ app->app_bus_addr = g_strdup_printf ("unix:path=%s/socket", app->app_tmp_dir);
+ else
+ app->app_bus_addr = g_strdup_printf ("unix:path=%s/at-spi2-socket-%d",
+ g_get_user_runtime_dir (), getpid ());
+
+ if (!spi_global_app_data->app_bus_addr)
+ return -1;
+
+ dbus_error_init(&error);
+ server = dbus_server_listen(spi_global_app_data->app_bus_addr, &error);
+ if (server == NULL)
+ {
+ g_warning ("atk-bridge: Couldn't listen on dbus server: %s", error.message);
+ dbus_error_free (&error);
+ spi_global_app_data->app_bus_addr [0] = '\0';
+ g_main_context_unref (spi_global_app_data->main_context);
+ spi_global_app_data->main_context = NULL;
+ return -1;
+ }
+
+ atspi_dbus_server_setup_with_g_main(server, NULL);
+ dbus_server_set_new_connection_function(server, new_connection_cb, NULL, NULL);
+
+ spi_global_app_data->server = server;
+#endif
+
+ return 0;
+}
+
+/*
+ * Checks the status of the environment variables
+ *
+ * At this moment it only checks NO_AT_BRIDGE
+ *
+ * Returns TRUE if there isn't anything on the environment preventing
+ * you to load the bridge, FALSE otherwise
+ */
+static gboolean
+check_envvar (void)
+{
+ const gchar *envvar;
+
+ envvar = g_getenv ("NO_AT_BRIDGE");
+
+ if (envvar && atoi (envvar) == 1)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+void
+spi_atk_activate ()
+{
+ DRoutePath *treepath;
+
+ spi_atk_register_event_listeners ();
+ if (!spi_global_cache)
+ {
+ spi_global_cache = g_object_new (SPI_CACHE_TYPE, NULL);
+ treepath = droute_add_one (spi_global_app_data->droute,
+ "/org/a11y/atspi/cache", spi_global_cache);
+
+ if (!treepath)
+ {
+ g_warning ("atk-bridge: Error in droute_add_one(). Already running?");
+ return;
+ }
+ spi_initialize_cache (treepath);
+ if (spi_global_app_data->bus)
+ droute_path_register (treepath, spi_global_app_data->bus);
+ }
+}
+
+/*
+ * spi_app_init
+ *
+ * The following needs to be initialized.
+ *
+ * - DRoute for routing message to their accessible objects.
+ * - Event handlers for emmitting signals on specific ATK events.
+ * - setup the bus for p2p communication
+ * - Application registration with the AT-SPI registry.
+ *
+ */
+int
+atk_bridge_adaptor_init (gint * argc, gchar ** argv[])
+{
+ GOptionContext *opt;
+ GError *err = NULL;
+ DBusError error;
+ AtkObject *root;
+ gboolean load_bridge;
+ DRoutePath *accpath;
+
+ load_bridge = check_envvar ();
+ if (inited && !load_bridge)
+ g_warning ("ATK Bridge is disabled but a11y has already been enabled.");
+
+ if (inited || !load_bridge)
+ return 0;
+
+ inited = TRUE;
+
+ root = atk_get_root ();
+ g_warn_if_fail (root);
+ if (!root)
+ {
+ inited = FALSE;
+ return -1;
+ }
+
+ /* Parse command line options */
+ opt = g_option_context_new (NULL);
+ g_option_context_add_main_entries (opt, atspi_option_entries, NULL);
+ g_option_context_set_ignore_unknown_options (opt, TRUE);
+ if (!g_option_context_parse (opt, argc, argv, &err))
+ {
+ g_warning ("AT-SPI Option parsing failed: %s\n", err->message);
+ g_error_free (err);
+ }
+ g_option_context_free (opt);
+
+ /* Allocate global data and do ATK initializations */
+ spi_global_app_data = g_new0 (SpiBridge, 1);
+ spi_global_app_data->root = g_object_ref (root);
+
+ /* Set up D-Bus connection and register bus name */
+ dbus_error_init (&error);
+ spi_global_app_data->bus = atspi_get_a11y_bus ();
+ if (!spi_global_app_data->bus)
+ {
+ g_free (spi_global_app_data);
+ spi_global_app_data = NULL;
+ inited = FALSE;
+ return -1;
+ }
+
+ if (atspi_dbus_name != NULL)
+ {
+ if (dbus_bus_request_name
+ (spi_global_app_data->bus, atspi_dbus_name, 0, &error))
+ {
+ g_print ("AT-SPI Recieved D-Bus name - %s\n", atspi_dbus_name);
+ }
+ else
+ {
+ g_print
+ ("AT-SPI D-Bus name requested but could not be allocated - %s\n",
+ atspi_dbus_name);
+ }
+ }
+
+ spi_global_app_data->main_context = g_main_context_new ();
+
+ atspi_dbus_connection_setup_with_g_main (spi_global_app_data->bus, NULL);
+
+ /* Hook our plug-and socket functions */
+ install_plug_hooks ();
+
+ /*
+ * Create the leasing, register and cache objects.
+ * The order is important here, the cache depends on the
+ * register object.
+ */
+ spi_global_register = g_object_new (SPI_REGISTER_TYPE, NULL);
+ spi_global_leasing = g_object_new (SPI_LEASING_TYPE, NULL);
+
+ /* Register droute for routing AT-SPI messages */
+ spi_global_app_data->droute =
+ droute_new ();
+
+ accpath = droute_add_many (spi_global_app_data->droute,
+ "/org/a11y/atspi/accessible",
+ NULL,
+ introspect_children_cb,
+ NULL,
+ (DRouteGetDatumFunction)
+ spi_global_register_path_to_object);
+
+
+ /* Register all interfaces with droute and set up application accessible db */
+ spi_initialize_accessible (accpath);
+ spi_initialize_application (accpath);
+ spi_initialize_action (accpath);
+ spi_initialize_collection (accpath);
+ spi_initialize_component (accpath);
+ spi_initialize_document (accpath);
+ spi_initialize_editabletext (accpath);
+ spi_initialize_hyperlink (accpath);
+ spi_initialize_hypertext (accpath);
+ spi_initialize_image (accpath);
+ spi_initialize_selection (accpath);
+ spi_initialize_socket (accpath);
+ spi_initialize_table (accpath);
+ spi_initialize_table_cell (accpath);
+ spi_initialize_text (accpath);
+ spi_initialize_value (accpath);
+
+ droute_context_register (spi_global_app_data->droute,
+ spi_global_app_data->bus);
+
+ /* Register methods to send D-Bus signals on certain ATK events */
+ if (clients)
+ spi_atk_activate ();
+
+ /* Set up filter and match rules to catch signals */
+ dbus_bus_add_match (spi_global_app_data->bus, "type='signal', interface='org.a11y.atspi.Registry', sender='org.a11y.atspi.Registry'", NULL);
+ dbus_bus_add_match (spi_global_app_data->bus, "type='signal', interface='org.a11y.atspi.DeviceEventListener', sender='org.a11y.atspi.Registry'", NULL);
+ dbus_bus_add_match (spi_global_app_data->bus, "type='signal', arg0='org.a11y.atspi.Registry', interface='org.freedesktop.DBus', member='NameOwnerChanged'", NULL);
+ dbus_connection_add_filter (spi_global_app_data->bus, signal_filter, NULL,
+ NULL);
+
+ /* Register this app by sending a signal out to AT-SPI registry daemon */
+ if (!atspi_no_register && (!root || !ATK_IS_PLUG (root)))
+ register_application (spi_global_app_data);
+ else
+ get_registered_event_listeners (spi_global_app_data);
+
+ dbus_error_free (&error);
+ return 0;
+}
+
+void
+atk_bridge_adaptor_cleanup (void)
+{
+ GList *l;
+ GSList *ls;
+
+ if (!inited)
+ return;
+
+ if (!spi_global_app_data)
+ return;
+
+ spi_atk_tidy_windows ();
+ spi_atk_deregister_event_listeners ();
+
+ deregister_application (spi_global_app_data);
+
+ if (spi_global_app_data->bus)
+ {
+ dbus_connection_remove_filter (spi_global_app_data->bus, signal_filter, NULL);
+ droute_context_unregister (spi_global_app_data->droute, spi_global_app_data->bus);
+ dbus_connection_close (spi_global_app_data->bus);
+ dbus_connection_unref (spi_global_app_data->bus);
+ spi_global_app_data->bus = NULL;
+ }
+
+ for (l = spi_global_app_data->direct_connections; l; l = l->next)
+ {
+ DBusConnection *connection;
+
+ connection = l->data;
+
+ droute_context_unregister (spi_global_app_data->droute, connection);
+ droute_unintercept_dbus (connection);
+ dbus_connection_close (connection);
+ dbus_connection_unref (connection);
+ }
+ g_list_free (spi_global_app_data->direct_connections);
+ spi_global_app_data->direct_connections = NULL;
+
+ for (ls = clients; ls; ls = ls->next)
+ g_free (ls->data);
+ g_slist_free (clients);
+ clients = NULL;
+
+ g_clear_object (&spi_global_cache);
+ g_clear_object (&spi_global_leasing);
+ g_clear_object (&spi_global_register);
+
+ if (spi_global_app_data->main_context)
+ g_main_context_unref (spi_global_app_data->main_context);
+
+ droute_free (spi_global_app_data->droute);
+
+ g_free (spi_global_app_data);
+ spi_global_app_data = NULL;
+
+ inited = FALSE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static gchar *name_match_tmpl =
+ "type='signal', interface='org.freedesktop.DBus', member='NameOwnerChanged', arg0='%s'";
+
+void
+spi_atk_add_client (const char *bus_name)
+{
+ GSList *l;
+ gchar *match;
+
+ for (l = clients; l; l = l->next)
+ {
+ if (!g_strcmp0 (l->data, bus_name))
+ return;
+ }
+ if (!clients)
+ spi_atk_activate ();
+ clients = g_slist_append (clients, g_strdup (bus_name));
+ match = g_strdup_printf (name_match_tmpl, bus_name);
+ dbus_bus_add_match (spi_global_app_data->bus, match, NULL);
+ g_free (match);
+}
+
+void
+spi_atk_remove_client (const char *bus_name)
+{
+ GSList *l;
+ GSList *next_node;
+
+ l = clients;
+ while (l)
+ {
+ next_node = l->next;
+
+ if (!g_strcmp0 (l->data, bus_name))
+ {
+ gchar *match = g_strdup_printf (name_match_tmpl, l->data);
+ dbus_bus_remove_match (spi_global_app_data->bus, match, NULL);
+ g_free (match);
+ g_free (l->data);
+ clients = g_slist_delete_link (clients, l);
+ if (!clients)
+ spi_atk_deregister_event_listeners ();
+ return;
+ }
+
+ l = next_node;
+ }
+}
+
+void
+spi_atk_add_interface (DRoutePath *path,
+ const char *name,
+ const char *introspect,
+ const DRouteMethod *methods,
+ const DRouteProperty *properties)
+{
+ droute_path_add_interface (path, name, introspect, methods, properties);
+
+ if (properties)
+ {
+ if (!spi_global_app_data->property_hash)
+ spi_global_app_data->property_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free, NULL);
+ g_hash_table_insert (spi_global_app_data->property_hash, g_strdup (name),
+ (gpointer) properties);
+ }
+}
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/bridge.h b/atk-adaptor/bridge.h
new file mode 100644
index 0000000..64882e4
--- /dev/null
+++ b/atk-adaptor/bridge.h
@@ -0,0 +1,97 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
+ * Copyright 2001, 2002, 2003 Ximian, Inc.
+ * Copyright 2008, 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef BRIDGE_H
+#define BRIDGE_H
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+
+typedef struct _SpiBridge SpiBridge;
+typedef struct _SpiBridgeClass SpiBridgeClass;
+
+G_BEGIN_DECLS
+
+typedef struct _AtspiPropertyDefinition AtspiPropertyDefinition;
+struct _AtspiPropertyDefinition
+{
+ char *name;
+ GType type;
+ DRoutePropertyFunction func;
+};
+
+typedef struct _event_data event_data;
+struct _event_data
+{
+ gchar *bus_name;
+ gchar **data;
+ GSList *properties;
+};
+
+struct _SpiBridge
+{
+ GObject parent;
+
+ AtkObject *root;
+
+ DBusConnection *bus;
+ DRouteContext *droute;
+ GMainContext *main_context;
+ DBusServer *server;
+ GList *direct_connections;
+
+/*
+ SpiRegister *reg;
+ SpiCache *cache;
+ SpiLeasing *leasing;
+*/
+ gchar *desktop_name;
+ gchar *desktop_path;
+gchar *app_tmp_dir;
+gchar *app_bus_addr;
+ GList *events;
+ gboolean events_initialized;
+ GHashTable *property_hash;
+};
+
+extern SpiBridge *spi_global_app_data;
+
+void spi_atk_add_client (const char *bus_name);
+void spi_atk_remove_client (const char *bus_name);
+
+int spi_atk_create_socket (SpiBridge *app);
+
+void spi_atk_add_interface (DRoutePath *path,
+ const char *name,
+ const char *introspect,
+ const DRouteMethod *methods,
+ const DRouteProperty *properties);
+
+DRoutePropertyFunction _atk_bridge_find_property_func (const char *property,
+ GType *type);
+
+GType _atk_bridge_type_from_iface (const char *iface);
+G_END_DECLS
+
+#endif /* BRIDGE_H */
diff --git a/atk-adaptor/event.c b/atk-adaptor/event.c
new file mode 100644
index 0000000..0662664
--- /dev/null
+++ b/atk-adaptor/event.c
@@ -0,0 +1,1366 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2011, F123 Consulting & Mais Diferenças
+ * Copyright 2008, 2009, Codethink Ltd.
+ * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
+ * Copyright 2001, 2002, 2003 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include <atk/atk.h>
+#include <droute/droute.h>
+#include <atspi/atspi.h>
+
+#include "bridge.h"
+#include "accessible-register.h"
+
+#include "spi-dbus.h"
+#include "event.h"
+#include "object.h"
+
+static GArray *listener_ids = NULL;
+
+static gint atk_bridge_key_event_listener_id;
+static gint atk_bridge_focus_tracker_id;
+
+/*---------------------------------------------------------------------------*/
+
+#define ITF_EVENT_OBJECT "org.a11y.atspi.Event.Object"
+#define ITF_EVENT_WINDOW "org.a11y.atspi.Event.Window"
+#define ITF_EVENT_DOCUMENT "org.a11y.atspi.Event.Document"
+#define ITF_EVENT_FOCUS "org.a11y.atspi.Event.Focus"
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct _SpiReentrantCallClosure
+{
+ DBusConnection *bus;
+ GMainLoop *loop;
+ DBusMessage *reply;
+ guint timeout;
+} SpiReentrantCallClosure;
+
+static void
+switch_main_context (GMainContext *cnx)
+{
+ GList *list;
+
+ if (spi_global_app_data->server)
+ atspi_dbus_server_setup_with_g_main (spi_global_app_data->server, cnx);
+ atspi_dbus_connection_setup_with_g_main (spi_global_app_data->bus, cnx);
+ atspi_set_main_context (cnx);
+ for (list = spi_global_app_data->direct_connections; list; list = list->next)
+ atspi_dbus_connection_setup_with_g_main (list->data, cnx);
+}
+
+static void
+set_reply (DBusPendingCall * pending, void *user_data)
+{
+ SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data;
+
+ closure->reply = dbus_pending_call_steal_reply (pending);
+ dbus_pending_call_unref (pending);
+ switch_main_context (NULL);
+ g_main_loop_quit (closure->loop);
+}
+
+static gboolean
+timeout_reply (void *data)
+{
+ SpiReentrantCallClosure *closure = data;
+
+ switch_main_context (NULL);
+ g_main_loop_quit (closure->loop);
+ closure->timeout = -1;
+ return FALSE;
+}
+
+static DBusMessage *
+send_and_allow_reentry (DBusConnection * bus, DBusMessage * message)
+{
+ DBusPendingCall *pending;
+ SpiReentrantCallClosure closure;
+ GSource *source;
+
+ closure.bus = bus;
+ closure.loop = g_main_loop_new (spi_global_app_data->main_context, FALSE);
+ closure.reply = NULL;
+ switch_main_context (spi_global_app_data->main_context);
+
+ if (!dbus_connection_send_with_reply (bus, message, &pending, 9000) || !pending)
+ {
+ switch_main_context (NULL);
+ return NULL;
+ }
+ dbus_pending_call_set_notify (pending, set_reply, (void *) &closure, NULL);
+ source = g_timeout_source_new (500);
+ g_source_set_callback (source, timeout_reply, &closure, NULL);
+ closure.timeout = g_source_attach (source, spi_global_app_data->main_context);
+ g_source_unref (source);
+ g_main_loop_run (closure.loop);
+ if (closure.timeout != -1)
+ g_source_destroy (source);
+
+ g_main_loop_unref (closure.loop);
+ if (!closure.reply)
+ dbus_pending_call_cancel (pending);
+ return closure.reply;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Functionality related to sending device events from the application.
+ *
+ * This is used for forwarding key events on to the registry daemon.
+ */
+
+static gboolean
+Accessibility_DeviceEventController_NotifyListenersSync (const
+ AtspiDeviceEvent
+ * key_event)
+{
+ DBusMessage *message;
+ dbus_bool_t consumed = FALSE;
+
+ message =
+ dbus_message_new_method_call (SPI_DBUS_NAME_REGISTRY,
+ ATSPI_DBUS_PATH_DEC,
+ ATSPI_DBUS_INTERFACE_DEC,
+ "NotifyListenersSync");
+
+ if (spi_dbus_marshal_deviceEvent (message, key_event))
+ {
+ DBusMessage *reply =
+ send_and_allow_reentry (spi_global_app_data->bus, message);
+ if (reply)
+ {
+ DBusError error;
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (reply, &error, DBUS_TYPE_BOOLEAN,
+ &consumed, DBUS_TYPE_INVALID))
+ {
+ /* TODO: print a warning */
+ dbus_error_free (&error);
+ }
+ dbus_message_unref (reply);
+ }
+ }
+ dbus_message_unref (message);
+ return consumed;
+}
+
+static void
+spi_init_keystroke_from_atk_key_event (AtspiDeviceEvent * keystroke,
+ AtkKeyEventStruct * event)
+{
+ keystroke->id = (dbus_int32_t) event->keyval;
+ keystroke->hw_code = (dbus_int16_t) event->keycode;
+ keystroke->timestamp = (dbus_uint32_t) event->timestamp;
+ keystroke->modifiers = (dbus_uint16_t) (event->state & 0xFFFF);
+ if (event->string)
+ {
+ gunichar c;
+
+ keystroke->event_string = g_strdup (event->string);
+ c = g_utf8_get_char_validated (event->string, -1);
+ if (c > 0 && g_unichar_isprint (c))
+ keystroke->is_text = TRUE;
+ else
+ keystroke->is_text = FALSE;
+ }
+ else
+ {
+ keystroke->event_string = g_strdup ("");
+ keystroke->is_text = FALSE;
+ }
+ switch (event->type)
+ {
+ case (ATK_KEY_EVENT_PRESS):
+ keystroke->type = ATSPI_KEY_PRESSED;
+ break;
+ case (ATK_KEY_EVENT_RELEASE):
+ keystroke->type = ATSPI_KEY_RELEASED;
+ break;
+ default:
+ keystroke->type = 0;
+ break;
+ }
+#if 0
+ g_print
+ ("key_event type %d; val=%d code=%d modifiers=%x name=%s is_text=%d, time=%lx\n",
+ (int) keystroke->type, (int) keystroke->id, (int) keystroke->hw_code,
+ (int) keystroke->modifiers, keystroke->event_string,
+ (int) keystroke->is_text, (unsigned long) keystroke->timestamp);
+#endif
+}
+
+
+static gint
+spi_atk_bridge_key_listener (AtkKeyEventStruct * event, gpointer data)
+{
+ gboolean result;
+ AtspiDeviceEvent key_event;
+
+ spi_init_keystroke_from_atk_key_event (&key_event, event);
+
+ result =
+ Accessibility_DeviceEventController_NotifyListenersSync (&key_event);
+
+ if (key_event.event_string)
+ g_free (key_event.event_string);
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static const void *
+validate_for_dbus (const gint type,
+ const void *val)
+{
+ switch (type)
+ {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ if (!val)
+ return "";
+ else if (!g_utf8_validate (val, -1, NULL))
+ {
+ g_warning ("atk-bridge: Received bad UTF-8 string when emitting event");
+ return "";
+ }
+ else
+ return val;
+ default:
+ return val;
+ }
+}
+
+static void
+append_basic (DBusMessageIter *iter,
+ const char *type,
+ const void *val)
+{
+ DBusMessageIter sub;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type, &sub);
+
+ val = validate_for_dbus ((int) *type, val);
+ dbus_message_iter_append_basic(&sub, (int) *type, &val);
+
+ dbus_message_iter_close_container(iter, &sub);
+}
+
+static void
+append_rect (DBusMessageIter *iter,
+ const char *type,
+ const void *val)
+{
+ DBusMessageIter variant, sub;
+ const AtkRectangle *rect = (const AtkRectangle *) val;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, type, &variant);
+
+ dbus_message_iter_open_container (&variant, DBUS_TYPE_STRUCT, NULL, &sub);
+
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->x));
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->y));
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->width));
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &(rect->height));
+
+ dbus_message_iter_close_container (&variant, &sub);
+
+ dbus_message_iter_close_container(iter, &variant);
+}
+
+static void
+append_object (DBusMessageIter *iter,
+ const char *type,
+ const void *val)
+{
+ spi_object_append_v_reference (iter, ATK_OBJECT (val));
+}
+
+static gchar *
+signal_name_to_dbus (const gchar *s)
+{
+ gchar *ret = g_strdup (s);
+ gchar *t;
+
+ if (!ret)
+ return NULL;
+ ret [0] = toupper (ret [0]);
+ while ((t = strchr (ret, '-')) != NULL)
+ {
+ memmove (t, t + 1, strlen (t));
+ *t = toupper (*t);
+ }
+ return ret;
+}
+
+/*
+ * Converts names of the form "active-descendant-changed" to
+ * "ActiveDescendantChanged"
+ */
+static gchar *
+ensure_proper_format (const char *name)
+{
+ gchar *ret = (gchar *) g_malloc (strlen (name) * 2 + 2);
+ gchar *p = ret;
+ gboolean need_upper = TRUE;
+
+ if (!ret)
+ return NULL;
+ while (*name)
+ {
+ if (need_upper)
+ {
+ *p++ = toupper (*name);
+ need_upper = FALSE;
+ }
+ else if (*name == '-')
+ need_upper = TRUE;
+ else if (*name == ':')
+ {
+ need_upper = TRUE;
+ *p++ = *name;
+ }
+ else
+ *p++ = *name;
+ name++;
+ }
+ *p = '\0';
+ return ret;
+}
+
+void
+append_properties (GArray *properties, event_data *evdata)
+{
+ GSList *ls;
+ gint i;
+
+ for (ls = evdata->properties; ls; ls = ls->next)
+ {
+ gboolean dup = FALSE;
+ for (i = 0; i < properties->len; i++)
+ {
+ if (ls->data == g_array_index (properties, AtspiPropertyDefinition *, i))
+ {
+ dup = TRUE;
+ break;
+ }
+ }
+ if (!dup)
+ g_array_append_val (properties, ls->data);
+ }
+}
+
+static gboolean
+signal_is_needed (const gchar *klass, const gchar *major, const gchar *minor,
+ GArray **properties)
+{
+ gchar *data [4];
+ event_data *evdata;
+ gboolean ret = FALSE;
+ GList *list;
+ GArray *props = NULL;
+
+ if (!spi_global_app_data->events_initialized)
+ return TRUE;
+
+ data [0] = ensure_proper_format (klass + 21);
+ data [1] = ensure_proper_format (major);
+ data [2] = ensure_proper_format (minor);
+ data [3] = NULL;
+
+ /* Hack: Always pass events that update the cache.
+ * TODO: FOr 2.2, have at-spi2-core define a special "cache listener" for
+ * this instead, so that we don't send these if no one is listening */
+ if (!g_strcmp0 (data [1], "ChildrenChanged") ||
+ ((!g_strcmp0 (data [1], "PropertyChange")) &&
+ (!g_strcmp0 (data [2], "accessible-name") ||
+ !g_strcmp0 (data [2], "accessible-description") ||
+ !g_strcmp0 (data [2], "accessible-parent") ||
+ !g_strcmp0 (data [2], "accessible-role"))) ||
+ !g_strcmp0 (data [1], "StateChanged"))
+ ret = TRUE;
+
+ /* Hack: events such as "object::text-changed::insert:system" as
+ generated by Gecko */
+ data [2][strcspn (data [2], ":")] = '\0';
+
+ for (list = spi_global_app_data->events; list; list = list->next)
+ {
+ evdata = list->data;
+ if (spi_event_is_subtype (data, evdata->data))
+ {
+ ret = TRUE;
+ if (!props)
+ props = g_array_new (TRUE, TRUE, sizeof (AtspiPropertyDefinition *));
+ append_properties (props, evdata);
+ }
+ }
+
+ g_free (data [2]);
+ g_free (data [1]);
+ g_free (data [0]);
+ *properties = props;
+ return ret;
+}
+
+/* Convert a : to a / so that listeners can use arg0path to match only
+ * * the prefix */
+static char *
+adapt_minor_for_dbus (const char *source)
+{
+ gchar *ret = g_strdup (source);
+ int i = strcspn (ret, ":");
+ if (ret[i] == ':')
+ ret[i] = '/';
+ return ret;
+}
+
+static void
+open_variant (DBusMessageIter *iter, const char *name, const char *type,
+ DBusMessageIter *out)
+{
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, type, out);
+}
+
+/*
+ * Emits an AT-SPI event.
+ * AT-SPI events names are split into three parts:
+ * class:major:minor
+ * This is mapped onto D-Bus events as:
+ * D-Bus Interface:Signal Name:Detail argument
+ *
+ * Marshals a basic type into the 'any_data' attribute of
+ * the AT-SPI event.
+ */
+static void
+emit_event (AtkObject *obj,
+ const char *klass,
+ const char *major,
+ const char *minor,
+ dbus_int32_t detail1,
+ dbus_int32_t detail2,
+ const char *type,
+ const void *val,
+ void (*append_variant) (DBusMessageIter *, const char *, const void *))
+{
+ DBusConnection *bus = spi_global_app_data->bus;
+ char *path;
+ char *minor_dbus;
+
+ gchar *cname;
+ DBusMessage *sig;
+ DBusMessageIter iter, iter_dict, iter_dict_entry, iter_variant, iter_array;
+ GArray *properties = NULL;
+
+ if (!klass) klass = "";
+ if (!major) major = "";
+ if (!minor) minor = "";
+ if (!type) type = "u";
+
+ if (!signal_is_needed (klass, major, minor, &properties))
+ return;
+
+ path = spi_register_object_to_path (spi_global_register, G_OBJECT (obj));
+ g_return_if_fail (path != NULL);
+
+ /*
+ * This is very annoying, but as '-' isn't a legal signal
+ * name in D-Bus (Why not??!?) The names need converting
+ * on this side, and again on the client side.
+ */
+ cname = signal_name_to_dbus (major);
+ sig = dbus_message_new_signal(path, klass, cname);
+
+ dbus_message_iter_init_append(sig, &iter);
+
+ minor_dbus = adapt_minor_for_dbus (minor);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor_dbus);
+ g_free (minor_dbus);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
+ append_variant (&iter, type, val);
+
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict);
+ /* Add requested properties, unless the object is being marked defunct, in
+ which case it's safest not to touch it */
+ if (minor == NULL || strcmp (minor, "defunct") != 0 || detail1 == 0)
+ {
+ if (properties)
+ {
+ gint i;
+ for (i = 0; i < properties->len; i++)
+ {
+ AtspiPropertyDefinition *prop = g_array_index (properties, AtspiPropertyDefinition *, i);
+ dbus_message_iter_open_container (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL,
+ &iter_dict_entry);
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop->name);
+ prop->func (&iter_dict_entry, obj);
+ dbus_message_iter_close_container (&iter_dict, &iter_dict_entry);
+ }
+ g_array_free (properties, TRUE);
+ }
+ }
+ dbus_message_iter_close_container (&iter, &iter_dict);
+
+ dbus_connection_send(bus, sig, NULL);
+ dbus_message_unref(sig);
+
+ if (g_strcmp0 (cname, "ChildrenChanged") != 0)
+ spi_object_lease_if_needed (G_OBJECT (obj));
+
+ g_free(cname);
+ g_free (path);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * The focus listener handles the ATK 'focus' signal and forwards it
+ * as the AT-SPI event, 'focus:'
+ */
+static void
+focus_tracker (AtkObject * accessible)
+{
+ emit_event (accessible, ITF_EVENT_FOCUS, "focus", "", 0, 0,
+ DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
+}
+
+/*---------------------------------------------------------------------------*/
+
+#define PCHANGE "PropertyChange"
+
+/*
+ * This handler handles the following ATK signals and
+ * converts them to AT-SPI events:
+ *
+ * Gtk:AtkObject:property-change -> object:property-change:(property-name)
+ *
+ * The property-name is part of the ATK property-change signal.
+ */
+static gboolean
+property_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ AtkPropertyValues *values;
+
+ const gchar *pname = NULL;
+
+ AtkObject *otemp;
+ const gchar *s1;
+ gint i;
+
+ accessible = g_value_get_object (&param_values[0]);
+ values = (AtkPropertyValues *) g_value_get_pointer (&param_values[1]);
+
+ pname = values[0].property_name;
+
+ /* TODO Could improve this control statement by matching
+ * on only the end of the signal names,
+ */
+ if (strcmp (pname, "accessible-name") == 0)
+ {
+ s1 = atk_object_get_name (accessible);
+ if (s1 != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
+ }
+ else if (strcmp (pname, "accessible-description") == 0)
+ {
+ s1 = atk_object_get_description (accessible);
+ if (s1 != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
+ }
+ else if (strcmp (pname, "accessible-parent") == 0)
+ {
+ otemp = atk_object_get_parent (accessible);
+ if (otemp != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ "(so)", otemp, append_object);
+ }
+ else if (strcmp (pname, "accessible-role") == 0)
+ {
+ i = atk_object_get_role (accessible);
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ DBUS_TYPE_UINT32_AS_STRING, GINT_TO_POINTER(i), append_basic);
+ }
+ else if (strcmp (pname, "accessible-table-summary") == 0)
+ {
+ otemp = atk_table_get_summary (ATK_TABLE (accessible));
+ if (otemp != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ "(so)", otemp, append_object);
+ }
+ else if (strcmp (pname, "accessible-table-column-header") == 0)
+ {
+ i = g_value_get_int (&(values->new_value));
+ otemp = atk_table_get_column_header (ATK_TABLE (accessible), i);
+ if (otemp != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ "(so)", otemp, append_object);
+ }
+ else if (strcmp (pname, "accessible-table-row-header") == 0)
+ {
+ i = g_value_get_int (&(values->new_value));
+ otemp = atk_table_get_row_header (ATK_TABLE (accessible), i);
+ if (otemp != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ "(so)", otemp, append_object);
+ }
+ else if (strcmp (pname, "accessible-table-row-description") == 0)
+ {
+ i = g_value_get_int (&(values->new_value));
+ s1 = atk_table_get_row_description (ATK_TABLE (accessible), i);
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
+ }
+ else if (strcmp (pname, "accessible-table-column-description") == 0)
+ {
+ i = g_value_get_int (&(values->new_value));
+ s1 = atk_table_get_column_description (ATK_TABLE (accessible), i);
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, s1, append_basic);
+ }
+ else if (strcmp (pname, "accessible-table-caption-object") == 0)
+ {
+ otemp = atk_table_get_caption (ATK_TABLE (accessible));
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ "(so)", otemp, append_object);
+ }
+ else
+ {
+ emit_event (accessible, ITF_EVENT_OBJECT, PCHANGE, pname, 0, 0,
+ DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
+ }
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+#define STATE_CHANGED "state-changed"
+
+/*
+ * The state event listener handles 'Gtk:AtkObject:state-change' ATK signals
+ * and forwards them as object:state-changed:(param-name) AT-SPI events. Where
+ * the param-name is part of the ATK state-change signal.
+ */
+static gboolean
+state_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ const gchar *pname;
+ guint detail1;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ pname = g_value_get_string (&param_values[1]);
+
+ detail1 = (g_value_get_boolean (&param_values[2])) ? 1 : 0;
+ emit_event (accessible, ITF_EVENT_OBJECT, STATE_CHANGED, pname, detail1, 0,
+ DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
+
+ if (!g_strcmp0 (pname, "defunct") && detail1)
+ spi_register_deregister_object (spi_global_register, G_OBJECT (accessible),
+ TRUE);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * The window event listener handles the following ATK signals and forwards
+ * them as AT-SPI events:
+ *
+ * window:create -> window:create
+ * window:destroy -> window:destroy
+ * window:minimize -> window:minimize
+ * window:maximize -> window:maximize
+ * window:activate -> window:activate
+ * window:deactivate -> window:deactivate
+ */
+static gboolean
+window_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ GSignalQuery signal_query;
+ const gchar *name, *s;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ s = atk_object_get_name (accessible);
+ emit_event (accessible, ITF_EVENT_WINDOW, name, "", 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, s, append_basic);
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * The document event listener handles the following ATK signals
+ * and converts them to AT-SPI events:
+ *
+ * Gtk:AtkDocument:load-complete -> document:load-complete
+ * Gtk:AtkDocument:load-stopped -> document:load-stopped
+ * Gtk:AtkDocument:reload -> document:reload
+ * Gtk:AtkDocument:page-changed -> document:page-changed
+ */
+static gboolean
+document_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ GSignalQuery signal_query;
+ const gchar *name, *s;
+ gint detail1 = 0;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ if (n_param_values > 0) // on the case of page-changed
+ if (G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ s = atk_object_get_name (accessible);
+ emit_event (accessible, ITF_EVENT_DOCUMENT, name, "", detail1, 0,
+ DBUS_TYPE_STRING_AS_STRING, s, append_basic);
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Signal handler for "Gtk:AtkComponent:bounds-changed". Converts
+ * this to an AT-SPI event - "object:bounds-changed".
+ */
+static gboolean
+bounds_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ AtkRectangle *atk_rect;
+ GSignalQuery signal_query;
+ const gchar *name;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+
+ if (G_VALUE_HOLDS_BOXED (param_values + 1))
+ {
+ atk_rect = g_value_get_boxed (param_values + 1);
+
+ emit_event (accessible, ITF_EVENT_OBJECT, name, "", 0, 0,
+ "(iiii)", atk_rect, append_rect);
+ }
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Handles the ATK signal 'Gtk:AtkObject:active-descendant-changed' and
+ * converts it to the AT-SPI signal - 'object:active-descendant-changed'.
+ *
+ */
+static gboolean
+active_descendant_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ AtkObject *child;
+ GSignalQuery signal_query;
+ const gchar *name;
+ gint detail1;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ child = ATK_OBJECT (g_value_get_pointer (&param_values[1]));
+ g_return_val_if_fail (ATK_IS_OBJECT (child), TRUE);
+
+ detail1 = atk_object_get_index_in_parent (child);
+
+ emit_event (accessible, ITF_EVENT_OBJECT, name, "", detail1, 0,
+ "(so)", child, append_object);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Handles the ATK signal 'Gtk:AtkHypertext:link-selected' and
+ * converts it to the AT-SPI signal - 'object:link-selected'
+ *
+ */
+static gboolean
+link_selected_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ GSignalQuery signal_query;
+ const gchar *name, *minor;
+ gint detail1 = 0;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ minor = g_quark_to_string (signal_hint->detail);
+
+ if (G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, 0,
+ DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Handles the ATK signal 'Gtk:AtkText:text-changed' and
+ * converts it to the AT-SPI signal - 'object:text-changed'
+ * This signal is deprecated by Gtk:AtkText:text-insert
+ * and Gtk:AtkText:text-remove
+ *
+ */
+static gboolean
+text_changed_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ GSignalQuery signal_query;
+ const gchar *name, *minor;
+ gchar *selected;
+ gint detail1 = 0, detail2 = 0;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ minor = g_quark_to_string (signal_hint->detail);
+
+ if (G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ if (G_VALUE_TYPE (&param_values[2]) == G_TYPE_INT)
+ detail2 = g_value_get_int (&param_values[2]);
+
+ selected =
+ atk_text_get_text (ATK_TEXT (accessible), detail1, detail1 + detail2);
+
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ DBUS_TYPE_STRING_AS_STRING, selected, append_basic);
+ g_free (selected);
+
+ return TRUE;
+}
+
+/*
+ * Handles the ATK signal 'Gtk:AtkText:text-insert' and
+ * converts it to the AT-SPI signal - 'object:text-changed'
+ *
+ */
+static gboolean
+text_insert_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ guint text_changed_signal_id;
+ GSignalQuery signal_query;
+ const gchar *name;
+ const gchar *minor_raw, *text = NULL;
+ gchar *minor;
+ gint detail1 = 0, detail2 = 0;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ /* Get signal name for 'Gtk:AtkText:text-changed' so
+ * we convert it to the AT-SPI signal - 'object:text-changed'
+ */
+ text_changed_signal_id = g_signal_lookup ("text-changed", G_OBJECT_TYPE (accessible));
+ g_signal_query (text_changed_signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+
+ /* Add the insert and keep any detail coming from atk */
+ minor_raw = g_quark_to_string (signal_hint->detail);
+ if (minor_raw)
+ minor = g_strconcat ("insert:", minor_raw, NULL);
+ else
+ minor = g_strdup ("insert");
+
+ if (G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ if (G_VALUE_TYPE (&param_values[2]) == G_TYPE_INT)
+ detail2 = g_value_get_int (&param_values[2]);
+
+ if (G_VALUE_TYPE (&param_values[3]) == G_TYPE_STRING)
+ text = g_value_get_string (&param_values[3]);
+
+ if (text != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ DBUS_TYPE_STRING_AS_STRING, text, append_basic);
+ g_free (minor);
+ return TRUE;
+}
+
+/*
+ * Handles the ATK signal 'Gtk:AtkText:text-remove' and
+ * converts it to the AT-SPI signal - 'object:text-changed'
+ *
+ */
+static gboolean
+text_remove_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ guint text_changed_signal_id;
+ GSignalQuery signal_query;
+ const gchar *name;
+ const gchar *minor_raw, *text = NULL;
+ gchar *minor;
+ gint detail1 = 0, detail2 = 0;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ /* Get signal name for 'Gtk:AtkText:text-changed' so
+ * we convert it to the AT-SPI signal - 'object:text-changed'
+ */
+ text_changed_signal_id = g_signal_lookup ("text-changed", G_OBJECT_TYPE (accessible));
+ g_signal_query (text_changed_signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ minor_raw = g_quark_to_string (signal_hint->detail);
+
+ /* Add the delete and keep any detail coming from atk */
+ if (minor_raw)
+ minor = g_strconcat ("delete:", minor_raw, NULL);
+ else
+ minor = g_strdup ("delete");
+
+ if (G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ if (G_VALUE_TYPE (&param_values[2]) == G_TYPE_INT)
+ detail2 = g_value_get_int (&param_values[2]);
+
+ if (G_VALUE_TYPE (&param_values[3]) == G_TYPE_STRING)
+ text = g_value_get_string (&param_values[3]);
+
+ if (text != NULL)
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ DBUS_TYPE_STRING_AS_STRING, text, append_basic);
+ g_free (minor);
+ return TRUE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Handles the ATK signal 'Gtk:AtkText:text-selection-changed' and
+ * converts it to the AT-SPI signal - 'object:text-selection-changed'
+ *
+ */
+static gboolean
+text_selection_changed_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values,
+ gpointer data)
+{
+ AtkObject *accessible;
+ GSignalQuery signal_query;
+ const gchar *name, *minor;
+ gint detail1 = 0, detail2 = 0;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ minor = g_quark_to_string (signal_hint->detail);
+
+ if (G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ if (G_VALUE_TYPE (&param_values[2]) == G_TYPE_INT)
+ detail2 = g_value_get_int (&param_values[2]);
+
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ DBUS_TYPE_STRING_AS_STRING, "", append_basic);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Children changed signal converter and forwarder.
+ *
+ * Klass (Interface) org.a11y.atspi.Event.Object
+ * Major is the signal name.
+ * Minor is 'add' or 'remove'
+ * detail1 is the index.
+ * detail2 is 0.
+ * any_data is the child reference.
+ */
+static gboolean
+children_changed_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ GSignalQuery signal_query;
+ const gchar *name, *minor;
+ gint detail1 = 0, detail2 = 0;
+
+ AtkObject *accessible, *ao=NULL;
+ gpointer child;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+ minor = g_quark_to_string (signal_hint->detail);
+
+ detail1 = g_value_get_uint (param_values + 1);
+ child = g_value_get_pointer (param_values + 2);
+
+ if (ATK_IS_OBJECT (child))
+ {
+ ao = ATK_OBJECT (child);
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ "(so)", ao, append_object);
+ }
+ else if ((minor != NULL) && (strcmp (minor, "add") == 0))
+ {
+ ao = atk_object_ref_accessible_child (accessible,
+ detail1);
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ "(so)", ao, append_object);
+ g_object_unref (ao);
+ }
+ else
+ {
+ emit_event (accessible, ITF_EVENT_OBJECT, name, minor, detail1, detail2,
+ "(so)", ao, append_object);
+ }
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Generic signal converter and forwarder.
+ *
+ * Klass (Interface) org.a11y.atspi.Event.Object
+ * Major is the signal name.
+ * Minor is NULL.
+ * detail1 is 0.
+ * detail2 is 0.
+ * any_data is NULL.
+ */
+static gboolean
+generic_event_listener (GSignalInvocationHint * signal_hint,
+ guint n_param_values,
+ const GValue * param_values, gpointer data)
+{
+ AtkObject *accessible;
+ GSignalQuery signal_query;
+ const gchar *name;
+ int detail1 = 0, detail2 = 0;
+
+ g_signal_query (signal_hint->signal_id, &signal_query);
+ name = signal_query.signal_name;
+
+ accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
+
+ if (n_param_values > 1 && G_VALUE_TYPE (&param_values[1]) == G_TYPE_INT)
+ detail1 = g_value_get_int (&param_values[1]);
+
+ if (n_param_values > 2 && G_VALUE_TYPE (&param_values[2]) == G_TYPE_INT)
+ detail2 = g_value_get_int (&param_values[2]);
+
+ emit_event (accessible, ITF_EVENT_OBJECT, name, "", detail1, detail2,
+ DBUS_TYPE_INT32_AS_STRING, 0, append_basic);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Registers the provided function as a handler for the given signal name
+ * and stores the signal id returned so that the function may be
+ * de-registered later.
+ */
+static guint
+add_signal_listener (GSignalEmissionHook listener, const char *signal_name)
+{
+ guint id;
+
+ id = atk_add_global_event_listener (listener, signal_name);
+
+ if (id > 0) /* id == 0 is a failure */
+ g_array_append_val (listener_ids, id);
+
+ return id;
+}
+
+/*
+ * Initialization for the signal handlers.
+ *
+ * Registers all required signal handlers.
+ */
+void
+spi_atk_register_event_listeners (void)
+{
+ /*
+ * Kludge to make sure the Atk interface types are registered, otherwise
+ * the AtkText signal handlers below won't get registered
+ */
+ GObject *ao = g_object_new (ATK_TYPE_OBJECT, NULL);
+ AtkObject *bo = atk_no_op_object_new (ao);
+ guint id = 0;
+
+ g_object_unref (G_OBJECT (bo));
+ g_object_unref (ao);
+
+ if (listener_ids)
+ {
+ g_warning ("atk_bridge: spi_atk-register_event_listeners called multiple times");
+ return;
+ }
+
+ /* Register for focus event notifications, and register app with central registry */
+ listener_ids = g_array_sized_new (FALSE, TRUE, sizeof (guint), 16);
+
+ atk_bridge_focus_tracker_id = atk_add_focus_tracker (focus_tracker);
+
+ add_signal_listener (property_event_listener,
+ "Gtk:AtkObject:property-change");
+
+ /* window events: we tentative try to register using the old format */
+ id = add_signal_listener (window_event_listener, "window:create");
+
+ if (id != 0)
+ {
+ /* If we are able to register using the old format, we assume
+ * that the ATK implementor is managing window events without
+ * AtkWindow. We can't use the opposite test because after
+ * including AtkWindow on ATK you would be able to register to
+ * that event, although the ATK implementor could or not use it.
+ */
+
+ add_signal_listener (window_event_listener, "window:destroy");
+ add_signal_listener (window_event_listener, "window:minimize");
+ add_signal_listener (window_event_listener, "window:maximize");
+ add_signal_listener (window_event_listener, "window:restore");
+ add_signal_listener (window_event_listener, "window:activate");
+ add_signal_listener (window_event_listener, "window:deactivate");
+ }
+ else
+ {
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:create");
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:destroy");
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:minimize");
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:maximize");
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:restore");
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:activate");
+ add_signal_listener (window_event_listener, "Atk:AtkWindow:deactivate");
+ }
+
+ add_signal_listener (document_event_listener,
+ "Gtk:AtkDocument:load-complete");
+ add_signal_listener (document_event_listener, "Gtk:AtkDocument:reload");
+ add_signal_listener (document_event_listener,
+ "Gtk:AtkDocument:load-stopped");
+ add_signal_listener (document_event_listener,
+ "Gtk:AtkDocument:page-changed");
+ /* TODO Fake this event on the client side */
+ add_signal_listener (state_event_listener, "Gtk:AtkObject:state-change");
+ /* TODO */
+ add_signal_listener (active_descendant_event_listener,
+ "Gtk:AtkObject:active-descendant-changed");
+ add_signal_listener (bounds_event_listener,
+ "Gtk:AtkComponent:bounds-changed");
+ add_signal_listener (text_selection_changed_event_listener,
+ "Gtk:AtkText:text-selection-changed");
+ add_signal_listener (text_changed_event_listener,
+ "Gtk:AtkText:text-changed");
+ add_signal_listener (text_insert_event_listener,
+ "Gtk:AtkText:text-insert");
+ add_signal_listener (text_remove_event_listener,
+ "Gtk:AtkText:text-remove");
+ add_signal_listener (link_selected_event_listener,
+ "Gtk:AtkHypertext:link-selected");
+ add_signal_listener (generic_event_listener,
+ "Gtk:AtkObject:visible-data-changed");
+ add_signal_listener (generic_event_listener,
+ "Gtk:AtkSelection:selection-changed");
+ add_signal_listener (generic_event_listener,
+ "Gtk:AtkText:text-attributes-changed");
+ add_signal_listener (generic_event_listener,
+ "Gtk:AtkText:text-caret-moved");
+ add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-inserted");
+ add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-reordered");
+ add_signal_listener (generic_event_listener, "Gtk:AtkTable:row-deleted");
+ add_signal_listener (generic_event_listener,
+ "Gtk:AtkTable:column-inserted");
+ add_signal_listener (generic_event_listener,
+ "Gtk:AtkTable:column-reordered");
+ add_signal_listener (generic_event_listener, "Gtk:AtkTable:column-deleted");
+ add_signal_listener (generic_event_listener, "Gtk:AtkTable:model-changed");
+ add_signal_listener (children_changed_event_listener, "Gtk:AtkObject:children-changed");
+
+#if 0
+ g_signal_connect (G_OBJECT (spi_global_app_data->root),
+ "children-changed::add",
+ (GCallback) toplevel_added_event_listener, NULL);
+
+ g_signal_connect (G_OBJECT (spi_global_app_data->root),
+ "children-changed::remove",
+ (GCallback) toplevel_removed_event_listener, NULL);
+#endif
+
+ /*
+ * May add the following listeners to implement preemptive key listening for GTK+
+ *
+ * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-press-event");
+ * atk_add_global_event_listener (spi_atk_bridge_widgetkey_listener, "Gtk:GtkWidget:key-release-event");
+ */
+ atk_bridge_key_event_listener_id =
+ atk_add_key_event_listener (spi_atk_bridge_key_listener, NULL);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * De-registers all ATK signal handlers.
+ */
+void
+spi_atk_deregister_event_listeners (void)
+{
+ gint i;
+ GArray *ids = listener_ids;
+ listener_ids = NULL;
+
+ if (atk_bridge_focus_tracker_id)
+ {
+ atk_remove_focus_tracker (atk_bridge_focus_tracker_id);
+ atk_bridge_focus_tracker_id = 0;
+ }
+
+ if (ids)
+ {
+ for (i = 0; i < ids->len; i++)
+ {
+ atk_remove_global_event_listener (g_array_index (ids, guint, i));
+ }
+ g_array_free (ids, TRUE);
+ }
+
+ if (atk_bridge_key_event_listener_id)
+ {
+ atk_remove_key_event_listener (atk_bridge_key_event_listener_id);
+ atk_bridge_key_event_listener_id = 0;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * TODO This function seems out of place here.
+ *
+ * Emits fake deactivate signals on all top-level windows.
+ * Used when shutting down AT-SPI, ensuring that all
+ * windows have been removed on the client side.
+ */
+void
+spi_atk_tidy_windows (void)
+{
+ AtkObject *root;
+ gint n_children;
+ gint i;
+
+ root = atk_get_root ();
+ n_children = atk_object_get_n_accessible_children (root);
+ for (i = 0; i < n_children; i++)
+ {
+ AtkObject *child;
+ AtkStateSet *stateset;
+ const gchar *name;
+
+ child = atk_object_ref_accessible_child (root, i);
+ stateset = atk_object_ref_state_set (child);
+
+ name = atk_object_get_name (child);
+ if (atk_state_set_contains_state (stateset, ATK_STATE_ACTIVE))
+ {
+ emit_event (child, ITF_EVENT_WINDOW, "deactivate", NULL, 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, name, append_basic);
+ }
+ g_object_unref (stateset);
+
+ emit_event (child, ITF_EVENT_WINDOW, "destroy", NULL, 0, 0,
+ DBUS_TYPE_STRING_AS_STRING, name, append_basic);
+ g_object_unref (child);
+ }
+}
+
+gboolean
+spi_event_is_subtype (gchar **needle, gchar **haystack)
+{
+ while (*haystack && **haystack)
+ {
+ if (g_strcmp0 (*needle, *haystack))
+ return FALSE;
+ needle++;
+ haystack++;
+ }
+ return TRUE;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/event.h b/atk-adaptor/event.h
new file mode 100644
index 0000000..1a9f9f3
--- /dev/null
+++ b/atk-adaptor/event.h
@@ -0,0 +1,33 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ * Copyright 2008, 2009 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EVENT_H
+#define EVENT_H
+
+void spi_atk_register_event_listeners (void);
+void spi_atk_deregister_event_listeners (void);
+void spi_atk_tidy_windows (void);
+
+gboolean spi_event_is_subtype (gchar **needle, gchar **haystack);
+#endif /* EVENT_H */
diff --git a/atk-adaptor/gtk-2.0/Makefile.am b/atk-adaptor/gtk-2.0/Makefile.am
new file mode 100644
index 0000000..4aac9c3
--- /dev/null
+++ b/atk-adaptor/gtk-2.0/Makefile.am
@@ -0,0 +1,5 @@
+ gtkmoduledir = $(libdir)/gtk-2.0/modules
+
+include $(top_srcdir)/atk-adaptor/Makefile.include
+
+libatk_bridge_la_SOURCES = module.c
diff --git a/atk-adaptor/gtk-2.0/module.c b/atk-adaptor/gtk-2.0/module.c
new file mode 100644
index 0000000..d2a49ee
--- /dev/null
+++ b/atk-adaptor/gtk-2.0/module.c
@@ -0,0 +1,62 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008, 2009 Codethink Ltd.
+ * Copyright 2001, 2002, 2003 Sun Microsystems Inc.,
+ * Copyright 2001, 2002, 2003 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include <gmodule.h>
+#include <atk-bridge.h>
+
+/*---------------------------------------------------------------------------*/
+
+int
+gtk_module_init (gint * argc, gchar ** argv[])
+{
+ return atk_bridge_adaptor_init (argc, argv);
+}
+
+gchar*
+g_module_check_init (GModule *module)
+{
+ g_module_make_resident (module);
+
+ return NULL;
+}
+
+void
+gnome_accessibility_module_init (void)
+{
+ atk_bridge_adaptor_init (NULL, NULL);
+
+ if (g_getenv ("AT_SPI_DEBUG"))
+ {
+ g_print ("Atk Accessibility bridge initialized\n");
+ }
+}
+
+void
+gnome_accessibility_module_shutdown (void)
+{
+ atk_bridge_adaptor_cleanup ();
+}
diff --git a/atk-adaptor/introspection.c b/atk-adaptor/introspection.c
new file mode 100644
index 0000000..bc1f332
--- /dev/null
+++ b/atk-adaptor/introspection.c
@@ -0,0 +1,913 @@
+
+/*
+ * This file has been auto-generated from the introspection data available
+ * in the at-spi2-core repository. The D-Bus procol is defined in this
+ * repository, which can be found at:
+ *
+ * http://download.gnome.org/sources/at-spi2-core/0.1/
+ *
+ * DO NOT EDIT.
+ */
+
+
+const char *spi_org_a11y_atspi_Accessible =
+"<interface name=\"org.a11y.atspi.Accessible\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"Name\" type=\"s\" />"
+""
+" <property access=\"read\" name=\"Description\" type=\"s\" />"
+""
+" <property access=\"read\" name=\"Parent\" type=\"(so)\">"
+" "
+" </property>"
+""
+" <property access=\"read\" name=\"ChildCount\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"Locale\" type=\"s\" />"
+""
+" <method name=\"GetChildAtIndex\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetChildren\">"
+" <arg direction=\"out\" type=\"a(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetIndexInParent\">"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetRelationSet\">"
+" <arg direction=\"out\" type=\"a(ua(so))\" />"
+" "
+" </method>"
+""
+" <method name=\"GetRole\">"
+" <arg direction=\"out\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GetRoleName\">"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetLocalizedRoleName\">"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetState\">"
+" <arg direction=\"out\" type=\"au\" />"
+" "
+" </method>"
+""
+" <method name=\"GetAttributes\">"
+" <arg direction=\"out\" type=\"a{ss}\" />"
+" "
+" </method>"
+""
+" <method name=\"GetApplication\">"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Action =
+"<interface name=\"org.a11y.atspi.Action\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"NActions\" type=\"i\" />"
+""
+" <method name=\"GetDescription\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetName\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetLocalizedName\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetKeyBinding\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetActions\">"
+" <arg direction=\"out\" type=\"a(sss)\" />"
+" "
+" </method>"
+""
+" <method name=\"DoAction\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Application =
+"<interface name=\"org.a11y.atspi.Application\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"ToolkitName\" type=\"s\" />"
+""
+" <property access=\"read\" name=\"Version\" type=\"s\" />"
+""
+" <property access=\"read\" name=\"AtspiVersion\" type=\"s\" />"
+" <property access=\"read\" name=\"Id\" type=\"i\" />"
+""
+" <method name=\"GetLocale\">"
+" <arg direction=\"in\" name=\"lctype\" type=\"u\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"RegisterEventListener\">"
+" <arg direction=\"in\" name=\"event\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"DeregisterEventListener\">"
+" <arg direction=\"in\" name=\"event\" type=\"s\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Collection =
+"<interface name=\"org.a11y.atspi.Collection\" version=\"0.1.7\">"
+""
+" <method name=\"GetMatches\">"
+" <arg direction=\"in\" name=\"rule\" type=\"(auuasuauusub)\" />"
+" "
+" <arg direction=\"in\" name=\"sortby\" type=\"u\" />"
+" <arg direction=\"in\" name=\"count\" type=\"i\" />"
+" <arg direction=\"in\" name=\"traverse\" type=\"b\" />"
+" <arg direction=\"out\" type=\"a(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetMatchesTo\">"
+" <arg direction=\"in\" name=\"current_object\" type=\"o\" />"
+" "
+" <arg direction=\"in\" name=\"rule\" type=\"(auuasuauusub)\" />"
+" "
+" <arg direction=\"in\" name=\"sortby\" type=\"u\" />"
+" <arg direction=\"in\" name=\"tree\" type=\"u\" />"
+" <arg direction=\"in\" name=\"limit_scope\" type=\"b\" />"
+" <arg direction=\"in\" name=\"count\" type=\"i\" />"
+" <arg direction=\"in\" name=\"traverse\" type=\"b\" />"
+" <arg direction=\"out\" type=\"a(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetMatchesFrom\">"
+" <arg direction=\"in\" name=\"current_object\" type=\"o\" />"
+" "
+" <arg direction=\"in\" name=\"rule\" type=\"(auuasuauusub)\" />"
+" "
+" <arg direction=\"in\" name=\"sortby\" type=\"u\" />"
+" <arg direction=\"in\" name=\"tree\" type=\"u\" />"
+" <arg direction=\"in\" name=\"count\" type=\"i\" />"
+" <arg direction=\"in\" name=\"traverse\" type=\"b\" />"
+" <arg direction=\"out\" type=\"a(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetActiveDescendant\">"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Component =
+"<interface name=\"org.a11y.atspi.Component\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"HighlightIndex\" type=\"i\" />"
+""
+" <method name=\"Contains\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coord_type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GetAccessibleAtPoint\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coord_type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetExtents\">"
+" <arg direction=\"in\" name=\"coord_type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"(iiii)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetPosition\">"
+" <arg direction=\"in\" name=\"coord_type\" type=\"u\" />"
+" <arg direction=\"out\" name=\"x\" type=\"i\" />"
+" <arg direction=\"out\" name=\"y\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetSize\">"
+" <arg direction=\"out\" name=\"width\" type=\"i\" />"
+" <arg direction=\"out\" name=\"height\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetLayer\">"
+" <arg direction=\"out\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GetMDIZOrder\">"
+" <arg direction=\"out\" type=\"n\" />"
+" </method>"
+""
+" <method name=\"GrabFocus\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GrabHighlight\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"ClearHighlight\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GetAlpha\">"
+" <arg direction=\"out\" type=\"d\" />"
+" </method>"
+""
+" <method name=\"SetExtents\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"width\" type=\"i\" />"
+" <arg direction=\"in\" name=\"height\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coord_type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"SetPosition\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coord_type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"SetSize\">"
+" <arg direction=\"in\" name=\"width\" type=\"i\" />"
+" <arg direction=\"in\" name=\"height\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Document =
+"<interface name=\"org.a11y.atspi.Document\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"CurrentPageNumber\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"PageCount\" type=\"i\" />"
+""
+" <method name=\"GetLocale\">"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetAttributeValue\">"
+" <arg direction=\"in\" name=\"attributename\" type=\"s\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetAttributes\">"
+" <arg direction=\"out\" type=\"{ss}\" />"
+" "
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Hypertext =
+"<interface name=\"org.a11y.atspi.Hypertext\" version=\"0.1.7\">"
+""
+" <method name=\"GetNLinks\">"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetLink\">"
+" <arg direction=\"in\" name=\"linkIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetLinkIndex\">"
+" <arg direction=\"in\" name=\"characterIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Hyperlink =
+"<interface name=\"org.a11y.atspi.Hyperlink\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"NAnchors\" type=\"n\" />"
+""
+" <property access=\"read\" name=\"StartIndex\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"EndIndex\" type=\"i\" />"
+""
+" <method name=\"GetObject\">"
+" <arg direction=\"in\" name=\"i\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetURI\">"
+" <arg direction=\"in\" name=\"i\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"IsValid\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Image =
+"<interface name=\"org.a11y.atspi.Image\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"ImageDescription\" type=\"s\" />"
+""
+" <property access=\"read\" name=\"ImageLocale\" type=\"s\" />"
+""
+" <method name=\"GetImageExtents\">"
+" <arg direction=\"in\" name=\"coordType\" type=\"u\" />"
+" <arg direction=\"out\" type=\"(iiii)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetImagePosition\">"
+" <arg direction=\"out\" name=\"x\" type=\"i\" />"
+" <arg direction=\"out\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coordType\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GetImageSize\">"
+" <arg direction=\"out\" name=\"width\" type=\"i\" />"
+" <arg direction=\"out\" name=\"height\" type=\"i\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Selection =
+"<interface name=\"org.a11y.atspi.Selection\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"NSelectedChildren\" type=\"i\" />"
+""
+" <method name=\"GetSelectedChild\">"
+" <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"SelectChild\">"
+" <arg direction=\"in\" name=\"childIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"DeselectSelectedChild\">"
+" <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"IsChildSelected\">"
+" <arg direction=\"in\" name=\"childIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"SelectAll\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"ClearSelection\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"DeselectChild\">"
+" <arg direction=\"in\" name=\"childIndex\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Table =
+"<interface name=\"org.a11y.atspi.Table\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"NRows\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"NColumns\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"Caption\" type=\"(so)\">"
+" "
+" </property>"
+""
+" <property access=\"read\" name=\"Summary\" type=\"(so)\">"
+" "
+" </property>"
+""
+" <property access=\"read\" name=\"NSelectedRows\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"NSelectedColumns\" type=\"i\" />"
+""
+" <method name=\"GetAccessibleAt\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetIndexAt\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetRowAtIndex\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetColumnAtIndex\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetRowDescription\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetColumnDescription\">"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"GetRowExtentAt\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetColumnExtentAt\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetRowHeader\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetColumnHeader\">"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"(so)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetSelectedRows\">"
+" <arg direction=\"out\" type=\"ai\" />"
+" "
+" </method>"
+""
+" <method name=\"GetSelectedColumns\">"
+" <arg direction=\"out\" type=\"ai\" />"
+" "
+" </method>"
+""
+" <method name=\"IsRowSelected\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"IsColumnSelected\">"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"IsSelected\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"AddRowSelection\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"AddColumnSelection\">"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"RemoveRowSelection\">"
+" <arg direction=\"in\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"RemoveColumnSelection\">"
+" <arg direction=\"in\" name=\"column\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GetRowColumnExtentsAtIndex\">"
+" <arg direction=\"in\" name=\"index\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" <arg direction=\"out\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" name=\"col\" type=\"i\" />"
+" <arg direction=\"out\" name=\"row_extents\" type=\"i\" />"
+" <arg direction=\"out\" name=\"col_extents\" type=\"i\" />"
+" <arg direction=\"out\" name=\"is_selected\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_TableCell =
+"<interface name=\"org.a11y.atspi.TableCell\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"ColumnSpan\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"Position\" type=\"(ii)\" />"
+""
+" <property access=\"read\" name=\"RowSpan\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"Table\" type=\"(so)\" />"
+""
+" <method name=\"GetRowColumnSpan\">"
+" <arg direction=\"out\" type=\"b\" />"
+" <arg direction=\"out\" name=\"row\" type=\"i\" />"
+" <arg direction=\"out\" name=\"col\" type=\"i\" />"
+" <arg direction=\"out\" name=\"row_extents\" type=\"i\" />"
+" <arg direction=\"out\" name=\"col_extents\" type=\"i\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Text =
+"<interface name=\"org.a11y.atspi.Text\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"CharacterCount\" type=\"i\" />"
+""
+" <property access=\"read\" name=\"CaretOffset\" type=\"i\" />"
+""
+" <method name=\"GetStringAtOffset\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"granularity\" type=\"u\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetText\">"
+" <arg direction=\"in\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endOffset\" type=\"i\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"SetCaretOffset\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GetTextBeforeOffset\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetTextAtOffset\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetTextAfterOffset\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"type\" type=\"u\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetCharacterAtOffset\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetAttributeValue\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"attributeName\" type=\"s\" />"
+" <arg direction=\"out\" type=\"s\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"defined\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GetAttributes\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"out\" type=\"a{ss}\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" "
+" </method>"
+""
+" <method name=\"GetDefaultAttributes\">"
+" <arg direction=\"out\" type=\"a{ss}\" />"
+" "
+" </method>"
+""
+" <method name=\"GetCharacterExtents\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"x\" type=\"i\" />"
+" <arg direction=\"out\" name=\"y\" type=\"i\" />"
+" <arg direction=\"out\" name=\"width\" type=\"i\" />"
+" <arg direction=\"out\" name=\"height\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coordType\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GetOffsetAtPoint\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coordType\" type=\"u\" />"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetNSelections\">"
+" <arg direction=\"out\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"GetSelection\">"
+" <arg direction=\"in\" name=\"selectionNum\" type=\"i\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"AddSelection\">"
+" <arg direction=\"in\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endOffset\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"RemoveSelection\">"
+" <arg direction=\"in\" name=\"selectionNum\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"SetSelection\">"
+" <arg direction=\"in\" name=\"selectionNum\" type=\"i\" />"
+" <arg direction=\"in\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endOffset\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GetRangeExtents\">"
+" <arg direction=\"in\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"x\" type=\"i\" />"
+" <arg direction=\"out\" name=\"y\" type=\"i\" />"
+" <arg direction=\"out\" name=\"width\" type=\"i\" />"
+" <arg direction=\"out\" name=\"height\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coordType\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GetBoundedRanges\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"width\" type=\"i\" />"
+" <arg direction=\"in\" name=\"height\" type=\"i\" />"
+" <arg direction=\"in\" name=\"coordType\" type=\"u\" />"
+" <arg direction=\"in\" name=\"xClipType\" type=\"u\" />"
+" <arg direction=\"in\" name=\"yClipType\" type=\"u\" />"
+" <arg direction=\"out\" type=\"a(iisv)\" />"
+" "
+" </method>"
+""
+" <method name=\"GetAttributeRun\">"
+" <arg direction=\"in\" name=\"offset\" type=\"i\" />"
+" <arg direction=\"in\" name=\"includeDefaults\" type=\"b\" />"
+" <arg direction=\"out\" type=\"a{ss}\" />"
+" <arg direction=\"out\" name=\"startOffset\" type=\"i\" />"
+" <arg direction=\"out\" name=\"endOffset\" type=\"i\" />"
+" "
+" </method>"
+""
+" <method name=\"GetDefaultAttributeSet\">"
+" <arg direction=\"out\" type=\"a{ss}\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_EditableText =
+"<interface name=\"org.a11y.atspi.EditableText\" version=\"0.1.7\">"
+""
+" <method name=\"SetTextContents\">"
+" <arg direction=\"in\" name=\"newContents\" type=\"s\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"InsertText\">"
+" <arg direction=\"in\" name=\"position\" type=\"i\" />"
+" <arg direction=\"in\" name=\"text\" type=\"s\" />"
+" <arg direction=\"in\" name=\"length\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"CopyText\">"
+" <arg direction=\"in\" name=\"startPos\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endPos\" type=\"i\" />"
+" </method>"
+""
+" <method name=\"CutText\">"
+" <arg direction=\"in\" name=\"startPos\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endPos\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"DeleteText\">"
+" <arg direction=\"in\" name=\"startPos\" type=\"i\" />"
+" <arg direction=\"in\" name=\"endPos\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"PasteText\">"
+" <arg direction=\"in\" name=\"position\" type=\"i\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Cache =
+"<interface name=\"org.a11y.atspi.Cache\" version=\"0.1.7\">"
+""
+" <method name=\"GetItems\">"
+" <arg direction=\"out\" name=\"nodes\" type=\"a((so)(so)a(so)assusau)\" />"
+" "
+" </method>"
+""
+" <signal name=\"AddAccessible\">"
+" <arg name=\"nodeAdded\" type=\"((so)(so)a(so)assusau)\" />"
+" "
+" </signal>"
+""
+" <signal name=\"RemoveAccessible\">"
+" <arg name=\"nodeRemoved\" type=\"(so)\" />"
+" "
+" </signal>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Value =
+"<interface name=\"org.a11y.atspi.Value\" version=\"0.1.7\">"
+""
+" <property access=\"read\" name=\"MinimumValue\" type=\"d\" />"
+""
+" <property access=\"read\" name=\"MaximumValue\" type=\"d\" />"
+""
+" <property access=\"read\" name=\"MinimumIncrement\" type=\"d\" />"
+""
+" <property access=\"readwrite\" name=\"CurrentValue\" type=\"d\" />"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_Registry =
+"<interface name=\"org.a11y.atspi.Registry\" version=\"0.1.7\">"
+""
+" <method name=\"RegisterEvent\">"
+" <arg direction=\"in\" name=\"event\" type=\"s\">"
+" </arg>"
+" </method>"
+""
+" <method name=\"DeregisterEvent\">"
+" <arg direction=\"in\" name=\"event\" type=\"s\">"
+" </arg>"
+" </method>"
+""
+" <method name=\"GetRegisteredEvents\">"
+" <arg direction=\"out\" name=\"events\" type=\"a(ss)\">"
+" </arg>"
+" </method>"
+""
+" <signal name=\"EventListenerRegistered\">"
+" <arg direction=\"out\" name=\"bus\" type=\"s\" />"
+" <arg direction=\"out\" name=\"path\" type=\"s\" />"
+" </signal>"
+""
+" <signal name=\"EventListenerDeregistered\">"
+" <arg direction=\"out\" name=\"bus\" type=\"s\" />"
+" <arg direction=\"out\" name=\"path\" type=\"s\" />"
+" </signal>"
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_DeviceEventController =
+"<interface name=\"org.a11y.atspi.DeviceEventController\" version=\"0.1.7\">"
+""
+" <method name=\"RegisterKeystrokeListener\">"
+" <arg direction=\"in\" name=\"listener\" type=\"o\" />"
+" <arg direction=\"in\" name=\"keys\" type=\"a(iisi)\">"
+" "
+" </arg>"
+" <arg direction=\"in\" name=\"mask\" type=\"u\" />"
+" <arg direction=\"in\" name=\"type\" type=\"au\">"
+" "
+" </arg>"
+" <arg direction=\"in\" name=\"mode\" type=\"(bbb)\">"
+" "
+" </arg>"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"DeregisterKeystrokeListener\">"
+" <arg direction=\"in\" name=\"listener\" type=\"o\" />"
+" <arg direction=\"in\" name=\"keys\" type=\"a(iisi)\">"
+" "
+" </arg>"
+" <arg direction=\"in\" name=\"mask\" type=\"u\" />"
+" <arg direction=\"in\" name=\"type\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"RegisterDeviceEventListener\">"
+" <arg direction=\"in\" name=\"listener\" type=\"o\" />"
+" <arg direction=\"in\" name=\"types\" type=\"u\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"DeregisterDeviceEventListener\">"
+" <arg direction=\"in\" name=\"listener\" type=\"o\" />"
+" <arg direction=\"in\" name=\"types\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GenerateKeyboardEvent\">"
+" <arg direction=\"in\" name=\"keycode\" type=\"i\" />"
+" <arg direction=\"in\" name=\"keystring\" type=\"s\" />"
+" <arg direction=\"in\" name=\"type\" type=\"u\" />"
+" </method>"
+""
+" <method name=\"GenerateMouseEvent\">"
+" <arg direction=\"in\" name=\"x\" type=\"i\" />"
+" <arg direction=\"in\" name=\"y\" type=\"i\" />"
+" <arg direction=\"in\" name=\"eventName\" type=\"s\" />"
+" </method>"
+""
+" <method name=\"NotifyListenersSync\">"
+" <arg direction=\"in\" name=\"event\" type=\"(uiuuisb)\" />"
+" <arg direction=\"out\" type=\"b\" />"
+" "
+" </method>"
+""
+" <method name=\"NotifyListenersAsync\">"
+" <arg direction=\"in\" name=\"event\" type=\"(uiuuisb)\" />"
+" "
+" </method>"
+""
+"</interface>"
+"";
+
+const char *spi_org_a11y_atspi_DeviceEventListener =
+"<interface name=\"org.a11y.atspi.DeviceEventListener\" version=\"0.1.7\">"
+""
+" <method name=\"NotifyEvent\">"
+" <arg direction=\"in\" name=\"event\" type=\"(uiuuisb)\" />"
+" "
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+"</interface>"
+"";
+
diff --git a/atk-adaptor/introspection.h b/atk-adaptor/introspection.h
new file mode 100644
index 0000000..2210483
--- /dev/null
+++ b/atk-adaptor/introspection.h
@@ -0,0 +1,55 @@
+
+/*
+ * This file has been auto-generated from the introspection data available
+ * in the at-spi2-core repository. The D-Bus procol is defined in this
+ * repository, which can be found at:
+ *
+ * http://download.gnome.org/sources/at-spi2-core/0.1/
+ *
+ * DO NOT EDIT.
+ */
+
+#ifndef SPI_INTROSPECTION_DATA_H_
+#define SPI_INTROSPECTION_DATA_H_
+
+
+extern const char *spi_org_a11y_atspi_Accessible;
+
+extern const char *spi_org_a11y_atspi_Action;
+
+extern const char *spi_org_a11y_atspi_Application;
+
+extern const char *spi_org_a11y_atspi_Collection;
+
+extern const char *spi_org_a11y_atspi_Component;
+
+extern const char *spi_org_a11y_atspi_Document;
+
+extern const char *spi_org_a11y_atspi_Hypertext;
+
+extern const char *spi_org_a11y_atspi_Hyperlink;
+
+extern const char *spi_org_a11y_atspi_Image;
+
+extern const char *spi_org_a11y_atspi_Selection;
+
+extern const char *spi_org_a11y_atspi_Table;
+
+extern const char *spi_org_a11y_atspi_TableCell;
+
+extern const char *spi_org_a11y_atspi_Text;
+
+extern const char *spi_org_a11y_atspi_EditableText;
+
+extern const char *spi_org_a11y_atspi_Cache;
+
+extern const char *spi_org_a11y_atspi_Value;
+
+extern const char *spi_org_a11y_atspi_Registry;
+
+extern const char *spi_org_a11y_atspi_DeviceEventController;
+
+extern const char *spi_org_a11y_atspi_DeviceEventListener;
+
+
+#endif /* SPI_INTROSPECTION_DATA_H_ */
diff --git a/atk-adaptor/object.c b/atk-adaptor/object.c
new file mode 100644
index 0000000..404fb24
--- /dev/null
+++ b/atk-adaptor/object.c
@@ -0,0 +1,504 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008, 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This module contains utility functions for exporting AT-SPI
+ * objects based upon an ATK object.
+ *
+ * It incudes functions for marshalling object references
+ * and supported interfaces to a D-Bus message.
+ */
+
+#include <atk/atk.h>
+#include "atspi/atspi.h"
+#include "spi-dbus.h"
+
+#include "accessible-register.h"
+#include "accessible-cache.h"
+#include "accessible-leasing.h"
+
+#include "bridge.h"
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * This is the all important function that decides whether an object should
+ * be leased or not.
+ *
+ * The choice of algorithm for this is somewhat vuage. We want ideally to lease
+ * all atk objects that are not owned by their parent.
+ *
+ * The 'cache' object attempts to cache all objects that are owned by their
+ * parent by traversing the tree of accessibles, ignoring the children of
+ * manages-descendants and transient objects.
+ *
+ * This function will simply look for all the accessibles that the cache object
+ * has not found and assume that they need to be leased.
+ */
+void
+spi_object_lease_if_needed (GObject *obj)
+{
+ if (!spi_cache_in (spi_global_cache, obj))
+ {
+ spi_leasing_take (spi_global_leasing, obj);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * It is assumed that all of these functions are returning an accessible
+ * object to the client side.
+ *
+ * All of them will lease the AtkObject if it is deemed neccessary.
+ */
+
+void
+spi_object_append_null_reference (DBusMessageIter * iter)
+{
+ DBusMessageIter iter_struct;
+ const char *name;
+ const char *path = ATSPI_DBUS_PATH_NULL;
+
+ name = dbus_bus_get_unique_name (spi_global_app_data->bus);
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
+ &iter_struct);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
+ dbus_message_iter_close_container (iter, &iter_struct);
+}
+
+void
+spi_object_append_reference (DBusMessageIter * iter, AtkObject * obj)
+{
+ DBusMessageIter iter_struct;
+ const gchar *name;
+ gchar *path;
+
+ if (!obj) {
+ spi_object_append_null_reference (iter);
+ return;
+ }
+
+ spi_object_lease_if_needed (G_OBJECT (obj));
+
+ name = dbus_bus_get_unique_name (spi_global_app_data->bus);
+ path = spi_register_object_to_path (spi_global_register, G_OBJECT (obj));
+
+ if (!path)
+ path = g_strdup (SPI_DBUS_PATH_NULL);
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
+ &iter_struct);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
+ dbus_message_iter_close_container (iter, &iter_struct);
+
+ g_free (path);
+}
+
+/* TODO: Perhaps combine with spi_object_append_reference. Leaving separate
+ * for now in case we want to use a different path for hyperlinks. */
+void
+spi_hyperlink_append_reference (DBusMessageIter * iter, AtkHyperlink * obj)
+{
+ DBusMessageIter iter_struct;
+ const gchar *name;
+ gchar *path;
+
+ if (!obj) {
+ spi_object_append_null_reference (iter);
+ return;
+ }
+
+ spi_object_lease_if_needed (G_OBJECT (obj));
+
+ name = dbus_bus_get_unique_name (spi_global_app_data->bus);
+ path = spi_register_object_to_path (spi_global_register, G_OBJECT (obj));
+
+ if (!path)
+ path = g_strdup (SPI_DBUS_PATH_NULL);
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
+ &iter_struct);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
+ dbus_message_iter_close_container (iter, &iter_struct);
+
+ g_free (path);
+}
+
+void
+spi_object_append_v_reference (DBusMessageIter * iter, AtkObject * obj)
+{
+ DBusMessageIter iter_variant;
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "(so)",
+ &iter_variant);
+ spi_object_append_reference (&iter_variant, obj);
+ dbus_message_iter_close_container (iter, &iter_variant);
+}
+
+void
+spi_object_append_desktop_reference (DBusMessageIter * iter)
+{
+ DBusMessageIter iter_struct;
+ const char *name = spi_global_app_data->desktop_name;
+ const char *path = spi_global_app_data->desktop_path;
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
+ &iter_struct);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path);
+ dbus_message_iter_close_container (iter, &iter_struct);
+}
+
+DBusMessage *
+spi_object_return_reference (DBusMessage * msg, AtkObject * obj)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return (msg);
+ if (reply)
+ {
+ DBusMessageIter iter;
+ dbus_message_iter_init_append (reply, &iter);
+ spi_object_append_reference (&iter, obj);
+ }
+
+ return reply;
+}
+
+DBusMessage *
+spi_hyperlink_return_reference (DBusMessage * msg, AtkHyperlink * obj)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return (msg);
+ if (reply)
+ {
+ DBusMessageIter iter;
+ dbus_message_iter_init_append (reply, &iter);
+ spi_hyperlink_append_reference (&iter, obj);
+ }
+ if (obj)
+ g_object_unref (G_OBJECT (obj));
+
+ return reply;
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+spi_object_append_interfaces (DBusMessageIter * iter, AtkObject * obj)
+{
+ const gchar *itf;
+
+ itf = ATSPI_DBUS_INTERFACE_ACCESSIBLE;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+
+ if (ATK_IS_ACTION (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_ACTION;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (atk_object_get_role (obj) == ATK_ROLE_APPLICATION)
+ {
+ itf = ATSPI_DBUS_INTERFACE_APPLICATION;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_COMPONENT (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_COMPONENT;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_EDITABLE_TEXT (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_EDITABLE_TEXT;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_TEXT (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_TEXT;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_HYPERTEXT (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_HYPERTEXT;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_IMAGE (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_IMAGE;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_SELECTION (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_SELECTION;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_TABLE (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_TABLE;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_TABLE_CELL (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_TABLE_CELL;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_VALUE (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_VALUE;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+#if 0
+ if (ATK_IS_STREAMABLE_CONTENT (obj))
+ {
+ itf = "org.a11y.atspi.StreamableContent";
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+#endif
+
+ if (ATK_IS_OBJECT (obj))
+ {
+ itf = "org.a11y.atspi.Collection";
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_DOCUMENT (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_DOCUMENT;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+
+ if (ATK_IS_HYPERLINK_IMPL (obj))
+ {
+ itf = ATSPI_DBUS_INTERFACE_HYPERLINK;
+ dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &itf);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+spi_object_append_attribute_set (DBusMessageIter * iter, AtkAttributeSet * attr)
+{
+ DBusMessageIter dictIter;
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{ss}", &dictIter);
+ while (attr)
+ {
+ DBusMessageIter dictEntryIter;
+ AtkAttribute *attribute = (AtkAttribute *) attr->data;
+ const char *key = attribute->name;
+ const char *value = attribute->value;
+
+ if (key == NULL)
+ key = "";
+ if (value == NULL)
+ value = "";
+
+ dbus_message_iter_open_container (&dictIter, DBUS_TYPE_DICT_ENTRY, NULL,
+ &dictEntryIter);
+ dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING,
+ &key);
+ dbus_message_iter_append_basic (&dictEntryIter, DBUS_TYPE_STRING,
+ &value);
+ dbus_message_iter_close_container (&dictIter, &dictEntryIter);
+ attr = g_slist_next (attr);
+ }
+ dbus_message_iter_close_container (iter, &dictIter);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static gboolean
+init_role_lookup_table (AtspiRole * role_table)
+{
+ int i;
+ /* if it's not in the list below, dunno what it is */
+ for (i = 0; i < ATK_ROLE_LAST_DEFINED; ++i)
+ {
+ role_table[i] = ATSPI_ROLE_UNKNOWN;
+ }
+
+ role_table[ATK_ROLE_INVALID] = ATSPI_ROLE_INVALID;
+ role_table[ATK_ROLE_ACCEL_LABEL] = ATSPI_ROLE_ACCELERATOR_LABEL;
+ role_table[ATK_ROLE_ALERT] = ATSPI_ROLE_ALERT;
+ role_table[ATK_ROLE_ANIMATION] = ATSPI_ROLE_ANIMATION;
+ role_table[ATK_ROLE_ARROW] = ATSPI_ROLE_ARROW;
+ role_table[ATK_ROLE_CALENDAR] = ATSPI_ROLE_CALENDAR;
+ role_table[ATK_ROLE_CANVAS] = ATSPI_ROLE_CANVAS;
+ role_table[ATK_ROLE_CHECK_BOX] = ATSPI_ROLE_CHECK_BOX;
+ role_table[ATK_ROLE_CHECK_MENU_ITEM] = ATSPI_ROLE_CHECK_MENU_ITEM;
+ role_table[ATK_ROLE_COLOR_CHOOSER] = ATSPI_ROLE_COLOR_CHOOSER;
+ role_table[ATK_ROLE_COLUMN_HEADER] = ATSPI_ROLE_COLUMN_HEADER;
+ role_table[ATK_ROLE_COMBO_BOX] = ATSPI_ROLE_COMBO_BOX;
+ role_table[ATK_ROLE_DATE_EDITOR] = ATSPI_ROLE_DATE_EDITOR;
+ role_table[ATK_ROLE_DESKTOP_ICON] = ATSPI_ROLE_DESKTOP_ICON;
+ role_table[ATK_ROLE_DESKTOP_FRAME] = ATSPI_ROLE_DESKTOP_FRAME;
+ role_table[ATK_ROLE_DIAL] = ATSPI_ROLE_DIAL;
+ role_table[ATK_ROLE_DIALOG] = ATSPI_ROLE_DIALOG;
+ role_table[ATK_ROLE_DIRECTORY_PANE] = ATSPI_ROLE_DIRECTORY_PANE;
+ role_table[ATK_ROLE_DRAWING_AREA] = ATSPI_ROLE_DRAWING_AREA;
+ role_table[ATK_ROLE_FILE_CHOOSER] = ATSPI_ROLE_FILE_CHOOSER;
+ role_table[ATK_ROLE_FILLER] = ATSPI_ROLE_FILLER;
+ role_table[ATK_ROLE_FONT_CHOOSER] = ATSPI_ROLE_FONT_CHOOSER;
+ role_table[ATK_ROLE_FRAME] = ATSPI_ROLE_FRAME;
+ role_table[ATK_ROLE_GLASS_PANE] = ATSPI_ROLE_GLASS_PANE;
+ role_table[ATK_ROLE_HTML_CONTAINER] = ATSPI_ROLE_HTML_CONTAINER;
+ role_table[ATK_ROLE_ICON] = ATSPI_ROLE_ICON;
+ role_table[ATK_ROLE_IMAGE] = ATSPI_ROLE_IMAGE;
+ role_table[ATK_ROLE_INTERNAL_FRAME] = ATSPI_ROLE_INTERNAL_FRAME;
+ role_table[ATK_ROLE_LABEL] = ATSPI_ROLE_LABEL;
+ role_table[ATK_ROLE_LAYERED_PANE] = ATSPI_ROLE_LAYERED_PANE;
+ role_table[ATK_ROLE_LIST] = ATSPI_ROLE_LIST;
+ role_table[ATK_ROLE_LIST_ITEM] = ATSPI_ROLE_LIST_ITEM;
+ role_table[ATK_ROLE_MENU] = ATSPI_ROLE_MENU;
+ role_table[ATK_ROLE_MENU_BAR] = ATSPI_ROLE_MENU_BAR;
+ role_table[ATK_ROLE_MENU_ITEM] = ATSPI_ROLE_MENU_ITEM;
+ role_table[ATK_ROLE_OPTION_PANE] = ATSPI_ROLE_OPTION_PANE;
+ role_table[ATK_ROLE_PAGE_TAB] = ATSPI_ROLE_PAGE_TAB;
+ role_table[ATK_ROLE_PAGE_TAB_LIST] = ATSPI_ROLE_PAGE_TAB_LIST;
+ role_table[ATK_ROLE_PANEL] = ATSPI_ROLE_PANEL;
+ role_table[ATK_ROLE_PASSWORD_TEXT] = ATSPI_ROLE_PASSWORD_TEXT;
+ role_table[ATK_ROLE_POPUP_MENU] = ATSPI_ROLE_POPUP_MENU;
+ role_table[ATK_ROLE_PROGRESS_BAR] = ATSPI_ROLE_PROGRESS_BAR;
+ role_table[ATK_ROLE_PUSH_BUTTON] = ATSPI_ROLE_PUSH_BUTTON;
+ role_table[ATK_ROLE_RADIO_BUTTON] = ATSPI_ROLE_RADIO_BUTTON;
+ role_table[ATK_ROLE_RADIO_MENU_ITEM] = ATSPI_ROLE_RADIO_MENU_ITEM;
+ role_table[ATK_ROLE_ROOT_PANE] = ATSPI_ROLE_ROOT_PANE;
+ role_table[ATK_ROLE_ROW_HEADER] = ATSPI_ROLE_ROW_HEADER;
+ role_table[ATK_ROLE_SCROLL_BAR] = ATSPI_ROLE_SCROLL_BAR;
+ role_table[ATK_ROLE_SCROLL_PANE] = ATSPI_ROLE_SCROLL_PANE;
+ role_table[ATK_ROLE_SEPARATOR] = ATSPI_ROLE_SEPARATOR;
+ role_table[ATK_ROLE_SLIDER] = ATSPI_ROLE_SLIDER;
+ role_table[ATK_ROLE_SPIN_BUTTON] = ATSPI_ROLE_SPIN_BUTTON;
+ role_table[ATK_ROLE_SPLIT_PANE] = ATSPI_ROLE_SPLIT_PANE;
+ role_table[ATK_ROLE_STATUSBAR] = ATSPI_ROLE_STATUS_BAR;
+ role_table[ATK_ROLE_TABLE] = ATSPI_ROLE_TABLE;
+ role_table[ATK_ROLE_TABLE_CELL] = ATSPI_ROLE_TABLE_CELL;
+ role_table[ATK_ROLE_TABLE_COLUMN_HEADER] =
+ ATSPI_ROLE_TABLE_COLUMN_HEADER;
+ role_table[ATK_ROLE_TABLE_ROW_HEADER] = ATSPI_ROLE_TABLE_ROW_HEADER;
+ role_table[ATK_ROLE_TEAR_OFF_MENU_ITEM] =
+ ATSPI_ROLE_TEAROFF_MENU_ITEM;
+ role_table[ATK_ROLE_TERMINAL] = ATSPI_ROLE_TERMINAL;
+ role_table[ATK_ROLE_TEXT] = ATSPI_ROLE_TEXT;
+ role_table[ATK_ROLE_TOGGLE_BUTTON] = ATSPI_ROLE_TOGGLE_BUTTON;
+ role_table[ATK_ROLE_TOOL_BAR] = ATSPI_ROLE_TOOL_BAR;
+ role_table[ATK_ROLE_TOOL_TIP] = ATSPI_ROLE_TOOL_TIP;
+ role_table[ATK_ROLE_TREE] = ATSPI_ROLE_TREE;
+ role_table[ATK_ROLE_TREE_TABLE] = ATSPI_ROLE_TREE_TABLE;
+ role_table[ATK_ROLE_UNKNOWN] = ATSPI_ROLE_UNKNOWN;
+ role_table[ATK_ROLE_VIEWPORT] = ATSPI_ROLE_VIEWPORT;
+ role_table[ATK_ROLE_WINDOW] = ATSPI_ROLE_WINDOW;
+ role_table[ATK_ROLE_HEADER] = ATSPI_ROLE_HEADER;
+ role_table[ATK_ROLE_FOOTER] = ATSPI_ROLE_FOOTER;
+ role_table[ATK_ROLE_PARAGRAPH] = ATSPI_ROLE_PARAGRAPH;
+ role_table[ATK_ROLE_RULER] = ATSPI_ROLE_RULER;
+ role_table[ATK_ROLE_APPLICATION] = ATSPI_ROLE_APPLICATION;
+ role_table[ATK_ROLE_AUTOCOMPLETE] = ATSPI_ROLE_AUTOCOMPLETE;
+ role_table[ATK_ROLE_EDITBAR] = ATSPI_ROLE_EDITBAR;
+ role_table[ATK_ROLE_EMBEDDED] = ATSPI_ROLE_EMBEDDED;
+ role_table[ATK_ROLE_ENTRY] = ATSPI_ROLE_ENTRY;
+ role_table[ATK_ROLE_CHART] = ATSPI_ROLE_CHART;
+ role_table[ATK_ROLE_CAPTION] = ATSPI_ROLE_CAPTION;
+ role_table[ATK_ROLE_DOCUMENT_FRAME] = ATSPI_ROLE_DOCUMENT_FRAME;
+ role_table[ATK_ROLE_HEADING] = ATSPI_ROLE_HEADING;
+ role_table[ATK_ROLE_PAGE] = ATSPI_ROLE_PAGE;
+ role_table[ATK_ROLE_SECTION] = ATSPI_ROLE_SECTION;
+ role_table[ATK_ROLE_FORM] = ATSPI_ROLE_FORM;
+ role_table[ATK_ROLE_REDUNDANT_OBJECT] = ATSPI_ROLE_REDUNDANT_OBJECT;
+ role_table[ATK_ROLE_LINK] = ATSPI_ROLE_LINK;
+ role_table[ATK_ROLE_INPUT_METHOD_WINDOW] =
+ ATSPI_ROLE_INPUT_METHOD_WINDOW;
+ role_table[ATK_ROLE_TABLE_ROW] = ATSPI_ROLE_TABLE_ROW;
+ role_table[ATK_ROLE_TREE_ITEM] = ATSPI_ROLE_TREE_ITEM;
+ role_table[ATK_ROLE_DOCUMENT_SPREADSHEET] =
+ ATSPI_ROLE_DOCUMENT_SPREADSHEET;
+ role_table[ATK_ROLE_DOCUMENT_PRESENTATION] =
+ ATSPI_ROLE_DOCUMENT_PRESENTATION;
+ role_table[ATK_ROLE_DOCUMENT_TEXT] = ATSPI_ROLE_DOCUMENT_TEXT;
+ role_table[ATK_ROLE_DOCUMENT_WEB] = ATSPI_ROLE_DOCUMENT_WEB;
+ role_table[ATK_ROLE_DOCUMENT_EMAIL] = ATSPI_ROLE_DOCUMENT_EMAIL;
+ role_table[ATK_ROLE_COMMENT] = ATSPI_ROLE_COMMENT;
+ role_table[ATK_ROLE_LIST_BOX] = ATSPI_ROLE_LIST_BOX;
+ role_table[ATK_ROLE_GROUPING] = ATSPI_ROLE_GROUPING;
+ role_table[ATK_ROLE_IMAGE_MAP] = ATSPI_ROLE_IMAGE_MAP;
+ role_table[ATK_ROLE_NOTIFICATION] = ATSPI_ROLE_NOTIFICATION;
+ role_table[ATK_ROLE_INFO_BAR] = ATSPI_ROLE_INFO_BAR;
+ role_table[ATK_ROLE_LEVEL_BAR] = ATSPI_ROLE_LEVEL_BAR;
+ role_table[ATK_ROLE_TITLE_BAR] = ATSPI_ROLE_TITLE_BAR;
+ role_table[ATK_ROLE_BLOCK_QUOTE] = ATSPI_ROLE_BLOCK_QUOTE;
+ role_table[ATK_ROLE_AUDIO] = ATSPI_ROLE_AUDIO;
+ role_table[ATK_ROLE_VIDEO] = ATSPI_ROLE_VIDEO;
+ role_table[ATK_ROLE_DEFINITION] = ATSPI_ROLE_DEFINITION;
+ role_table[ATK_ROLE_ARTICLE] = ATSPI_ROLE_ARTICLE;
+ role_table[ATK_ROLE_LANDMARK] = ATSPI_ROLE_LANDMARK;
+ role_table[ATK_ROLE_LOG] = ATSPI_ROLE_LOG;
+ role_table[ATK_ROLE_MARQUEE] = ATSPI_ROLE_MARQUEE;
+ role_table[ATK_ROLE_MATH] = ATSPI_ROLE_MATH;
+ role_table[ATK_ROLE_RATING] = ATSPI_ROLE_RATING;
+ role_table[ATK_ROLE_TIMER] = ATSPI_ROLE_TIMER;
+
+ return TRUE;
+}
+
+AtspiRole
+spi_accessible_role_from_atk_role (AtkRole role)
+{
+ static gboolean is_initialized = FALSE;
+ static AtspiRole spi_role_table[ATK_ROLE_LAST_DEFINED];
+ AtspiRole spi_role;
+
+ if (!is_initialized)
+ {
+ is_initialized = init_role_lookup_table (spi_role_table);
+ }
+
+ if (role >= 0 && role < ATK_ROLE_LAST_DEFINED)
+ {
+ spi_role = spi_role_table[role];
+ }
+ else
+ {
+ spi_role = ATSPI_ROLE_EXTENDED;
+ }
+ return spi_role;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/atk-adaptor/object.h b/atk-adaptor/object.h
new file mode 100644
index 0000000..5f283bc
--- /dev/null
+++ b/atk-adaptor/object.h
@@ -0,0 +1,63 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008, 2009, 2010 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ACCESSIBLE_OBJECT_H
+#define ACCESSIBLE_OBJECT_H
+
+#include <atk/atk.h>
+#include <dbus/dbus.h>
+
+void
+spi_object_lease_if_needed (GObject *obj);
+
+void
+spi_object_append_reference (DBusMessageIter * iter, AtkObject * obj);
+
+void
+spi_hyperlink_append_reference (DBusMessageIter * iter, AtkObject * obj);
+
+void
+spi_object_append_v_reference (DBusMessageIter * iter, AtkObject * obj);
+
+void
+spi_object_append_desktop_reference (DBusMessageIter * iter);
+
+void
+spi_object_append_null_reference (DBusMessageIter * iter);
+
+DBusMessage *
+spi_object_return_reference (DBusMessage * msg, AtkObject * obj);
+
+DBusMessage *
+spi_hyperlink_return_reference (DBusMessage * msg, AtkHyperlink * obj);
+
+void
+spi_object_append_interfaces (DBusMessageIter * iter, AtkObject * obj);
+
+void
+spi_object_append_attribute_set (DBusMessageIter * iter, AtkAttributeSet * attr);
+
+AtspiRole
+spi_accessible_role_from_atk_role (AtkRole role);
+
+#endif /* ACCESSIBLE_OBJECT_H */
diff --git a/atk-adaptor/spi-dbus.c b/atk-adaptor/spi-dbus.c
new file mode 100644
index 0000000..e757376
--- /dev/null
+++ b/atk-adaptor/spi-dbus.c
@@ -0,0 +1,289 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <dbus/dbus.h>
+
+#include <atspi/atspi.h>
+
+DBusMessage *
+spi_dbus_general_error (DBusMessage * message)
+{
+ return dbus_message_new_error (message,
+ "org.a11y.atspi.GeneralError",
+ "General error");
+}
+
+DBusMessage *
+spi_dbus_return_rect (DBusMessage * message, gint ix, gint iy, gint iwidth,
+ gint iheight)
+{
+ DBusMessage *reply;
+ dbus_uint32_t x, y, width, height;
+
+ x = ix;
+ y = iy;
+ width = iwidth;
+ height = iheight;
+ reply = dbus_message_new_method_return (message);
+ if (reply)
+ {
+ DBusMessageIter iter, sub;
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_STRUCT, NULL, &sub))
+ goto oom;
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &x);
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &y);
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &width);
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &height);
+ if (!dbus_message_iter_close_container (&iter, &sub))
+ goto oom;
+ }
+ return reply;
+oom:
+ /* todo: return an error */
+ return reply;
+}
+
+void spi_dbus_emit_valist(DBusConnection *bus, const char *path, const char *interface, const char *name, int first_arg_type, va_list args)
+{
+ DBusMessage *sig;
+
+ sig = dbus_message_new_signal(path, interface, name);
+ if (first_arg_type != DBUS_TYPE_INVALID)
+ {
+ dbus_message_append_args_valist(sig, first_arg_type, args);
+ }
+ dbus_connection_send(bus, sig, NULL);
+ dbus_message_unref(sig);
+}
+
+dbus_bool_t spi_dbus_message_iter_get_struct(DBusMessageIter *iter, ...)
+{
+ va_list args;
+ DBusMessageIter iter_struct;
+ int type;
+ void *ptr;
+
+ dbus_message_iter_recurse(iter, &iter_struct);
+ va_start(args, iter);
+ for (;;)
+ {
+ type = va_arg(args, int);
+ if (type == DBUS_TYPE_INVALID) break;
+ if (type != dbus_message_iter_get_arg_type(&iter_struct))
+ {
+ va_end(args);
+ return FALSE;
+ }
+ ptr = va_arg(args, void *);
+ dbus_message_iter_get_basic(&iter_struct, ptr);
+ dbus_message_iter_next(&iter_struct);
+ }
+ dbus_message_iter_next(iter);
+ va_end(args);
+ return TRUE;
+}
+
+dbus_bool_t spi_dbus_message_iter_append_struct(DBusMessageIter *iter, ...)
+{
+ va_list args;
+ DBusMessageIter iter_struct;
+ int type;
+ void *ptr;
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &iter_struct)) return FALSE;
+ va_start(args, iter);
+ for (;;)
+ {
+ type = va_arg(args, int);
+ if (type == DBUS_TYPE_INVALID) break;
+ ptr = va_arg(args, void *);
+ dbus_message_iter_append_basic(&iter_struct, type, ptr);
+ }
+ va_end(args);
+ if (!dbus_message_iter_close_container(iter, &iter_struct)) return FALSE;
+ return TRUE;
+}
+
+dbus_bool_t spi_dbus_marshal_deviceEvent(DBusMessage *message, const AtspiDeviceEvent *e)
+{
+ DBusMessageIter iter;
+
+ if (!message) return FALSE;
+ dbus_message_iter_init_append(message, &iter);
+ return spi_dbus_message_iter_append_struct(&iter, DBUS_TYPE_UINT32, &e->type, DBUS_TYPE_INT32, &e->id, DBUS_TYPE_INT16, &e->hw_code, DBUS_TYPE_INT16, &e->modifiers, DBUS_TYPE_INT32, &e->timestamp, DBUS_TYPE_STRING, &e->event_string, DBUS_TYPE_BOOLEAN, &e->is_text, DBUS_TYPE_INVALID);
+}
+
+dbus_bool_t spi_dbus_demarshal_deviceEvent(DBusMessage *message, AtspiDeviceEvent *e)
+{
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(message, &iter);
+ return spi_dbus_message_iter_get_struct(&iter, DBUS_TYPE_UINT32, &e->type, DBUS_TYPE_INT32, &e->id, DBUS_TYPE_INT16, &e->hw_code, DBUS_TYPE_INT16, &e->modifiers, DBUS_TYPE_INT32, &e->timestamp, DBUS_TYPE_STRING, &e->event_string, DBUS_TYPE_BOOLEAN, &e->is_text, DBUS_TYPE_INVALID);
+}
+
+/*
+ * This is a rather annoying function needed to replace
+ * NULL values of strings with the empty string. Null string
+ * values can be created by the atk_object_get_name or text selection
+ */
+static const void *
+provide_defaults(const gint type,
+ const void *val)
+{
+ switch (type)
+ {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ if (!val)
+ return "";
+ else
+ return val;
+ default:
+ return val;
+ }
+}
+
+/*
+ * Appends all the standard parameters to an AT-SPI event.
+ */
+void
+spi_dbus_signal_new (const char *path,
+ const char *klass,
+ const char *major,
+ const char *minor,
+ dbus_int32_t detail1,
+ dbus_int32_t detail2)
+{
+ DBusMessage *sig;
+ DBusMessageIter iter;
+ gchar *cname, *t;
+
+ if (!klass) klass = "";
+ if (!major) major = "";
+ if (!minor) minor = "";
+
+ /*
+ * This is very annoying, but as '-' isn't a legal signal
+ * name in D-Bus (Why not??!?) The names need converting
+ * on this side, and again on the client side.
+ */
+ cname = g_strdup(major);
+ while ((t = strchr(cname, '-')) != NULL) *t = '_';
+
+ sig = dbus_message_new_signal(path, klass, cname);
+ g_free(cname);
+
+ dbus_message_iter_init_append(sig, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
+}
+
+void
+spi_dbus_emit_signal(DBusConnection *bus, const char *path,
+ const char *klass,
+ const char *major,
+ const char *minor,
+ dbus_int32_t detail1,
+ dbus_int32_t detail2,
+ const char *type,
+ const void *val)
+{
+ gchar *cname, *t;
+ DBusMessage *sig;
+ DBusMessageIter iter, sub;
+ if (!klass) klass = "";
+ if (!major) major = "";
+ if (!minor) minor = "";
+ if (!type) type = "u";
+
+ /*
+ * This is very annoying, but as '-' isn't a legal signal
+ * name in D-Bus (Why not??!?) The names need converting
+ * on this side, and again on the client side.
+ */
+ cname = g_strdup(major);
+ while ((t = strchr(cname, '-')) != NULL) *t = '_';
+
+ sig = dbus_message_new_signal(path, klass, cname);
+ g_free(cname);
+
+ dbus_message_iter_init_append(sig, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &minor);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail1);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &detail2);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, type, &sub);
+ /*
+ * I need to convert the string signature to an integer type signature.
+ * DBUS_TYPE_INT32 is defined as 'i' whereas the string is "i".
+ * I should just be able to cast the first character of the string to an
+ * integer.
+ */
+ val = provide_defaults((int) *type, val);
+ dbus_message_iter_append_basic(&sub, (int) *type, &val);
+ dbus_message_iter_close_container(&iter, &sub);
+
+ dbus_connection_send(bus, sig, NULL);
+ dbus_message_unref(sig);
+}
+
+
+/*
+dbus_bool_t spi_dbus_get_simple_property (DBusConnection *bus, const char *dest, const char *path, const char *interface, const char *prop, int *type, void *ptr, DBusError *error)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, iter_variant;
+ int typ;
+
+ dbus_error_init (error);
+ message = dbus_message_new_method_call (dest, path, "org.freedesktop.DBus.Properties", "get");
+ if (!message) return FALSE;
+ if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID))
+ {
+ return FALSE;
+ }
+ reply = dbus_connection_send_with_reply_and_block (bus, message, 1000, error);
+ dbus_message_unref (message);
+ if (!reply) return FALSE;
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_variant);
+ typ = dbus_message_iter_get_arg_type (&iter_variant);
+ if (type) *type = typ;
+ if (typ == DBUS_TYPE_INVALID || typ == DBUS_TYPE_STRUCT || typ == DBUS_TYPE_ARRAY)
+ {
+ return FALSE;
+ }
+ dbus_message_iter_get_basic (&iter_variant, ptr);
+ dbus_message_unref (reply);
+ return TRUE;
+}
+*/
diff --git a/atk-adaptor/spi-dbus.h b/atk-adaptor/spi-dbus.h
new file mode 100644
index 0000000..61a43be
--- /dev/null
+++ b/atk-adaptor/spi-dbus.h
@@ -0,0 +1,56 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SPI_DBUS_H_
+#define SPI_DBUS_H_
+
+#include <glib.h>
+#include <atspi/atspi.h>
+
+#define DBG(a,b) if(_dbg>=(a))b
+
+extern int _dbg;
+
+#define SPI_DBUS_NAME_REGISTRY "org.a11y.atspi.Registry"
+#define SPI_DBUS_PATH_REGISTRY "/org/a11y/atspi/registry"
+#define SPI_DBUS_INTERFACE_REGISTRY "org.a11y.atspi.Registry"
+
+#define SPI_DBUS_PATH_NULL "/org/a11y/atspi/null"
+#define SPI_DBUS_PATH_ROOT "/org/a11y/atspi/accessible/root"
+
+DBusMessage *spi_dbus_general_error(DBusMessage *message);
+DBusMessage *spi_dbus_return_rect(DBusMessage *message, gint ix, gint iy, gint iwidth, gint iheight);
+
+void spi_dbus_emit_valist(DBusConnection *bus, const char *path, const char *interface, const char *name, int first_arg_type, va_list args);
+dbus_bool_t spi_dbus_message_iter_get_struct(DBusMessageIter *iter, ...);
+dbus_bool_t spi_dbus_message_iter_append_struct(DBusMessageIter *iter, ...);
+dbus_bool_t spi_dbus_marshal_deviceEvent(DBusMessage *message, const AtspiDeviceEvent *e);
+dbus_bool_t spi_dbus_demarshal_deviceEvent(DBusMessage *message, AtspiDeviceEvent *e);
+dbus_bool_t spi_dbus_get_simple_property (DBusConnection *bus, const char *dest, const char *path, const char *interface, const char *prop, int *type, void *ptr, DBusError *error);
+void spi_dbus_emit_signal(DBusConnection *bus, const char *path, const char *klass, const char *major, const char *minor, dbus_int32_t detail1, dbus_int32_t detail2, const char *type, const void *val);
+/*
+void spi_dbus_add_disconnect_match (DBusConnection *bus, const char *name);
+void spi_dbus_remove_disconnect_match (DBusConnection *bus, const char *name);
+*/
+
+#endif /* SPI_DBUS_H_ */
diff --git a/atk-bridge-2.0.pc.in b/atk-bridge-2.0.pc.in
new file mode 100644
index 0000000..6af5861
--- /dev/null
+++ b/atk-bridge-2.0.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: atk-bridge-2.0
+Description: ATK/D-Bus Bridge
+Version: @VERSION@
+Requires.Private: gobject-2.0 atspi-2
+Libs: -L${libdir} -latk-bridge-2.0
+Cflags: -I${includedir}/at-spi2-atk/2.0
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..78dabeb
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+
+olddir=`pwd`
+cd "$srcdir"
+
+# gnome-autogen.sh runs configure, so do likewise.
+autoreconf -vif
+
+cd "$olddir"
+
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..d7f5c73
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,103 @@
+AC_INIT([at-spi2-atk], [2.12.0], [accessibility-atspi@lists.linux-foundation.org])
+AC_CONFIG_AUX_DIR(config)
+
+AT_SPI_ATK_MAJOR_VERSION=0
+AT_SPI_ATK_MINOR_VERSION=3
+AT_SPI_ATK_INTERFACE_AGE=0
+AT_SPI_ATK_BINARY_AGE=0
+AT_SPI_ATK_VERSION="$AT_SPI_MAJOR_VERSION.$AT_SPI_MINOR_VERSION"
+AC_SUBST(AT_SPI_ATK_VERSION)
+
+# libtool versioning
+LT_RELEASE=$AT_SPI_MAJOR_VERSION.$AT_SPI_MINOR_VERSION
+LT_CURRENT=0
+LT_REVISION=0
+LT_AGE=0
+LT_VERSION_INFO='-version-info ${LT_CURRENT}:${LT_REVISION}:${LT_AGE}'
+AC_SUBST(LT_VERSION_INFO)
+AC_SUBST(LT_RELEASE)
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+
+AM_INIT_AUTOMAKE([-Wall foreign no-dist-gzip dist-xz])
+
+# Enable silent build when available (Automake 1.11)
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
+AC_PROG_CC
+AM_DISABLE_STATIC
+AM_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG
+
+GETTEXT_PACKAGE="${PACKAGE}"
+AC_SUBST(GETTEXT_PACKAGE)
+
+AC_CONFIG_HEADERS([config.h])
+
+PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.5])
+AC_SUBST(DBUS_LIBS)
+AC_SUBST(DBUS_CFLAGS)
+
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.32.0])
+AC_SUBST(GLIB_LIBS)
+AC_SUBST(GLIB_CFLAGS)
+
+PKG_CHECK_MODULES(GOBJ, [gobject-2.0 >= 2.0.0])
+AC_SUBST(GOBJ_LIBS)
+AC_SUBST(GOBJ_CFLAGS)
+
+PKG_CHECK_MODULES(GMODULE, [gmodule-2.0 >= 2.0.0])
+AC_SUBST(GMODULE_LIBS)
+AC_SUBST(GMODULE_CFLAGS)
+
+PKG_CHECK_MODULES(ATK, [atk >= 2.11.90])
+AC_SUBST(ATK_LIBS)
+AC_SUBST(ATK_CFLAGS)
+
+PKG_CHECK_MODULES(ATSPI, [atspi-2 >= 2.11.2])
+AC_SUBST(ATSPI_LIBS)
+AC_SUBST(ATSPI_CFLAGS)
+
+GLIB_GSETTINGS
+
+AC_ARG_ENABLE(p2p, [ --enable-p2p Allow peer-to-peer DBus connections [default=yes]], enable_p2p="$enableval", enable_p2p=yes)
+
+#libtool option to strip symbols starting with cspi
+LIBTOOL_EXPORT_OPTIONS='-export-symbols-regex "^[[^cspi]].*"'
+AC_SUBST(LIBTOOL_EXPORT_OPTIONS)
+
+# Extra libraries for sockets added by Willie Walker
+# based upon how SunStudio libraries work.
+#
+if test "$GCC" = yes; then
+ EXTRA_SOCKET_LIBS=""
+else
+ EXTRA_SOCKET_LIBS="-lsocket -lnsl"
+fi
+AC_SUBST(EXTRA_SOCKET_LIBS)
+
+dnl find sizes & alignments
+orig_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS"
+CPPFLAGS=$orig_CPPFLAGS
+
+if test "x$GCC" = xyes; then
+ CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
+fi
+
+if test "x$enable_p2p" = "xno"; then
+ P2P_CFLAGS=-DDISABLE_P2P
+fi
+
+AC_SUBST(P2P_CFLAGS)
+
+AC_CONFIG_FILES([Makefile
+ atk-bridge-2.0.pc
+ droute/Makefile
+ atk-adaptor/Makefile
+ atk-adaptor/adaptors/Makefile
+ atk-adaptor/gtk-2.0/Makefile
+ ])
+
+AC_OUTPUT
diff --git a/droute/Makefile.am b/droute/Makefile.am
new file mode 100644
index 0000000..f214d19
--- /dev/null
+++ b/droute/Makefile.am
@@ -0,0 +1,30 @@
+noinst_LTLIBRARIES = libdroute.la
+
+libdroute_la_CFLAGS = $(DBUS_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ -I$(top_builddir)\
+ -I$(top_srcdir)
+
+libdroute_la_SOURCES =\
+ droute.c\
+ droute.h\
+ droute-variant.c\
+ droute-variant.h\
+ droute-pairhash.c\
+ droute-pairhash.h
+libdroute_la_LIBADD = $(DBUS_LIBS)
+
+TESTS = droute-test
+
+check_PROGRAMS = droute-test
+droute_test_SOURCES = droute-test.c
+droute_test_CFLAGS = $(DBUS_CFLAGS) \
+ -I$(top_builddir)\
+ $(GLIB_CFLAGS) \
+ $(ATSPI_CFLAGS) \
+ -I$(top_srcdir)
+
+droute_test_LDFLAGS = libdroute.la\
+ $(DBUS_LIBS) \
+ $(GLIB_LIBS) \
+ $(ATSPI_LIBS)
diff --git a/droute/droute-pairhash.c b/droute/droute-pairhash.c
new file mode 100644
index 0000000..c2f2c29
--- /dev/null
+++ b/droute/droute-pairhash.c
@@ -0,0 +1,87 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "droute-pairhash.h"
+
+/*---------------------------------------------------------------------------*/
+
+static guint
+str_hash (guint32 h, const char *p)
+{
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+/*---------------------------------------------------------------------------*/
+
+StrPair *
+str_pair_new (const gchar *one, const gchar *two)
+{
+ StrPair *pair;
+
+ pair = g_new (StrPair, 1);
+ pair->one = one;
+ pair->two = two;
+ return pair;
+}
+
+guint
+str_pair_hash (gconstpointer key)
+{
+ StrPair *pair = (StrPair *) key;
+ guint hash = 0;
+
+ /*g_return_val_if_fail (pair != NULL, 0);
+ g_return_val_if_fail (pair->one != NULL, 0);
+ g_return_val_if_fail (pair->two != NULL, 0);
+ */
+
+ if (*(pair->two) != '\0')
+ {
+ hash = *(pair->two);
+ hash = str_hash (hash, pair->two);
+ hash = str_hash (hash, pair->one);
+ }
+
+ return hash;
+}
+
+gboolean
+str_pair_equal (gconstpointer a, gconstpointer b)
+{
+ StrPair *ap = (StrPair *) a;
+ StrPair *bp = (StrPair *) b;
+
+ if (g_str_equal (ap->one, bp->one) &&
+ g_str_equal (ap->two, bp->two))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/droute/droute-pairhash.h b/droute/droute-pairhash.h
new file mode 100644
index 0000000..1491c2d
--- /dev/null
+++ b/droute/droute-pairhash.h
@@ -0,0 +1,41 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_PAIRHASH_H
+#define _DROUTE_PAIRHASH_H
+
+#include <glib.h>
+
+typedef struct _StrPair StrPair;
+struct _StrPair
+{
+ const gchar *one;
+ const gchar *two;
+};
+
+StrPair *str_pair_new (const gchar *one,
+ const gchar *two);
+
+guint str_pair_hash (gconstpointer key);
+gboolean str_pair_equal (gconstpointer a,
+ gconstpointer b);
+
+#endif /* _DROUTE_PAIRHASH_H */
diff --git a/droute/droute-test.c b/droute/droute-test.c
new file mode 100644
index 0000000..1865622
--- /dev/null
+++ b/droute/droute-test.c
@@ -0,0 +1,308 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+#include <droute/droute.h>
+
+#include "atspi/atspi.h"
+
+#define TEST_OBJECT_PATH "/test/object"
+#define TEST_INTERFACE_ONE "test.interface.One"
+#define TEST_INTERFACE_TWO "test.interface.Two"
+
+#define OBJECT_ONE "ObjectOne";
+#define OBJECT_TWO "ObjectTwo";
+
+#define STRING_ONE "StringOne"
+#define STRING_TWO "StringTwo"
+
+#define INT_ONE 0
+#define INT_TWO 456
+
+#define NONE_REPLY_STRING "NoneMethod"
+
+const gchar *test_interface_One = \
+"<interface name=\"test.interface.One\">"
+" <method name=\"null\"/>"
+" <method name=\"getInt\">"
+" <arg direction=\"out\" type=\"o\"/>"
+" </method>"
+" <method name=\"setInt\">"
+" <arg direction=\"in\" type=\"o\"/>"
+" </method>"
+" <method name=\"getString\">"
+" <arg direction=\"out\" type=\"s\"/>"
+" </method>"
+" <method name=\"setString\">"
+" <arg direction=\"in\" type=\"s\"/>"
+" </method>"
+"</interface>";
+
+const gchar *test_interface_Two = \
+"<interface name=\"test.interface.One\">"
+" <method name=\"null\"/>"
+" <method name=\"getInt\">"
+" <arg direction=\"out\" type=\"o\"/>"
+" </method>"
+" <method name=\"setInt\">"
+" <arg direction=\"in\" type=\"o\"/>"
+" </method>"
+" <method name=\"getString\">"
+" <arg direction=\"out\" type=\"s\"/>"
+" </method>"
+" <method name=\"setString\">"
+" <arg direction=\"in\" type=\"s\"/>"
+" </method>"
+"</interface>";
+
+typedef struct _AnObject
+{
+ gchar *astring;
+ guint *anint;
+} AnObject;
+
+static DBusConnection *bus;
+static GMainLoop *main_loop;
+static gboolean success = TRUE;
+
+static DBusMessage *
+impl_null (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static DBusMessage *
+impl_getInt (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_INT32, &(object->anint), DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_setInt (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &(object->anint), DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static DBusMessage *
+impl_getString (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &(object->astring), DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_setString (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ AnObject *object = (AnObject *) user_data;
+ DBusMessage *reply;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ g_free (object->astring);
+ dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &(object->astring), DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return (message);
+ return reply;
+}
+
+static DBusMessage *
+impl_getInterfaceOne (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error;
+ gchar *itf = TEST_INTERFACE_ONE;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &itf, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_getInterfaceTwo (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error;
+ gchar *itf = TEST_INTERFACE_TWO;
+
+ dbus_error_init (&error);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &itf, DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DRouteMethod test_methods_one[] = {
+ {impl_null, "null"},
+ {impl_getInt, "getInt"},
+ {impl_setInt, "setInt"},
+ {impl_getString, "getString"},
+ {impl_setString, "setString"},
+ {impl_getInterfaceOne, "getInterfaceOne"},
+ {NULL, NULL}
+};
+
+static DRouteMethod test_methods_two[] = {
+ {impl_null, "null"},
+ {impl_getInt, "getInt"},
+ {impl_setInt, "setInt"},
+ {impl_getString, "getString"},
+ {impl_setString, "setString"},
+ {impl_getInterfaceTwo, "getInterfaceTwo"},
+ {NULL, NULL}
+};
+
+static DRouteProperty test_properties[] = {
+ {NULL, NULL, NULL}
+};
+
+static void
+set_reply (DBusPendingCall *pending, void *user_data)
+{
+ void **replyptr = (void **)user_data;
+
+ *replyptr = dbus_pending_call_steal_reply (pending);
+}
+
+static DBusMessage *
+send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, DBusError *error)
+{
+ DBusPendingCall *pending;
+ DBusMessage *reply = NULL;
+
+ if (!dbus_connection_send_with_reply (bus, message, &pending, -1))
+ {
+ return NULL;
+ }
+ dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL);
+ while (!reply)
+ {
+ if (!dbus_connection_read_write_dispatch (bus, -1))
+ return NULL;
+ }
+ return reply;
+}
+
+gboolean
+do_tests_func (gpointer data)
+{
+ DBusError error;
+ const gchar *bus_name;
+ DBusMessage *message, *reply;
+
+ gchar *expected_string;
+ gchar *result_string;
+
+ dbus_error_init (&error);
+ bus_name = dbus_bus_get_unique_name (bus);
+
+ /* --------------------------------------------------------*/
+
+ message = dbus_message_new_method_call (bus_name,
+ TEST_OBJECT_PATH,
+ TEST_INTERFACE_ONE,
+ "null");
+ reply = send_and_allow_reentry (bus, message, NULL);
+ dbus_message_unref (message);
+ if (reply)
+ dbus_message_unref (reply);
+
+ /* --------------------------------------------------------*/
+
+ expected_string = TEST_INTERFACE_ONE;
+ result_string = NULL;
+ message = dbus_message_new_method_call (bus_name,
+ TEST_OBJECT_PATH,
+ TEST_INTERFACE_ONE,
+ "getInterfaceOne");
+ reply = send_and_allow_reentry (bus, message, NULL);
+ dbus_message_unref (message);
+ dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &result_string,
+ DBUS_TYPE_INVALID);
+ dbus_message_unref (reply);
+ if (g_strcmp0(expected_string, result_string))
+ {
+ g_print ("Failed: reply to getInterfaceOne was %s; expected %s\n",
+ result_string, expected_string);
+ exit (1);
+ }
+
+ /* --------------------------------------------------------*/
+
+out:
+ g_main_loop_quit (main_loop);
+ return FALSE;
+}
+
+
+int main (int argc, char **argv)
+{
+ DRouteContext *cnx;
+ DRoutePath *path;
+ AnObject *object;
+ DBusError error;
+
+ /* Setup some server object */
+
+ object = g_new0(AnObject, 1);
+ object->astring = g_strdup (STRING_ONE);
+ object->anint = INT_ONE;
+
+ dbus_error_init (&error);
+ main_loop = g_main_loop_new(NULL, FALSE);
+ bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ atspi_dbus_connection_setup_with_g_main(bus, g_main_context_default());
+
+ cnx = droute_new ();
+ path = droute_add_one (cnx, TEST_OBJECT_PATH, object);
+
+ droute_path_add_interface (path,
+ TEST_INTERFACE_ONE,
+ test_interface_One,
+ test_methods_one,
+ test_properties);
+
+ droute_path_add_interface (path,
+ TEST_INTERFACE_TWO,
+ test_interface_Two,
+ test_methods_two,
+ test_properties);
+
+ droute_path_register (path, bus);
+
+ g_idle_add (do_tests_func, NULL);
+ g_main_loop_run(main_loop);
+ if (success)
+ return 0;
+ else
+ return 1;
+}
diff --git a/droute/droute-variant.c b/droute/droute-variant.c
new file mode 100644
index 0000000..bd5ef36
--- /dev/null
+++ b/droute/droute-variant.c
@@ -0,0 +1,125 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "glib.h"
+
+#include "droute-variant.h"
+
+/*---------------------------------------------------------------------------*/
+
+dbus_bool_t
+droute_return_v_int32 (DBusMessageIter *iter, dbus_int32_t val)
+{
+ DBusMessageIter sub;
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &val);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_double (DBusMessageIter *iter, double val)
+{
+ DBusMessageIter sub;
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_DOUBLE, &val);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_string (DBusMessageIter *iter, const char *val)
+{
+ DBusMessageIter sub;
+
+ if (!val)
+ val = "";
+ if (!g_utf8_validate (val, -1, NULL))
+ {
+ g_warning ("droute: Received bad UTF-8 string");
+ val = "";
+ }
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &val);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+dbus_bool_t
+droute_return_v_object (DBusMessageIter *iter, const char *path)
+{
+ DBusMessageIter sub;
+
+ if (!dbus_message_iter_open_container
+ (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub))
+ {
+ return FALSE;
+ }
+ dbus_message_iter_append_basic (&sub, DBUS_TYPE_OBJECT_PATH, &path);
+ dbus_message_iter_close_container (iter, &sub);
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+dbus_int32_t
+droute_get_v_int32 (DBusMessageIter *iter)
+{
+ DBusMessageIter sub;
+ dbus_int32_t rv;
+
+ // TODO- ensure we have the correct type
+ dbus_message_iter_recurse (iter, &sub);
+ dbus_message_iter_get_basic (&sub, &rv);
+ return rv;
+}
+
+const char *
+droute_get_v_string (DBusMessageIter *iter)
+{
+ DBusMessageIter sub;
+ char *rv;
+
+ // TODO- ensure we have the correct type
+ dbus_message_iter_recurse (iter, &sub);
+ dbus_message_iter_get_basic (&sub, &rv);
+ return rv;
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/droute/droute-variant.h b/droute/droute-variant.h
new file mode 100644
index 0000000..47feb96
--- /dev/null
+++ b/droute/droute-variant.h
@@ -0,0 +1,35 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_VARIANT_H
+#define _DROUTE_VARIANT_H
+
+#include <dbus/dbus.h>
+
+dbus_bool_t droute_return_v_int32 (DBusMessageIter *iter, dbus_int32_t val);
+dbus_bool_t droute_return_v_double (DBusMessageIter *iter, double val);
+dbus_bool_t droute_return_v_string (DBusMessageIter *iter, const char *val);
+dbus_bool_t droute_return_v_object (DBusMessageIter *iter, const char *path);
+
+dbus_int32_t droute_get_v_int32 (DBusMessageIter *iter);
+const char *droute_get_v_string (DBusMessageIter *iter);
+
+#endif /* _DROUTE_VARIANT_H */
diff --git a/droute/droute.c b/droute/droute.c
new file mode 100644
index 0000000..838aacd
--- /dev/null
+++ b/droute/droute.c
@@ -0,0 +1,742 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "droute.h"
+#include "droute-pairhash.h"
+
+#define CHUNKS_DEFAULT (512)
+
+#define oom() g_error ("D-Bus out of memory, this message will fail anyway")
+
+#if defined DROUTE_DEBUG
+ #define _DROUTE_DEBUG(format, args...) g_print (format , ## args)
+#else
+ #define _DROUTE_DEBUG(format, args...)
+#endif
+
+struct _DRouteContext
+{
+ GPtrArray *registered_paths;
+
+ gchar *introspect_string;
+};
+
+struct _DRoutePath
+{
+ DRouteContext *cnx;
+ gchar *path;
+ gboolean prefix;
+ GStringChunk *chunks;
+ GPtrArray *interfaces;
+ GPtrArray *introspection;
+ GHashTable *methods;
+ GHashTable *properties;
+
+ DRouteIntrospectChildrenFunction introspect_children_cb;
+ void *introspect_children_data;
+ void *user_data;
+ DRouteGetDatumFunction get_datum;
+};
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct PropertyPair
+{
+ DRoutePropertyFunction get;
+ DRoutePropertyFunction set;
+} PropertyPair;
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+handle_message (DBusConnection *bus, DBusMessage *message, void *user_data);
+
+static DBusMessage *
+droute_object_does_not_exist_error (DBusMessage *message);
+
+/*---------------------------------------------------------------------------*/
+
+static DRoutePath *
+path_new (DRouteContext *cnx,
+ const char *path,
+ gboolean prefix,
+ void *user_data,
+ DRouteIntrospectChildrenFunction introspect_children_cb,
+ void *introspect_children_data,
+ DRouteGetDatumFunction get_datum)
+{
+ DRoutePath *new_path;
+
+ new_path = g_new0 (DRoutePath, 1);
+ new_path->cnx = cnx;
+ new_path->path = g_strdup (path);
+ new_path->prefix = prefix;
+ new_path->chunks = g_string_chunk_new (CHUNKS_DEFAULT);
+ new_path->interfaces = g_ptr_array_new ();
+ new_path->introspection = g_ptr_array_new ();
+
+ new_path->methods = g_hash_table_new_full ((GHashFunc)str_pair_hash,
+ str_pair_equal,
+ g_free,
+ NULL);
+
+ new_path->properties = g_hash_table_new_full ((GHashFunc)str_pair_hash,
+ str_pair_equal,
+ g_free,
+ g_free);
+
+ new_path->introspect_children_cb = introspect_children_cb;
+ new_path->introspect_children_data = introspect_children_data;
+ new_path->user_data = user_data;
+ new_path->get_datum = get_datum;
+
+ return new_path;
+}
+
+static void
+path_free (DRoutePath *path, gpointer user_data)
+{
+ g_free (path->path);
+ g_string_chunk_free (path->chunks);
+ g_ptr_array_free (path->interfaces, TRUE);
+ g_free(g_ptr_array_free (path->introspection, FALSE));
+ g_hash_table_destroy (path->methods);
+ g_hash_table_destroy (path->properties);
+ g_free (path);
+}
+
+static void *
+path_get_datum (DRoutePath *path, const gchar *pathstr)
+{
+ if (path->get_datum != NULL)
+ return (path->get_datum) (pathstr, path->user_data);
+ else
+ return path->user_data;
+}
+
+/*---------------------------------------------------------------------------*/
+
+DRouteContext *
+droute_new ()
+{
+ DRouteContext *cnx;
+
+ cnx = g_new0 (DRouteContext, 1);
+ cnx->registered_paths = g_ptr_array_new ();
+
+ return cnx;
+}
+
+void
+droute_free (DRouteContext *cnx)
+{
+ g_ptr_array_foreach (cnx->registered_paths, (GFunc) path_free, NULL);
+ g_ptr_array_free (cnx->registered_paths, TRUE);
+ g_free (cnx);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+
+static DBusObjectPathVTable droute_vtable =
+{
+ NULL,
+ &handle_message,
+ NULL, NULL, NULL, NULL
+};
+
+DRoutePath *
+droute_add_one (DRouteContext *cnx,
+ const char *path,
+ const void *data)
+{
+ DRoutePath *new_path;
+
+ new_path = path_new (cnx, path, FALSE, (void *)data, NULL, NULL, NULL);
+
+ g_ptr_array_add (cnx->registered_paths, new_path);
+ return new_path;
+}
+
+DRoutePath *
+droute_add_many (DRouteContext *cnx,
+ const char *path,
+ const void *data,
+ DRouteIntrospectChildrenFunction introspect_children_cb,
+ void *introspect_children_data,
+ const DRouteGetDatumFunction get_datum)
+{
+ DRoutePath *new_path;
+
+ new_path = path_new (cnx, path, TRUE, (void *) data,
+ introspect_children_cb, introspect_children_data,
+ get_datum);
+
+ g_ptr_array_add (cnx->registered_paths, new_path);
+ return new_path;
+}
+
+/*---------------------------------------------------------------------------*/
+
+void
+droute_path_add_interface(DRoutePath *path,
+ const char *name,
+ const char *introspect,
+ const DRouteMethod *methods,
+ const DRouteProperty *properties)
+{
+ gchar *itf;
+
+ g_return_if_fail (name != NULL);
+
+ itf = g_string_chunk_insert (path->chunks, name);
+ g_ptr_array_add (path->interfaces, itf);
+ g_ptr_array_add (path->introspection, (gpointer) introspect);
+
+ for (; methods != NULL && methods->name != NULL; methods++)
+ {
+ gchar *meth;
+
+ meth = g_string_chunk_insert (path->chunks, methods->name);
+ g_hash_table_insert (path->methods, str_pair_new (itf, meth), methods->func);
+ }
+
+ for (; properties != NULL && properties->name != NULL; properties++)
+ {
+ gchar *prop;
+ PropertyPair *pair;
+
+ prop = g_string_chunk_insert (path->chunks, properties->name);
+ pair = g_new (PropertyPair, 1);
+ pair->get = properties->get;
+ pair->set = properties->set;
+ g_hash_table_insert (path->properties, str_pair_new (itf, prop), pair);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* The data structures don't support an efficient implementation of GetAll
+ * and I don't really care.
+ */
+static DBusMessage *
+impl_prop_GetAll (DBusMessage *message,
+ DRoutePath *path,
+ const char *pathstr)
+{
+ DBusMessageIter iter, iter_dict, iter_dict_entry;
+ DBusMessage *reply;
+ DBusError error;
+ GHashTableIter prop_iter;
+
+ StrPair *key;
+ PropertyPair *value;
+ gchar *iface;
+
+ void *datum = path_get_datum (path, pathstr);
+ if (!datum)
+ return droute_object_does_not_exist_error (message);
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args
+ (message, &error, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID))
+ {
+ DBusMessage *ret;
+ ret = dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message);
+ dbus_error_free (&error);
+ return ret;
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ oom ();
+
+ dbus_message_iter_init_append (reply, &iter);
+ if (!dbus_message_iter_open_container
+ (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict))
+ oom ();
+
+ g_hash_table_iter_init (&prop_iter, path->properties);
+ while (g_hash_table_iter_next (&prop_iter, (gpointer*)&key, (gpointer*)&value))
+ {
+ if (!g_strcmp0 (key->one, iface))
+ {
+ if (!value->get)
+ continue;
+ if (!dbus_message_iter_open_container
+ (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry))
+ oom ();
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING,
+ &key->two);
+ (value->get) (&iter_dict_entry, datum);
+ if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry))
+ oom ();
+ }
+ }
+
+ if (!dbus_message_iter_close_container (&iter, &iter_dict))
+ oom ();
+ return reply;
+}
+
+static DBusMessage *
+impl_prop_GetSet (DBusMessage *message,
+ DRoutePath *path,
+ const char *pathstr,
+ gboolean get)
+{
+ DBusMessage *reply = NULL;
+ DBusError error;
+
+ StrPair pair;
+ PropertyPair *prop_funcs = NULL;
+
+ void *datum;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING,
+ &(pair.one),
+ DBUS_TYPE_STRING,
+ &(pair.two),
+ DBUS_TYPE_INVALID))
+ {
+ DBusMessage *ret;
+ ret = dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message);
+ dbus_error_free (&error);
+ }
+
+ _DROUTE_DEBUG ("DRoute (handle prop): %s|%s on %s\n", pair.one, pair.two, pathstr);
+
+ prop_funcs = (PropertyPair *) g_hash_table_lookup (path->properties, &pair);
+ if (!prop_funcs)
+ {
+ DBusMessage *ret;
+#ifdef DBUS_ERROR_UNKNOWN_PROPERTY
+ ret = dbus_message_new_error (message, DBUS_ERROR_UNKNOWN_PROPERTY, "Property unavailable");
+#else
+ ret = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable");
+#endif
+ dbus_error_free (&error);
+ return ret;
+ }
+
+ datum = path_get_datum (path, pathstr);
+ if (!datum)
+ return droute_object_does_not_exist_error (message);
+
+ if (get && prop_funcs->get)
+ {
+
+ DBusMessageIter iter;
+
+ _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr);
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ if (!(prop_funcs->get) (&iter, datum))
+ {
+ dbus_message_unref (reply);
+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Get failed");
+ }
+ }
+ else if (!get && prop_funcs->set)
+ {
+ DBusMessageIter iter;
+
+ _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr);
+
+ dbus_message_iter_init (message, &iter);
+ /* Skip the interface and property name */
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_next(&iter);
+ (prop_funcs->set) (&iter, datum);
+
+ reply = dbus_message_new_method_return (message);
+ }
+#ifdef DBUS_ERROR_PROPERTY_READ_ONLY
+ else if (!get)
+ {
+ reply = dbus_message_new_error (message, DBUS_ERROR_PROPERTY_READ_ONLY, "Property is read-only");
+ }
+#endif
+ else
+ {
+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Getter or setter unavailable");
+ }
+
+ return reply;
+}
+
+static DBusHandlerResult
+handle_dbus (DBusConnection *bus,
+ DBusMessage *message,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ static int id = 1;
+ char *id_str = (char *) g_malloc(40);
+ DBusMessage *reply;
+
+ if (strcmp (iface, DBUS_INTERFACE_DBUS) != 0 ||
+ strcmp (member, "Hello") != 0)
+ {
+ g_free (id_str);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ /* TODO: Fix this hack (we don't handle wrap-around, for instance) */
+ sprintf (id_str, ":1.%d", id++);
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &id_str, DBUS_TYPE_INVALID);
+ dbus_connection_send (bus, reply, NULL);
+ dbus_connection_flush (bus);
+ dbus_message_unref (reply);
+ g_free (id_str);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+handle_properties (DBusConnection *bus,
+ DBusMessage *message,
+ DRoutePath *path,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ DBusMessage *reply = NULL;
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
+
+ if (!g_strcmp0(member, "GetAll"))
+ reply = impl_prop_GetAll (message, path, pathstr);
+ else if (!g_strcmp0 (member, "Get"))
+ reply = impl_prop_GetSet (message, path, pathstr, TRUE);
+ else if (!g_strcmp0 (member, "Set"))
+ reply = impl_prop_GetSet (message, path, pathstr, FALSE);
+ else
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (reply)
+ {
+ dbus_connection_send (bus, reply, NULL);
+ dbus_message_unref (reply);
+ }
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static const char *introspection_header =
+"<?xml version=\"1.0\"?>\n";
+
+static const char *introspection_node_element =
+"<node name=\"%s\">\n";
+
+static const char *introspection_footer =
+"</node>";
+
+static DBusHandlerResult
+handle_introspection (DBusConnection *bus,
+ DBusMessage *message,
+ DRoutePath *path,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ GString *output;
+ gchar *final;
+ gint i;
+
+ DBusMessage *reply;
+
+ _DROUTE_DEBUG ("DRoute (handle introspection): %s\n", pathstr);
+
+ if (g_strcmp0 (member, "Introspect"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ output = g_string_new(introspection_header);
+
+ g_string_append_printf(output, introspection_node_element, pathstr);
+
+ if (!path->get_datum || path_get_datum (path, pathstr))
+ {
+ for (i=0; i < path->introspection->len; i++)
+ {
+ gchar *introspect = (gchar *) g_ptr_array_index (path->introspection, i);
+ g_string_append (output, introspect);
+ }
+ }
+
+ if (path->introspect_children_cb)
+ {
+ gchar *children = (*path->introspect_children_cb) (pathstr, path->introspect_children_data);
+ if (children)
+ {
+ g_string_append (output, children);
+ g_free (children);
+ }
+ }
+
+ g_string_append(output, introspection_footer);
+ final = g_string_free(output, FALSE);
+
+ reply = dbus_message_new_method_return (message);
+ if (!reply)
+ oom ();
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &final,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send (bus, reply, NULL);
+
+ dbus_message_unref (reply);
+ g_free(final);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+handle_other (DBusConnection *bus,
+ DBusMessage *message,
+ DRoutePath *path,
+ const gchar *iface,
+ const gchar *member,
+ const gchar *pathstr)
+{
+ gint result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ StrPair pair;
+ DRouteFunction func;
+ DBusMessage *reply = NULL;
+
+ void *datum;
+
+ pair.one = iface;
+ pair.two = member;
+
+ _DROUTE_DEBUG ("DRoute (handle other): %s|%s on %s\n", member, iface, pathstr);
+
+ func = (DRouteFunction) g_hash_table_lookup (path->methods, &pair);
+ if (func != NULL)
+ {
+ datum = path_get_datum (path, pathstr);
+ if (!datum)
+ reply = droute_object_does_not_exist_error (message);
+ else
+ reply = (func) (bus, message, datum);
+
+ /* All D-Bus method calls must have a reply.
+ * If one is not provided presume that the caller has already
+ * sent one.
+ */
+ if (reply)
+ {
+ dbus_connection_send (bus, reply, NULL);
+ dbus_message_unref (reply);
+ }
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ _DROUTE_DEBUG ("DRoute (handle other) (reply): type %d\n",
+ dbus_message_get_type(reply));
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusHandlerResult
+handle_message (DBusConnection *bus, DBusMessage *message, void *user_data)
+{
+ DRoutePath *path = (DRoutePath *) user_data;
+ const gchar *iface = dbus_message_get_interface (message);
+ const gchar *member = dbus_message_get_member (message);
+ const gint type = dbus_message_get_type (message);
+ const gchar *pathstr = dbus_message_get_path (message);
+
+ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ _DROUTE_DEBUG ("DRoute (handle message): %s|%s of type %d on %s\n", member, iface, type, pathstr);
+
+ /* Check for basic reasons not to handle */
+ if (type != DBUS_MESSAGE_TYPE_METHOD_CALL ||
+ member == NULL ||
+ iface == NULL)
+ return result;
+
+ if (!strcmp (pathstr, DBUS_PATH_DBUS))
+ result = handle_dbus (bus, message, iface, member, pathstr);
+ else if (!strcmp (iface, "org.freedesktop.DBus.Properties"))
+ result = handle_properties (bus, message, path, iface, member, pathstr);
+ else if (!strcmp (iface, "org.freedesktop.DBus.Introspectable"))
+ result = handle_introspection (bus, message, path, iface, member, pathstr);
+ else
+ result = handle_other (bus, message, path, iface, member, pathstr);
+#if 0
+ if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
+ g_print ("DRoute | Unhandled message: %s|%s of type %d on %s\n", member, iface, type, pathstr);
+#endif
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static DBusMessage *
+droute_object_does_not_exist_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" could not be processed as object %s does not exist\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_path (message));
+#ifdef DBUS_ERROR_UNKNOWN_OBJECT
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_UNKNOWN_OBJECT,
+ errmsg);
+#else
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_FAILED,
+ errmsg);
+#endif
+ g_free (errmsg);
+ return reply;
+}
+
+/*---------------------------------------------------------------------------*/
+
+DBusMessage *
+droute_not_yet_handled_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message));
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_UNKNOWN_METHOD,
+ errmsg);
+ g_free (errmsg);
+ return reply;
+}
+
+DBusMessage *
+droute_out_of_memory_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" could not be processed due to lack of memory\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message));
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_NO_MEMORY,
+ errmsg);
+ g_free (errmsg);
+ return reply;
+}
+
+DBusMessage *
+droute_invalid_arguments_error (DBusMessage *message)
+{
+ DBusMessage *reply;
+ gchar *errmsg;
+
+ errmsg= g_strdup_printf (
+ "Method \"%s\" with signature \"%s\" on interface \"%s\" was supplied with invalid arguments\n",
+ dbus_message_get_member (message),
+ dbus_message_get_signature (message),
+ dbus_message_get_interface (message));
+ reply = dbus_message_new_error (message,
+ DBUS_ERROR_INVALID_ARGS,
+ errmsg);
+ g_free (errmsg);
+ return reply;
+}
+
+void
+droute_path_register (DRoutePath *path, DBusConnection *bus)
+{
+ if (path->prefix)
+ dbus_connection_register_fallback (bus, path->path, &droute_vtable, path);
+ else
+ dbus_connection_register_object_path (bus, path->path,
+ &droute_vtable, path);
+}
+
+void
+droute_path_unregister (DRoutePath *path, DBusConnection *bus)
+{
+ dbus_connection_unregister_object_path (bus, path->path);
+}
+
+void
+droute_context_register (DRouteContext *cnx, DBusConnection *bus)
+{
+ g_ptr_array_foreach (cnx->registered_paths, (GFunc) droute_path_register,
+ bus);
+}
+
+void
+droute_context_unregister (DRouteContext *cnx, DBusConnection *bus)
+{
+ g_ptr_array_foreach (cnx->registered_paths, (GFunc) droute_path_unregister,
+ bus);
+}
+
+void
+droute_context_deregister (DRouteContext *cnx, DBusConnection *bus)
+{
+ g_ptr_array_foreach (cnx->registered_paths, (GFunc) droute_path_unregister,
+ bus);
+}
+
+void
+droute_intercept_dbus (DBusConnection *bus)
+{
+ dbus_connection_register_object_path (bus, DBUS_PATH_DBUS,
+ &droute_vtable, NULL);
+}
+
+void
+droute_unintercept_dbus (DBusConnection *bus)
+{
+ dbus_connection_unregister_object_path (bus, DBUS_PATH_DBUS);
+}
+
+/*END------------------------------------------------------------------------*/
diff --git a/droute/droute.h b/droute/droute.h
new file mode 100644
index 0000000..b19dec6
--- /dev/null
+++ b/droute/droute.h
@@ -0,0 +1,113 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2008 Novell, Inc.
+ * Copyright 2008 Codethink Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef _DROUTE_H
+#define _DROUTE_H
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+#include <droute/droute-variant.h>
+
+
+typedef DBusMessage *(*DRouteFunction) (DBusConnection *, DBusMessage *, void *);
+typedef dbus_bool_t (*DRoutePropertyFunction) (DBusMessageIter *, void *);
+typedef gchar *(*DRouteIntrospectChildrenFunction) (const char *, void *);
+
+typedef void *(*DRouteGetDatumFunction) (const char *, void *);
+
+typedef struct _DRouteMethod DRouteMethod;
+struct _DRouteMethod
+{
+ DRouteFunction func;
+ const char *name;
+};
+
+typedef struct _DRouteProperty DRouteProperty;
+struct _DRouteProperty
+{
+ DRoutePropertyFunction get;
+ DRoutePropertyFunction set;
+ const char *name;
+};
+
+/*---------------------------------------------------------------------------*/
+
+typedef struct _DRouteContext DRouteContext;
+
+typedef struct _DRoutePath DRoutePath;
+
+/*---------------------------------------------------------------------------*/
+
+DRouteContext *
+droute_new ();
+
+void
+droute_free (DRouteContext *cnx);
+
+DRoutePath *
+droute_add_one (DRouteContext *cnx,
+ const char *path,
+ const void *data);
+
+DRoutePath *
+droute_add_many (DRouteContext *cnx,
+ const char *path,
+ const void *data,
+ DRouteIntrospectChildrenFunction introspect_children_cb,
+ void *introspect_children_data,
+ const DRouteGetDatumFunction get_datum);
+
+void
+droute_path_add_interface (DRoutePath *path,
+ const char *name,
+ const char *introspect,
+ const DRouteMethod *methods,
+ const DRouteProperty *properties);
+
+DBusMessage *
+droute_not_yet_handled_error (DBusMessage *message);
+
+DBusMessage *
+droute_invalid_arguments_error (DBusMessage *message);
+
+DBusMessage *
+droute_out_of_memory_error (DBusMessage *message);
+
+void
+droute_path_register (DRoutePath *path, DBusConnection *bus);
+
+void
+droute_path_unregister (DRoutePath *path, DBusConnection *bus);
+
+void
+droute_context_register (DRouteContext *cnx, DBusConnection *bus);
+
+void
+droute_context_unregister (DRouteContext *cnx, DBusConnection *bus);
+
+void
+droute_intercept_dbus (DBusConnection *connection);
+
+void
+droute_unintercept_dbus (DBusConnection *connection);
+#endif /* _DROUTE_H */
diff --git a/packaging/at-spi2-atk.manifest b/packaging/at-spi2-atk.manifest
new file mode 100644
index 0000000..017d22d
--- /dev/null
+++ b/packaging/at-spi2-atk.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/at-spi2-atk.spec b/packaging/at-spi2-atk.spec
new file mode 100644
index 0000000..8ce313a
--- /dev/null
+++ b/packaging/at-spi2-atk.spec
@@ -0,0 +1,77 @@
+Name: at-spi2-atk
+Version: 2.12.0
+Release: 1
+Summary: Assistive Technology Service Provider Interface - GTK+ module
+License: LGPL-2.0+
+Group: System/Libraries
+Url: http://www.gnome.org/
+Source: http://download.gnome.org/sources/at-spi2-atk/2.12/%{name}-%{version}.tar.xz
+Source1001: %{name}.manifest
+Requires: at-spi2-core
+BuildRequires: dbus-devel
+BuildRequires: glib2-devel
+BuildRequires: atk-devel
+BuildRequires: at-spi2-core-devel
+BuildRequires: gettext
+
+%description
+AT-SPI is a general interface for applications to make use of the
+accessibility toolkit. This version is based on dbus not ORBIT / CORBA.
+
+%package -n libatk-bridge-2_0-0
+Summary: ATK/D-Bus bridging library
+Group: System/Libraries
+
+%description -n libatk-bridge-2_0-0
+AT-SPI is a general interface for applications to make use of the
+accessibility toolkit. This version is based on dbus.
+
+The package contains a ATK/D-Bus bridge library.
+
+%package devel
+Summary: Assistive Technology Service Provider Interface - Developent files
+Group: System/Libraries
+Requires: libatk-bridge-2_0-0 = %{version}
+
+%description devel
+AT-SPI is a general interface for applications to make use of the
+accessibility toolkit. This version is based on dbus.
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%build
+%autogen
+%__make %{?_smp_flags}
+
+%install
+rm -rf %{buildroot}
+%make_install
+find %{buildroot} -name '*.la' -or -name '*.a' | xargs rm -f
+find %{buildroot} -name '*.desktop' | xargs rm -f
+
+%clean
+rm -rf %{buildroot}
+
+%post -n libatk-bridge-2_0-0 -p /sbin/ldconfig
+
+%postun -n libatk-bridge-2_0-0 -p /sbin/ldconfig
+
+%files -n libatk-bridge-2_0-0
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%{_libdir}/libatk-bridge-2.0.so.*
+%{_libdir}/gtk-2.0/modules/libatk-bridge.so
+
+%files devel
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%{_includedir}/at-spi2-atk/2.0/atk-bridge.h
+%{_libdir}/libatk-bridge-2.0.so
+%{_libdir}/pkgconfig/atk-bridge-2.0.pc
+
+%changelog
+* Mon Mar 25 2013 tomasz.duszynski@comarch.com
+- Initial packaging of at-spi2-atk (2.5.92)
+
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..741f850
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS =
diff --git a/tests/cspi/Makefile.am b/tests/cspi/Makefile.am
new file mode 100644
index 0000000..b5b8d05
--- /dev/null
+++ b/tests/cspi/Makefile.am
@@ -0,0 +1,19 @@
+noinst_PROGRAMS = key-listener-test keysynth-test simple-at test-simple
+
+key_listener_test_SOURCES = key-listener-test.c
+keysynth_test_SOURCES = keysynth-test.c
+simple_at_SOURCES = simple-at.c
+test_simple_SOURCES = test-simple.c
+
+INCLUDES = -I$(top_srcdir) \
+ -I$(top_builddir) \
+ $(DBUS_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(ATK_CFLAGS) \
+ $(DBIND_CFLAGS) \
+ $(DEBUG_CFLAGS)
+
+LDADD = $(top_builddir)/common/libspicommon.la \
+ $(top_builddir)/cspi/libcspi.la \
+ $(TESTS_LIBS) $(XINPUT_LIBS) $(ATK_LIBS) $(GTK_LIBS) $(DBIND_LIBS) @EXTRA_SOCKET_LIBS@
diff --git a/tests/cspi/key-listener-test.c b/tests/cspi/key-listener-test.c
new file mode 100644
index 0000000..b212a21
--- /dev/null
+++ b/tests/cspi/key-listener-test.c
@@ -0,0 +1,201 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include "../../cspi/spi.h"
+
+static SPIBoolean report_command_key_event (const AccessibleKeystroke *stroke, void *user_data);
+static SPIBoolean report_ordinary_key_event (const AccessibleKeystroke *stroke, void *user_data);
+static SPIBoolean report_synchronous_key_event (const AccessibleKeystroke *stroke, void *user_data);
+static SPIBoolean report_tab_key_event (const AccessibleKeystroke *stroke, void *user_data);
+static SPIBoolean report_all_key_event (const AccessibleKeystroke *stroke, void *user_data);
+
+static AccessibleKeystrokeListener *command_key_listener;
+static AccessibleKeystrokeListener *ordinary_key_listener;
+static AccessibleKeystrokeListener *synchronous_key_listener;
+static AccessibleKeystrokeListener *tab_key_listener;
+static AccessibleKeystrokeListener *all_key_listener;
+static AccessibleKeySet *command_keyset;
+static AccessibleKeySet *async_keyset;
+static AccessibleKeySet *sync_keyset;
+static AccessibleKeySet *tab_keyset;
+
+int
+main (int argc, char **argv)
+{
+ const char *tab_strings[1] = {"Tab"};
+ short keycodes[] = {65, 64, 23};
+ SPIBoolean retval = FALSE;
+
+ SPI_init ();
+
+ /* prepare the keyboard snoopers */
+ command_key_listener = SPI_createAccessibleKeystrokeListener (report_command_key_event, NULL);
+ ordinary_key_listener = SPI_createAccessibleKeystrokeListener (report_ordinary_key_event, NULL);
+ synchronous_key_listener = SPI_createAccessibleKeystrokeListener (report_synchronous_key_event, NULL);
+ tab_key_listener = SPI_createAccessibleKeystrokeListener (report_tab_key_event, NULL);
+ all_key_listener = SPI_createAccessibleKeystrokeListener (report_all_key_event, NULL);
+
+ command_keyset = SPI_createAccessibleKeySet (1, "q", NULL, NULL);
+ async_keyset = SPI_createAccessibleKeySet (3, NULL, keycodes, NULL);
+ sync_keyset = SPI_createAccessibleKeySet (3, "def", NULL, NULL);
+ tab_keyset = SPI_createAccessibleKeySet (1, NULL, NULL, tab_strings);
+ retval = SPI_registerAccessibleKeystrokeListener(command_key_listener,
+ command_keyset,
+ SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL,
+ (unsigned long) ( SPI_KEY_PRESSED ),
+ SPI_KEYLISTENER_ALL_WINDOWS);
+ fprintf (stderr, "Command key registry: result %s\n", retval ? "succeeded" :
+ "failed");
+ retval = SPI_registerAccessibleKeystrokeListener(ordinary_key_listener,
+ async_keyset,
+ SPI_KEYMASK_UNMODIFIED,
+ (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
+ SPI_KEYLISTENER_NOSYNC);
+
+ retval = SPI_registerAccessibleKeystrokeListener(synchronous_key_listener,
+ sync_keyset,
+ SPI_KEYMASK_UNMODIFIED,
+ (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
+ SPI_KEYLISTENER_CANCONSUME);
+
+ retval = SPI_registerAccessibleKeystrokeListener(tab_key_listener,
+ tab_keyset,
+ SPI_KEYMASK_ALT,
+ (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
+ SPI_KEYLISTENER_ALL_WINDOWS);
+ fprintf (stderr, "tab listener registry: %s\n", retval ? "succeeded" : "failed");
+
+ retval = SPI_registerAccessibleKeystrokeListener(all_key_listener,
+ SPI_KEYSET_ALL_KEYS,
+ SPI_KEYMASK_CONTROL | SPI_KEYMASK_SHIFT,
+ (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
+ SPI_KEYLISTENER_ALL_WINDOWS);
+
+ fprintf (stderr, "all key registry: %s\n", retval ? "succeeded" : "failed" );
+
+ SPI_registerAccessibleKeystrokeListener(all_key_listener,
+ SPI_KEYSET_ALL_KEYS,
+ SPI_KEYMASK_SHIFT,
+ (unsigned long) ( SPI_KEY_PRESSED ),
+ SPI_KEYLISTENER_NOSYNC | SPI_KEYLISTENER_CANCONSUME);
+
+ SPI_event_main ();
+
+ putenv ("AT_BRIDGE_SHUTDOWN=1");
+
+ return SPI_exit ();
+}
+
+static void
+simple_at_exit (void)
+{
+ SPI_deregisterAccessibleKeystrokeListener (command_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL);
+ AccessibleKeystrokeListener_unref (command_key_listener);
+ SPI_freeAccessibleKeySet (command_keyset);
+
+/*
+ SPI_deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL); */
+ AccessibleKeystrokeListener_unref (ordinary_key_listener);
+ SPI_freeAccessibleKeySet (async_keyset);
+
+/* SPI_deregisterAccessibleKeystrokeListener (synchronous_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL); */
+ AccessibleKeystrokeListener_unref (synchronous_key_listener);
+ SPI_freeAccessibleKeySet (sync_keyset);
+
+ SPI_deregisterAccessibleKeystrokeListener (tab_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL);
+ AccessibleKeystrokeListener_unref (tab_key_listener);
+ SPI_freeAccessibleKeySet (tab_keyset);
+
+ SPI_event_quit ();
+}
+
+static SPIBoolean
+is_command_key (const AccessibleKeystroke *key)
+{
+ switch (key->keyID)
+ {
+ case 'Q':
+ case 'q':
+ simple_at_exit();
+ return TRUE; /* not reached */
+ default:
+ return FALSE;
+ }
+}
+
+static void
+print_key_event (const AccessibleKeystroke *key, char *prefix)
+{
+ fprintf (stderr, "%s KeyEvent %s%c (keycode %d); string=%s; time=%lx\n",
+ prefix,
+ (key->modifiers & SPI_KEYMASK_ALT)?"Alt-":"",
+ ((key->modifiers & SPI_KEYMASK_SHIFT)^(key->modifiers & SPI_KEYMASK_SHIFTLOCK))?
+ (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
+ (int) key->keycode,
+ key->keystring,
+ (long int) key->timestamp);
+}
+
+static SPIBoolean
+report_command_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ print_key_event (key, "command");
+ return is_command_key (key);
+}
+
+static SPIBoolean
+report_ordinary_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ print_key_event (key, "ordinary");
+ return FALSE;
+}
+
+static SPIBoolean
+report_synchronous_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ /* consume 'd' key, let others pass through */
+ print_key_event (key, "synchronous (consumable) ");
+ return ( key->keyID == 'd' ) ? TRUE : FALSE;
+}
+
+static SPIBoolean
+report_tab_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ print_key_event (key, "[TAB]");
+ return FALSE;
+}
+
+static SPIBoolean
+report_all_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ fprintf(stderr, "(%ld)", key->keyID);
+ return FALSE;
+}
+
diff --git a/tests/cspi/keysynth-test.c b/tests/cspi/keysynth-test.c
new file mode 100644
index 0000000..73aa240
--- /dev/null
+++ b/tests/cspi/keysynth-test.c
@@ -0,0 +1,65 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include "../../cspi/spi-private.h" /* A hack for now */
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <atk/atk.h>
+#include <atk/atknoopobject.h>
+#include "common/spi-dbus.h"
+
+typedef struct {
+ long int val;
+ char *string;
+ AccessibleKeySynthType type;
+} TextTest;
+
+static TextTest text[] = {
+ {65, NULL, SPI_KEY_PRESSRELEASE},
+ {64, NULL, SPI_KEY_SYM},
+ {0, "--hello!", SPI_KEY_STRING},
+ {0, "StudlyCaps!", SPI_KEY_STRING}
+};
+
+static void
+test_key_synthesis (void)
+{
+ int i;
+ for (i = 0; i < G_N_ELEMENTS (text); ++i) {
+ SPI_generateKeyboardEvent (text[i].val, text[i].string, text[i].type);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ gtk_init (&argc, &argv);
+ SPI_init ();
+
+ test_key_synthesis ();
+
+ return SPI_exit ();
+}
+
diff --git a/tests/cspi/simple-at.c b/tests/cspi/simple-at.c
new file mode 100644
index 0000000..23cb0ec
--- /dev/null
+++ b/tests/cspi/simple-at.c
@@ -0,0 +1,615 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2002 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#undef MAGNIFIER_ENABLED
+#include "../../cspi/spi-private.h" /* A hack for now */
+
+#define PRINT_TREE
+
+static void report_focus_event (const AccessibleEvent *event, void *user_data);
+static void report_generic_event (const AccessibleEvent *event, void *user_data);
+static void report_window_event (const AccessibleEvent *event, void *user_data);
+static void report_text_event (const AccessibleEvent *event, void *user_data);
+static void report_button_press (const AccessibleEvent *event, void *user_data);
+static void check_property_change (const AccessibleEvent *event, void *user_data);
+static SPIBoolean report_command_key_event (const AccessibleKeystroke *stroke, void *user_data);
+static SPIBoolean report_ordinary_key_event (const AccessibleKeystroke *stroke, void *user_data);
+static void get_environment_vars (void);
+
+static int _festival_init (void);
+static void _festival_say (const char *text, const char *voice, SPIBoolean shutup);
+static void _festival_write (const char *buff, int fd);
+
+#ifdef PRINT_TREE
+static void print_accessible_tree (Accessible *accessible, char *prefix);
+#endif
+
+#ifdef MAGNIFIER_ENABLED
+static SPIBoolean use_magnifier = FALSE;
+#endif
+
+static SPIBoolean use_festival = FALSE;
+static SPIBoolean festival_chatty = FALSE;
+static SPIBoolean name_changed = FALSE;
+
+static AccessibleEventListener *focus_listener;
+static AccessibleEventListener *property_listener;
+static AccessibleEventListener *generic_listener;
+static AccessibleEventListener *window_listener;
+static AccessibleEventListener *button_listener;
+static AccessibleEventListener *text_listener;
+static AccessibleKeystrokeListener *command_key_listener;
+static AccessibleKeystrokeListener *ordinary_key_listener;
+static AccessibleKeySet *command_keyset;
+
+int
+main (int argc, char **argv)
+{
+ int i, j;
+ int n_desktops;
+ int n_apps;
+ char *s;
+ Accessible *desktop;
+ Accessible *application;
+ const char *modules;
+
+ if ((argc > 1) && (!strncmp (argv[1], "-h", 2)))
+ {
+ printf ("Usage: simple-at\n");
+ printf ("\tEnvironment variables used:\n\t\tFESTIVAL\n\t\tMAGNIFIER\n\t\tFESTIVAL_CHATTY\n");
+ exit (0);
+ }
+
+ modules = g_getenv ("GTK_MODULES");
+ if (!modules || modules [0] == '\0')
+ {
+ putenv ("GTK_MODULES=");
+ }
+ modules = NULL;
+
+ SPI_init ();
+
+ focus_listener = SPI_createAccessibleEventListener (report_focus_event, NULL);
+ property_listener = SPI_createAccessibleEventListener (check_property_change, NULL);
+ generic_listener = SPI_createAccessibleEventListener (report_generic_event, NULL);
+ window_listener = SPI_createAccessibleEventListener (report_window_event, NULL);
+ text_listener = SPI_createAccessibleEventListener (report_text_event, NULL);
+ button_listener = SPI_createAccessibleEventListener (report_button_press, NULL);
+ SPI_registerGlobalEventListener (focus_listener, "focus:");
+ SPI_registerGlobalEventListener (property_listener, "object:property-change");
+/* :accessible-selection"); */
+ SPI_registerGlobalEventListener (property_listener, "object:property-change:accessible-name");
+ SPI_registerGlobalEventListener (generic_listener, "object:selection-changed");
+ SPI_registerGlobalEventListener (generic_listener, "object:children-changed");
+ SPI_registerGlobalEventListener (generic_listener, "object:visible-data-changed");
+ SPI_registerGlobalEventListener (generic_listener, "object:text-selection-changed");
+ SPI_registerGlobalEventListener (text_listener, "object:text-caret-moved");
+ SPI_registerGlobalEventListener (text_listener, "object:text-changed");
+ SPI_registerGlobalEventListener (button_listener, "Gtk:GtkWidget:button-press-event");
+ SPI_registerGlobalEventListener (window_listener, "window:minimize");
+ SPI_registerGlobalEventListener (window_listener, "window:activate");
+ n_desktops = SPI_getDesktopCount ();
+
+ for (i=0; i<n_desktops; ++i)
+ {
+ desktop = SPI_getDesktop (i);
+ s = Accessible_getName (desktop);
+ fprintf (stderr, "desktop %d name: %s\n", i, s);
+ SPI_freeString (s);
+ n_apps = Accessible_getChildCount (desktop);
+ for (j=0; j<n_apps; ++j)
+ {
+ application = Accessible_getChildAtIndex (desktop, j);
+ s = Accessible_getName (application);
+ fprintf (stderr, "app %d name: %s\n", j, s ? s : "(nil)");
+#ifdef PRINT_TREE
+ print_accessible_tree (application, "*");
+#endif
+ SPI_freeString (s);
+ Accessible_unref (application);
+ }
+ Accessible_unref (desktop);
+ }
+
+ /* prepare the keyboard snoopers */
+ command_key_listener = SPI_createAccessibleKeystrokeListener (report_command_key_event, NULL);
+ ordinary_key_listener = SPI_createAccessibleKeystrokeListener (report_ordinary_key_event, NULL);
+
+ command_keyset = SPI_createAccessibleKeySet (11, "qmf23456789", NULL, NULL);
+
+ /* will listen only to Control-Alt-q KeyPress events */
+ SPI_registerAccessibleKeystrokeListener(command_key_listener,
+ command_keyset,
+ SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL,
+ (unsigned long) ( SPI_KEY_PRESSED ),
+ SPI_KEYLISTENER_ALL_WINDOWS);
+
+ /* will listen only to CAPSLOCK key events, both press and release */
+ SPI_registerAccessibleKeystrokeListener(ordinary_key_listener,
+ (AccessibleKeySet *) SPI_KEYSET_ALL_KEYS,
+ SPI_KEYMASK_SHIFTLOCK,
+ (unsigned long) ( SPI_KEY_PRESSED | SPI_KEY_RELEASED ),
+ SPI_KEYLISTENER_NOSYNC);
+
+ get_environment_vars ();
+
+ SPI_event_main ();
+
+ putenv ("AT_BRIDGE_SHUTDOWN=1");
+
+ return SPI_exit ();
+}
+
+static void
+get_environment_vars (void)
+{
+ if (g_getenv ("FESTIVAL"))
+ {
+ fprintf (stderr, "Using festival\n");
+ use_festival = TRUE;
+ if (g_getenv ("FESTIVAL_CHATTY"))
+ {
+ festival_chatty = TRUE;
+ }
+ }
+#ifdef MAGNIFIER_ENABLED
+ if (g_getenv ("MAGNIFIER"))
+ {
+ fprintf (stderr, "Using magnifier\n");
+ use_magnifier = TRUE;
+ }
+ else
+ {
+ fprintf (stderr, "Not using magnifier\n");
+ }
+#endif
+
+ if (!use_festival)
+ {
+ fprintf (stderr, "No speech output\n");
+ }
+}
+
+#ifdef PRINT_TREE
+static void
+print_accessible_tree (Accessible *accessible, char *prefix)
+{
+ int n_children;
+ int i;
+ char *name;
+ char *role_name;
+ char *parent_name = NULL;
+ char *parent_role = NULL;
+ char child_prefix[100];
+ Accessible *child;
+ Accessible *parent;
+
+ strncpy (child_prefix, prefix, 98);
+ strcat (child_prefix, "*");
+ parent = Accessible_getParent (accessible);
+ if (parent)
+ {
+ parent_name = Accessible_getName (parent);
+ parent_role = Accessible_getRoleName (parent);
+ Accessible_unref (parent);
+ }
+ name = Accessible_getName (accessible);
+ role_name = Accessible_getRoleName (accessible);
+ fprintf (stdout, "%sAccessible [%s] \"%s\"; parent [%s] %s.\n",
+ prefix, role_name, name ? name : "(nil)",
+ parent_role ? parent_role : "(nil)",
+ parent_name ? parent_name : "(nil)");
+ SPI_freeString (name);
+ SPI_freeString (role_name);
+ SPI_freeString (parent_name);
+ SPI_freeString (parent_role);
+ n_children = Accessible_getChildCount (accessible);
+ for (i = 0; i < n_children; ++i)
+ {
+ child = Accessible_getChildAtIndex (accessible, i);
+ print_accessible_tree (child, child_prefix);
+ Accessible_unref (child);
+ }
+}
+#endif
+
+void
+report_focussed_accessible (Accessible *obj, SPIBoolean shutup_previous_speech)
+{
+ char *s;
+ int len;
+ long x, y, width, height;
+ /* hack for GUADEC demo, to make sure name changes are spoken */
+ shutup_previous_speech = (shutup_previous_speech && !name_changed);
+
+ if (use_festival)
+ {
+ if (festival_chatty)
+ {
+ s = Accessible_getRoleName (obj);
+ _festival_say (s, "voice_don_diphone", shutup_previous_speech);
+ SPI_freeString (s);
+ }
+ fprintf (stderr, "getting Name\n");
+ s = Accessible_getName (obj);
+ _festival_say (s, "voice_kal_diphone",
+ shutup_previous_speech || festival_chatty);
+ SPI_freeString (s);
+ }
+
+ if (Accessible_isComponent (obj))
+ {
+ AccessibleComponent *component = Accessible_getComponent (obj);
+ AccessibleComponent_getExtents (component, &x, &y, &width, &height,
+ SPI_COORD_TYPE_SCREEN);
+ fprintf (stderr, "Bounding box: (%ld, %ld) ; (%ld, %ld)\n",
+ x, y, x+width, y+height);
+ if (Accessible_isText (obj))
+ {
+ long x0, y0, xN, yN, w0, h0, wN, hN, nchars;
+ AccessibleText *text = Accessible_getText (obj);
+ nchars = AccessibleText_getCharacterCount (text);
+ if (nchars > 0)
+ {
+ AccessibleText_getCharacterExtents (text, 0, &x0, &y0, &w0, &h0,
+ SPI_COORD_TYPE_SCREEN);
+ AccessibleText_getCharacterExtents (text, nchars-1, &xN, &yN, &wN, &hN,
+ SPI_COORD_TYPE_SCREEN);
+ x = MIN (x0, xN);
+ width = MAX (x0 + w0, xN + wN) - x;
+ fprintf (stderr, "Text bounding box: (%ld, %ld) ; (%ld, %ld)\n",
+ x, y, x+width, y+height);
+ }
+ }
+#ifdef MAGNIFIER_ENABLED
+ if (use_magnifier) {
+ magnifier_set_roi ((short) 0, x, y, width, height);
+ }
+#endif
+ }
+
+
+ if (Accessible_isValue (obj))
+ {
+ AccessibleValue *value = Accessible_getValue (obj);
+ fprintf (stderr, "Current value = %f, min = %f; max = %f\n",
+ AccessibleValue_getCurrentValue (value),
+ AccessibleValue_getMinimumValue (value),
+ AccessibleValue_getMaximumValue (value));
+ }
+ /* if this is a text object, speak the first sentence. */
+
+ if (Accessible_isText(obj))
+
+ {
+ AccessibleText *text_interface;
+ long start_offset, end_offset;
+ char *first_sentence = "empty";
+ text_interface = Accessible_getText (obj);
+ first_sentence = AccessibleText_getTextAtOffset (
+ text_interface, (long) 0, SPI_TEXT_BOUNDARY_SENTENCE_START, &start_offset, &end_offset);
+ if (first_sentence && use_festival)
+ {
+ _festival_say(first_sentence, "voice_don_diphone", FALSE);
+ SPI_freeString (first_sentence);
+ }
+ len = AccessibleText_getCharacterCount (text_interface);
+ s = AccessibleText_getText (text_interface, 0, len);
+ fprintf (stderr, "done reporting on focussed object, text=%s\n", s);
+ }
+}
+
+void
+report_focus_event (const AccessibleEvent *event, void *user_data)
+{
+ char *s;
+
+ g_return_if_fail (event->source != NULL);
+ s = Accessible_getName (event->source);
+ if (s)
+ {
+ fprintf (stderr, "%s event from %s\n", event->type, s);
+ SPI_freeString (s);
+ report_focussed_accessible (event->source, TRUE);
+ }
+ Accessible_getParent (event->source);
+ name_changed = FALSE;
+}
+
+void
+report_generic_event (const AccessibleEvent *event, void *user_data)
+{
+ fprintf (stderr, "%s event received\n", event->type);
+}
+
+void
+report_window_event (const AccessibleEvent *event, void *user_data)
+{
+ fprintf (stderr, "%s event received\n", event->type);
+ if (!strcmp (event->type, "window:activate"))
+ {
+ print_accessible_tree (event->source, "window");
+ }
+}
+
+void
+report_text_event (const AccessibleEvent *event, void *user_data)
+{
+ AccessibleText *text = Accessible_getText (event->source);
+ fprintf (stderr, "%s event received\n", event->type);
+#ifdef MAGNIFIER_ENABLED
+ if (use_magnifier && strcmp (event->type, "object:text-changed"))
+ {
+ long offset = AccessibleText_getCaretOffset (text);
+ long x, y, w, h;
+ fprintf (stderr, "offset %d\n", (int) offset);
+ AccessibleText_getCharacterExtents (text, offset, &x, &y, &w, &h,
+ SPI_COORD_TYPE_SCREEN);
+ fprintf (stderr, "new roi %d %d %d %d\n", (int) x, (int) y, (int) w, (int) h);
+ magnifier_set_roi ((short) 0, x, y, w, h);
+ }
+#endif
+ if (!strcmp (event->type, "object:text-changed"))
+ {
+ long start, end;
+ char *new_text = AccessibleText_getTextAtOffset (text, (long) event->detail1, SPI_TEXT_BOUNDARY_WORD_START, &start, &end);
+ _festival_say (new_text, "voice_kal_diphone", FALSE);
+ fprintf (stderr, "text changed: %s", new_text ? new_text : "");
+ SPI_freeString (new_text);
+ }
+ else
+ {
+ long start, end;
+ char *word_text = AccessibleText_getTextAtOffset (text, (long) event->detail1, SPI_TEXT_BOUNDARY_WORD_START, &start, &end);
+ char *sentence_text = AccessibleText_getTextAtOffset (text, (long) event->detail1, SPI_TEXT_BOUNDARY_SENTENCE_START, &start, &end);
+ fprintf (stderr, "text changed: word %s; sentence %s at %ld",
+ (word_text ? word_text : ""),
+ (sentence_text ? sentence_text : ""),
+ event->detail1);
+ if (word_text) SPI_freeString (word_text);
+ if (sentence_text) SPI_freeString (sentence_text);
+ }
+}
+
+void
+report_button_press (const AccessibleEvent *event, void *user_data)
+{
+ char *s;
+
+ g_return_if_fail (event->source != NULL);
+
+ s = Accessible_getName (event->source);
+
+ fprintf (stderr, "%s event from %s\n", event->type, s);
+ SPI_freeString (s);
+ s = Accessible_getDescription (event->source);
+ fprintf (stderr, "Object description %s\n", s);
+ SPI_freeString (s);
+}
+
+void
+check_property_change (const AccessibleEvent *event, void *user_data)
+{
+ AccessibleSelection *selection = Accessible_getSelection (event->source);
+ int n_selections;
+ int i;
+ char *s;
+ fprintf (stderr, "property change event!\n");
+ if (selection)
+ {
+ n_selections = (int) AccessibleSelection_getNSelectedChildren (selection);
+ s = Accessible_getName (event->source);
+ fprintf (stderr, "(Property) %s event from %s, %d selected children\n",
+ event->type, s, n_selections);
+ SPI_freeString (s);
+ /* for now, speak entire selection set */
+ for (i=0; i<n_selections; ++i)
+ {
+ Accessible *obj = AccessibleSelection_getSelectedChild (selection, (long) i);
+ g_return_if_fail (obj);
+ s = Accessible_getName (obj);
+ fprintf (stderr, "Child %d, name=%s\n", i, s);
+ SPI_freeString (s);
+ report_focussed_accessible (obj, i==0);
+ }
+ }
+ else if (!strcmp (event->type, "object:property-change:accessible-name"))
+ {
+ name_changed = TRUE;
+ report_focussed_accessible (event->source, TRUE);
+ }
+ else
+ {
+ fprintf (stderr, "Property change %s received\n", event->type);
+ }
+}
+
+static void
+simple_at_exit (void)
+{
+ SPI_deregisterGlobalEventListenerAll (focus_listener);
+ AccessibleEventListener_unref (focus_listener);
+
+ SPI_deregisterGlobalEventListenerAll (property_listener);
+ AccessibleEventListener_unref (property_listener);
+
+ SPI_deregisterGlobalEventListenerAll (generic_listener);
+ AccessibleEventListener_unref (generic_listener);
+
+ SPI_deregisterGlobalEventListenerAll (text_listener);
+ AccessibleEventListener_unref (text_listener);
+
+ SPI_deregisterGlobalEventListenerAll (button_listener);
+ AccessibleEventListener_unref (button_listener);
+
+ SPI_deregisterAccessibleKeystrokeListener (command_key_listener, SPI_KEYMASK_ALT | SPI_KEYMASK_CONTROL);
+ AccessibleKeystrokeListener_unref (command_key_listener);
+ SPI_freeAccessibleKeySet (command_keyset);
+
+ SPI_deregisterAccessibleKeystrokeListener (ordinary_key_listener, SPI_KEYMASK_SHIFTLOCK);
+ AccessibleKeystrokeListener_unref (ordinary_key_listener);
+
+ SPI_event_quit ();
+}
+
+static SPIBoolean
+is_command_key (const AccessibleKeystroke *key)
+{
+ switch (key->keyID)
+ {
+ case 'Q':
+ case 'q':
+ simple_at_exit();
+ return TRUE; /* not reached */
+#ifdef MAGNIFIER_ENABLED
+ case 'M':
+ case 'm':
+ use_magnifier = ! use_magnifier;
+ fprintf (stderr, "%ssing magnifier\n", use_magnifier ? "U" : "Not u");
+ return TRUE;
+#endif
+ case 'F':
+ case 'f':
+ use_festival = ! use_festival;
+ fprintf (stderr, "%speech output\n", use_festival ? "S" : "No s");
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static SPIBoolean
+report_command_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ fprintf (stderr, "Command KeyEvent %s%c (keycode %d); string=%s; time=%lx\n",
+ (key->modifiers & SPI_KEYMASK_ALT)?"Alt-":"",
+ ((key->modifiers & SPI_KEYMASK_SHIFT)^(key->modifiers & SPI_KEYMASK_SHIFTLOCK))?
+ (char) toupper((int) key->keyID) : (char) tolower((int) key->keyID),
+ (int) key->keycode,
+ key->keystring,
+ (long int) key->timestamp);
+ return is_command_key (key);
+}
+
+
+static SPIBoolean
+report_ordinary_key_event (const AccessibleKeystroke *key, void *user_data)
+{
+ fprintf (stderr, "Received key event:\tsym %ld\n\tmods %x\n\tcode %d\n\tstring=\'%s\'\n\ttime %lx\n",
+ (long) key->keyID,
+ (unsigned int) key->modifiers,
+ (int) key->keycode,
+ key->keystring,
+ (long int) key->timestamp);
+ return FALSE;
+}
+
+static int
+_festival_init (void)
+{
+ int fd;
+ struct sockaddr_in name;
+ int tries = 2;
+
+ name.sin_family = AF_INET;
+ name.sin_port = htons (1314);
+ name.sin_addr.s_addr = htonl(INADDR_ANY);
+ fd = socket (PF_INET, SOCK_STREAM, 0);
+
+ while (connect(fd, (struct sockaddr *) &name, sizeof (name)) < 0) {
+ if (!tries--) {
+ perror ("connect");
+ return -1;
+ }
+ }
+
+ _festival_write ("(audio_mode'async)\n", fd);
+ _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
+ _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
+ return fd;
+}
+
+static void
+_festival_say (const char *text, const char *voice, SPIBoolean shutup)
+{
+ static int fd = 0;
+ gchar *quoted;
+ gchar *p;
+ gchar prefix[50];
+ static gchar voice_spec[32];
+
+ if (!fd)
+ {
+ fd = _festival_init ();
+ }
+
+ fprintf (stderr, "saying text: %s\n", text);
+
+ quoted = g_malloc(64+strlen(text)*2);
+
+ sprintf (prefix, "(SayText \"");
+
+ strncpy(quoted, prefix, 10);
+ p = quoted+strlen(prefix);
+ while (*text) {
+ if ( *text == '\\' || *text == '"' )
+ *p = '\\';
+ *p++ = *text++;
+ }
+ *p++ = '"';
+ *p++ = ')';
+ *p++ = '\n';
+ *p = 0;
+
+ if (shutup) _festival_write ("(audio_mode'shutup)\n", fd);
+ if (voice && (strncmp (voice, (char *) (voice_spec+1), strlen(voice))))
+ {
+ snprintf (voice_spec, 32, "(%s)\n", voice);
+ _festival_write (voice_spec, fd);
+ _festival_write ("(Parameter.set 'Duration_Model 'Tree_ZScore)\n", fd);
+ _festival_write ("(Parameter.set 'Duration_Stretch 0.75)\n", fd);
+ }
+
+ _festival_write (quoted, fd);
+
+ g_free(quoted);
+}
+
+static void
+_festival_write (const gchar *command_string, int fd)
+{
+ fprintf(stderr, command_string);
+ if (fd < 0) {
+ perror("socket");
+ return;
+ }
+ write(fd, command_string, strlen(command_string));
+}
+
diff --git a/tests/cspi/test-simple.c b/tests/cspi/test-simple.c
new file mode 100644
index 0000000..62bcb31
--- /dev/null
+++ b/tests/cspi/test-simple.c
@@ -0,0 +1,816 @@
+/*
+ * test-simple.c: A set of simple regression tests
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2001 Ximian, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * ******** Do not copy this code as an example *********
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+#include <cspi/spi.h>
+#include <cspi/spi-private.h>
+
+#include "dbus/dbus.h"
+
+/* Known bugs */
+#define WHOLE_STRING -1
+
+static void validate_accessible (Accessible *accessible,
+ gboolean has_parent,
+ gboolean recurse_down);
+
+#define WINDOW_MAGIC 0x123456a
+#define TEST_STRING_A "A test string"
+#define TEST_STRING_A_OBJECT "A_test_string_object"
+#define TEST_STRING_B "Another test string"
+
+static int print_tree_depth = 0;
+static gboolean print_tree = FALSE;
+static gboolean do_poke = FALSE;
+static gboolean key_press_received = FALSE;
+static gboolean key_release_received = FALSE;
+
+typedef struct {
+ gulong magic;
+ GtkWidget *window;
+} TestWindow;
+
+static gboolean
+focus_me (GtkWidget *widget)
+{
+ AtkObject *aobject = atk_implementor_ref_accessible (
+ ATK_IMPLEMENTOR (widget));
+
+ /* Force a focus event - even if the WM focused
+ * us before our at-bridge's idle handler registered
+ * our interest */
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_widget_grab_focus (widget);
+/* else: FIXME - gtk_widget_grab_focus should send a notify */
+ atk_focus_tracker_notify (aobject);
+
+ g_object_unref (G_OBJECT (aobject));
+
+ return FALSE;
+}
+
+static void
+test_window_add_and_show (GtkContainer *container, GtkWidget *widget)
+{
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+}
+
+static GtkWidget *
+create_tree (void)
+{
+ GtkWidget *widget;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ GtkTreeViewColumn *column;
+
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, TEST_STRING_A, -1);
+ column = gtk_tree_view_column_new_with_attributes ("String",
+ gtk_cell_renderer_text_new (), "text", 0, NULL);
+ widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (G_OBJECT (store));
+ gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column);
+
+ return widget;
+}
+
+static TestWindow *
+create_test_window (void)
+{
+ TestWindow *win = g_new0 (TestWindow, 1);
+ GtkWidget *widget, *vbox;
+ AtkObject *obj;
+
+ win->magic = WINDOW_MAGIC;
+ win->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_widget_show (win->window);
+
+ vbox = gtk_vbox_new (0, 0);
+ gtk_container_add (GTK_CONTAINER (win->window), vbox);
+ gtk_widget_show (vbox);
+
+ widget = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (widget), TEST_STRING_A);
+ obj = gtk_widget_get_accessible (widget);
+ atk_object_set_name (obj, TEST_STRING_A_OBJECT);
+
+ test_window_add_and_show (GTK_CONTAINER (vbox), widget);
+
+ widget = gtk_button_new_with_label ("_Foobar");
+ test_window_add_and_show (GTK_CONTAINER (vbox), widget);
+
+ widget = gtk_hseparator_new ();
+ test_window_add_and_show (GTK_CONTAINER (vbox), widget);
+
+ widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION,
+ GTK_ICON_SIZE_LARGE_TOOLBAR);
+ test_window_add_and_show (GTK_CONTAINER (vbox), widget);
+
+ widget = g_object_new (GTK_TYPE_HSCALE, NULL);
+ gtk_range_set_range (GTK_RANGE (widget), 0.0, 100.0);
+ test_window_add_and_show (GTK_CONTAINER (vbox), widget);
+
+ widget = create_tree ();
+ test_window_add_and_show (GTK_CONTAINER (vbox), widget);
+
+ g_idle_add ((GSourceFunc) focus_me, win->window);
+
+ return win;
+}
+
+static void
+test_window_destroy (TestWindow *win)
+{
+ gtk_widget_destroy (win->window);
+ g_free (win);
+}
+
+static void
+test_roles (void)
+{
+ int i;
+
+ fprintf (stderr, "Testing roles...\n");
+ for (i = -1; i < 1000; i++)
+ g_assert (AccessibleRole_getName (i) != NULL);
+
+ g_assert (!strcmp (AccessibleRole_getName (SPI_ROLE_FILE_CHOOSER), "file-chooser"));
+ g_assert (!strcmp (AccessibleRole_getName (SPI_ROLE_RADIO_BUTTON), "radio-button"));
+ g_assert (!strcmp (AccessibleRole_getName (SPI_ROLE_TABLE), "table"));
+ g_assert (!strcmp (AccessibleRole_getName (SPI_ROLE_WINDOW), "window"));
+}
+
+static void
+test_action (AccessibleAction *action)
+{
+ gint n_actions, i;
+ gchar *s, *sd;
+ g_assert ((n_actions = AccessibleAction_getNActions (action)) >= 0);
+
+ fprintf (stderr, "Testing actions...");
+ for (i = 0; i < n_actions; ++i)
+ {
+ s = AccessibleAction_getName (action, i);
+ g_assert (s);
+ sd = AccessibleAction_getDescription (action, i);
+ g_assert (sd);
+ fprintf (stderr, "%d: %s (%s); ", i, s, sd);
+ SPI_freeString (s);
+ SPI_freeString (sd);
+ g_assert (AccessibleAction_doAction (action, i));
+ }
+ fprintf (stderr, "\n");
+}
+
+static void
+test_desktop (void)
+{
+ Accessible *desktop;
+ Accessible *application;
+ Accessible **list;
+
+ fprintf (stderr, "Testing desktop...\n");
+
+ g_assert (SPI_getDesktop (-1) == NULL);
+ desktop = SPI_getDesktop (0);
+ g_assert (desktop != NULL);
+
+ g_assert ((SPI_getDesktopList (&list)) > 0);
+ g_assert (list[0] == desktop);
+ SPI_freeDesktopList (list);
+
+ validate_accessible (desktop, FALSE, FALSE);
+
+ application = Accessible_getChildAtIndex (desktop, 0);
+ g_assert (application != NULL);
+ AccessibleApplication_unref (application);
+
+ Accessible_unref (desktop);
+}
+
+static void
+test_application (Accessible *application)
+{
+ char *str;
+
+ fprintf (stderr, "Testing application ...\n");
+ g_assert (Accessible_isApplication (application));
+ g_assert (Accessible_getApplication (application) ==
+ application);
+ AccessibleApplication_unref (application);
+
+ str = AccessibleApplication_getToolkitName (application);
+ g_assert (str != NULL);
+ g_assert (!strcmp (str, "GAIL"));
+ SPI_freeString (str);
+
+ str = AccessibleApplication_getLocale (application, LC_MESSAGES);
+ g_assert (!strcmp (str, setlocale (LC_MESSAGES, NULL)));
+ SPI_freeString (str);
+
+ str = AccessibleApplication_getVersion (application);
+ g_assert (str != NULL);
+ SPI_freeString (str);
+
+ AccessibleApplication_getID (application);
+}
+
+static void
+test_editable_text (AccessibleEditableText *etext)
+{
+ char *str;
+ AccessibleText *text;
+
+ fprintf (stderr, "Testing editable text ...\n");
+
+ g_assert (Accessible_isText (etext));
+ text = Accessible_getText (etext);
+
+ AccessibleEditableText_setTextContents (
+ etext, TEST_STRING_B);
+
+ str = AccessibleText_getText (text, 0, WHOLE_STRING);
+ g_assert (!strcmp (str, TEST_STRING_B));
+
+ SPI_freeString (str);
+
+ /* FIXME: lots more editing here */
+
+ AccessibleEditableText_setTextContents (
+ etext, TEST_STRING_A);
+
+ AccessibleText_unref (text);
+}
+
+static void
+test_table (AccessibleTable *table)
+{
+ Accessible *header;
+ gint index;
+ gint rows, columns;
+
+ fprintf (stderr, "Testing table ...\n");
+
+ rows = AccessibleTable_getNRows (table);
+ g_assert (rows > 0);
+
+ columns = AccessibleTable_getNColumns (table);
+ g_assert (columns > 0);
+
+ index = AccessibleTable_getIndexAt (table, rows - 1, columns - 1);
+
+ g_assert (AccessibleTable_getRowAtIndex (table, index) == rows - 1);
+
+ g_assert (AccessibleTable_getColumnAtIndex (table, index) == columns - 1);
+
+ g_assert ((header = AccessibleTable_getColumnHeader (table, 0)));
+ Accessible_unref (header);
+
+ AccessibleTable_isSelected (table, 0, 0);
+
+ /* FIXME: lots more tests */
+}
+
+static void
+test_text (AccessibleText *text)
+{
+ char *str;
+
+ fprintf (stderr, "Testing text ...\n");
+
+ g_assert (AccessibleText_getCharacterCount (text) ==
+ strlen (TEST_STRING_A));
+
+ str = AccessibleText_getText (text, 0, WHOLE_STRING);
+ g_assert (!strcmp (str, TEST_STRING_A));
+ SPI_freeString (str);
+
+ str = AccessibleText_getText (text, 0, 5);
+ g_assert (!strncmp (str, TEST_STRING_A, 5));
+ SPI_freeString (str);
+
+ AccessibleText_setCaretOffset (text, 7);
+ g_assert (AccessibleText_getCaretOffset (text) == 7);
+
+ /* FIXME: lots more tests - selections etc. etc. */
+}
+
+static void
+test_value (AccessibleValue *value)
+{
+ float original_value;
+
+ fprintf (stderr, "Testing value ...\n");
+
+ original_value = AccessibleValue_getCurrentValue (value);
+
+ g_assert (AccessibleValue_getCurrentValue (value) <=
+ AccessibleValue_getMaximumValue (value));
+
+ g_assert (AccessibleValue_getCurrentValue (value) >=
+ AccessibleValue_getMinimumValue (value));
+
+ AccessibleValue_setCurrentValue (value,
+ AccessibleValue_getMinimumValue (value));
+
+ g_assert (AccessibleValue_getCurrentValue (value) ==
+ AccessibleValue_getMinimumValue (value));
+
+ AccessibleValue_setCurrentValue (value,
+ AccessibleValue_getMaximumValue (value));
+
+ g_assert (AccessibleValue_getCurrentValue (value) ==
+ AccessibleValue_getMaximumValue (value));
+
+ AccessibleValue_setCurrentValue (value, original_value);
+
+ g_assert (AccessibleValue_getCurrentValue (value) == original_value);
+}
+
+static void
+test_component (AccessibleComponent *component)
+{
+ long x, y, width, height;
+
+ fprintf (stderr, "Testing component...\n");
+
+ AccessibleComponent_getExtents (
+ component, &x, &y, &width, &height, SPI_COORD_TYPE_SCREEN);
+
+ AccessibleComponent_getPosition (
+ component, &x, &y, SPI_COORD_TYPE_SCREEN);
+
+ AccessibleComponent_getSize (component, &width, &height);
+
+ if (width > 0 && height > 0) {
+#ifdef FIXME
+ Accessible *accessible, *componentb;
+#endif
+
+ g_assert (AccessibleComponent_contains (
+ component, x, y, SPI_COORD_TYPE_SCREEN));
+
+ g_assert (AccessibleComponent_contains (
+ component, x + width - 1, y, SPI_COORD_TYPE_SCREEN));
+
+ g_assert (AccessibleComponent_contains (
+ component, x + width - 1, y + height - 1,
+ SPI_COORD_TYPE_SCREEN));
+
+#ifdef FIXME
+ accessible = AccessibleComponent_getAccessibleAtPoint (
+ component, x, y, SPI_COORD_TYPE_SCREEN);
+
+ g_assert (Accessible_isComponent (accessible));
+ componentb = Accessible_getComponent (accessible);
+ g_assert (componentb == component);
+
+ AccessibleComponent_unref (componentb);
+ Accessible_unref (accessible);
+#endif
+ }
+
+ AccessibleComponent_getLayer (component);
+ AccessibleComponent_getMDIZOrder (component);
+/* AccessibleComponent_grabFocus (component); */
+}
+
+static void
+test_image (AccessibleImage *image)
+{
+ char *desc;
+ long int x = -1, y = -1, width = -1, height = -1;
+
+ desc = AccessibleImage_getImageDescription (image);
+ g_assert (desc != NULL);
+ SPI_freeString (desc);
+
+ AccessibleImage_getImagePosition (image, &x, &y,
+ SPI_COORD_TYPE_SCREEN);
+ AccessibleImage_getImageSize (image, &width, &height);
+ AccessibleImage_getImageExtents (image, &x, &y, &width, &height,
+ SPI_COORD_TYPE_WINDOW);
+}
+
+static void
+validate_tree (Accessible *accessible,
+ gboolean has_parent,
+ gboolean recurse_down)
+{
+ Accessible *parent;
+ long len, i;
+
+ parent = Accessible_getParent (accessible);
+ if (has_parent) {
+ long index;
+ Accessible *child_at_index;
+
+ g_assert (parent != NULL);
+
+ index = Accessible_getIndexInParent (accessible);
+ g_assert (index >= 0);
+
+ child_at_index = Accessible_getChildAtIndex (parent, index);
+
+ g_assert (child_at_index == accessible);
+
+ Accessible_unref (child_at_index);
+ Accessible_unref (parent);
+ }
+
+ len = Accessible_getChildCount (accessible);
+ print_tree_depth++;
+ for (i = 0; i < len; i++) {
+ Accessible *child;
+
+ child = Accessible_getChildAtIndex (accessible, i);
+#ifdef ROPEY
+ if (!child)
+ fprintf (stderr, "Unusual - ChildGone at %ld\n", i);
+
+ g_assert (Accessible_getIndexInParent (child) == i);
+ g_assert (Accessible_getParent (child) == accessible);
+#endif
+
+ if (recurse_down && child)
+ validate_accessible (child, has_parent, recurse_down);
+
+ Accessible_unref (child);
+ }
+ print_tree_depth--;
+}
+
+static void
+validate_accessible (Accessible *accessible,
+ gboolean has_parent,
+ gboolean recurse_down)
+{
+ Accessible *tmp;
+ char *name, *descr;
+ AccessibleRole role;
+ AccessibleRelation **relations;
+ char *role_name;
+ GString *item_str = g_string_new ("");
+ int i;
+
+ name = Accessible_getName (accessible);
+ g_assert (name != NULL);
+
+ descr = Accessible_getDescription (accessible);
+ g_assert (descr != NULL);
+
+ role = Accessible_getRole (accessible);
+ g_assert (role != SPI_ROLE_INVALID);
+ role_name = Accessible_getRoleName (accessible);
+ g_assert (role_name != NULL);
+
+ relations = Accessible_getRelationSet (accessible);
+ g_assert (relations != NULL);
+
+ for (i = 0; relations [i]; i++) {
+ AccessibleRelationType type;
+ int targets;
+
+ fprintf (stderr, "relation %d\n", i);
+
+ type = AccessibleRelation_getRelationType (relations [i]);
+ g_assert (type != SPI_RELATION_NULL);
+
+ targets = AccessibleRelation_getNTargets (relations [i]);
+ g_assert (targets != -1);
+
+ AccessibleRelation_unref (relations [i]);
+ relations [i] = NULL;
+ }
+ free (relations);
+
+ if (print_tree) {
+ int i;
+
+ for (i = 0; i < print_tree_depth; i++)
+ fputc (' ', stderr);
+ fputs ("|-> [ ", stderr);
+ }
+
+ if (Accessible_isAction (accessible)) {
+ tmp = Accessible_getAction (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "At");
+ else
+ test_action (tmp);
+ AccessibleAction_unref (tmp);
+ }
+
+ if (Accessible_isApplication (accessible)) {
+ tmp = Accessible_getApplication (accessible);
+ if (print_tree)
+ fprintf (stderr, "Ap");
+ else
+ test_application (tmp);
+ AccessibleApplication_unref (tmp);
+ }
+
+ if (Accessible_isComponent (accessible)) {
+ tmp = Accessible_getComponent (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Co");
+ else
+ test_component (tmp);
+ AccessibleComponent_unref (tmp);
+ }
+
+ if (Accessible_isEditableText (accessible)) {
+ tmp = Accessible_getEditableText (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Et");
+ else
+ test_editable_text (tmp);
+ AccessibleEditableText_unref (tmp);
+ }
+
+ if (Accessible_isHypertext (accessible)) {
+ tmp = Accessible_getHypertext (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Ht");
+ AccessibleHypertext_unref (tmp);
+ }
+
+ if (Accessible_isImage (accessible)) {
+ tmp = Accessible_getImage (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree) {
+ char *desc;
+
+ fprintf (stderr, "Im");
+
+ desc = AccessibleImage_getImageDescription (tmp);
+ g_string_append_printf (
+ item_str, " image descr: '%s'", desc);
+ SPI_freeString (desc);
+ } else
+ test_image (tmp);
+
+ AccessibleImage_unref (tmp);
+ }
+
+ if (Accessible_isSelection (accessible)) {
+ tmp = Accessible_getSelection (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Se");
+ AccessibleSelection_unref (tmp);
+ }
+
+ if (Accessible_isTable (accessible)) {
+ tmp = Accessible_getTable (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Ta");
+ else
+ test_table (tmp);
+ AccessibleTable_unref (tmp);
+ }
+
+ if (Accessible_isText (accessible)) {
+ tmp = Accessible_getText (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Te");
+ else {
+ if (strcmp (name, TEST_STRING_A_OBJECT) == 0)
+ test_text (tmp);
+ }
+ AccessibleText_unref (tmp);
+ }
+
+ if (Accessible_isValue (accessible)) {
+ tmp = Accessible_getValue (accessible);
+ g_assert (tmp != NULL);
+ if (print_tree)
+ fprintf (stderr, "Va");
+ else
+ test_value (tmp);
+ AccessibleValue_unref (tmp);
+ }
+
+ if (print_tree)
+ fprintf (stderr, " ] '%s' (%s) - %s: %s\n",
+ name, descr, role_name, item_str->str);
+
+ SPI_freeString (name);
+ SPI_freeString (descr);
+ SPI_freeString (role_name);
+ g_string_free (item_str, TRUE);
+
+ validate_tree (accessible, has_parent, recurse_down);
+}
+
+static void
+test_misc (void)
+{
+ fprintf (stderr, "Testing misc bits ...\n");
+
+ g_assert (!Accessible_isComponent (NULL));
+ g_assert (Accessible_getComponent (NULL) == NULL);
+ SPI_freeString (NULL);
+}
+
+static void
+global_listener_cb (const AccessibleEvent *event,
+ void *user_data)
+{
+ TestWindow *win = user_data;
+ Accessible *desktop;
+ AccessibleApplication *application;
+
+ g_assert (win->magic == WINDOW_MAGIC);
+ g_assert (!strcmp (event->type, "focus:"));
+
+ fprintf (stderr, "Fielded focus event ...\n");
+
+ if (!do_poke) {
+ desktop = SPI_getDesktop (0);
+ application = Accessible_getChildAtIndex (desktop, 0);
+ g_assert (application != NULL);
+ Accessible_unref (desktop);
+
+ test_application (application);
+
+ AccessibleApplication_unref (application);
+
+ print_tree = FALSE;
+
+ validate_accessible (event->source, TRUE, TRUE);
+
+ fprintf (stderr, "quitting mainloop.\n");
+ gtk_main_quit ();
+ }
+
+ print_tree = TRUE;
+ validate_accessible (event->source, TRUE, TRUE);
+}
+
+static SPIBoolean
+key_listener_cb (const AccessibleKeystroke *stroke,
+ void *user_data)
+{
+ AccessibleKeystroke *s = user_data;
+
+ *s = *stroke;
+ if (stroke->keystring) s->keystring = g_strdup (stroke->keystring);
+
+ if (s->type == SPI_KEY_PRESSED)
+ key_press_received = TRUE;
+ else if (s->type == SPI_KEY_RELEASED)
+ key_release_received = TRUE;
+
+ return TRUE;
+}
+
+
+static void
+test_keylisteners (void)
+{
+ int i;
+ AccessibleKeystroke stroke;
+ AccessibleKeystrokeListener *key_listener;
+ AccessibleKeySet *test_keyset;
+
+ fprintf (stderr, "Testing keyboard listeners ...\n");
+
+ key_listener = SPI_createAccessibleKeystrokeListener (
+ key_listener_cb, &stroke);
+
+ test_keyset = SPI_createAccessibleKeySet (1, "=", NULL, NULL);
+
+ g_assert (SPI_registerAccessibleKeystrokeListener (
+ key_listener,
+ test_keyset,
+ 0,
+ SPI_KEY_PRESSED | SPI_KEY_RELEASED,
+ SPI_KEYLISTENER_CANCONSUME | SPI_KEYLISTENER_ALL_WINDOWS));
+
+ for (i = 0; i < 3; i++) {
+ memset (&stroke, 0, sizeof (AccessibleKeystroke));
+ g_assert (SPI_generateKeyboardEvent ('=', NULL, SPI_KEY_SYM));
+ while (!(key_press_received))
+ g_main_context_iteration (NULL, TRUE);
+ fprintf (stderr, "p [%s]", stroke.keystring);
+ g_assert (!strcmp (stroke.keystring, "="));
+ while (!(key_release_received))
+ g_main_context_iteration (NULL, TRUE);
+ fprintf (stderr, "r [%s]", stroke.keystring);
+ key_press_received = FALSE;
+ key_release_received = FALSE;
+ }
+ g_assert (SPI_deregisterAccessibleKeystrokeListener (key_listener, 0));
+ SPI_freeAccessibleKeySet (test_keyset);
+
+ fprintf (stderr, "\n");
+
+ AccessibleKeystrokeListener_unref (key_listener);
+
+ g_assert (SPI_generateMouseEvent (100, 100, "rel"));
+ g_assert (SPI_generateMouseEvent (-50, -50, "rel"));
+ g_assert (SPI_generateMouseEvent (-50, -50, "rel"));
+ g_assert (SPI_generateMouseEvent (-1, -1, "b1c"));
+}
+
+int
+main (int argc, char **argv)
+{
+ int leaked, i;
+ TestWindow *win;
+ const char *modules;
+ AccessibleEventListener *global_listener;
+
+ modules = g_getenv ("GTK_MODULES");
+ if (!modules || modules [0] == '\0')
+ putenv ("GTK_MODULES=gail:atk-bridge");
+ modules = NULL;
+
+ for (i = 1; i < argc; i++) {
+ if (!g_strcasecmp (argv [i], "--poke"))
+ do_poke = TRUE;
+ }
+
+ gtk_init (&argc, &argv);
+
+ g_assert (!SPI_init ());
+ g_assert (SPI_init ());
+ g_assert (SPI_getDesktopCount () == 1);
+
+ test_roles ();
+ test_misc ();
+ test_desktop ();
+ test_keylisteners ();
+
+ win = create_test_window ();
+
+ global_listener = SPI_createAccessibleEventListener (global_listener_cb, win);
+
+ g_assert (SPI_registerGlobalEventListener (global_listener, "focus:"));
+
+ fprintf (stderr, "Waiting for focus event ...\n");
+ gtk_main ();
+
+ g_assert (SPI_deregisterGlobalEventListenerAll (global_listener));
+ AccessibleEventListener_unref (global_listener);
+
+ test_window_destroy (win);
+
+ /* Wait for any pending events from the registry */
+ g_usleep (500*1000);
+ for (i = 0; i < 100; i++)
+ dbus_connection_read_write_dispatch (SPI_bus(), 5);
+
+ if ((leaked = SPI_exit ()))
+ g_error ("Leaked %d SPI handles", leaked);
+
+ g_assert (!SPI_exit ());
+
+ fprintf (stderr, "All tests passed\n");
+
+ if (g_getenv ("_MEMPROF_SOCKET")) {
+ fprintf (stderr, "Waiting for memprof\n");
+ gtk_main ();
+ }
+
+ putenv ("AT_BRIDGE_SHUTDOWN=1");
+
+ return 0;
+}