pax_global_header00006660000000000000000000000064126230725440014517gustar00rootroot0000000000000052 comment=62bd54bcde3c0d79337a0eb7361ff6d7375bc73c maliit-framework-0.99.1+git20151118+62bd54b/000077500000000000000000000000001262307254400175375ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/.gitignore000066400000000000000000000002401262307254400215230ustar00rootroot00000000000000core *-stamp Makefile doxygen.log* .moc .obj *.a *.so *.so.* *.o moc_* gen_* *.swp *~ *.pro.user *.gcov *.gcda *.gcno /meego-im-framework.schemas *.tar.* *.md5 maliit-framework-0.99.1+git20151118+62bd54b/INSTALL.local000066400000000000000000000030011262307254400216530ustar00rootroot00000000000000LOCAL BUILD, INSTALL AND RUN Gtk+ paths and executable names may differ between distros and architectures, check them on your own. The description below was tested on Fedora 15 (Lovelock) 64-bit. # framework build 1. export GCONF_CONFIG_SOURCE="xml:merged:$HOME/.gconf/gconf.xml.defaults" 2. cd maliit-framework 3. qmake-qt4 -r CONFIG+=local-install PREFIX="$HOME/maliit-local" LIBDIR="$HOME/maliit-local/lib64" CONFIG+=disable-gtk-cache-update 4. make -j4 # framework install 5. make install 6. export LD_LIBRARY_PATH="$HOME/maliit-local/lib64" 7. GTK_PATH="$HOME/maliit-local/lib64/gtk-2.0" /usr/bin/gtk-query-immodules-2.0-64 >"$HOME/maliit-local/lib64/gtk-2.0/2.10.0/gtk.immodules" 8. GTK_PATH="$HOME/maliit-local/lib64/gtk-3.0" /usr/bin/gtk-query-immodules-3.0-64 >"$HOME/maliit-local/lib64/gtk-3.0/3.0.0/gtk.immodules" # plugins build 9. cd ../maliit-plugins 10. export QMAKEFEATURES="$HOME/maliit-local/mkspecs/features" 11. qmake-qt4 -r 12. make -j4 # plugins install 13. make install # server run 14. "$HOME/maliit-local/bin/maliit-server" & # qt app run 15. export QT_PLUGIN_PATH="$HOME/maliit-local/plugins" 16. QT_IM_MODULE=Maliit "$HOME/maliit-local/bin/maliit-exampleapp-plainqt" # gtk2 app run 17. GTK_IM_MODULE_FILE="$HOME/maliit-local/lib64/gtk-2.0/2.10.0/gtk.immodules" GTK_IM_MODULE=Maliit "$HOME/maliit-local/bin/maliit-exampleapp-gtk2" # gtk3 app run 18. GTK_IM_MODULE_FILE="$HOME/maliit-local/lib64/gtk-3.0/3.0.0/gtk.immodules" GTK_IM_MODULE=Maliit "$HOME/maliit-local/bin/maliit-exampleapp-gtk3" maliit-framework-0.99.1+git20151118+62bd54b/LICENSE.LGPL000066400000000000000000000622331262307254400213070ustar00rootroot00000000000000GNU Lesser General Public License Version 2.1, February 1999 Copyright (C) 1991, 1999 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 Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] 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 Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these 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 other code 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. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. 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, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) 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. d) 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. e) 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 materials to be 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 with 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 Lesser 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. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 maliit-framework-0.99.1+git20151118+62bd54b/NEWS000066400000000000000000001077701262307254400202520ustar00rootroot000000000000000.99.1 ====== CHANGES SINCE 0.99.0 * Introduced Qt5 input context, replacing the one provided by Qt. Can be enabled by CONFIG+=qt5-inputcontext * Move maliit-glib from GTK+ input context package back into frameowrk * Use GDBus in maliit-glib * Allow plugin window reactive area and input method area reported to application differ * Fix window state to have transient hint and window type as with Maliit 0.8x * Made the dependency from xcb optional * Added a CONFIG option to disable the hardware keyboard BUG FIXES * Clear preedit state on input context reset * Reshow virtual keyboard when hardware keyboard disappears * Fix bugs with Qt 5.3, Qt 5.4 and Qt 5.5 0.99.0 ====== CHANGES SINCE 0.94.0 * Requires Qt 5 * GTK+ and Qt 4 input context are moved into a separate rpository/package * Do not use debug config for unit tests * Do not abort if there are no plugins. * Improvements for QML plugins - Notify qml keyboard when editor target focus changes - Expose editor state better to QML input methods - Replace correctionEnabled with predictionEnabled in qml interface - Enhanced QML interface event sending * Use QScreen::availableSize to calculate screenSize * Add window group class managing plugins' QWindows - Replaces surface abstraction * Remove CONFIG options - disable-background-translucency - disable-dbus - enable-qdbus - noqml * Remove MIndicatorServiceClient * Use QDBus instead of glib-dbus * Remove unused code * Update Wayland support to latest protocol changes * Add support for input region also on wayland * Add a proper Platform class * Remove unneeded plugin factories BUG FIXES * Fix some quick input method docs a bit. * Fix build when building without CONFIG+=wayland * Fix build with CONFIG+=wayland. * Fix unused parameter warning. * Fix minputmethodquickplugin test for Qt 5 * Fix private include and use QT+=gui-private * Fix some QDBus issues. * Fix plugins windows are never added to WindowGroup * Fix showing of nemo-keyboard * Fix qdbus interface and adaptor generation 0.94.0 ====== CHANGES SINCE 0.93.1 * Add Wayland input method support * Auto-detect subviews based on system locale - If no configuration exists, Maliit uses LANGUAGE to guess plugin's subview(s). * Don't write user configuration to disk for default values - Only write *actual* user configuration that's different from factory defaults. * Remove version suffix from libraries and install directories - Affects packaging & {header, .pc , .prf} install directories * Adjust to Qt 5.0.0 API changes * Add surface support for QtQuick2 * Remove SDK - It was pretty much unmaintained. 0.93.1 ====== CHANGES SINCE 0.93.0 * Use QtQtuick2 when compiling against Qt5 - Only affects QML plugins such as Nemo Keyboard. BUG FIXES * Fixes: MALIIT#194 - Maliit can not input when QML viewer is set to full screen on QWS without x11 * Fixes: MALIIT#197 - Read initial SW_TABLET_MODE state correctly * Fix qmake warnings about using CONFIG+=qdbus * Fix qmake warnings about using deprecated IN_PWD variables 0.93.0 ====== CHANGES SINCE 0.92.5 * Monitor SW_TABLET_MODE to determine hardware keyboard presence - A new, default implementation for MImHwKeyboardTracker: we look for a readable evdev device which has a SW_TABLET_MODE switch. If found, we use that device for determining the presence/availability of the hardware keyboard. * Allow QML plugins to send key events: - Use MInputMethodQuick.sendKey() BUG FIXES * Fix focus handling for Qt5 * Fix the build when disabling GTK+ support * Fix QML plugin loading for Qt5 * Fix "fullscreen" surfaces (required by QtQuick still): - Events can be passed through to application again even if input method with a semi-translucent "fullscreen" surface is shown. 0.92.5 ====== CHANGES SINCE 0.92.4 * Allow to disable GTK+ support: - Use qmake CONFIG+=nogtk to disable building the GTK+ input context module and the glib-based application support libraries. * New "disable-background-translucency" option to workaround VKB's garbled visuals on non-compositing WMs. Use CONFIG+=disable-background-translucency. * Make maliit-framework compile against Qt 5 beta release. BUG FIXES * Fixes: MALIIT#188 - maliit-server forgets active subview * Fixes: MALIIT#183 - Can not rotate the keyboard 0.92.4 ====== CHANGES SINCE 0.92.3 * GConf settings backend removed. This backend was deprecated in previous release, 0.92.3. Settings applications and other wishing to manipulate Maliit setting entries should use the libmaliit (Qt) or maliit-glib APIs. * There is a change in the DBus interfaces to support invoking actions on application side (beside just copy and paste). A invokeAction was added to the com.meego.inputmethod.uiserver1 interface. The copy and paste methods were removed from the com.meego.inputmethod.inputcontext1 interface. BUG FIXES * Fixes: Extensions overrides are not registered for the first time. * Fixes: Input context plugin does not load. 0.92.3 ====== CHANGES SINCE 0.92.2.1 * GConf settings backend deprecated. The default backend is now QSettings. GConf backend can be enabled using CONFIG+=enable-gconf, but will be removed in 0.92.4 * Add maliit-exampleapp-settings-python3, a Python + maliit-glib based command-line application for settings. Is also useful while developing to configure settings. 0.92.2.1 ======== CHANGES SINCE 0.92.2 * Revert to old install prefix behavior (<=0.92.1). By default the install prefix for files extending GTK+, Qt, gconf follows what the respective system component reports. For installing not system-wide, use CONFIG+=local-install. See INSTALL.local for details. This is equivalent to the old CONFIG+=enforce-install-prefix option. 0.92.2 ====== CHANGES SINCE 0.92.1 * Use common environment variables to configure install behaviour of framework files. - Use PREFIX to specify install prefix and LIBDIR ($PREFIX/lib, by default) to specify library install directory (for example /usr/lib64 on x64, for Fedora systems). All other M_IM_INSTALL_SOMETHING variables have been changed to SOMETHINGDIR. Use qmake HELP=1 to see the configure options. * Rename M_IM_DEFAULT_* environment variables for default plugin configuration to MALIIT_DEFAULT_*. * Add settings API to maliit-glib, too. * Add plugin settings API: - Plugins can export their settings to applications via the settings API, see the settings example for more. BUG FIXES * Fixes: Some examples and tests fail to link. * Fixes: Settings are not propagated to plugins in some cases. * Fixes: MALIIT#169 - Custom install prefix not respected for GTK, QT input context plugins * Fixes: MALIIT#57 - Remove prefix from M_IM_* configure variables 0.92.1 ====== CHANGES SINCE 0.92.0 * Added settings API - Added client API in libmaliit to enumarate and update settings - Allow changing enabled/active Maliit plugins * Changed the format for onscreen/enabled and onscreen/active settings: onscreen/active is a single string with format : (es. "libmaliit-keyboard-plugin.so:en_gb") and onscreen/enabled is a list of strings in the same format as onscreen/active * Added libmaliit-glib - Allows GTK+ applications to control certain features of the input method directly (currently show/hide, but feature parity with libmaliit is the goal). - Uses gtk-doc instead of doxygen (which is normally used in framework), but will also be disabled when using CONFIG+=nodoc. - Comes with GObject instrospection. As a proof-of-concept, there's a GTK+ Python demo app that can explicitly show and hide the virtual keyboard. See examples/apps/gtk3-python for more. BUG FIXES * Fixes: MALIIT#127 - Add settings API, as an integration point for settings applets * Fixes library dependencies for tests linked to plugins * Fix commit-string signal in connection-glib * Fixes: MALIIT#140 - Add method to explicit show/hide the keyboard to libmaliit-glib * Fixes OOT build by using extra compilers instead of targets * Add maliit-glib to PKG_CONFIG path of sdk * Fixes: MALIIT#144 - Empty region reported by inputMethodAreaChanged * Remove INSTALLs from tests.pro * Fixes: MALIIT#67 - Keyboard does not auto-show after a few auto hides * Fixes: warning during qmake's run about unknown quick1. * Fix position of overlay surfaces after rotation * Fix geometry of surfaces after screen size change * Fix WindowedSurface::relativePosition() * Fix AbstractSurfaceFactory's screen size API 0.92.0 ====== CHANGES SINCE 0.91.0 * Update maliit plugin interface from 0.80 to 1.0 * Add surfaces API for abstracting window/widget management for plugins - Add surfaces implementation for windowed widgets * Removed legacy support for MeeGo Harmattan: - Remove Toolbar API - Remove legacy minputmethodnamespace.h * Cleanup plugin API: - Rename MInputMethodPlugin to InputMethodPlugin - Remove MAbstractInputMethodSettings - Remove InputMethodPlugin::languages() - Remove MImWidget and MImGraphicsView - Move plugin headers and sources to maliit/plugins - Remove unused parameter from MAbstractInputMethod - Remove unused widget parameters from InputMethods * Add config switch to enable QtDBus implementation - Use qmake CONFIG+=enable-qdbus to enable the QtDBus based DBus connection backend * Add backend for QSettings backed by temporary file BUG FIXES * Fixes: MALIIT#118 - Child surfaces need to be working correctly * Fixes: MALIIT#117 - Window surfaces need to be transient to the application window * Fixes: MALIIT#101 - Allow to build without QtDbus (for non-*nix platforms) * Fixes: MALIIT#23 - Maliit should work without a compositing window manager under X11 * Fixes: MALIIT#20 - Ubuntu's login screen (lightdm) is completely black apart from the Maliit keyboard * Fix unused parameter warning * Fix clipping bug * Fix compile error on Arch Linux current * Fix warning when creating sdk * Fix MAttributeExtensionId module * Explicitly link to libmaliit-connection * Add dependency in maliit-plugins pkg-config file * Use .pri files in ut_minputmethodquickplugin * Fix maliit-plugins pkg-config dependencies * Fix include path in maliit-plugins.prf 0.91.0 ====== CHANGES SINCE 0.90.0 * Removed legacy support for MeeGo Harmattan: - CONFIG+=enable-legacy removed, - No longer uses MeeGo graphics system, - No longer reads GConf configuration under /meegotouch/inputmethods, - No longer installs meego-im-uiserver, - No longer uses /usr/lib/meego-im-plugins for Maliit plugins * Allow to run Maliit server and plugins in application process: - See examples/apps/embedded or examples/apps/server-embedded. The former uses a special input context that will load the server, MaliitDirect, whereas the second example shows how to load the server directly, without the special input context. * Clean up tests to use minimal dependencies: - Same as with maliit-keyboard in plugins repo, most tests should be able to run without QtGui or QWidget dependencies. * Experimental QtDBus support * Add preedit supoprt for GTK+ applications * Improve Windows build BUG FIXES * Fix ft_exampleplugin on Qt 5 * Fix ut_minputcontextplugin not finding libmaliit-qt4.so * Fix dependency issues for make check * Fixed build error caused by commit "Split the DBus and direct Qt4 input context plugins.". 0.90.0 ====== CHANGES SINCE 0.81.3 * Allow pluggable backends to store maliit-server settings. * Added a compilation option to disable the GConf settings backend, using QSettings as a fallback. * Notify applications when attribute extensions are changed by Maliit plugins - Typical use case would be buttons in an input method toolbar, where the application needs to know about the button state. * New connection directory to isolate all D-Bus dependend code - This will make it easier to use other IPCs (or no IPC at all, in case the application hosts the input method system) in the future. * Introduce -h/--help parameter to maliit-server - When giving invalid parameters to maliit-server, it will complain and print a useful help message. BUG FIXES * Fixes: MALIIT#88 - Remove hard dependency on GConf * Fixes: NB#298678 - (Regression): Alphabetical VKB shown automatically in "Change security code"-view * Fixes: Maliit#92 - maliit-server does not take a -help/-h argument * Fixes: NB#298276 - Observed im-ui-server crashes on CITA * Fixes: NB#298229 - PIN query appears black for several seconds during startup * Fixes: NB#296576 Vkb is not shown in text field, when swype keyboard is enabled & disabled in a scenario * Fixes: Maliit#68 - maliit-server does not always notify IC about InputMethodArea changes * Fixes: NB#295883 - All input methods are still installed after tapping the emergency keyboard button in the device lock screen and typing the lock code on system startup 0.81.3 ====== CHANGES SINCE 0.81.2 * DBus activation for maliit-server now optional. Pass CONFIG+=disable-dbus-activation to qmake to disable. Use this option when using a system/session manager (like systemd) to start and keep maliit-server alive * Improved support for Qt Embedded (QWS) * Make framework compile on older platforms - With the fix of MALIIT#14, latest version of framework will now compile on Maemo Fremantle again (might require skipping the tests still). BUG FIXES * Fixes: MALIIT#14 - Maliit requires glib/gio 2.26+ * Fixes: MALIIT#73 - Make dbus-x11 an optional dependency * Fixes: Use the QPA platform implementation when compiling for Qt Embedded (QWS). * Fixes: do not use X11 plugin host implementation for Qt Embedded (QWS). * Fixes: Use correct qmake binary when creating SDK 0.81.2 ====== CHANGES SINCE 0.81.1 * M_IM_DEFAULT[_HW]_PLUGIN configuration variables available to set default plugins (and also plugin subview) at configure time. See qmake HELP=1 for more. BUG FIXES * Fixes: Add missing header to plainqt example application for Qt 4.8 * Fixes: SDK creation fails if libmaliit is not installed * Fixes: Docs/SDK installed to wrong location if destination directory exists * Fixes: SDK example applications fails in legacy-mode * Fixes: NEMO#14 - VKB opens even if HWKB is already open * Fixes: Crash happening during initiated hide in Gtk+ app. * Fixes: enforce-install-prefix for legacy mode * Fixes: Copy/paste error in GTK+ 2 im cache update for Fedora 0.81.1 ====== CHANGES SINCE 0.81.0 * Plugins can store plugin data such as graphical assets in /usr/share/maliit/plugins/. The prefix can be queried through "$ pkg-config --variable pluginsdatadir maliit-plugins-0.80". * Standardized logging output on Maliit server and Qt and Gtk+ input contexts. - Debug output is enabled with setting the environment variable MALIIT_DEBUG to enabled (MALIIT_DEBUG=enabled). - Old environment variable MIC_ENABLE_DEBUG is not supported any longer. * Use a static, non-installed lib for common GTK+ IC code. * Framework and examples can be compiled with Qt 5. BUG FIXES * Fixes: MALIIT#48 - It is possible to have more than one maliit-server per session * Fixes: MALIIT#31 - On closing IM with GTK+ applications, user has to unfocus manually to be able to invoke IM again * Fixes: MALIIT#33 - maliit-sdk make clean fix and .obj/.moc removal * Fixes: MALIIT#16 - root owned directory ./sdk/build/maliit-sdk is created on make install * Fixes: NB#286366 - libmeegoimframework-dev package is incomplete * Fixes: QML helloworld plugin build failure * Fixes: ut_selfcompositing fails on buildbot * Fix GTK+ IC build for out-of-tree builds * Fixes: Ut_MInputContext::testCopyPasteState() failing if clipboard has text at test start * Fixes: MALIIT#17 - Qt input-context crashes if using GtkStyle and have GTK+ input-context enabled * Fix build for MImQPAPlatform * Fix missing QApplication include in case of non X11 platform. * Fixes: Missing linker directory in ut_minputmethodquickplugin 0.81.0 ====== CHANGES SINCE 0.80.8 * D-Bus activation for maliit-server - An application can launch a maliit-server instance via D-Bus activation; use MALIIT_SERVER_ARGUMENTS when building maliit-server to specify additional arguments. Check src/org.maliit.server.service for currently configured arguments. - Each user session can run its own maliit-server now. * Plain QML file loading support for QML-based input methods - Install main QML file into plugins directory and set the GConf keys in /maliit/onscreen/[active,enabled] to that file. * Improved documentation - Stand-alone application and plugins examples are installed by default - A maliit-sdk executable can be used to extract examples and to view documentation. BUG FIXES * Fixes: Building example applications stand-alone * Fixes: NB#291062 - Regression: QML Components Gallery, Text Input, Sip Attributes Example failed. 0.80.8 ====== CHANGES SINCE 0.80.7 * Merge GTK+ input context bridge from https://gitorious.org/meegotouch-inputmethodbridges into Maliit - Use GTK_IM_MODULE=Maliit to activate the input context. * Improved GTK+ support - GTK+ applications now properly reconnect when the connection to the Maliit server was lost or when the Maliit server was started after the application. - By default, update GTK+ inputmethod module cache. Packagers might want to override this at configure time via qmake CONFIG+=disable-gtk-cache-update * Forward all Qt inputmethod hints to Maliit plugins, via MImUpdateEvent::hints(). * Allow applications to control whether symbol view or QWERTY view should be shown when a text entry gains focus (check widgetproperties example): - Set the Qt::ImPreferNumbers inputmethod hint. * Add a translucent inputmethod mode (check widgetproperties example): - Use QObject::setProperty(Maliit::InputMethodQuery::translucentInputMethod, true|false) * New MImUpdateReceiver class demonstrates a Qt property technique for plugins to cleanly process MImUpdateEvents. BUG FIXES * Fixes: Compilation warnings in GTK+ IC * Fixes: Wrong upchaining in meego_imcontext_finalize * Fixes: GTK+ IC crashes if server is not started on app startup * Fixes: NB#284151 - [TASK] ImhPreferNumbers does not open page 2 on virtual keyboard * Fixes: GTK+ input context not showing plugin * Fixes: MPreeditInjectionEvent compatibility * Fixes: activeConnection uninitialized in MInputContextConnection * Fixes: Crash in Server->IC connection due to wrong upchaining * Fixes: Wrong values are shown when both label and icon are overriden. 0.80.7 ====== CHANGES SINCE 0.80.6 * Improved QPA (Qt Lighthouse) support * New MImUpdateEvent: Instead of forcing plugins to poll data from MAbstractInputMethodHost after each update, they can now choose to handle this MImExtensionEvent. MImUpdateEvent informs about the changes (through its propertiesChanged list) and allows extraction of updates through its value method. * More dynamic key override examples. * Bring dynamic key overrides to QML plugins. * Let QObject properties override input method queries. This allows more consistent integration with QML Componeents and plain Qt apps. BUG FIXES * Fixes: Let IM properties on QObjects override IM queries * Fixes: Label and icons are both shown at the same time. * Fixes: LD_LIBRARY_PATH for tests does not contain input-method-quick * Fixes: Lookup of data files causes make check to fail in out-of-tree build * Fixes: Plugins get an empty map when focus is switched. * Fixes: Action key label does not change back in QtQuick override plugin. * Fixes: Action key label does not change back in C++ override plugin. * Fixes: Documentation was not installed. * Fixes: Extension attributes are not registered after input context creation. * Fix unredirecting in self-compositing mode * Fixes: Server sometimes crashes in dbus connection 0.80.6 ====== CHANGES SINCE 0.80.5 * Server can build against Qt 4.8 with Lighthouse and run under Wayland * Legacy mode config option changed to enable-legacy instead of enable-meegotouch. Enable with: $ qmake -r CONFIG+=enable-legacy* Support hardware keyboard handling for Qt Quick plugins * Removed deprecated support for integrating with input methods via LMT/meegotouch directly. LMT/meegotouch uses libmaliit for that now. * Track hardware keyboard status on Fremantle (N900) * New MAbstractInputMethodHost::setLanguage(QString) API - New method setLanguage added to D-Bus interface. Through this method plugins can give applications a hint of the language user is going to write. * qmake HELP=1 will now output a list of build options * Input context <-> server communication is more generic, and allows implementation of other IPC/transport mechanisms * Legacy mode and non-legacy mode now parallel installable. BUG FIXES * Fixes: Install gconf schemas on make install * Fixes: Failure to generate dbus glue files in out-of-tree build * Fixes: NB#277853 - Meego-im-uiserver crash on invalid plugin name 0.80.5 ====== CHANGES SINCE 0.80.4 * PySide bindings for Maliit Plugin API - Python plugins can now make use of the generic plugin loader found at https://github.com/renatofilho/maliit-python - together with the new plugin factory MImAbstractPluginFactory, the requirement for a Qt/C++ wrapper in the case of Python plugins has been eliminated. * New plugin switch handling - SwitchPreparationBackward, SwitchPreparationForward and SwitchCanceled, required for new panning gesture to change between plugins/subviews. * New MAbstractInputMethodHost::preeditClickPos() API: - Forwards the preedit-local coordinate to input method plugins. BUG FIXES * Fixes: NB#277834 - libmaliit seg. fault in libmeegotouch unit tests: ut_mtextedit and ut_minputmethodstate * Fixes: BMC#19298 - [FEA] Provide PySide bindings for Maliit Plugin API 0.80.4 ====== CHANGES SINCE 0.80.3 * Improved legacy support: - Applications that want to integrate with input methods can freely choose whether to use MTF/libmeegotouch or libmaliit * Improved unit tests: - Added tests for Maliit::AttributeExtension{, Registry} API - Fixed skipped unit tests - Fix tests for plugin examples * Build system: - Fix out-of-tree builds BUG FIXES * None 0.80.3 ====== CHANGES SINCE 0.80.2 * Remove Harmattan-specific settings applet * Add support for ContextKit keyboard tracker BUG FIXES * Fixes: AttributeExtensions with libmaliit 0.80.2 ====== CHANGES SINCE 0.80.1 * New libmaliit contains additional API for application developers to interact with input methods (besides Qt's input context API): - Maliit::InputMethod: Query input method area and control input method orientation, - Maliit::AttributeExtension: Allows to control input method toolbar and customization of certain virtual keyboard keys, - Maliit::PreeditInjectionEvent: Used by text entries to inject a new preedit into the input context, - Maliit namespace for all input method related enums, superseds MInputMethod namespace. * New input context name: - Use QT_IM_MODULE=Maliit for regular builds and QT_IM_MODULE=MInputContext for legacy builds. * Script for making Maliit Plugin SDK tarball. * Enabled all unit tests again. BUG FIXES * Fixes: Settings applet does not compile with enable-meegotouch * Fixes: NB#268826 0.80.1 ====== CHANGES SINCE 0.80.0 * Support for QML plugins to let user hide plugin * Legacy mode can be enabled through: $ qmake -r CONFIG+=enable-meegotouch BUG FIXES * Fixes: NB#254635, meego-im-uiserver is missing capabilities * Fixes: BMC#15415 - corrupt text-input-settings.qm * Fixes: NB#265488 - Word tracker is shown empty when the device is rotated. * Fixes: MAbstractInputMethodHost's dependency to MIMApplication * Fixes: NB#259910, CommonComboBoxIcons missing from Text input settings * Fixes: NB#259600, Order of layout information, non-tapable area and line to be removed from settings. 0.80.0 ====== CHANGES SINCE 0.20.20 * Maliit rebranding: - Libraries: - libmeegoimframework => libmaliit-plugins - libmeegoimquick => libmaliit-plugins-quick - Binaries: - meego-im-uiserver => maliit-server - Plugins install paths: - /usr/lib/meego-im-plugins => /usr/lib/maliit/plugins-x.y * Added library versioning - Allows for parallel installation of different versions * Removed internal libmeegotouch dependency - MPreeditInjectionEvent, MInputMethodState added to new experimental libmaliit * Improved build infrastructure: - Common defines for install paths, names, etc. - Better pkg-config support (whilst deprecating prf files) - Better install prefix handling through M_IM_PREFIX BUG FIXES * Fixes: BMC#18772 - meego-im-uiserver is changing the window type after it's window is mapped 0.20.11 ======= * Added support for enabling/disabling plguins and subviews. - MAbstractInputMethod::subViews() should return all subviews instead of just the enabled ones now - The new GConf keys : - /meegotouch/inputmethods/onscreen/enabled - /meegotouch/inputmethods/onscreen/active replace the old ones: - /meegotouch/inputmethods/plugins/onscreen - /meegotouch/inputmethods/virtualkeyboard/layouts - /meegotouch/inputmethods/virtualkeyboard/lastactivesubview 0.20.10 ======= * Added basic framework support for QML-based plugins: - MInputMethodQuick: A MInputMethod implementation that sets up a QML environment and exposes a MInputMethodQuick context to the QML side. - MInputMethodQuickPlugin: A ready-made plugin wrapper, to use it reimplement MInputMethodQuickPlugin::qmlFileName and MInputMethodPlugin::name. 0.20.0 ======= * Removed MeeGo Touch from public API. * Allow to build framework without MeeGo Touch (optional) - Use "$ qmake CONFIG=+nomeegotouch -r ." or "DEB_BUILD_OPTIONS=nomeegotouch". * New helper classes: - MImGraphicsView: Use this widget if your input method plugin uses QGraphicsView (or QDeclarative*). - MImWidget: Use this widget if your input method offers a tradtional QWidget-based UI. - Both widgets boost render performance of input method plugins by using the framework's latest self-compositing feature. Check their documentation for subclassing advice. Also, in case you cannot reuse these classes, you need to use MAbstractInputMethodHost::background - if null, it can be ignored. Otherwise, it needs to be drawn into the background of your central widget (assuming full-screen widgets). For QWidgets, this can be done in QWidget::paintEvent. For QGraphicsView, it is required to override QGraphicsView::drawBackground instead. - MImHwKeyboardTracker: Tracks state (open/closed) of HW keyboard (does not provide any functionality yet when framework is build without MeeGo Touch support). - MImSettings: Currently a wrapper for GConf, but supposed to be extended for GConf-less platforms. * API changes: - Removed MIMSettingsDialog (use settings applet instead). - Removed MAbstractInputMethodHost::showSettings, too. This means that IM plugins can no longer request the settings dialog. - Removed MPlainWindow. - MAbstractInputMethod: - c'tor now takes an additional QWidget parameter, the main window (top level widget) supplied by the framework. This frees plugins from using MPlainWindow. Plugins can now choose between traditonal QWidget UI's or QGraphicsView UI's (including MeeGo Touch and QML). Make sure to reparent your central widget to the main window. - centralWidget: Returns central widget of your plugin. - setCentralWidget: Sets central widget of your plugin. Important if you want to take advantage of self-composting by using MImGraphicsView or MImWidget. - MInputMethodPlugin: - createInputMethod: Takes an additional QWidget parameter, the main window. Parameter is supplied by framework. - MInputMethod namespace: - added OrientationAngle, Orientation, TextContentType (copied from MeeGo Touch) 0.19.41 ======= * API changes - MAbstractInputMethod was changed. The method handleAppOrientationChange() was renamed as handleAppOrientationChanged(), which means target application already finish changing orientation. And there was a new method handleAppOrientationAboutToChange() says target application is about to change orientation. - Added X key event time parameter to MAbstractInputMethod::processKeyEvent(). 0.19.39 ====== * API changes - New entry setOrientationAngleLocked added to input-context D-Bus interface and similar method added also to MInputContextConnection and MAbstractInputMethodHost. - Added MAbstractInputMethodHost::hiddenText() 0.19.37 ======= * API changes - MInputContextConnection was changed. Add new parameters replaceStart and replaceLength in sendPreeditString(). Add new parameters replaceStart, replaceLength and cursorPos in sendCommitString(). Add new pure virtual method setSelection(). - MAbstractInputMethodHost was changed. Add new parameters replaceStart and replaceLength in sendPreeditString(). Add new parameters replaceStart, replaceLength and cursorPos in sendCommitString(). Add new pure virtual method setSelection(). 0.19.32 ======= * API changes - Toolbar specification was changed. Add a new attibute "visible" for button. Check latest version of the specification in the file doc/src/toolbarxml.dox. - new variant of MToolbarItem::setVisible() with explicit visibility flag was added. 0.19.31 ======= * API changes - Parameters in MInputContext::updatePreedit() are changed to accept definitions of different formats for each part of preedit, and support to show cursor inside preedit. - A parameter cursorPos is added to MAbstractInputMethod::setPreedit(). - Parameters in MInputMethodHost::sendPreeditString() are changed to accept definitions of different formats for each part of preedit, and support to show cursor inside preedit. - new struct PreeditTextFormat in namespace MInputMethod which defines the text format for the preedit string. - MAbstractInputMethodHost was changed. Add a new pure virtual method cursorRectangle(). 0.19.30 ======= * API changes - Toolbar specification was changed. Add a new attibute "enabled" for button. Check latest version of the specification in the file doc/src/toolbarxml.dox. 0.19.27 ======= * API changes - MInputMethodBase was renamed to MAbstractInputMethod - MInputMethodSettingsBase was renamed to MAbstractInputMethodSettings - Removed region signal from MAbstractInputMethod and replaced them with setScreenRegion() and setInputMethodArea() in MAbstractInputMethodHost. - renamed in MAbstractInputMethod: - mouseClickedOnPreedit() -> handleMouseClickOnPreedit( - focusChanged() -> handleFocusChange() - visualizationPriorityChanged() -> handleVisualizationPriorityChange - appOrientationChanged() -> handleAppOrientationChange() - clientChanged -> handleClientChange() 0.19.26 ======== * API changes - A request type parameter was added to MInputContext::keyEvent to allow signal only and event only key events. - Similar change to MInputContextConnection::sendKeyEvent and the "keyEvent" method in DBUS interface "com.meego.inputmethod.inputcontext1". - Removed MInputContextConnection from public API and replaced it with MAbstractInputMethodHost for MInputMethodBase. - Removed some ...Requsted() signals from MInputMethodBase and replaced with methods in MAbstractInputMethodHost - Removed indicator setting from MInputMethodBase and replaced with method on MAbstractInputMethodHost. Moved the indicator enum to MInputMethod namespace. - Changed the D-Bus interface of MIMPluginManager to use meego prefix. 0.19.24 ======== * API changes - Toolbar specification was changed. Check latest version of the specification in the file doc/src/toolbarxml.dox - class MToolbarRow was removed 0.19.22 ======== * API changes - moved contents from mpreeditface.h, mimdirection.h and mimhandlerstate.h to minputmethodnamespace.h using "MInputMethod" namespace. Also renamed MInputMethodSwitchDirection -> SwitchDirection. - Moved headers out of meegotouch dir to /usr/include/meegoimframework/ 0.19.21 ======== * API changes - MInputContext::keyEvent will always emit a signal, additional parameter "signalOnly" is used to suppress delivering the KeyEvent to focused widget. - D-BUS message "keyEvent" in interface "com.meego.inputmethod.inputcontext1" has new boolean parameter to match the new parameter in MInputContext::keyEvent 0.19.20 ======== * Uses MInputMethodState signals for notifying application for real hw keyboard signals 0.19.19 ======== * API changes - Public API of MToolbarData and MToolbarRow was changed, most of methods are private now. - Source code of MToolbarRow and MToolbarLayout was moved to dedicated files, so you need to include mtoolbarrow.h and mtoolbarlayout.h if you want to use that classes. = 0.18/0.1.22 = == New == * New RPC setComposingTextInput, composingTextInput, and setModifierState to support hardware keyboard key event filtering == Changed == * Region given to DuiPassThruWindow::inputPassthrough() is not translated anymore * dui-im-context is now moved back to here * Window's properties are set during the construction of the passtrough window = 0.1.21 = == New == * DuiIMPluginManager handles different kind of input method * Selective painting is enabled == Changed == * DuiIMPluginLoader is renamed into DuiIMPluginManager with new features * DuiIMPluginManager no longer needs scene argument = 0.1.20 = == Changed == * Compilation in passthroughserver now using the library created in src, and no longer look in /usr/lib * By default now using -software, even for device usage = 0.1.19 = == New == * Unit tests are now packaged * Server is now launched from a helper script in order to "guarantee" a correct connection with DBus * XSession script is now removed and rely on the DBus service = 0.1.18 = == New == * inputMethodAreaUpdated signal to announce the changes to the input method area. This is now separated from the area sent to passthrough server. == Changed == * Further changes to reaction maps API = 0.1.17 = == Changed == * Haptics related class name changed * Support for quering pre-edit rectangle from input-context * No longer use software rendering == Fixed == * NB#141431 candidate list rotation is broken = 0.1.16 = == Changed == * Rendering method (software/hardware accelerated) is now determined in runtime (using -software argument) = 0.1.15 = == Fixed == * NB#137201 Virtual keyboard is getting closed when typing the first character = 0.1.14 = == new == * Depends on libdui 0.11 * Direct mode input is now supported * Input method server is now also a dbus service * DuiInputContext::WidgetInfo sets default values * Input-context notifies input method when it's application's orientation changes == Changed == * input-context is moved to libdui, starting on libdui 0.11 * Passthrough window is no longer shown/hidden during the region update, it is always shown all the time. == Removed == * Old unused files (css, input-context unit tests) == Fixed == * NB#130249 Virtual keyboard uses local instance of theme daemon * NB#137201 Virtual keyboard is getting closed when typing the first character = 0.1.13 = == new == * imInitiatedHide() to notify that im server wants the IM to be hidden. * Remove focus when input method is hidden. == Changed == * inputMethodShown() and inputMethodHidden are removed in favor of imInitiatedHide() * QSettings are deprecated in favor of DuiGConfItem. = 0.1.11 = == New == * inputMethodShown() to hide the navigation bar == Changed == * mouseClickedOnPreedit() now includes the rectangle of the preedit = 0.1.9 = == Changed == * Make dui-im-uiserver have its own reaction map = 0.1.8 = == New == * content type support * error correction information support * word prediction hint support * support for notifying inputmethodbase about widget visualization priority * support for enabling/disabling error correction in input context via dbus * Initial support for selective compositing. == Changed == * preedit style depends on parameters of DuiInputContext::updatePreedit = 0.1.6 = == New == * send preedit (also with attribute) on preeditinjection event = 0.1.4 = == New == * Plugin framework now use settings for specifying driver location, activated plugins and blacklisted plugins * Input context supports plain Qt application * Input context supports focus out == Changed == * Passthrough server now receives all region updates from the plugins = 0.1.3 : 2009.02.17 = == Changed == * Input method plugin is refactored * Package now contains the framework, Qt input context, and the UI server maliit-framework-0.99.1+git20151118+62bd54b/README000066400000000000000000000040011262307254400204120ustar00rootroot00000000000000Maliit Maliit provides a flexible and cross-platform input method framework. It has a plugin-based client-server architecture where applications act as clients and communicate with the Maliit server via input context plugins. The communication link currently uses D-Bus. Maliit is an open source framework (LGPL 2) with open source plugins (BSD). This is the Maliit framework. For plugins, such as virtual keyboards, see http://wiki.maliit.org/Plugins Installing Qt5 must be installed to build the Maliit framework. At a terminal, run: qmake make make install Run qmake HELP=1 to get more information about build options. Running Set Maliit as the Qt and GTK+ input context: export QT_IM_MODULE=Maliit export GTK_IM_MODULE=Maliit Start the server: maliit-server Note that a compositing window manager and a D-Bus session bus are required to use Maliit. Test with the provided example applications: maliit-exampleapp-plainqt # for Qt maliit-exampleapp-gtk2 # for Gtk2 maliit-exampleapp-gtk3 # for Gtk3 Double-tap on the input field, and an input method (usually a virtual keyboard) should be shown. Note that an input method plugin, such as the Maliit keyboard from the maliit-plugins package, must be installed for the example applications to work. Resources Wiki: http://wiki.maliit.org/ IRC: #maliit on chat.freenode.net Announcement mailing list: maliit-announce@lists.maliit.org Discussion mailing list: maliit-discuss@lists.maliit.org NETWORK TRANSPARENCY On one computer run: maliit-server -allow-anonymous -override-address tcp:host=xxx.xxx.xxx.xxx,port=yyyyy Any valid dbus address is supported. Using -allow-anonymous must only be done on a trusted network. If using a method with authentication, the -allow-anonymous flag may be dropped. On another computer: MALIIT_SERVER_ADDRESS=tcp:host=xxx.xxx.xxx.xxx,port=yyyyy export MALIIT_SERVER_ADDRESS maliit-exampleapp-plainqt (or maliit-exampleapp-gtk{2,3}) Where xxx.xxx.xxx.xxx is IP address of computer where maliit-server is ran and yyyyy is port number < 65536. maliit-framework-0.99.1+git20151118+62bd54b/VERSION000066400000000000000000000000071262307254400206040ustar00rootroot000000000000000.99.1 maliit-framework-0.99.1+git20151118+62bd54b/common/000077500000000000000000000000001262307254400210275ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/common/.gitignore000066400000000000000000000000131262307254400230110ustar00rootroot00000000000000*.pc *.prf maliit-framework-0.99.1+git20151118+62bd54b/common/common.pro000066400000000000000000000016051262307254400230430ustar00rootroot00000000000000include(../config.pri) TOP_DIR = .. TEMPLATE = lib TARGET = $$TOP_DIR/lib/maliit-common CONFIG += staticlib outputFiles(maliit-framework.pc) outputFiles(maliit-framework.prf) OTHER_FILES += \ maliit-framework.pc.in \ maliit-framework.prf.in \ FRAMEWORKHEADERSINSTALL = \ maliit/namespace.h \ maliit/settingdata.h \ HEADERS += \ $$FRAMEWORKHEADERSINSTALL \ maliit/namespaceinternal.h \ SOURCES += \ maliit/settingdata.cpp \ frameworkheaders.path += $$INCLUDEDIR/$$MALIIT_FRAMEWORK_HEADER/maliit frameworkheaders.files += $$FRAMEWORKHEADERSINSTALL install_pkgconfig.path = $${LIBDIR}/pkgconfig install_pkgconfig.files = $$OUT_PWD/maliit-framework.pc install_prf.path = $$MALIIT_INSTALL_PRF install_prf.files = $$OUT_PWD/maliit-framework.prf INSTALLS += \ frameworkheaders \ install_pkgconfig \ install_prf \ OTHER_FILES += \ libmaliit-common.pri maliit-framework-0.99.1+git20151118+62bd54b/common/libmaliit-common.pri000066400000000000000000000005071262307254400250010ustar00rootroot00000000000000# Use when a .pro file requires libmaliit-common # The .pro file must define TOP_DIR to be a relative path # to the top-level source/build directory, and include config.pri INCLUDEPATH += $$TOP_DIR/common LIBS += $$TOP_DIR/lib/$$maliitStaticLib(maliit-common) POST_TARGETDEPS += $$TOP_DIR/lib/$$maliitStaticLib(maliit-common) maliit-framework-0.99.1+git20151118+62bd54b/common/maliit-framework.pc.in000066400000000000000000000005361262307254400252360ustar00rootroot00000000000000prefix=@PREFIX@ exec_prefix=@PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: Maliit Framework Description: Maliit provides a flexible and cross platform input method framework. It is usable on all MeeGo user experiences, and in other GNU/Linux distributions as well. Version: @MALIIT_VERSION@ Cflags: -I${includedir}/@MALIIT_FRAMEWORK_HEADER@ maliit-framework-0.99.1+git20151118+62bd54b/common/maliit-framework.prf.in000066400000000000000000000001341262307254400254150ustar00rootroot00000000000000DEFINES *= @MALIIT_FRAMEWORK_FEATURE@ INCLUDEPATH *= @INCLUDEDIR@/@MALIIT_FRAMEWORK_HEADER@ maliit-framework-0.99.1+git20151118+62bd54b/common/maliit/000077500000000000000000000000001262307254400223065ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/common/maliit/namespace.h000066400000000000000000000140171262307254400244160ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_NAMESPACE_H #define MALIIT_NAMESPACE_H #include #include //! \ingroup common namespace Maliit { /*! * \brief Position of the window on the screen. */ enum Position { PositionOverlay, PositionCenterBottom, PositionLeftBottom, PositionRightBottom, }; /*! * \brief Content type for text entries. * * Content type of the text in the text edit widget, which can be used by * input method plugins to offer more specific input methods, such as a * numeric keypad for a number content type. Plugins may also adjust their * word prediction and error correction accordingly. */ enum TextContentType { //! all characters allowed FreeTextContentType, //! only integer numbers allowed NumberContentType, //! allows numbers and certain other characters used in phone numbers PhoneNumberContentType, //! allows only characters permitted in email address EmailContentType, //! allows only character permitted in URL address UrlContentType, //! allows content with user defined format CustomContentType }; /*! * \brief State of Copy/Paste button. */ enum CopyPasteState { //! Copy/Paste button is hidden InputMethodNoCopyPaste, //! Copy button is accessible InputMethodCopy, //! Paste button is accessible InputMethodPaste }; /*! * \brief Direction of plugin switching */ enum SwitchDirection { SwitchUndefined, //!< Special value for uninitialized variables SwitchForward, //!< Activate next plugin SwitchBackward //!< Activate previous plugin }; enum PreeditFace { PreeditDefault, PreeditNoCandidates, PreeditKeyPress, //!< Used for displaying the hwkbd key just pressed PreeditUnconvertible, //!< Inactive preedit region, not clickable PreeditActive //!< Preedit region with active suggestions }; enum HandlerState { OnScreen, Hardware, Accessory }; //! \brief Key event request type for \a MInputContext::keyEvent(). enum EventRequestType { EventRequestBoth, //!< Both a Qt::KeyEvent and a signal EventRequestSignalOnly, //!< Only a signal EventRequestEventOnly //!< Only a Qt::KeyEvent }; /*! * \brief The text format for part of the preedit string, specified by * start and length. * * \sa PreeditFace. */ struct PreeditTextFormat { int start; int length; PreeditFace preeditFace; PreeditTextFormat() : start(0), length(0), preeditFace(PreeditDefault) {}; PreeditTextFormat(int s, int l, const PreeditFace &face) : start(s), length(l), preeditFace(face) {}; }; namespace InputMethodQuery { //! Name of property which tells whether correction is enabled. //! \sa Maliit::ImCorrectionEnabledQuery. const char* const correctionEnabledQuery = "maliit-correction-enabled"; //! Name of property which holds ID of attribute extension. //! \sa Maliit::InputMethodAttributeExtensionIdQuery. const char* const attributeExtensionId = "maliit-attribute-extension-id"; //! Name of property which holds attribute extension. //! \sa Maliit::InputMethodAttributeExtensionQuery. const char* const attributeExtension = "maliit-attribute-extension"; //! Name of the property which overrides localized numeric input with western numeric input. //! \sa Maliit::WesternNumericInputEnforcedQuery. const char* const westernNumericInputEnforced = "maliit-western-numeric-input-enforced"; //! Name of the property which controls translucent VKB mode. const char* const translucentInputMethod = "maliit-translucent-input-method"; //! Name of the property which can suppress VKB even if focused. //! \sa Maliit::VisualizationPriorityQuery const char* const suppressInputMethod = "maliit-suppress-input-method"; } enum SettingEntryType { StringType = 1, IntType = 2, BoolType = 3, StringListType = 4, IntListType = 5 }; namespace SettingEntryAttributes { //! Name of setting entry attribute which holds the list of values that can be assigned to the entry. //! \sa Maliit::SettingsEntry const char* const valueDomain = "valueDomain"; //! Name of setting entry attribute which holds the descriptions for the values in valueDomain. //! \sa Maliit::SettingsEntry const char* const valueDomainDescriptions = "valueDomainDescriptions"; //! Name of setting entry attribute which holds the minimum valid value (inclusive) for an integer property. //! \sa Maliit::SettingsEntry const char* const valueRangeMin = "valueRangeMin"; //! Name of setting entry attribute which holds the maximum valid value (inclusive) for an integer property. //! \sa Maliit::SettingsEntry const char* const valueRangeMax = "valueRangeMax"; //! Name of setting entry attribute which holds the default value for a setting entry. //! \sa Maliit::SettingsEntry const char* const defaultValue = "defaultValue"; } } Q_DECLARE_METATYPE(Maliit::TextContentType) Q_DECLARE_METATYPE(Maliit::PreeditTextFormat) Q_DECLARE_METATYPE(QList) #endif maliit-framework-0.99.1+git20151118+62bd54b/common/maliit/namespaceinternal.h000066400000000000000000000014231262307254400261500ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef NAMESPACEINTERNAL_H #define NAMESPACEINTERNAL_H //! \internal namespace Maliit { namespace Internal { //! Name of the input method hints stored in our update map. const char* const inputMethodHints = "maliit-inputmethod-hints"; }} // namespace Internal, Maliit #endif // NAMESPACEINTERNAL_H maliit-framework-0.99.1+git20151118+62bd54b/common/maliit/settingdata.cpp000066400000000000000000000100001262307254400253100ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "maliit/settingdata.h" namespace { bool checkValueDomain(const QVariant &value, const QVariant &domain) { if (!domain.isValid()) return true; if (!domain.canConvert(QVariant::List)) return false; QVariantList domain_values = domain.toList(); return domain_values.contains(value); } bool checkValueRange(const QVariant &value, const QVariant &range_min, const QVariant &range_max) { if (!range_min.isValid() && !range_max.isValid()) return true; if (range_min.isValid()) { if (!range_min.canConvert(QVariant::Int)) return false; if (range_min.toInt() > value.toInt()) return false; } if (range_max.isValid()) { if (!range_max.canConvert(QVariant::Int)) return false; if (range_max.toInt() < value.toInt()) return false; } return true; } bool checkValueDomain(const QVariantList &values, const QVariant &domain) { if (!domain.isValid()) return true; if (!domain.canConvert(QVariant::List)) return false; const QVariantList &domain_values = domain.toList(); Q_FOREACH (const QVariant &v, values) if (!domain_values.contains(v)) return false; return true; } bool checkValueRange(const QVariantList &values, const QVariant &range_min, const QVariant &range_max) { if (!range_min.isValid() && !range_max.isValid()) return true; Q_FOREACH (const QVariant &v, values) if (!checkValueRange(v, range_min, range_max)) return false; return true; } bool checkIntList(const QVariant &value) { if (!value.canConvert()) return false; const QVariantList &values = value.toList(); Q_FOREACH (const QVariant &v, values) { QVariant copy = v; if (!v.canConvert() || !copy.convert(QVariant::Int)) return false; } return true; } } bool validateSettingValue(Maliit::SettingEntryType type, const QVariantMap attributes, const QVariant &value) { QVariant domain = attributes[Maliit::SettingEntryAttributes::valueDomain]; QVariant range_min = attributes[Maliit::SettingEntryAttributes::valueRangeMin]; QVariant range_max = attributes[Maliit::SettingEntryAttributes::valueRangeMax]; QVariant copy = value; switch (type) { case Maliit::StringType: if (!value.canConvert()) return false; if (!checkValueDomain(value, domain)) return false; break; case Maliit::IntType: if (!value.canConvert() || !copy.convert(QVariant::Int)) return false; if (!checkValueDomain(value, domain)) return false; if (!checkValueRange(value, range_min, range_max)) return false; break; case Maliit::BoolType: if (!value.canConvert()) return false; break; case Maliit::StringListType: if (!value.canConvert()) return false; if (!checkValueDomain(value.toList(), domain)) return false; break; case Maliit::IntListType: if (!checkIntList(value)) return false; if (!checkValueDomain(value.toList(), domain)) return false; if (!checkValueRange(value.toList(), range_min, range_max)) return false; break; } return true; } maliit-framework-0.99.1+git20151118+62bd54b/common/maliit/settingdata.h000066400000000000000000000036441262307254400247750ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_SETTINGDATA_H #define MALIIT_SETTINGDATA_H #include #include #include #include /*! * \brief Single configuration entry for Maliit input method plugin * * \sa Maliit::SettingsEntry */ struct MImPluginSettingsEntry { //! Human-readable description QString description; //! The attribute extension key attribute for this entry QString extension_key; //! Entry value type Maliit::SettingEntryType type; //! Current value for the configuration entry QVariant value; //! Attributes, including domain values and descriptions QVariantMap attributes; }; /*! * \brief Settings for a Maliit input method plugin */ struct MImPluginSettingsInfo { //! The language used for human-readable descriptions QString description_language; //! Internal plugin name; "server" for global configuration entries QString plugin_name; //! Human-readable plugin description QString plugin_description; //! Attribute extension id; multiple MImPluginSettingsInfo instances might share the same extension id int extension_id; //! List of configuration entries for this plugin QList entries; }; /*! * \brief Validate the value for a plugin setting entry */ bool validateSettingValue(Maliit::SettingEntryType type, const QVariantMap attributes, const QVariant &value); Q_DECLARE_METATYPE(MImPluginSettingsEntry) Q_DECLARE_METATYPE(MImPluginSettingsInfo) Q_DECLARE_METATYPE(QList) #endif maliit-framework-0.99.1+git20151118+62bd54b/config.pri000066400000000000000000000130761262307254400215270ustar00rootroot00000000000000MALIIT_VERSION = $$system(cat $$PWD/VERSION) MALIIT_ABI_VERSION = $$MALIIT_VERSION # For libmaliit MALIIT_LIB = maliit MALIIT_SETTINGS_LIB = maliit-settings MALIIT_HEADER = maliit MALIIT_FRAMEWORK_HEADER = maliit/framework # For libmaliit-glib MALIIT_GLIB_LIB = maliit-glib include(defines.pri) # Linker optimization for release build QMAKE_LFLAGS_RELEASE+=-Wl,--as-needed # Compiler warnings are error if the build type is debug QMAKE_CXXFLAGS_DEBUG+=-Werror -O0 QMAKE_CFLAGS_DEBUG+=-Werror -O0 OBJECTS_DIR = .obj MOC_DIR = .moc isEmpty(MALIIT_VERSION) { MALIIT_VERSION=$$MALIIT_VERSION } isEmpty(PREFIX) { PREFIX = /usr } isEmpty(BINDIR) { BINDIR = $$PREFIX/bin } isEmpty(LIBDIR) { LIBDIR = $$PREFIX/lib } isEmpty(INCLUDEDIR) { INCLUDEDIR = $$PREFIX/include } DATADIR = $$PREFIX/share isEmpty(DOCDIR) { DOCDIR = $$DATADIR/doc } isEmpty(MALIIT_PLUGINS_DIR) { MALIIT_PLUGINS_DIR = $$LIBDIR/$$MALIIT_PLUGINS } DEFINES += MALIIT_PLUGINS_DIR=\\\"$$MALIIT_PLUGINS_DIR\\\" isEmpty(MALIIT_PLUGINS_DATA_DIR) { MALIIT_PLUGINS_DATA_DIR = $$DATADIR/$$MALIIT_PLUGINS_DATA } DEFINES += MALIIT_PLUGINS_DATA_DIR=\\\"$$MALIIT_PLUGINS_DATA_DIR\\\" isEmpty(MALIIT_FACTORY_PLUGINS_DIR) { MALIIT_FACTORY_PLUGINS_DIR = $$MALIIT_PLUGINS_DIR/factories } DEFINES += MALIIT_FACTORY_PLUGINS_DIR=\\\"$$MALIIT_FACTORY_PLUGINS_DIR\\\" isEmpty(MALIIT_ENABLE_MULTITOUCH) { MALIIT_ENABLE_MULTITOUCH=true } MALIIT_EXTENSIONS_DIR = $$DATADIR/$$MALIIT_ATTRIBUTE_EXTENSIONS/ DEFINES += MALIIT_EXTENSIONS_DIR=\\\"$$MALIIT_EXTENSIONS_DIR\\\" isEmpty(MALIIT_DEFAULT_HW_PLUGIN) { MALIIT_DEFAULT_HW_PLUGIN = libmaliit-keyboard-plugin.so } isEmpty(MALIIT_DEFAULT_PLUGIN) { MALIIT_DEFAULT_PLUGIN = libmaliit-keyboard-plugin.so } MALIIT_TEST_DATADIR = $$DATADIR/$$MALIIT_TEST_SUITE MALIIT_TEST_LIBDIR = $$LIBDIR/$$MALIIT_TEST_SUITE MALIIT_TEST_TMPDIR = /tmp/$$MALIIT_TEST_SUITE MALIIT_TEST_PLUGINS_DIR = $$MALIIT_TEST_LIBDIR/plugins DEFINES += MALIIT_TEST_PLUGINS_DIR=\\\"$$MALIIT_TEST_PLUGINS_DIR\\\" DEFINES += MALIIT_CONFIG_ROOT=\\\"$$MALIIT_CONFIG_ROOT\\\" DEFINES += MALIIT_FRAMEWORK_USE_INTERNAL_API # Do not define keywords signals, slots, emit and foreach because of # conflicts with 3rd party libraries. CONFIG += no_keywords unix { MALIIT_STATIC_PREFIX=lib MALIIT_STATIC_SUFFIX=.a MALIIT_DYNAMIC_PREFIX=lib MALIIT_DYNAMIC_SUFFIX=.so MALIIT_ABI_VERSION_MAJOR= } win32 { # qmake puts libraries in subfolders in build tree on Windows (installation is unaffected) release { MALIIT_STATIC_PREFIX=release/lib MALIIT_DYNAMIC_PREFIX=release/ } debug { MALIIT_STATIC_PREFIX=debug/lib MALIIT_DYNAMIC_PREFIX=debug/ } # one would suspect this to be .lib, but qmake with mingw uses .a MALIIT_STATIC_SUFFIX=.a # qmake adds the first component of the version as part of the DLL name on Windows MALIIT_ABI_VERSIONS=$$split(MALIIT_ABI_VERSION, ".") MALIIT_ABI_VERSION_MAJOR=$$member(MALIIT_ABI_VERSIONS, 0) MALIIT_DYNAMIC_SUFFIX=$${MALIIT_ABI_VERSION_MAJOR}.dll } defineReplace(maliitStaticLib) { return($${MALIIT_STATIC_PREFIX}$${1}$${MALIIT_STATIC_SUFFIX}) } defineReplace(maliitDynamicLib) { return($${MALIIT_DYNAMIC_PREFIX}$${1}$${MALIIT_DYNAMIC_SUFFIX}) } mac { # Do mac stuff here M_BUILD_FEATURES = debug M_PROFILE_PARTS = INCLUDEPATH += include/ } contains(QT_CONFIG,embedded) { CONFIG += qws } wayland { DEFINES += HAVE_WAYLAND } noxcb { DEFINES += NOXCB } MALIIT_INSTALL_PRF = $$[QT_INSTALL_DATA]/mkspecs/features local-install { MALIIT_INSTALL_PRF = $$replace(MALIIT_INSTALL_PRF, $$[QT_INSTALL_PREFIX], $$PREFIX) } defineTest(outputFile) { out = $$OUT_PWD/$$1 in = $$PWD/$${1}.in !exists($$in) { error($$in does not exist!) return(false) } MALIIT_IN_DIR = $$PWD MALIIT_OUT_DIR = $$OUT_PWD variables = MALIIT_FRAMEWORK_FEATURE \ PREFIX \ BINDIR \ INCLUDEDIR \ LIBDIR \ DOCDIR \ MALIIT_PLUGINS_DIR \ MALIIT_PLUGINS_DATA_DIR \ MALIIT_FACTORY_PLUGINS_DIR \ MALIIT_VERSION \ MALIIT_ENABLE_MULTITOUCH \ MALIIT_DEFAULT_HW_PLUGIN \ MALIIT_DEFAULT_PLUGIN \ MALIIT_QUICK_FEATURE \ MALIIT_PLUGINS_LIB \ MALIIT_PLUGINS_HEADER \ MALIIT_LIB \ MALIIT_HEADER \ MALIIT_PLUGINS_QUICK_LIB \ MALIIT_PLUGINS_QUICK_HEADER \ MALIIT_PLUGINS_QUICK_FACTORY \ MALIIT_SETTINGS_LIB \ MALIIT_TEST_SUITE \ MALIIT_TEST_DATADIR \ MALIIT_TEST_LIBDIR \ MALIIT_TEST_TMPDIR \ MALIIT_IN_DIR \ MALIIT_OUT_DIR \ MALIIT_PACKAGENAME \ MALIIT_PACKAGE_BRIEF \ MALIIT_FRAMEWORK_HEADER \ MALIIT_SERVER_ARGUMENTS \ MALIIT_CONNECTION_LIB \ MALIIT_SERVER_HEADER \ MALIIT_ABI_VERSION_MAJOR \ MALIIT_GLIB_LIB \ command = "sed" for(var, variables) { command += "-e \"s;@$$var@;$$eval($$var);g\"" } command += $$in > $$out system(mkdir -p $$dirname(out)) system($$command) system(chmod --reference=$$in $$out) QMAKE_DISTCLEAN += $$1 export(QMAKE_DISTCLEAN) return(true) } defineTest(outputFiles) { files = $$ARGS for(file, files) { !outputFile($$file):return(false) } return(true) } maliit-framework-0.99.1+git20151118+62bd54b/connection/000077500000000000000000000000001262307254400216765ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/connection/.gitignore000066400000000000000000000006011262307254400236630ustar00rootroot00000000000000org.maliit.server.service minputmethodserver.service minputmethodcontext1interface_adaptor.cpp minputmethodcontext1interface_adaptor.h minputmethodcontext1interface_interface.cpp minputmethodcontext1interface_interface.h minputmethodserver1interface_adaptor.cpp minputmethodserver1interface_adaptor.h minputmethodserver1interface_interface.cpp minputmethodserver1interface_interface.h maliit-framework-0.99.1+git20151118+62bd54b/connection/README.weston000066400000000000000000000006511262307254400240760ustar00rootroot00000000000000Things not yet implemented in Weston, but used by Maliit Keyboard: 1. IM initiated hiding notifications. 2. Action invoking. By action we mean "copy", "paste" and such. For completness we could also pass a key sequences like Ctrl+c for copying or Ctrl+v for pasting. 3. Make putting a cursor before commited text possible. For now Weston takes an unsigned int which is relative to the beginning of commited text. maliit-framework-0.99.1+git20151118+62bd54b/connection/connection.pro000066400000000000000000000052351262307254400245640ustar00rootroot00000000000000include(../config.pri) TOP_DIR = .. VERSION = $$MALIIT_ABI_VERSION TEMPLATE = lib TARGET = $$TOP_DIR/lib/$$MALIIT_CONNECTION_LIB include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/weston-protocols/libmaliit-weston-protocols.pri) DEFINES += MALIIT_INPUTCONTEXT_NAME=\\\"$${MALIIT_INPUTCONTEXT_NAME}\\\" CONFIG += staticlib # Interface classes PUBLIC_HEADERS += \ connectionfactory.h \ minputcontextconnection.h \ PUBLIC_SOURCES += \ connectionfactory.cpp \ minputcontextconnection.cpp \ # Default to building qdbus based connection CONFIG += qdbus-dbus-connection wayland { QT += gui-private PUBLIC_SOURCES += \ waylandinputmethodconnection.cpp PUBLIC_HEADERS += \ waylandinputmethodconnection.h } include($$TOP_DIR/dbus_interfaces/dbus_interfaces.pri) qdbus-dbus-connection { server_adaptor.files = $$DBUS_SERVER_XML server_adaptor.header_flags = -i dbusinputcontextconnection.h -l DBusInputContextConnection server_adaptor.source_flags = -l DBusInputContextConnection context_adaptor.files = $$DBUS_CONTEXT_XML context_adaptor.header_flags = -i dbusserverconnection.h -l DBusServerConnection context_adaptor.source_flags = -l DBusServerConnection DBUS_ADAPTORS = server_adaptor context_adaptor DBUS_INTERFACES = $$DBUS_SERVER_XML $$DBUS_CONTEXT_XML QDBUSXML2CPP_INTERFACE_HEADER_FLAGS = -i maliit/namespace.h -i maliit/settingdata.h QT += dbus !enable-dbus-activation { DEFINES += NO_DBUS_ACTIVATION } PRIVATE_HEADERS += \ dbuscustomarguments.h \ dbusinputcontextconnection.h \ serverdbusaddress.h \ mimserverconnection.h \ dbusserverconnection.h \ inputcontextdbusaddress.h \ PRIVATE_SOURCES += \ dbuscustomarguments.cpp \ dbusinputcontextconnection.cpp \ serverdbusaddress.cpp \ mimserverconnection.cpp \ dbusserverconnection.cpp \ inputcontextdbusaddress.cpp \ # DBus activation enable-dbus-activation { outputFiles(org.maliit.server.service) DBUS_SERVICES_DIR = $$system(pkg-config --variable session_bus_services_dir dbus-1) DBUS_SERVICES_PREFIX = $$system(pkg-config --variable prefix dbus-1) local-install { DBUS_SERVICES_DIR = $$replace(DBUS_SERVICES_DIR, $$DBUS_SERVICES_PREFIX, $$PREFIX) } install_services.path = $$DBUS_SERVICES_DIR install_services.files = org.maliit.server.service INSTALLS += install_services } } HEADERS += \ $$PUBLIC_HEADERS \ $$PRIVATE_HEADERS \ SOURCES += \ $$PUBLIC_SOURCES \ $$PRIVATE_SOURCES \ OTHER_FILES += libmaliit-connection.pri maliit-framework-0.99.1+git20151118+62bd54b/connection/connectionfactory.cpp000066400000000000000000000025541262307254400261370ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "connectionfactory.h" #include "dbusinputcontextconnection.h" #ifdef HAVE_WAYLAND #include "waylandinputmethodconnection.h" #endif namespace Maliit { namespace DBus { MInputContextConnection *createInputContextConnectionWithDynamicAddress() { QSharedPointer address(new Maliit::Server::DBus::DynamicAddress); return new DBusInputContextConnection(address); } MInputContextConnection *createInputContextConnectionWithFixedAddress(const QString &fixedAddress, bool allowAnonymous) { Q_UNUSED(allowAnonymous); QSharedPointer address(new Maliit::Server::DBus::FixedAddress(fixedAddress)); return new DBusInputContextConnection(address); } } // namespace DBus #ifdef HAVE_WAYLAND MInputContextConnection *createWestonIMProtocolConnection() { return new WaylandInputMethodConnection; } #endif } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/connection/connectionfactory.h000066400000000000000000000017541262307254400256050ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_DBUS_CONNECTIONFACTORY_H #define MALIIT_DBUS_CONNECTIONFACTORY_H #include "minputcontextconnection.h" namespace Maliit { namespace DBus { MInputContextConnection *createInputContextConnectionWithDynamicAddress(); MInputContextConnection *createInputContextConnectionWithFixedAddress(const QString &fixedAddress, bool allowAnonymous); } // namespace DBus #ifdef HAVE_WAYLAND MInputContextConnection *createWestonIMProtocolConnection(); #endif } // namespace Maliit #endif // MALIIT_DBUS_CONNECTIONFACTORY_H maliit-framework-0.99.1+git20151118+62bd54b/connection/dbuscustomarguments.cpp000066400000000000000000000057151262307254400265300ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "dbuscustomarguments.h" #include #include QDBusArgument &operator<<(QDBusArgument &argument, const MImPluginSettingsEntry &entry) { argument.beginStructure(); argument << entry.description; argument << entry.extension_key; argument << static_cast(entry.type); // DBus does not have an "invalid variant" value, so we encode the validity as // a separate boolean field argument << entry.value.isValid(); if (entry.value.isValid()) argument << QDBusVariant(entry.value); else argument << QDBusVariant(QVariant(0)); argument << entry.attributes; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, MImPluginSettingsEntry &entry) { bool valid_value; int type; argument.beginStructure(); argument >> entry.description; argument >> entry.extension_key; argument >> type; // see comment in operator<< argument >> valid_value; argument >> entry.value; if (!valid_value) entry.value = QVariant(); argument >> entry.attributes; argument.endStructure(); entry.type = static_cast(type); return argument; } QDBusArgument &operator<<(QDBusArgument &argument, const MImPluginSettingsInfo &info) { argument.beginStructure(); argument << info.description_language; argument << info.plugin_name; argument << info.plugin_description; argument << info.extension_id; argument << info.entries; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, MImPluginSettingsInfo &info) { argument.beginStructure(); argument >> info.description_language; argument >> info.plugin_name; argument >> info.plugin_description; argument >> info.extension_id; argument >> info.entries; argument.endStructure(); return argument; } QDBusArgument &operator<<(QDBusArgument &arg, const Maliit::PreeditTextFormat &format) { arg.beginStructure(); arg << format.start << format.length << static_cast(format.preeditFace); arg.endStructure(); return arg; } const QDBusArgument &operator>>(const QDBusArgument &arg, Maliit::PreeditTextFormat &format) { int preedit_face(0); arg.beginStructure(); arg >> format.start >> format.length >> preedit_face; arg.endStructure(); format.preeditFace = static_cast (preedit_face); return arg; } maliit-framework-0.99.1+git20151118+62bd54b/connection/dbuscustomarguments.h000066400000000000000000000024061262307254400261670ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef DBUSCUSTOMARGUMENTS_H #define DBUSCUSTOMARGUMENTS_H class MImPluginSettingsEntry; class MImPluginSettingsInfo; class QDBusArgument; class QVariant; #include // MImPluginSettingsEntry marshalling QDBusArgument &operator<<(QDBusArgument &argument, const MImPluginSettingsEntry &entry); const QDBusArgument &operator>>(const QDBusArgument &argument, MImPluginSettingsEntry &entry); // MImPluginSettingsInfo marshalling QDBusArgument &operator<<(QDBusArgument &argument, const MImPluginSettingsInfo &info); const QDBusArgument &operator>>(const QDBusArgument &argument, MImPluginSettingsInfo &info); QDBusArgument &operator<<(QDBusArgument &arg, const Maliit::PreeditTextFormat &format); const QDBusArgument &operator>>(const QDBusArgument &arg, Maliit::PreeditTextFormat &format); #endif // DBUSCUSTOMARGUMENTS_H maliit-framework-0.99.1+git20151118+62bd54b/connection/dbusinputcontextconnection.cpp000066400000000000000000000322151262307254400301070ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "dbusinputcontextconnection.h" #include "minputmethodserver1interface_adaptor.h" #include "minputmethodcontext1interface_interface.h" #include "dbuscustomarguments.h" #include #include #include #include namespace { const char * const DBusPath = "/com/meego/inputmethod/uiserver1"; const char * const DBusInterface = "com.meego.inputmethod.uiserver1"; const char * const DBusClientPath = "/com/meego/inputmethod/inputcontext"; const char * const DBusClientInterface = "com.meego.inputmethod.inputcontext1"; const char * const DBusLocalPath("/org/freedesktop/DBus/Local"); const char * const DBusLocalInterface("org.freedesktop.DBus.Local"); const char * const DisconnectedSignal("Disconnected"); } DBusInputContextConnection::DBusInputContextConnection(const QSharedPointer &address) : MInputContextConnection(0) , mAddress(address) , mServer(mAddress->connect()) , mConnectionNumbers() , mProxys() , lastLanguage() { connect(mServer.data(), SIGNAL(newConnection(QDBusConnection)), this, SLOT(newConnection(QDBusConnection))); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); new Uiserver1Adaptor(this); } DBusInputContextConnection::~DBusInputContextConnection() { } void DBusInputContextConnection::newConnection(const QDBusConnection &connection) { ComMeegoInputmethodInputcontext1Interface *proxy = new ComMeegoInputmethodInputcontext1Interface(QString(), QString::fromLatin1(DBusClientPath), connection, this); static unsigned int connectionCounter = 1; // Start at 1 so 0 can be used as a sentinel value unsigned int connectionNumber = connectionCounter++; mConnectionNumbers.insert(connection.name(), connectionNumber); mProxys.insert(connectionNumber, proxy); mConnections.insert(connectionNumber, connection.name()); QDBusConnection c(connection); c.connect(QString(), QString::fromLatin1(DBusLocalPath), QString::fromLatin1(DBusLocalInterface), QString::fromLatin1(DisconnectedSignal), this, SLOT(onDisconnection())); c.registerObject(QString::fromLatin1(DBusPath), this); proxy->setLanguage(lastLanguage); } void DBusInputContextConnection::onDisconnection() { const QString &name = connection().name(); unsigned int connectionNumber = mConnectionNumbers.take(name); ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.take(connectionNumber); mConnections.remove(connectionNumber); delete proxy; handleDisconnection(connectionNumber); QDBusConnection::disconnectFromPeer(name); } void DBusInputContextConnection::sendPreeditString(const QString &string, const QList &preeditFormats, int replacementStart, int replacementLength, int cursorPos) { if (activeConnection) { MInputContextConnection::sendPreeditString(string, preeditFormats, replacementStart, replacementLength, cursorPos); ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->updatePreedit(string, preeditFormats, replacementStart, replacementLength, cursorPos); } } } void DBusInputContextConnection::sendCommitString(const QString &string, int replaceStart, int replaceLength, int cursorPos) { if (activeConnection) { MInputContextConnection::sendCommitString(string, replaceStart, replaceLength, cursorPos); ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->commitString(string, replaceStart, replaceLength, cursorPos); } } } void DBusInputContextConnection::sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType) { if (activeConnection) { MInputContextConnection::sendKeyEvent(keyEvent, requestType); ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->keyEvent(keyEvent.type(), keyEvent.key(), keyEvent.modifiers(), keyEvent.text(), keyEvent.isAutoRepeat(), keyEvent.count(), requestType); } } } void DBusInputContextConnection::notifyImInitiatedHiding() { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->imInitiatedHide(); } } void DBusInputContextConnection::setGlobalCorrectionEnabled(bool enabled) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if ((enabled != globalCorrectionEnabled()) && proxy) { proxy->setGlobalCorrectionEnabled(enabled); MInputContextConnection::setGlobalCorrectionEnabled(enabled); } } QRect DBusInputContextConnection::preeditRectangle(bool &valid) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { int x, y, width, height; if (proxy->preeditRectangle(x, y, width, height)) { valid = true; return QRect(x, y, width, height); } } valid = false; return QRect(); } void DBusInputContextConnection::setRedirectKeys(bool enabled) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if ((enabled != redirectKeysEnabled()) && proxy) { proxy->setRedirectKeys(enabled); MInputContextConnection::setRedirectKeys(enabled); } } void DBusInputContextConnection::setDetectableAutoRepeat(bool enabled) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if ((enabled != detectableAutoRepeat()) && proxy) { proxy->setDetectableAutoRepeat(enabled); MInputContextConnection::setDetectableAutoRepeat(enabled); } } void DBusInputContextConnection::invokeAction(const QString &action, const QKeySequence &sequence) { if (activeConnection) { QDBusMessage message = QDBusMessage::createSignal(DBusPath, DBusInterface, "invokeAction"); QList arguments; arguments << action << sequence.toString(); message.setArguments(arguments); QDBusConnection(mConnections.value(activeConnection)).send(message); } } void DBusInputContextConnection::setSelection(int start, int length) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->setSelection(start, length); } } QString DBusInputContextConnection::selection(bool &valid) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { QString selectionText; if (proxy->selection(selectionText)) { valid = true; return selectionText; } } valid = false; return QString(); } void DBusInputContextConnection::setLanguage(const QString &language) { lastLanguage = language; ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->setLanguage(language); } } void DBusInputContextConnection::sendActivationLostEvent() { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->activationLostEvent(); } } void DBusInputContextConnection::updateInputMethodArea(const QRegion ®ion) { qDebug() << "Updating input method area to" << region; ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { QRect rect = region.boundingRect(); proxy->updateInputMethodArea(rect.x(), rect.y(), rect.width(), rect.height()); } } void DBusInputContextConnection::notifyExtendedAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(activeConnection); if (proxy) { proxy->notifyExtendedAttributeChanged(id, target, targetItem, attribute, QDBusVariant(value)); } } void DBusInputContextConnection::notifyExtendedAttributeChanged(const QList &clientIds, int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value) { Q_FOREACH (int clientId, clientIds) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(clientId); if (proxy) { proxy->notifyExtendedAttributeChanged(id, target, targetItem, attribute, QDBusVariant(value)); } } } void DBusInputContextConnection::pluginSettingsLoaded(int clientId, const QList &info) { ComMeegoInputmethodInputcontext1Interface *proxy = mProxys.value(clientId); if (proxy) { proxy->pluginSettingsLoaded(info); } } unsigned int DBusInputContextConnection::connectionNumber() { return mConnectionNumbers.value(connection().name()); } void DBusInputContextConnection::activateContext() { MInputContextConnection::activateContext(connectionNumber()); } void DBusInputContextConnection::showInputMethod() { MInputContextConnection::showInputMethod(connectionNumber()); } void DBusInputContextConnection::hideInputMethod() { MInputContextConnection::hideInputMethod(connectionNumber()); } void DBusInputContextConnection::mouseClickedOnPreedit(int posX, int posY, int preeditRectX, int preeditRectY, int preeditRectWidth, int preeditRectHeight) { MInputContextConnection::mouseClickedOnPreedit(connectionNumber(), QPoint(posX, posY), QRect(preeditRectX, preeditRectY, preeditRectWidth, preeditRectHeight)); } void DBusInputContextConnection::setPreedit(const QString &text, int cursorPos) { MInputContextConnection::setPreedit(connectionNumber(), text, cursorPos); } void DBusInputContextConnection::updateWidgetInformation(const QVariantMap &stateInformation, bool focusChanged) { MInputContextConnection::updateWidgetInformation(connectionNumber(), stateInformation, focusChanged); } void DBusInputContextConnection::reset() { MInputContextConnection::reset(connectionNumber()); } void DBusInputContextConnection::appOrientationAboutToChange(int angle) { MInputContextConnection::receivedAppOrientationAboutToChange(connectionNumber(), angle); } void DBusInputContextConnection::appOrientationChanged(int angle) { MInputContextConnection::receivedAppOrientationChanged(connectionNumber(), angle); } void DBusInputContextConnection::setCopyPasteState(bool copyAvailable, bool pasteAvailable) { MInputContextConnection::setCopyPasteState(connectionNumber(), copyAvailable, pasteAvailable); } void DBusInputContextConnection::processKeyEvent(int keyType, int keyCode, int modifiers, const QString &text, bool autoRepeat, int count, uint nativeScanCode, uint nativeModifiers, uint time) { MInputContextConnection::processKeyEvent(connectionNumber(), static_cast(keyType), static_cast(keyCode), static_cast(modifiers), text, autoRepeat, count, nativeScanCode, nativeModifiers, time); } void DBusInputContextConnection::registerAttributeExtension(int id, const QString &fileName) { MInputContextConnection::registerAttributeExtension(connectionNumber(), id, fileName); } void DBusInputContextConnection::unregisterAttributeExtension(int id) { MInputContextConnection::unregisterAttributeExtension(connectionNumber(), id); } void DBusInputContextConnection::setExtendedAttribute(int id, const QString &target, const QString &targetItem, const QString &attribute, const QDBusVariant &value) { MInputContextConnection::setExtendedAttribute(connectionNumber(), id, target, targetItem, attribute, value.variant()); } void DBusInputContextConnection::loadPluginSettings(const QString &descriptionLanguage) { MInputContextConnection::loadPluginSettings(connectionNumber(), descriptionLanguage); } maliit-framework-0.99.1+git20151118+62bd54b/connection/dbusinputcontextconnection.h000066400000000000000000000110751262307254400275550ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef DBUSINPUTCONTEXTCONNECTION_H #define DBUSINPUTCONTEXTCONNECTION_H #include "minputcontextconnection.h" #include "serverdbusaddress.h" #include #include #include class ComMeegoInputmethodInputcontext1Interface; class DBusInputContextConnection : public MInputContextConnection, protected QDBusContext { Q_OBJECT public: explicit DBusInputContextConnection(const QSharedPointer &address); ~DBusInputContextConnection(); //! \reimp virtual void sendPreeditString(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); virtual void sendCommitString(const QString &string, int replaceStart = 0, int replaceLength = 0, int cursorPos = -1); virtual void sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType); virtual void notifyImInitiatedHiding(); virtual void setGlobalCorrectionEnabled(bool); virtual QRect preeditRectangle(bool &valid); virtual void setRedirectKeys(bool enabled); virtual void setDetectableAutoRepeat(bool enabled); virtual void invokeAction(const QString &action, const QKeySequence &sequence); virtual void setSelection(int start, int length); virtual QString selection(bool &valid); virtual void setLanguage(const QString &language); virtual void sendActivationLostEvent(); virtual void updateInputMethodArea(const QRegion ®ion); virtual void notifyExtendedAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); virtual void notifyExtendedAttributeChanged(const QList &clientIds, int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); virtual void pluginSettingsLoaded(int clientId, const QList &info); //! \reimp_end void activateContext(); void showInputMethod(); void hideInputMethod(); void mouseClickedOnPreedit(int posX, int posY, int preeditRectX, int preeditRectY, int preeditRectWidth, int preeditRectHeight); void setPreedit(const QString &text, int cursorPos); void updateWidgetInformation(const QVariantMap &stateInformation, bool focusChanged); void reset(); void appOrientationAboutToChange(int angle); void appOrientationChanged(int angle); void setCopyPasteState(bool copyAvailable, bool pasteAvailable); void processKeyEvent(int keyType, int keyCode, int modifiers, const QString &text, bool autoRepeat, int count, uint nativeScanCode, uint nativeModifiers, uint time); void registerAttributeExtension(int id, const QString &fileName); void unregisterAttributeExtension(int id); void setExtendedAttribute(int id, const QString &target, const QString &targetItem, const QString &attribute, const QDBusVariant &value); void loadPluginSettings(const QString &descriptionLanguage); private Q_SLOTS: void newConnection(const QDBusConnection &connection); void onDisconnection(); private: unsigned int connectionNumber(); const QSharedPointer mAddress; QScopedPointer mServer; QHash mConnectionNumbers; QHash mProxys; QHash mConnections; QString lastLanguage; }; #endif // DBUSINPUTCONTEXTCONNECTION_H maliit-framework-0.99.1+git20151118+62bd54b/connection/dbusserverconnection.cpp000066400000000000000000000212461262307254400266530ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "dbusserverconnection.h" #include #include #include "minputmethodcontext1interface_adaptor.h" #include "minputmethodserver1interface_interface.h" #include "dbuscustomarguments.h" #include #include namespace { const char * const IMServerPath("/com/meego/inputmethod/uiserver1"); const char * const IMServerConnection("Maliit::IMServerConnection"); const char * const InputContextAdaptorPath("/com/meego/inputmethod/inputcontext"); const char * const DBusLocalPath("/org/freedesktop/DBus/Local"); const char * const DBusLocalInterface("org.freedesktop.DBus.Local"); const char * const DisconnectedSignal("Disconnected"); const int ConnectionRetryInterval(6*1000); // in ms } DBusServerConnection::DBusServerConnection(const QSharedPointer &address) : MImServerConnection(0) , mAddress(address) , mProxy(0) , mActive(true) , pendingResetCalls() { qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); new Inputcontext1Adaptor(this); connect(mAddress.data(), SIGNAL(addressReceived(QString)), this, SLOT(openDBusConnection(QString))); connect(mAddress.data(), SIGNAL(addressFetchError(QString)), this, SLOT(connectToDBusFailed(QString))); QTimer::singleShot(0, this, SLOT(connectToDBus())); } DBusServerConnection::~DBusServerConnection() { mActive = false; Q_FOREACH (QDBusPendingCallWatcher *watcher, pendingResetCalls) { disconnect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(resetCallFinished(QDBusPendingCallWatcher*))); } } void DBusServerConnection::connectToDBus() { mAddress->get(); } void DBusServerConnection::openDBusConnection(const QString &addressString) { if (addressString.isEmpty()) { QTimer::singleShot(ConnectionRetryInterval, this, SLOT(connectToDBus())); return; } QDBusConnection connection = QDBusConnection::connectToPeer(addressString, QString::fromLatin1(IMServerConnection)); if (!connection.isConnected()) { QTimer::singleShot(ConnectionRetryInterval, this, SLOT(connectToDBus())); return; } mProxy = new ComMeegoInputmethodUiserver1Interface(QString(), QString::fromLatin1(IMServerPath), connection, this); connection.connect(QString(), QString::fromLatin1(DBusLocalPath), QString::fromLatin1(DBusLocalInterface), QString::fromLatin1(DisconnectedSignal), this, SLOT(onDisconnection())); connection.registerObject(QString::fromLatin1(InputContextAdaptorPath), this); #if 0 connect(mProxy, SIGNAL(invokeAction(QString,QKeySequence)), this, SIGNAL(invokeAction(QString,QKeySequence))); #endif Q_EMIT connected(); } void DBusServerConnection::connectToDBusFailed(const QString &) { QTimer::singleShot(ConnectionRetryInterval, this, SLOT(connectToDBus())); } void DBusServerConnection::onDisconnection() { delete mProxy; mProxy = 0; QDBusConnection::disconnectFromPeer(QString::fromLatin1(IMServerConnection)); Q_EMIT disconnected(); if (mActive) QTimer::singleShot(ConnectionRetryInterval, this, SLOT(connectToDBus())); } void DBusServerConnection::resetCallFinished(QDBusPendingCallWatcher *watcher) { pendingResetCalls.remove(watcher); watcher->deleteLater(); } bool DBusServerConnection::pendingResets() { return !pendingResetCalls.empty(); } void DBusServerConnection::activateContext() { if (!mProxy) return; mProxy->activateContext(); } void DBusServerConnection::showInputMethod() { if (!mProxy) return; mProxy->showInputMethod(); } void DBusServerConnection::hideInputMethod() { if (!mProxy) return; mProxy->hideInputMethod(); } void DBusServerConnection::mouseClickedOnPreedit(const QPoint &pos, const QRect &preeditRect) { if (!mProxy) return; mProxy->mouseClickedOnPreedit(pos.x(), pos.y(), preeditRect.x(), preeditRect.y(), preeditRect.width(), preeditRect.height()); } void DBusServerConnection::setPreedit(const QString &text, int cursorPos) { if (!mProxy) return; mProxy->setPreedit(text, cursorPos); } void DBusServerConnection::updateWidgetInformation(const QMap &stateInformation, bool focusChanged) { if (!mProxy) return; mProxy->updateWidgetInformation(stateInformation, focusChanged); } void DBusServerConnection::reset(bool requireSynchronization) { if (!mProxy) return; QDBusPendingCall resetCall = mProxy->reset(); if (requireSynchronization) { QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(resetCall, this); pendingResetCalls.insert(watcher); QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(resetCallFinished(QDBusPendingCallWatcher*))); } } void DBusServerConnection::appOrientationAboutToChange(int angle) { if (!mProxy) return; mProxy->appOrientationAboutToChange(angle); } void DBusServerConnection::appOrientationChanged(int angle) { if (!mProxy) return; mProxy->appOrientationChanged(angle); } void DBusServerConnection::setCopyPasteState(bool copyAvailable, bool pasteAvailable) { if (!mProxy) return; mProxy->setCopyPasteState(copyAvailable, pasteAvailable); } void DBusServerConnection::processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time) { if (!mProxy) return; mProxy->processKeyEvent(keyType, keyCode, modifiers, text, autoRepeat, count, nativeScanCode, nativeModifiers, time); } void DBusServerConnection::registerAttributeExtension(int id, const QString &fileName) { if (!mProxy) return; mProxy->registerAttributeExtension(id, fileName); } void DBusServerConnection::unregisterAttributeExtension(int id) { if (!mProxy) return; mProxy->unregisterAttributeExtension(id); } void DBusServerConnection::setExtendedAttribute(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value) { if (!mProxy) return; mProxy->setExtendedAttribute(id, target, targetItem, attribute, QDBusVariant(value)); } void DBusServerConnection::loadPluginSettings(const QString &descriptionLanguage) { if (!mProxy) return; mProxy->loadPluginSettings(descriptionLanguage); } void DBusServerConnection::pluginSettingsLoaded(const QList &info) { pluginSettingsReceived(info); } void DBusServerConnection::keyEvent(int type, int key, int modifiers, const QString &text, bool autoRepeat, int count, uchar requestType) { keyEvent(type, key, modifiers, text, autoRepeat, count, static_cast(requestType)); } void DBusServerConnection::notifyExtendedAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QDBusVariant &value) { extendedAttributeChanged(id, target, targetItem, attribute, value.variant()); } bool DBusServerConnection::preeditRectangle(int &x, int &y, int &width, int &height) const { bool valid; QRect result; getPreeditRectangle(result, valid); x = result.x(); y = result.y(); width = result.width(); height = result.height(); return valid; } bool DBusServerConnection::selection(QString &selection) const { bool valid; getSelection(selection, valid); return valid; } void DBusServerConnection::updateInputMethodArea(int x, int y, int width, int height) { updateInputMethodArea(QRect(x, y, width, height)); } maliit-framework-0.99.1+git20151118+62bd54b/connection/dbusserverconnection.h000066400000000000000000000071651262307254400263240ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef DBUSSERVERCONNECTION_H #define DBUSSERVERCONNECTION_H #include "mimserverconnection.h" #include "inputcontextdbusaddress.h" #include #include class ComMeegoInputmethodUiserver1Interface; class DBusServerConnection : public MImServerConnection { Q_OBJECT public: explicit DBusServerConnection(const QSharedPointer &address); ~DBusServerConnection(); //! reimpl virtual bool pendingResets(); virtual void activateContext(); virtual void showInputMethod(); virtual void hideInputMethod(); virtual void mouseClickedOnPreedit(const QPoint &pos, const QRect &preeditRect); virtual void setPreedit(const QString &text, int cursorPos); virtual void updateWidgetInformation(const QMap &stateInformation, bool focusChanged); virtual void reset(bool requireSynchronization); virtual void appOrientationAboutToChange(int angle); virtual void appOrientationChanged(int angle); virtual void setCopyPasteState(bool copyAvailable, bool pasteAvailable); virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); virtual void registerAttributeExtension(int id, const QString &fileName); virtual void unregisterAttributeExtension(int id); virtual void setExtendedAttribute(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); virtual void loadPluginSettings(const QString &descriptionLanguage); //! reimpl end //! forwarding methods for InputContextAdaptor using MImServerConnection::keyEvent; void keyEvent(int type, int key, int modifiers, const QString &text, bool autoRepeat, int count, uchar requestType); void notifyExtendedAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QDBusVariant &value); void pluginSettingsLoaded(const QList &info); bool preeditRectangle(int &x, int &y, int &width, int &height) const; bool selection(QString &selection) const; using MImServerConnection::updateInputMethodArea; void updateInputMethodArea(int x, int y, int width, int height); private Q_SLOTS: void connectToDBus(); void openDBusConnection(const QString &addressString); void connectToDBusFailed(const QString &errorMessage); void onDisconnection(); void resetCallFinished(QDBusPendingCallWatcher*); private: QSharedPointer mAddress; ComMeegoInputmethodUiserver1Interface *mProxy; bool mActive; QSet pendingResetCalls; }; #endif // DBUSSERVERCONNECTION_H maliit-framework-0.99.1+git20151118+62bd54b/connection/inputcontextdbusaddress.cpp000066400000000000000000000044431262307254400273770ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "inputcontextdbusaddress.h" #include #include #include #include namespace { const char * const MaliitServerName = "org.maliit.server"; const char * const MaliitServerObjectPath = "/org/maliit/server/address"; const char * const MaliitServerInterface = "org.maliit.Server.Address"; const char * const MaliitServerAddressProperty = "address"; const char * const DBusPropertiesInterface = "org.freedesktop.DBus.Properties"; const char * const DBusPropertiesGetMethod = "Get"; } namespace Maliit { namespace InputContext { namespace DBus { Address::Address() { } Address::~Address() { } void DynamicAddress::get() { QList arguments; arguments.push_back(QVariant(QString::fromLatin1(MaliitServerInterface))); arguments.push_back(QVariant(QString::fromLatin1(MaliitServerAddressProperty))); QDBusMessage message = QDBusMessage::createMethodCall(MaliitServerName, MaliitServerObjectPath, DBusPropertiesInterface, DBusPropertiesGetMethod); message.setArguments(arguments); QDBusConnection::sessionBus().callWithCallback(message, this, SLOT(successCallback(QDBusVariant)), SLOT(errorCallback(QDBusError))); } void DynamicAddress::successCallback(const QDBusVariant &address) { Q_EMIT addressReceived(address.variant().toString()); } void DynamicAddress::errorCallback(const QDBusError &error) { Q_EMIT addressFetchError(error.message()); } FixedAddress::FixedAddress(const QString &address) : mAddress(address) { } void FixedAddress::get() { Q_EMIT this->addressReceived(mAddress); } } // namespace DBus } // namespace InputContext } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/connection/inputcontextdbusaddress.h000066400000000000000000000026551262307254400270470ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_INPUTCONTEXT_DBUS_INPUTCONTEXTDBUSADDRESS_H #define MALIIT_INPUTCONTEXT_DBUS_INPUTCONTEXTDBUSADDRESS_H #include class QDBusVariant; class QDBusError; namespace Maliit { namespace InputContext { namespace DBus { class Address : public QObject { Q_OBJECT public: Address(); virtual ~Address(); virtual void get() = 0; Q_SIGNALS: void addressReceived(const QString &address); void addressFetchError(const QString &errorMessage); }; class DynamicAddress : public Address { Q_OBJECT public: void get(); private Q_SLOTS: void successCallback(const QDBusVariant &address); void errorCallback(const QDBusError &error); }; class FixedAddress : public Address { Q_OBJECT public: FixedAddress(const QString &address); void get(); private: QString mAddress; }; } // namespace DBus } // namespace InputContext } // namespace Maliit #endif // MALIIT_INPUTCONTEXT_DBUS_INPUTCONTEXTDBUSADDRESS_H maliit-framework-0.99.1+git20151118+62bd54b/connection/libmaliit-connection.pri000066400000000000000000000011151262307254400265130ustar00rootroot00000000000000# Use when a .pro file requires libmaliit-connection # The .pro file must define TOP_DIR to be a relative path # to the top-level source/build directory, and include config.pri include($$PWD/../common/libmaliit-common.pri) include($$PWD/../weston-protocols/libmaliit-weston-protocols.pri) LIBS += $$TOP_DIR/lib/$$maliitStaticLib($${MALIIT_CONNECTION_LIB}) POST_TARGETDEPS += $$TOP_DIR/lib/$$maliitStaticLib($${MALIIT_CONNECTION_LIB}) INCLUDEPATH += $$TOP_DIR/connection $$OUT_PWD/$$TOP_DIR/connection QT += dbus wayland { CONFIG += link_pkgconfig PKGCONFIG += wayland-client } maliit-framework-0.99.1+git20151118+62bd54b/connection/mimserverconnection.cpp000066400000000000000000000057321262307254400265020ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimserverconnection.h" /* Dummy class that does nothing. */ MImServerConnection::MImServerConnection(QObject *parent) : QObject(parent) , d(0) { Q_UNUSED(parent); } void MImServerConnection::activateContext() {} void MImServerConnection::showInputMethod() {} void MImServerConnection::hideInputMethod() {} void MImServerConnection::mouseClickedOnPreedit(const QPoint &pos, const QRect &preeditRect) { Q_UNUSED(pos); Q_UNUSED(preeditRect); } void MImServerConnection::setPreedit(const QString &text, int cursorPos) { Q_UNUSED(text); Q_UNUSED(cursorPos); } void MImServerConnection::updateWidgetInformation(const QMap &stateInformation, bool focusChanged) { Q_UNUSED(stateInformation); Q_UNUSED(focusChanged); } void MImServerConnection::reset(bool requireSynchronization) { Q_UNUSED(requireSynchronization); } bool MImServerConnection::pendingResets() { return false; } void MImServerConnection::appOrientationAboutToChange(int angle) { Q_UNUSED(angle); } void MImServerConnection::appOrientationChanged(int angle) { Q_UNUSED(angle); } void MImServerConnection::setCopyPasteState(bool copyAvailable, bool pasteAvailable) { Q_UNUSED(copyAvailable); Q_UNUSED(pasteAvailable); } void MImServerConnection::processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time) { Q_UNUSED(keyType); Q_UNUSED(keyCode); Q_UNUSED(modifiers); Q_UNUSED(text); Q_UNUSED(autoRepeat); Q_UNUSED(count); Q_UNUSED(nativeScanCode); Q_UNUSED(nativeModifiers); Q_UNUSED(time); } void MImServerConnection::registerAttributeExtension(int id, const QString &fileName) { Q_UNUSED(id); Q_UNUSED(fileName); } void MImServerConnection::unregisterAttributeExtension(int id) { Q_UNUSED(id); } void MImServerConnection::setExtendedAttribute(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value) { Q_UNUSED(id); Q_UNUSED(target); Q_UNUSED(targetItem); Q_UNUSED(attribute); Q_UNUSED(value); } void MImServerConnection::loadPluginSettings(const QString &descriptionLanguage) { Q_UNUSED(descriptionLanguage); } maliit-framework-0.99.1+git20151118+62bd54b/connection/mimserverconnection.h000066400000000000000000000206371262307254400261500ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSERVERCONNECTION_H #define MIMSERVERCONNECTION_H #include #include class MImServerConnectionPrivate; class MImPluginSettingsInfo; class MImServerConnection : public QObject { Q_OBJECT public: //! \brief Constructor explicit MImServerConnection(QObject *parent = 0); virtual bool pendingResets(); /* Outgoing communication */ virtual void activateContext(); virtual void showInputMethod(); virtual void hideInputMethod(); virtual void mouseClickedOnPreedit(const QPoint &pos, const QRect &preeditRect); virtual void setPreedit(const QString &text, int cursorPos); virtual void updateWidgetInformation(const QMap &stateInformation, bool focusChanged); virtual void reset(bool requireSynchronization); virtual void appOrientationAboutToChange(int angle); virtual void appOrientationChanged(int angle); virtual void setCopyPasteState(bool copyAvailable, bool pasteAvailable); virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); virtual void registerAttributeExtension(int id, const QString &fileName); virtual void unregisterAttributeExtension(int id); virtual void setExtendedAttribute(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); virtual void loadPluginSettings(const QString &descriptionLanguage); public: /*! \brief Notifies about connection to server being established. * * Note: Creating connection to server and thus emission of this signal * have to be deferred to the mainloop. */ Q_SIGNAL void connected(); Q_SIGNAL void disconnected(); /* Incoming communication */ Q_SIGNAL void activationLostEvent(); //! \brief Notifies about hiding initiated by the input method server side Q_SIGNAL void imInitiatedHide(); /*! * \brief Commits a string to current focus widget, and set cursor position. * \param string The new string committed * \param replacementStart The position at which characters are to be replaced relative * from the start of the preedit string. * \param replacementLength The number of characters to be replaced in the preedit string. * \param cursorPos The cursor position to be set. the cursorPos is the position relative * to commit string start. Negative values are used as commit string end position * * Note: If \a replacementLength is 0, \a replacementStart gives the insertion position * for the inserted \a string. * For example, if the replacement starting at -1 with a length of 2, then application will * remove the last character before the preedit string and the first character afterwards, * and insert the commit string directly before the preedit string. */ Q_SIGNAL void commitString(const QString &string, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); /*! * \brief Updates preedit string of the current focus widget * \param string The new string * \param preeditFormats The formats for each part of preedit. * \param replacementStart The position at which characters are to be replaced relative * from the start of the preedit string. * \param replacementLength The number of characters to be replaced in the preedit string. * \param cursorPos Cursor position. If it is less than 0, then the cursor will be hidden. * */ Q_SIGNAL void updatePreedit(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); //! \brief Sends a non-printable key event. Parameters as in QKeyEvent constructor Q_SIGNAL void keyEvent(int type, int key, int modifiers, const QString &text, bool autoRepeat, int count, Maliit::EventRequestType requestType = Maliit::EventRequestBoth); //! // \brief Updates the input method window area // \param rect Bounding rectangle of the input method area Q_SIGNAL void updateInputMethodArea(const QRect &rect); /*! * \brief set global correction option enable/disable */ Q_SIGNAL void setGlobalCorrectionEnabled(bool); /*! \brief Get rectangle covering preedit * \param valid validity for the return value * \param rectangle the preedit rectangle. * * Warning: If multiple slots are connected to this signal, the last slot to be * called will be able to overwrite value set by previously called slots. */ Q_SIGNAL void getPreeditRectangle(QRect &rectangle, bool &valid) const; /*! * \brief Sends command action to text editor. * This method tries to call action slot in the focused widget * and sends QKeyEvent corresponding to sequence if slot can not be called. */ Q_SIGNAL void invokeAction(const QString &action, const QKeySequence &sequence); /*! * \brief Set if the input method wants to process all raw key events * from hardware keyboard (via \a processKeyEvent calls). */ Q_SIGNAL void setRedirectKeys(bool enabled); /*! * \brief Set detectable autorepeat for X on/off * * Detectable autorepeat means that instead of press, release, press, release, press, * release... sequence of key events you get press, press, press, release key events * when a key is repeated. The setting is X client specific. This is intended to be * used when key event redirection is enabled with \a setRedirectKeys. */ Q_SIGNAL void setDetectableAutoRepeat(bool enabled); /*! * \brief Sets selection which start from \start with \a length in the focus widget. * * \param start the start index * \param length the length of selection * Note: The cursor will be moved after the commit string has been committed, and the * preedit string will be located at the new edit position. */ Q_SIGNAL void setSelection(int start, int length); /*! * \brief get selecting text * \param valid validity for the return value * \param selection the current selection * * Warning: If multiple slots are connected to this signal, the last slot to be * called will be able to overwrite value set by previously called slots. */ Q_SIGNAL void getSelection(QString &selection, bool &valid) const; /*! * \brief Updates current language of active input method in input context. * \param language ICU format locale ID string * \sa QInputContext::language() */ Q_SIGNAL void setLanguage(const QString &language); /*! *\brief Informs application that input method server has changed the \a attribute of the \a targetItem * in the attribute extension \a target which has unique \a id to \a value. */ Q_SIGNAL void extendedAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); /*! * \brief Updates the list of server settings known to the application. * \param info list of server and plugin settings * * Sent in response to \a loadPluginSettings(). Might be sent spontaneously by * the server in response to external events (plugin loaded/unloaded, ...). */ Q_SIGNAL void pluginSettingsReceived(const QList &info); private: Q_DISABLE_COPY(MImServerConnection) MImServerConnectionPrivate *d; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/connection/minputcontextconnection.cpp000066400000000000000000000400061262307254400274030ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "minputcontextconnection.h" #include namespace { // attribute names for updateWidgetInformation() map const char * const FocusStateAttribute = "focusState"; const char * const ContentTypeAttribute = "contentType"; const char * const CorrectionAttribute = "correctionEnabled"; const char * const PredictionAttribute = "predictionEnabled"; const char * const AutoCapitalizationAttribute = "autocapitalizationEnabled"; const char * const SurroundingTextAttribute = "surroundingText"; const char * const AnchorPositionAttribute = "anchorPosition"; const char * const CursorPositionAttribute = "cursorPosition"; const char * const HasSelectionAttribute = "hasSelection"; const char * const InputMethodModeAttribute = "inputMethodMode"; const char * const WinId = "winId"; const char * const CursorRectAttribute = "cursorRectangle"; const char * const HiddenTextAttribute = "hiddenText"; const char * const PreeditClickPosAttribute = "preeditClickPos"; } class MInputContextConnectionPrivate { public: MInputContextConnectionPrivate(); ~MInputContextConnectionPrivate(); }; MInputContextConnectionPrivate::MInputContextConnectionPrivate() { // nothing } MInputContextConnectionPrivate::~MInputContextConnectionPrivate() { // nothing } //////////////////////// // actual class MInputContextConnection::MInputContextConnection(QObject *parent) : activeConnection(0) , d(new MInputContextConnectionPrivate) , lastOrientation(0) , mGlobalCorrectionEnabled(false) , mRedirectionEnabled(false) , mDetectableAutoRepeat(false) { Q_UNUSED(parent); } MInputContextConnection::~MInputContextConnection() { delete d; } /* Accessors to widgetState */ bool MInputContextConnection::focusState(bool &valid) { QVariant focusStateVariant = mWidgetState[FocusStateAttribute]; valid = focusStateVariant.isValid(); return focusStateVariant.toBool(); } int MInputContextConnection::contentType(bool &valid) { QVariant contentTypeVariant = mWidgetState[ContentTypeAttribute]; return contentTypeVariant.toInt(&valid); } bool MInputContextConnection::correctionEnabled(bool &valid) { QVariant correctionVariant = mWidgetState[CorrectionAttribute]; valid = correctionVariant.isValid(); return correctionVariant.toBool(); } bool MInputContextConnection::predictionEnabled(bool &valid) { QVariant predictionVariant = mWidgetState[PredictionAttribute]; valid = predictionVariant.isValid(); return predictionVariant.toBool(); } bool MInputContextConnection::autoCapitalizationEnabled(bool &valid) { QVariant capitalizationVariant = mWidgetState[AutoCapitalizationAttribute]; valid = capitalizationVariant.isValid(); return capitalizationVariant.toBool(); } QRect MInputContextConnection::cursorRectangle(bool &valid) { QVariant cursorRectVariant = mWidgetState[CursorRectAttribute]; valid = cursorRectVariant.isValid(); return cursorRectVariant.toRect(); } bool MInputContextConnection::hiddenText(bool &valid) { QVariant hiddenTextVariant = mWidgetState[HiddenTextAttribute]; valid = hiddenTextVariant.isValid(); return hiddenTextVariant.toBool(); } bool MInputContextConnection::surroundingText(QString &text, int &cursorPosition) { QVariant textVariant = mWidgetState[SurroundingTextAttribute]; QVariant posVariant = mWidgetState[CursorPositionAttribute]; if (textVariant.isValid() && posVariant.isValid()) { text = textVariant.toString(); cursorPosition = posVariant.toInt(); return true; } return false; } bool MInputContextConnection::hasSelection(bool &valid) { QVariant selectionVariant = mWidgetState[HasSelectionAttribute]; valid = selectionVariant.isValid(); return selectionVariant.toBool(); } int MInputContextConnection::inputMethodMode(bool &valid) { QVariant modeVariant = mWidgetState[InputMethodModeAttribute]; return modeVariant.toInt(&valid); } QRect MInputContextConnection::preeditRectangle(bool &valid) { valid = false; return QRect(); } WId MInputContextConnection::winId() { #ifdef Q_WS_WIN WId result = 0; return result; #else QVariant winIdVariant = mWidgetState[WinId]; // after transfer by dbus type can change switch (winIdVariant.type()) { case QVariant::UInt: if (sizeof(uint) >= sizeof(WId)) return winIdVariant.toUInt(); break; case QVariant::ULongLong: if (sizeof(qulonglong) >= sizeof(WId)) return winIdVariant.toULongLong(); break; default: if (winIdVariant.canConvert()) return winIdVariant.value(); } return 0; #endif } int MInputContextConnection::anchorPosition(bool &valid) { QVariant posVariant = mWidgetState[AnchorPositionAttribute]; valid = posVariant.isValid(); return posVariant.toInt(); } int MInputContextConnection::preeditClickPos(bool &valid) const { QVariant selectionVariant = mWidgetState[PreeditClickPosAttribute]; valid = selectionVariant.isValid(); return selectionVariant.toInt(); } /* End accessors to widget state */ /* Handlers for inbound communication */ void MInputContextConnection::showInputMethod(unsigned int connectionId) { if (activeConnection != connectionId) return; Q_EMIT showInputMethodRequest(); } void MInputContextConnection::hideInputMethod(unsigned int connectionId) { // Only allow this call for current active connection. if (activeConnection != connectionId) return; Q_EMIT hideInputMethodRequest(); } void MInputContextConnection::mouseClickedOnPreedit(unsigned int connectionId, const QPoint &pos, const QRect &preeditRect) { if (activeConnection != connectionId) return; Q_EMIT mouseClickedOnPreedit(pos, preeditRect); } void MInputContextConnection::setPreedit(unsigned int connectionId, const QString &text, int cursorPos) { if (activeConnection != connectionId) return; preedit = text; Q_EMIT preeditChanged(text, cursorPos); } void MInputContextConnection::reset(unsigned int connectionId) { if (activeConnection != connectionId) return; preedit.clear(); Q_EMIT resetInputMethodRequest(); if (!preedit.isEmpty()) { qWarning("Preedit set from InputMethod::reset()!"); preedit.clear(); } } void MInputContextConnection::updateWidgetInformation( unsigned int connectionId, const QMap &stateInfo, bool handleFocusChange) { if (activeConnection != connectionId) return; QMap oldState = mWidgetState; mWidgetState = stateInfo; #ifndef Q_WS_WIN if (handleFocusChange) { Q_EMIT focusChanged(winId()); } #endif Q_EMIT widgetStateChanged(connectionId, mWidgetState, oldState, handleFocusChange); } void MInputContextConnection::receivedAppOrientationAboutToChange(unsigned int connectionId, int angle) { if (activeConnection != connectionId) return; // Needs to be passed to the MImRotationAnimation listening // to this signal first before the plugins. This ensures // that the rotation animation can be painted sufficiently early. Q_EMIT contentOrientationAboutToChange(angle); Q_EMIT contentOrientationAboutToChangeCompleted(angle); } void MInputContextConnection::receivedAppOrientationChanged(unsigned int connectionId, int angle) { if (activeConnection != connectionId) return; // Handle orientation changes through MImRotationAnimation with priority. // That's needed for getting the correct rotated pixmap buffers. Q_EMIT contentOrientationChanged(angle); Q_EMIT contentOrientationChangeCompleted(angle); } void MInputContextConnection::setCopyPasteState(unsigned int connectionId, bool copyAvailable, bool pasteAvailable) { if (activeConnection != connectionId) return; Q_EMIT copyPasteStateChanged(copyAvailable, pasteAvailable); } void MInputContextConnection::processKeyEvent( unsigned int connectionId, QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time) { if (activeConnection != connectionId) return; Q_EMIT receivedKeyEvent(keyType, keyCode, modifiers, text, autoRepeat, count, nativeScanCode, nativeModifiers, time); } void MInputContextConnection::registerAttributeExtension(unsigned int connectionId, int id, const QString &attributeExtension) { Q_EMIT attributeExtensionRegistered(connectionId, id, attributeExtension); } void MInputContextConnection::unregisterAttributeExtension(unsigned int connectionId, int id) { Q_EMIT attributeExtensionUnregistered(connectionId, id); } void MInputContextConnection::setExtendedAttribute( unsigned int connectionId, int id, const QString &target, const QString &targetName, const QString &attribute, const QVariant &value) { Q_EMIT extendedAttributeChanged(connectionId, id, target, targetName, attribute, value); } void MInputContextConnection::loadPluginSettings(int connectionId, const QString &descriptionLanguage) { Q_EMIT pluginSettingsRequested(connectionId, descriptionLanguage); } /* End handlers for inbound communication */ bool MInputContextConnection::detectableAutoRepeat() { return mDetectableAutoRepeat; } void MInputContextConnection::setDetectableAutoRepeat(bool enabled) { mDetectableAutoRepeat = enabled; } void MInputContextConnection::setGlobalCorrectionEnabled(bool enabled) { mGlobalCorrectionEnabled = enabled; } bool MInputContextConnection::globalCorrectionEnabled() { return mGlobalCorrectionEnabled; } void MInputContextConnection::setRedirectKeys(bool enabled) { mRedirectionEnabled = enabled; } bool MInputContextConnection::redirectKeysEnabled() { return mRedirectionEnabled; } /* */ void MInputContextConnection::sendCommitString(const QString &string, int replaceStart, int replaceLength, int cursorPos) { const int cursorPosition(mWidgetState[CursorPositionAttribute].toInt()); bool validAnchor(false); preedit.clear(); if (replaceLength == 0 // we don't support replacement // we don't support selections && anchorPosition(validAnchor) == cursorPosition && validAnchor) { const int insertPosition(cursorPosition + replaceStart); if (insertPosition >= 0) { mWidgetState[SurroundingTextAttribute] = mWidgetState[SurroundingTextAttribute].toString().insert(insertPosition, string); mWidgetState[CursorPositionAttribute] = cursorPos < 0 ? (insertPosition + string.length()) : cursorPos; mWidgetState[AnchorPositionAttribute] = mWidgetState[CursorPositionAttribute]; } } } void MInputContextConnection::sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType) { if (requestType != Maliit::EventRequestSignalOnly && preedit.isEmpty() && keyEvent.key() == Qt::Key_Backspace && keyEvent.type() == QEvent::KeyPress) { QString surrString(mWidgetState[SurroundingTextAttribute].toString()); const int cursorPosition(mWidgetState[CursorPositionAttribute].toInt()); bool validAnchor(false); if (!surrString.isEmpty() && cursorPosition > 0 // we don't support selections && anchorPosition(validAnchor) == cursorPosition && validAnchor) { mWidgetState[SurroundingTextAttribute] = surrString.remove(cursorPosition - 1, 1); mWidgetState[CursorPositionAttribute] = cursorPosition - 1; mWidgetState[AnchorPositionAttribute] = cursorPosition - 1; } } } /* */ /* */ void MInputContextConnection::handleDisconnection(unsigned int connectionId) { Q_EMIT clientDisconnected(connectionId); if (activeConnection != connectionId) { return; } activeConnection = 0; Q_EMIT activeClientDisconnected(); } void MInputContextConnection::activateContext(unsigned int connectionId) { if (connectionId == activeConnection) { return; } /* Notify current/previously active context that it is no longer active */ sendActivationLostEvent(); activeConnection = connectionId; /* Notify new input context about state/settings stored in the IM server */ if (activeConnection) { /* Hack: Circumvent if(newValue == oldValue) return; guards */ mGlobalCorrectionEnabled = !mGlobalCorrectionEnabled; setGlobalCorrectionEnabled(!mGlobalCorrectionEnabled); mRedirectionEnabled = !mRedirectionEnabled; setRedirectKeys(!mRedirectionEnabled); mDetectableAutoRepeat = !mDetectableAutoRepeat; setDetectableAutoRepeat(!mDetectableAutoRepeat); } Q_EMIT clientActivated(connectionId); } /* */ void MInputContextConnection::sendPreeditString(const QString &string, const QList &preeditFormats, int replaceStart, int replaceLength, int cursorPos) { Q_UNUSED(preeditFormats); Q_UNUSED(replaceStart); Q_UNUSED(replaceLength); Q_UNUSED(cursorPos); if (activeConnection) { preedit = string; } } /* */ void MInputContextConnection::setSelection(int start, int length) { Q_UNUSED(start); Q_UNUSED(length); } void MInputContextConnection::notifyImInitiatedHiding() {} void MInputContextConnection::invokeAction(const QString &action, const QKeySequence &sequence) { Q_UNUSED(action); Q_UNUSED(sequence); } QString MInputContextConnection::selection(bool &valid) { valid = false; return QString(); } void MInputContextConnection::setLanguage(const QString &language) { Q_UNUSED(language); } void MInputContextConnection::sendActivationLostEvent() {} void MInputContextConnection::updateInputMethodArea(const QRegion ®ion) { Q_UNUSED(region); } void MInputContextConnection::notifyExtendedAttributeChanged(int , const QString &, const QString &, const QString &, const QVariant &) { // empty default implementation } void MInputContextConnection::notifyExtendedAttributeChanged(const QList &, int , const QString &, const QString &, const QString &, const QVariant &) { // empty default implementation } void MInputContextConnection::pluginSettingsLoaded(int clientId, const QList &info) { Q_UNUSED(clientId); Q_UNUSED(info); // empty default implementation } QVariantMap MInputContextConnection::widgetState() const { return mWidgetState; } maliit-framework-0.99.1+git20151118+62bd54b/connection/minputcontextconnection.h000066400000000000000000000352721262307254400270610ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MINPUTCONTEXTCONNECTION_H #define MINPUTCONTEXTCONNECTION_H #include #include #include class QKeyEvent; class MInputContextConnectionPrivate; class MAbstractInputMethod; class MAttributeExtensionId; class MImPluginSettingsInfo; /*! \internal * \ingroup maliitserver * \brief Base class of the input method communication implementation between * the input context and the input method server. */ class MInputContextConnection: public QObject { Q_OBJECT Q_DISABLE_COPY(MInputContextConnection) public: explicit MInputContextConnection(QObject *parent = 0); virtual ~MInputContextConnection(); /*! * \brief Returns focus state if output parameter \a valid is \c true. * * By focus state it is meant to be focus state of an input widget * on application side. If returned value is valid and is \c true then this * means that input widget is focused. Otherwise, if returned value is * \c false then no input widget is focused. * * \param valid An output parameter stating whether return value is valid. */ virtual bool focusState(bool &valid); /*! * \brief returns content type for focused widget if output parameter valid is true, * value matches enum M::TextContentType */ virtual int contentType(bool &valid); /*! * \brief returns input method correction hint if output parameter valid is true. */ virtual bool correctionEnabled(bool &valid); /*! * \brief returns input methoContextd word prediction hint if output parameter valid is true. */ virtual bool predictionEnabled(bool &valid); /*! * \brief returns input method auto-capitalization hint if output parameter valid is true. */ virtual bool autoCapitalizationEnabled(bool &valid); /*! * \brief get surrounding text and cursor position information */ virtual bool surroundingText(QString &text, int &cursorPosition); /*! * \brief returns true if there is selecting text */ virtual bool hasSelection(bool &valid); /*! * \brief get input method mode */ virtual int inputMethodMode(bool &valid); /*! * \brief get preedit rectangle */ virtual QRect preeditRectangle(bool &valid); /*! * \brief get cursor rectangle */ virtual QRect cursorRectangle(bool &valid); /*! * \brief true if text input is being made hidden, e.g. with password fields */ virtual bool hiddenText(bool &valid); /*! * \brief Updates pre-edit string in the application widget * * Implement this method to update the pre-edit string * \param string The new pre-edit string * \param preeditFormats Selects visual stylings for each part of preedit * \param replacementStart The position at which characters are to be replaced relative * from the start of the preedit string. * \param replacementLength The number of characters to be replaced in the preedit string. * \param cursorPos The cursor position inside preedit */ virtual void sendPreeditString(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); /*! * \brief Updates commit string in the application widget, and set cursor position. * * Implement this method to update the commit string * \param string The string to be committed * \param replaceStart The position at which characters are to be replaced relative * from the start of the preedit string. * \param replaceLength The number of characters to be replaced in the preedit string. * \param cursorPos The cursor position to be set. the cursorPos is the position relative * to commit string start. Negative values are used as commit string end position */ virtual void sendCommitString(const QString &string, int replaceStart = 0, int replaceLength = 0, int cursorPos = -1); /*! * \brief Sends key event to the application * * This method is used to deliver the key event to active widget. * A \a MInputMethodState::keyPress or \a MInputMethodState::keyRelease * event is also emitted. Depending on the value of \a requestType * parameter, a Qt::KeyEvent and/or a signal is emitted. * \param keyEvent The event to send * \param requestType The type of the request: event, signal, or both. */ virtual void sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType = Maliit::EventRequestBoth); /*! * \brief notifies about hiding initiated by the input method server side */ virtual void notifyImInitiatedHiding(); /*! * \brief calls actions like "copy" or "paste" on the focused text entry. * * \param action The action to call * \param sequence The fall-back key sequence when action is not available */ virtual void invokeAction(const QString &action, const QKeySequence &sequence); /*! * \brief Set if the input method wants to process all raw key events * from hardware keyboard (via \a processKeyEvent calls). */ virtual void setRedirectKeys(bool enabled); /*! * \brief Set detectable autorepeat for X on/off * * Detectable autorepeat means that instead of press, release, press, release, press, * release... sequence of key events you get press, press, press, release key events * when a key is repeated. The setting is X client specific. This is intended to be * used when key event redirection is enabled with \a setRedirectKeys. */ virtual void setDetectableAutoRepeat(bool enabled); /*! * \brief set global correction option enable/disable */ virtual void setGlobalCorrectionEnabled(bool); /*! *\brief Sets selection text start from \a start with \a length in the application widget. */ virtual void setSelection(int start, int length); /*! * \brief returns the position of the selection anchor. * * This may be less or greater than cursor position, depending on which side of selection * the cursor is. If there is no selection, it returns the same as cursor position. */ virtual int anchorPosition(bool &valid); /*! * \brief returns the current cursor position within the preedit region */ virtual int preeditClickPos(bool &valid) const; /*! * \brief returns the selecting text */ virtual QString selection(bool &valid); /*! * \brief Sets current language of active input method. * \param language ICU format locale ID string */ virtual void setLanguage(const QString &language); virtual void sendActivationLostEvent(); public: // Inbound communication handlers //! ipc method provided to application, makes the application the active one void activateContext(unsigned int connectionId); //! ipc method provided to the application, shows input method void showInputMethod(unsigned int clientId); //! ipc method provided to the application, hides input method void hideInputMethod(unsigned int clientId); //! ipc method provided to the application, signals mouse click on preedit void mouseClickedOnPreedit(unsigned int clientId, const QPoint &pos, const QRect &preeditRect); //! ipc method provided to the application, sets preedit void setPreedit(unsigned int clientId, const QString &text, int cursorPos); void updateWidgetInformation(unsigned int clientId, const QMap &stateInformation, bool focusChanged); //! ipc method provided to the application, resets the input method void reset(unsigned int clientId); /*! * \brief Target application is changing orientation */ void receivedAppOrientationAboutToChange(unsigned int clientId, int angle); /*! * \brief Target application changed orientation (already finished) */ void receivedAppOrientationChanged(unsigned int clientId, int angle); /*! \brief Set copy/paste state for appropriate UI elements in the input method server * \param copyAvailable bool TRUE if text is selected * \param pasteAvailable bool TRUE if clipboard content is not empty */ void setCopyPasteState(unsigned int clientId, bool copyAvailable, bool pasteAvailable); /*! * \brief Process a key event redirected from hardware keyboard to input method plugin(s). * * This is called only if one has enabled redirection by calling \a setRedirectKeys. */ void processKeyEvent(unsigned int clientId, QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); /*! * \brief Register an input method attribute extension which is defined in \a fileName with the * unique identifier \a id. * * The \a id should be unique, and the \a fileName is the absolute file name of the * attribute extension. */ void registerAttributeExtension(unsigned int clientId, int id, const QString &fileName); /*! * \brief Unregister an input method attribute extension which unique identifier is \a id. */ void unregisterAttributeExtension(unsigned int clientId, int id); /*! * \brief Sets the \a attribute for the \a target in the extended attribute which has unique \a id to \a value. */ void setExtendedAttribute(unsigned int clientId, int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); /*! * \brief Requests information about plugin/server settings. */ void loadPluginSettings(int connectionId, const QString &descriptionLanguage); public Q_SLOTS: //! Update \a region covered by virtual keyboard virtual void updateInputMethodArea(const QRegion ®ion); /*! * \brief Informs current application that input method servers has changed the \a attribute of the \a targetItem * in the attribute extension \a target which has unique \a id to \a value. */ virtual void notifyExtendedAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); /*! * \brief Informs a list of clients that input method servers has changed the \a attribute of the \a targetItem * in the attribute extension \a target which has unique \a id to \a value. */ virtual void notifyExtendedAttributeChanged(const QList &clientIds, int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); /*! * \brief Sends the list of plugin/server settings to the specified client. */ virtual void pluginSettingsLoaded(int clientId, const QList &info); Q_SIGNALS: /* Emitted first */ void contentOrientationAboutToChange(int angle); void contentOrientationChanged(int angle); /* Emitted later */ void contentOrientationAboutToChangeCompleted(int angle); void contentOrientationChangeCompleted(int angle); void focusChanged(WId id); //! Emitted when input method request to be shown. void showInputMethodRequest(); //! Emitted when input method request to be hidden. void hideInputMethodRequest(); void resetInputMethodRequest(); void copyPasteStateChanged(bool copyAvailable, bool pasteAvailable); void widgetStateChanged(unsigned int clientId, const QMap &newState, const QMap &oldState, bool focusChanged); void attributeExtensionRegistered(unsigned int connectionId, int id, const QString &attributeExtension); void attributeExtensionUnregistered(unsigned int connectionId, int id); void extendedAttributeChanged(unsigned int connectionId, int id, const QString &target, const QString &targetName,const QString &attribute, const QVariant &value); void pluginSettingsRequested(int connectionId, const QString &descriptionLanguage); void clientActivated(unsigned int connectionId); void clientDisconnected(unsigned int connectionId); void activeClientDisconnected(); void preeditChanged(const QString &text, int cursorPos); void mouseClickedOnPreedit(const QPoint &pos, const QRect &preeditRect); void receivedKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); protected: unsigned int activeConnection; // 0 means no active connection bool detectableAutoRepeat(); bool globalCorrectionEnabled(); bool redirectKeysEnabled(); void handleActivation(unsigned int connectionId); QVariantMap widgetState() const; public: void handleDisconnection(unsigned int connectionId); private: /*! * \brief get the X window id of the active app window. Warning: Undefined on non-X11 platforms */ WId winId(); private: MInputContextConnectionPrivate *d; int lastOrientation; /* FIXME: rename with m prefix, and provide protected accessors for derived classes */ QMap mWidgetState; bool mGlobalCorrectionEnabled; bool mRedirectionEnabled; bool mDetectableAutoRepeat; QString preedit; }; //! \internal_end #endif maliit-framework-0.99.1+git20151118+62bd54b/connection/org.maliit.server.service.in000066400000000000000000000001361262307254400272370ustar00rootroot00000000000000[D-BUS Service] Name=org.maliit.server Exec=@BINDIR@/maliit-server @MALIIT_SERVER_ARGUMENTS@ maliit-framework-0.99.1+git20151118+62bd54b/connection/serverdbusaddress.cpp000066400000000000000000000036601262307254400261410ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "serverdbusaddress.h" #include #include #include #include namespace { const char * const MaliitServerName = "org.maliit.server"; const char * const MaliitServerObjectPath = "/org/maliit/server/address"; } namespace Maliit { namespace Server { namespace DBus { AddressPublisher::AddressPublisher(const QString &address) : QObject() , mAddress(address) { QDBusConnection::sessionBus().registerObject(MaliitServerObjectPath, this, QDBusConnection::ExportAllProperties); if (!QDBusConnection::sessionBus().registerService(MaliitServerName)) { qWarning("maliit-server is already running"); std::exit(0); } } AddressPublisher::~AddressPublisher() { QDBusConnection::sessionBus().unregisterObject(MaliitServerObjectPath); } QString AddressPublisher::address() const { return mAddress; } Address::Address() {} Address::~Address() {} DynamicAddress::DynamicAddress() {} QDBusServer* DynamicAddress::connect() { QLatin1String dbusAddress("unix:tmpdir=/tmp/maliit-server"); QDBusServer *server = new QDBusServer(dbusAddress); publisher.reset(new AddressPublisher(server->address())); return server; } QDBusServer* FixedAddress::connect() { QDBusServer *server = new QDBusServer(mAddress); return server; } FixedAddress::FixedAddress(const QString &address) : mAddress(address) {} } // namespace DBus } // namespace Server } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/connection/serverdbusaddress.h000066400000000000000000000031261262307254400256030ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_SERVER_DBUS_SERVERDBUSADDRESS_H #define MALIIT_SERVER_DBUS_SERVERDBUSADDRESS_H #include #include class QDBusServer; namespace Maliit { namespace Server { namespace DBus { class AddressPublisher : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.maliit.Server.Address") Q_PROPERTY(QString address READ address) public: explicit AddressPublisher(const QString &address); ~AddressPublisher(); QString address() const; private: const QString mAddress; }; class Address { public: explicit Address(); virtual ~Address(); virtual QDBusServer* connect() = 0; }; class DynamicAddress : public Address { public: explicit DynamicAddress(); //! reimpl virtual QDBusServer* connect(); private: QScopedPointer publisher; }; class FixedAddress : public Address { public: explicit FixedAddress(const QString &address); //! reimpl virtual QDBusServer* connect(); private: QString mAddress; }; } // namespace DBus } // namespace Server } // namespace Maliit #endif // MALIIT_SERVER_DBUS_SERVERDBUSADDRESS_H maliit-framework-0.99.1+git20151118+62bd54b/connection/waylandinputmethodconnection.cpp000066400000000000000000000446231262307254400304130ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include // for errno #include // for strerror #include #include #include #include "wayland-client.h" #include #include #include #include "waylandinputmethodconnection.h" namespace { // TODO: Deduplicate it. Those values are used in // minputcontextconnection, mimpluginmanager, // mattributeextensionmanager and in input context implementations. const char * const FocusStateAttribute = "focusState"; const char * const ContentTypeAttribute = "contentType"; const char * const CorrectionAttribute = "correctionEnabled"; const char * const PredictionAttribute = "predictionEnabled"; const char * const AutoCapitalizationAttribute = "autocapitalizationEnabled"; const char * const SurroundingTextAttribute = "surroundingText"; const char * const AnchorPositionAttribute = "anchorPosition"; const char * const CursorPositionAttribute = "cursorPosition"; const char * const HasSelectionAttribute = "hasSelection"; const char * const HiddenTextAttribute = "hiddenText"; typedef QPair Modifier; const Modifier modifiers[] = { Modifier(Qt::ShiftModifier, XKB_MOD_NAME_SHIFT), Modifier(Qt::ControlModifier, XKB_MOD_NAME_CTRL), Modifier(Qt::AltModifier, XKB_MOD_NAME_ALT), Modifier(Qt::MetaModifier, XKB_MOD_NAME_LOGO), Modifier(Qt::KeypadModifier, XKB_LED_NAME_NUM) }; QByteArray modifiersMap() { QByteArray mod_map; for (unsigned int iter(0); iter < (sizeof(modifiers) / sizeof(modifiers[0])); ++iter) { mod_map.append(modifiers[iter].second); } return mod_map; } xkb_mod_mask_t modifiersFromQt(const Qt::KeyboardModifiers qt_mods) { xkb_mod_mask_t mod_mask(0); if (qt_mods == Qt::NoModifier) { return mod_mask; } for (unsigned int iter(0); iter < (sizeof(modifiers) / sizeof(modifiers[0])); ++iter) { if ((qt_mods & modifiers[iter].first) == modifiers[iter].first) { mod_mask |= 1 << iter; } } return mod_mask; } xkb_keysym_t keyFromQt(int qt_key) { switch (qt_key) { case Qt::Key_Backspace: return XKB_KEY_BackSpace; case Qt::Key_Return: return XKB_KEY_Return; case Qt::Key_Left: return XKB_KEY_Left; case Qt::Key_Up: return XKB_KEY_Up; case Qt::Key_Right: return XKB_KEY_Right; case Qt::Key_Down: return XKB_KEY_Down; default: return XKB_KEY_NoSymbol; } } QtWayland::wl_text_input::preedit_style preeditStyleFromMaliit(Maliit::PreeditFace face) { switch (face) { case Maliit::PreeditDefault: return QtWayland::wl_text_input::preedit_style_default; case Maliit::PreeditNoCandidates: return QtWayland::wl_text_input::preedit_style_incorrect; case Maliit::PreeditKeyPress: return QtWayland::wl_text_input::preedit_style_highlight; case Maliit::PreeditUnconvertible: return QtWayland::wl_text_input::preedit_style_inactive; case Maliit::PreeditActive: return QtWayland::wl_text_input::preedit_style_active; default: return QtWayland::wl_text_input::preedit_style_none; } } Maliit::TextContentType contentTypeFromWayland(uint32_t purpose) { switch (purpose) { case QtWayland::wl_text_input::content_purpose_normal: return Maliit::FreeTextContentType; case QtWayland::wl_text_input::content_purpose_number: return Maliit::NumberContentType; case QtWayland::wl_text_input::content_purpose_phone: return Maliit::PhoneNumberContentType; case QtWayland::wl_text_input::content_purpose_url: return Maliit::UrlContentType; case QtWayland::wl_text_input::content_purpose_email: return Maliit::EmailContentType; default: return Maliit::CustomContentType; } } bool matchesFlag(int value, int flag) { return ((value & flag) == flag); } const unsigned int wayland_connection_id(1); } // unnamed namespace namespace Maliit { namespace Wayland { class InputMethodContext; class InputMethod : public QtWayland::wl_input_method { public: InputMethod(MInputContextConnection *connection, struct wl_registry *registry, int id); ~InputMethod(); InputMethodContext *context() const; protected: void input_method_activate(struct ::wl_input_method *object, struct ::wl_input_method_context *id) Q_DECL_OVERRIDE; void input_method_deactivate(struct ::wl_input_method_context *context) Q_DECL_OVERRIDE; private: MInputContextConnection *m_connection; QScopedPointer m_context; }; class InputMethodContext : public QtWayland::wl_input_method_context { public: InputMethodContext(MInputContextConnection *connection, struct ::wl_input_method_context *object); ~InputMethodContext(); QString selection() const; uint32_t serial() const; protected: void input_method_context_commit_state(uint32_t serial) Q_DECL_OVERRIDE; void input_method_context_content_type(uint32_t hint, uint32_t purpose) Q_DECL_OVERRIDE; void input_method_context_invoke_action(uint32_t button, uint32_t index) Q_DECL_OVERRIDE; void input_method_context_preferred_language(const QString &language) Q_DECL_OVERRIDE; void input_method_context_reset() Q_DECL_OVERRIDE; void input_method_context_surrounding_text(const QString &text, uint32_t cursor, uint32_t anchor) Q_DECL_OVERRIDE; private: MInputContextConnection *m_connection; QVariantMap m_stateInfo; uint32_t m_serial; QString m_selection; }; } } struct WaylandInputMethodConnectionPrivate { Q_DECLARE_PUBLIC(WaylandInputMethodConnection) WaylandInputMethodConnectionPrivate(WaylandInputMethodConnection *connection); ~WaylandInputMethodConnectionPrivate(); void handleRegistryGlobal(uint32_t name, const char *interface, uint32_t version); void handleRegistryGlobalRemove(uint32_t name); Maliit::Wayland::InputMethodContext *context(); WaylandInputMethodConnection *q_ptr; wl_display *display; wl_registry *registry; QScopedPointer input_method; }; namespace { void registryGlobal(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { qDebug() << __PRETTY_FUNCTION__; WaylandInputMethodConnectionPrivate *d = static_cast(data); Q_UNUSED(registry); d->handleRegistryGlobal(name, interface, version); } void registryGlobalRemove(void *data, wl_registry *registry, uint32_t name) { qDebug() << __PRETTY_FUNCTION__; WaylandInputMethodConnectionPrivate *d = static_cast(data); Q_UNUSED(registry); d->handleRegistryGlobalRemove(name); } const wl_registry_listener maliit_registry_listener = { registryGlobal, registryGlobalRemove }; } // unnamed namespace WaylandInputMethodConnectionPrivate::WaylandInputMethodConnectionPrivate(WaylandInputMethodConnection *connection) : q_ptr(connection), display(0), registry(0), input_method() { display = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("display")); if (!display) { qCritical() << Q_FUNC_INFO << "Failed to get a display."; return; } registry = wl_display_get_registry(display); wl_registry_add_listener(registry, &maliit_registry_listener, this); } WaylandInputMethodConnectionPrivate::~WaylandInputMethodConnectionPrivate() { input_method.reset(); if (registry) { wl_registry_destroy(registry); } } void WaylandInputMethodConnectionPrivate::handleRegistryGlobal(uint32_t name, const char *interface, uint32_t version) { Q_UNUSED(version); Q_Q(WaylandInputMethodConnection); if (!strcmp(interface, "wl_input_method")) { input_method.reset(new Maliit::Wayland::InputMethod(q, registry, name)); } } void WaylandInputMethodConnectionPrivate::handleRegistryGlobalRemove(uint32_t name) { qDebug() << Q_FUNC_INFO << name; } Maliit::Wayland::InputMethodContext *WaylandInputMethodConnectionPrivate::context() { return input_method ? input_method->context() : 0; } // MInputContextWestonIMProtocolConnection WaylandInputMethodConnection::WaylandInputMethodConnection() : d_ptr(new WaylandInputMethodConnectionPrivate(this)) { } WaylandInputMethodConnection::~WaylandInputMethodConnection() { } void WaylandInputMethodConnection::sendPreeditString(const QString &string, const QList &preedit_formats, int replace_start, int replace_length, int cursor_pos) { Q_D(WaylandInputMethodConnection); qDebug() << Q_FUNC_INFO << string << replace_start << replace_length << cursor_pos; if (!d->context()) return; MInputContextConnection::sendPreeditString(string, preedit_formats, replace_start, replace_length, cursor_pos); if (replace_length > 0) { int cursor = widgetState().value(CursorPositionAttribute).toInt(); uint32_t index = string.midRef(qMin(cursor + replace_start, cursor), qAbs(replace_start)).toUtf8().size(); uint32_t length = string.midRef(cursor + replace_start, replace_length).toUtf8().size(); d->context()->delete_surrounding_text(index, length); } Q_FOREACH (const Maliit::PreeditTextFormat& format, preedit_formats) { QtWayland::wl_text_input::preedit_style style = preeditStyleFromMaliit(format.preeditFace); uint32_t index = string.leftRef(format.start).toUtf8().size(); uint32_t length = string.leftRef(format.start + format.length).toUtf8().size() - index; qDebug() << Q_FUNC_INFO << "preedit_styling" << index << length; d->context()->preedit_styling(index, length, style); } // TODO check if defined like that/required if (cursor_pos < 0) { cursor_pos = string.size() + 1 - cursor_pos; } qDebug() << Q_FUNC_INFO << "preedit_cursor" << string.leftRef(cursor_pos).toUtf8().size(); d->context()->preedit_cursor(string.leftRef(cursor_pos).toUtf8().size()); qDebug() << Q_FUNC_INFO << "preedit_string" << string; d->context()->preedit_string(d->context()->serial(), string, string); } void WaylandInputMethodConnection::sendCommitString(const QString &string, int replace_start, int replace_length, int cursor_pos) { Q_D(WaylandInputMethodConnection); qDebug() << Q_FUNC_INFO << string << replace_start << replace_length << cursor_pos; if (!d->context()) return; MInputContextConnection::sendCommitString(string, replace_start, replace_length, cursor_pos); if (cursor_pos != 0) { qWarning() << Q_FUNC_INFO << "cursor_pos:" << cursor_pos << "!= 0 not supported yet"; cursor_pos = 0; } if (replace_length > 0) { int cursor = widgetState().value(CursorPositionAttribute).toInt(); uint32_t index = string.midRef(qMin(cursor + replace_start, cursor), qAbs(replace_start)).toUtf8().size(); uint32_t length = string.midRef(cursor + replace_start, replace_length).toUtf8().size(); d->context()->delete_surrounding_text(index, length); } cursor_pos = string.leftRef(cursor_pos).toUtf8().size(); d->context()->cursor_position(cursor_pos, cursor_pos); d->context()->commit_string(d->context()->serial(), string); } void WaylandInputMethodConnection::sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType) { Q_D(WaylandInputMethodConnection); qDebug() << Q_FUNC_INFO; if (!d->context()) return; xkb_keysym_t sym(keyFromQt(keyEvent.key())); if (sym == XKB_KEY_NoSymbol) { qWarning() << "No conversion from Qt::Key:" << keyEvent.key() << "to XKB key. Update the keyFromQt() function."; return; } wl_keyboard_key_state state; switch (keyEvent.type()) { case QEvent::KeyPress: state = WL_KEYBOARD_KEY_STATE_PRESSED; break; case QEvent::KeyRelease: state = WL_KEYBOARD_KEY_STATE_RELEASED; break; default: qWarning() << "Unknown QKeyEvent type:" << keyEvent.type(); return; } xkb_mod_mask_t modifiers(modifiersFromQt(keyEvent.modifiers())); MInputContextConnection::sendKeyEvent(keyEvent, requestType); d->context()->keysym(d->context()->serial(), keyEvent.timestamp(), sym, state, modifiers); } QString WaylandInputMethodConnection::selection(bool &valid) { Q_D(WaylandInputMethodConnection); qDebug() << Q_FUNC_INFO; Maliit::Wayland::InputMethodContext *context = d->input_method->context(); valid = context && !context->selection().isEmpty(); return context ? context->selection() : QString(); } void WaylandInputMethodConnection::setLanguage(const QString &language) { Q_D(WaylandInputMethodConnection); qDebug() << Q_FUNC_INFO; if (!d->context()) return; d->context()->language(d->context()->serial(), language); } void WaylandInputMethodConnection::setSelection(int start, int length) { Q_D (WaylandInputMethodConnection); qDebug() << Q_FUNC_INFO; if (!d->context()) return; QString surrounding = widgetState().value(SurroundingTextAttribute).toString(); uint32_t index(surrounding.leftRef(start + length).toUtf8().size()); uint32_t anchor(surrounding.leftRef(start).toUtf8().size()); d->context()->cursor_position(index, anchor); d->context()->commit_string(d->context()->serial(), QString()); } namespace Maliit { namespace Wayland { InputMethod::InputMethod(MInputContextConnection *connection, struct wl_registry *registry, int id) #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) : QtWayland::wl_input_method(registry, id, 1) #else : QtWayland::wl_input_method(registry, id) #endif , m_connection(connection) , m_context() { } InputMethod::~InputMethod() { } InputMethodContext *InputMethod::context() const { return m_context.data(); } void InputMethod::input_method_activate(struct ::wl_input_method *, struct ::wl_input_method_context *id) { qDebug() << Q_FUNC_INFO; m_context.reset(new InputMethodContext(m_connection, id)); m_context->modifiers_map(modifiersMap()); } void InputMethod::input_method_deactivate(struct wl_input_method_context *) { qDebug() << Q_FUNC_INFO; m_context.reset(); m_connection->handleDisconnection(wayland_connection_id); } InputMethodContext::InputMethodContext(MInputContextConnection *connection, struct ::wl_input_method_context *object) : QtWayland::wl_input_method_context(object) , m_connection(connection) , m_stateInfo() , m_serial(0) , m_selection() { qDebug() << Q_FUNC_INFO; m_stateInfo[FocusStateAttribute] = true; m_connection->activateContext(wayland_connection_id); m_connection->showInputMethod(wayland_connection_id); } InputMethodContext::~InputMethodContext() { qDebug() << Q_FUNC_INFO; m_stateInfo.clear(); m_stateInfo[FocusStateAttribute] = false; m_connection->updateWidgetInformation(wayland_connection_id, m_stateInfo, true); m_connection->hideInputMethod(wayland_connection_id); } QString InputMethodContext::selection() const { return m_selection; } uint32_t InputMethodContext::serial() const { return m_serial; } void InputMethodContext::input_method_context_commit_state(uint32_t serial) { qDebug() << Q_FUNC_INFO; m_serial = serial; m_connection->updateWidgetInformation(wayland_connection_id, m_stateInfo, false); } void InputMethodContext::input_method_context_content_type(uint32_t hint, uint32_t purpose) { qDebug() << Q_FUNC_INFO; m_stateInfo[ContentTypeAttribute] = contentTypeFromWayland(purpose); m_stateInfo[AutoCapitalizationAttribute] = matchesFlag(hint, QtWayland::wl_text_input::content_hint_auto_capitalization); m_stateInfo[CorrectionAttribute] = matchesFlag(hint, QtWayland::wl_text_input::content_hint_auto_correction); m_stateInfo[PredictionAttribute] = matchesFlag(hint, QtWayland::wl_text_input::content_hint_auto_completion); m_stateInfo[HiddenTextAttribute] = matchesFlag(hint, QtWayland::wl_text_input::content_hint_hidden_text); } void InputMethodContext::input_method_context_invoke_action(uint32_t button, uint32_t index) { qDebug() << Q_FUNC_INFO << button << index; } void InputMethodContext::input_method_context_preferred_language(const QString &language) { qDebug() << Q_FUNC_INFO << language; } void InputMethodContext::input_method_context_reset() { qDebug() << Q_FUNC_INFO; m_connection->reset(wayland_connection_id); } void InputMethodContext::input_method_context_surrounding_text(const QString &text, uint32_t cursor, uint32_t anchor) { qDebug() << Q_FUNC_INFO; const QByteArray &utf8_text(text.toUtf8()); m_stateInfo[SurroundingTextAttribute] = text; m_stateInfo[CursorPositionAttribute] = QString::fromUtf8(utf8_text.constData(), cursor).size(); m_stateInfo[AnchorPositionAttribute] = QString::fromUtf8(utf8_text.constData(), anchor).size(); if (cursor == anchor) { m_stateInfo[HasSelectionAttribute] = false; m_selection.clear(); } else { m_stateInfo[HasSelectionAttribute] = true; uint32_t begin = qMin(anchor, cursor); uint32_t end = qMax(anchor, cursor); m_selection = QString::fromUtf8(utf8_text.constData() + begin, end - begin); } } } } maliit-framework-0.99.1+git20151118+62bd54b/connection/waylandinputmethodconnection.h000066400000000000000000000040311262307254400300450ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef WAYLANDINPUTMETHODCONNECTION_H #define WAYLANDINPUTMETHODCONNECTION_H #include #include "minputcontextconnection.h" #include #include class WaylandInputMethodConnectionPrivate; /*! \internal * \ingroup maliitserver * \brief Input method communication implementation between the Weston * and the input method server. */ class WaylandInputMethodConnection : public MInputContextConnection { Q_OBJECT Q_DISABLE_COPY(WaylandInputMethodConnection) Q_DECLARE_PRIVATE(WaylandInputMethodConnection) public: explicit WaylandInputMethodConnection(); virtual ~WaylandInputMethodConnection(); virtual void sendPreeditString(const QString &string, const QList &preedit_formats, int replacement_start = 0, int replacement_length = 0, int cursor_pos = -1); virtual void sendCommitString(const QString &string, int replace_start = 0, int replace_length = 0, int cursor_pos = -1); virtual void sendKeyEvent(const QKeyEvent &key_event, Maliit::EventRequestType request_type); virtual void setSelection(int start, int length); virtual QString selection(bool &valid); virtual void setLanguage(const QString &language); private: const QScopedPointer d_ptr; }; //! \internal_end #endif maliit-framework-0.99.1+git20151118+62bd54b/dbus_interfaces/000077500000000000000000000000001262307254400226775ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/dbus_interfaces/dbus_interfaces.pri000066400000000000000000000002341262307254400265520ustar00rootroot00000000000000DBUS_XML_DIR = $$PWD DBUS_CONTEXT_XML = $$DBUS_XML_DIR/minputmethodcontext1interface.xml DBUS_SERVER_XML = $$DBUS_XML_DIR/minputmethodserver1interface.xml maliit-framework-0.99.1+git20151118+62bd54b/dbus_interfaces/dbus_interfaces.pro000066400000000000000000000002731262307254400265630ustar00rootroot00000000000000TOP_DIR = .. include($$TOP_DIR/config.pri) TEMPLATE = lib CONFIG += plugin TARGET = dummy OTHER_FILES += \ minputmethodcontext1interface.xml \ minputmethodserver1interface.xml maliit-framework-0.99.1+git20151118+62bd54b/dbus_interfaces/minputmethodcontext1interface.xml000066400000000000000000000042551262307254400315130ustar00rootroot00000000000000 maliit-framework-0.99.1+git20151118+62bd54b/dbus_interfaces/minputmethodserver1interface.xml000066400000000000000000000046331262307254400313350ustar00rootroot00000000000000 maliit-framework-0.99.1+git20151118+62bd54b/defines.pri000066400000000000000000000012251262307254400216700ustar00rootroot00000000000000MALIIT_PLUGINS = maliit/plugins MALIIT_PLUGINS_DATA = maliit/plugins MALIIT_SERVER = maliit-server MALIIT_PLUGINS_LIB = maliit-plugins MALIIT_PLUGINS_QUICK_LIB = maliit-plugins-quick MALIIT_PLUGINS_HEADER = maliit/plugins MALIIT_PLUGINS_QUICK_HEADER = maliit/plugins-quick MALIIT_PLUGINS_QUICK_FACTORY = maliit-plugins-quick-factory MALIIT_SERVER_HEADER = maliit/server MALIIT_TEST_SUITE = maliit-framework-tests MALIIT_PACKAGENAME = maliit-framework MALIIT_PACKAGE_BRIEF = Maliit Framework MALIIT_ATTRIBUTE_EXTENSIONS = $${MALIIT_PACKAGENAME}/extensions MALIIT_CONFIG_ROOT = /maliit/ MALIIT_INPUTCONTEXT_NAME = Maliit MALIIT_CONNECTION_LIB = maliit-connection maliit-framework-0.99.1+git20151118+62bd54b/doc/000077500000000000000000000000001262307254400203045ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/doc/.gitignore000066400000000000000000000000201262307254400222640ustar00rootroot00000000000000html/ mdoxy.cfg maliit-framework-0.99.1+git20151118+62bd54b/doc/aliases.sed000066400000000000000000000001721262307254400224220ustar00rootroot00000000000000s/\\reimp_end/\\endcond/g s/\\reimp/\\cond REIMPLEMENTATION/g s/\\internal_end/\\endcond/g s/\\internal/\\cond INTERNAL/g maliit-framework-0.99.1+git20151118+62bd54b/doc/doc.pro000066400000000000000000000020341262307254400215720ustar00rootroot00000000000000include(../config.pri) DOXYGEN_BIN=doxygen TEMPLATE = lib CONFIG += plugin TARGET = dummy outputFiles(mdoxy.cfg) DOXYGEN = . HTML_BUILD_DIR = $${OUT_PWD}/html/ # qmake creates wrong install rules for directories # that do not exist at qmake time, so we hack it here system(mkdir -p $$HTML_BUILD_DIR) doc.name = doc doc.CONFIG += target_predeps no_link doc.output = $$HTML_BUILD_DIR/index.html doc.clean_commands = rm -rf $$HTML_BUILD_DIR/* doc.clean = doxygen.log doxygen.log.xml doc.input = DOXYGEN isEmpty(DOXYGEN_BIN) { doc.commands = @echo "Unable to detect doxygen in PATH" } else { # Build docs doc.commands += $${DOXYGEN_BIN} $${OUT_PWD}/mdoxy.cfg; doc.commands += cp $${PWD}/src/images/* $$HTML_BUILD_DIR ; doc.commands += cp $${PWD}/src/*.html $$HTML_BUILD_DIR ; doc.commands += $${PWD}/xmlize.pl; # Install rules htmldocs.files = $$HTML_BUILD_DIR htmldocs.path = $$DOCDIR/$$MALIIT_PACKAGENAME htmldocs.CONFIG += no_check_exist directory INSTALLS += htmldocs } QMAKE_EXTRA_COMPILERS += doc maliit-framework-0.99.1+git20151118+62bd54b/doc/images/000077500000000000000000000000001262307254400215515ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/doc/images/architecture-overview.png000066400000000000000000000224641262307254400266150ustar00rootroot00000000000000PNG  IHDRU`sBIT|d pHYs''">tEXtSoftwarewww.inkscape.org< IDATxw|uld7JБ"""*bg9g9۝lyz"ީa %􀔄HBHon! ~x9>Yɳ|[UUBp IBBT"$ !DIRB*!$IU!BHB$U!!IBBT"$ !DIRB҅;qhdfe70# ,*QwB#GV0Ҧ*!%IU!BHB$U!!y/D5!c<3O@ zsrUx!!}T9g6 zC =f3QV+]^Ga4jNǘL^y`b8ERE(*oի:Ǝe1 yUZoN}ĄF#{Ο{ ).aGs1$=m<7xECsu7rLJΘ{GO7^ؒ˯u49Ed2QU] zO>JKTR s49~}11pm|Bsx<0dN58%n W_{67fz*\uvn]TVU1̌ F&df-y477sUs//_i牧ndpZ7vaPA*U!# #?,^BAv~1 Je}~F z-[(ٵ*PQYA||&ÇQ]Sݷ @tt4k֭gBF}1GO@Ƹ|, ihO444mg1}Kּ|V^go~X}TBqMM.q\0s+WfيL&cs}>??kZss3+VgʒX.aCςO>ccZ-YFn`>xdOfʕxvsiW6tL%}TuM57l&|~oHUU5ny7sN; ~\Byy96o\N'۷od V{9O[n%@R&lͣngDzekO?;3ǏK~Ͽ /?GcSk߰+WǞ䜳 ;+UGVA`Y+p!alAsT3CPQ*'/A!.jfVC`ȡ _P3]sWB==Pwffe˭NI53+{,0= 77;!DUCEtAfV9A!CEdD !:*N8Q_@ѷKY@LxB$ !XKרp [:&U[X迢oTE%_BBv:&UkX$ !ڑz`$ !T{P͑K: !TD! UTbLN~ Ͼ/ 1% VKN⠢IʞH}.@GO]ꚵ/NLsj)sT`cݼyNiR:WKǏ%vm]1呬4䉥ht'W2wd=.Bn w8M+S׼.©*:IGz#F1;gϯW86ɔ&UXZjW(*]w!vEyyss _Rl70)f4돮V 덝=LIm9sx=h7 qh-We԰4 f->UG^G×ۣ؊pt=&@)mԇG$Y*̋KG<۫3~ݍzʛ߭^ \1 6S+ܖU\6QPgɫquHk¨Uj@ X t 4~<Z(E{nB5~&T U0ul:No2lvZ{%j/LMmud$@QGe=G:SL(@..^`rt_i9C|3GW$5D]14+m@~(n 4F剜鯶ya_nbJjS)m N"2l!+;_TV0+Ar@ӳ{Ś|_g@'.MQ@UwkPb5oƥçjX;}9Yݭ!vEglܞ2)D0 KOso=vPidK:Tc+.+3j961.P֢j wlI(u+͑/o-+olc+ zxqC<^iKlSmpku@;2 ?+օɯܦ&)&꿝Xóu[EV:F=N@z CՙYُY2}o@E{eA<˓Ժ!HGJGKۯ!-559.~iX7.ns< nWor0ͳF3y:ʄ.*: صD'Ի$uӨl6%-N/n-;OxIxRcM%;8CB5]==gx(ȭ43(_axneaq?)V/ *F9#Lc󷕉T8uY wfWpkV XOv_ﰲ 67RHNLknɕob3R##wK?O'䣶Ym6/W Z^/]R-^&&:EQ?)ə,fc=SRcI3vwzb1)ɉFQ3Ο4g ѣ٧_C*<0ଅ ,|͆`ROÓ3J)Ǘl=4Gsưf;8aP#(UjNA©%!{FD˅ȯ52ؠUYvi n-} fzPk<4owFsUweWȏ% |9dެ]x Vc畍q\2b3Pe/˒(Ҭ~2`&X&*hh#1q.u_'l)bzZm`C̨!܏4[&UJ9t޽OӫJuuy_#ؓcL\3+vW|n>-b\7ImW$+.U9#ƷimaQKSl\Q!f5qjp4Y;`=_Fm^*ӓb.(m jWg䗤.D(3IIN-^[5֤:8˽SPYU|=5֤)ԚTPM^Ue 5m.WKƀf\~,,+nئ]򄁍$E4DsԻ*c)%3[P8c'sٹ^ nę} cw9n`myLĬ ɶ縸„D}6Oa&Ԙ8cX)b<(ICvBi.IƤS;'$%{("ɯ |ڻ) [{nL~m$6\izFV`uy$n*͝SDNm37}jq}V6;ydynݳh)ɬPsx?φ˧x.SǥV^n*㏷xhZK#[^9|sa!zMozFT ]/^3W͈*qhٌ~Bt 7QFk١f1ZR>IhW_1;^[_eFGT pT\s[jL]}Ǖ" m"IU|ocmE/M ~ q -%B鰻^ WIDMƨ kS߬Jg (|^n;_Wk?BpURx81ţ+jGc㛹rFƺYTlჼƱYiW>ZNAwƐbpJ4 6fC+ !D>WN,%M1\1ߌm?eow%J0T^̍è #3n kLoS Bj!LcIxdwD[iffurJ?>_7YXlˆh^Zӆ[_ě}'>`YN>h>wAǗqtm!%Ղ:# ZYWargv*,rvGK%d~4Ŝ0|6C61[&UI=^JۉݯMNCF4f~!SuZ5ߌ弑,M]mSlרv"G'{1\6/(dG*lruF \; Lǽ8͢VQkU)vZ>)Œ4]:Z9@7[4bSk76Q _OYN*AOKKGnbԩ0ƦXv4*R^zĺ(oS1omC3g$ejđ〒Ŗv(R k?+11ɂw`1Dl1WE{珪GndAVCp!o/=;{h½MzˤSq}f1z7^#YM80o6~ ǂU9H*BSB`2)BpP'T`M!{;fcwaO % mu{?6U!z!ș wh8*1?jQ@!Fd' GjcRݷd/~bi hx{K4_n?uL=5;!GB^@˃~/gT$U![r?z`$ q`cR=t j3RcR(M@Y J5wUN%7'rJoSXwȣ$ qj< wBT_z%}+rlQ%!DJ5wUNqbOTp!PPpݡ )w BTwIYrW2eѝ|ryDC?V=N*P"TB#,BIԀT!Jur*GZ;І1!Lڀ w,=OATOy޶E-zye_Zq$ j՝$U!DQ~UB#gT}gy_+8(gU$ !.T"J*QHP<}wW2J7@(p$U!D;YFT|'{{)Ugex_ t$U!DGw;l;hGV$x:^*+B8IDAT(*(Z%~FT}y1$FՋrv6~*!$IU!BHB$U!!IBBTLRh0TR,^uhMkM-IB2gs}7Od2EO={T55\QXłY0w;/R%cjQė22ݫJ^ۑtB(tQ'`c0jUDxaDw@amyM_'Rޤojr;* f 7/|pl;+)]7cæj3?خҩG@vJ b~\^z#ϮI|͸ ~VG׈.IB^Y;_Ul=41Xƙ<3>̦jS4,4no5jp]-1՚Zc悏tP<.Qǂ}vfQ1nc +y(ژ6q TWcdC1n>+q`;Nb |\_UHX9RZc|"<|2낕tO?.' ʯ5P"=IB^d?>u^~ǻi猨ya} 2012-02-22T14:02:26P1DT8H35M4S1612012-07-24T17:05:55LibreOffice/3.5$Linux_X86_64 LibreOffice_project/350m1$Build-3PKx@ settings.xmlZQs6~x>! !$iȵ7a/Fz$9I 'NyH,}jwZ|%`G $Equ>8}t>uٌzы&A)=E\W;N$xI6ڛ jQqJm׍8>9F1wnt=5 5Q7lzgt^e5{s=" m6ެ[lPV̭yZ){+iPJo ]ѨfswåNw?k^\Qth3ۜuo|('L0t2)WN֨^H߅>ʆoZd៞No'''Ek k6Jh"C<ĔJhgp5,@؂"2 PF !rI8AÒDT}D9:{H9THq?b%g {,& 8p%|8׌#dDmC=z.+*5NurUaCԙoHкBu |2R4C_};)UpW1U?4((ٱ<8c`:o 2)z 575[DR4 <@("sfk qmȞ Ao-"1-%+s%Uz ÜǏ?EZSWiXԎUW2zO10Rӽhʃ~Im3ώȅ5o 31i*h4 +1vbJ}7݆2TWmmDZeyB%;]攛55/ORħvOpy\vPxKgv3ޓگFTnWg5O io\琢&ޖwioiGU% URA! Tc6QI>p bF;w{k(0 u D~&u綴H >r]}S HvZ bAUY(aTmL.1ey/A(C܍Nk3kց,2,EqWs)T]ޤY~2&uz=3UqvRHqC_gb !ۓAyW{7PKsEU)$PKx@ content.xml]u`I-Bҵ3Sصd';)oŖnz$Q&nD~$9M%Ңֶ(|88ji} 4o&gf}+˲Zjy<,jEܷc1Yh2Z~3ϲt)}_2xgڵ[WYEL ,ZUw DmxZs'K. 6Ѭ: _좒$ykh***-lKɯ͂bR\}~8$G,;,;ۦYxj"x+²6(gZpSqH$ Z Ry&;Ԫ0.0.EvBtJ=[7h]lU/ cj6,lr &pGp=wj 0Ƈ.Ų rigFR\8ˤkwT♚WJťrل)^";W5۩.ZMq >R乴nJzG L~ّ̅Od^J Q..)[Rb)/˓p.ÜQ|8WD;wzzȇ\ll1sFk9GB 1j,D=D}Î7|q|-#1M[5jF$w0.ȑ F+@w~Hz}pKeDM.›8KIbcxrAf_LcЗ8*=c=H4D=e3o&_)-O]F 鋜~\W.yqPm4H}u˝%G/ *,2{/.M{E43hD_%B|DW !D !*q7B?"BeHEמ] Z^Oo׈r=aB| I=T̗-i&BDfc!( mVV='e+f/xpzF@{Su~[,nQ. OxgZAI9#]R/7Ӳ^.-wa ) H!(qp,J8Q1wjJ=m9p:n&g7~_Zk[-@QNİATw&BleƏ(JSW'8aqG 49g=]qfևsDr_N1`ۣj>Ս&C=meS=F!~Sz~M16靓"<:)y{]>̄"1QpNbqVSS(.Z[yE0 |D.Ĩ9T"OtjROP¡:BkCF#ϡ>HwLY* %f2i6lαFFPkj-ZL{uVԶKnW˛hfI%hZ4*yBkh%VBW`hYZ:>_lx$f`^ N.aJL-n;&J6ք}"d:y!'QBz=0;t"B:CQum_<-AyUqbwcl1wr|ItםJ:(r;,ac|=% жmCۆǢ 4v5v{6O$m:X-8w!Yqfo 0 E'sH',P,C~ n=)ELdILѓp'j&%Fxn{)89 NݢsMT,6>  oOAGTžSeJj5r2O;}JS|W\=:Vhq(l1FM\Y@xڋ:Lt#5ߝP\1l6 l 6q)#Dϊ} Ю1|Shۀ/ T ƴƎA[, <,B@u qZ\zaa8^ 3xN@%.ql.+( Tyx\L1u=GBZ\Bq)ֈS{ŝCQd-)w `l >̏҆Iyu ;*S>6+2&؃Uvɏ Tz\ }[x-[^'|PM%> l`]E1nS @mSQ)Jt&jnӂ:.5Lv;yC͏#|U1a?_sR0:ˆafBDP_u6y2TU]Cz0,&ΥɖI#@=K\&XQAsQ5o!LH* Pt3p`aJ}Hs(C?Is2 CMX./@U:QUwU 8'gTe$=A-0ap ?xDѳ5| XϿA|}d,-xt:6g'=a\]z|qߔOYs8We⎞8hޛdž k~&zcҝ}>ꪥ~y7moYd8pW9A("z6.O_e9qur*H/OήRg32hLHu%'4y`v2's]xyq@3’CJ'NckSvtdm0.q1^1ҰM(&#$\{nl[7|j+|HwYs,ecdy(L3pe*2[q]q3XKb{G{;5 kb>f0X/czyJt2Nk4yS &5Lj􊘴g>dShi;|4 /ab?PTC6B=ę = MZ)>"QM.C/I)aVyw 20',Lv=Kc,Rc9fh(A891Pcg 1jYnw) mc!}z:AdNSzX ѷ؄)ᖇ.'$866_,<>k;![oZu+6#m2:g9,3?\^~E)5sw3#yXNfz;p:@k3h% X8v G#FpN=)iw AᄯνS|'cm̄%Ƈv Oi0<X|Ju\]UKMwlu=l ml0ÈG`zjQ!堆R1R6UR5mrh)JL0OŠEuǧ;/xqX+fde5 eU" $#>EDnUm!aFۘ} @D|-߅,Rse‚a#RjD69.?-5ݾEjLK #.&q7jX|q`o I{q"cI'@#-pea6̵02A !0>Ϗnp5bۏ|&cZw㝞$_n& gټpV]Svtyؕ#n y2i(P+F}(R'"s0aLØ11Xˬ)̯MÛ7 o^o6=u:cزPLC2/CŹjغ>;ƑfKyGOK4!/;QL޾\[^MˡF+h{s9]Bw֘cj1ZjvC-Dixk }!.6%,k(0(u>NX>96I,N78 }4Z5jJg:]Hwm06 D"R이k!z=l`d֊ $X"G]5RFBeXTQP#s6`˹lHN< 68cUBsfYKm_4]J>7hިwgoFw~!#B4 FjeX`4zMqGr2}O6(?N%ۮ]@BϮ#~]:"B«yM W)PT"7,GPHn@[}ƯҏwL;Ƽy1T$bJ[[ Yd/Rf`"w' ;WL8Mgw.y(wxK6\^'^nARO~7qw:~5[^ -[JSw6" p]\w^y["Y%q~9=(!k(`3eʹQHn@!=}ϊE߱.3o:'a"-8iu"N|{q$)Dz2em !0I}.1* ow. yk*m19FD8"#7 +C)&k'*¨|ZýFrpӉ ?Z%MN5D" YWZVϊxiFAې={ja)Q5z5Ϡ0>YywoƳdnOECd=ٛ (qOnZ"_i.RuAm%#Xm'4c"B8d~#ٓ'ϪTH$ )rZ8@abB6[Gh) so(3` ",0/"0aXOˆEN\eK3^2;ffsAޝ׵;;m0'Fڧ]Yf@UgkTnv #솱kN0A(鞝t b':'cR]Z bGnģ)6@i Y~^!t DIõ}ᴵC~Ɛe@(Wbwgq#uy' RW<^ ]HVxV 7tVAt8@ h.$8rP_%Ou{x71/1];Ar|;7uV/b}]*$ѰDH/P~V <(\.ZstSșr]qO񗟅KJ8 !EV(یkYEE0r<|}ZTtD+P;d!/2ӸT )nZ"P٪ jk;u֢mPaZQ.s@/F>D#)VRҦbj8GwS7gtPӺM`?NC`>l|f |mo=*Z]82 xˇ3r]|q6YgaQw9>uIb|C#X5N- //+V@P{$ތJY;09@+*Vԋp왓i`#+Hs abLsoJgv`ْFXyBϺ'U4Js$ @] .q$4 __j, VQ- պ,;O '>G:^>e @hrG҃|?4Ph۟ppܸcﴽ:rnw5= V+13o1~Cska^'[&$J[EZ W  &?G)G;)Fq\!QzЭƅ\RMoRd.>d5&/B7s`ݭdf, ցh1x.{I{yY7GRtڃCk-e[߽de) <?[F@m{+`3GJ5=. (orv>l,yQT iJ@t;j.7^})ԀOvorWִX229=Dv~'1.f;憗u~O\7uZf%V,}k ` x6l@v+eǑ6`7@Hq/vJd']2p42P3S)(p V`rb{U g VpVT#x<W{rhB ]b1PC6r/,8bmxGp:Lۍ*~DMcΪ)Lkh{%ИcL`G%VR|@>Qo9Zi|bmKYi\{2~[x:KX9 i~IT%_R- #9WZԽ3G\oӡ"`A yDpkKG>Ҡፗ쓄Ck$,v zƂ{Bw%o}^ڄ)mVrahld#^7Q1 7ޔ8ajGU]HL,n&_? 묪Va&o)jZ$孷ܱFM[?O-N}jl"ɡa3޺Y奖GNXd\!/vig8 &Cj++KHJ_IGl@Q܈'6E9Zmog斸 :IT=|v;Иo=Y)w0HenUҶbf0JK^wГG=5͍?A#؅UYC<Ա<ǹsXY_d>x19BPWO1?}LwF˙]GwIVx%@"EL+صPQHկ$`\f {(BfVV#o8 /xѤS:̧99{SK wv/_>בaϘ :I_peW$VS!Aމ+Kժ0K9j*+jOr#S-*Q厤~Vm;8>@*tsX[u&VJ&=yj|3'Hbj5L.8u'J3I } Kz11g7]>wWcw$sᆰ6G!5=sh Ȋ|m=[b"_)rEºX}eY7Ge~dÊ9AܧZT _T$<}1YMZޱ%QÏ+RI1&5p%vS\"hƖa\oxh»&W~,h<(럂?/I| Fs`ׂ)_dc@ 48,K+?/\}9]׸{?-jT R>p9cg. FAfM.p  1iLyoPXm$*J E'ItKڀ @jbz5GU3Aˈ*%UגLd)_ Ld=3(dXmSU2"Uo፧t UZ@URDEhS(^YE5&@P $ %Fؘ{tc'\hKn a[q˷Cd ǫJ^+Mh Ř4fIlcuJ/db[or 0 薁90]g˭`cx5c#`KgfȜ[ kʬR)qWpO`P@՗.U}ftM `#甮7cxIHo;[!Pke))|=wV8U(Jo#{)mtj1yME:hhI}P881k E lAWTdM ouI 3Gj -ƠV5/KJHîpGI k ~oK}#ض'py/(aǠncЭ=5L9Y F09_1ks*s8\*vWX:F1﹔&_\1ቃ498 A.K2_`jk-&DL3xM8`Od*_'nBTU`D ;䫷C:^3#u-YqւFV SՁ rG[}aBڎH0c Z"2̞+ӵ(fmEg!e=3r',Cs=A *0*û{N sTde~܆ `b]Avw#* |? n򉘸@E췉>Xh)EpQp?5P=jqje-ns1\mhܐ.Od,5HH]aؖ\q-źw1{i$,yy{pn{7ݷ0pnK0&9Z gq6޲ 9f`!rUsWR9P= ,}5\#Ƣ#*B4s8m[n)txC-;kIX. xV_So5S'r/gg *`5)Kj2ٖf`3!= mK07?d%uL&4/0(h~*iG#p[&e퍀~Q6k m`0^k07m4 &jj $ K:z]/V 9X(! 7 Ŀ%<(1(!?`T">\E IJrqpe\ʥow`xce9.|aC+n%"@w$MCZ߇[kPҁ$ءf黳<qV(TW5ODaH rͣ4!3DU$>\K&F˾: Sb7U? 4I=_V"۵ w'fo kR9ąԊӼ@ӆ!]U\*W/:l~,ObRD #tkKU-D! *|ݜpl_pTn vB/ ǃ5|AMe5\l p\(?$iϴ:]6T (F|-ɱoلVO^8?k?$sվDl{\8 50.z'hE% (\d2h|"~Z#BT^1t>`Z2vI5wBy]}(}xSN̸G`*cʼn6Im7䶻3hH| 淒>_/mHĖrE&>?omՆ8Pci\㽣jD<Ќt -0h\A,{Y )ov7qtR^tC/_WY~A5WZc҈|1B1ؠ2I}.VQp5U%&b]WZZbDݳs?zSQYmW +8DBFqd&a%r(8E=;  sNfeBiZQQ'rn<!cCV}={zc)G ?Srn0*6lb:Aotj+[',P[5,fI}V?Ch-Q]ݵ>e3ӫD<;_V\ٍ>F9Jⓣp5mtiv o6ypޓ(u?Q`P,S2i 6jppB s*PF)7-m-S:RL{GP[ֿ7 (fAK3^Zf7&|+W'2\p 7L2Kߨl{(cTQ_ ̣A".Ju <]ow"=mK?I}2q's{_ӴܙG04㦘:5ȽKsȷ5^(NyCEk.gkG<(1K iӪ#^MI'L}kn'k_[5ۏguf%" ! b}ϥg%JXӟ\<ZHArE (a [R%710Xշ}L*{8\Y(7SP* buu$.Ԣb o $^WZ 0AY,QK95ly*pC.ÅB+vՁKUfI7>ZAA-i/~+Z6Tj$`ح~(~E0ypLnUc>,`~/ȉA(?wAa&8i#hMsEdox],îrzm&An6~bFa :8 g?1;Хlc`e l p!+^i#aaav$ :  Z) cV{[O.eq)hLV}ڛDofp/0S`K 0Y)k_[|9njC#1rF-;Z# xa 00)LlxbL12#X? (d,6b]-k,ΎQ˓:kR1g,"f8F(pi쐺_g8xO[q܏7̵ x c *Y3`^KQ}J2ck50t;4Vfb@1ĺC~!g<_ k7zZaICw\dF7ߵ_=׽Pmg:c!YA{{dv44!,UF_0Z9IENDB`PKx@Configurations2/images/Bitmaps/PKx@Configurations2/popupmenu/PKx@Configurations2/toolpanel/PKx@Configurations2/statusbar/PKx@Configurations2/progressbar/PKx@Configurations2/toolbar/PKx@Configurations2/menubar/PKx@Configurations2/floater/PKx@'Configurations2/accelerator/current.xmlPKPKx@ styles.xml]͎6S3=Av L^ZmfdQv }}ddm ȢXX, alx#(Z>6/b|x`Q%Km%a!= J#}FY{w%J6j>m3B[0o3'V[l6fSmk>^ E{\<(0^i|oV::&K<9~NoHȩ߀!d%[FF)hUY69$)(jL`BIL/۽HmSЯekzZig*N^U@mf|g#{+n-@SP19]4]C<+F-A)$ H*(eP >1^ԔFI@ZChKJN cLE{K{sJa`A%)e1W{Bpݸ4+ܴj‰T2 FO$q*9`u[񓫓"'Vً$_!CjC"csdls䘢E4lؐKRB-J}/(?rEU8/ڎdT+*~ibQqG-ђS3ER%)ڟSi-lB)DЩ0^?h:$EԳX--p,Vky۩DJ lRĀ)KxOAq1S1QOWN tu%kkׇDKYSEdsyJ-Q-@\n'T*^Uv@js)PI(0CGDg.3$h!J "FZ] *P(B<J7)/ A܀%-/&J eU]R[ӟg%Z&/I e^ c:#K%guVY#ۯUe"G()'*]}:ީgaVgzNqaU 'b {pa9yܢ!fbLNBS^37z}:Y*fh欶a.A^s/Nd ـZm FV%ի?6I/| `3 ƊeO3J){BH-WJoM[PaSFro>."Zd!uBA7aӑd|⏢JcnwpKm(B05Xߩ ھ7~~Yq8bt'Y$ip6tk3n!7,7#BDhB$Bw!$>Q;= !F#Bi-7&oP+rfm*oY2.Bn!da(]J,ߠbYA2y)G ŴnJCIY>M⌤+7˕&gZP揈X3AeOd JFM|f+1'L>VڈT+F#Q+ڢT W1\+ LޜE2*]"So7 сtRjE 2vEoRnMj"L&WA isILГ#,aW4xM8 zB **Ѣ#$^GC!|fͥ3轘'q9%9mvzG hgXu`m|չb|,pWf]̜pTYT]"3KT{a2g[."pد^;)bw]cf^U+*Ʒ޲8NdA[K4]NjQatSu9l>aW2+W [A)!H6ekYPٮ&A̤SP*mb~$s]JnZޖ( ~ ؇&' &1| g0)< ^w\C;p Jo3ZmC>мhu7̕%'G% XBFWm~^V6L%b"(ʞi4gJO3kL\x>IcfgChzxSw]M~G:_"ݍ&74RħD<˼QCc&e]~xy'PcPC5"YBCB($"pf;ي0K jrs!rA>;ΩMWV|,n?;gG>R1L]ݳ#nUA|2 i? E|{ >?xW'~g<.d -Osv_:8 8NNk9ՄNN:䂟kh( o8]B Cha- !p !0Zx󡅊x24V]91[л@7PZ̾:A ;>_lT^RC!UQB\{0^j 6 =ˁ _p &L]'{&2.+~笙/Or/>ԗKq &<ͬKqF|8߬/fO6ѽݘgR9ĜT73g֊ˡȶ6|d%+ZV;ՠz44MZ$ۜ2@,}&TJ@5GRٗ! @jY `]JFC:İYrt1K7wOr5!Q KQݝOkcإ|~Ӊ>ɮ3]I8=@»>+JԝGNWA=..:;t So۹oZ0b}~=ձ1|1۵z8'z׋Ew8s3Sy"e1Xz gMLrQN{TmBX0 ]2zʺ{tݮ>_JX5<~N]ka΅#䏵by js㖺z]ݻSuqY߳F9w Z3ԪX0&S[2ݚx9Y*%gY2.Ǒ1^vXEb"'.Fy NqwxwF߬$PKE.$PKx@META-INF/manifest.xmlSn +" %aҾF S5?mSٟNزW*@;C>6ShzH$/AU0]ӖҫdD II35[زݦB]xuPtlrvUe*k&NY0_!B*-Hn3 4Q"=X{ig}26 }LBiϲ׷{:7;3o8aaa Fhh(xr?vP&;0JCNhK# 6`@ɰY"2w~P'R :{3(P0Ƚ,DG]ryBs֮qcvݐ)oF<7yaY1o^wgh sn+ĹB09YD``佨{lx삚7cdʛ1iacW k0je$Eu/Rr3``Haa 0`0]Z69 9Q}Zl{{SY,HO6Q s߈&LJe&vΠMmQ{4=kWrYQ|Mkjged:T~ki3sL˛vg ,M}]TҦw/}@+c mBd;NbUaOUhD<)r;;1F7 (+'[Esuı=1'#Y̒gv~Dc6gd]yix{ԀBiŽL5$d'nT3GԭL%H v1Wݵ="- RB.;% g((sX~)nD Mi_ϰ=V⚱"W+6}8Nh hSv{k`r/ghl$573w͝aF$P62)GGM?#HPKu9CxSӅpzO<)dǣHiǝF,pl-ǐ6fZ\ L|t%薔%mzfδǖ3?ͭcƕZXiιϞL537 Y;mՖ9UV))RQgVȢ8PqtJ?i/~/F/?m`n]&ߋ2TGS00%u]#veօ,m R|ւdGyy6j˜K UPK/?uߴ0<:Õrba^-e7pmKJC!%aC]kHDz쾌p,0XqPhe/ŰV^ '<o4"{֕XkMM`rAHu4Lslϰׂ0?I!$P!=(eD?Fk6\*(hzM[x%XGau61h;sPQgfpCMZ7:V^ "F5g~Gѳ;Q st RɔʚFBM5?zfZ{Lc aj0C}0UK|%~˗cʒq7!6jժEUvIQv[XXdggӼN盘Z~ԩ>}05@6&--V6֭7nݪi) 28 md-LMҡL"b1aؐyNl.hYs/|GJcGYfAi\ԗTwWOHXKKf_9ek Z&ҦS}N԰enf66}Qr6KuDnY)6'a֎vM<6KĊh"(ǸG}zm[ q6.rjE7;xۏ m^m Mt3g$|m$q$oqT$UҒ-m!G5 f@wwۘmMoiIWC,iy^~sΒFSڨ56&U~ZKӝjT3"CGgIT@ hlV/퇅 ʮ޵ݦ{KVve¢F=GN4q enY ;'t&w"++=DMn/.O_O"2N, 8z/Ķ Kgj0W9 wTBD/rBŋ=\)u(&Ֆ,9,sfHc[eNiMPLΊue22~8xC|I?)[WZ@qnީsnT %4Jȥc_?Y019Jk>JNŭ)d"Je ilbRP z~B+ ;F *hCFGSOXUg!xmBt/ 2ULnb$΄>E 5V(\lR?r.Ir u ^^,n@"tu 0 1/gPL<|jiUWjKq)m@7I"3E+G\ؼ26oq lx$e眖ѿu Sk0p:k3~8-L7l,ڿ箣o<;mXOq~͌ r2v;A'^+,؝g(\#tS/nʿ˗/g&]dNhi[M&ۋ0GiXMV1˥ iȤJSi=l]L35gp!zUBcU6Q/iE791g-ZFJbӬIj}&/hEXi[ FGz&HrU /C*T@\?@ܞ: liiKihD `,*E/OQND," g]^DO/MxhBVtvȢ 6f{Y9>S;gd][=ϙ+f㓷wκQ $Q8tcU$ojq%5KH7\;Xش9͢僮9FzqmhsΝ6m*6h5dzu5g!tǜGg zcO۠czܠX{;xsBT=Z{t,([lتnmzu|sȥZ;%mT4;weAٻT:tX3{} )$z83f 6oȉ֭[<)dͥSD \%s(qica~_rΌ;Ȩx Oףvpy\_@]mb#xkl[ h.3j4}YaB ocz;߱ns@ANt'FIA[c6مbA_<'Q9=vᨁKvxu dŧ#>WehƄ?fzXJQi N6сߞ.ZϩPWBm_M# 9$ot*V:r>BF%P>Yας0zI/Ԉ SUc{#rf6w!%V2!?RՋt5 葊YuuϯaA&ž+H[rr]G"fGm]OR ";m\^gߥ(dXl60a967ť5hXͼߎ{&y=[6>9|M>rzW@lbgB/KtvU56>~1r۝swYwEz;-ވI`hy9 @kbeӺ^E*u[9|u"s;"wV9 (Ka콑#6A,RY'KHEl2d80 )`%AW:zOuRj *G;N Z3CfNJPN)kX0:/Ҝ9A~1̑݌>jq|Όt6xq`gZ$$$`s8Z&Eb錟?@=w? 0y:fA1HeZ >3GPڼy2ӛbCTA-l FFXҭbZRyWC/Vs*J2G~#Z~z`_ȣρ!.r|8^Zϓ!K-PricvbtuCGCf|R{tHg7Hj6;~<{1`Kl@\BW-Sxy?L6 T*wW53O[EJR+6`:#gΠÉZ.r&0>=hWO?pT|;~&Zth'¼l#S r#zu(Ya`H+06'S%u>Q6Hw%Փƕ4k܈%d_;,=q6ѧgԉoks< %`U~a0y$3h^eu=8ƱeDIvi RMZAyq`}LU.E26sƗ'!!/N- mޚfxoL3 s_۱ѷ(00 $%%999NNris$h: ﵼw YFmyqש~+ZU)1;ʣqv !!z?י1{@JKE233acףF*U̡-vnOv[Scż5 l5/[ǶNZvN~٘_oq/VA1x(: M]jO:M ^uus01G\@!sk?lP 7L!'xk# q^܆[a^IKi>&6UڔiRpStJq%@OA_mr\XO6&B>1E nn(y~~_amҰVqn>MkzLLVV>3*O~`@Sa} PbDs{>RZ7'W˫$ CӋ}էKպa?hs{?ͮR⭊TǤݘ4s̏?:88W3,1 x&(q.$(mmO.REwk)6h3lyJ,eԥi+WҫnQWJhf&9,3cc|@oʔ^|~_HuwȊʝ ]yxemsVfXh[ zXm4t^Eyc,Jm@g<{ sZ5m";ZP~]0t)t[&d#kN Ŋp^9֨Kҳj `cYRxɀeddst@ mi^li煢;<[/`֝T˫A44 E7n]lk76KKh^m܌) 'Y;=3m \նu0 CfCCRѣ6譅\ͿSviE93r`}K6)ȡqE ,I'K24!?sm4+yq铉jV$AiC.~K>EKu)e MVVQ7[n⃗H1z0G]4?,<۞oWeA6v"ghS6W`62*] =Nᅣ| tCаps`Յ53 N [1um4ytz}מ 5De!5=>А".C!3կĕ^.!7rx&f '#-[""ԥ:_ \2s (HS_Tm7 栴rvx$#;Y\4 @{boWg[h^NP{ԃ*761cl߾0$60 rׇ4hY_cǎѣϹ5DNMMLiii_m\ߥ!D?F 8ІhuB\c"](% .ꮒkjqRh۷J*n3ʕ+eJ-'K 7tPtw`TL( gh#/@"?~p.5?OW/T] e9똪-&Wxd~a*aUN9/94M X&n_cC͟tfmxb7t+eEO@)Lk/å͊^Uf }_Zl?C#* ]pusLoQ̖>ԅ7)4m4g-| & h{.~:+ 99s mPc%贷fLmO!nRj(<6ñm&UUuURB9 wT~9$ BkVy嶅']C.2:H>F%z>AV,e,!QM'ܷ5lF, TQYF.g f6"v+\wifm2;ǹАqw)\r7BIϜx!<={K-O0~Ǎh,:lKr⪛u?Vxe8zP83M7Uggj>|q|Mu/>p"oެb6.})ybȂEq\l.Cp?Dd.҆X8U2|^-"B>{!Uz?9޽q~%͐TDfz0Jaߨ y!㰟}E~(ٺo\Z[K8<-dNh,[QC@\<ʶ)$aR0UϦ@IֵJu?3 %dӢH2/NriCxe JJfleFaMWϩ@HqQ$̉\:{b>we+N{@b6̐+Kk[$ZN]cvtS^Lqn"-FG DIYv쮕n r[ž "=ı\h'ۻl^frHrKɖ0X%=a O`ɄTT>b!9ŔmAۻD­MO$魕itglDm %s)F9N>(K $Cvwj%|?z0r 9hF3fS4j h\d X>]RǙX5:.ĢfZ3iQxrCm c]xQǶR"-1x(vE=, Ў9R50VK)VBܳs䲞M# 7 Id29l7r_g*+ ZM1OaOq֎<2»5[U|Q'L6(gPlA(b+, I4_<[d9`3Ӄ?WrOAQÌmO!mpRNZ b @ %](^ c{|Bt."Qs_!da@ l&3gaV3\f!kⷃ~E'1ڈM`ؤi3!j{föiAkYj0t鷡4HF e i2`oQÆ<s)t%HJXy.ӆ3Ea{/u#8B=`9>c6@yJ z:ִaq6Q# &U<#$KrP™wkF]V3TA}蹓(Qf *8 &Vj98Bj:5/SRHUWjB9;̂E:H\f#uG}t|Fvx.g*&8CS;;h!M&&,8p՟r[ggZ(x7(qmM<:|Mvb-Ba!M/ƟHÉd"u'XR)f?f#uf7tʭ0 s7kO=9k̨Xy:aPt<&CJnJ2[$X}2t'4`:ūHqdD[~/Y36[r8JaHI^qo B^cu633v)A颮 Ɗ=5-kBۧixg?ku{D,Y,i0 61  Ŏ MϮRG[%_+8V\]DZߧ|ZO5FT0H`v1ۆx.=+-nf;I<4qεP0 4>[]K=o=WY;qGިy݃Ә/HRs:i {Xd~q8ę'l CrFL 8 E _i`➣άWswtm_- ^t["4\h#N.mx*X,ap)ĩ 0ܥ p Yeg{=K+-SL 9 "Cּ{G:5п0AR{F5t4+ClV=i5/=DH)-UCt$]|rkQwl5u)lF.DXW/B![xqq%C``09 j$KA]~\[{Z~0p`Ws$ 3'@GkƉORQK/F03H΀g5c!)^8hta ͖HzEԊ^ֳN$`4m1G3.#VT79( -a#{ ' Ց (MIgVᲤ$ O(5 #>qrEnjpx _ c ;勽 &qmn0@ic8J0(UL1fYo2zs !VW}iAN=)Za儈`<F2WW`lg`w2޽F^&su=DU -4mtݐp {TmQUVi[!DDZ. \)ǡbYqY]o1"O4 ar?|G!G+Z*gKn 35 x1rx@ʩ=f 31M~sGm25G0@f8sYΐmxUqOe8 ݨڀfe*)j6Tm=Ϗ?`S:U-(^f߃Ѳk+WM|@ޙ&I$  m.{#SvSkmч;/2Ȯ kdA/pi36b3 Q@=wS~Oo5W<ͺ!:;WبHK7Nj%K~b9tРA߽{W&F^m!T.系 6³ o Dz[oBI,k1_GdmQr߅'xԭj*FCv`M23.ig!7>YSɛBUK1Dp~6/v҆.D9)c93U2}l0Sa,X n 讓K/$lOT43::&grv)G gx h =RV}#sB3HsJo&; FT\~S6`(Ǜ0 rΨ`H87Pv"gsHEzDUԼ*ERE COgL=0owx965t&chKn=&'-&b1rj16)J^52ߺpmh0p3>gI ! ^|E< yuˋJͺ}$*Iz~n5rV 3wv:IYT~- ū2% %"6LO!mZ_ilBPPWAsy5ۖ4M [ǵPΨ6-Kz G ~.bwRݞi=F9} { '>ʦ悔ja y aMR//QVQ[,l"@4^6=i&9R8b)x r+'¶|@'u}"f*_bzjWryi=f+뾶zc6!ڐ̡N_0(}ݧgfXHOeZ#u*tMن 60%?hk8D`ыFIz? mm8JE%sj֗-{FUs~~"@q''fD]zKU( r2Ia o.!cW0~9#u?c@l"D6Tw<\Yr/#V<YloWRw*|=[6ŵ?6"W ,5ovn,A_<($_#w?Դ[x>@0_;[pDW_=Bn.ͱf0 V枡 q(5!f)Qr9s4doK:/}qln,ʺ /.DiC: !14vyj飚3'}~dw1``F˳P.'Z7WpRqp٠VFe:i.9ÔG8wL=0?'`6e gP`]d-Г6r=WOgdV(Oah#TJPZIOgPtR[7J P"(+ПyŇ1Uc {{ ueֺ'C(M Ψ^3PzVBTL'@%g- euyQ9GBsܹsԨQ6jwu<1Dg -F3rԬ:իjG'ŋrsIN6mdd2Fwۜ&Sj,gO2u~9#VvJOW\MCno5)4as\\\VVVV޽ , o>]p<BP~;QõQRGu.U3~V~3])5*8c0K0X,\f'vt/ձ_}]AΦM lle@l{pMhio2c]UGCpFffi+K^)Pa˝ӹ?EmaYLҗ6={(ЗW I Š {=3h (dP`RN̵ݗW9s-kָRoQ󑽼;w~UFF0h͛o~ I,#V90v zX6RB7?gGO؂ի{[%aΤY;Hs&z ó Es4h3m nVK_-{|Hp'KMCC8#e/aLQș_/ghCZ-48a(B3Oݭzrf"z<ݹћR,Z3MrCˊΊj|"cI8q" aZYYeffRwլY匡KZj'OThhhXXXY ʙq|ӌtP5 iqF[J0 .t]`Oji#IՠN硓O]z@kmّ2}/m䫼~n˰Wr%*GKv%=LfSIER{H+dOMS%6U[W9˨WȪoH3zL:RPLhIKyاR?r*욯?$|FIW,3p6 Tg0IX:EJ'A_L^ȝ GθBQ0w+j>?/G<e.40$zXr}&§\c @<Ltˏ;z]pxp Z e-~dgtE"'&hA8$wM*綝!* 6`G=ՋУF("5c|4dh9;C`1Nht¢(I Ud̦ LfE& Q}3.4{ 0Txgx3Ɛ]quW'˓ϦQUTwMo%*3K, \`Mr`&YWch-5|kf[3ЊgAyxzӮop|O& ,epv%bS2+xy ^>DP 55X ͭ5TYG82&?k_,Ѩ&C6CnfI b7(g̢8<)YT3:Ֆe(&@GZSXqq\d蔩*g`ybw4U<#|~)Zb!S8Ѥ,vUr9M6{_&"&7$+ /-GHura@?E aC񞴤'LQ_L&9J#m3B,}n`:ie5ݥ6Q}-Ȁiߏ{%ovY <<>K ڰ~++zXOMF̀iG> Wl#匟3ؐXY3k%2#oM+x2lWehtX~ _g#ix ߐuch]PbE6R*fF@`?~LtЏ6] }jwȱrTJ^u2S) 4bhÀf`ut(',, ǀ  Pƀ iPsy]n 0(mA@! /7̽F7KY01<o1SEG#{8߫F) O9hdHy˃)ǀ! gK-6V]q_L/$/,{rba4Lz4;ƭъS;.3)%C#3v|3--o_qn]~=#yjZ}Jecnql6a[.ݍL䊺'b"{,Sͩv䪃ͪ7qJnǼүJ'8Q 6(vu,SC_>/6 0`.7c>H9d*l8!7Y1 F$7:ۿZ‘{UEs zZRoegx,S0` 0`7 0`7 ]^d); f-RvyL0]2@侴sQrA~1€㛽9]O*w 5AlOCK*;hgOo}i]θ f,ޥr=rOőR JA Hߢ bfEUjQǿ<O:]QRaQEw`ypUN'FjOܢi~t L̸DƗ ɜF\ˆ,ʳ}U],% >]< x7c 23X d M[;No[Ȳ \M<@BH.'%K::u%hS:CPgqMWuԯVpnvr 8ᒳQhKj<8-$s]qk.|[(ra{q_Fz@z ?v[حg7{W VV-(n@,>"H(3S sNfif/T ^{3nWߒ}\9@]^"Rr o \8jaDjWCZZUAb_3T7e\ӆg':$+4<|ڰB!Ά/MQxVyjBĢ@~nyFh3((`A ț%D{DyH7ap>O ѹp/yc*1_db:a~/QW<(pИT,eHd3)g]KFR-x+ΐ8Oâ¦ӈcC?Jq l}lˇY,y+_q.SKyUZ$ĩ7?z lg9 6zKև̤w0Q$/6<[f|%]4g{)@g)6٘'ydQ/IC H:0DeM\*c=rCq{!*R }jɗ7/NJ{ZsRǛ Md1ΦCb^%< Ttȶ~ky W%oK$$zo=^ {?27b oY@@vm1j}mk6TG xHqT vn؆O/0P6\0Ópn^ni72b*iF4!(CDt'*$~/#dpU΅ 3e'Oe!!!$o l:ut5`f a0,0KbFܹ֭Az  ѥo>!)*l͛7kf@4n+;hX NKKc*V7HHcWy7)2}"j))Oqx67^'Q_oɓ gL tzM^l@>uIO%k->0;)շ9Luq"rla3m\j7גFI0O[̓<>*/!5.zJOyx,f܎x(As#XjzAԈӺyCDjo6aEu V\4S}5q{1{3=g<=N h\-}|qm|/ML؈&ͷ!zJ='pa*k:GF;yOaMd^D GmG==>qﮍra91[AmqzCM DsDۍRo"0 9M.-d+ʹ{HeǓL;{7j6e ӧ;TkI߯xrA"6hىurj8FW0}#R¯U [6Gcn[_Z[0y= l խRvyĂz kmvs{Qr4E,,͆Aòm\7ed#׈"%ÕH$F񱉿Թ0Hpps-SY |{Ƭf >j W dՎwI J౥iW7u}ЭNTwuRM:zGMBNaհXha 5L;Mry2SXt6'U}/a |v=:J.vO{e'{n!?ǷʟR \- B0T:VJ,=ieǶO'mV  Ӆy72V2gt_OeDjb5\sˀ6sCX%7<8[˾)h)wOMJ'`8(݄6Z,bL6Ons l9mP"^1ıh od~as&XJ{A5Oㅍ`e슨Md&nT2X}$ME8s&fP!w4h[{FOycKAk~t7h bp͋]itXPG<B17#VNHOɏ?kur-1¯Rk'l'NTq bA\aLHh N}!O jzλH/o)Gv_;3dH׏"N]_!3jUzLY噘i:4je&ZhЂ_ 0Zu5Qa+3j8Ь=BvcU$)3w?Gdw5NqZ~bqqM*mify#196|l̓7wM0YW5Zxb-iPN-K-}q)94?lk76o#`#^]A,֣㳛X b$H$*Ptm5T1Ym^Վ{̓i$obm7$dRkQ{B dِDEF9[QUq!*`r5d6J]=?TF%C]09.!Hʛ@WAPѬņt,l뢲jkgPuEJ?AU) s&%Tg:>M*lvNlVv@A7%i ,!#SyjdN\ZJ,?|eC}]XM޽S)E D@B; [ [EDP ;jYfgv{盝 lrvky܍4i`AV kh5D5$1BfzO,"(~\ѮW_6:o>q>\0QB)7J "" >{"͜BCrNNMxgUr}/3U2bFD[[Z3&p<%iUB+@$Q鄻OP(T!Y\|뱩S6ΠܠMˎf-; >o,Y">-K*7yIj7["_~dyX7@>frn? (ei7E@A^oD$YRd̤^ʕMZ)ּ%yS#4r`'lnnkr\IY!\'/fA7Ƚ bU+Mΰ4j =\Z|p| (>?EHPl,JaC-MzukJi[_YT/xFi,`Ȧ-y|]Cd ߀9i+S#~qK6mgxհܛ(q " dlCCޏ.Ľn- _]ys:"ɷ(yJ>-ÚR,&Cd2%`_{&&!XK Y]C2è}{"{br(vCEYFH/, b ARo|#V|],2JlRo&IbS;{xgff-.eٴE->*D8'@(CKkRrM:6c% w?!jؑ6? ͨ5,2nSieIeMa'l]+ҽ{wĆ&043 vl6) x(HImޭ|rc>k-ldQ"<"dEIBFdVMQ^4^J: kkVS?E}X&6t2gM47hQB vdk籸#jD~ R!=lѵffs> D"n&d[,`b]{MYVwqvW?R%ZNd_˺1Jm.qxWDAm*Xm:B)'Bu#I Yi4;ID6USi\gqj7mÐ)d$B7V#C5Xt8eg=ΒkO]눟ѲLqFsb׶m(ӝbnd$,9gG⾖ RdiaVɀl2z/偸21IkDۘD\Q=ȎЗP󇈁c:Y H(V{w}p95 oZǢPِNc%Eˬmך=(K*anFtyxd#&nf]ES 7 p<oV>jg%sFf<KrEzV0[i# ߶p-GQxuaM9po5. &TfBO(%+Dp'9W } X1[ 88(r\6P`#xE(f#mWi09?2U8l$btǔ{ztz7׳n}ȫ5J9>^_7 Y܍ݿ 5 \ P (2wtYⶅ_; Bo@SϨVRsȦcGi雴qe|F"fc Uj.; Rd聶P&p\ʨY p#!EF'D4噇 :ǐǂED 2VL5[:R;w *~e32I\44A)]) *o<ݭ)>;'Ǥ?=Vps'䛚EH0Lb U>'3O^#jbѻYƸwQS ;NߨĽw^_BKG7cp8Liвզy.}ȇ[{'p}j8zJ{^`E"n"{bdвU}PjЍ>h *x 9)xE"v͸oD\=hݝnڿh޷ҿ6VmU›zm{F~*!xbRM\ 6t|:Z?]\* Dŷi2L)n?>̈'85DP8 Wz86ԩsx;+Ndͤd~Ī#gVۄ2r}jДJbbx׻nZ(0_#@6??=r+F4xaewb4#sܓ{KS[گ+Wx' I_q?%Ҥ bnܺ.*|Kܿjb5$ėFa\>w^S͕4T+( od/tui~+DFw]:+ntaͶXĐZ}y'x_,ܹuDsb BDrgt1S^IqKE NV^|7UfgG"$Wmz)ٰw-o!=4ސ[q `aaG7CIh?k9r˄17rqXEB]E=WY~@6?j5TVaM_&Bfg➌$_( p%/pywuYC]^ZO]?LWn$tУTl[=|Hk#OdQٌU)|ߪ ׯ(ъvl-Y$A,NUrӕpO5!#b39J20,ΉGSt;wXTo;9Dؤ)lĻeZ|t܆gqn)?X773VVrOXeoH(~5"HU!7\DrK]ƺ_* wÉ+`ـz-/;4y5>\> r&lhN{Wf̲ p31ED! @9?qX%Jpi[_ 4,C˖#1}ڙWY[ׯPժCܾqIA -)Ўj]Y'նFq[.1dߌe٠AJjT{6e܍_c J)'zzz5 r z!ɦ+uJAIpHiY.įd@6!KXdĥ\䌔 $I}J O>};CJ Z6|UV^?4c.ٸw:~cxVg`„ b@J_PoRW܀d"Eݸ>Ϟܟ3O!EmOoTյMY)vqewY$~*Y[pwjj*M)'O{[Bn2VzG,Y}zAFֶdӴdU8_zf #?Ϩ=N6gxly 8ͭ7hLWYl{J;>P|M<36]Gȿ/  %I"jPTim0z]į:o[AO[*md gJ|75ơcqf̭߀q˓|VpقlpǴM \(h^g]W x=bav'9s귃)wo8l?q6 RTӿly3#/GxumN7 „o|1 Cjo]ONjsνԘg7GR2ӹ~Ek/_]|#*:jSm2I%C ړ]GԜyv-V޾Oo&`R:ׯ_:u C^Z^d&#-.SqbVڵs%3?HqĭA^SV6 =&">N+MIϗJ'%dgR*9!YD5{O{l6[͎~'ۻ\F#^mؾ7l6 \D'?MMq7BE$P߭'s\=63*+Zɟp'Иr[F./Cioj#yl,׻;i0[&r|m\%omݸF"{mpMqp=:мVMZ{\PR¶AڶF%X5G?] q'l]u"9E]>Ǒ2jZj9ȱr̛/-d,SDp@d)?oEQE}IW&˻P6_mq60HrvzUT Q(rFW uqɦZ1`"UNdʲsVlf)ٔF6$"kCK W^ .~>*1Q\\xz>M ~dמ%u8 ]#RVG=OU=46Af冯EuQ^|姪.|D~#;[<|c/2s8IieK r6YKӜ͙^SruG-]yatd53IfMIcGLZ1gZF a|gh(OrYd$qЮ+b˰3v*lQtܟ$}I^[:sѧ\WgadEI6vTK* od3fGCd&mA%]rMޯ*T,>(V4pwmھ jsf=Ko)d:{(uz[lU0C *t&  ѡ;f1N+hicu~hl3Hoo ' *l6 '_8gG:$~vX=p6kڕMS "t ^ӭ'Ij"`|} [*p$zf٤Et 򍤅E.:.: _f# ~Iumɫ*:)q9lGIo@1Rl7)Ԭ it<޾p( "Ո E%C}o1Amw/4j,{['Q̗^[#yi>rJH(?l>qq&\<ZTb2vM=R"_,&֋|%p DqcaLJm'ҁ;cI q߷XaxɃYWԖ H T#]?ao YCtM,jYU_h:I/QPM ;زC(JݫJd;w $ f7|$\V!HV]m,]yT7\gf=eF #_c Z?W;W'9<פ`6vS(7ZSH6oߞ(99}1crrJis$Q/@tԩ4jHO5kt ./EQ{1鄑M~~Y۷3dD.MZ1]\\~# |mС=p@. g5婩,]vM4ISSl֫WO>\333Oh ds!k׮W?vvŋ֭ K#]χY@}Wr.bWJI7Q%233k6G!Kds~􊂁$DDDx{{63Y8TVJHH޽{]uְ>Y1dU|L )=.*GAA1Yr ݳ{c! q8/Abcc܀t%XòDq;sa0bŠ|*If.]z HfZB 0KO+l=)~/.m_gxg}Q -[j5qMjn w% P@6\"(fZ8jشL@62K1^dw | 캯ESΚÆ|S!:+.&u\j?џI)_ձMæ% Fyn)%z^"M뛒G١ΆLqaCoG^ٹ4<<@sbxlWͺstsQs3r,&dI2DEDpJoՙ'N6nu[I@6=Ro f1o_@)zl]5*j߅jOP zM6{,*=trQEwtCNM]0Md'qo$?pU(H@b~FxlZ}ve*qA/ozqA̬{IXonWBWkܳJfhxpܨϡ:J<_vN[t;pdS;l`r̪¿PcnA 7-pX6i<3~Őo@X|`H' &j,3Lfy;&nDPc0b%"tMd#NȒl䂥77*(TN6& J o]EӁOE1u*|^©y,M~W9iDm oXvF]C3 mh7ΖY`@y]J&Ob~c[dI| S#cqEsU5̵W*{$RI.JLm>ѾQCw6oR XV2"JL0У.ZzzЃiwy }mCG62WbX$XrJ}#CI޵j= j{J`]m@/}>y&yJ*n}R`&)aL|Oepܟd~讥RYoO.uh÷)o(4r삓8E3Uwb>*kT42l]uKPF((Ik@̚lQ|ɴW[絢 gPM`L(ÖAAqi+MR?Y#ݦ bRq/G*{$;~:ZnX|6ocbIh>%|[]WϦo4>8ɦy[դd -c9i+3GS.`Q" D uɐUZb|i6y"`1T/h 99\M%r>% Wx?06]o^U}\vUG-Rn| aQĝ }Szz/ 1r|7wKL=A{Z rX?L6qJ-28=L~1̶gVK`P>{y}]lTQO_yRĖFG _nmjMi=`g|#*p݀i*=4 ϣh Dպ7v E}χ]n#xk?:zE-;s|SCzo{F00_0¶*3}kHUQS-v[[z 'AvB@@@@!1#B@@@@tMPP|@``陶4i/;/ΤA@@@@Hl T3_ nIM2$ #ziƥ!oOG((ÙrOXq6O5rlڷ~/ψ3S}bhd_9A0K\[2>'i |&Yk^,9lce ~z^k4<ZG6|BV<_֎oUG t4|豥6q o`IiYWc朋Qā +c&wLLJ @@@@@ %,j5LS13U]n,6G"VQZ.lptqq0`#BYj8Tά8xt DQ@ ld6#E{0SE9x FեkOK/qlE,5aVPt> >=ާid]wdKS*DM5#A2EnBYyJ >?)4dwhhng觚S >sϱD\`5Vz)C@@@ X4aϑ;'Ǥv>+ANX0a"u_0:Sp-+?3/6.ucs=zG<\ЄVb4pLJ?[RY#o>mW#g4ZF¨\jڅza4Oq?;J&&7tޟ&Ə cigIͼO'i{ؔ! @@@@@@d $H6~O&V$UԾ <9^:Kd5ZE6zוx F !YԬE y N׵lo[ V,V%rY;R 's!|h;6;֘bWJ^OxԼ.NM=|dG8s}aТ];߳A#a#-<3|w5l'<;G^b6oof_LU8p4/(/`r>]Hoi]{.Q׽s )*ϯ>Nm[x-"󰆕&y۫=@x@f _ jL{:ٿ4_ˀGuPľr`86r˙{7b!~s!1\jD^ /%y\bV` |(Y (fB_F[ O?q b<$ ^Ŵ!A;[E?tzI}iˠԁLSȆT9vR͆{oJ{ZEpr\?żf`|C׷.Qq>];HЁLȨ)3*+w`"x郖BGv<_qNw.ԀIi@Fgry};7>SGy^ͦV:LDy:zYYDZ F6 :y*Kze黢Ə+/i<b^̱=Hx:ʼy[}vkUg2|)/e@Zj_ )0&B ; |0CNS>KcSP¼ l-WFDdIFLP+;ݧTk5Z(%C6-\CePvsϬ7 O_qՄP*-7K=[{֕O(D(:]U׬ʃ-]5!@&)gҾt<DGq:caw-dc:iui   Mm=Hȕt; &ӔLӗe kh6 M*HI;J )D|!Rf `JlJ-7޶8 wTT >pMMdH$iy޺OexDg 0\{{ZB@Q"KH68?ifG$l/\ba_eYt[YY8,ʐxv͛/ל4 Ero(8ATx8g$;少.h:BAI,شhrݠasc^\\] <;O-S^WY_#"%SJ@`e`ܴҟSTLe12[)~#-}ͮP*zqѧBbYWA 41\V.pd7gJ1R ݾyvbr2GFomOf Li[3Rz弒. "r'y~D>yIH-F`^yyIiO}68\XIJ;K'BԷ鎩DB\V2ώ16 vq+yhEFHCЗ#}VS:PF?YT +~*ܪZ6'+;真 33z-G7v^^3T' doڿ[cS9w5T rbC3BnõQM];g-Gq @9tsf!c*LOD: CP[awf<w1T̔cTMԠa,)"˺hVX%(^z!h߷%>YEJd_:qR#rpVdϥk V=<72@ze! }lf"򪳙l4]O岒D}Fv4TACzϓKnL6@$ɤc9< 鮆2lJq^K&w./M} ,_c J~\hѩ\e!%Kn6y|Sk{.T7J/%{0O^8QKP)|IҞ=vkkHiW;6_H #-]qem LS*Fr!3et!98p6x16,Xp,󦷪ǔ͆4x~_nI6.[ 閛l?ܼ1i*NOT1Xz!^U@,ʙ&m@#WClВJSG݃42;˖j?'Q.ph ^#n`) }+% v3,:42Ky̾i}o$jh]R=^ⰔEggZ"B{ϟ#$vl>%~Y:}$%Z;GԞDˤ$I`MýiOnvyrJ/d")%#PH‡KW)Exr Y:|?ڳds D +kԍt@DPOaQ9/U A'Zsr'و¼?DTT>E1QR;:Ԟg^;7b4jvXE ["ڳIKvUɦ(d) vvD턒ZO_+q=3|O}  V8P&]GVxR(s}^%0ԤOH]v%PF`W%Έ|X d%RBs>Eq{4Wȼ bwœZ&PyV$,XdARSj[']?> +Y5MU )سVgz ll d<$,f-,|lԁ!~DNol2Q\0d&l6591P`V /xƽ!qlm՜/b׮]&Mb1]vul65lla%@ɠXQhӦM۶m|۷'Qncbbܰh̙8Ӱ ~`k֬@p`g@$۷l:w,f@F]:㗛ŋͱ)5 X~=$c̘1HI6t'S۷/ ؼysDDHbbJ  +|dÇ Re_]UU,-ãFi H(pjU322LLȴYfl4^lvcW ,[, ܹs>>>dϟMMMaC%@<4@9~ӧ{kKfffגCEY7fZЊ)ĤA.` J UN.Ij!w&WpZ|@O .ޓ4zifHIjvj1.O/w>> @OI=|Bսpy"-r9WQƠ:-[}RѻYf|Rii68\&t䕳w"O^#ԓ(lܚAlB)wwRcu:UD,xsRVPJEґ^5;7cUﯚ=ahvZN]*MI个Ms>&LWŗxףnأLK[ T3#|b3(8^=9:P5V+5:ȧTYyZahj܌Y4|NcpW޹RCZݏXs309~^=f/m[(q@DcoBAlkw:Ocy'G?ui/kpY;5Fo x#3XD - sb5Q3]$XB&^kS]*E.o6sGeNj+JQ6JgݟolG[;m]lzat8b͍+54u$`wLr35dg~&'tfYvcX 5BJwq/Ǜ; dC,Șivuޝ:4*b2P,.$x Hqs\=nTv^i8)N/ n>+,-?Wb18aX+/A:(> j9,dSWnt퐶c؝|K'M'e(~Ya6}~y9?or C0]Vrj:q* d"PJ" !.[lROXQEiY9y/dl%de4,&FޢH$i4PKl~fL{w:ݤ"K;g`guG}wt893Ql޸wW-1}rE*c[dL6'EuPS啅e(*\B8B{j_Ca#He_8}W:QB r-w;4VM߄ɮ5iZgǫO/2v]zymX&OVx7ܽlFrIs-9];!ytuH4Q4KU܏*ۇ#eKO鼠zdg=|%]uǜz9#/Թ3mlʅs j1r&b?4Z@ȞiQ5و %Ub4萚]w7_!z-OyYC,z6D?,% w%\Bf,UeV Cғ 051~^/\ $FKT. XiZ7E?<>E3_&(JyM4e&ybJ-vX<~x.F˘g)"SxWi2m*ZĖ::Hq ^fٿ<;]2(~ I)(<:HH2eYJɟR8l&f]*mrq!„3 +TۍS2+h

aC>XMSٔԆySH/^}!6*]QQ \!`6U:$>+Nn_ ئ~Y=Gvʝ])e/oʔ]SzrGl,ْ("yۃ#g_!lb JX 7Lsj6ax܄DR 0zZm¦fa3\*鴀 {yy%J#ǯWǐ_˥DjuN4ȆsqQ鷪Xؤ=d>^ ,EQ{0L/bJ|R>oOܻICV]um7 |o$BiBdr+ e Hdc.]zi߉gs{|a/k~~Lމ44FJV?Qbi.tɩkQrgn`&u]8ʹw%W&ie `7t,HДND`.!>4I%>#۬ [T ͑մ{aryKd f3 䘬#Djt  ߥ£e%PW2HE]Xztz7W1a4Nm5|{5xj-xkzuthCјY4[5qΗWHUZڷ!.8]jAR!NI|!uS(I?lSi}ݎQgp8CnWkQ5N+1X⋨ 4Ȭ'8`c6[;l٩ec_)) mI79A8@@3.xS)4\v=3LS,]"d Gup%ZΊ~ 7~rϤg 0xڛ96 %_eֲ3wsI p=2s)$ H6J8K.IIڙ)-Ef5噡eK1Ls2p̐(5m6ǷF]hCDTf7Uny_gqV{ͥ,_H6bʠԣڨ yp$;ήllg>-=`,[ff_ }c&:0o}Īg*YM[HGߪ6:Q/('ҳuq`Rv4˺$UA|WkWdu&~/I7H6~QEÂj} םe~-G%o/dАC!W#e4@)P'bxu]j1 `bJ25ydWar_T_Mſ<_W@@jYgDͳi̙qF$(A[{5&M7ho̬VkZ2* 6yݖcee5jV.қ^ٸx]8?7^s@Gژv} )Zu2U"d& R-ޥfXys -y|JA9lRPT%%%Y&̙Uf&Ki)PIA3C 3 9ammmAHJ5f|N ȓjl6ֹ| @09M 0 aEl=}h"3 \eoݎ3 ]Wz9n솧?O7j!R)QnPIMOi^p"J؅6" _PlLnFRPĠc88n37;;gcfHpԯenebj#RāKBkk~MJës2E*^$v!›c׾SW_Y&H"3O@ ifwqOok޴edH\.5w JN]' ߤڛM]5*w.j5OM]V!ay/]Y@j6[tE4h!N|y? T?q RW4S#C dr5cJXґ )*)Gb$|[yY2_+bOϽ"+s-īGaY߃߬r%/o釔EŦ彔nkXg\sq!^j>|NF} _XcӍ"p[Z{Y,AO).]`=dAN=::|+'[0x蚓56>}q.wRLϩLk!y,"Fe{U?l sߤn>{0?#  64c4< 2ݪ-N]}v˾ =wNaR7ܞ(z0eu HkX;5FvL)-$Jt Jt^ۼ ɜɸ;nMYUH Gfߕ7_uK/8|yOР 鍞Iz6M{"EmV .AG%ȴwbџY?S09x %G2n]VmSEċS 3%뿤y í炕=5OěG]K'<@5 2hjhkݦGAvlfr8i֮ qI'ViH$ƵlYgb@+aѪ Rl)Q~6=146N;{京+z]Si[t',f*[Ř%g |F,r;'} T''ίm;Kbq\Wєow k-ir<RU ؗL$5Te;r>#R?t7nZMP˘+:!uMमJ̚6dšR󾹩Ľ^0)lE-#R^bM:=&r4ܷvu~$-{8,&ˋoa7:t,Lfq4IՋV$|,"Ħy}9L|\_\gl3J=JI6DқԪ%A"Lzlmsưx̫ˢ+J-6pW`ʮ)L*fi-(b}  JQJdTkU5hSġ`vȧnSrYjnaqj-e: VM&چx;fɝi*jtg-/oqG_8 '`*s̅!29Ԣ䨐U5Bds05nW`Mrּ 8+'Et2y%8;d﯏-&i_n딄j[6$Pv̈́ m]lRH.&]@KrŠϩĺm{)ڼY:O*BSטIi>4|WO}j]hqጼ(M=,@qAHiprQInh<$Zp0|ACr ߟ:_BjOisi4pyfDvdnmrX)-+ I:THd2:bSWuۧ#{[g&mʆAJs{.^KlbJljDǡ6k2RyJwdM*^mn$eL2 Puv}n Y6+Cۦ|O4{#'?>G\[wJEV?@W@l㗢?xs S%%WL~Tq)[ol"=GǷwkdof'WB93"+M\gI'˪Ӟʼu 0l wç"Y*}9Vf~Qn*N鹀L\nӣʇ]kRF||U*Hu徙|ÑaUj1]E bC޺XR99F)Ou޻:b ;_e8(Қ0 6ſSk j>B% 6o8Siɒq S\.ܜg Ԗ,w0b*Us1i5\SVE3vد-^ax7Kw_{V٠A0;@ t3F[2ET?u4v\bB`.f65}憀H:?DXAaN^&aVn:hIA{? EnEf^yl d4g0w?!$EƜu$]3‘ f .9έ~]bV]^3=:|%9,ˉ~N\ bSFE 4Qr$` Ld>!^'eTG *>쥣4BELBW.LYhȲ{"Fl6sa/%Uk{e+4\p!X61rc6񾸞1YI~>P`X? dfa5D5R`M#r Iʽ.ȽwgORnO&6_缛Ba, }ŽF ߮NBZ=A'ڋ_.?&*66bdTe{4a0K~lK嶱=6[F dГ%gr1N^^[)y 9tR!hCVK뗕4Edanw?KZME̠Bs{:," "4#Sp v ә@Q M-<,EF[PxF|LYcF_KpuH7hpcX~.UwϿ t&>%.*#>MXTߌp^=^Qnr^};w"o㣺6-jm?<} rp0a`,{goi-Sr82NW2dX#'c!:)=!,^Dh[rP,$,IR Ml~3_?!ڞ[MHi#5ƍ-),2ÎLvEn!&"WJz(QciO-#|&E>M&bBɕMZp+T4JB};+z嵟F> WV7&q٦+t8 ԇ,cۂeI:CBJծpa4smI߰|O3d>4;VIV1e-uO@l׬ʬ(+ jqgmV*xW|IHiDF.*d {qsڊM)?,|~tiL%i~=&UҵMK9E'GN5#l.՚ض}ow(;2di}6I^kي >rnO :]ҶC0uF@l--NٸG#^?޸el-M2̀ Ebb"|qzWWgNÝ̪!6_U@7lɩnoU2C5ЈGumgZzȗrQ{^Wi)*oLm]yHA7B b#5XզxޒCWPষDK2rRԕ [c.[(O6EЬ]w|}ԡ-5QTwf򪥅ld (BU!t\RW;#Tn 9!H@lv+ݗ#6UsitP#Oܝi"wR{Έ+6.狍}شsU{9,J'R__bly1ߝBWvʊr&bb#(B{U Ȥ0nfTX4rhȓ_T(e%'F6LZG--.YWi /nA `e- A=v3; u!&cÿ8 ;>]n!BG8xCJc)w9h1ez{.6:vu)^2`Ԣfe \w"}cGC{9.Hn KDn4-CMj P6'#O|[0z#0Na'??*JEd u6lAoH?>M3HSm47{)lܖ(?C?%2S)ĢM 6rĈQB#,Z,'yOՆmoDI0]zu?5"$ggE!aـS/+ T@. waԜ  YMw?&9'o$hJO.'$*\'wcyus(A-@lš`{*Ģm=~2١#@[$|Uz!2$w*F-$Z[(/^F~ΚB?R9mbN bb3쥼J x©!6\c]15~b) se#>G3#fICHrD=6{g^ovm`H3R2Dr;$GbRDd$mÚ(ݲjz!2Q0l=+ES ИeY.XNڱļ1E,~&|J٨!Sa- FDYq@6R )ڲ1H?qP 6ʅrɰqcfA2np>9/ˆb\̌%KL=^krOGP)N b\\0aܓmzm=rdH|u*A99|ȑ#Alë TijO\=ҸS&)r\@гssZMRXJd[ƒF1FYr'(YRC>Y:]-rsF%/Q\:X&Էu9ZX?+CWF<<_gsXBsGOvMԴm:[j-źy󦠏Vvv6ߝfUTJޞe0 2DCCF{ɚD"Nt[~orwn%^]J)o]/%h ,?=Oc>a$Υ&ݶdWL!svJuqqW2!l%)*4BJSl0 :\L4$bЖ97kҞ6MϼX[=5v|T*e(h&|sGVIײ܋ųe1ۮdLUXV80жY)k";WB,w&t )RWaCN<<۵٭xfx A1={4 tD2P!ب\Y8NL3lV_چ,ĮC_>&2ƴ̘mW榥~~ls-{4֭^/yТˈ]xO/io?~"/IXk=ZwOG : JmDi˅7~g|O1PqqFS.w 6blg RB"実Qfn\<<yp 6i* aRT):z*I{6qh5bS9Wi,?0V~Y[%8m=`Ap?qW*& Q-~)MԥZ yI1lm8As;Uv=AlaZb%X8/5*=bfޙ'չ,? b㨽OEbnҌ1ݱx`K Lga'>%s9m)BOÉ˝&ygЭٷ2^"S\2+ih^-LV AsNcCbS-wSR䙟GE?MVkrH0SZ+٬}PwL>ȋaҤ%,bU~?lk]j摏w6ɒ" B};M;Q+xUPYOE^]0ng Z*Xg+Cf3.6D:Xn *"8 ˙%;L.7-===<>v>BĺEJsxG^P-*2]5\p7R=.Uno^>|f>=Nqh: 7c7qn!20ۑGy@F}ްaè(%fk4,E5 ^57G?D0bmư\SRot{igmY櫋pIpZ?7}dչ?{LZMJP_>}O˛6}śVBUi=ȯ퐩z Qw½ yPBglғ 4Y%4iwJ4:r?|jnnXN]t䏫Naa!$Ķl=A$uj ˞Q/n&HL!L {[q0mFp*Mտ ,ŀ(S_"ahUeV3G''rW;߷lxQԖq }VȦ; ړOG&޵kW,r|RljMmUnWZҬ袵䶄=l1`2mNq-MӲX|n[#e{PґaYAz!bV$g~Ҷ-}#%,ix']%4 dk~ıT*t 6H7>P0ϥhW}w,ch~~ݤ~vI$w7O:t,JA:4'g)bڵ3r)-qy_c" "gf7#) ld3TlQņ)"3lŔUAܶEAlE)~ff<R伤:qW2 Ni!f<z}jm CbtS Th5 my.^t{OxB69Y񔻤5IUoExY1m֝RkM |˹AW̝;w:wt 6F+?)̛ͧtRfM;mj%F * " RN4bX(Cۦ s9ϻ7ˊWˉˊ'Wg3H<=gСr gÔ[GƴxYo>Qœ!BQqjU` 㞫iW)L =bR.bkd3|/, -(5嫠 vOcEkM>Ӡ]:::={,wprxBRN}/wG-e{_W nҜp0%G?eG'Xgu0 ,y4n|,]CӤH_ ${yTn hZ׶'WF wO/M&?CmI3 :- {6J0YskIߪ%:~"PDMpP-q~E#y\,xf3M4UXȲH>no8ҡ} 6)g9THg{z~ FK! /)չHxd]zS%I9Iks7Lms >\s|mF'-h`fܯWvՆ{hF~7k=n#vD\iuq|&49F H_zO<@OZF#ڪdQZ\ǵry}oI!J4]*9Q)p9Hiz6C$6ѡ{UPгMگw97b}S'=gNs "f{epACfOpZ-k}%SM;"Bm W#e=|QΕ|\=Rӯ˓m{:RH(0b#J%-%R҃LSkmޕK"kۺaVy2cՓR MK_V!%T MLkWd {%x϶.YZ6O.2ю*ºV[pnĔ[{nԣmj=fc.6:3-cDʿi&Eip\.TS3RUOPv½?3g/Ylj?å,Og|}|n}66/힆ce$E&Alĥ2o^>9,MEK|o@F3W9m ?"B7|i4MyS1e ;AIg#_ '0&N!ar9$w ?.hWF8OG{ ?_?{FZZjl=qډWvd055l\_cPA3GyM:jAa3l,hMyi=6.wF?%nM3UgPu42`$My!gRTh\5P, ɭ"װAj}CHD2Cfe??փ$3( qXci9ɳKYbW$d//g0L}69.H}H}gZ?gy=38lЖp%ҍ=%Q2!z׬pM5#"ˬ3F~7^ 2 6-=&7_Uwcܚ/Anۏ%ϦOq6{.T3h_ɯmm)Ӳ5#gK\@iHF BFzB2h7h,F< jJ'&CS 2qAzf b#i]FAFHO8y/i}?#VFK{w.e)Uۓް4r`y#6TjZ:|pdͪ{ndj~:Rpz[͔GlU?vZaKħ|n*GYg|˖-̐Hŏl2ö;իɦレ=~ի)5.IսwCe޶m _IBB:aU_ , );3klǏ)܁۽{611qwwV'h;bĈاO+1[vAAq 2 dFH=z9s \pVVֱcǼl&WpiPo tS X=׈t}!cuMF\ڶm+W"ܹ֭Jd2Y,ݻ(WݺuOKddd7n˗H~Z(cu%s mc)L_Fj>|rΝ;#fZjIPAݻwTSN >` ԷoB)8~y~k)@Ck?ӪUgϞsqKE~$ ̤ƠA yKǒdxά'O{7c֬Y...PW c+S $ҧ|&rm;doӅ? 43ÇpLVDEE 6E dik׮SQQYrܹsm1~F,{#`jͿaIyz9Q7 LV[`KQ]]]/_ IHb±oX` B,Ҷ|D/B;ih(Ǹ3C)`jԅv%}nD٨mj b#sAnE?b4}C>c5lrjN@li5`Alj<ФO~_Ifjdp^N⹜Ұ0l}2}@lDu]ŷ2U5jKR d #3yo3dy[S][`aP4%=~jd>1k>ņ}i9M"j,?vF^wYiȑV;\H %44ܗIA^nTm PkKF]Y^ /eƌ& fԘ5NnET`:P* gmit u ~ElCGiŦlmM osCfr [BӒک,l3x|f4$6Z?KYb8ʅkfk8u~~Η|))6ytҿT'DU'ĪʙVc7X~W RrV ]|^&?6cTGVr :6 ݍsWVf!Q@;0r߫f$'o4+:${7MJCN3ɽ% 3/z.ŰUkkdeTͭ]zq!Ь\ESd/(t] M1WWɉ Z|s6riՉ2,’{[V) Ͼe$FJ)R,ESLashTCd=n9D&͒pҫNj Lw@ Ȕ x̆ZV*eW̡}I eL290. 9Zy+Y.:t,4 k[| I~VQέӴɞGi|^9!A+VUں%BPCJbQSQ!)^ش *Xў>Ő2\U]{^X>ez߰.>!G5܀zTqKfњ_1}햹5]8hk^M6҉~ql21 'x}z67nZ\.wiބT( /ns\Jג&5p X5*f_h_rhf DgyweG5} = 5|i57!9}%튯gVД!ݳ21i^)o%TU*w{<[HEAiJ,wꪒyu8N:CYCMw>-1 ^ Sj ]6.:l} 6~E^؉h95>6L;ݬܢϡ恍bH& :FB5xY/IBP8d T q֮^VY z7MĆY~CZִv)QNgUQgci;TFc)=lE]KIjJXOgP4!@jɝfQwf$~+u""8,[5#džK%+ ]פ~z ê.s(YJÜ4EU=mI $[6jU+aIjnwEyF~!ԫƱyjűP Lnm}znNS8v!2+a &y,Y[#V=&uO~i9cnUF(}>|;nߣc>: ݼ%0O}cWK_;s(ZCi1 6Dkٸ'<ڠv@+ 5ae| q7Hr t8زlrz0\V*)7 %pYihVq6?rgC16k vo%WAMpU_{h7|+q2y`QPyvCC2Oc=,'Wd5~Tu_,/·n鴏7c.Z9y~jf'DJ:6=o&[[}(*ȣmC[1ho霗WjfҢb#.e!N_;\!dUD_*aMLPI|VAZU#Jr%{,(+;ÂVc\*S4)/`N}8ȽFD–FY.=EJl\'?AĦ"n5fbD Zj|-S6w38*&:n2S1j 0¶< YݡޱUx-5h 6f}Hd-t0%矩!7gDgex(R 6@ /@dYlX6Py^!`_Z.F H@m@P60&, FN jL"&Nڕqg-G+6Gr"m&l_4dܶ'Zgzx<ɮq;xx8rzM{YJ& ek54DZkʖ.åȽ[~0u09Vx)澿}>?@Ǣi+7sȿYMs??sI[4oӢi楐''uyɐu(]?Y&h<#u;dQUǪsD&>ѣ>At͝vWL6DDCcK[qȈ~mϤ>G}-lvCNCæ:d&hʺ|Wx|iƏ5{ڶmo9nfӃ ;M8[t]Rr}hn=7^}1`5򶍥? #-ƭ4֏^9B̬>#7IPz'bשW_A' 63t9eBdj?N ,2EˢN->Hv}syE!ǒJiկ܌3n¦EKbe?`8̯^Ch5R2u_,^DȰ^S}H{١m}u*|.~t3}7FUvÞ;=YwW< V* GON/@sFwϠ&2l{WHJ5=~;سKwwRݟ&(hOhRwgu"22lxC Dlf>RV)H07us2^ЌNUU`|C[[mjfUYg3"׏vq(2}bDl"LRMS`&^y薬Sh2Sg^!<)v{JCjMW{q?07|2n϶DPU<ܰrejКa^;H$j nn91"AKdeXR3n:-]:;i`ȽR~gR2nO?pzcV=Йn$C:a<F"Ѐ FA@#_ !&lP٩ڭatF0Ee;3#O46ښVOS}ͨ_9LWm]6yǩs  v7peg܂l9E7tl벵\KQQu;3~I"ks?Sq2*zz( Ud$*_Ke}B}#llm rLE e˥/N@URz/  4mj:PKJ9"3e`TUJyP(*PTT5j-wd4j6y|,Ƴ`^x݌L[" bE9>>ʦ^ sYiA`Jm DJu( 8=UGr?tj~!;fZW'X϶?Ӱ1,ᝮMAkRH}^5R4M;:`b^(`Ϯ4c7t>:m(R3vy~c?Snh&'WlTOsK脍"{ "fE^%tﴥB!;E7-ѯܱ꽨xA[Fw^Zd"ٳndhP,?>kҬK;h#gy^^ߺeֳ߬قi`ζecO}U#3eIՎ׉dFL[t]cb] dx3pEKx(XV<#m=E{q7as{c-8;eEdj';"F&U j+p jR2G?+Ekn9lAn,^;yi&V+k mO~ۣ2l gyA-1`ζELqVlV- Dzb$İWxuk xnTa= ~%SP$^Nj #|.'~y4* îby8\aKv Z3XZSȸu{G[ n΍¼Ry6D?G5$I|{:G%ӗH~r]l܎]ŦLdh>A%y 6.S-X)M놶tmvSܣ9T1 s=a-B_ؗ ]ϊ|MwRQwsxY.y280z?0Y䳬Yݍ|<2PM-,ʃ>`'ެ\t?{cA S|:%dڪYZLجjPE۽<1#Æ'lgw#Ńφx-/LFﯯ kEwwf;r^,5u8ݒa#v8B{u<')(nTeM:˚("+f BM߾у%F-"x0PNKcMDȇˈớ,y֤6n$bGxEໍA"Q ⯞X>E?@˜_D9;_Uu6~G[QAvcm/~ƹV'f̟Qgvcc:zfCG{nt9vjz__j&-MHId,#nDYvvMLnǒ=NR Z6-K9bI 6@ՆƸ\JLVACl=ס "5)u?M0 *url4cnrF f, Ze=;<3Em,IbѶdNϟul\fQ`GG kCuRH$.̀j'"6~I}hF$%?-tѴ%-1KؒX1eϛC}O FJ&>Qդ>sQ ^BWU7&ٜv!m#1` ^Gny%w=ÖܞlS2͕ h8XkȽd,_-8$Yot`锇 vbj9ȹ͵-3Nn̻g!1MO9υPZX,5iLTh6gi7d!]$*M$:Mi*=m#KL'vGP]褟چkf6Mx l*¹|Ԅu>]9rԗ}zpD4_<8mJ&5Y_`//99#B^yTr fپY=gUlyi ,A 740J`);e"!|Wli۶y@Z`F-26bW: jR,bvURsv;jLA21 7w RgV9S?FFv\Pd'&oN8~2V i=3.NSip$m? }Je8fazbJkco4 *q$զYs'  Q8K]ul ?:E؅r=Ǽf"bT'8?9#Y'S}\_93YtS`<:h*szwcn_Jsu{mO{Hq}zݸ,]t`;WQ.}?[2bXmS7b{u}n_nXUۦ"0Ų_Ԋ A(RߥteǝWoe*nl8 Y4/o;|>!8=;?ۺ7J&k50)ܦjWa߭(U "2ͤm۬|Kò#2,M\ɼ8Ek[&e=(AcIKd?TRaQ˼3 _TTHG0ߏ9}:շvIլOa<4lߗrp"9OlpJ5t>=%|&apRvyRG{/` è(nJ`Mc*TI}P=gMy_9A"s3TZy`ƎXv\ޣKvzڴdc &<+Yv9ea1Vx慱Taǝ#z].Ĵcݰwfo~ۜC&yHu-a~w?+uj|~?aq`&fQl8WdBưv+Mjyg6>?3B XgFiyסut|M\.NK]쳁f"^0IͷG UVm~ 83o9m2]ýhhab*lE |Xyv[jL.f&bdg;m7[3#,y0|ר:egLSootJEw]Z . 0lvM=*MK҂lZӉ'ɾolm*>Sjw5%˹E4le {x5U0xsc*w_C6JLS)/Lz3_b Y^)s)K@  B t-mދS&Ńa#æ6t׵ִTEܢY -NVr 9$ -삄Y1̰73/B*:qcz^_PU}_B; (8o ( (J)(v}"*"vcwc(J "\~{Gpwfwg;qgPe3u?le5FK! "6{1XVp™”_Ŝ3Z︁U%ʋWgk YH&kɁr}BU*p0LcV6klRt[s3&IBVm`%QS͑;J܅pǙ59qP rhS}A>{6{v׫2H >zPuo3Nei1gXOX[Zh|W C͹&\qT [U[n3fۭ#هxgX/WoV'’j>_VqZPsc ֫i+Q-6YFNh?1h AH&Y+BxPz?,0S7{(ɯ݂#lX:n3^z~+ҍE[fƓPyd_3jV}9 F 7 Pĸ ]hϧ 6׻K ϧV+b P!;}( H-Vh \ !/#݇nJ:~>ߪazAV}~o1imP'j#vu xb`%49_- lWĭՄMe ~> T6xN7Ϧ6];#"H90TzH4+!0|p@\fL} 1E&Kx+ܩ++dQ (0 y@b/-ue :Q,|#I:3EzJ+?֔@'C-w L26DO@淫P"rX@4([(;X^ffcmueAA7 G\\ܷ?]Mmn:)o>?1:ȩ!o+wCy0O6D!vAQCNٮ+EPȅbҠbm DIG@ `!3Nÿ"ܩk]{ YLn i[A0+ Qk_RA>h *=A-kœ 80 hVW]s b'7X>DI¬T`~S^R#-P*QL6OD"+2220%+@Qk޽0W$&&k1$ VhVe֭ WC>=.$ll܉gϞ wmÆ fpB[[[qq2` a%bccmll)m\|qarfV =z &>}jff "| 6  ,8x h T>|xS699iiiJ?ԩS׮]c0СCO> R d2x===`acٲe[l[nqs۬eVIg-#ȵsM&tEK$w|:^4:cC%y"&*{Čavcmjj8// AqjF}ՍՍK+^Hϙg 5JsN}YYY^;0X۪KB  꺿j )s J H8tK [¡YU* GXu Һ% iXe%;w=sd2onq֌ZoWMհZ734R*;y_faL'i뀩@ۈyu|ФüF<ҸxyW E0JRIzóMgn0 i!~ҳEֆǶsAfvu<~mQ܊ϞYfw2H'd:Sr﵎25ęL!r&s& $-*NǫFO'a&3h|ɴv%ԥĭm^Jh v6뫇.zu4jLX$0po0]-B.94gp30P5f`Q6j6gG;G'\A) Nvm0x{۲UR<@fZ`LGߘ*|Em;3j8Ƚlc3+"L{øH@3>؁ȫzޒ+D\c9mwx8fj#ԘL&IqTVnSrR./`(=~qJ1Vrޗ2>|)yfF䂜C]#)~xU,Z*#&_ϵƞ9 t=7]Ebju5{gXL[9&}=,Z&=o1"nTamt82tJ{q8ؙYORr6?WgXO;L_?v))鞱NGi{_H$jA?/Լ2|.Mdr`Tg IZW˲Mn1Rh}60Ī+5M2ŕ Dnf]s^Ý]W&a1\'cXG ?y;Ҏ4TBoƉ%o~ZRPٱh:S?WIU;Gr|:T=̃AMя&Acl&eq2çՐ0y+_TqAki฻_$MLk[0Or!EFsyg9m>T~٭ Vkݎ :1WAf Ho/]R_n##&Q_ØH_ 68˳`x;Rr5N\LptWԣm&bMG^z/T,W")!߿d;j 07J/RX~,?d!j|G/xb'Qw{.wꁠ%~gzҗ'THnHĺRW;n$՚=cggYv3|ϥ񜳢gq:YDLV&991Z3i<TmO7a+\ j&=^Ag KjtMɝR+H99>=^}.̉'g|!1 t/Q#թ]Qgݬf0{5`0zLU?Gg^68qy5W\M?g90t>sgobە;󻓻{oW4BzgAj>5kD5tYCKG5r"#'ƍү~SAڬKε.a7zu,א9x_UG8=~4B5y;=<Nhz?I@2sz}hD}Z^{5?i[cݸzUL*L19u4Cw"1/_64lb*~FJDzMO 6^ ؇:ao W/v^5NrȘ6 m{I\ Jذcu?ڤTV7Gaw5^\^a6253/ @Ö7!<`G>X |jTZH$ C+AC@mh6"ey7gwpNNC3xtS㙙gqϟ}r ;[fux8SCo 78!zߨ~˨`F~H 2!2^a=.GE飖kؼ/ ;:I)<'ֲf:t)@4{& %tv>{`h@K۲M-?Tg!bMX!t§,RmSH~چSJi%iZ:/ڐgTҸ6e) ?K~9s> hZ]t~?$7ۘw'B1zxhs~%~Fh:t5?VE:'%8|E^]4"06n" ʨ?saOtmt\nG l Æ6#.G @ɸIh1c I8尯qՏTV@شW޽RPj m$?ǩe8+=VPQ+K#(+"OZR+ h!܁2׺J!yL!Mo⚽&a`iOY #51:wmܧʙ~_ӢjNL:QEeɄ&W]s8ʰJ99?E@39aXJQ5@3 1S0qA2Яt{{Lj9?n0E!$T NCv8~W H(Ic>e1Ҩ1! qw茡Ǐ8DGQ}z+ (| ^ޡ/CJ8I>ו!ۣð//=S$:IuPƌ֮tW̎esSRT/+c/%AB.nsfbQ$*OŏUbkfءugogfU|!-#mdAf(]֢ĄXC&Jr)6m0ex` H*~uҊBG0?!dk_[ 5-i'# 6ʚMઇ0ۙ=،(H)= @ss,_x'X*\8Nu' X6ƽyrG DN76_pHd:_8@ơ ]Ya#*(*_-}}`a^ 9SmO95 l8m _D;yǭP+I% mtzQ!?p'ʒRxS)$K-B%3^ A}5ʫ|ʙTQ3L81dɶsFRO $ejg|}<,Qm(ĥ &CfZi /&+S?40ZPQL[N8K*ts Ȓ2LDܞ-Z6\yϵ g!$o1nL' ` ^j;@P3 3/9-鏆u9sآg =/D;weʮNA!o:hE!-5B[azii6\yֽ4dR3}\)!S&?\Ar394zgU`п}F>Y#|6z07$vaQrrv]4SKAqNT^zrZ9[:8-hBZ^k>6 :MȖR*aP<O+]Y~'/~@RۈUp/eCqFX*ylǘH7~Onֳ )D2gz&q}(P *d;yIʙ%9EnGqREu Kyl+-MoI᮶Ǧ5 M4 Li[miI_lfsp?o(ԟ]|:$c||7Xqs)T8C9KĤZi\HA9-л8^3|uaU|2Y;4%; b)%NŇe&r.}J5./Ϭs0nH@W7bm=I5{|,$:bޕ?uN U*3}y@VJ?{Gؾ^ǽ@)/8_|e#gET7pz.eZ;E!6E1ۗwPeߞWk/'ǴXo[4N{FGlLg>T:Oj5|^]J;̿^͗+7:ɼDɁZ%/uk bc6C3lnK]__;l?;t$`I .bHhqe(ǝY nb]`T(4)WĬE헵#mS&ί%漋x`㽪YM^4h ~W!^W. 匪*kAcBV7jOR1[)eIMqb+(s~^_) .Be7QZGHBV:N{T^ 7EFػ[qd&q~92~"2K!?*F6)؎ iCT0Nckkc_L1+od2O*S_RլRT_-eX6@Xл:JC'o3!E9\)بm)^4%Ut+tmflEbm%1T{c6ʛ|6UրYEUO]u~j*~4lJڧfQQLXFzr=սZ#Xu Kc٪ U'޼peKj;r+#kIrA}A ݼǸd|yԻUu1 ٸYמXnˊn$$dw\Uo0 F;Y}ofPOYґ]{ӲlDGa &lvMif 7J)tHisE%^RMU垦_j]"#Oz/ Pz׺i=bZ۟`=AamG|s.f粼$MWՍ]w|/!c :Xڋ(^`[?QCp:[zPd(܎6 D*%5%)ܞ?싡;: f?uoʹ$ޠ:u"'Nʓǜth+}G]c`"ƄQIL\8qTy+ OH+Q+bvDz_Y)?sgbSQ_KAMA/58IsMж!ViUc G>JzfRn K7:=f(Sv'&Mqx*㚯nJ6 (my,A6Tgd| `68B@~ZrA 1Lk?8tLK+wSіU\D޶wĒ/`ЮSXbbi.vkt6pg54+-t.\g˙Y' HD(5[+Q)ԛ~|d/GaEkvܬ迄zcUbts:ѷ9i<d.lH < X?L! [a ^(/lgI[!Up jl% ~Jc?[}>~haVSL dnmCl0)Ճ< ݚwG~e$F&jqiG6|6* I=R9J秖TL:~Qa!.b CABNf} r'䋗8vs5Ȅu)Uv'W>H1RoAkS-Qb6 O}^>&;=D'%:P(߶[ [)Y#Fw],QN봑+d=oj32Yn_{l!"wL   2?]&Xi˞Y-k[cO84y4(/r1u=>=4kPyIa.Kw veGMld]m#U \$tm.|hR` ㊉U@s%o7[h'rvelPFP(uƓ<@l2Iv]n86<OBnn_hK11ҷb?7\ q}KsE6GUcl6X.BxpxB+g41aDŠ׊.On޴:|^ֵ;U5D7[8sɓ]Г]D"]lF1r2a`3>BX#X`O@{6,z' 7~̋ {Dp827p߀M.XEE@ܦ`FZxJo }.qθjZ“(0l.SyFS.죂aUȔ zu2h\Vvk,SBP`@=*.Joϴ:A Fq/Q;<*o0 <}թp'厺k+u{Bas.XgԬY3&w4xZj,U'nv)/)<:)ÓnF lWt]bH 0AM: m#oެA:{2~lzYV~q]ׇW9 Fg^ wMN'4495-bB_?t'_ok4̌9ߟ>'µt2.;L&9QB2{"7k2 JGīZ3ՠbva=^_=? 3\bܢ`(xiW#ꈛo[G['`uנd2nywGQlx~{v3HQ۰!?ZKdrRBi1 юT,4@wAQ|OڔB1̪AÔ"L&@`J@T(!_&@9 0 ı'ز8)5{a&24JI3(A-,/TG%ܭq&eEJH29U^'16?!Lpz`2?HWw,¥S fc~C&wQ+ѐV\i[qv%eD3({3zX>5h`.mM̠~'})7-!7-1/= 3 ү[k"׎,sӗ(V8XʹW_3 K +e뇨-^1 _0|M)yɧo0A#;M]L^\hݑ폼7FhgsJuiN=f/Tdr l_d lRcA"^LXRYN3t~rj˛GnF}cqFa^yI! f1}LGu!d];69kΪSFQg (j 9bЫG|m{.nn\UkIḁS޲4tx ziJBIIi}Uio] nNIBNQA1*8ķqbOo+⮈t;00pϞ= boo?zajό"I|8/:.XU{<%D,RVM2uYbIi 'm-E^:kD_9{ [S\ Sc5 93Yb)^ ]o_;~JCN}vĊcS% NuppؿJ[Pü#eOgNN5\8uujf F0ӏ{GLU0`k8'?z, s-"olY&2+rV#Oo{ 5.o9poĞ]b$sXsvrnr'O VCp[Oc ip,ȋdQk 5g9vtuըݻw/:*A@ nUTC-vp-NqLPؾ(lJW.VdHzn㡲JR=r:eXZ͡kyqltϥX 50b6gNcdыPz:;N{T~}>y+EFػ[qd![1kYbm+k}؟ (:} &鯮iԧ?Q~lyNxΗj Jɲ_qNwy+._7yg;13p{ l5<ZA,yHC:¦1-O`<ԓq\Ҳ-? R7Q =gMݻ/thqRQپvi7 :!;^eh%K ?U~no/]wC1L^`Z>O{ɔS`[/EWl8qŝs!JH?/)8bhrR/ s:WCs`(`3O0<ұn @IɈ Z|3~ƄW>ZL:sN}XAS_Q@(SW#Vb;yk./-Q^]5D 1_c풓 jP*P/@V(|漘fq4o4k.Z:RWbe=v-qt$Mt !AѣC m1f/}n+Bj&VHڦ!.N#UKW,(BT%+2S@zlf(-]L"F( \AzVK<wWMWA @%J?W`S^RZu-W.o6k`fr +UrmeRn-;0}#,LC!cV}Yɠ;![6OUв| yY.!ηo}cL l(s L^?m. XMd`pL9j OJZ?p''<@acM갼;kž|G^%rΔWDCLIJ!lfp@ֹ N;hxuO:n%` ˛ݓd5DŽERaSZ(Jp+ߴpgrzu%N<#g񫇯%ܚDoYDԗ'>nklPB@N޿D)q.jp.h4ܭz好JxvS24(%ASO</N*cw/AQ-K7+nU4o%/T YǴ7Xu׽v:p.ŅmᒾS&pYS|+`eT´Zr,,*,ά%32ȸ9CJ `H"A6HN)}ah泾:V q  JF_TГuSL R/1EGUg?òw Zol:-Bʘ7T0͠OpIܪ֥~U]A?enGCz6pg}#ቤQǰ K٦s }VaRVzkӳ۱}>#gb L؜]9})MAP#X|3pg[YijC5g_Q_ދ#T鐱 Nkї̦ǰA5]S Q8Y+᫘5$iIYr*$II h g }2{WHp[`LO8Pc" ӶZNk9ҩ.?VEð3$8%À’/_ڠ|_RY:$\-Ym8}b/B$ڴ 3M2nOZ7*g >4Đ%۰_S=j [YS\[_ծU {[9XO$uPM^̔֟I %};#H09_\J.֑;?\;LRnļ>v,(IN<@(#ɉ  uKKfeϸN S$1iK1MƯD }tR]b8Э+]6 ۶8"&öݨlaS+IEɨ~ %٨Abr<ͪߜнnPBN^s yaw0riSx>.0w]wu qq*,=%DPРI\M9_1\fJK+Q\Fݒ1W5-SY^riM>?`h{ qgvQ3*0VΑUߟW׬ujQ{ͳe4ü#%">Wtq*uJl'~jY-֡]w@m*DFS(eD:]@8a(&m!I~s[HPP3π*x@s+.ۚ\G@mA\tdlSV=~'5|0=~:̧Eۘ>:؁ h ~'T29.ڝ2[ۀ@M'~:;P1s%7M*E{;pX3?{Ulۉڻ;[&]A(v .lʪeHuR-YMTG`6oF@aɬf){tFr!XQ)`mZV8Fr>d >AKʷMq_XN:P2yߋ$_Kq >50hW;nw-G4$ІA>Hüm)@N'Zv[mT0f椚y5d<;"^*7Q&rr:=PХ2@oPuxJl S)~22  ͽ!#pQ@N4ML`슻mhd6zTA. ^ n$`z!U(O)';1h/d;>gsx'/&.lR/#=Lюt}_U {;6A(U-y A)2Yakiikmc9smLA܂;6C-!!΁QX^YbH؁缙k4-d8fLZYK).{f02T2@ )jʃ%S`(n:x jw#(L(/),Lv9PZ>᥽:Q^EփM>t$ҊQRq2>3;\eP36#u6fvzS%*hv/ @,z* M5^)~>W ͦ9R>2:h?`)g_lV? '6"햆R\(2c"Y֊RYS3rWdL؅tVDBUԲjqۏ~uyxu:!*sj5#tl_zL~O˳OSwB;@@1'iׂDg){eyk$~aW_?s&ym"8i#7b¦6 qWhK㍾UP &4ZʨY%cu@CřyWkNYmyLQSMá6N$NDf^D{> KxI}~,y})c(+ Y'/I3k\Cu v/~^PSRc0X@!6:v]lz?Mgf_bO8>F/<0UU3PӐ =2F7LSbKK mlt>qWb;?6ZA[dj aX#QY_`z=v+s[nS"2jQv`%^cįq77W7x+ne|W&zzI c4fL5g5boɳvAOxkߖ!}Gnm5JACj[­æB!6~NJ H}ߓn.i)aܡĪ[VmPr<;_כ+{Ʒ~=mChh*(DYchA#'LU^J>'IG RtHztJɇ+b %O4Uo oׅmU$^ffjtgl"+)mݑa V߿2<l"z9 s ^EK`]h Or2qzN`Rw(xm}}'mFʹ} Ոsm ̀?|y b omц1dWƅK.2aCQh3igEAZ]MCv)Iz Z&#2*d4yap~{E!nU$&zoE>`ٰM Np7άKK~mBLhaMH<(X}lC?؞&8'n9 & _J@$CKa˕ikVv2\ZvMJ_E"ңOzҬ,Mv#ksҌSv&9"J(VZT elș+!3F:.X&=;"r޹uI0MؐtZwԔla0)Ф7_̺ՉZU /7VϯF g6DSzt:yȂ` H4Kÿ'1Uw7Υ ]Ȓ7t#Oty.X?TĀ@UPT` F'':{PYVU HYWj0u`"&I]1{{ #ܧ?Ϲڡ];Tg]iWq6tc#L65n݀ 'R-~KYɋFm@<,tZϹg߁)V/A)BPM? RZkv䷻Rٱ6+I+u~86疧~{cꥎ<{srMȐuilu#u?Jgx+KyUBeOP??!`cRIywѫUůMaͧ{&6lEď㜘Z6͠m$34-0}oy?86y Q~ui fgvINŬg/<1m{|c#pG 6CC)x-=r( |[l눷Y}}b[L)GK+n䄇WHN _]wps\>L7~Oa^/$N5PnJؾ= N iS<^'D 4O˟˯kg)wǼPm6QS~~+8l1Cc=Y8!1pB֥Np.5_}>9ϲv{GgX+h;mك]2p7i%ԭ 3/& ZۦigX۴n?jE;*>`iu7 Kg04Rd 4p昃%'"SR;mg jWe-~kiL&vbiɇvCQCN03u3LՀǸHŻS,Mcaб6!S.dpM?sWQ^r>{ ϻÝY[|Iz](KF\F"ڋ}ڇAەCij}ecIf]6:檇g^l8ݽ|NDz=#< j$(|FCuz!+qW=S_剜S,QB1;sOD|zyHCe2!5F^sW-0vsġ[g:UML& q0uӪ3- ;EXeQ*چ2Q7~Û(3*iLBQ92M'bg{cs䂈U,Eg"fNly:F$[Tr%^]2QnKkp` JiHUb =a16rv@l)m3t؁ofZۃ6@ˆ?F`!T $̷qw*.G7`b0E m*TνJҴFU,9>$)ZIUmιb^[%E^FRk;xV쀶%ӓUthgnt >sj<1,u<0EKqr6V!lZ^jUjtVʮ6%aw}O#lFm(̆?k[v; mb.XO|g20H!%Jؠn(k)qiz;Z&}u˘kk/s-l*<g{"rtmj[mF n-_)9{ܮij“IS˕m?ğj(aZZZ$݂QT*޽{>D"޾Uh@m^G[0Ed`/#巄zdן'R8sw^y5ߒ|g CxtlÌ`>SQRFst6S )s>?.cvxwܞ4 -8-Ț8:;{W<: O|jeוy4BR5K`vTo6 vO8~\nb'\3}>*ؾ U9nY?0= @ľ;=MI9D\1s8yyњdEe> vcwnӕn׹$m00:7czہPۖ{*?DE?xECck͇زhZ]+l'b_Xju嚾rظֶy~g}/ [=7l؁|zzwҎ`hI`6ڄ\zas` y۾8F$>~ вtr_uo ZƯɯMKنO'*,)3~mv3tQ`Iَ3#,!@NZvgAS[:(TMK}h) :򊘰1L}kOa6 7P!)/&}l㉅Ci9.WC&i)H9T9M7,6WAGDb m7)y VMBg){eyC土ۻj5MVܽ(k lViAb?e.&.ؠk2-ܷLW\MއY/e2*/^r-%DZ? ԸHAh'\ׅ}@qU`z]~qsK% 0zW(SqeٞG 8*w8bԫz=RJey&1) Ur2)=&kQrg}Un=+)^fi=4؈`֌zp_:^w8&Ak^# ~qX 44tܹܹ3h Д( a-7L>Q*z]x?oO=XElPC:wHy8:$pȦOYmFh< Gn;h!×kY4_a†CLFt^-J[Ӓ?<iNs&vxI fc ]3VU((N!) r'5L܌ώ .|wMUD=GjVZmzĈ-OuuuAAAEEEii/_ܽ{7HlUY۟k+= O;* ]f-]ZVs !$0Ď.Γ0ӇbNn+/d=eP<9P ؁ 03 pN_i}Gu8Pꗫ2jC AD獟l׮]l$;w=A (K꣦k::0gu{Kb {C IKUYUnk;<N|iYK!!$D`2 16=i~V%-V ^3նGx)pfۧwzPY-i4pPȈ>dg 2?r48'6bcpp*` x|KZU!f`E=uuhekz[NPM-b}&N[hU )y.ٚh>2Vb+?o$TI0u D v6|dd%JyS%8jd04@! i8O'c/w 7uh]_wgVw5vNg:z=T ^3""`Jm#4LNN_&ص | d0d)'T?A NdAA$]4kUv6 xX@@k`ХeߝceTzu ߨ"CYF%*ʠ[;%fO܏ EJMTkѹ>; M} ;dMZm@L8l7̂)[_"lXd~lcj5G}8 l(l;rnhf3b#~i xv%!>=;u6cwO"d9~ xL0` UΰFFFq);eG%m۞!77w>ڧNݻ7heve݌1A%_^D .B)}AnJǖK *Inȉοy4TT`DEJdQdf_㷁ܷx[[ mY!S7ퟖE2]R)FN3wxHjm9UTJ5 s˥~xM_ A:cܦRE}vvviT@Hǜ]*!&Qd;0o*͒yanmvz|?Nh̒@"a*; %YKc#)FnUϬy@Qֶ|CDpr= Fq^ ^lvT{b`CLjzi$ژt}:اܿT 1uvޚu~x1WMvڭS@ePD)Zw;=Yd *} +Xc//o)LfeIϑ}t|yN4JbMIJ&w@.tEGxB&!GdH40W"PTt6eE$u 0hdUxz[e9**Zîme2V _?7}Рo^s-~¶k}hxkg}WnwwŎFa#!DQGi@Oj8=^Ө=@غ-͸% \̊F.#e`$;}ʊ>Açu>M]{gp#-n7 n:xWʐ}"N}gW&qrjg9׮tH DZ1krO'ĹmYӡfKan/} _}R 36F&}+}u;P&mZ&9w]i` miޖW7vk7XE6:}c2 ΋waϫҏ 6_Z[DPɴo;PYKo%_'] nܷx_2ׄI-չ|:'Yk׬3Qdt _ Rue5[p$ Fb†#]XnyYJ%NQ/ #%4fj%F}mBJZ68L_e6WԋZIMv0PF;t\UciHm>ϋ+ŸyѩxÍ o/'?|*kk8f\EoAr4l!h@YAؠ*3@)Rj޴w E0}'dɽ^_!vu~9Ԛ%vg9m'` kzh}uzrI'Ο;S3`dH{n}RϋK!̥(%߷uoO(SIs%#1X De-L(U6Ǧ-َOISn |״HS5,j,ݎ: > "*KRaڡRtbdL@LLba5IV3#hZQa"cp8}f4ˇC-ʠK22#,F4Rw_t"H2HL`Gr =#bbTiy?^q *v6@0q cE״e*M&X-]A,WEQZQ}'Ub~?zoW 5I  x@>H,7npwo0L.bOrJK7 ix63B2{n׭m LZ4wsU5}XK6j!fJA Jj[h@Q2(׆BQ.v Ə2,oUjM+Ne)On'>9v)-BQΗ]VD>(@fUޖ^?r@6h}>vݗyj83ɇݹ8q%T EΓ)J.JXoaje*USJ=Qoj8ZUy`)bHa(c؅ZspmmUo>[fy7W <lvvY/ 2]A+O ZٰR͒#]QkjY?+}Wٹ\'HKD7><}"/ҭ gؿH31wBX  CeMe4iq0dNhP7W9e076yvv\E[l xPF#EuǠ羒{0Ltž_$opm?gQ|a"Tw-U5z|z40r|ܐSܞgcߑ=?°/MrQ-lsnmÏX;=??%__anaS (ڧF^ R_2cULܶ[f'1qR6w_]5 (CQ4l,܁6ΏHa|[H츞}*G P)Q^E)eAoN)ޓSf e亏1z%w:[:(BʉsXc/U,#_*K*,iry]fYxh-5mYu ;'g&i90lKxINY3.xH7x俐(Iy,ʄ_>_W-="٫͉Rdm' uC kkܟ Tǂ_2'p@y`xύ}5=3A:pkcL'X?+f.Ǩ)u2RN,zͬ)cLh"Ǫ4(/EM:|~~/>1C 2}66 ѢSWFL~ok;0_S^'>qrkWA]O13Im$.dRW+ kh R p5kbJŔ}Rv#FRZ,u)jzfB=}tpu(r7G hD ]p `ƱPacǎM<.ɓ'޽ҥM&0Ӿ}w/,,ܿ#G>}bPAAL(RZZ[nc™c|O ՛3<.oc2jam!+ԐK@Eh4Հ9?~ܷo˗/5?xA@J`2=J$'L`WuTUU;gӧO={rkxsss WaCg" n:2 P [RX"` %'Mt9 }6!!V'""rӦMkŰaH$R;m,gbcca[>bBLpu͠$hDFF%%;:Z SSSL7fee|uVgΜaŋw ޟ\~Æ"ji8a 3}Z8.FD6}A<fl.fglp߆///?w9ydǎ&dR\\"uOhKQQQyꕔ֭[͛U %~~`6"@pp09P `[ yU'\OuYhp kp= T5b~P5lP&CUz AژZ}K}}Aaɸw.2ĒNqj*Q|5tA[F|+kCu2 .4~wU#.Uf_(4TeXjsG׮)$"/. T~u%D(wγO:MpThZ.3bÕu^/ xPf6XD KVv[_ys-CXviq8];tTA6vea 8$,L=0uz X"w/}|rQ+bf܌5!S `68{ã㛰!5BHXxc=T+;"3.Ӽ-{\KiV  >GI/i8"YU( +kwW̝ =eȧ("E]AYu3&Zk|yۜ_b Hˉr7Q [޴^f%\z+vn_I,4+g\3Ņyhu(F y0{-9U/2߮+Oe˯`uRM)$Jة7SEG2 4?r %?阗]]sƅ">'QU CXG;CY8l,>Ħ$JewC^Y'Ik~~o?K3\eXKf4&qZ5Ze"Qm rk)齃84-et:vԉ}`,CTj^"tHu?H5r9/urHV>A39XSA:xx/IDr'?MdNFV珞(V,er<[OwՏӫrK)WIÛ"\﷞.w'TQqtG N{rzãʊ DG>bN~weS89n{fvxfOܸ(?CMITJTzCBZy9&T{yʳ ~o]&gP0r:۽ XI(L[ͦoZIp덣V0O[NjѴGLijqD' 4R#OG=E@f? "OP~`NT,~2HFTKm7nC_9dbLPI v6Iw#9F:e|_ ו\Rerb,bC\h .0)B1\eyʏK:ۓxAŅz?׷_Z3{r5]>K^DN E]GNoqxBIKCB*a:M79;ZuzlcD0Gjk@U}uf~U<|%ظS'J͑/Fz>S,?LXCCy&YǶs;Vy3 fָqzmN[<ÀDxРKL{7vɤR/{c_\BmF*)x" Du\iQY%gg6h4^=7$'ڬuOdʳDH\4ye4r)ˤsu55M2Y ts:`ctO󣦫hxT:oig$e`gV G22WVTS< ϬΰFB5swڵFژ9I71ܿ߹SLtdj2w4XLvm˥ pS6T|nxf)T/Y.ӂ܂5!+_I=qrP8~,&k͞?Xr ,i6_ 7V#G0F<וg lTf-΢n:Vw jT:#klt74Z6\Tf)TղJO"֯)hDޒD KOg zqr7cS@lNm}oSV mytMO跍}: b57C<شVPf 0;M 2+iK},11ܩ&@$m"g M\ȿ"`8QfRZhJZ5I*" 8\t ڹa%a)7`l\7sMmb\6UB?Quljj%jjBu޻S#G^WuV/ȂvP0o l)j&$LT6텦#4@\HR7#(I42ũP]dcGҵJkArעhm`[ <9jFX :'oYV+{C~(Vt[[8| ` ~"n(Fg){e25EO'jUtAX(| Y2d5RΠS Z8‘VE4fNFĬWpMh!,a>>VE_GQcgr3&A̎E5Lp=&@,ye0O2T0vȀ)#&bMI_4eyJ]/~E[㙽AHdx/D3aGqLxHJJjԩ354:hw#4m@İ~1 mF?JWEh%rt@+`q8Ff@KۭvH88rɠ| u냢9?lÑT0Mo$3cMX@:{̎dńc:s(7sz;丛ՉEq3/g6\~\z0[ѡnaLٰOiHy6<̦I/>0Q}ԱO_˸\pSn fUiwN8 |`6]Shehhe{*gʒX?(JkPJ9N1VgB皥̶|pg-C9pz:UgCQij Ϩx:~dυWM)rաQ9=ѿ3eefiϣ qߕ;sG4^jԩ&]e{q88^>,58uͶ u| 60huiʈs FPc5]7RUSGbb7NXUzɛӜW-Er uy_nOOmҌ"Lܻjۙ7;E?RXma,Q3اgV|$:Ra0(0fe߉3h09Q?)xް'/jSy+$͉6aPRC5=yҪjs%Y'`Ee3z `hUS۩%(R3/"8~Y1Xx\5RRɑ ];_ns.yÂJ_e刬+sVۤ}gG >)?2à| Ex0LB %ӏlYShJUR/3f OemZ$- tb[^̔)i &~YazmH G#BphI t;3y9RjCf>y19[DK+7[&e u=C6$veY3>tQI˄@k%Sl},(+Q g}kZ p` nS4>{k|~/a)آ94Θ3i߇&t˷ʧ]ܷU4uB US݌]I鈴ÔFou)p9)oTYu~a6@єeCaz^ ZOߋuOGr V' Q?*ZWqx4 b#Z^{ghZiz?{~S#Ty5ͼq\Zt44+vH@WAI=NtfHƻ1[[&Ix6yCw;; {~Hn7INrmx\ck$x~v߃h#Ǚ~qmN]>7e}xj*zGGv9hH>Eιts6{5R s=[hPPAei9I_4/=vwod'.Ox!z\2/uxGa9+nay'\ f LW~|y N9Uxы`ԡW]_>6ٔq]#ҋ*d/Eglzy0UCҶ_Ht~}iͧ1+kmT*ŠWt4L Cja)S( ?8gLOva!R5ޱ,@u?t)WVaRT Qn֡cxo٣fi/*KpU0,1|3Uɵ^K}z4Nq;]'~]^D{}(ֆ,U]YȊy/nͳeSfENў~al:}e-fГ]Zѫia+OorRh8#aO S E=5_W?ÖlUt F^I:sDW?Im\1OP$;n{ձf ݨ*}fJgCp$YEvՋ׿`Ka®ƍ) ,*OlLaqU*krPu.ύ{^LqHGQUŖ*٪聯1:$LEWxa~vWjXIxyH@R3~wۏ=Xx~L4f"W"װ#{uh$l-{L1TVFKAf,9?FS# C\;̠*W$9ޭ'X>d|6m>oƷ~(JոJgς("䏰1CUpO\_̗U $:#2j9gQc>vTfT#lEqV-9UZIUoDM4hl.l g>x9mi™FD)#HdL2.#c"sAw+i9I*ŰYT 3ߘGgƟNnV +F.*,wf=@Ӗ;R"zMǡbYHEֻ6zx$iBK' 6wls˄=RJ$5ɮW͙%wS+ꯓؒڄ=@=z oG/|uQI-~WPj,Ӵ$5. r3// [y l0| ˥g3:頣i8$iBQ.z[mwcGʪL]VŖ }SPΘ6XXO0P˒ K<["$MwбCeX6m5ԁ8GaSfw*i RMƜy:(7ß!zA'vR_9P2D,yq͕YOj}:(zyLC3&:^/c]4,&!i))t3tJǙ7t{L!򏱁+2?O)UwΩkàq:9ǣ9#Hw᥮鞑/tf~3;;^rMOnl7dHӳ>p7{+)ԯ}ʼ;/엜Μ-W=1z% h'{ut hLo[p/gm;^PXN ? 9VTMcS3\՘tőQ5N:pv@q֍M[%ޣ==KA?I;z@欛VqQ?GVc_R_@xIE~.ޫ.{m|x?"\ȑ'`0݆ I'^Ϗnv܇x/L$ƍMY_&Cf 2Exɩ7JI6 f?Q?>R^+v:aeز7ϕ+tG@ 3tKfDYuSL \a#dc$~6q%6jg؏+rH!lovc5ʝ VO!jׅ+yo[_#j9u# l@a6 l@ 6a Юm#Bvy'/3RB P*[6HlcWYS+І(/.Xta  bF 7`@ l@Ma4NMo~>X&@r 1N4hNy6 zDq((ҥ 旦 g#wG6Q,psayk jA<7OՅl e#<]C΄NQ=*֔#Ta>7u-|{{w4LlK=\Gls侜ao xt|){p:h hl;s ׎ΝvV ׽3ޢ$ mG_eXF|G]+?S^z0CL vLR_:}x5א2!dv&X3-OqO19 FCF۵HO|5} K]7V+('iF^#)1--+1;KհK:yߺYs ڦZmx[cO_-?3KN;Bkؕ> qVQ|Y3,d\o +Źf1?H8i;7S)Ccynlzc%L,g]^:c ѸK8 †}7f 2*_dߡށVx.2ǖםw\k᝵LؾO{ U@ 28 z9':uza}~Jn X eWn~ؿ!3۬xhijXiݟar˩*<,PZ\fVTy񼞲U*K`)Rs #5|n2f8{-+(Օ6眦ŞP%`p7x:5qOܷMo* @N91d03>_Ɩ7Q,qqs7̐^u93|U1+ucϻ? z%ajآ>+a&Ru4Qinr}]Ek[-K,Ɣg=xK`cղO-6Q[8l, OWHhG"{T|[ cNڊV~-?wLCd[3ڻkCp@\eVȠ$Au 3:uD:OVynXR P"z?rc?a@KP׍>`;Rע>" Co1Nn|}HYEӃBdc/êILI^=cp5qX@Sv\}4e]b_CAP=uA\e^t ~|5VrQvu'gKؐit@g 9"# nZբj(q*Z&GF4weo3T[z* (jX&; VXٲ>bun~׎H"p _^ TRqR]V^zsRY+˭4;NM0dV #t2l-% SF0I.YGkn'/@#W`sIj a=@Ӯ'^CEe:8ͻa;mhuĂuDhUjiX-#bKMiRV:XϜÐ'2p9#SnAN͜mơ!.|p&%3v XH)}P5%eY7Ol+("SN|Y_nQx_7Oݪh]y, qPG`Xr/u K-2ȿ*Jp@c_b$rkdz5/kb/i=N:O?nX.v_ݟ&$<(1>͎%sϺV>g??7 9vH}ߪJڳv',0'[Z܃] #WkO Kh*ѫXᩧS T]WDq_Q"g3@QE|/p@L O|D<=ZG"fPbf^ ,R_۟d2h 'gzY?i1hmI8+/4QQ6x$_}!&F":-—ٲ!kXBwm/mXF{qΙW+{G4zwB*co6&l$O*rG ɥJi/V  0[W݁ۖ5zIvh;.ln<~V4{ H2~n~J@k >+||2:\ 9G L%y "q$:|}] d-K4~a[>Gu:9Ύ#Y6T3H|xtB`Ej@e%Ny<L[GSSめ$kp)5IlX28!=ۮ){NC6E$p"r/TBwZa;tǵѶTtMk9H\90_dc7FBlysH 2Ϯ,}8E{<$% sU:s6HżH+~+#4GA+A^B&/RGz/(B7\fv4S4 ɛ+G:;x$N,^%$B1w^dK#I뢔{@\'\]O2)s4ѫ⠮*,6wT̯y0 9 BtFAӐ+M>AH fAA1 `\sm i|lo,uӺ.8!pHeb8zTeOwH;] Y>I"W 3d> / *+Jp/ Vⓗ*=c42F*wzN&W$j-^ϟ p2 {ɷRAT bAvvnLFGLa#~wRǃR Q3~0_Jb+`nSϔ ,aYu~`Cg5+ҥ{*qֺ>O }w)}ITTTfp b온AۚoOBrZh]'~x.%&g-5T yݏ˾B*.YOuKոgKV5uUvv5y_ɬKʈ~.j1+OgjK3oQUW[\%o|*S= q7-Sgm.Z͛^Yoo>C|kL$QZ Jmg*׮Q]՜]o VAԦA7ibv q:|% y).. 䱉zW'W8\5 wN .\0u+ksuX4Ue_c}1%ؒAE_]Л4+z+7+'9X'xN #ӨlR!ntjq|(>:MV綷W#No/7FWغ`P/'͎g\]̙S_u%Kyrpu2_־8ֳmWuxբdFÛ"o[q66hhcXD%TM^OgyWuWl(޽rɨD^Z˪mx[ '3Kg lOgv9F}y*ycPu|g/DA>y}(P޼<ڊ獴c(yȹDc%d_0Uw8elV5p(A>7'2}Wn^S]hSYaU!?V"C7ԋAg A3+q[%D>2E fk0p:@k,_D<yt iBl8ȟ:<c:T2Ϥ %:^IK1'}K۰vT{x"Jdw''񟖓޿:C?I sB"(=8ϱ= V|pCOe~괝sR+bk 3_jPψ VH#߳CM,N- .[- <2k(:ߔw?46ꪈi҅Hq/>taw}Y##* 6HYrY|ti"'+%ݶb%l-鿬S*G٪FT+,?AsyiKoBh-Ó&r w+uloZcڞӹ &M oP4yp2v-I綣C1^Gwͧ]e%JݣFPҦ v-v(cotֶ k] +G2h0FdD@vd~ [V+:Ň.W;өrypǛrmSOP3#%ceJLf`0[(g -ikȀډY8ռkq -]dUNa,h|U=&hV%O:2濜$:#B$ЯQMy)R`05tm/a2 6^5VH(N'dII)Yf]vEL-MPܦ]|)=Z`x4\wo0П TDS :?)x|q'{ȡو]MNqLD}7s?'I(^ m+cϩZ1kc /Dc?5+O کbIP>gɵzuQu3?W>foEqB|dT *ɁcB\F7_=Yٕ R3qm"ѿתgq' ؎7I]t(ΠKDih2ϔ0$p#Pzp.WSGgVUR ,y=#[LS|/C8aFU JYHdȚ2]p'o9Rv^!WieAG4]Gt֫tj!cAvwltK9dzѱ]Wv-St4өV ۳'Z= ~)V_e6Ə,!%it#Uk:S:FlDy\k'N>+M4CGJl :z4IvK0ZT\T ٔAvrhTD?+>DgXL '$I;k*! JʲQ<T-+) Fna iYO4J!A)(ƧFIc:ss8mΉ]MH?.r_>3۴ȿpxYm<& &ͦNQ[-36M2(ӧa)-?lU|up"!G+#Z̩O1CVWpO=WSذ_^ $^پctNՓ^g&IZ|ބs){c*nO[mAԠӨzpˆP!HC$&B"ꖈu B%`ubEƋ; ~*}i+"0qH+! lz2ԩd,.MB.Z{2‚5'طفxW\ \ut5@̆הk?H"g)@ @$_6}4o#u7S#;5m ad DYؔ1f)h}[ovP_a |7d!87mZϰtCOW'8!.MpRQ@n X8oίÏX^*'~IT3~ئp][s/AAEeG\`@4KiK1@Ht_.DO<#o,R?x`o%u!J KtD;+NmlS#+n^zoց '_ tWktu~%ء" T\013&Fti7S3|1I†2U ?tʼn[HOJ+ ؑؐEX2nXgw;n:Ni"udaMF;VA7܌`:b6eņoXh2 빉7:餀)Oexa6Ҍ2+Onz l_{yA>UHIt1j VH"YGȚjdVFQU oah2OGw96\[%\oJ ~MzMFscG^+Ctʐz&GYB۸1; H5 l8BŹ`@xQR/ x@xQ* l6:zz9y%ٲ"U3j%R*j3~+**  D SFAUR ,_m%:x<@OP_i֢GFQB`q;ƽA纃"; 2r6SDFւXٮXfh ryUykmtϭaAoISw]PS E:A |q _6ewSO;Tau7eye`@І!$ tH*Ш<I O+0`,)` l2. 8C` %Ҋ`AQYZ Fa (6 (2eU4(%Fa@!`oqبNb&JHZҟYO(-;+l:*9}=Jby5͇N1_hT \ eU $-a @PS֓E 'c1 3ۋzkӡx3̨[>|k׮3gTcj1AeeeV@h-;lA>9%nH16b[;vA uuuǏ 233䢢\\\\@+3cƌ0www0ȣ¦EҚ`PPP `6 pԩ'OB t---dJJJ$%KKKNo`())Z*)) ,&[l177a#gffZϟ?o (5T6.ѩ/(( DQ466vر`(՜ݜ8< lZ:Ba!L¦^O~~>h2߾}322QUe~ ##C[[+*A'Om@ش4;w&ֹMVVM}̛7/00?<7nWdJJBIjj* hM.]daa7qDۉ;(w# IIIxM;w.66?eee;422:|Aؤ EaS~Z {h233Yjx< ۷ŋ` ۷o` ''M}8)++;/_4iR]}Ehh7`|LL v.y;o}L4iĉp966499 &o߾lr׮]{իX*X"##WV|ܖ,Y`sĉC?z% Sf6<ƅ.]a0 D,*cΣg7,25(0y!,yo;߿9 ppƅ3HW5D v/QRgٳĴZ A 36k! G0, (s-JGQW#lF%eoa2 bbR9(hwb۹N^8<<e.:b債4MADvymg(B$=ա{w6)lDze6S[}$- ZRQ+]g2p[fV|e=֬TYZOnZJep;_io3*e]i,0i{,D619~ca"\ZuU7 @4սQNNH{F±n_.K2s{Drjھo%K~jJȷIk\74T,u:b>OH~t* GlҦN'gv,KzBa@ϼ/AMٯ-ձv x@(QuA4ׇ+vh}vӆ,OWvNf|HHO|x+ځ9j[u^ٻxQt;v t:ЧioT0㌊r~,)$>ih3oñn2Y/d24&!֨2>sϾ ;ek{IaDIi0_gfMϵsĒ^6;l Ib~Alyo@ i}VP".~%øgZhYgA=ۺa{@qnƗg7oS3_-wAQt~T"FbG],RF#WuS l u1T)/.JI~& &`gLs|V5;cۨfFw7.M_p&!!:GFXGh,_B;4 [_A '^GS*6 VCq;4_ k4O$-VQRmABjy|6ߞR; `Kt!,gٚ\N`0"?>sXJ)Mx#%Q xLCQT|Y12J rܻe:;\|m=$ ky/j<Ł`!GͰcqn Bn>oD3ТH+2&cOtzQ(Tb[?9xjzΘ;wի,uŦZ`pP^]ǻa[Ec'oSd Q7 6kk2JjC|6`?퉧o\^/(֘ ~@-z}yvy6;/I;( ziZMsD59gQ!lJ_;9 Z~CN]ؾZm{W8W;h|’x$hJz~לG{7%A (%?UyDƫ$$n+6\z1}x"I<EL~_ߚ4v ‰ioi>e?-a9 [o3s j?elj1| KNL ;z2ءv)[%mÂopWn|c]B/0grO@3Ү]wWXNq:zc+G{z}l WS xm \ y3tʟlO{u7C8 {-qUqG\8= ֝ڥ$xVԢKAN37Ix|m yQH_=ʞ$d[jq+rm)OxzW幡Hu5{ a"p$RVa4}+cD:}ȼ≸>]y O˪hBLR7 @()[mCdQ)9mȆ쬨m ȁG?+J_bMei4y]ZN$ cB`*ŏf7ӎ܍a0Xfm̖A' q'tخ۬h!GL)0G(IgVոiK+O}:`?bdQ5KĖXF^0Xt ?xGݱ.p\De3ez'!濵JsWޢ${)L mLHd,$mCxtr/Nk'";*rOzy㻎n݋y3zt]Z(3'IY0Q: E|}3\2]ҶaWlk8JW&=$b/2hr 9/_-GId_dΘ>Ko6qYL» ;Z[w_Z:GKm֡3&8}Q<5]~I%+/ky2g> Oow䳖2<2[qg.M1N)K AnGXw&\;vJ ֱ=1g`l"DIaRG Oy/#䕗^L{(|2\mCnfmC`FY$/5+2BMmc^3|2` sEFAN^*hak  M|7r:ZiU*-bXcńrϽ nR l t B(ye0j3GVN*ޱ{l#/DoC^|G ZLwÍɓD,-V34 ޸}ns76VXXZɛhrcY2帪[ׂv4@" w(Nj@jbFR, 䬍;k5fQv/c2v 5-ow_ݿ?]Ɯ++QOy)IA_YW(MuiiHe7uIYq4@hǻ'`YCKkR{nϛ3:j}vKm÷ݼ󭂤I F9Ǒi_Od=B!V~~!l,u;-~;p&v#!c%1PfJsu߱%jc QF^qRQ6kXX˗KƝ ҒVOƭ?sck..utߪcJ`;e~KcjjSYBL39DҠq_ۅU)|!jzEVϻ`2|ac'tN2ލ Qׇ ].Eg'YW?cK[cSc=ëmnU",hT U,ܷ緸"9ށv#+ o}A~rүFGta'Tw{ւÑ'#)gqt:]$"Sؐ`yTc0O]Ί2}ZcOkױj`v!Љ 8TA<2siwU)d"gCG $4BuUj;SK#% }=A`D̏7rƺb )um/K-ehu%2xD02i⵳kO_Q -†7=f~`lN]eGbsVh8#˒9&;%A̓ruaʝi70Dt sқaf1~"-:::5㞦=x>Aszb'FBȧȊw W:N?.a~284 lz;z:ld`V(!FZ-–;nUgt:gd(A$ivsXiGZd c?p6.YqS~FLir*>&^vqꚹ?8l#5 䦮<>$6 % Srڢyо f9KA Nl0kĔ7AVM(燼.ءu+M 06nvbk}su}OU5^vp>_HYUI#r2sDi{-TuZU"PPY{~Acw\4Mq~,LD8&Z< UYՓxs@54PN)( H;?w\m)7v(皌ZEI!4d~I+Fg[˝€am542 )Zo9cCMY N:BsAtN;0EӰ^nؕ!` RR78Z =/p a#py(N3Lh2+@([7@w.M.m]YՎ^vٺ1\8h}N<`#wpQeeY3q{aGh9 ),I }5A oMew,ș=Sg oȧL%!퓟H/k1`NPY8swj {VHauS׃#nL^0ܫs~r{1+!Щ O d־Ecq lZJI^P5@GB,HT0؉)׉,FHhK*i 9i%Y9|٥/|]4SXpOkGᇑc&ғ`hKQ` Xf45p oyT(t;h rfGqxbt7f_G7w|Yvd@v+%{Cͅʑ:ܟAmnMl{̎e{I`AF `~j qVuT$wg6ǦkLKөkSp8ZJC>]Z㯩R8зzBgb3W.Ljn/aϤ1$D?LE۰|V%e h4or}!JV+lLt F'= w.9&t!A6b9v!G X-qK_`ob5Z cihLgNS%(SeuKg _Quٷp/YfF teq<#e0y̟%ՋrRyx0BalٸBfO=V/mgSו9My|2KTzE\% Ro@ڒhfC6ݏ&ኘ{P6K~bL]¬eԺ#Qgǁ<|2m]0dt~vH*h8v#&.Цg0NZYޥni ƹC8/dZ@L"(t>|ϟt6be3ؿőPV ͚: O\V0*)#B2sdE-[B);tفR8[+l NMZ#?BΏ;)]Ծ1A]t[ITgu>+uYHW'pPT'=D9>6deTjCc%u|PϠ'p&pOڗ#ή53JGLVgժ&Z1|68cď. Պ''v5Z$΅^%P#Td%7Rtνϐ ȯ)z~;ܔ_ֺ*??PcgVc@vNlF~}q[dk4؂oO<'IvWz^,M щrK-F Qiq(H'>Q,Lsl-Tٵyݫ woY,F$Av[#=b+ (-S,̻K>"E0#A ݹ<`ݟE;zӯ2D9=ua 9+@UWutH}w 6}}~xH&lD)o .7Llp4 ͒DSQYJ Q)8 hů3RWU+\,R|m n MiIh5W1,%% >e.؊4R;/uf JڴB9K>]?wG&Wc\߲XePP++vC[~)QƟomaAj {Mz$+ \yn4J{8)olr6aSKctA| ]V_XSE]Gc ,B# CB2 %rfjZ4" t092 yZUW/:~WNhYE*G9a$ d}o!Ytͽ_`@Z6ʗ0\B8__H6W2.<0",}xgG|_+z/ A_hq'#r\2 nv/n߽|Ib9_d%YV_a-Q4Jv~zs^ŢvtK% ]^-=_su2 73o.G Y/ $g@?u&R6`%eco-$Nyc) b?ByV/^'r+RaIIwڟӭvj!-K͊ $E- G usǒO]1[WZƎ2b:Fz75';,t4.=* &.+wO;mt&ڷN ]Eո'z,:ŢPADJtb:y)d4%٠c% ^ոYاzJ ٻN&R2|'1P5~YnktA0YmCJf]q1}+owB-NT еt-RۇDlfoxQ{ q#O=՞$d3ݎ.Vr>6e%^-;3/H'υQbPb*d]'z D 2BʦC-9)Q| K2=O<{t@ire +~Wi%x򾥊z UXIԜrSK {~q0 ^ ˫LDPBnn;C7G\[cY<<Wd*S 73w7W4 1g:ҙ5)4+O% o4Z{K5@rM$GFߚTV8֙1DgPTM㈑%d%&mh ؤ3M(ͱ1כbU4Hfr0vWͬh%PËb3}76:g)WCh0iw!-{o{#& If~?xE!{ ٶjeUC8ijg/q`t~9"Z䚺 *,:oMC3P-Ӕ@AǸ4?KBAMc4AfqB.w 7]RɄŐpD+ߓ/ĮL*Ub&k@X&whDf"d2K#|'O,6p6 NU5e`:eLLz k (:랰0x(uYh>.3a{lV>vztyo+ ~]E-C}U383RFGMl4\YԔZ{XNPoXeƩ -s|M_>?1V?NjoMdLHKnJ-[()c~^Ϥc]n*Ln?{L?D?Le˂@#\Iyew҄BIM^qILw֌D A,HX[+thLMguK(KDҬ*A"gMh4lcm Z ^+fP7Qʊ&K+,,dac# !E\\}b=~ivGPd 1".QZ\ r6jP ĿCͷU:OyAE 2ޯJ,:o+HW񷊦Mb y,3Lz!k^`~Ǩ#._xM9]i}|}^_[0⮍n#zQg÷d$BU{Ȭ_gD‰[  +E(9/I*C?yyQ}u^fit*4/Iq?F¡^>w7Լc<)+{*wոڅH /|ַ8륱 U ':4@ w2*Hg$gٳ#h̠B2*Ӣ*ڂTЌhw E8M:fݚ.m od+rJ5ڵ+_$yW3_RXVu7^ꟆnZ0'f }~*3Hs)ELĥ+a:+|¦|uw\\4Dmc:kX-I\(O*a8u/@Z VQl^lE~{ C: 3Y|Ǻݸ_ޓr| ɠ@eRP4 C%>-47"XSWԸYLjk iv?A뷪@Wl}C O۾jWa*<>Wo5isρz񱚭/K;WL1`ݡFo A!YOmM(V3"⟯fC 3uwwl㓡.f+%.C1 !ix!xICDD6CbQ$}g *O^3YC{eeK*xU#G=z Ff ^ro  @T𳀅{6dqNZ߄@?^S($#V214Ƅ/ \f˺ݨz4fq^z׿ϲ^E6aԜ9GhR0*d d2#!}.|O &ӍH 4x8@͸aN/YFءi(z$aŒjXXV¢έ %?Țl`^`h9*%?2]17qI}~xs{Ҫ:4^ A3z}>N6w2)ZFm7@@EQ>YNءn]_P jNАVh͋bqn:"WsӊrRff$Vi%u- :[[, #bT elMDThqK@teNú];Orӡ萘\f$l۾Sex Scz*\ㅞ_?2F-dq lJ7܏~5csS4wOAgX(EYߊrJ~dPBR֔TTV֒R6!a aH11Mh\e* < j^]:Nr3Otưg \ׁO3^5}K^ sz@ $J7(;hy<ݒ# (-,4"=F Xhaؐ|.ɲJQӟ۵̻R]QO.udp &&r&z$YMS8פֿ—e8/)7@LPouwIqFT#R#u(Z, AӮxke_oD0ah]xsqv[ۜC5,,zv~/| ^Y4b+% Gr<3ѳN}lUCZC!?dպPZ SY\o,#x}Jsw0cieg !ai&Dj X/('+Sq~eܠ{ouH1D\|Z:D)a:5ۧ=5%'Z\^ Ë2FCEa^9{} s7Ev'Nq=?w6V̪NܙG5#@t;7A]jѹa}d^RitaT9  "&Uχk0'f:-WT"%l'>= 9Op,(fYqՕe$ʆwjD82*ŽoXb'AGk'@pyS7!Fy9yȪ@f3fV MP?G>q5G0DLu[FO(.wFwu !ʬ{C̍NC`X> :khDlc PwLwʕɍvB]>\ߪH.iLKl2T4zj9'R&<8}>*B _y~So ;I5 XNUD+JJJb2$Y ^Z7CO68H#ajuieǙg 1L bEσ|iŗt垍(4fuLOn1|}00E]] 1ٳNCE-6ȑ-z25q^5?>#>B_JyI{d׷,4q MKq7d vn£m/7|5[Lۅiy6|?xI{#G͇OM]U6.: P,n6`mP%o,\,W$})IFhFO}!9b1f0lh%˻;!"gD烣eAD؈`[/lFl"sfj碴gNzYw ^6–.*ZMHWA8km$k̏o`8J1sA,ab0Yݺ87}bETY3:MX]ʜ/KfCD*yȵ);>]݃N qj]_^9"XW䛊]wLR2tqҩF=&>2=~|tǤvI@O,RKV>6qkz@RWQ-#DJYs"qu\? ();~E޶/FIvT)?ri uO:^7ʵ'm>qyVZơNEMvU(5(W̘@1A 55io cir NF~~@dQ<ÕoOoZviE(R:I@p?(+=ztfb{ A_FI lcn}}\R"G3N"v: i 63`fڇ6@5KeXD87{.~vl&mu;V)MRBY{8h ApQ1nmX+ª NY|6m SJswpSs=$/bc x}F|i raUg1 `1x~"lM q%}g= RVP+qi/m6TҘRbv,ռs]KR[KUwj?b xnع>B F2vc% ƫБI7uf3Q6h5&\w6q[#+&(.X姀ehF| Sfb(Z%K&mUۊ3hT.c֟!Kw; dH0/O6a>_wHRִ/(q]>e2{a:T Wf=LXlwj> HzŶWSi+vH0i ;z.r ׷ת(1d{ɮٹCn jeuَ ׻4pjȈ =Y(;F;iwh~u5P aA8&RYtC5QhH߭kZS]P<} 2YVqŕTD0ͦY[=(zFxfρ]&=Q3ja%T|gx)xK%kSh_]4gwF9,U ZFɻH̎e B*uKfO{R%k$L u59+&x.5|FW1 5@KATM3| ~ C0Zv=dKxrQr)N=6͒~paDؖ>nvSkyZCdOB Dވ%bM(pLmXh5xK_/\p:A٠gҥ)CWI|Xy^;V0GyM4ς@hF|Zw.(=|T(+9С -IIltqeCs`Cѡ`=S9G3h dWw❼yfLi" lMxaSD =|y* -4Ga:vLD6*/|NNhL)A\ѫ:b*K">#7Cf&'(TqKM[C{f1 : IFŕP*m?xyg! `=ɮ@ЬQ̠5P)C aN&lM z [B^+D$g=,H"j{|=_R'^p-[iX/"Գ ƿW/fC&$dP@)A 2ڝb=7G{ilŘ=\'JLH_п-t l`DW"2Hu/w[u*&X?AP{bNr>v8͞ېfoe~vI/y,FǂOY#㣤gc^ (6aSgCAPn^{vaXL;LmkQm.3\*Lb)bLtqAJixK\f b`O)HaD 9]vc M;`Π%"úFب]&TiA5q \ڏx4~%62J600)zU^T50ް"Ǹ#sJB^i+cg~aa)գx=k9-ڌ\o~uzᠠ]NHAXV]OFMOFU,dc1׷,D,t؞{!S^*YՈmɔ0 Q5Od3&<Ţ3Q Wd]dc^ʠf1( h;r_i؀Ծ`YZj&p9nDcpW:DgR4qLTC%v-;Ɣ2y6YrjG`~.4 L yW5!𖂮dA > 'Xu1F1R {nǂ}"*h>~]5{UV[SnrBȢyԪB l>c 9;b CjɤutIiKT ¦QD|6gg骊)E9e9ȓ'Ar"G&R3Gݯ[*/Ub^jV$ /4@X-R/-U#1H0LnKXy_?џF_]"OA$:p*IEc14*:b] mf:rG[b ?98ѥ6>SFvMƈ B.6\޷Gr[N/ /D/auɶ k/4HQ/bCp6yB2,*Yc!TqZrH iUWWDsE~ <2 :ݕ{lFKe'!WSoX/j adžfޒ .\rݻtڟ j2: Zʆ戶h {aνm 6YK~+-F6RQ~?fez66CѬ?mə˺]=.iǟ|[%ד_ QvrЕ8w^C-O.%$65 :sI68J{{Mprj߿e9.;Ie5Gƞ [WO7 k֚(~g%=3G,&2ׯ{pؑ6E9X=9 {)VR^uL_3x'zci_Ln uh,K%.9gw(MeVyZy;n:y)|ݓ;H0Cη&XvFJYa吙i$$/"X~}bb\f1- AӡZ :4EN5uKTM%4Bp6@j<^y-,'Q&3$DR `qIe٭;%Y,֟"LJ3ww Cz#.0hF[k&9NZWiz ,T8Ǽ+ḡ n{W"Jt{2eׯ4sI5^V5D3V{gi,LA}֟~kږdf ePEӖ`jꞛ奰ȓrvF>R+/S6Epk_<V ynf;RZfF%T3jWS %Th~qGWݬ?ت #o`hh6G qvmfodjR/ 5*Rt8n/~h/OcnYGFMװ}F&I+)p{ M}wvHJy "z !d2 . G܈422=M~g%D /3&J+yM9Q,yhU.O"ּ-?LB^YF6jIO!+Ȋ2e''#cx<0qXovB~ z:Q0tV7]YB:/o4\-bܰCO^~>~1%%j>aDZ!2+!FLXqۜZӟ;yӛ#4oߞ/^$/#QupDшcC^]nsk5˱&gƮ?(ޖc>ZIϬK!%.#N~͠>,mg%TKӯ?G[:[*N3s—ČҒ~BVWr}潹v4|Eq. @LvuGIA=>wd=RK[Y\NY5f EΝ;Yۦge[U,, >Š >)σC hW.3h 2ْl}dMˉ O 1]n Yyp m|zf+.6CF񨖍@~rrϠ75C.(>W@>l_$4,=5Uaӑ#zDxMZː3˻7.x#c>tyna2n3rB-Q :NSȲJ6 GmNѐS\aRr b4huox|bciJ o=/ ʼn^D컱-¢ S6|']0Ԫpb*SɃh\U2p^K0Knm㧓dиϐ}fv\^dn%XԚh2>E>Rh7 0bX,LqV&DZrn=}i$?qgo7_RS;#sm2><\(bC*T#/6Ϭm ǭok(v95f0ϊ@ͱQ2X#ۄAX 9%+*B蘆.v+<,>>uW=ђ~y36J-9+~%gڊl~Ss9;x%JIGlBt$Gh(OPʊ ӠV{n D~~qe~voaY8) D KJ,L5B Й`%pwə,مsja-[C?5ܹ`iE>V_g46!jDfbhE,"zRg%P ?s!tǚ=yIu> smj8سUVo;|?EU'& R@VTm@MohTQwg)hzC.>4P4 A&VG#FwMm84u7}>b׵+@ l hc aL?aY~;D ݿF䩏['KdpH2u!BÃnFmW/:.#v+ CG׉u y!]kAH_6«p_::{؇ ΍C#t.? ~\w.d ?~EB vJ8QVAcަ**%h a4_e2dt2?fN툼}}('j9Ioyx frQ1X,jV\cn\.\x@5|}.~{_}#<#h5'3О3@]US/Һ~hhdɍJ=m-ШUZtcI]//dj<+l϶M14^6X1b:/)#-Mv1\zP+E^lR7`^nSL8Nabĕȱ{^*@:rIzscLQ6%jҪ:sK_yCQV]RIU|y}C:&ǿZ;.>xuܝ/dШ+ɠ^y@(dh8GD*$l8,LJOxg/$%cOp}/6Opޅ^ I^7p*Sю ǧVU~ya11;!Foۙ~Gu[T:}cD)Uz2ef#=pD@)j6REcֿdϩ(v:QKM|Ƈgw'>4S:QCб|ZW(%Z[9xmV{k,a: e܏ƾE/Ye]:ux? sY~jrs^2MNjDHh2Q29? %nl[m]"XL5bN+PvL\vE5u (9o;2!sZ$ ?)ј~Av 1F R4{XI)k _+l8Ъ*^Dc"(l(ҍ`FCX b@p IG\XAG]VM^JQnk7պ%,f2~; xB (&"++hwOp0u;F>> lbӯ+ly3"ںvkƖoBCtBÜȒq*E9*BY :i.1sĊA% 8J5$Sose;Ï8~zۤ?&h!vD01 a$!K^ *p2f:wSө?{sBB x^:[a{En]$=@)2|uSol]jmg<K` d. R`oڗ-,yƻZUGۮhT kI^  i(zٵSP7闛 aiq\%@&ukNJ€zYgf~-j((w@ hg%W fE222tuupnC3 τ={j~-Gccc~%8| 4.r9IoTz k%`=yu :Ym $]P)WG1:}# xl 6bV1G_1-[|SGf"@.'Uț;n\18Eŕ dV42 O`W/YoRκY`wQ.C: ]IY. AB87 P*@w+ apbch H{\\;"vz3CO4 xt|'(n@D KC hPZ[vJ]M F #&sr)'"H+Ha7"w#Qm}v&6+vffs` š8D C)|6>7eSE7gС)Jٲ P-'2B]7 z΂N/BE03GkaE2~ N(6-G$dՌ-Ŝ:nY%ܮ=)BXoY!.dZ&{Ƨwr W N'Z} o>\wzW"S0b;zA8r_:zb] @4mX}Z#¦ ZU!p< ? †XC2 KƒbHhW` a뻇U77]w碱l33EV]O{"L#& Xմî{|L?P"lF]5J#_ [,IȝuU{7ت7WdsAࢫMV./Oif kbǩ/M jU"j~JRuK\ ˻ 8(PXwU(.rpD2>WHhct& ^Ia#d0ބI Jʦ{Ӻ/*}} kqX E#tp-CU=(6a#g PP-rP(tuE|J>,euL?4?&cHu(쀋ltq[ >a#L{{_\EMFM(' $qYnA@o-:cQ? w+; ff,.a#Z:uߌ~s Yd3>Iud0Lg|g? AEuE)QJءp^5x㽋.wVS~1X:(T+䥼rUeE֫͞nd[Ǯ?c<)@*EVvHUYbY͆LPGج ZG<^L>2bi{o MHȫVtQoC)%k(k.,vT7זT~xG%jD~ bm#E1" DJ]>9393'O`j#y:+@[fǽ9g S5Q^$JD =7 ֢sD6.gH+qg}D \C=ݜmO8׫XFͤaX,yu㜧?\JJAζ `F%@StcȤL}ut6X]D IJ ͑^'{8 nmM`{F2#prr'3_M>F|OD 07y$!+jT?.4'\6ѠL VK4@v]q\)VȀGWyj3"m*M~+=7:7_>N tߑQLĕ4?KBQݕeBd2ZFyzz!7eHvP}\x<紆Uݩ JA:!vs~K$-)?>g9Rs>ܬا 6* UgVW*Rɠt%iХniN2ӂ33yvsv c[ oOg;VfU}05 \+@B݅zPžDڭuqþ zH^3ةsR̕Uu?[||:݂  f;ڍ7k޸m7:$IHK+niKcE ! :MX : ḫ|$F[Rrne{QK9[u`>g +ա֞>عHԵNeQhW6NCC~{Qt1 $*"pK>5pb $bDC%B;"Ƕ‡UbAK qJ1c i_b›2uؿ}ĥSUqq`=;3`uxG ch*j :uy@ h{&-)tXy|@06ՄFL&GqLnǯٟ޽{p0 ry\ H,,Ng떆(b6(cWio,fHfx$ ;&;h:kSmDLִQ :ȟ:ƍvΤoM6]%,!Sz3;*,xh`ԯa8m1 HLo<E =A[k{roc]K%N}IQe4+HgA](1z0KIV0lj2)ն Ոbx/l*`L؇%`f>nuS"iN+ @y.068|&N. { v=[e>r-*tj)O= >Rk:9#J'(bZ8 G7*0>lu1? 1~ed Yp^R;-ȕvn{CQK;F>|I7Vރ5GiIXLԽK; >@>'*˵ȹEk9acR_FT>qUٖ/ ose~|>?઴WOeGG֙tvcj  P]z(9.'x z&ɱukնRuZC. <:4=Pka춑& +dSunGH1cا" =W1ev~c{n@(a? R|:\b(Xd] vrILV6d6*9+ҋ"$&uP86wqQf2pLl8%+j g&HRCp b2K,#WX$7oͦFIi"nzpG]&VQj`Ͷ"5xU*54i.q7I' dǤfK<yԶ3[9KN՗q'@,twϯnD|@;vD!+O>L 9E[8eb ^rrktxk+˥lpC` 4ϧQ7\s'`:,1r6$Ai³u5]+T Colks|Oy5k&,Z[vCZ!a:i}\@0,K@rY%ᕖe=OeEM` }3kti6µc?# dJ"ˢY/< 2D՛5Y `v' PLlХ?Ϋa Џ.Z:uN#6=j5PK>5)YkӒMk-06nIxSc ])>v]1)m4iu4@@Ȩ?!׬wTK.B]0,vؚ3-zWޱ7N:@Ma#"MZ 5c*J7`trXcʚ.cJtz006@nD ɣP'|}cY\J9((ZT2JMlW fۈX~Kz*Ae'PA +#{ޤComȈnHT5!O_%S7e+1)RFl =Q3Q#Db6]DĂSD'Rh "9? FȊ A:KQ Fj qCp_$]^3C`TY_cD K\Zԁq|R A&,RAҟdWH'U!Yױd{\PoIn̪hQdzY!窘~hL /%}>y8 -Ʊ ׺e\0F>E8E:Ǐ*a16>}$1 ~ ®فY,V^^^ "z'}E9~/jx+/ ȪJ˱0^:H>Oe-@BK'㶚WfhۺeFwc&.FX<jPz+V '(( K}jMQ:]ڵl$ GOnk~e_tMe? mNlUZ:ʮ Ou=p,&g}cnދ i%,`؊\x[d]juZrXD#¦/.]Mj.lYU? 556/ի A ںxrʆڳ׿nG*ߚ WUڤY믉/jgN6tLʮZQO*#kCgYK@XM0`{:{/nM g̥mNY|c&YOեKL2a*our Gf/D8\GNj>-l}1CƍCZXוeNhg~~i)w A8:g <'C~=fE+EtФd,b6xN4?~ <}R(j?i@m+ɗoᢃ$ \YT,<;!n)sv|no[ɘ 3X~ R;-vU~Fg |zݤFK*#u2%? ْr;&K|}#Ǥ$X67sHHB%YRПRZnܮ5hH^1G9 "8_:Cnŭr]pESR>&u/?E[z i+'W8F06_A ̣:gBs܀WOFyHT֋~\~ ,C[18}tj̮.:يyշ^LJ#$>|mWh &"n9m=R `p2o}R.]5ϺF~5njFzSK.ujcl8 'j9 }Xf: N[=B`lel׮N4wy4BiCH˒YBFx7J$?\uv ,X#쇃ޑlZ9%WԢEyqb>^{wԾ5."DGx0-ZciGڝeb7IegWͳ͛fĬƽ=A5<.bx|b R#SQfEcՉ+VxO06"jMZShi0jk*v)(J-! hםҒnC"Ƀ#Jc\\zkOYrv!#jh|YL/!؅?/Zڒʤ:Q`{=xD^D7{G~tg=U> H&+8\?HU!{JԈ |il#.Vsknr0gԆ}oz:6>9Ko3.H"JSL"I\򰻛 A8;fo-=d{m\L$#ig1Ki+' +ճb@A-9F! F3R |~|;"o#JQw;@~2I#Wۥ9Vp# FQϱ$Ę3qaKr8զ53'mNñ(%z djP;nmHxB%c^kƆrP+ǽ|x.wKfE#[wwh dԒ#cJg빻1Ć[{y%Gmr0ڞdq߷I;;"u}ʸ2,}q#;;z pdF11G1['!^E ԍ,J|9#[<'75%9AFK3IOruGAvnsAhꅏ~ %C-}Y J4y :F0\qG Z1zTڑl.bV54U ߉90KԮuY=1ř W4k50:~|M*gQ] [@_ʺ%wwJ}?>۸[R% ;d'S]5A$C1&Zyz%lҳ[uydU &8wu+ g;U !ْbCqQcfaط8L1 |$?!8@Ks?nG\chx3^I|eܛjmtEEA>|m›BTMn>v.;wH<|y DPQ"6 OA06rW`E֋9ѵuڮ]O?['98/:zr(sk9A}C?\ͳӫ706BpZ(Rab=HZsP㛎)AТ*BKӗ>bp‹(aVB{TӺy=> kEcȘe;w 4|yGxp`7הMnXTTlo6W=.} )5ݰDaULՁ+``j|>gPѷ^Qܭy@#_뛀rب"W2c?K&>-`_6Ъц5}T5ch,:T;^j>PI<tPi|[')cctlz>L8?(Vn[ߪnz`lTO14}cw=no+ILma3%y$ڕh4ӇqpCCP31rH$ѿIQXe=&/+cx ڹbp3||aK&:tGbxByU'tbP@"fҵ"N_SRX9W`Ogɺc< 5ȹqQ:,DsŘw.QaqGbQ>+ЫŖs_\utr W =Wٱ4MĈCqXS^7cm=AiʫZc`p}^]KQ>/`̈.5n[/^unV7-JIOh_Zq|y::7*N*6i60~oh"wR8S*)>)_n}$h3nuN 'Jc4} 94r xl_)]㇌t,NS0jl#-rK;m|v3ϵruAgx'aZv.3Š^v=5Uq[% (M:b#?xC}dVC\81Tn5U9gmn'Uxl2uBнˇ<_F9p}i'kɊhgo[mj:j3\ [18o t~#;OƽF~'I{ tO*+o[Cu [ j5$iktT+lǻĪߒ£ΤLw]"q5=McECFn6QZ`0AYAFٹuʻO,߂^}8LI0%']Fyïu :W[=Ey?16l 55GZbM:gw"ZРIok]s&pĠm`Po {_*k)L{ib G p9,̂9ERth`lulJfd~xm`ޔDXjǤ{Aן@ekaΥ+]0Vm{8Qznecq~O+вaZF3z+ۆfo^a[GfbqS6lE ( \z:ԔfwlP|O~gb8.[| 5tq<0/!ǕYYK>ԝϿ}#el\8S}[ EPNM?JV:]TT|2r[׾,&PM&44&^+hL93V4NIvRC*%3rr V۟~gqg^0 -'mc5Z^~utH+h?O*ƨ]#;'boۖJm*tMKRc$ ?^7AIEN,PL~`HR$^>bTuFnaCì0 4u#7)5W2(ӛVB ZC}fg]ԭgI0_/ _")=fjE㕊Ds{gK(@^j=W9. i`llG?Ad6vZ ǃU'd.0f_9Q'VsKMWd"lHHw|G cnfj-T׶9,šBdax-Q2[?N-(P 06jFDPעx-}q߰gA r}, ɴc4_IQ:PN~n ~$nL=kyT3XH Af; clQPؼ}>>t Ȇ8vz)17ͳrs.L#Wd+meb[ӗMRTg2/6o:ȵnG$P["r X:yX,G7u@afAnƠԖx-܍Rc#@u7gB&k:|9YQCKF t #.r٬]A d#/V$Mv=A"0 79 NhȖŸԓ!?dE)knovoXJq&tO S@y1l:`l@=)\&tA˘.06CwС|ɌL Կ(C(VaBNg: Ν;֮8c9Z\p~|12MdPH)j-{p;FFLS{NQ|y`:fj: $4 PsN^t(=]׸h t쵽P7h1H:0={̫9Ro}[_\PEZC3v\Q&^'/t=a޹ 5&7V\?}cOрR\Ḻbu 9p~Ǽzׄ͜Ap!K瓨:JwpӇm oBj?nc3pnS). "ș/`sqI:ĒOZn;-q?O9sMT=D,-=,6O3k%5g,CnogBP}Cq {Jۥ߈[k}7oެ~bP\\p8ǣh)RD"ɩqvvvttc5|Bm7~o Yd=ۇ-RTͧ{ Vꙝx\eCJp'E~< 3`ՔBQvΝ:^DVv,Icqg8t?vaFKwjս;kwmڴE<4,}988ԩ`l첑nK}K! CS=tۇ6l_@JKvاk[Z_*>kڀ .ktm2?/eǚ8#Lq׵OZZ#H-M|HTc?_? ZqT*Fߴ1(#+:=&)ajF"Yx" D&g}c I t13FOp#ոtJHV*)3 'ЀW+۸m0Ly f$xF6Ъ&ppZuߒj\AFӎ}@@HNk̮︹!s&P1EaYګݝ\lo>j Ca7>Hh_Jm=_;}e9acbqT7Ԉ f;w-kn69pO4K]K#6l8n]CfP4ȫCWONMM]x[[FϠђ8_ONLʘy6Gcպk[E =]?+ Kt"bQvujslݶ50K?6fV].vKSbԤvs?-zPY[Oq9,2CSџ w(OK_k0] ,̅U9D DPN9Nt>/ ]!jQ'ca2›j#  qrz._1ި1M*Zd@9e[.p&>ztV?+gV73^5:=AIC ~%2/ɚЂxmx=N bs{X^&nV Gaʬ \3TN}Ǡ Q{~h*J݇Q )ҳYtVy0 ]ONa4aQ NP\ N+ 3faKB[e+;ԇOzW 52G'f;j54qw$<I']7Ey?Kll g \wK,1l`}n-OJT6Q5ڐHZW\ FA:-Q˧ { %B«~nCxhvbVhWX^9]dyvjBmɍak`ݎ;Fm Q`<cqB4z|)6z6wдH Z6OzFv@gvTB]خe_n-_:K8kHIvE[_ Zd $d<6ZYtv.A2j6lNg`w7OX5ij2ÆtF6gEzqB[Q -,Aեt$Z~_ЊXU CWP;mi?ib4`>t[8Bٓ'Ʈtda}eP\>Bxh 1W[n7x Ͻy>9FiμEKW.Pϖ'bkh:ȟqQ0J8,5&g/;޿;w|8\^=ҢRkJ f̘FЊFz)g LF01 oZ r#xo'0QR?7V`{n@f·PAAL^DvJZ bFuv?{~;+= 0ݯXYq*Y/({Ĥi+}3[:3K\Ш%_w7r.=,1<;+sv`#3m7oof'ɐƃ 06 tP~\ja0Kw-`08լ@nn.DWt]]| @aa÷o*׼yVXqA/:Q MyKeﭓ% j#^tw[TYۇ2iג\0QJ'"e<գ7@3N`B/q d \;BOj C+:݇T80x,6`#6{6лq[xaxsLխcV6F0XsK{4 h]r[9'|PۓZ>-ݻw ܵڰ:RiGy pΗ\83)ˣ8*qoWM~Op >ub Qj]ʯ*H~r3&>AJz˷qE|$P]y\A]ְOJ0'm'40ְd?̦^ Raaa:u1jC<T6R'7ͅoBп4#wAkchztw?>`@7#E~7`>b*x[Tq怦M9rur/ꖱ;n/kuDp}Km`L}"jA!X^.¼{A.38H -&FAp_069A٪NP⊩Ƣ!Y[sο肆c By^ wWe0s`fdtF0>"|z#e}|ȡȮ@px˜7?f+A~A2N'CS8NƢ@ 86+|.cFӍ oeC?Iv:`l:Պ*jӉ q]M bBKc):ѪHRl?)Fjy fhL?.O4/):`lyp |Gwy*Cל^],TjAWepd [d7P⊌ [Ӭ> 'Wpt؝@ݼO1\@ye`ͬeٷScH&pY9*PSXܲAOJ$sis?M`gc#O0ڮZB¥+ׂ'u%bE4?F&MPK _ȳ x-e VR 16ONlP tM̑ Wp 2Vt d nOCNY1<).}yd@^U÷@12uT<,fMɚ#χg_z8QHy-}iߞzO _ OpAehX,akIzr@ʆɬ]IO88v;ﬕV}b8jZs VQ fc3m3=٢Ug9eb+- ̗_Uw8cD] 0\åY{j2`4|3?CB 4PijjPmRғp8uQcxP*HTܠKAT@qleOH:䰗j SqtP6|fV'pQ78>IG Ŕ>x͜& NV 1O˽SW]m8)q|vyKK1+]&ihhlقb̮]Ús0B V뼹sz̶ J@,r#_=~9|,:wڟG/BY V]%ja|?ҲːćϠ~Lz6jDkus\~_؋!𮳣onZfEde[{Ʈɓ7o\falm9{P*,}.EwHb`7"vwbwQ;__5z{"syfvv~&vj h$Gψ\gZ_oZRW tIyoґ[}4&-..}tZNKB6>tVw3Bpɓׯ__M !][Mxuax*#=N?W^aI+VkUu#s$n%\ n̄(cmmD3 4*Oēk-T "" aÆ8wJ3Af/2VM >K>ʚw>;Zwv6*|zpƍ<w 1JB*qApp999162ºuLRavPkt²!ₗe/f.nBXt?/5!|po{ HXm{Nm]XBssÇ_ Y9&dD;T!1kT0 oZŔmLCkPdA#N4Xq7jtId4쎲a9ã4%><36l4iR _l4Oi~FZأz p9'%~y[>zV]٤o +/%C&{6Ԝr%<(*OW7ء:7v)^JVR(5Ư釞M)ZⰦ_7mo޼߿av2ku6Ooj>p:Rel k k&I/tקܨ\nDr ءt Ku29=9&33W5 la^7uH3[gA-ڳX$w=`UwhiZjh,M3]f[|\52|ҫ0t .36IꥸG0Qk$: p9D2[E -Դ΄U_}ytVdg, Tg ģBeم$rvʭ:,mV7?'(oNZblu6L`*?0 %@U%(fd:vSNV>6gbdJt<f;NMӭwwaF%←U<22'h v\%u| >uIj w63 Z%.o%BgyoP%WNJjpO낇nflCg[鋄:UMcw/1a`aO8y53npowS UFqᑗm`wNcۍ]7}vj6n3u0H>=#[à ?0G\&|cӽ~^l$0QknwlIީjYi m}hGttquOҽe+_$>MO40SabL.Ӵ迿zm>@TfEq75}J2{: QwlwH^US' $X-N6{ +<1ݨLM;ݼ7X|H(○vHb~Ӂ4{tn~U]K\>ޮ+Q7Zu2@E=O`ﲿ()tMQ;ᎂ+ .zֵsR7~djtl׍fvQeLġk^m;>[*sQ*eƖ ")m uX9øaE'K Zh[q/ w۹ywb`{oי4ߴ |syA^[pP+D(:_Dz^7K^&CZ2I ? ÈB9ܜXg᮱~h5AAAX$ihϽLA P }+*.L,m=.=}- r%Ԡ(jڮI<¹Sي Vth~w E|S teJ!\HF>̚O&1GQ-ROg OrqE$(:.{$&g")\]+ eX{&ضmqZ` avcx*6"%}+֐@[:v|~y7-sձ|rMݎ\;Ꮊ_93Af"N>ȓ:yiDq|Ce[F2X(L@"ٳj G&{*Fzr('N l;)FvpcפG ii!>apwjl@E  ^|K^wbW5? @0w1zrlCT#Eɱu g &Qh/k1d6*ـHFݻqLqjZ`볪 s+"#Vewh}#=5|B7g3p@?4@ ӟ<ƽ&PLeOKZL-)PQnN}.LpC̫RZ֣-}MSq@(duß>}w3NB8,\Uu| `F2P@^K jR:N=`P@%5t:,GXpG<7CD#1g櫶qrtK&N@(ճԽ N,%TꑊdA#X+ 6Ba`3U +/&j'?7dלC&nNDOH$_m7֨!c  lـi.tJ萻M +C V q1]d֍z:g AB?4@ :uksf]|a3&&A,r~IT޾??;1P| gsh-.6CK2Pd-ܣ- HeIX,Wޏj3('wb2T ~hne딓J+k'P( le;*rVIl޷|} )iNMk4 GH67u7q20yVIN_CE'gq AmYC?MAC; 7A}Vt0~YӺPcsF^6@1ԧO7%Xo8ldP!\\Ps(yIȏ3!_"߬_Y%`1.Qff=+ݠ3>fn=9Hr*==' A!؁<ѩ?X9)H3S"Q#wbD8Tēz zרeEQI,_aZ i`ApCrz5mŗH" *$;jIKLLpAAvsȵ]L0 ๩SÚƎa <.PPECqulsl(,O{׊g`*ӊD~jкPLjڷJ+@G!)2^NJ|X4jO #T9(2D^7 M`* ;ugUeߘ:5P'tj 5IU6kN '2= PP/x -8ԯ@1 {bb"zz=#o(\=,b2L2[}:NpGax.T=mSRa`F~c!YɋME2C,$hn4Cat*Hi9jpN_ e!ȍ{!YO!-Ԛ3qV`O=)≱n3۵K0{94Y%3@Ϭ/'%#-[_qRм:Z^{Ԏ`sՀH@͎HV5Lc݉m֨&^kB#3@٧t(Z:X.lH"|5wWfu/[ؐ6R?H_kMgn^;hGh"Z_)[N5;Avg]x+O! 3٥x8ϥi4gƺy lEBח;5L5qc3FUij:V ڀJn35CWa fa,`&փg^LeyJM3AanN+skߗ[$x  =rL?1p|'K6B1Ç;M̠)O%jñZ=&c"^{(g-cyz<>6=a l5qy7%ϷWMxK$S&,o1d6,}}tx}m$MfKJO"ϼ]$U W$MA|\(Wwl:R d0דyqQ'6G*0Cc].:\ErK.nj6@cp7C$%HXҶS]WjAmXs%UL^"J550 *f}Z!߾3oDqƕPcA@MŽdYʖn>n|.d$U^6-O~r(d 2;U|Ӂj"=e-9).;tih2iTFWXmy S0,5KzhIchC:aN"??Vp N?fTVc]oLgr2"H>=z痙7[R 5yô:R#=C܋7ir9(7D `b%HC?> ޞ=sǑ0 lt-I^0pߴJ½goNQBEL``bL wo!e.6;h-&'4+BXğ(A~ 1 ۄj(js&y<Imeu/οWo0vy%l&-+V3^cX g6|H @7R*(6@CehI79B(@2C>r9jK gpU#jvҴ&%/Q+.*ԅO4 mw01& m\9#aeDZ_0"-Ǻ# QZi_LM\8g?դxM Y%LHn@@g&F/{!Dz97ѾYg.t X @ˊҌɹVm;Aj?G2"4b!./|E b2`ՙO5$ Uyr~xHn]Gmj2>( Qݻl7-]NO:>GJ_ݸu~NJùs`*D+.5+_,%Aj?-+wsuňd03|ޣv>PH~wn곐YPԫLm+*`B) !cD:a?0,9Ž^K`m_kd> Qa.\Y;)]Cǥ}{%@bbD~~yk/0H=3D|FFGɲVi\`B}So(f L:_){^udWaG[UPǮ9O#>?sp7C$vܦoZBާXf9jH}G˔4$ǸAX0R3kO2l E_v {b Ec ''c 1UY)z?y/n~s#T{!>]@F"XWDAOHfK49]mT?ײF|ÆVG BEl}  !g_Y;wƽL:^H7E'XeǩUF;nyvts7 ԜXzz%/QkPbsMgU,̺m?TM-Nxe lF}:#(6>$)]?W^ytF7fQ-6rVHsM'T2q)E]pu |2jŤ/_ܔ@h_@JCF—4?bi EMO}í Lw40~}3ՙI׉P9֌dـ{OMߠcnރj1&Wo __֟+qvn\ݾ.ۡy:5Pt $U))0ZV%c J({l]W˫&, άLv1u)6@IDח~ǣGݻgbb@$[DJ ر1$::nd2s 6TP(==$A4(2 pfqE1X 3'MLL\Ҍlgg7dHMrQ)7DPٰYcLrut'Oaj,YPXܡCL<988X%ӈ7dN)x/]1j((~:440\֫W ׊`rٳgŊx1hРcǎդ,DX j+ Uzjgg^`>@eIKKsrr:wU8 co!{֬Yx[H$۷ \3x:;;hEcHHh 4;E=^ҴwrBuagS|d~a@F||޸Z}C!<o#F(Ϟ=Seff={O>PJ Ͽw^q+P=WFFFx۴iӫ# \ݻ0904Zj~X+Ⴐ Aohh(}vRϟ?777r.\(>}tرUa\őHvu Yfx]*'L߰t: cv{A}n: +G;u*t"zQ]n]Mdҳg{Z66q0 y7-Brssǎ;`sΜ9AAAT*o|\h ʈ%JZv\H_YY_ d2͛JL&z wtmƌvIqռ#GBF?wn(wwwPByܽn:]]]eX/:uj%DNNb1+^xtiGGSݻwC=}\xE7DFuWŽ_)5!aq6VZYXX51~&Ǐ捇Guxe\V 8;rssO>;za``9 V\o3~z z֭Όk`Z6g_/K$' #>Oә@U:5 >TgϞnݺ}6--Znx`RrG%`@`0 n޸qc߾}>>>ڸq} )1}Ǐg͚ELubo_dNBm2b#3{-Z_:9؄ \re̘1ХP(۷oƒ@ lٲeUDHHHzzz/,9s&;;{, (;] m/ιXZZgǎyyy`.Pj~%1i$#ßS?A%pvE(~X jooo܀vvvK,Ȩ+'&&Z)q:tk*th.]]]=<|f͚?]\\4iҢE \n0 (HFҞ"a3fyx\R~f! T/ lѣ9( x{Ϟ=cƌ˫8pzJvvӧ;w \a7%@H'$'99BO<ٿ/D"lWÆ qӲ0/(͗ZܻL-L,}\&m׵)ǃ<f<LQt١ѣÇW:x۽qƸFGF B+ +^+::zh{!t{{)Sԯ__illr-[+1 ü8`nnY ! շT>Ʀ|*V>A#WoU@=Y8cP_YnڔE+z|ۣAi-Zw򂦦d+P%0 l/LS̥jQ0h5tg&( wgnYIC_(` @ }>*wumiڵTˮVFB>gfB%K@Ε{,va:MY));9NIJB. b l%%q3ak@MK<0CP2)rj1wZinރ W| cP, \Nw-Y~`%za'F5D$Vg#O ?ϣw2]er-^?Cejz}}y_Cѿ%t}ZvaμM1T8mF.MC}`v)@(x9NX, F-? l MVE†@#C3N̄#x1~s3uHlɫߦ^vWMxĆ%b TN}stvٳgw67PXy~wpדo!ЎAf`@ YҔ)s&j?Y܄0j=JUٵh|~ 0^"ء~ez`@lN]ի½EP[~~`z@1 g%9. ((R,vV:S@H1i"L k5T5Sו:O𔿱qVaJMOt-$}5^a>@XҔ}F=?*2B9h>OiH  CmxbIϷX/E,މ-=;q[O>6zM6 " Cc[&f)6oaVx}u<L!eұwչmAI% 7B\H}2;0n2MOrIlA*WA#F0.S!00IM2 HyV̹ H} n6/$ #iSN %% r°+<m XCG%ҽ%A:f X}1tH}ku ?#eMig#^*+Xڒ@pÉ~$J$],bcg|(ZCA* lr!d7ϯu\N3ߎvVQ%pqR=@bׇkġP[dFס%~ yqf[C`@Lzj*JF3bwqҶcz bTFs@ylAR y26mxJ*$oooC#Ǩ~DLfmR| lnP`/Nooe춗v8yz Jȏ)1,cWq27E O$ěbLjR8eaSKЫa q}OҥB5.ͳcǎ4$2 ,Q@ >5Nbp }s@Bsʐ7 o.EU!l;HINRh$i] xJM%} )Q;y{us_ڢߜ ͒S(&I 5G RF,6#78 :BШNU6pjay^PVS 1z䯎J+M-P%oK䅍]So势QK a#G d 2_63x[!ļ߿l]+qk'Q/WeAEKOmMPF]ZzE"215V5ac&/lDj4  hpk6IrYbs?{RL4(/m>?XTn(T0H=uLt)Ǧ#r :8yj:jGX ro (3M7''GeR={  P^*6]g Py@9Ӵ, ?:0Pl_9W4 au`פB` @a4 Va8fRG~SmqGueF5@+XFܵ t?KX6PK;((#b<` q}\؀5\л ׭cK4eVqSIi;(N|r`&A-&9 ]FTcv?Z<P$ ?łZ@F$IzWqQ52m3"Ȃm uϑ4cRѳ R?ꍙI5[#ULP0Q$@ fRW  Wu2>ɔڊѷ%Të+%bZϊO ^URCkt( 䧩)8U;z6®K'V ym1mV:By'J\r-gxr\U'joʞO|HG uncS]?_3KQA|hٜ9!.{ƶdgu\Vꜜ%|#nᱫDRXCؼai|OU&EW_Jw:}7ߝ!nA|N˸c|!JuM [y|_cזp$FG⿗nwQ*k}>%մk6qߙ_"Dtfs]?m{nʇHǑܽ@T;D|jլn'UHeG___6@IWx+mZN"n4<^!30 }~z%ޭGחk-5ûs #lOo3Jq]Yc\ 4'<հy>v@Qj~zz9^ZThw}L  au))?viQwSC/m p6Ȥno pv>cG;̤.B~mslYmNl5AacxbnZ S9}'g`Ӓ T0J.l&T 7QgΕn GFyYdޅxB$W՟d݃/0j37S,>WdJ T%X|iח(!.66jq%G6\('tsW⾩~y"d׏俣H؂Nu;{$w6cY+SrX9hq) l@p9WM~soTPUKǸQFWk$Z̛Sm&&@:S:?*cv5(Am*ח7r=M%39*Z4qJ"l=$]l!9Vmk?Z$\!Ѷ~5Ԕ&ޢlÅVP칙"$)N&aٯLqPWǾ}tl/7?rs__{6# xEv( XE(DâYi͚E=1|^*Hq|ZW{tJ#~u'F<I'o5 lB`XO@tU8Oj_H"HsM&lGv2Oyhݠ?"/HC()N| $̏Y$|EuQl.2f!ra'2sq]-^֟߱J ./S'R#x(DmqxդmxyفݐP&1t ˽gDt͓qy߉-lYE1p ,3sR$\YG%5I$/#ZߕpۂZ-|n萻kRO~xSO }GHL 3}=Mr*భDFd ᬎ쁩 7*юEEiozQ{SHzy'ߌى? ґ8zo N:EtFU믷1T΀"{#K h2c^AZ#8XG#0E'x%IRHnP_rZM&="r@0ɝ/ N5~C S\AKUӶ"<&\I𭦺AQNZ C[urʷ춣}>Ub Ia ~ڼH4~!HYFI,ҩ_1ygWH=7N5sגpBKE}0k[XZ{4 ]\jl퉊=Qf|.;0KqZXMUf*,O:l)@]Ñ%'}H*`Y]bs`9E xQA(9 C H:vbkLQ3ooo6@-xh ?3}⥣5Ynep1cF'+M0e ",m!種vMEC<8ԴxJЬ3 p%&&;hGOMfbԋ{a.*g# J|d\5xC$1_B~B)PgN(Z΀(& f$ ѩ/52th$'w>! 6&P[Ka·_W}kct аQ}{'P#72:21hfzߢ+b[j&YF0L׏mH͈ 18X󡼭۩EZF1۱zi -#n-fsSN\8A~& _X R'\YؙԤHz_Yk 5Z{rPb{ &[11/h4F~e]XؘhcƎg~ S`sn-qo$a\Ɓc]DuzuCڢр$` Z\%J/ -GpcA|@ V3|h2ڍVx,c,_~NgH sИ=e^◇H|eTX 7#`FX({MZGcgCyC:d%Z$TFҊ:zڏhGZ 5-\=EޙDWF3ˆtA87sZMLpDve`'U6"o 9ܭnFD۴"t;TA@P`5MZm, FA^J q LQ- Fz49mR\XzѾ]:-8u@EKV3 ӆ x9=OUpZ4%Z4;TAa֍])3 VVWnoPQx(]E} !cgqif Ѧ \r1B1`źn`*#(t9uB;xE< o@O`P.|KI%TH}pU#B{h0\LM;P]U*6 l@ ;j,eL2 (yZr6A=̅b 60PPwJs[E=:8Nw7Ogdj[7h2vU#pĸsqî]hGnrrwhPlG^]؟Ch5~ZP=2.-"˴^K=$w ?뵍ONpub)w#o^aT3L@+g<_=8S:HN{7`qk9iYi)WRzspzlRo߰>bj¿4x(<x[.(5l33y-T&~,&J( aE'I=ץ?TAvp|c& +֡/6$Pܧ?&A[!Ʌ6)ldc?oW;.?W9c;{%?3ao/;5*@ uƽ>דb~#_0Jp!2@5 q;,O:;)YڿWҖn㱺 Bwa'8緑ʟ5%ޜK&/+71"=X`@Ws%uw^԰|շzwݑ_6k"y85]?&%0%"n1Q;޹gP'n:H5T̅ Sv-r}Ok*UL˖pAͷ=pUa})>'Yf{ZWc1ЗuF]Hv(a]-<3|e_a-e̍ M{qvk9caΣ˧FÖL݉ϓzWd-]f+߾3L/?P(TF\zÆa9 &w%!V4_8_i94LOF-۴wu3qNJ\ϩθ$@q{O3aPq.] F>xȔ))GW!*%ibψa@5 Űw׭[w8g7ezmoAnr..1 5'S".D=c3gNٕ{r Eh<|J'g:3}^ P[ UͯC;JS==򏗵d6Z<]j'S<ձy\f1s5{"JO'դ^j3[Ϸ~Uòl?}1܀j4_xv3k泒@;*>r~u*6Zz4ehh(}6OB\G:)~WaUGwpSB^A~\ Qc/pg96Zu@]s}5&I+.uz^hMY1I-W=VU%SEs2OA3{$f~1$q-8=|U?awr c6:1IJi~=kv/VUNvV1so( [f.:?NӴqU*X1w-E0Զ(9ɯcS$90sȍEs%Glm')Z>Uk 7KY|"=)[Dϳvzqvrgw'vc! )E$\`~~avygf}zľ+w 4-FiyIO/OK2q^__8u qI6ڴ#WηۧmR _+Kuѷ{GGTWl2 ]^.VK7ºNji=6Ï4z=v}p܆VUZ^'˽45|]ٶKP{Qʸ:fKo-yXkgbC(Uf*] PӏN ]zu_ziisN65QznV!^)~[aZ+j5#6*{ZytM|/PG;@TlP&)*6hhFP(a5k,TlCP@Ŧ PfLYfNQhJ1@C!gP(|>l r6Pld)x B PPr gPn$2 !g%$H! L(8gA@%lOsacRy7ͷnZYsd^P6Ta?6z?e%v 岛IϷ5fУ[vnv«.~yjԫ,_=uF7Dnţ9BԬؕeMU_Q}}cθ$iΫ̷^krr,!3!'qjρ*.nb;ψOV \vUQ2 g~bݏJB )_}rYcrһ3j> SH)ӀαG{ SK tR=É| ~raO9?^ۏ 26M~ia wXٺ$۬i۬~ɩox&gchjFc}~p֋GaOS' ]3-8p1s9.ݲ[t*odDqQtP / %]ƸG+ wpq"5Υ.O)+#%7Ao0ABSsNK31RQ'yX4ߦݶ:'N5wje]̂/pИO/|vXb ߤ?he_V.hksn=ZPiE@+}xL0گUv.?95|yU.]@K @P]#~:1i`LRÅ:/9GekJ6%i7mkv>YpȽǦÎ۶0з"ϊ$V"%>۽'Fo3E|Aϡo>:fN&IK6HvhqyEV*kyeh}e뚕[RQ̗6O0B g&;gl̩_&ݶLeJw I n{ :S]32_Q_[Qd/n➩K>nHyEm|^" = 1[XVNlҗzdᡴҭb :B3G˦Z+WJ"mخL5N䦟nu1wRoۆNƝ{dec==A5َu hK".jRy wlmͩ{8tv:?PŕEOUC3j9Ͽf 2ZPj-#W›fxdlj-@WE"BUmL>^tıQ"i!Ks}|L:q?"Wχ=|~fߍS!'xWz}"&G'd5Sy\.A 9q}hg#?Z,M|bC ^+}JmB~hb `{)iUY>n<ܪNMK7"DR+!/ϣI00+zMV[U_Z8ɕN#h&fWlV&YK6B~x9\{;n.{ h$rlҕ1n3)שf{ʍNM8*.Yf,I|3-Fm7}S{P*6>w7ulu)jW۱oDqˣ۹sY9MS,zD)C]ChɆeZAlrAzl1JL{sX4w+jkݤ$,r(ۉޫ'Q*xe[Vn I~Y~ɳEZ-TTSE̲ r|mIq:#[Fvj )g]u}7ݺN: zy+㿴r+Z.AIϾ74ϲ鋃 ?= {;տw喎CkBNKl4Munub h$ /w}v^+a߭k~KNwѻ40mgcữ {gi3zLδ'Q<ݼ~~LhznjI*6lnPIBDc=L>TvxYvQo?=Zv08Qbػ's` ͳlmt+ʁy ӳb|ǁ.,,Q̱-Բ^?oJB]&9CCwlR~MؤߢJ8闯W-,hYbb'g#J=7yO RK271nwC}=Zq10u(N*IJ}SWkPDONe95wk]J|VG't˨吜|:!. h r6P"*ǂ{Fx'\{tz,;{%[S7t]b)hl҈Vщ6ޔiF$%mfOn?dѯ̖HǡAQ++hCv ~A'3Gp1uReu#OT>m>ڬf@>т]~^d;d:fg3˶dOo,,̓M<2:EQ63\B*9Hϸ{.oZ 7piUgr3 c?{Wc"s!oiV rH49(4[tS.+gO vh &W !C϶k_v:'ny15㢗߰J'~6k_.U׿` ? @C!gP(|>l r69‡ @C!gP(|>l r6/9..3"PN [SE%rrF1eЋ!#7-WRV<&>PN$?days.F#?ȌZTr|*%@C!gP(|٤Z>XP=g8)?' [߭z+ߔ_[jCKxys N@ ИP?r~(sI;lQeQ 'g4/-acկf{Q~О_gl$ENqmI$јX Zo@?9TsF8';׵CeϘ+#XHDZK^lN5u-v~rx00'\ߵJZ?gX2Rry>5/Uh8`Egt qeJo³_yd?S6S=<}|ktf^qƵZ9vXzPx ߤ%Q~,/#_{;~]|L0ƛGc?PW~ 1$>Sv@[b/윝Z'YYߜX4~,,iw9]:v76D{wbѵg9N>l}j)Ҙ2r[^M9N$` 3#}=53ŧ{e@[ ev,H 1ZIJK"}cJArNmf.c;ú5(l'_wuOݮL{ֱUvx_%/vݷ궲yl55_yi ^n?žuz4daY˟\q_c9Mhz,݈A+^bXeޟ0痐;K7wu3K!/K&nKώY9c2h[m䦪 2I{~pd7F^U4t:5V̓*?tٵ5Ƅʄ\7+̳c/U÷\v9]-cYMdk9eIABV-7vZVs+OkCe7cZirml ekn[FIo}nSn&uW82*swzi١R-ZNh;h?jLgK"kcbQiID:trceޥ)ZJm+Դ&`D)e;Y4~&zQ楽ʸ_Ei膶 ^RodJs[ղKд MjknUB$ElWǺʢ{Y(K+.>}WdE/被5Q~qnG ˦Szi w?®)M{Tgǣi-νVܢG}aMmˀ(S7S %Da-@s6I~㯧\LϿּU֏XI蛘$-JM]9w1}y{,ܜkآM$:0+?Wv+ӝ\~nڿO.8߰KnsncؑH(E%QޑPk׷^$>:wIrsk?r]:pQ|FQǮwL;*e_ES=qت3OT[qJy9MP_aghJ*%zo/Y帳)*Mr6V0p.S@ mˀ·8QQٷ6 qr hpGk& Vvխ@OpyM[>* ~}7j:ɻjTL~h\mn,~"+|=IJz꿫'|C;KRw͎W+]1B_:ǝ3Ȧkm-$S|g;{vSZ`/bInI$oL,*-$fMj69"n} ~I~S(̀UZƅaVW8R/1ivqKG|Ѵ Eڶ7>7|J\ۗ&:Z0I2Yrb;d}YH ]cSٽkHSv)K?SBCS=6?MU#K疁㴲UGmްKNe@\&tSHQDȔQظˊgon5#s=1?u^l$X]+N8s:Ps;>y}1͍_n_Huł]'S~haG~G5e86.}Qxޛ7+:8Wgက㿟ݹO~~tb?'fg\wcx"Ĺm?|Wԙ}.Vv;{W4&pK"}cbQiI$yjLZ|SOiS~UB$qlH 7?A y:ͽt{D&[upODJngд:y.i+U>.hprʊ?^jJ~>xl瀄#ma\UU0CQIGTq޹X$D ,~OKYrb9U8+=许^IȌ zf(q]/[:|vRN5dT(إPw?u*ޝƫ3ezRT"'F)OZU Q[3KD:##88RDX*zFh)h 3E|r+ySG4%qfr (jڰ<,=8^H'`90ZJ/v2j_R/O1bB IBAn>nvЛX 8RrL_;z@¦$yR5N<`(7H SH(_TvxD-06UM!i9(pOg~&u' xdcb`k[vv!$'XA}qzO cKj!΅us_>0Dqy Gy:!Wſ]q_&䏄%1L*:#&5gH8ƶpCXy{[qf )!~j#@&xz0"ڣ7?<EfnȣD)Yy/݊淚gT*\]/mO(Д#kD}닣+h%so~oV_샀 ?E& |\ re+;_>Ј߱7`nF9k7kq4K2FqucwfC8z[A}@A8bkqȎIb?l$%\b /~bk5 +H(B$@R6<~P 4/8 'Wmk 8hc2Z9L?ltID1Ju\ssZr}Bt6 Q{F ʰsN\C'lRJȡQۋ++,Sqf" ȦZ6*(֐)>B o_}ƈDÚZK*5I&d[ߘUgli\@$:fbƋ/-l9k9>S}v9H]>40*%j.wE՛ڧ,(!FKX<rL+Gm/~ڧ,}@0ZrՑ0P0qi~nwMAΦȓ% fcJt9࿸)<0jD #]|w).k)~zRjR9b ֩%ҹI߷S rT wݖpmn %scVb6L%F3n;ʶcĚu:g^?xJ׈upK>EjxBNs# ͚]^8lR;ǟ~Vqq:%rZaW3H_%ű\mkP)B)Js2*6ޑ_2iYmyQ:S *,[hj#x5Έ+hmᣰ塤\ X NGhF6B9+wF*Km=YFCGM̲ 8@QVͫ*WDf%O:hdja̴w݈~vEq9cԶy86 V刾a"K" B;xhcBn.v-sxyybniʄ}Y:J-Y ͑3c(Gۄ 3h8ZbisnjJl`-QPEۃEEt 1v~)9t:tD'{bB:ԗ[ZgL|I~::?F,0s^z +r-ѧKC기(G cs/3Skܘ6[5=] ;.IeEL-FPٸ_vfXk1Bsvdəc_#=% \G0M>cS$pe9haΓwo~ԙrjKڈuе'g<8g$$g8Q43O@Sxf"a>|cMݩ+CiUμ#L/Ч0dme|"G˯6b'U4ZTc-bh]YY(cHStQITo, Χ+i3u:)Xstgs1tRqkgDSQO8(Ri%R+AL2nݥb\n\(~ZSQҺ"^vE>1vI"䧡kF i;+a:#iߠﶨ^nWƚ6s^;*i^ -Y ;!AAțqV{=Lv(ӍZÇfpw-)fA8\q"5ә)u:aڿMv8\%gSKG3/Q:9N-*GZ&(d(;gcIÁ8׏Xp!eEHC呁#J¼[dH}ϳb>AE!+θlcv=nƋ}gId&E}urzO=R? y$]Bz&z8&.Mj}tM)HNM"F!_ -w}ǫ ?LS".!vRLGȜƦh;IvQ_%/u[\jUи۩eŸz>~eZ315jT}Eti}Su:0GsvVIK3952!dc+|YO=U\/; bh!As0-gyovor}2Ce#$#G;'yDO5izv]q_'(00(wCG ' a?GtSG)sODšМ1GHCF0wWZUo'hJ׫FիF7ugݳrdRS%ĺyU0Q}bia RZ[[jYvCOս>t`#*Fm6|KYʡ]2]Ǡ8rH='\3g7̍r+'4f5o.Z51iݢ/Xַm;Ұ>5;6Ku8 fj]m8bAD"a.G#^ ??A8-M.쪭Y6i8~H_욬'"zMsn`6N0>}˒K4v 9#E&~C, z:^"G''K?_^8#)>2]C&,ח׶TMTg_Y,#`6D׭-6' a{>FG}t(t^Rfywa~9,[.+K|>I(J&šL rǡyYT\RGv踀7 "2ikoKj8䗜 =s+ef@tCQd5"#nmU _wϣ_$_dd^_9s=,U+INL̲T\R9isHZ~]~de8.ũ0.R]e}0n?j3=HS%D{#AdcHij(Q&0Ywo[&+1mj<>TW*)k:JH+v(苍LOmmVv3TiK52oTJ,(椱ޛcp)?,E e**;J̮ǟO5Ob?wK5%5y.I,ɈMwrnO53Blg&M%;ݸ{l^D8#Ni2u;{,ZQE[]muZ9I-rDE=ϙb6U׊ZWA?!lĩ!tŒkLu;XޜaA,SΡ._/ 3E1#<yҳ/_V{YPT7{[fj+UBo)z5R=?%h@St'يF?Rzmԋ2Ce KTȼ-|#wSv3/vG 'MkpKKO39ovs}U=;u5pv_|a#_ Mkhbņ)ߤ@Ϛb{CMUICLCxQ]yMrMlj'nA#)FXĞ#lNI>bumE+{nUo'!Pܾ26ZnZ޲.A<urPFo=)1X/gA[;zY`̤]YF} cmeM^,B`cֱTt}ލ 3y}e;dbZ C62̚9N Py[ (vw_]1󲝓a<]ګ|é|JCƱ;s6CJcfV&@ߊ޾!Y].jTߓc}]ާ]} :{'v^]ꨳi ҳ8xexcjTur*<*ñ3nĽV-L]iƻO˽ŀOhӁ><%TrlȼC]H3[*1 CQ;=d3Ekrnj*ʰ"rk>O ]T,P(V7& F]q%x6x&$='ON(B;ʹd}k5'1!D*!|bL[ c=G# 8u%Ɉ(۴I '4n@cD1M]v߼^V4)"Ks91K!K+Z84?d;4ï+ri2bQCb뭰^"%e_KJi*&u<_4rPwo#a˾˒.19EXȈ%!RO$KjnYΧ\6oiTXo/ʥQ^ 6 N }I(vT,N* mSrs6Q ZqAI710תEbKa,?;IV:k| eT0bouaj$Zpm IDb" G?9e y1EJI7Cs~!wyB\Xi:Jӷa}((LeS܌q}+2_H:Z-J7!xq;_&ɤztvm%D a]F:Pd%#w(k{";>Ab:Z{GQBț-8 ܹSX~ߵz#J^s&3.۱o;3UGt<.؃\2\IėUSZ?b;B qOyAz.ushֹqn(/dIO.F2YwBPq *#60G}F({(( 6M 1&I$DF"())I(" 3K{Rh'lJxų{2 'n(GBfTV%ș(RPDQUCV;[^]&#Er6!g'INBPTCXr@Vʊ81ٔhʜ nŏi۽#둳PIG# P̠ Mt gS%Fߍ, ,PA@9.ksu6 ?MͲ,]1D\P?|!tP\6z ٔh'3"AZPNǙFEEɻ}zY1vdٹEhК -X׷W+Cph-bN4#@FA-/`x|D4Žbr(HZwݢ @&&T ܻP<95n?oDcZsv.U k}˾'6h%Z_Bax*[e@V]D8P|H4~p ڄ'EGm]օR] ge=$FCy<," TLFYـ.]&]©B'^n P+ZbA5O@p(hr6P=+ ge<?^F(]EF,J@(Ha=C͠]~l[P08Z s4sCܮW-\bCINE(IĢ#K{ a%hb,"بW/owDIو/K]h@I +{ą6Cdro†OC8Q^g.!ZqcCs$ 25.MNB(@㐳Mz~;g[Qt_0#l;aBEQذ#<=ϡ}9uγpDJR.N?}EO50NB ؕF(@ I]EnQlT EAX "\<>evvm,49@`{m@D@ 4!>y JJJJO6W{fi4ZF~{>1rРA~tWJB>zhmX E܄!@p}ќ PN/M~zB{w˗[n дBCCϟ߷o_۱cކ  @x{{Ǐ3FUJh o߾ 6lӦMB h'L&~ 7uTuuumË/|}}]\\ !@p^^^'O6mDQF999A4@ӂڣcǎsB(@KK \)))bbb68|ǺбcDŽ&tR}}}|ȬY'** m~rW^h6 W!@}mmm+*!AΦݹ}v||"D4$ My T_7/$$)ϻΝ;\\\.]Ttdr?GƏQ]h͛kVmÇ]6o<.R249ٴ;ʎNr䈔8Muuׯs͝;WLL /:u h{.^hhhz())! d2#""*oH$uu:MuAڕgφϘ1W M+55bA(ZBBЀPaE>f:T\\|̙N\KKɓ'xԓh:tcǎUV-Xѣy-Y` SN ox'P7hiGt… T 9!>>kjjB(*((PWWoH ǎSTT\~}dd_K @;|?iaa1yd r6  ݺuP~ëcBlK.A]сPX@x{{7[j222 Tz葥 z@pnZ ox9bhri/N(_ݻǏ-,, &(ޣqqq ^z)l@sM?g]]k׮A4@;vi׮]!dz{{X,!!!o߾FEDDHKK7_(2| &l|1c}fϞ=D"D޽ӧOmmm!&" KEDD @|E]]}С>ī7Blڅ=z`qͰAd(EE7z"͚lHUIHHwުU>~p!Yݐ!CU0?Rj۶m[z5AWFFFA4sN@@I y˃P! O *xs۶m S(,''*‡֮]fww% EGG111ҥKĉ!A4@hjjEEEG5 7[n4iҰaèT[Ǝ 1@*B 3f Dwwԉ'Uـ96ᑓcaawÇf崵QATTԪUƍ㣣a@ r6 p6oތW\ H$JHHdeeA(@ F\\d#~|*PXX(&&QRTT}֭[`0~UFFĄYrjjj.@vرi&{{{]]]}}W^@Xs>;ga 7d2WZERa3<6l@xԴG6mڼy3Ñ_N^^be^WKJJ[XZZ66@](ӧO999kkk |KMMM\\<440E%Kĉ Xe%>nC{WCXVs$J$/I6mVѸ#lޠ(*--M& FNNNjjgZqy֯_333===wb͍ڱܿ{yyIJJJHH}qqq^FAlI]˽{W^; v?*((7oD?gرcEEEڻw4&yDeh-9Фٴ,h[a,6 5\j|Xh/))BLb`H2-#}=??`NRdvQ{XSCJnJ|^ZB^jĂԏeEc/Dak@C"H~k'l۶HD$o#y,@40K ݵ495nn2rx0;M bԍ&~^焟#Itw(N% (ʆ];th?M"?kw0wU(J*DŽ<~uɰܔ8_l닀xlF'l-*)̥(˩**))(P4-JBQ}Y?p/%t6eмRZAbB4?cЋnU};ODBB(@ӂv׌$ vcC=?*?=bl ^ R,e,9 :&n;X SETçd$fffą墜té-(DVYO?MNQ,M,]C/[: Hh%x?),BYjדS,$hiUbJ#hZ ̲}o--̣Ia.9OO0o UGJ_Js1\jY"bHI ]bEqs̈ @RISJY5ߎQk^ʼn56eî]7[AhIZJ'*Gx]iO"*Ž˰87Baog8u,L;Jɠ3D~ YV4hC,OxM.hRW|'MD")&DmM@o.ij5GUVՕQדQv2N ,?+KZw Q5D{$}o 6V~WAf24-sy#a`3kX 'W`' yza -e|+ B<aΚ ~xANy; .ݎxĨH?Ok&YEeyvܔ8nTqɁsu(L4zEy%B?>j6@*#P7hSO@@H"%,. \ $J$3`2 ͬ9$h+>b&IYMHsoM+!|~xCFF-;HL_.]E$dm &d$ۂRYsnkh>u:=GaNEUnaoУm W6g)v>!k%4-biTcIgdN4?Q1g7ubN"yVIh_6+-*8!7m3s3xQlhc1I^-o0^$5zES!]GG|svH"C4WPM--̣IYywLY+å&Qkm/r6f=aXJ ]ϥ7CG}lM3пeV@3ܩ`s~ika Зwt; pG[E,+~LdJE&{&7%ۍBZ&xL@d HR`w>pR?(Ayয়N\^4YJW3:FaIԇ|q?U2lb3Fnrl^Zb ,c^,1zƥ#ן((,+g:5*b{&Ftj^8WQڼ*/TB(o;]xa$)EI+ffr=!?'%Q>!hvLՏyʱL_1"v~P?ϢZ&UeiUU6u07H|ꉄАYRCj+L}r Ox4=>NGbj}&#6D}Hq\]]djPޟhFgqܢ(z .Xa'D^v23sm$4⊏Mi}.TFoEЏũlo3BP7{wt 5n"pս:B ÒzDgIhdG(ĤH)k-YtnNÎOH*i@XEUACMm\c<3Q73͇W,#f,mfohVAoB,7%^QSPNe]V8)Qǔw{M7*)tcixa̪JQ4~ͮRxީ-x7F70VsiAϯx_3?ocҎcsE]M~T|t1>bo;žv}!)glx>q=/;-}>(|=blW Į]Qv@,d읆'? ^^rF-Vjn lR^||;31 "-kdqHW7،uqe|wH؅xsǪ;z|]U'~yZ&qe+sR≩H_\g3gĝדWN=o o^WMd+d FתgLɁgfA>7|]RqEΆ-Hw(Irw u2-|SaGƇ $;9xAE%Aٷ'V{NP? PEeeeDbAAAqq*s/GiiiKKK33323TqbZnO8˻x=|𷏢u>lA w4+)c"ɱX)(q^\n ʥqdJ5t=!$UޛfhZu9#,CTοgOV=6۝W.,܈YԬ#GPפp#.;3XOvr"Z /[_y뮉a6znXzwYf\ yv:g 54 ؋''q|/60x=n/ $8se9~eGfF DdT4MUm{P>ڳI\k84)e(:-"pJ>`_qEB#Cyo]g9DKMIȩ Cxe!NL*`AS~/3JJTqqUCUQf#ƉVE&y>묟?JJP}GbB޵2҃%LYZb"$aIac5 4/*^Yսjl^!?`\vuc}~a Ø5_1+?ߩi'w)VF4ae#Pkb?ܒUEV޹$u~dH@I6Slzz3ټ2Uo[.h}+!_l^z&v_qs8ʽu}Ih{~]8yZI,:Z_b$~] aދ P~0fV޹++&-sXi{&Wk8=';GQrvb3th9Q~x|m%Yj˹ڶ"=bǟE5_beD#n=Nz-q1ZqԢ@(*qa o.-)+u0oxqT7vOX_d R{w;|N+E=im#gߵS(rT.?VDfVlO38fk\:q~`yն~S^Fh0U~D-*v X7kk"/ xz׌T&ϟXu'k4fO\U[{#\ )CG=&]3_o)y1'+TT֩&otg9ΨKsy鶙!k ƴNXhQc3/K?|Q!ڌ8|NQ}Gl.O,b4L5iEikH*:U}ӔϽEDB@:tpP hj¬H?Oy-#aqihD$e.;1f:ȫ'jA$9yG+H=oUfǬJi[ P7 %W<}aL'b;grq#W:wa-6:W>7Z"(dfdx$s5M2lD G?|97H}kИ9ކ:]׮)/k@՘rۆyvx97a6A AlVyڛ>:Xn4 wi<؍SN#x濘No͎FD?0$=՜LmLˀ*!F+ڈ U~q?W&ld֥[nyj^NzNJG}{rL`L{=f͉~sE/'L,^%M)+Ji aSO+}S^eš+ѸX;]{+/v\5G2 H]@gw!f:v5S[' }p{|bewm!EXtLSbwn yz ZKblmf ߬y:B8E7Jc޿TRXLPQ27X^]P(Y'xR56]sW#"o z473!˪+lGvf0u->?75Qi09ia>_ {"^9bS5t3^3tу4Mn=M5hFw4S}3̸(z 4,g(*q"ˌ>9&#䤴ju6ӛ?[vYMXn5|>W{ xMP*kaetkmUM0jt6u8Qk8ʲn+L=|,`t&.p0$("Ch6TVbn>\-9~]a "WzjtM2nqw{~_|a)TPkj &;?㙍=İ Ypl% jhDL _*f PW'>+3*/. j7@/L9j`sEz^'߫VXDK$1 A*r6wٯ=|*:3Ư^J| 0O(R ()B;;?k4E$$nɗpᎁK`CjxCT7݈1~>æIj왙6_Q3!@ /K.~y6]~%XR;ޝ}Hf>b:l@kD-2 f(qϋӢBq:dY!fY*#kly}(C]8:Aނ%+O2jw߄Eyx%BjhY+ j+VF4sΐRҗJck"-9W-6n 彯lfzxr^>3#?m{ϝ%e**ˮ܎ %ExyN.!+毣 I&Ҭ;X1'lc'N:jH Z{df@1ggοRrS>?htzz Ȃc̷U-*P݌g޿};{a ERZ/ m>iZZhzL \$Ո1{_  /ijHzN9%"mw0Z3[>0̓WBc&Ti(U&lp:s^t~wsB&sc 2W}T"`'\ 9df7)Jk;C@D^|'1~]cШBѩ>&yaY2)hae%J ЖPij9ŹRr g@-|߱{4!R;8W*/V+_y7֥Fc;_|$9_[llAE{'%jM Ѳ&k#3sш5頗~[A|Z~"#)v?ѐ(6ۼ΄uLW]6 7so{:#??_TTT^umὼվ I;N`oIЖ<_446!wmM)h$^$ĝ;a[Ptt i=b?ߠB24"HM_u퐳+{&7\?a \^,ZԪ ܧ9lVNb.L3 j ƨv),C4 ,|ay;wPm1ʦ<Ɵ4Rjn9}cWXQP)^dT%V}j?=d*4$ӯ|Yzr7yJ PES%Mj:ש3z`zf1sY%$L.\]>ܜ6b=7άV@)HD1TJd:@4Aac^X :瞓WX;-h>Gyׂмp+_ :CL{m/թڶ OVP6Fո7I!glUc=?&e6t)~>Ë(za!$4F5ϝޞ>32Q&)5TjstQ~Yl$,!d3꣤o6g_Ͻ:sz ~>¾,)c74yMYnGt6$ݶO }ŕ嬄:$/yVѶUO,ߡȗO|KK.-.F$nq-7"vBy;ﶊt0UK e*P."|y] hyl: v~zpY\ૉ~UTV\㓰\F{ A̻gڙ=Wx&S$!&pϪO ]X\ZFavRި1-ϐ $ gکf2O윓bV{) U+#"U~Ϥ ΢] S(&*%r9;Z"*+}{i ?z_ZPixxWok MBQߌb@(@ G^n`=``Ɉ ;5BXBf8047 c~PbRW#);o1ͤ 3X2zT3pef旧?9dȒHd!2E}@>`MI 6-2Rr1'}P5OR#M a#ңB;Y; hZ"AX+‘`2rq禛C=i:A@3SY"if|x=)雑!\e.7["-gj^vr~ZE?׍^:9ػ^'+PyCh||l+/a(ULrڳAqx8&qD҃1. !@ u`3k3D 4+"GxSg5&= P%ygp;WjO*F-K\NeGVE{G8Ev *ȣBv |iPESbldfPQigN*uδl"Gg2f,r>Y 2oȼr 9,7Wgcɣj-.}6_=)]gM]kֳuIP%34n9ZblQ 7 >|?b+l,:68 OU$l8Lm>:Řpq4/Ymظ7 819ˣ ~&6c!_@Φ[{e8*B I(ByYK)v̢BT1I]S}!1m(XWgSh 5]vJ ۤ;- ?q6r >7dɁןXj:h y*K pΪs6h59 ?SR^9~=C!ܺJ>X16ij@8i r=q[Y\Vu8JDhw|!ٷv'[Ŗ]ΦP“ x;KY9"PbbQM=VPF.`,$.Gp7'ϯf=6Vmz3u5D%~zKܣ 41w;TVYh&F`&f.stm$  &gZs[*\sFND,C$$lZ{xq  >CL2ܰ) Xc)YȑODa;@T3C;o,]?R̄5Ц"{d1g0b?O{yj!g^'e-r2feȿSXNp5O{;TZ@DR/'׽ i αlf7| ,q8l>#!+3>T-U!9R>SLo*'-vgi4ُO:թYU<+l%|'.pS?ӫa¤P +ʆ]2_Hzn(e1W}< , 8{Sin߫{QDh g(Jd)Ҫ:7\ ׷PJ|]VA `lrq$̢JALNp",|rm=jap82o8b? }qr6TzZd׾EZ}! C 8ZG<;.3mD`ף]s, -83lC].T Qx_;T!+D,xIS$ Xj1 + 4R!ٞ؞ۃ+<9;E{[}a29(HQ3PNUjbZbօzqb-%4 !L=ІYv6E5`-JXD%ad@f8 A>c б01*+fnORIOOTЅJh?}~MVh r|P" m,~@CzLI+!DJkDU9G@O^EQ:G&,HUquo9,LBQx $}~,b_I2Q!hy_.N0dI$J 6DIzB(W ͇LPh}zs6bdiF]VyVp;>,4`9BoۑЏx_դBp﫛ZA(@sгs6 mŀ'9i9?,S\+/d'Y?'X'tcV.mMb dywg]{#HKGL @@@BΆ {.Y-?Td1@P4?>} ^aܕ-A`3B6@ۧfCb0iaaX2l' J16Ԗ֞IUղ ֺh~݉ Q`@ ^(+^"2`6hV<GZ+ayem cږ2saAx}͂5_ J0hG$ t OM1bAЍr JsTiA\xse!nx <*hw#g׹ >7^M?a ԛc%~Z$g*_lJ/L.>]]~rlm/l@|Є &mPVy#^qrlHKL;\m{8Ą?~r"8?ǧ |p6_ysa{f|8Tr6(ޚJ1/dmO71g: SqY_!gWG|uk]y ͦtf—@AyΆEȖfZH!#}-DX A ?BOb}|dzWfn~B4c EZ_\Qwk{hBXt0E֍0NpO}CW^-L[RNY`sY|$ 1pB>u=ltpDt*BͽzOwÏra|B龍PwDF9DOJɭ<>i#V:r&ĤE.cq{,`%TIf̦'pj=gk %oAaȲ8ZRy6o YP3T,~еdż!}6_ ;H5Ie,DQbdbQo&q68xCCj"K&0VhlAV Xv {ܸ_@~!Ϳc˴]c^8n1i1wUWko.Wdf{lVӹɇ U"[~+RoPe֢$|!XدFFmPP9V,+vaV٭eÍU/*j?ZtMJt$V|m AL{1$}?֑ i1Ynfu9SLNBoΆ7^C?KBnz{4J n'D 㽗-[*0"+7bsl6lFK BHB~!:w!%lFdiwpQ,ݽ;DlDQO}v系~v~]*!q\O+ ((~eon~3%pE 9[I 9.qi'TVǕ*|l1>BTuLUCo2ZM s; x(Fklz̺opfkZ rr :KJ~O2EWwnť,}e^]t Xu2IF,, U`+iUbNŒw-4*7ώ럕aΚ-{1 Ģn+1"K=il&pڟF:Ѐ#ڔ&y*h݆*;kYA=WD1 0OZ.Q)Js ɸI0倕GwҁOzyڿ;rRk|>HrR'^=82Wl6ЯNʃA.&M]5ѵEL{ %EC`? L)R3 6 wh~upF,Αe}TIeyZ^zLZ;Z.a /FZlv{ gSh{;u.ؕobˉl.qy )Q#M/)շڿKsz_C~JR [,T-_:'ɇtZ|1.f5:73yѦu|wG8AN9w Cf1n"e: ׷p.瞽UrjMCrꃩǻ{SfSQDQ-F$ ٕoc 5Nc؊"cyӹVD[#(p:c**P8Xb6)bՉeپfrkE {$FZӭo-F/T**k;,S"tk!PdXX(y!@FՐkk7얾B!qLP<_ƌ|zzf"ȫMBm6 L[-FDʈF $ZvqM FA_#XQ=clJCQ+$EtCm3T,(4|F2(; ))@zNȮ l+6>c0EAHa2B~sRܽ*U&!Jz"mDhdj0QTJzRfJیިrt%D9IH&VHYz!9Fl]j3$a\9x;xV12|g}^˅bF6.6#-ͽ+ïHotМza 7ՀFi=q]6;!A&?¬XM;r%_.2h׼k7Y3d`TI'/irLx>V4Ue/o$7Q<{w9NZuMI*r͗#O-U2ۖPv[c<ϗ1ܪȻ*Gg=:wk/HCCf$/jnn1 ʟL+>BL YRl4$9R)*9Q")VjA% \qm:YRV^3ċ07;աO(1%)ߑ+')e0QjLQ;^^9*hӛ90',7VhZcl:-,)t ]=q|0 3)Ƚ٤lִtUaDHޓbuUǂ@* TI$duAznڭpu A x@%"/+aēf8cH/BV #{~Y@ 6O#IQ䣐Iɹi Œ䜔xz';}VR,N%E'Z֤g`JϳQH!G4G4|76g*) Yy"aaH 25'>S[>#@*`JD^F (4QjEp58R}G +T 2[qnR*yRJoa t2\6M} I4/G)w. InL$I87S.ΓP´DMtMzֺ&V6roo4\ 6M̹KY73N Iḧ́-kc~z#[I^TyG=v6|{LYETevd[BpVNkb,}xfXIϫozhNHأb]o>F_fl6\=Gə9U}l .@v壊ؼϝ6>u ̈{w. y:?r]\GossR8'S2߆g|]:p'o-+E*˧?iW F.VG2yjn CfݐxЌ a or}Uż0e~h\ 6ڊγ)jHiE#d3[!C0g2j4JcwӌqBn}#b %Cn5^ldkӺ4S?JD5.z Eᕥ~Z$z\J@ BCV?CV~Ay!F@Jզ}ڇPeߦn&Jt-s$_7QK|i辯'k6bJ[#8[zc"!ۙ_bZOP=oNЮ!=ST䇘OF/rZlۑp6yv$*3dsqҜ[w(x?m2^_&nдihhO3)5.NA `#\D QZk,MJT*|h0LPNjr3"IV =;zh/.~ޥ-2Pp#>BJa(aG͆}?blovv~9A֞E惇> (nnPʵ.GN0f(rXlc>ȭ32smE{޽kBq ytEvgFݑ_2gjseP 6qAwg LʑNJ™9Mm:f3s3`PTwio4]zy_`<3]B5apXL]`t?ktb6_}^3!T*/DX+'ATY.B 0vyI*CKU wl"GV=96wk=G2?Nad{QB!o4F.-;h0LjfSp /?{Õn!VȯAGu5ؚv:zg2Dz@y[+ڤo-6!ȿ˧AO"?ɗ)>`Uh6b-}LlOHIn"T68@ -&K厜o*6M{WَA;pܮ L J!|n2S'G_X.avސD'@ jkޝ9˯Mrc'} fXuLDZ(`6ph1zRN2˗ ZYYM?|^o0d xG 'W*pKOxzFV<˯6+h7GZ_9jʑ=ƎpLTPJ;ߤ`7I s>ldd1IfIeɾC}Ow.E\6i+HrLp`3Zr2``Sc ~Gj@'SFoET)[Z'Ƒ>+G2!b;w`&q ?Yѻ<~EBy NsrR{:`@,jKȸՑfS0ңq;`oA ZZި AaKHs0"`Vab>lz͝s N]πh1=T m'ͱ+aM@5rsK4OptA,@iٰոU,O*A8Z>զY"w&rʏ=~ !/G00(e^4iAM۱]mY&s/0|LYzL^9u|wG8ANP+{Ƶ zد5|=;)4V}pu_>ݞ*?k}S/լk5(G֟\4QIA4,n}ZINjV8}K9T,VY"8N G{o9z- ӵaL9 8{7w2މ~xVT/Du l:p6OXPtClO͜ULJɶwyDBG_V bl6\+uVD*]Fj LaC 6Ǿ/ܴ -lnFuMMݦ/N0@DN~2~ƶIovJ@TxנKW_kRL/P$C 2\^azp Ĉct1=@OϠLskF2(; ѵ S]]l|#K/a)P]$!Xeb =Gd|t`[ RA_IaK}U_ph?sǮQ_[ʭA YB=Fu%fk':Ɩ,NQNnZbΫ=vwᑷξq̹GDYinBƭDT"6aTŢݴ-t]0A{k惲Hr2-'Q@kHs"Wzq 0F]\>A W/f%R$mKU( R4[yW-ե kBn,[22Uҁahr%M#Q'gw<^췺!׀WՃ= [LӼ} % <:D43'[!ZP{s`ԁ. .jnnh~HeN49_5%LQTN4c6٭[{W{T8֧EM 7-`0 Gwݥ-iT*fb)YR#CEБHƫ` m]:U%Gm]G-픍Žʥbwn6OD?PJQ 3GeǨwJVWi;7͜<>N~gf*'7Gi7φ f!B֌>ƪ͵J؇ޔ()1te3L~jmߗNm?ldgGtmвVHz > Փ( D|e-+M#'#4qXBewB0)37=q*Dsj@Y$>8FȰgث4,Y+HxmƧ\ږ }\ 툺\k9C^X?H|Ӭh,.Y$VHo@>elqv8 )(q|[ṯjm1 #Dqz4 $5a _8K.5RaT  UHQp 8(9l7xQ.xU'v IUU.A]9'5էZCj:/Qe'g)o`M ͢/"y/E^i|Ix1M[/dy}m79Ww, P ;z.,.]W͏~|k8N|~1:͒%Co#=WHAIҷTp2"kC6dskIO1 Q8dx«7voݯwbbޤ6(2{rB!yg#JxDzgIvHߚOʀ]{~UaX%@&GY;ȏ=)] xkާ™}W?JiN4,A enXmc@@ ֹ֯CUk>޳3;Uyw/B&$/,zw> Y 3?-kg#Od&dv{.JC^)F~;.7-uoƭa+D =lډ~1mJXU/ Z"͜*v0KAQjd0i{}}09nKmXA $+1\]öSqpQH:<<дZz<20 VJ/KWȍ)LdDH ]!wrA5ƽ )Ry˰tEr ި-XqףNzA@ST $|R_Gzh壁*&,N9) k*HSpnf ݪNJ 5b:,qIm!;4aMg r u hLmcg|nLodC9`u=;SB&Zw2:FܶV^uӷ}H]M?N@(*@)*>l $猫\He"= Wr#*mu)ې?18?rBH{n35O=Kӱ<\HđjDy<&"곪*z ũ%7?`M @&OE*]E6p-*Lgf5z'-<84lC'TF0<íneG= Sſ->ŤF?8imq,-E=2~ TJRhCXbi Ȕ~2ᓰMfJv'̼cyea`,/FN<6R9ݹ߷c."FjJqAxwfmhM yEGʻz0lԑ#2klgzT*YGSǪ޼; @%d r<.4׶c2*{棖сާH͝а-sLQM͡fVi{cS>L(%`o]_o@oBwq A#:F׉ezn@.Kjy@p4 "\ڝA&P8 ~Eg]6cB@ ܹcmL ~+.Ѿ N06ê^{dECIRTgUj^-3O ù &UA&@łKt2h &v-Û[va=V3^6J%Hxg]zY77K>Yv`lS;d$s$u{;X mM<{Ƕ <5Zbʅ'7h;_pa0' :|{qUmÃg84s7ˆ*u_׉&d;]@h܎NfB`8ިפ&gW6`RQߝ2ɰ=O:P6hV34̵ o.Ɓt )Pqp;OYU /{05 fV<8ٽ8d^ޓA,w1%]F/uU/: [)&'%.ٗ=xx^fʧxc;76VU̝ԟ ggfT.*\ NUc@uҡNLYkj5+ƫ 6M<<ll(?43% uC^POy-mp C( }.Y錗 ǠJg^_3XrˠdxJt !"JA)J̗ϳymB*!o;[]r9+1&ѕW]xQACC)*H6 f$wk[- PڗB~aݔKr1qix3u×oǽܾĈ2Q&C*vnysM[){}I7[=[.-#IX!!S&+5V(R$IJtU1ĘUv3uE*P.tMnH:%QaQR%1a9/B(5^ȝ~=w@ɳNJSE_3i&];Tx:&N @ۛkPF3RB,|_Y/M2LQUaҖl={.4*T7.y̙i\0kO=eY+W6`LE)Hc$TrQDd 9Oc.9 9%{,?{<̘Xk)&I5Il w܏8ްeF<jԃ۹A* &&ڎEQeƶ-R9(*ػWr 74\5Ur"b{1DC h hKܑ0pns'P[0 k6btpw{6foCkT&9$=tS,%LRFbWY#RRٽl)eyFhdҚK ɼ2%F zHlđ@r|Egq"wC앣 h< $ A[Z+gnpk\82OBͦM^kG>oo Kʦ;5j"&|7#J+Kq¿:Т~vnbxzM3_I䭳7yoS7`VGgMo$ܴDw&5:&/#YRc,6rz|W: 60\Fd$^0>PKI>ŰU՞$5[DcC Uj{ K.A1SEE(HY5@ß(aϒQ81rd̑lP?~ xo rmrߖR8Fԝ ÅSk70vLkcZӚsJ <e/2.o]XU6Y"ۼbvRxggakRγ|ϕ}(rzf@Ӗ?u7"`_TI{ynw ]j8x[aY5 I%P~)]>Lx|fיc>?2\!5Z`AVZOgOm{|z'?W9ƫmQ|36B.Jr$y92P*ʕRa\*KD Q T&Γ}$)YxW5rt xz\=#އP赃B:q7IV>4!N< k7s>Kԃu'Yyԛ70l(aɱYI 9y)9i ƶo^3׭kezfёbdyQ"~q[L(qa];ȱn`\d"aðۡ7|Ay7s6x=KQ9ǸtFoM4)&-ߝJAgn[5}lk6&4A44nݔ#O@{h-ߠ9GE;yhfsXB؋ KhEӃHR)ˑ %m$/[eˤ0+3QN8'C.N4|c85J71qN$Iҕܩ^STonK- `ou=gAoGxͺ@x}+FJkRC O;wܻw/>>ٳQQQE:[]M?=3k)btrM\]TT8xZˢ~]A(tFacᓧK˭M  im*QJzq[ٟQ&a(h~cѵt*SE=ӏ9s^OH8EÞʾ,>m\ *^wRR3N9-(*1E3qD#Yle|^zL·L|s@&Qڒk4¨ ;}\)oS7Hlv>GÐBX)V`:_ cР:LwdÓW.G5Df&DĖCӺT{~#Ы֬W!ա p/L/ス{q/ğWYղpiR̹k.|2S<0wDCmgf]4qY!J>MUq;u^I9?<3,M.] N?ŧ"#Ȧʫ0(92%b('n F=Zc6*i*P,t1^\5nګEg^K T,(7'%.;I5;+1Z>#0-*njMvLҁt2@ѼSw x6;WL.?;Չi x"& $ܹsɳg>~˫M6gϦ?9A :~6rf0tl™I~)94U`+-,oa%dP"?ɞp-)JY=c[Ab%T E(Q_l|Xa8Gn-rCd;!-E9157C" rfKHś: = 0qCMǸȾ[I?z0vm)8Cͦ'Իy#aőL$SLKzAoH3eCWpu`)Pskط~yuQ1 ;Ehŷ c8DDDlݺuNNNW^0^zmڴٲeK͚5aCQ[^97{S i=I0L3R|e yMY21e9L$oYK޻a;R;$sXYm_3O~<5UNj|4tcdblf_˿ol]a8 ok.dl,K嬲W^ιKLJ&HwY{zӡy)߉{~/}EԱ^Sg j+^@@^lU)RY=/R.{q7WbTi]©^S7fXAi)ܽ{;jss^z]p#7-y:z\]>Ri47Sy7SVn/K\'RK j0#rcȄu-ڗZSV,dX3jmsu3dէ'"f32uXgb ֈrg}nsWU&[lOW |9nG4<4N=x&-] :1Ԓ:&]Qg/'pIoeżNy<݋g$}^Ĵoag]۾}mSǪ7T.>GWʥqu ,j9y9Wccb1 Qo`ךEIRz6TYqF?]kz6kj 9A:Ɩ?cb(+S7{s'L6צZ}ZLf8˰aJP9srrڶm[F@,'$3N j-i%`r@r6b;)/^:":#ɕ.G^g&EGL* 5' e։8dP!reb1_L~Z<F:GM\C*ѡЛ_?k b{tU~s2ZKa'ȼzpv3YU y}(x*S C*6H6DسtxUD0}Ux^C7cd{~_oا7}!uZ_1V*y93|c;~z lp{ k=~o#1wq+KKF}^1g4G׭01}|OrI3 5f_a~꙼ss:q,*  /=NL둇/?<3v|> 2>re{ǎ1f^1$4`o0-s&n5yj~N<)Kī'澀7Pڴ즊sNz70!YסCаo0M'wN?:mϥn~)|p|SEYi8NT {y3j/傂c(bn7 jCgRGz?7-ʣ^As!|l<}tu˛Qʣ#9}$0`f & Y IR K̸&6(VL޸-rऒ thүWW߳]g,.',b0'L=WO _y/e|Zr ci;Mq~mvI7۵b2q5%S]]kriΆGxYW߳z۾-6fSڛ:}DHb2L2{=/02m&!rם{B&qku@򀚠r RJ*rgT*qtnX k:_`hů8tv^4n:&_O|s|7C'˰&V#XݥX@QV L $P e!IR*a ]kdTWEMKVđZ i(H&Gȫ >Wm %Y[,⬤fJیH J^$$##Bs*8%飦og㲯$ >V)XU&QY1oӊy,”6WLD޵Q^puTc8=d9u, n6>нwlmQwPktg=VS n` Vo@MP,g J(A2y\Q$iF5N0Gz?/3ܚ[XPE>o5qrXI|Cӻq=9.5Xvҵa+[Ww,1}$Y |܆\咣ei壁~UU:7_O@#?ηg s_Uʁx4?K0bMD '9Ym0d ך X߳0 iՃAwB,봛ʱK;l.qzS/frtA7tU!7dH~ = Z.#hr.*ٺ'sI[預I.nk5CkgSߦmfuLV>Ukؖ9Oi2puQ2pMoK? 2bܸqf+Vu ־L*2<" " L4O6u6 Tk dmKYm@{!m46_ Jlv9Y{z`xlj&;;9.hh)}p۠mw8=# 3 eǏ#.k<^N*&c4I&r&l>AW4#!/3മs-|V*t{lހVwW[1F6{]SkTd߄/ÎVo;Lkc#\s n䓣ggÉ `_u+ͧMęd J2M^ ќٴb֎#zEUg!5 kkkf7~grzrD)6W^pm@ *$ O"/L*'$<[D?0?>?a_D(1ýk70.ڞ1) Я(z\<--FJM3F4v|>`0AJaFNU$¬q\5QBp-Ko}'.ʉ;;πMpZЌ_nZՠC:BG,D*A,ߒe55иv˞.o}fCfjsl3$ӁatF| c`orw[H(SiZ lw$&ryu9 QדLi ^н۝[=1x䒆%"qN(;Ԓ1c8˖RQnzl$pR9zmhs<=,?As.R19#Dp*Px@Eh>Ǽ&a_w)ȤɀY /ܻ33DڭA~#^q hN{B.d4tݽ: i=q ˱=*Qo!dJart$گXZo4O+>JQB.NMq5Qz}(/:šk @ Kϧ쑗RczLh6b4*5˱׍ +)Am#utDi391G AnٻYա >|wLK2+k3.阽ZڑGG0[rvtSfJjy:`UA@%ivusk;8/=~N,͔\^*Dd<&c`,S bxv?Ӵtݴޝ_A <<%#뿞}-$Vx+nVTfBeN#G2v<`_n"\A4xe:?. lݝR(b+ygwygݝ}vww7**H7l7",>8ľ3;+ r[JlCn!z΋1ڣӴue{vӸo% ƮA1M#(%ۡ~=spV}6#[kf~yާ~ObB՛q>cO^6 lP-'dn&d% &AlB1f#l./IBؘ︾RSdLWFbZ}I886jƭ`ΖeG B(Zsfp#{M9l,}_B? JI2 AP;K;OXh=| ;ӻ8d8FrsmܴĒt gkĈS:[~(2hQqB@e(-'s%QIng\oґZP+/aרž(Y:_x' EPC ,Pc,ǝKmiZ:( ߂},F8y =z]!>5OHgՄ*$slh4ާG5YqHZ ]Qgl.Hd'}>ڏ\S'7 r6h ) @ļlw$GG96nҼ DMu}K.k3Bt0!uGr$v 0zL`Z_cu] ^lhC:3}+NfĦk{'/|ROYHi QnA| SGV ڂ,ػƄ%[@@gښ.gu3՗] fں̍ 4D 59C7۾Ak#`p~myԓI;xeT[jHQKH }]$[C@6@i95& U gvi;nٳ35ٷ5DÞr3!gjP| 3iuvQMVN9^Ī3;p%E9>P /6Z*k4;ԑ2g,ƣ~ヰ sF'4SCg]4[.st{nym?ޏI 2}-ǖ&=Kv\M}nvP5+N/oa?; m9l3 uz.j]khFyp 1Bx bhպ:3I\gqjJ@/! sFEpԏsfs~%O// r:FKxq[R`#4Jx?49hrJ@ӛ V@ Zy7 az$!ʛP7ڏW/3aQm@cj5P]AX Gr=Tr0*eƆ oz1icAd"Hy*,Ԍ% u`J'BmS뺾lNomuoiu1Qzd;;%BjhЭ10~Vd,A(@ Pi kj=R\LHi]lдN֡( C38c8זgn~"^zҕu:n|Wpz":Աqk/@Y3q )A(@ aU9޻w :ҭէ , 2Pp!@#)lSK<>sĆ><2 +ͩIEr,Pʯ6+@ ZLޤ#sOc N¥a PQcﳩ;2ʺiz:7l7:kj?C !hکosbC5h ab2SέxP< ԥK@:K%XEQS:L\EckkgSԘ0{wvL>Ԟ}VfsP =r@INcwdQbef6{;ۮ+9tTv;n̩IQv&i?m4T/ak[]( A + yt Qd+zJ.J<$m|.+: V$JN:"5ab/2{ܦEǯc k"!R ƾ³/W95%Zo(K;&If|3D(qh+8d+@֎7(oe9x=-VtԡG8 r^ܳ #ʔQ QlL!gSHz$ ?9Q#⠊֫8AB$ 0(X6h''/YmS%~|$ʺ@pc(^#ػ~(H ~l+œxuVMLHCt6׳}F=xT [ ĽybW#<~}bgq|z2\7ed=`;[eRE# "mzQ ԏd;6aʧwu! zt ȶ 'BtL,یYL6}>~||3w@ٟ9#&nF6u m ,jLUbJ.%si.OW hdhD"Wa|Lه8QW_ao)}b-[NT0?{(2WCY2xrָ^x/YWYou IQp1>&R=RBE[̲<ʙ PxsN*6zqn;91ߜI4[vr3PIE&dϴгyvk*UPT QrΫ; o~ ka1eM̟Tš,! xUG^X3lR-Tߛ$ {F'Yۮ_Pp 6Mȣ%gbT@ ttS6S֓1%3h;i$%M]Dg8ڍgTڷjaQduDq|4j!5C@2U^$nȠ=b 2,f\2WL~y!MjLx&TmAD% d@.*z4eT?9L<,O6Tx,yZ2%?{nz86jK3!\59' wE?@4@bՍ&2C6~' ƆFńy<3!:+1&7-Qq83'{!JW;IptZLVƩb}|ǜ$Ⱦ3 )fp"XY̜oc݊OUG!S|6T\~{mR>@ ](x4L$qMœ=/uՓy:ڱ~3Ws**6!B=@N9=xΦ\ޫ(JZevșJ:EE ٹ%'^CjDy ן<&$ݝS;ǵIbנElC*acSg+7}K;iTR0QIǣmF=7lSx U-d8eG+]`)rM؛a_ɮƓ){Fp 0mГ[S81e[2{D(9W)J ldȑdH ̿Y%ajGE9XTnK!AHY`XsEOejŦ}žЫUL2T,%I_%~MIgf|J͜;ul5rU  wS2ʯU r6*Pitv[<9.G7S.?1tiKmZ:x-'ե^ǁ~ԻH&! )FdB(4m\lsOLJh}</5|_B|SNUR's6T$N!# ]gq.0lUBшTL] )[=oAK]U[³ |$2imQ;W\qt&>2~`=h|^t+oeՓ%>!Hն5=GSjP;Qdqkd(3qؤ:!ޗlIQUwY_#^9z7,;}q*JRdT9b:k9BroD6~mD窌㜛ttԸ]ާ%#譺b l\1N8%(Gbg$$*%.M[+vdI|xz$){^cve$eeeQn TznjB~2v q ͊=S@"%EN|CC.O􎟙Zl ong`h```iOv[Y#;La/mzj0_]@5Fi򄇭o 5 ňu1ە\y+G}];G8mF/aabTJ وNB^ނS}1>Փk+nV+ [%gç#|ILdS[+-f&#T[K'q,zj1̈_֜t.x.eTd&PeDy '*IR|HoaĝY?FWGX6TL/-$JR \1}ghUn4E]8vph\*-C&+6 &Vz Y_W(=='Cs^%ˤSLESLhڙxCڝxwI6{ s2"T$rI/AvC g9lmfdS`̔O.DGNg)XonKvR[rtM8nC3#sДc`11$eF۵cFmih M+-6"7-r6@E%/?uAdG\$Hʟ8~a)ϻL/Ie%i\߼EVeIK_l8x?xȎ$Dh y'Z2s`fi7U'rJI EW!EϨ~5N ǩJ-:g4>O`l=3 NTEfm$:Qe췒xR ]d,D0" Ok%oG`&+3E"l[*z4s63r5v,B!XHcfaȦpOv9rSm g8,_N)I937-OI:kbcbclKM,luMLkg]} 'S`{랰AnH^݆fH=mٺ@(N( [YK ˮh$V%3h0c"#YY烈oM_A&AGl(Ҙ#7 AA,88Wt*c:c{2 8T:~lwc[R[d! 7[vAԆO\=S@-9$p¥Ar~FJnZBNjBnj|nZbB؋/ YIR#)ihhhldlljn3aQ=$KQiv=*vi*|%/0u NpJwsˬ/ޭ->z3zQ`EbhTJ"Ro$匼dR3(LsLXP+A0XZR'/_""b#;kjW0ZwKFu}61STػ]Giۈ&j5bPP:y&@(@M dl2=2q%h6BQT̆l|ږ3Xf/~uPgrYXtǾa:M;433b o>Ь/`s6L'EBPQYOTCi&‡ւ VdSb"A{_}tx]VbW!]GT}82>=غ|P)#3 d~f[M< @@~2Ҽ tgBWW7[.1"l78Qt6WqR_~?2]cEhi P"1Rk{(UA!@ĿF-]p$W_NA9,M~y4pkfcl~_FXy'l><;=5&L&S )P=JPPkF[ Om>墶 @ć='VZAl7^C-\4~1lE=r 8tP%@AԀgUvGweԳqlo]?(4zɯfٙ0bT1`ptb cKb0$=,(pIo΋(9VjEGc-Y^n7 QSaP YŦԡMng_X) mm&yEvƄ\<$pjAfG𔨷iA(9bܥ'xYd$/۞'FP> 9)_tM!i~ۧeCLR/ &\:%`5^˞AԦ!j&=lNM͠Ja.͢ hRL{x/=#lPFό](MGA( r6LGoVkL"2cTHRJ (It'EM) >f1g{-RL$&Xa(b#)u}K}pYaJYdaqk(jb@XP s0f:a#HMى=l(E 4n3*l@qzb-qJ9din7O P>7S): ۑ̄h[ PNkl$9Bz|zb謀)hS`/&$l{(yJk^Ć>kK]?̏M^n@F:iBpҫU#g\. @Lr6~too 9vToiOb!4[lmנ%B0z cu#wD.EB@6p1E]S= gj E+w>L^r\KPlb  7l4oYPƎcG]m"^l gjLfw[1!lo!b@EVSO ʧ|s@MFd%Xy4f@4@m9P{>=zwrw&`* bTdNSc BSZ!s:vnBj &(QfbAnOM|L(JL} 1?хP>JPKy9f!с @MA4sErŅw*%+1&5&ܺ/Dr9x@ _Dsn֫9DCcHE8,@A4MыslH^up(SGȧ7Rc g@PDć@v"^ <BIp9@4&C!eFc;7rrA\ P?&u@(@9sμƈ89#vU` ND׺"sܥU`lBSc!(C(qwN}}%27+S& T&CDռ^k Pi-&EA F @3 ͂W;!O=uϣ-e}q]̣aQ;NPPDL\P ϻO[*ljHXI~}(Fk7u5-]x: Pf^au PSP<hS+ t{\ph9},{nNt~Xiq̹f1a2Jg@@(L,$R!B±$l5b9$?kMƵC _?~{b҇0~NJshXm?lVM73fT^v$%R8fA3v<[Q9ގ!CLe69\j(B$^]VaDlHLl׳\l PS Ɵw xE>u]_d[ 9&̘h\}yn3~-G;2W^-o2H/aF[ddbTM1C ySsz>WuRQ{H(׎HikUh$* Ad MseM?K%11q7ZC(Td0ĈPXD9 =?MXd:~|P ؽC^:ieϘU!mM݂/8Jv{AǼQо;&^xv>2!N\u7j`['EL~l*V-#8.oh"s6xDhOgq % g(i2 T i/."?-gCӑw#r3Rdbpmvwr y>ū] Wo!DV֞V%Ԟgq'A4Z@)m}F KQo"!祾J6Lޫov|R_qo%⿫d /yhSdţ⌐^X_unIF~MBr6PT[I0*mcfPC=Fm(tzNYP]_m\'>A n8.XBaҥKTj\.L%jf|yG6'OQDujȩU;ђf\?vcg. vbDT6¾2QtQ 0R<ړMB8q$&{SIλYj}z)'no>#傗g΅閲+ So?w=¾ Na߰l1:C2 /5۷.e0?WHӷi61*Er]ĈRML] wW1%?캫V1hHo)wU}MYΔy9)_mjwJ[3o;bp串pɶե}7+B)&W?ٝzsF/G(?rڧ[XdIaHc(FPTR-'vW?ă*JT-Q!,>]ijgwF։(~sAHs䪕䧇޹!u8Aj ĺzݓR^r@jЧ 6{vp*e `=m{8A͹}da}t?mvA,Yk˭gUA1a&ENYdbb9n.KIrӃRFF-~rdCaE^ll&?α&tb=eœWdyC oT%캫ºTАrR^eL 9Puojl"Idva;O67W˄L,%=kcl]w 6%GR4sˈ[0LMLWIzԳ}$42B(j!K̪s8\ѷ՚l(r-Ud#qK2"'Ӟ M<⛺T/Ӫ^NVel r6@ z1;ߡ!;BWQ#x7A^dFig›c2( uPܛ'el,ݞ0H\ ewHׯR.K7aRo'_Tj-<9:ˆ{T+*KOn_@9֮R tF6U[e){ڝ%Ϛa4f7*o)9=h_LXiewH{Lݝ|t0dW_uW+4ⷔWz^FₑQnZbvg~38ڌ|"!I$E%(LmMR e/~V x#C '@,{=~`e]+ ̕?F3Xbtˇ%p9=h*DqAɁTmChvi}۲ ac- >jEU.|OG^~1foA}UHw񼟵QEy\_1FW8bP&p8ɢ|5l7Cn:/Jmyj><'~QLPňņnQr_)߭G tw-pvS,_,9oPO@6Qv @=4&ɦ2,[% S1߉b:COʥ#i _ɰ!h*D\5tA1g&^Aj(=OiƉ[6*jz^%t+c0*˴*'2)V"`Aj5;9bП>?5=51Zjb|}5d:+6C_?ק L۽=7:O6tSsx,+9O&OQq!c1+)\])I"B^VH&.MF\ғR۬C!)"p'ږX1#ZK絒1-(.BtWC8o&UYg#% =0K4:f)'*#7qn.];6Dd_ǓEr0mkڻtTum]̈ryi'l=+3"~]^BʼnPю&\2W雍nc[!8CIJ.%foǜ\.M{&)/ j7~m]'a琂nRVlR>_oRY`3t=nWTqtsl-VlDOV-6Q'b4SۖCۙ U,!!ʯn sSeZN^ŋl}_[j3Trwr*zB ,R ?k;_q >\!o*\4o ^ULz9YPYh# Eq_*4-r Ys̿/=.LI)q=DnDC|cpJUor2 ̌&QVc1\|w;)-\fեXg.!cЦc-;,`H\e͆DD#>$;.zH 9ƞM!L>fu|. +ɒݩhv#~p1d=wQZܚE%QdOIRY<λ(gZGc"ybUn{s9Ûl3o>VF<_љnu,^Q~ϯ\?nh:1g{bmflNѰ#wo"+hqȪ.E_`=mg㠼\hO%|LyGR ɫ%Ѹm! \P`owVg®/?٠ ʎ{3uͶ6ISvCcyR,{Uu5ʮ8Rnbto؊bR? F3ŁP**Hf򞧌^.tiF@MPVIf6~W( Rr&jʔiU-'*E-zvPlK&OzBgj(_1Rp`'7ND q{`~~A"zu62d!٘)! Sypʙ2Y47A'Tܱc4QeX8r~r%]dvgbt8hTӐfq5mL4KͨCI`)_3? {%Fosԕݞwmcs}y4#n~Q|0q^Xs3nv?Ģ;2S elkGμmf{dΦ"N=<#.LN׵os^ymzt|vFculT|8oXѧ~*,| f,}>x-~s)1*\C\Kw},YUfmn451O2H2kbѣh9քxbS"xrqF&MڏT00gӄ3D_+ 29kYϱݘݺQ1`JDfȠ~׺SmjZV\VvidP I}lB440'3΅P*,H=#b߽dt=+z<ϲnSO9$R+4/~V x#C '@,{=~`Og|V]2dUZvZwaZۘfH!Uy…b7̕cK9!P\]ʛ~OO^FceOɤW3*T֥|J03mDɚXS&hܔ*=0amEp{';#*KsdFnu9N06*JslgSMdsaWߒ [N唲I3sc@-U R꒖EdS+eWͤZuY4A6 p趐lJ~2wWvuWjxՃVqp*e'8l}c W؈~ @-tetTm l4GJg@(_ e~ ]6 ;[f0{ Zy% ̲X)y(5L%*+9n2^ _qd}{ E#B~Ň>C~)sl,ٞL*Z57/7o6_Y57Siw2P,M,՜ecM*ȔUYsqO }m+q}b&x%~}_kshsOKpq跳t󡳹!8.0 PMKIĦ,\q,!"r6Bɑo^e\Qq &Gf<_^ދ0WK$\h@0 P2Y؝Wo)rㆈ GlB[`!'|sҗ~f:B!#>|37ĥ$Q\`\JG]\us|-aWCsPQX=ㅗֱo^i$Y+u#bGڢXPOT5ֈkg wt稏v'Y9/kN-ot:}Ch̔~N¶f^*炏E^X܀Fx-ߴ覝VqcC8cJ_ȶ3ٶKCX.@B*Fcr f LJ\M efcgiݸGn4Ƃ T ˳Q.Pڈ5 = 1g"+`Z4 8ƴE!~]ύ"i8bMxфm'[) ~g͕.F|#C uni&[9C[g=]l~oTVr6 y|^V e/T"ֆέE|e: @!:/_o8L%U{iB29pCc~I CW ?n8tիuOc W'aGΜMjZUuv:#>/gcxƦ O`P<;G kDl3Ph̬0@B2lZd\eUU50NN%9%)s"#.v:]u*tKZjfCT|YLqtԑ47DTI(Ұ.mDtGq; ;̖$pg(uO@ձ A,Mړ3d" XX%~MV5$BI 2iLH Ff%hO|-cs I~74jM E䨷߳ ,2! gg`!c#ϗ;gI`IUJل0[;W+}㗘(ͅT Ah;F}G䠆ú5(۰ԏLk廲ny hS0ǵsGJaݲՈy+7C+G8nȸ ,;NZ0 p&9(OYՓߟWyQ:[kהoǐ?so[PG ZXlЬ^+TO`SAzg Xs2лȖ@4ėY;[@4ม1(T:1 lP1'!G> 9EEOns L9Q>]Pdv ȼ] | SGB4oFQxQ'h b.-.# ސm3z}(4sӀĆ>kBODމ *Q CElE@Sp&A4@I%jX:v ZƆ>HʼhȶE}uwr6\'L>oKv dm h\=h 4'ݶzkWm{@4GD qĆ>r6ć='V l_ٰƽC4 /=l @9޾;&&"8ɵ%炜 @  Pؿ9|9r6UֺsϷ2gcְpO&WϵE>=v=Zrȶ5h A-9!(4yq/_ = bʇ0<;Rl˯c[Sqzf62iB 1SȻȈ^^ 9~Gf1=rɶ ԅ 4MiL6lIp>>x~eu/LL 2H7MHG8:\[>E߾C4֊Lญ_ɏ~䗹cu V0i&wm#3/=<\}{"KTN775e_:d%7u쿓|^OŪ9+~ an~nRml}cvIBu, @H<$ V?!ڬD/ÖM"oggYo ujd]Ҥrz.\2mC7:յ Wr;Wx"E6"FVx8'pJ./֟ ؂Oд`x(Y)_gȫ7r˲c`A[z10xo7t]M-`͝fc7OU_LG6<)L~ m_0 _fc /F"+  ?ĢW;y/w v)@CzLڋl)o)r!H~F&I*oկmŶ$ك-炜 *~ m(J4T0m*F}I0 hd%l 3v- l2? )0R(jba\JQ?^ά(甐fCh0AN٦Phc]3z_gE8C@ٮP0L֣ݵezC^/:bB0 eh>]~vo\{Mz[Jm5dbk]tw*v'bwbN;"Mtw.,EDDP}gggޙ]f9gDQdtn㷡Mz(4u~_t|;;+hJu_~1kWeV y~lqk[¤!@Cur6L_%NG(X4nN+zMPo%:mp RE\o[]&Uaa*]å+1a ˰pl?r6,?[J)k556{4gcW ע2Rb^UOhGg+Mn`@q$=6A< 3,R-@uW1ѓ. 1*Ϻ{ЗK ;nAl3}Te߶%z줳8(谘6u*~ª]Ck5\ζ~{lmhc%BGa)"ـa;JE-~#\X laѰׅ>sg%*]#ѾG^w2ŵDyOۂ:>mK#ϊ|ߨU}D@TFCRahL t}UOk~1)-@LRR04j½Fh9Jgδ*PuGmkhL!;40CcRseO m>UT{I)o'KwT5`mV7Y>l@AR݇F{&%"yxޛZCv8lgH,RΪ8c}S]~sZtfo+L~aQu_:6`jZrVW(C% :kڳFAǏWW"F^_R甈0!;֦0#yx~#^&#L+Y)2T7)O v{v={&!M{y(뒺/l-U R0${DY7ǜ0춢*4>!v5^{u*:Fȫk:u,tzݣ} am޾jt :G%/_ 5^ lۡOWZ\R)Q!Z;0{>g}?fPJg  9rjJ]XSYw{8ʏN$_+`c^#D6Ab(JppB:m{{8AN/9ѡT:W\Fg  @EqYYn'NTJ4y2A:[2?N,9KDbϾBgt${CEV**ZxW4P[UXsDyD(zEq[j#ٰ{*ˑ1=r8W  bCoUzNOTBת*L'=UPcq+W,O^FJ\-݆Uuo\yz[qcO-ÕO)OЏW"qI$rCO^ٓY`E_(6E(@.@ gPQͦ _vC6h8Ç)RRN 4Z~cgżY(;p"9!jGM-A\۷RRQ vFqAbHfMi_ڄr;V>f~N|ȳ+l&<Օ^Ȇ ՆU? e0lHeEOq|ޝY)2xto[c_FB?߮Wϡx0)hs(j_V?w/H$F,i/u|WZͻ pDz M- iA͚sku{'r2k~YJJZـI/%Dg6 9Rv<0pc[œz9к&e&z=*>t:2G <[},MM+mXWFeVV!-Vnآ9}^2jȆ}G9 :jװ6?>0p˸w)ʽv,ɸ~AHytAsЇ}d-z=uqsjʼw.,}rZ=l˲^G<̇z;UM ?&&KZ5ơ$+9n|m*Sk>ox/;9?)ONmW6t=rL&LmsT2c(񯱖k:b%^n_f85:9)&u]xdd+*(ԵP)((l*J^\]|\0񛯎[B48ɠ*yrgBЄlDzmwuAu<6:2a@,=Eru#6ȩ3FXfdyCY1W1aY|Rdg`3|%WUmŧ5m18=({oa y苳=@$_/݈-T|cBE2.r oYOQ]*YA<)>WZyie  +ُq-s?l" Jm*Skd*ܞƽ" Onlaq*]~[;ҩ][tvKk<|L&;{N:J#,P)JZ-  yvle@q gPi.uq'RS?Cj],#CsJ{ieQ"Pr3\y[(gdN%Ubиڑ=Vʆ_|e ݜD{!S՚.oZ8wkݎm9fIW6 m.}zn}yɫ 8J?UmY4h[:\-ao# ~^!-ͺm@BX?ԡi-@q g "^%SIEa+! P8jZML||j[]N^ȇ +GevϢP襕c3ٽk厵5Tҧw76}$ѦY?!,PE?!S( ?Ƞʚ@@>E[Fc0" PZߓ3;_^~o؆İΞ lPn ^0@(j}A%uRg%Ŭf0qC?FA^n:`zgpXvJ|~Vhf /C(r6P~RBߔ6_xl (G'<9@@Fˈun 2xg_\1zuG2ܰNS֗mg%d ű^+8jZXUSXۜ& 4džvzA~.ڷwnw'ԱG(@.3UC(r6r(CA^M.ŇߣONmoI 5Ynsm6W3@VruV844eX,zrvg8^A Y;tܱfݍRG.ٚG'>-->>]`s6 Q/"i1eL>^U[ ]]l@N}(@ g ߿@=(*n߃Uk9bK}!/mؤ^j2K*چמ#ӻedD$y{&C64JgT}̥oO(BCҒ[V-6""f F*$d`%6Uf͋Υ/ϣHd#`$$R)"2,eh+˿i6Iv{kڛ͔zM%.f%E?)2žZcR_L ~xO|"!ʺ]y?P$>gYiDVQG(r6r]uuzZȁߩըEOmٿs"[Eyڴh:` z%G[y9w'®NߢalU9>$8]e.ɧe:2mI3B]?˳IEۙiq^ iΉJJ%/CV@Zޝ*xo!)S녲sH >m ]}hc8H=hZZ?n ٥.0'5!m@T_dwOEK*:Fwm:`WdT7aI9W(lMT_F|eUM~ ysK]4F@fILi](țWeCsӓ%um~'b{|r+:l`"?;j/=7]f*דSel m5=S Q38eL8QĻ_KMyy0qΨo(ф$'*W5)7[5]z*:Wy"r.ByTbۋE„РWѯEzQE‚A6_ &! 'DRRE(r6 WZpѵ%|*4L%iBeoa' qK—+T:U U-Ǹ^8e^_Dj~>sӓ{ү3,NIBҘO I{ H_)>gQEU4o4q!iujE[y׌>g'B"vιqlzי[:BX~>\!ALJH(K& b1qFDj*kS̚S݂Cg6 ۻ1B(@j%(77^'=unWgfaKcvkoP")^_ٔGǦQHoK?_D(gw:;<:Rl0(_bjT[ cǎVJJ^ML,y+^:N&ӓ#444|>_]]]$eee"455knnrkW9'%*d0'&;;Uj8鮆r6P67*/.zMqb*"{=I ZxʹRAd:T:Dԇu(|jIXr "(g!ai}iÀgaF ݙA"(#B~La>S[{Yi3BĈM}=c]܌6o;۫im>?SDwfxHM<\ɢz. ϚNt8(*?vwh/47G` >noߎ.}---B54C-lj39?j߫>3D ίf|vc{g c+IƱǧ'&I 1l6huL6dGB^^.#p ;YhـB}$I HWN_VÙIR_/#zgߍ#J^s<q.lWi%{aN}?z)(DIX?E177WVVۯV3@ wJ:·19e]>-mSAJsg=#]f]޽bIA׏_pxJPkv7 ($-4Yvy_[r /D!:qL`[cW!Jme%&"hgln\Di^|Ұ]An];A<35LI$9"2;_k׎`(ryǞapT7P}4u֫'׷ʓ on 7C.v@ eggk B]'Zͺ" >wPoPbyм&M֢nydr.ޙnV2uKKI"ٽ51/m4Ͷ2/+Rin'MC8.ΕU[ϾY1#O L4'\ːЀƂFDXAXS+G,i6%L1!?;}˵w+[R"I2`{sRjTS۴Llڎ[(هzyP\78cne(lu㛈tR4& o$\Ʊ\xŸ|D3heW[))|d^xs]U:^bm#~dDW=OVF<2%.== ='YvM\[;={+o,-Fڙ&zwj̭)Q!>5Mw%H{3L׌K T5 TڸM>9`Э7-/?7˦Y*h|KHA $66_{'@K<ֽ ԭ%MFԠ9O {ots⠴ң{?ISVZgeqm]# ɩ7 xzVlf\1z,0wҴT6:u @* bH/lZPrԿ#P,͝2'?9LiR.dsR~ɠ(ih:vXPGo]،#w5lt9 fѡC:?/XmMO~xt=Fo?~%PCK;A /''-QM4,9Y~RR;b_;dMw(To7Y3ۆI thRǜD<ࠉRY1D)2$QOG4t*-cߕ''31:!앎E5}SD"q:z^E&mf>&0XSn{X'iBLjİ^2S1gBAL2Lb@P)yFKGu]ƸCOpq@'mͦY^JdI5vX!Y8I`+Up=b 5 Ýv6lm짜ƻk佣E8cadDLn6M;!{|-kٶoi*pԌftf #%Qń {fOsv6>(u-"PpԴbKI'/Ե;nKYꃕ"1%^=L7fLiq! GF՚HX&E7i>YA(L~̄+&~L&{x p{H{Ezm83.EltnzIQMBmZ6i@̈ r,u/]T)՜ )Q!&u<8-?7k $zwHXPAlr6?zuƽ%ɛۧn^FPP'M}8\Wc71>s^FwAchP q/HL5ʨeb3'wy =dS '8#@io' 4t -*)\ȡȷsdO WHo(zZO=CB_6ڥS/E{xxm@Ra'kB8jf.@Egqf^ַ΁q:]moĤ(m_7=6m~#q-?$hr_M<2#/o96[ !/U;" ^GˏIlTqMOS5FxwΊEB} P5Bȳ'whW#cyFQsSDV*3}EM0_OshܕW#bvB/QL&uoKn_Fv3JѹI->,x{>ǙR| "Y>2oA!)r^\ʻJLą1O1D_5gA !ߣҢ~X92ȯ^a1oK 4miP8j;cX F9dͭ/Z9;?3o\-gB*#.J Phy:} !#j'pF|?zwl6nU))o@!ć$Is6Y*]YUMТAFm:bSjr6(]~CwͻB\42?V{7hd3{_Oa޻vJ<\xϧ~Uiޗ\Bn6f+9 #Ҹmgq ~ns&1߷KQ)?֩dG)炗sqqV w.fR)R6#QJXX{sRN~nOmE}ͤ^S릝omVl1+ݮ1 7zomn+>d21Mfɷ Y\%2,;s^J:i雉Gᮋ8<7MVpmuڥPZS;DA܇g8)HO^?}.yBW-Vӽ(JCnP o8[I1a󀧻<ߢC>RbD*_QGB!}#w8wJLR///R0/JZ_6D֎;W=ջ ;9)oה O|ijt(9>YL:oo9:d~&u\Y8+}zstZ7 #K$lSG L[K(tzv1F5܏ S(N튟8N޹Kr2e#)- z6 4:/{wX,@aG4KǢBePЩߴ-^cl^ \ }6"AMsfwO;G"vW^\߼o넴lfFZ1'v9eHJ_ܵkӇҥB:,<5G@mMgϞ5kӧwލ+.um2yUB*Jr}zdnn*W䂗8|,㧠p2ʻ>EvVe`2掭GF;1o2>]:U\񍊶!cդì1[=Vפ^SH;8 GMk?ꌝSiX$FnBs &Gs"^F|pvOߩ`*Y;׵gUO®_ǽu(ۡa4P!/YÖ@hVnykY"FA'&&fS1֞}-&q~i&jmcim~MH]7HlU4o{=S:_(ihj ׵)(RJX.xg,ЕL'zH)ްDBkqu ܕkkJؚxXS ?7ó"aAuΣ_?"Jz.ʃ\R6w'mp}Zr<Ĥ dCt&{TF=ӕLO $XǮ``*j֕x K|?I JSpNjBa0 ,4 -4, -Mu woE([˃DΞy!} ґ5"ݏ+[(>#m nttmNו#u-K6< |dv888ӳDgH5kD^ygX}XA_WV9#mኯɤ8h;=4evXs )- ~j)UI2I+AYpyJIv=gH3Q4t%K]@6uyz+}1JNv(M+B;w~xe>_b RuN'7=ϲjT[dqzoMOY{̬h9,ڍGղcc>ņw.#!2#>BOKnUS3js U Z5%c( ?4qhP-;Z G˳jujZG]R+祜$9+iқ{jUkڥCd¾[ d***|>_YYt:I! Z`g(...}ի^Z5ـqiƋn/ک\S$%Ɨ?Ď_YKxb⟜r.x9;'T$ˇ.f4?_CDI7'KDcjeaΦ>r6 ڎ[fӼQ͗zymV1 ?Ҡ۰z#P_ V]EW03#58ר"͸w-g}XQVrlvr񔟗7*뛩jfJش:xvQ6>9 5+?bOӬNb sˮY"[s")woJ>wR(]%9crr촴O>xݻw\.700P]]=,,nݺ_QF_ 55ݻk׎bU &+v+L%״.h+H)A őAl%[GD䞱"߼Cok3zqCL*/'I rv!P^ҳL[ 1T^rt%ʼnBy~B?+)FL {oF|DfBTFB$RT:CZVVǢyms;b$C"1o$5wlnhh" ~3#X\5DJvFwwJrr[ϝ^z{C82oHw[#͂'Oo(}ϦvDWs¹^R#1, cw~C}BOMj`5A1ܺO4ybŊ%K|U===zjՊJv8dY}~MXa<[gv'Ŏ z/*X9G(@AP ǃYws׏?xW[g?)g1XT[jW9 y_&3ħ\ %(ḡI"^rz{bkM xB;4ݓ8B(@4<ˡRCIť| O˴cQT[!鹉ƮZ_5JSD j{2"_? 8+1XgD5}3kN-A2C,vE0>&J /c jZ.rᏦivȞCʨlXYUm˗/WEF@ﭚ>P8\-n&:̢AV= ,{x QBՔD4iޞfM^2V/b NI=Ik'6.*cXʪ6>qo8&<(* " r6_(܎=r68|Qҳv@4@1uι䝃.msFc_S~ɛUkm O) ]Uvj0QkB5}3Gј丠-B<4ۡK Q6Dh0x.OCB&I:$D(&oKaH$θ'}jKraXȠ:bdǨ]Xueɗ%VZL[!VW۠C49X$dh G *5:4=kڍ Pkw@a䊒5!cdMsy]Diݴ3V49MLݿ*elT "}Ẍ́4X^1*Qj`+[}&c[ys8-'H16f р,DcfFf7ײ^5N+E35@b %*Ʃk:ϕ't@pA/=,eՆ݆# ^Dk6@4r6 wGc?[0c sd.ѬT>Qo6m*31ġPyg+ka~ ꕿX$4P@J Q)t13", -ONm?2D"<}K9i}ο{S=XTYA \r?#~S3տ};OynDHpY@SRZ4WbhJP E%Q ZhSH5H*#ߋEmk[-|fakUw^_*= AD_BY$@e86)2'%QGp.)F$s a @LۈI(|wPr6 (4V<eCmg7NbnTYRYh (ԁ/r2q]FڥJg 2J !J-ZqJϔJ)ui+33#yI|5s!G '/y_>qP(oJqbؖ1\qBžWrR≒O&]!YfmxjP)t6hə=Fط=qrDCA(P)jy yRV$9ȱwe6 P7y)25:Vs۵sSDKUMJAze*?Y+ˤeywxBit~< .hȽQ0uD4@Agu_eODH7ymCDC^u(P쫱q,nƴl~s 2"VQ7ՐLFEke4JS$bnL1rAX#u;=qJd0!LΞ P~ Izo48333iVGT l䙪1QfGY; r)%287=پ':3.~IK<<ӲV\s![o~9V^fZ\sP~i&='AL;DLc۹):LS19)?<=q%_=r!#>4(b?)TZ> dk tD 9ym^_ ^^;*@YCwB뻛0T>c٤bF*67#aZ5Z~ L~;ST{ױʝeQC(@q<9l :hMT`iَcK~#41|$_J nno#ezC'-۬d 4% b,m5{f>C߿}_'eӕ5kw7jF_W b瑳_d5 ]=}.]ڌA[/tF咙Js3} yt(Q62.YbɭtEML8yBU8L&UOQxR'%; P迸F#,VBa*L9pv5 ! $bd Q:DY~4VN~u 3mz̰-6)7ww5PaƄ^>f\&LJ$ߝ>C_:`7&x?KMd8:=w/5sKLe7m6Q-?CIB2g̒-64QF}j&Z>ykY"FA IHH]hGf) <3w&ʨW\ z'#>ֵ;GM ,.}'f?I˴Vgt-dͤ7h&ÖUOHtr TdRJ iy: tXU]CE!rށeDz"߱ yg@9H {wbF5XzQH$ifA_ e_W~ƒ}Gwy^ B̶^Bo/3btUns 6lXiy3shk*P}}^zťfqg,aFS"߉yvQ61t:u w1D"qq:C;0H?lPG|X1aY5aL^R|c*괳ON%J5]vrܳULth(ٳd)E 45HD7yDOd{z#I@{-U:A֥VK9I"Is6WVSl߾ϯ<5bbb9pӭ;D rYl6QV|Yw*chh1k,]]ݚFs-{ƾ|9[xB3>G}Emqc#{ ֭Z[GݳVju[[G[*Dld;n&Rp~b̽%O]=`jR&GMtܭΐ _M&zdXW)w:q/<嵳HlРA=uVJ80p2GMb^L||.b0-Y'(W^AOb&nڼ{Jw2Ojۍ6YnJ\{4qj8`Pz}1Go5oq׷EC5ߧW0 cx+J~mf`&Vز[Lz7w3>{; Y՜ˬ] ՄнZcEsu#OdwgATtN66Ƥ,)nҲ#WYqvM?w\\M!|vɫ8~E3q.첷V'HlذaqP9#8=>+W^0 $+ D.#{?f/g M[vבD簘{V so%\sY_], 1*2 uzeّ>n&icQl3ڏj]UH!P|yP?UyCXNoĐMsӢ74'axY_l[ZNM aDٯgy7[m6Tێ}Wx9ײor؝( \ݽP|r5;.09#KF^A5:n=feeOϦa߿.m?q?KPDy pFgHij?:U-GJ6`*s:0L*l?sJ7s.q7wL{unZLӿR/MIOn4ŧ͸% r6Fv~/;hTvo޽\1P\j6cfBqv(Nba|Z]G9J-u{=mݫ .- NXV2eLrj>`4\<Q$[ixKRyt_|͗_+IJ`.ZTV^8x\n`MVsnú|$_'v Hr NOje^+'DfQ e}[cajU%xKF7Jܦ֐PT:ލ:d[ݹsz IҽNϽW*8IWdv;nzV>5<4AnLX rk<9lSiR`D#19JEX? 7)ERkcen:tYf0"u};7c4R>}ͻ#O`;UcL5}v}ӍyH[5; aҹ|a9MӻvpPz5:}^ؕ@ y⋙ىaT>c4\Nh!8"(3!߿|~r6ƥ=w|?ʥkfHrfݷ̸՘EA5:| uuՓN~ppV͔UumͭNKf᏷&Ol\s}Y?n`C[\ZVR!q*E{_f`0hM,tC%0(N$Y#Jm+(.B`TeƶK'/Ĥw)#5'?96 %%yO.{ouZ$1ZyP-e'ǖ$l s{7N!i<;Kppԩ[x4?# b+rڊjtjUN.؃dtJMUI Ǿ{)űZ2qmD{#wv^?Єneq~:LZPK=Fئ%E\zqBoQa%49Wo\Cz>xB;uD=Q3yW>ǿ+G9 _b6*k9tKƣhYjm_n*RYͽRԳ$)w3ӎ4+|zp  غk9yPKʡs ;[ ӲL9t[f}+y![JPpdpHp{kq$sٺRMC츈+&;'o-F Jq <jḕW뾵/bR1w.To7j-DH\13Rcj<W.l]zCS2 I KgjVU-9y1gR[8y&QZAO\ѵEOE)0q waPi>-;V;+lM7gk֗w`V :SFu^gCqj$~LY94B3S,{lT@ONJ}ƚ+L±bYpS%Y}pOV UuI}ڟk2#i^/>up ;B9K,ce,VaEZiQ *do31KjѕXfv6TAjr y<#?&/P,1dё̦WQ|.rR4{PX/HzB={5OY#\)>PuwY40Q͗E(CAxo%*I1N*?ݗ?Me7#3snJ>.5kY{5xu;{.!??ĪD0a̸ʛ)%@ Dϓ+dyeyh,#X,J_SI"|ưRڣ=dQGCU=XG4`xPr6F +3gD^=1 U,YmpdD>WFlƣ^-BQahhjBϿe9n[]!M1m^}fY ]ά!h C҃ڣcmձF3u@ڠe{|mcwSW` SE6@V6iDMD^󪁘T{g `=PGU jKzm\j6 DGgsR-]l켳4e^ x8R*x_I }U^ñQ-pQ}ʟ% RM6ّX5g]ZpѮ0d`S tΉ AK\Tv*)3Y^ܶ2܅( ΖCzsnn`̀{-؉T!ń6< 4؄W OtNtMvK9ңR#Z\mivzG"{|MJJyk˲xm3r%M%V*ԧuQJLNh^&jB*'EwѧoQ lb[UP6l9dp!c[=:Nn|Bmgzw@E/2KrKrIr6.7k l3blc?nHRha9H$j-nh^EI/$wy[ޛ[F90<*PSB1 l%ͻ;mcZ=Fm"6BXMQ}L|ٜL*i!IJ$1|feXg٥G]4@R_sevR9z-`'i vs&xZ mvb#۠?D52GDP$;Kjifi^%.ü/Ӫ,\}p\ECs`HlJO֙KR"T\bx $Ϸ^%n&b}#2MZez"!2 1̐ef/2{q6O[ IyfsS>,c5\Ak<9/Q4 OsSⷎm9%IǓQR[ދ oIgedKmLmjK&)<բ0%, e3ޗHz<{v4űr$G^S36𖐳'u/ /{.[L.?lS 4#lΨ-WD@) ?H| 2Olcbcjcjcbcj_\iEyn<6=uT6N<ё_dISzXcP5#Z&${  0` KSCBޖ|Ƌ4MY?cA46ȹH-|(LllDԪ K޴S#|yeIJ8kbU³UL&0VI"KGRhz9ֶCiU QѬwuӳyEV,W!!g c3CrS{߲7Dp_}˷]j5C42t{|-(^U`+)kgkyҼ flwL]#)ZqPUzp/ '^b>/+D> l=y`4MW6Nv 1wy vŨyD4"([-gs9h*K/g_%w.QNqwy&,#-\~:6'z[o !^s(C7ܞ;ĎhA bCoRzvlK\ 'A :oW)ʹF.nrA|҉֠τ#f#Ph`T9E)faǩR R^ TcPc&hgD߿mΈwMhH. HJ> 1&}|(%EMЍF@>Ч O~ fiT-^;^1~M">e87WvmTɫ PH0-S8V te󥺢LVbbRl_ҍվ0^4~dJO5:Y[[h>yV *$eoBK; !0X@bkq&h)O*2:udtZ8-? ÿ[Usb\Hr|WN;OAjEubr Ǫ–4"=Ϥ0#0c*:I=JgpIL+lj*k3e |Z6SnL߀h|BNt 6PQELmÙU Rl>r6 ̄2'+{xDZτ~2#yCaM\b)J 1:^`Y=t3C3H2ǤVb_, Tg Й3cncl}uC4:Cc[SY>s'gʔ)Ƴ@yYvGf`3o]5EyBqÃefll1:sYf?#NA3c 29R ̋1f*o盠|rhKNIri$ T4N'ŧr yo"@G2;C%byQm2r6P,{ԄkZ!g:UoXX=\C͸V]Sg1}ӯeOk8\eFa>sX4|NhkL t|SkdEHz596V"&PaId6R[pU~@"E@Y£k66hqD ^^@Ą?=Et9鸎?Zsk~X,.MOIjv2f`)Jv@4I=iO`69#.|4EM㉕J*LT/2WZhEj®gACP:Q=Qf9-5& T ^AoqX@FyRdm)/6A`~fI+~XvP3˿U>9[oo T$m֭kFznї nЮ?snn_Y{sK jo~OP5EWUq/h:eU5Ȓb.0K I5^^!ۻN`@œ"2'Zw@Φw^}=տ掖{IT%il̞f^Z>8x@xcЛO8[yZbſzVG4e6_w22Ean/S'Z+/^= {TI%zՊ&3&//xM292 Ԕj 8|fkU%O :<뒱˿d+lfsyiBZ;$` Q:Ū#Aux }z\@Qŷ3tjUC߻쟛F6f M}{6h^%O$ kyN;jGؕ冠t\E /7?L/lFb95 ê_^#J$J{H#{OO=r&u:fGrph[~Zވ0]>IuW]IM^'m.;k:rTL^()U𮋽ɶKӼX3/X:M\o򐛕Zѱ);n.?abxwA83XɈ}3rR/lԹz#ǀ kWijܽmEևj:O -UG5NzXàs./4~v '>3Nq%߱#D$a~NlqZ_ 2}eD#6jM>-'WVE!`ZxĖzm†a3o%j&iIٌ;9r w] Ҿt!wrjڬUW uH;~{d쯃߇Msk\eKڱ)6hb9AUc@ꬌG_u`cJ}F]2'zVa_/-KQ>kcک4 n&~SAS/ttB {Wg=`uύdF `L ,lܡcg0dZ]?^{u^I}(9nRۇD=(8+ WOXUv)kZ )?)WOg6wumZ >ŸRWAhL ,}rzJ(ͽnl ˳ dZud阛7$A?r0-QknJ{  l/{5+Kg;qrOY7X)Hύ>аX:-ۻ}&oZYvJڈ,ζ1-M,~(7Sn~.v#Eܵ՜r6O{J[!]ltQMWao4|4MƋЫyɼ$<&X+Ҙ:;6Ҋ,Q #I-W3czayW n$|u0+! P <?| rwGJҦM~n>r6@'lN/hˏ^<ާ32'#=IF\xzlXqa9b)J2\ͯ3K^Sz00QqgZ¦ ^~ WO!5$aхg(@+ӘTQZUC1m]աZaBxx{1mBj8q_$j!/8@ (N4|+ôSi.ҹFcf(c$ŤLJGF\9~e1O ˰u|m\zٻ)6(SE*s`G5\eWa5 <V+-ş@"Cמ'm&b}eN~E\>뤎2/ #ٸ{PpFf:iz:cf\7$2GfnM0ۘ,&-&4-{C6I}iK H3ΫMqEw*GO=V9t2Lc&JW2bkȺ_܂f/@`jUeҾȜmc[mwoʣBS"ZmY9D@r6>bWw ocI&vƚWqcF޴L^)꯳6Z;TZ۾j-f "3KKH$]a̴FbN+FX#J2s餮DL'Ҋ:%M~%0s?J{Zŭ,&lyѽ;'_n5@yBPF|ĹMs(K _bbe oQ Jzrٓ۷n:p<=dT1S@*uxB1Y Д(86hLfn9q*R(p 3V\=_YDr%еgۇ6c,9osy׊&i1tYD!g+9_<KS_lڰW3f3n߾}= # ZN.兽m0\RIzk=)}3HNf!;{loooClNWfG6m4b 7֊,]E+O%&hQ)G UZΝ;#gFP0ثVb;6%%*/PuÇ'<<~cJlllww9F#z(:.99Y s@kHV^bEݺur92_m۶% t777ի>ӗ޸pǜ9_qgL?zgClٲ-[p8={ڵN: I^EPu;wΙ3''')UÛ5koRΞ=4i1G'''%$$gs"7"4s{3gvЁy(?nܸJuwܩ[.!Ϟ=v#Q9[S9ewr8{L2x9222/^n:Zmbb2z蘘Է0$I(e˖⒬]vM4A~ƍp*քhZGG!CxI|`9̞>}6mggojj %o6m /cNN߭[JQ{ڵ)}m. MҐLldl9{1c"""8ΠA  ed?ؼys.]ޓ'Of>olvڃHlԨ hNHH`>SSS  ժU+f!c`cc3HCZ}]v1şM4ԩSpppEڿݻw>9e®(˨17ꉪs)6NzGZ_r*{.Z(<<\,/]tȐ!hNfii9H3g|Fb^:u_|! 8: "{L@pT:鸸ФNhiҤ m]hڋ/9r]vO>-.d@[n繕Je@@>[n:t(v@y*&,uo븟ۧH4r*Vd6MŃ Th=zwƍwiUxƍfꫯi//%Kt͐6V՞?>99Y  8P$ð0bZ[[WVm۶l6x\.eUVj4k׮L>`zկ_A6͛7g+**#,eRBo;NYNs^jƼZ>vƨ5M-^\]3e4g# mEo_|ApS_rB\Şvl U@*{8PV65[SXE#mʔ)ݻwJC 3gy4NwĉdLֻwo@ *//Ν;Eq8^zI$DCxM̝;r^ѣW2̬zlmmkUV͚5ޣ fϞ]N]ܴi6`._?d%cml_X=YU|X\6l˞eμ¾|taԳhzn't`9<3@QFb5j=V g۶mÇ'Irƍ%|S#U~٤Id2RsV 2550`X,=p'OT)&HV|x*0gWsΙ3T^M3 syŀFʲj?Z 1m&f5?oȚ6q|Cק\[0_͌97V9 9 T wV6m4|pʓEJ3<<<(bm۶988T tA5N/_L{{{LMMy:.**Ǒǎ(^jy1'n/suuC f~W#Kw/+B蒄M1:QO$l^FaߕlBPTAAAw>>$$D0G ;0k֬?~svvy)ijժSt:]rrrBBBb;w:t`JRRR^lǿ+WWWflggW\=#|:{/p$$+,+.KSxočy~ sXtagohj }:>>92{?ߧHǎXLфyS?~|K8smRV-fܠAz҄_~fl]v`PkL?{^.njլmŀFξX AÌ(E>lܸ lmm#""8w}7mڴF.]޽;C7qƽ{A߾}MMM1{ fffzx<^"oZ ??sÇY&&&СC͚54hO0x f .r$ITڼO/#|l͙3رc'N9r$#--mΝ}ق ^_ڵk<`ޥE6Vjj#Ghn۶3`<"""֭cTyWQWgܺuƍ .|J*.mݺuڷo/JCȯr6P.]4+W"`` зo_zݺuۿy7n<|߿A2cǎ={ͭUVmڴ iѢũS8\`Bqɓ'X|߾}FcJ`NzqttD*y!M+V`g4i] *((~ǎ<?ܚ P e1533399ˈ ycqE!&Ziv=sLRYPCgr6P;૥:~F^^^[hsgfܰ~p5kִauL)5Vx88VdՅE8HDjͣsc4R!RY,yc;ڜy{OQŠ萳rN;ua3 0v.oܮ'VN:jr ~8 N+LyWx«sc6!FByTԨͻ] ĤʂMd⇹ X@B8&[~t_J9ֳXG0*6Uō l3@99i_!qm ƣv5_oύ?ȝ!*Y~2CTeh5 IkϊͭEjfLkW_&6Wff L%wӯAH ./1hM>%yC#g@ucze@Z;lreW"8<>*1i6?ǣeOrTٹnmRY?¶BF I tVBԩk̝ uv!x~nJ7EE搗 2(}^z#gkinK[#6^<^>F7:΢4J4C VHۇ6Z٠bxdg&ꂐ E{kc/ [܈8T".l\6oaƵB(89h}eq]=TaWRDi* oU5D?njNؔ9WdwOqb$}'#83"l_vnjZD(=.)ݣ۝^Ti8ϩ b $I|SSSDP=8kߜA4M![ Z;=}\M% x/6Ed RUj*RA<}S4N\`&B.C6UYNX^ fNOnDk 56Ef<_}z&E0Gyv)$ƒ~8w/cލЛ:۬ѷBY`]fl @ ;'w^\ӤsIz`4H1B,2̰UWQZ=q17>]55Y1OH&;E٨.Z\ʱ(a)Э/S|+Q^"5j_OW>OyӣDҗ3}f"a!gWNrlfBgu ?6 ~w~<®.9JPhOtuj._8Cj֫Q7o0=ZFXE*f Mw=%yu3~I/@E+LXgz:\e7Ia zr4{#B>ػm=D[O9TWˈۇ6:vבŅD2]cꄛP A7iG/GC3WՓ͘_yDL_xϺ|߿sFnp MqXMT+anтSfģVS/ MTvG |\ 1cG@v=< IDʌV~>OOPz}@+( -&׉rN=:|f!]d aۦcz.R_XֿXX*9(Jfm¥bF_.v::*zFIfV)ƐdD W{{cC>1A$f $̄Hf֝#.K\2B聈PdgӓT Ցr,==}I F=?q9_()N`&4ɥb+* O)03∘}atnttXN[.Iy՘~:cU/fi9/#9%^;n"J 1kfo:.rشzce<u@ڒũm 8,!!I_y r" wŅI&njr |0:My٬f=qdFAH؀9x ^-W*/>l,Ht褌틸=De.~Ҳ9·)wJuk"gPisOԵS|iev@L=\ض]$SϾp)6`l΄=;^s3E(6nܘ(V`p-M7lnU#DE/lYx~fZ^3Br)VHY뵧 D :vwc*( *wԱQ9Z^tFU~ok>&?gݾA[J`2d/AP'lQDA@!و " -ttQ~ޯ{KsI$$K2xJ.rG[o}ϛN.$I-]]q].HoAٷxUr]-ٯ1beGa0X_m""4lԨ~7<%㡉GX*К 4 MԬYs{U#gfF3Ӗ[8.Hk? 8VNn7\Z;yEu҅XxF#"EooDy|y#Be6P43em?/aX@|ًRԘ1cr޲Hkg쥝?Ćш%WdY'`73m۶2?A@=9˾ZQBd*+{~?.#va$ fu_1np @ gK[!&9kOz۵kd-Fd F#Gg1pa{ݓERy1tI!Ь1k9(M<(Įcȧ)4iDbNf@]mœMJm"7MZҶCjRiuxsk'#Ty@Yg$u(PNئ[ok4hpJ±s;Ay{7KvytBXrk؍:[;#Ur6fݢ +SbNjZZ"T bt_0<]QzAFQÏE xmcBl&+xqlQ7xڰKbU|ZVF+9^]FXa~_m 8X kywzs"HlY,읫[$4?'$F&H,t*Sq~8z/9ƥnZax%@vWt#^wRq::G<.}Fz%G" "b~ :e"Р7S-޵ݥGQ q:75OİXr%[t57m1с]'-i`߉oB4PۂNDXג47)*6YT;\C@*x#`7u S*д˛"Pg߿8pݹ77' s=7<͘w# =G8pF16 YIYN̺ ļۍ\y/n2GXNbR> ܋hgʣO/6L r|B0b\RcްơMk-Z_6 ''Nx8hrƁ5xHߝ7kF(&w\hו+WΘ1u*dvm.рjv{ AӃlUͣe_5v~%hՊq+p uR^mJ1*ީ֦"UE'7[ DW2MQ@>CKXxa?fݼα<NJ$~gzYQ΁GMRF4*Vػ P=%5HT-mFYZ9W >Q^{w4Q;uf3_HT ]M*gNq$l17)\zP chzyxt!Sg5 8>oHT2zJ#}iP:}J3Y< g8l{qRP{BJ(NB0CeRoXwq[ I68=d&n.芑sl\@qg\J ߡlU%Z: ;nڮ.T/F,R7yg}&pIxghM9<^  }ZĢD㱢Ã,CՂ}w=]ExbBV ۂ441VNnMzE[Wo*ͻ{74\azKѤ/Pj٘Ԍ{DŽDɻ2tʜEߒ?N%L`RYpzǾ[.?D.? ƅYM" [ )l96'f_Fbq Eў;5>ܟJ+~~{µ@~~ȷ(S@KC|͈T۱X9!D[o4o`v0CA-y˽V%{cs52?͍8OmmK>.xL8G6x>.ť@A53 TF *E|])ÂfK|,vѵ3rO6t=3\&[YTݾ؆h%o HAI"lax[ΗSF4!iC,QjW/e,THc.Z %82/PQv>_*M 0i;bOroPX/vxKQIVFۡW r`tx(&l] tJ!S뾍KR6FV~ר֋2ORE#%h~S·sr:Un{$'r省Ke?#H5Y`)]T-Cս[97!i%Iag&TD;iB[BAwjύC=)as,^nm_Jx9*+zu~hM=uh$p' MT.aGO3LtE<#zPxn|@XI W=t :@X.5-u +Yzv;(JS8D2B:%oȴ d8Z7bO2\^(ŴHSgL9":uUW[YOݣŠnuȔCZ\SE'cŴXrooZg%ln[' )(fJK.򠦽W|6#?Qur͆ ,12oe9]NR/\P)?_ݷMP8#_v0lp)IodKmtbfLAŷ"a*׉-H'10ۖUQ4I VD7uƣ.!a!12R`, - Ad Ův1Z$ %w񭕆I?% u )S M iqtYׇϼUӥ$^mlqld {?p|Sxƅ4|IK݅sT!3Ckb gTC1nl|%E6*9瓣b>}xOsO`ZAZ[uKfs3/¾(4F"_SIq&43qt4j\Lp>YtQC'r|\?k8<'8t Rh6G:VKB~*)G˒qm\8]3KThJSI"!(IV`_Z@.N骲d1S|Ӝᪧy(J<}Q|V.hQԓc&/CNOՓR'C5];tE~aUu;Tɿߗ}NТӨͿĺf6_z&Q*W>iV{?5}k[\pP]]^"ٞ~ؾ飏 U-:((z)Pf?2u{ƾ9eZd3P[CR7pTxxbjGk#^z(ɂ~QWT7qbT> V^͎-^T)I^q LϼUE" ͝HVDJ&hmKsbaUoƆI@w6Re/&1$!ѫ{t.bb'x y7=;bSK8ezӔ)1D$E$>N}sNJ,qQwvNh|/9Q="."ie+"nG 7#h8T/{&%i4`mkh:rRt`Y! կwD'O1DgOު޹Κ M¡LC -|\bq["Y힮/Vd675'"٫]h~ +I;-6N8|Tn$QlML4Ѧs[{0:q}1AJ uXT=G )IV_UCu~ ݏ?NFVo^~̬kyuVb&w @uw$?n\80Dy%l3 ,L{c'@+PwP-NHh%"=J2\KqdHO X&%NEӤ)2ôpI2Hnm<~&%c0֚^fllq;y3X~ޔ!z L@aK_}\pfÂǪujBKCãIsYؠ(e6/E:#\b\>uB$>L-ߌgw|&b:Bo}O+|f.G5ՎeC(c$8B4(νEH?lo5rи&+DJΎG2@pH L)-QTXWC3VJ8|S-uSHD>lzKkӡH^(_뢮dDvΆK?D׃uV=,-W36X'g-ܣ#ݙ'h6nvO='[ l匩Igpq%t)ؒdPSI?B_-K$0R|W}, lQ1tCfѯªƆJDYxڸuѭ/PlRꮸ[%%]Xq>-ϱ7=x$%O Y ePy(1.Xi f5s@h J*5P V8s5g. zT0mBY☽DR 3[+cKXt^KU$IYk%6zT i2i>nB*Eo<7;sQLDRԡ򴐆iT mMiHޘ3L+:a_~/9>+95Uj6U|јjUplymM|U0CYVjo$'@̭(CJ,1y莐ܫKkXEiCWOX&N#yHk2}PSS Nt}5hE;ī2.ۅ|2V/ơbjp Ovbc:S56M=HGݚFQ4٬}ʲzuFA_<f5k1u:;v͛?~ 2TXw,--|3T#gP)EHnL|T&>!l}`M z1wtѾ e-os[m-}|#2i6PZ8I XigēLkY{-G>6P'Dkx1?^:Td"FO}`Zt7珴H,ԓ#%k3&K%ޔg}+KnL$T5-XLjb!GCBeB)6F&E3̺$Q`xvDNjXAP`RW} j*)1AM~ꆹa0 V5^f +c|JtᅿxO*Ei%ևr=C"'%(=}D ] 5^~#x!/p77]TE>ZlPeP 8K֑4=fOdiaEYkrʇ5c2|Kl)jUw?Qlqn&vir8MVV:>;>K>>rlX vP4΄8@%  o6t+RCoM-~* 3<),4tbǮxzxVj8箳λ  *a j"U1KZR-bnv-[y$C P}ZS=DS%i5 eܲZy/YK9U0I4(L'/ 6^ %'~T=9jUxSL2 #4[=$H> Ѷtzik)z놧vhR'=4jlqMڸs>:# Ia/h c;ơq/NgE^Hcv1O8I[coG}sB\J!jѷ̀0q"O)Mտ)F>Q4%Rő,A۰CQ ){aoVVRZKQDq^"#okͰDQ.H\L-DԗT3I9Y{TG>Rn.@&I crsdsd]TLtgp /SJw,Z/oyy'6mT8V=d$%}򵸾߬_i`h ֳB ++]>ERs|m"1 ?JJoϾy#Nh"%P_iX̮az2翩S-+V668T!l({7'um#_m, W !7(/~v KBVGy^ŕ4evr^☷D}2aa%/$錯||k:vc.M*җ(]UP?'Gd_|?>8la!lJc'F>9E$*(W*W"g+y*y_JYW=6uvLTR>ix-׿Q$BPn(Nx7(_W)EܙW@Hʢ^U!^HMHƽ.6 9Rn:vUӱTԞ#,g{VB %pХ{*8 MU9jͦn6:ģC]^>}IxUj\W#𲴌Am(-#!U A=0v Jr&ܚ@́7aE-@F+ͱ[n„ ա&$mX>^Mrj{ Z]:ݡOQ4iO(Þ=߽arv4{P"yڳvw PcZ<8@Y}$v7CE2Ec8@[$l>c&E?gr)W7 Pr?TaO\;J3>zKƀя,K!&Z.E0uoLoNF(SNX)ve=\֠;NC4,p]f[zҿ kN8Txm\4,Cu<_j8nigZ-= ixsk3bRtmz#ڄnΫ̇8MX>$p?Emevɻ1ҳ]QN#K,&w= b}OnЛvE@ ~%k[!' qݭ!vdt^ܪA"R !g`tywx6V61N0obX@5# ^IҦ[C7?4tps7=T׃Fظ^2™EtpT!4C6(K}:F6-I0&+*)d!׭UH=daxqD!!ӵE2c(-As547説q:k YSmrE^}L=Ր"PۅJ?̓qkW%>J,ZwNt K%u`swPC1BQj A|i A_3_Z" .7@5&+/*Nj" jFb/ Nd=%0s76= jȷ ^ ")ZOlyIzvLe€8?+A&Og>!%?MSVY*v՞IM%Zq;CH~ UG#ֈuw'Pe#CkO~h-m"=ELqdZY:O쟩d_"V {6bݿE{."LxON({ QE]նʔ A gS搳(?9Y,eJE{rEU3RYE4t5[ gP V2ϯ)F.mWʞp=Gur| gP)BKC^FMZ(j}'RW~n C+#/>?"d W_nK)WEz xcX˒CpAGSxWYBv^?khˁ?9F#pd_M"R,Iro~܂0Se.nyb|3/nf7JB!]alpcTv02J8Jv\7c}ٛ[Z药|ȕ%! lZ i hTkDIդ@uoݻ)GL䀇OӳR2&4okRĈi\FʝIٴJ|'@29ü%o7xi@֖<˥hօDȱuÖ heacKRî5itGv>v磏Za9gZߤkoG%))wNmtlzxeY竴;ݬT7朷Mk5=/o&E>v{c|,ZPʨLA>m`跭6n>igVvvJ ŷ/3Nxpw^e>ks,2cx66OҵYo۲p?ѧ3i!4MJKmÚ<ǩy.P*_ݧ#:XN}swܶeHe@l祜7$yIIr ɿ=gkKTƾ^7>jd Z՛Vͥ-jom|"ϝen[w G>=vw&Co9JTkĶ kAe4j>Z2̚x>̳q3>dkV|ҩ5绍5㨨.4ۦLum \f*>}X+!seuzLF?Ij}k/72jِrۮ,ٝ3޾δ؇'lz:J搴s.,ϛt;b"ImBbM'IK[n=:kD8$2\|^L8ſ~x֥k_Da6A9~%q {&)s6_-@ai3Zv輎}q|j!y6ϑKn+mТ}m֌.)u]%eTR*zq?dtیM?'Q& 7d_t`ՖASGd uv9v#Rl=_\NX>fr%4rgY_3|uPuo A|;Ų+ҩЉI)gX }b 03qRb"ӓ4VyNXcm}I)4y=mRV{A(Z0jݬġy*Adl btYO,A.rPrL3gK6Ks;>osinɧ|j\$cԹ^ :-jomi-!gP~HJ;9M~*V{Kg6d[ ;nF}{fLKֲ[5)9!kqQ;FJQ`d/+r}Dncx\S6K˨\.T+\%%)yE7Z!ݣۃ/II6-t8go5+Owr6Gtז/ARLѳ߯뿮ukYz2Q: DڈƦ[of Scy7UĥO])EtM l^sk!U_CsIoenf re+|Quse^Rc#e Qo8g=S[J =$ { 9rrgqWkƁ_z9tG5gԽ#afުYg.<ѳJOr͡tM)>sO;~Aկ˹.=LxSaE=GU%ȕ\-8x={r7W3μ\JJ*]_=hna ^;Oc P(s}O˺FV߆r~1C.xx͸w\u٢xA£og4=YOWpA'zY^FFD>/ ,f=F 4~1ğgv!qA2$fRF9Ón(/K}~g&_ṱ,AlrK:3-zQǨ- ɋ}Ŭa1+ǔdf)]K߈ Ug&]'qAuDPrr6egR戽7mfĮ5]/p''E#>{o+Yh&kxߚ<پM͈ 0$i;=$ϛܢ|\.vD4aP%Dފ;7ι)hq1{'QsS3Q)Y~G$Fh5;6tkNskSZ=Ã!ڤGoXQ6[!iܳ;V ?IYԂ;0x[fֶJ ro;ׂsk씹?[ZY\EFm?wtg /{NtP&u Ꮿ쾺u]ڳ'6IjUJU,/\R maw7=}HB Ar|Cdh|)yջ(gP/ڐpx넉ӊf7챕yOgǎ0i^&e1̈́OMmՁ>H ߾|GR|i|,k֓V֮Tle|&\āW=Mv ~W8{ݲʞvnsrt}B' }T3?BcuN-zѪ]{\Pڭ?=Һ\^򉋘~&3Lk6MqcpDzޔ9v~g̓җ,um gk/ɔov2ZWA#avr69 @C!gPA!gAQI-B(9(/A0l*r69ylMIENDB`maliit-framework-0.99.1+git20151118+62bd54b/doc/mdoxy.cfg.in000066400000000000000000000127651262307254400225450ustar00rootroot00000000000000PROJECT_NAME = @MALIIT_PACKAGE_BRIEF@ OUTPUT_DIRECTORY = @MALIIT_OUT_DIR@ OUTPUT_LANGUAGE = English DISABLE_INDEX = YES EXTRACT_ALL = YES EXTRACT_PRIVATE = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_UNDOC_RELATIONS = YES BRIEF_MEMBER_DESC = NO REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = NO ENUM_VALUES_PER_LINE = 0 FULL_PATH_NAMES = NO STRIP_FROM_PATH = INTERNAL_DOCS = NO CLASS_DIAGRAMS = YES SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES CASE_SENSE_NAMES = NO VERBATIM_HEADERS = NO SHOW_INCLUDE_FILES = NO JAVADOC_AUTOBRIEF = YES INHERIT_DOCS = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES TAB_SIZE = 8 ENABLED_SECTIONS = HIDE_FRIEND_COMPOUNDS = YES CREATE_SUBDIRS = NO SHOW_USED_FILES = NO #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_FORMAT = "File: $file (row: $line) $text" WARN_LOGFILE = "doxygen.log" #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- FILE_VERSION_FILTER = "echo @MALIIT_VERSION@" INPUT = @MALIIT_IN_DIR@/../src/ \ @MALIIT_IN_DIR@/../maliit/ \ @MALIIT_IN_DIR@/../common/maliit/ \ @MALIIT_IN_DIR@/src/ FILE_PATTERNS = *.cpp *.h *.dox RECURSIVE = YES EXCLUDE = EXCLUDE_PATTERNS = moc_*.cpp *_p.h *_p.cpp */demo/* IMAGE_PATH = @MALIIT_IN_DIR@/images INPUT_FILTER = "sed -f @MALIIT_IN_DIR@/aliases.sed <" EXAMPLE_PATH = @MALIIT_IN_DIR@/../examples/apps/ #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 4 IGNORE_PREFIX = M #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_TESTLIST = YES GENERATE_HTML = YES HTML_OUTPUT = html HTML_HEADER = @MALIIT_IN_DIR@/src/header.html HTML_FOOTER = @MALIIT_IN_DIR@/src/footer.html HTML_STYLESHEET = @MALIIT_IN_DIR@/src/meego-im.css HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO #LATEX_OUTPUT = latex #COMPACT_LATEX = NO #PAPER_TYPE = a4wide #EXTRA_PACKAGES = #LATEX_HEADER = #PDF_HYPERLINKS = NO #LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO #RTF_OUTPUT = rtf #COMPACT_RTF = NO #RTF_HYPERLINKS = NO #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO #MAN_OUTPUT = man #MAN_EXTENSION = .3 #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO SEARCH_INCLUDES = YES INCLUDE_PATH = PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS EXPAND_ONLY_PREDEF = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- TAGFILES = @MALIIT_IN_DIR@/qt.tag=http://doc.trolltech.com/4.6 # GENERATE_TAGFILE = YES ALLEXTERNALS = NO PERL_PATH = /scratchbox/tools/bin #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = NO INCLUDE_GRAPH = NO GRAPHICAL_HIERARCHY = NO #DOT_PATH = /scratchbox/devkits/doctools/bin/ #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO #CGI_NAME = search.cgi #CGI_URL = #DOC_URL = #DOC_ABSPATH = #BIN_ABSPATH = /usr/local/bin/ # EXT_DOC_PATHS = EXCLUDE_SYMBOLS += *Private *View *Draft *Daemon* maliit-framework-0.99.1+git20151118+62bd54b/doc/src/000077500000000000000000000000001262307254400210735ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/doc/src/architecture.dox000066400000000000000000000064321262307254400242760ustar00rootroot00000000000000/*! \page architecture Architecture \section Overview Overview Maliit is an input method framework with a client-server architecture. The server hosts an UI for text input. The client receives the text input and displays it in the application. The Framework uses D-Bus for IPC (can be replaced with something else by re-implementing the communication class) and Qt's input method support, together with a Maliit input context backend. Server and client (that is, the application) run in different processes. The server runs as a single-instance process for each user session. \dot digraph { "Maliit Server" -> "Maliit Plugins" [label="{loads}"]; "Maliit Plugins" -> "Maliit Engine Plugins" [label="{loads}"]; "Qt-based Applications" -> "Maliit Input Context" [label="{loads}"]; "Maliit Server" -> "Maliit Input Context" [style=dotted,label="{calls}"]; "Maliit Input Context" -> "Maliit Server" [style=dotted,label="{calls}"]; "Maliit Server" -> "System Compositor (Optional)" [style=dotted,label="{uses}"]; "Maliit Server" -> "Window Manager" [style=dotted,label="{uses}"]; "System Compositor (Optional)" -> "Window Manager" [label="{composites for}"]; "Qt-based Applications" -> "Window Manager" [style=dotted,label="{uses}"]; } \enddot Whenever the server handles a client request (eg. when text entry is tapped, thus becoming the focus widget), the server projects a translucent fullscreen overlay onto the screen, effectivly capturing all input events. Maliit plugins then render their UI into the overlay, propagating the consumed input method area to the server. The fullscreen overlay is transient to the application window, that is, if the application window goes away, so does the fullscreen overlay. The system compositor composes the remaining translucent background area with the application UI's rendering output. Except for touch and mouse events targeting the active plugin's propagated input method area, all input events are forwarded to the underlying application window. Maliit can run in a self compositing mode, which bypasses the system compositor and instead composes the application UI's rendering output in the Maliit server process. In this mode, no system compositor is required. In Harmattan and MeeGo, MCompositor takes the role of a compositing window manager. MCompositor serves as a reference window manager for Maliit. The Framework provides interfaces which are implemented by the plugins. Plugins provide the input method's UI and are also responsible for input method engine integration. A typical plugin use-case is the implementation of a virtual keyboard with error correction and word prediction support. Plugins handle text composition and send the result to the application via the server, using either preedit or commit strings. The latter are considered the final text input, whereas the former can still be modified by plugins. Preedit strings can be used to show the would-be result to users. Each application creates its own input context, which acts as the application's client that connects to the Maliit server. The input context receives text composed by input methods and forwards it to the application's focus widget (usually a text entry). Maliit's input context backend supports Qt application. Support for GTK+ applications is provided through Maliit's input method bridges. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/common.dox000066400000000000000000000003061262307254400230760ustar00rootroot00000000000000/*! @defgroup common Common \brief Shared API between @ref libmaliit and @ref pluginapi. This API consists of enums and other constants that are generally useful to consumers of %Maliit APIs. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/extensions.dox000066400000000000000000000077131262307254400240160ustar00rootroot00000000000000/*! \page extensions MeeGo Input Method Extensions to Qt \section Overview Overview To support MeeGo Touch features, we often find they are not supported out of the box by Qt. Hence, we did some extensions to Qt to overcome this problem. The main goal would be still to push these extensions back to Qt upstream. \section IMQuery Qt::inputMethodQuery extensions In libmeegotouch we provided several extensions to Qt::inputMethodQuery. The query will be performed in QWidget::inputMethodQuery() and QGraphicsItem::inputMethodQuery(). The purpose is for input method to query the widget about a set of properties to support some input method operations. To make use of these queries the widget needs to reimplement the inputMethodQuery() function. \subsection VisualizationPriority M::VisualizationPriorityQuery This boolean query is answered by the widget if it wants to have higher visualization priority than the input method window. By answering this query to true, then the input method window will be hidden (or something else, depending on the implementation). Answering again to false will bring back the input method to the screen. \subsection PreeditRectangleQuery M::PreeditRectangleQuery This query returns a QRect of the area occupied by currently shown pre edit text. \subsection ImCorrectionEnabledQuery M::ImCorrectionEnabledQuery This query returns a boolean whether the widget wants to use the input method's error correction feature or not. If it is true then the text input is not using pre-edit mechanism, instead it will just commit the text to the text entry. \subsection ImModeQuery M::ImModeQuery This query returns M::InputMethodMode enum of the requested mode of text input. Here the widget can ask input method to use whether to use normal mode with pre-edit and/or committed text or a direct mode which uses a fake key event injection mode. In normal mode input method sends the inputted text using a standard pre-edit and/or the committed text. In Qt applications this mean sending text using QInputMethodEvent. In direct mode input method crafts a fake QKeyEvent and sends it to the input context. There, if the input method does not want to compose the event, it is forwarded to the application. \subsection InputMethodToolbarQuery M::InputMethodToolbarQuery This query returns a QString of input method toolbar name to be shown. Input method loads the named toolbar and displays that in it's UI. \section IMState MInputMethodState This class provides additional information which QInputContext does not provide. The widget which needs these information can connect to the available signal and slots. The more accurate description will be maintained in the MInputMethodState class documentation. However here is a short version. \subsection orientationAngle MInputMethodState::setActiveWindowOrientationAngle This slot sets the active window orientation angle to the named angle. This is used internally by MeeGoTouch library to tell input method that the current orientation of the current active window is changed. \subsection imArea MInputMethodState::setInputMethodArea This slot sets a rectangle of area occupied by input method on the screen. This is used by MInputContext to set the area upon receiving such information from input method side. \subsection activeWindowOrientationAngleChanged MInputMetodState::activeWindowOrientationAngleChanged This signal informs that the active window orientation angle is changed. This information is needed by input method to rotate according to the current orientation of the active window. \subsection orientationAngleSignal MInputMetodState::inputMethodAreaChanged This signal informs that the current area occupied by input method has been changed. Widgets or applications can connect to this signal to do further action. At MeeGo Touch library uses this information to move the pannable area upwards whenever the text input is obscured by input method. When there is no input method visible, the area will be updated to an empty rectangle. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/footer.html000066400000000000000000000005451262307254400232630ustar00rootroot00000000000000


Copyright © 2011 Nokia Corporation
Maliit
maliit-framework-0.99.1+git20151118+62bd54b/doc/src/header.html000066400000000000000000000006651262307254400232200ustar00rootroot00000000000000 $title
Home · API Reference · Modules
maliit-framework-0.99.1+git20151118+62bd54b/doc/src/images/000077500000000000000000000000001262307254400223405ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/doc/src/images/.dummy000066400000000000000000000000001262307254400234620ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/doc/src/images/dummyimage000066400000000000000000000000001262307254400244070ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/doc/src/internals.dox000066400000000000000000000361101262307254400236070ustar00rootroot00000000000000/*! \page internals MeeGo Input Method Framework Internals \section Overview Overview In this document "widget" refers to text entry widget which is used in application. \subsection Architecture Architecture \section Features Features This chapter describes the communication conducted between input method and widget when performing a feature. RPC functions prefixed with im:: are defined on the input method side, whereas functions prefixed with app:: are defined on the widget side. \subsection Showing/hiding Showing/hiding The Input method UI is shown when the MInputContext instance receives a QEvent::RequestSoftwareInputPanel event. It is hidden again when the MInputContext instance receives a QEvent::CloseSoftwareInputPanel event. In practice such events happen when an editable widget receives or loses the input focus. The application calls (via the MInputContext instance) the following RPC functions on the input method side: - im::activateContext [MInputContextDBusConnection::activateContext?] - im::showOnFocus [MInputContextDBusConnection::showInputMethod?] Then input method reports to the MInputContext instance whether the input method wants to compose all raw key event from hardware keyboard or not. A common use case is input method support for non-latin languages. Here, the input method calls app::setComposingTextInput(bool). This function could be called again if required by the input method, e.g., when an input method plugin was changed. Additionally, if the application gains a visualization priority higher than the input method, the input method is hidden temporarily. A use case of this is a long-pressed MTextEdit widget, which triggers a zoom-in. The input method will be hidden for the duration of that zoom-in. When the MTextEdit widget enters the release state, a zoom-out is triggered and the input method becomes visible again. To gain such a visualization priority, the application sets the M::VisualizationPriorityQuery property in its inputMethodQuery() function. The MInputContext instance queries the property during setFocusWidget() and update(). Depending on the current value of the property, it then calls im::visualizationPriorityChanged on the input method side. The input method can then decide about its visibility. \subsection KeyEventFiltering Key Event Filtering All key events received are filtered in MInputContext::filterEvent. This is done mainly to support features meant for hardware keyboard UI interaction. Upon interception of a key event, the MInputContext instance may cancel the event and redirect it back to input method. It can also choose to construct another key event and use the stored modifier state, then sending the event back to the widget - regardless of the actual modifier key state in the hardware - using QApplication::sendEvent(). \subsubsection KeyEventFilteringModifier Modifier Keys This section only applies in the hardware keyboard mode. On-screen keyboard with direct key event mode activated should not be applicable here, as the modifier key state is already stored on the input method side. In DirectUI, all modifier keys are sticky, meaning that the key state is kept even when the key is released. There are three modifier key states: - CLEAR: the modifier key is not active - LATCHED: the modifier key is active until other key is pressed and released - LOCKED: the modifier key is LATCHED until the same modifier key is pressed and released The diagram below describes the transitions of the modifier key states: \code +-------------------------------------+ | | | ^ V | NORMAL +-(pressed)-> LATCHED -(non-modifier key is pressed+released) ^ | ^ | | | | | | | | | | +-(pressed+released) -> LATCHED -+ | | | V | | | (same modifier key is pressed+released) | | | V | LOCKED | | | | | (same modifier key is pressed+released) | | | | +-------------------------------------+ \endcode For certain widget content types, modifier keys may be activated when the widget receives the input focus. For example, given a number content type, the Fn modifier is LATCHED initially. The MInputContext instance keeps the modifier key states (Ctrl, Shift, Sym and Fn) until the widget loses the input focus again. \subsubsection KeyEventFilteringDeadKey Dead Key Composition If the MInputContext instance receives a dead key composition key event (Qt::Key_Dead_*), it then needs to compose the event with the normal key event it receives next. The composited key event will be sent by the MInputContext instance, instead. \subsubsection KeyEventFilteringCompose Other Compositions If the input method wants to compose text input by itself, all incoming (queued?) key events are cancelled and redirected to the input method. The input method then sends the composed text either as pre-edit, as commit string, or as key event as described in the "Typing" section. \subsection Typing Typing There are three modes of typing: \subsubsection Pre_edit_string Pre-edit String The pre-edit string is composed as the user types. It is not part of the text entry, although it is displayed within a text entry. In practice, this string represents a candidate word that can be selected by the user. If selected, the candidate word is send to the text entry, replacing the partially typed word of the user. Candidate words are created by the word prediction or error correction driver. Candidate words might change as the user continues to type. The input method calls the app::updatePreedit RPC function when updating the pre-edit string. The receiver of the call, a MInputContext instance, constructs a QInputMethodEvent event, along with the formatting attributes of the pre-edit string. It then forwards the event to the currently focused widget (obtained via focusWidget()), using QApplication::sendEvent(). The emission of the widget's changed signal shall be blocked temporarily. \subsubsection Commit_string Commit string The commit string is the result of an input method interaction which is sent to a widget. It becomes part of the text entry's content. The input method calls the app::commitString() RPC function to send a commit string. The receiver of this call, a MInputContext instance, constructs a QInputMethodEvent event and sends the commit string with that event. It then forwards the event to the currently focused widget (obtained via focusWidget()), using QApplication::sendEvent(). The widget may now emit a textChanged signalThe event is then sent to current focusWidget() with QApplication::sendEvent. The widget may now emits an event telling that the content is changed. \subsubsection Key_event Key event Input method can send a constructed key event to a widget by calling app::keyEvent RPC function. Upon receiving this call MInputContext construct a QKeyEvent and sends that to it's focusWidget() with QCoreApplication::sendEvent(). If current input method mode is M::InputMethodModeDirect, then the input method sends key event instead of sending pre-edit or commit string. \subsection Pre_edit_injection Pre-edit injection MTextEdit widget requires that if a word is clicked then it needs to be turned into a pre-edit, so it can be changed into another word with error correction feature. When this happens, the clicked word is removed and the widget constructs a MPreeditInjection event and sends it to input context. If the event is accepted, e.g. if the error correction is enabled, then the incoming word enclosed in the event is treated as pre-edit. In MInputContext side, upon receiving this event, a QInputMethodEvent will be constructed with the word as a new pre-edit string and sent to the widget. MInputContext will then call im::setPreedit() RPC function to inform the input method about the new pre-edit string. Upon receiving the new pre-edit string, the input method will decide appropriate styling for the pre-edit and call app::sendPreeditString() RPC function. Please note that pre-edit becomes truly active only after input method has called app::sendPreeditString() RPC function. This means that update() will be called only after app::sendPreeditString() RPC function has been called and therefore input method will not know the true state of the widget (e.g. cursor position and surrounding text) before. \subsection Copy_and_paste Copy and paste MInputContext connects itself to widget's signal which called "copyAvailable(bool)" if exists. Whenever this signal is emitted, MInputContext calls im::setCopyPasteButton RPC function [MInputContextDBusConnection::setCopyPasteState?] to update the visibility of Copy/Paste button in the input method's toolbar. If system clipboard has text content, the Paste button is shown instead of Copy button. When the Copy button is clicked, input method calls app::copy RPC function. Upon receiving this call, MInputContext calls widget's "copy" function if available, otherwise it just sends ctrl-c combination key event to the widget. When the Paste button is clicked, input method calls app::paste RPC function. Upon receiving this call, MInputContext calls widget's "paste" function if available, otherwise it just sends ctrl-v combination key event to the widget. \subsection Setting Setting \subsubsection Input_mode Input mode The framework supports two modes: M::InputMethodModeNormal and M::InputMethodModeDirect [MInputContextDBusConnection::inputMethodMode?]. If the widget wants direct key event instead of getting the text using pre-edit/commit string, it can set the mode to M::InputMethodModeDirect, otherwise, the M::InputMethodModeNormal which is the default value will be used at all times. The widget can set the mode by answering the M::ImModeQuery query with the value according to the current mode when asked in inputMethodQuery method. [MTextEdit has the following properties: inputMethodCorrectionEnabled, inputMethodPredictionEnabled, inputMethodAutoCapitalizationEnabled - there is no inputMethodQuery] The input method obtains the current widget's mode by calling app::inputMethodMode RPC function. \subsubsection Autocapitalization Autocapitalization Autocapitalization regarding the input method means that upper case typing shall be activated if: - It starts a sentence - A sentence ends with a punctuation mark ("?!.") and is followed by at least one space [better: "whitespace character", e.g., also newlines?] (detailed behaviour is available from the UI specification) In widget's inputMethodQuery method, the widget returns the status of this feature when asked with M::ImAutoCapitalizationEnabledQuery. The input method can get the widget's autocapitalization state by calling app::autoCapitalizationEnabled RPC function [MTextEdit::inputMethodAutoCapitalizationEnabled]. \subsubsection Error_correction Error correction When the error correction feature is active, the input method always feeds the currently typed word to the error correction driver. Thhe suggested word is then constructed as a pre-edit string. This is done for every update on the input method side, e.g. when a key on the virtual keyboard is pressed. In widget's inputMethodQuery method, the widget returns the status of this feature when asked with M::ImCorrectionEnabledQuery. The input method can get the widget's autocapitalization state by calling app::correctionEnabled RPC function [MTextEdit::inputMethodCorrectionEnabled]. This feature can be disabled/enabled globally according to setting [which?]. The input method can override the state of this feature on the widget side by calling app::setGlobalCorrectionEnabled RPC function. \subsubsection Word_prediction Word prediction This is similar to error correction, but the key/string entered by user will be treated as commit string and the rest of the word predicted by the engine will be treated as pre-edit string. THIS IS NOT (YET) IMPLEMENTED IN INPUT METHOD SIDE. In widget's inputMethodQuery method, the widget returns the status of this feature when asked with M::ImPredictionEnabledQuery. Input method can get the widget's autocapitalization state by calling app::predictionEnabled RPC function [MTextEdit::inputMethodPredictionEnabled]. \subsection Error_correction_candidates Error correction candidates If error correction feature is enabled and mouse clicked is happening on a pre-edit word, then a candidate list of the word shall be displayed on the screen. To do this, in it's mouseHandler MInputContext asks the widget about the pre-edit rectangle by passing M::PreeditRectangleQuery to current focusWidget's inputMethodQuery. MInputContext calls im::mouseClickedOnPreedit RPC along with the rectangle. Input method then decide what to do with that. \subsection Text_entry_types Text entry types The widget can determine its content type. It returns the content type when asked with M::ContentTypeQuery in its inputMethodQuery method. \subsection Toolbar Toolbar The text entry widget can ask the input method to put a custom widget into a toolbar (which will be part of the input method UI). This widget, called "toolbar widget", is essentially a declarative widget written in XML. It is compiled into into a widget by the plugin during the loading of the plugin. Details can be found in the Input Method Toolbar. Toolbar widgets will appear in the toolbar only when instructed by the text entry widget. One use case is rich text editing. The rich text entry could show Bold, Italic, Underline and other buttons to control the rich text editing in the toolbar. The input method shows/hides the toolbar widgets upon receiving events as defined in the toolbar widget's XML data. When an event takes place on a toolbar widget, the input method sends a sequence of actions defined as defined in the XML data. The list below describes the actions and how it is handled by input method: - sendKeySequence: input method constructs key events and process it as described above - sendString: input method sends the word described as commit string - copy: input method asks the widget to copy selected text into clipboard - paste: input method asks the widget to paste from clipboard - sendCommand: input method passes the defined command to app::toolbarWidgetCommand RPC function The widget can change the attributes of an item in toolbar. Except the NAME attribute, all others attributes can be changed by the widget in runtime. To change an attribute, a widget call im::setToolbarItemAttribute() RPC function. The widget can also get the attribute on an item in toolbar by calling im::toolbarItemAttribute() RPC function. \sa toolbar */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/libmaliit.dox000066400000000000000000000012311262307254400235520ustar00rootroot00000000000000/*! @defgroup libmaliit Libmaliit \brief Input method extension library for Qt. Libmaliit is an input method extension library for Qt — use it to add application support for screen rotation and attribute extensions. @section basiclibmaliitusage Basic usage Include the header for the class that you wish to use. For example, if you want to use @ref Maliit::InputMethod "InputMethod": @code #include @endcode Add the libmaliit pkg-config checks to your project's qmake .pro %file: @code CONFIG += link_pkgconfig PKGCONFIG += maliit @endcode Finally, run qmake and build your application in the usual way: @code qmake make @endcode */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/mainpage.dox000066400000000000000000000062731262307254400234000ustar00rootroot00000000000000/*! @mainpage %Maliit Framework Documentation @section intro Introduction %Maliit provides a flexible and cross-platform input method framework. It has a plugin-based client-server architecture where applications act as clients and communicate with the %Maliit server via input context plugins. The communication link currently uses D-Bus. %Maliit is an open source framework (LGPL 2) with open source plugins (BSD). The framework provides two distinct plugin interfaces: - @ref pluginapi "Maliit plugin", for writing input methods such as virtual keyboards or handwriting - %Maliit engine plugin, for writing input method engines used for word prediction and error correction. @if false [ATTENTION: engine interface is not Maliit-fied yet]. * Writing Maliit plugins [LINK] * Writing Maliit engine plugins [LINK] @endif @image html architecture-overview.png The %Maliit @ref architecture provides an abstraction that enables application developers to concentrate on application logic, with the option to extend input method interaction with @ref libmaliitintro, while plugin developers are insulated from applications. Neither plugins nor applications know directly of each other, nor do they have to use the same toolkits. For example, plugins written for Qt or MeeGo Touch applications will work just as well for GTK+ applications, without any modifications. The framework is responsible for switching to specific plugins, depending on the application and device state. For example, when opening a hardware keyboard, %Maliit will automatically search for a HWKB-capable plugin and activate it. Additionally, plugins can trigger a plugin or language layout change. Plugins announce their services via a plugin description interface, the list of languages they support, whether they are on-screen or HWKB plugins (or both). @subsection maliit-fwbasicusage Basic Usage @subsubsection maliit-fwclasses Main classes The following base classes are needed to implement an input method UI plugin: - MAbstractInputMethod : to allow input method server to update input method plugin state - MAbstractInputMethodSettings : to provide settings in control panel - MInputMethodPlugin : to enable the plugin to be loaded by the input method server @subsection general General documentation - Architecture - Extensions to Qt - Plugin System - Feature Internals - Toolbar Widget XML Specification @subsection tutorial Tutorial - How to implement a plugin @section libmaliitintro Libmaliit @ref libmaliit "Libmaliit" is an input method extension library for Qt — use it to add application support for screen rotation and attribute extensions. @subsection libmaliitclasses Useful classes - @ref Maliit::AttributeExtension "AttributeExtension" : Register extensions such as key overrides. - @ref Maliit::InputMethod "InputMethod" : Listen to device orientation, language and raw key events. - @ref Maliit::PreeditInjectionEvent "PreeditInjectionEvent" : Extension for preedit text inside text edits. @section api API reference All Classes */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/maliitserver.dox000066400000000000000000000014131262307254400243140ustar00rootroot00000000000000/*! @defgroup maliitserver Maliit server %Maliit Server is an integration framework that provides interfaces to be implemented by input method UI plugins created by developers. If you are an application developer, you likely want to read the @ref pluginapi documentation instead. Such plugins offer a custom UI to be used in inputting text to text fields in applications. They also buffer and allow on-the-fly modification of text prior to delivery to the application. The included MeeGo Keyboard is an implementation of such a plugin. @note Input method plugins interact with word engine plugins, which can provide them with, for example, modified, alternate or corrected versions of the entered input. For more information, see the libmeegoimengine library introduction. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/meego-im.css000066400000000000000000000212251262307254400233060ustar00rootroot00000000000000body,h1,h2,h3,h4,h5,h6,p,center,td,th,ul,dl,div { font-family: Arial, Geneva, Helvetica, sans-serif; } h1, div.title { text-align: center; font-size: 160%; font-weight: bold; } h2 { font-size: 120%; } h3 { font-size: 100%; } caption { font-weight: bold } div.qindex { width: 100%; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } div.navpath { width: 100%; background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } div.navtab { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } td.navtab { font-size: 70%; } div.qindex { display: none; } a.qindex { text-decoration: none; font-weight: bold; color: #1A419D; } a.qindex:visited { text-decoration: none; font-weight: bold; color: #1A419D } a.qindex:hover { text-decoration: none; background-color: #ddddff; } a.qindexHL { text-decoration: none; font-weight: bold; background-color: #6666cc; color: #ffffff; border: 1px double #9295C2; } a.qindexHL:hover { text-decoration: none; background-color: #6666cc; color: #ffffff; } a.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } a { text-decoration: none; } a.el { text-decoration: none; } a.elRef { font-weight: bold } a.code:link { text-decoration: none; font-weight: normal; color: #0000FF } a.code:visited { text-decoration: none; font-weight: normal; color: #0000FF } a.codeRef:link { font-weight: normal; color: #0000FF } a.codeRef:visited { font-weight: normal; color: #0000FF } a:hover { text-decoration: none; background-color: #f2f2ff } dl.el { margin-left: -1cm } .fragment { font-family: monospace, fixed; font-size: 95%; } pre.fragment { border: 1px solid #CCCCCC; background-color: #f5f5f5; margin-top: 4px; margin-bottom: 4px; margin-left: 2px; margin-right: 8px; padding-left: 6px; padding-right: 6px; padding-top: 4px; padding-bottom: 4px; } div.ah { font-weight: bold; margin-bottom: 5px; margin-top: 5px } div.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold; } div.groupText { margin-left: 16px; font-style: italic; font-size: 90% } body { background: white; color: black; margin-right: 20px; margin-left: 20px; } td.indexkey { -moz-background-clip:border; -moz-background-inline-policy:continuous; -moz-background-origin:padding; background:#F0F0F0 none repeat scroll 0 0; color:black; } td.indexvalue { -moz-background-clip:border; -moz-background-inline-policy:continuous; -moz-background-origin:padding; background:#E4E4E4 none repeat scroll 0 0; color:black; } tr.memlist { background-color: #f0f0f0; } p.formulaDsp { text-align: center; } img.formulaDsp { } img.formulaInl { vertical-align: middle; } span.keyword { color: #008000 } span.keywordtype { color: #604020 } span.keywordflow { color: #e08000 } span.comment { color: #800000 } span.preprocessor { color: #806020 } span.stringliteral { color: #002080 } span.charliteral { color: #008080 } span.vhdldigit { color: #ff00ff } span.vhdlchar { color: #000000 } span.vhdlkeyword { color: #700070 } span.vhdllogic { color: #ff0000 } .mdescLeft { border:1px none #E0E0E0; font-size:100%; margin:4px; padding:2px 0 0 8px; white-space:nowrap; width:180px; } .mdescRight { border:1px none #E0E0E0; font-size:100%; margin:4px; padding:2px 8px 0; } .memItemLeft { border:1px none #E0E0E0; font-size:100%; margin:4px; padding:2px 0 0 8px; white-space:nowrap; width:180px; } .memItemRight { border:1px none #E0E0E0; font-size:100%; margin:4px; padding:2px 8px 0; } .memTemplItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplItemRight { padding: 1px 8px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplParams { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; color: #606060; background-color: #FAFAFA; font-size: 80%; } .search { color: #003399; font-weight: bold; } form.search { margin-bottom: 0px; margin-top: 0px; } input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } td.tiny { font-size: 75%; } a { color: #1A41A8; } a:visited { color: #2A3798; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid #84b0c7; } th.dirtab { background: #e8eef2; font-weight: bold; } hr { border: 0; color: #a0a0a0; background-color: #ccc; height: 1px; width: 100%; text-align: left; margin: 34px 0px 34px 0px; } /* Style for detailed member documentation */ .memtemplate { font-size: 80%; color: #606060; font-weight: normal; margin-left: 3px; } .memnav { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } .memitem { padding: 4px; } .memname { white-space: nowrap; font-weight: bold; font-size: 105%; } .memdoc{ padding-left: 10px; } .memproto { background-color:#EEEEEE; border:1px solid #DDDDDD; font-weight:bold; padding:3px 0 3px 10px; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; } .paramname { font-style: italic; white-space: nowrap; } /* End Styling for detailed member documentation */ /* for the tree view */ .ftvtree { font-family: sans-serif; margin:0.5em; } .directory { font-size: 9pt; font-weight: bold; } .directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } .directory > h3 { margin-top: 0; } .directory p { margin: 0px; white-space: nowrap; } .directory div { display: none; margin: 0px; } .directory img { vertical-align: -30%; } #top { visibility: hidden; display: none; } table.mainIndex { border-spacing: 0px; width: 100%; padding: 0px; background-color: #FAFAFA; border-width: 1px; border-style: solid; border-color: #E0E0E0; } table.mainIndex th { width: 33%; border-width: 1px 0px 1px 0px; padding: 2px; border-style: solid; border-color: #666; color:white; background-color:#555; background-image:url('gradient.png')}; background-repeat: repeat-x; font-size: 100%; } table.mainIndex td { border-style: none; vertical-align: top; padding-top: 1em; } table.qt-style th { background: #96E066; color: black; } table.qt-style { padding-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; border: none; background: none; } table.qt-style tr:nth-child(odd) { background: #e4e4e4; color: black; } table.qt-style tr:nth-child(even) { background: #f0f0f0; color: black; } /* Styles for settings language page */ div.settingsLanguageElement { border-style: solid; border-width: 1px; border-color: #E0E0E0; margin-bottom: 4em; padding: 8px; background-color: #FDFDFD; } div.settingsLanguageElement h2 { background-color: #ffd429; margin-top: 0px; padding: 8px; -moz-border-radius: 8px 8px 8px 8px; } table.settingsLanguageAttributes { border-spacing: 1px; width: 100%; padding: 4px; background-color: #FAFAFA; border-width: 1px; border-style: solid; border-color: #E0E0E0; -moz-border-radius: 8px 8px 8px 8px; } table.settingsLanguageAttributes th { background-color: #dddddd; padding: 4px; border-style: none; -moz-border-radius: 8px 8px 8px 8px; } table.settingsLanguageAttributes td { border-style: none; vertical-align: top; padding-top: 1em; } /* End of styles for settings language page */ td.generator { font-size: 75%; color: #a0a0a0; } maliit-framework-0.99.1+git20151118+62bd54b/doc/src/pluginapi.dox000066400000000000000000000001101262307254400235670ustar00rootroot00000000000000/*! @defgroup pluginapi Plugin API \brief Input method plugin API. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/pluginsystem.dox000066400000000000000000000072561262307254400243640ustar00rootroot00000000000000/*! \page pluginsystem Plugin System \section Overview Overview This document describes the plugin system of MeeGo Input Method Framework. The system consists of: - Plugin manager - Input method connection The whole system is running inside the input method server process. \subsection PluginManager Plugin Manager Plugin Manager is responsible to load the plugins and to activate them. It also activates a specific view of a plugin. \sa MIMPluginManager \subsection InputMethodConnection Input Method Connection Input Method Connection as the name states, functions as the connector between input method server and the application. The connection handles the protocol and data transport between the two ends. \sa MInputContextConnection \section management Plugin Management \subsection Handlers Handlers Handlers are components which handle the input method function. They are essentially plugins and activated by Plugin manager. There are three types of handlers: - On-screen handler, which is used with touchscreen - Hardware keyboard handler, which is used with hardware keyboard (perhaps also external keyboard) - Accessory handler, which is used with other means of input (eg. Bluetooth pens) A single plugin could act as multiple handlers. A plugin has to expose it's handling capabilities so it can be listed in MSettings. User can set a plugin to be the default plugin handling a specific handler by selecting it in MSettings. When a handler is activated, the following will be carried out: - Plugin Manager loads the plugin stated in the settings (see below) and passing the handler code - Plugin Manager rewired the input method connection to the loaded plugin - If plugin does not recognize or incapable to handle the handler code, the loading fails - The plugin update it's UI reflecting the handler code - Record the plugin name to settings \subsection Settings Settings \subsubsection SettingsHandler Handler Plugin Manager selects the active plugin based on the settings. GConf stores the settings of the plugin names which will be selected whenever the handler or language is changed or run in the first time. The settings hierarchy looks like this, where handler is either onscreen or hardware: \code /meegotouch/inputmethods/plugins/ = \endcode \subsection PluginMap Plugin Map When input method server is started, Plugin Manager reads the available plugins in the system and collects the handler information from the plugins. It then generates an in-memory map to be used whenever the handler is changed. The map is refreshed whenever a new plugin is installed or removed. Each handler will have a list of plugins in the map. \subsection PluginChange Plugin Change Plugin Manager subscribes to Context Framework events to change handler. E.g. when Plugin Manager receive a signal from context framework that a keyboard is attached or slided out the Hardware keyboard handler is activated. Plugin Manager then tries to find the plugin from the Settings, and if it fails it tries to find it from the map. If Plugin Manager finds a name from Settings but the plugin is no longer exist it continues to find a new value from the map and clears the Settings for that particular handler. Plugin change could also happen because of user's manual intervention. There are two places where user can change the plugin for a handler: - MSettings: user can select a plugin as handler in the UI - Swipe gesture in On-screen handler: On-screen handler plugin should change it's writing language when receiving swipe gesture. If there is no more language to switch, it should ask Plugin Manager to be replaced with another handler on the map. If there is none, the writing language switching cycles back. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/plugintutorial.dox000066400000000000000000000075241262307254400247010ustar00rootroot00000000000000/*! @page plugintutorial Plugin Tutorial @section intro Introduction This page is a short tutorial about creating your own input method plugin. MeeGo Touch Input Method provides a framework which developers can extend the functionality of the input method by providing a new input method user interface. The new input method is implemented as a plugin. This page shows some excerpts from MeeGo Keyboard source code. @section skeleton Skeleton There are two important parts in the plugin making: the user interface of the input method, which is the part that user interact with while inputting text; and the settings, which is the part that enables user to set preferences on the input method. @subsection ui User interface The UI is loaded and controlled by a MAbstractInputMethod class. @code class MKeyboardHost: public MAbstractInputMethod { Q_OBJECT public: MKeyboardHost(MAbstractInputMethodHost *host, QWidget *mainWindow); virtual ~MKeyboardHost(); ..... @endcode The MAbstractInputMethod itself needs to be loaded by the plugin class, which is a MInputMethodPlugin class. For the plugin system to work, class must declare proper interface using Q_INTERFACES (in the header file) and export the plugin with Q_EXPORT_PLUGIN2 (in the .cpp file): @code // The header file: class MKeyboardPlugin : public QObject, public MInputMethodPlugin { Q_OBJECT Q_INTERFACES(MInputMethodPlugin) public: MKeyboardPlugin(); virtual ~MKeyboardPlugin(); ..... @endcode @code // At the end of the .cpp file: Q_EXPORT_PLUGIN2(meego-keyboard, MKeyboardPlugin) @endcode The UI class is created in the createInputMethod method: @code MAbstractInputMethod * MKeyboardPlugin::createInputMethod(MAbstractInputMethodHost *host, QWidget *mainWindow) { MAbstractInputMethod *inputMethod = new MKeyboardHost(host, mainWindow); return inputMethod; } @endcode The plugin is given a main window that should be used as a parent widget for plugin visualization. Plugin is then free to create a QWidget or QGraphicsView or similar. The interaction between the UI and the application is done by employing functions provided by MAbstractInputMethod and MAbstractInputMethodHost. @subsection settings Settings Settings is basically a QGraphicsWidget which holds items to provide user to set some preferences or behaviour of the input method. It is displayed in the control panel of the system. The settings is created by subclassing MAbstractInputMethodSettings. @code /*! * \brief MKeyboardSettings is the implemetation of meego-keyboard setting. * MKeyboardSettings implement MAbstractInputMethodSettings and create the meego-keyboard * setting. It provides below functionalities: get/set error corretion, get/set word * completion, get/set installed (selected) keyboards. */ class MKeyboardSettings: public QObject, public MAbstractInputMethodSettings { Q_OBJECT public: MKeyboardSettings(); ..... @endcode The actual widget shown is created in MKeyboardSettings::createContentWidget: @code QGraphicsWidget *MKeyboardSettings::createContentWidget(QGraphicsWidget *parent) { // the pointer of returned QGraphicsWidget is owned by the caller, // so we just always create a new containerWidget. return new MKeyboardSettingsWidget(this, parent); } @endcode @section compilation Compilation To use the framework you need to add @c plugin and @c meegoimframework to @c CONFIG variable in your project file. @code CONFIG += plugin meegoimframework @endcode @section installation Installation The plugin is installed to @c /usr/lib/meego-im-plugins directory. Depending on the user interface type, the plugin can be activated programmaticaly by setting the handler GConf key to the name of the plugin. The GConf parent key is @c /meegotouch/inputmethods/plugins/handler. During runtime the plugin can be selected from control panel on the system. */ maliit-framework-0.99.1+git20151118+62bd54b/doc/src/toolbarxml.dox000066400000000000000000000175041262307254400240010ustar00rootroot00000000000000/*! \page toolbarxml Toolbar Widget XML Specification Version: 0.1 \section Overview This document describes the XML specification of the toolbar widget. \sa MToolbarData \section Tags \subsection INPUT-METHOD Root tag, it contains information which should be used by input method plugin. The VERSION attribute defines version of this specification. Current version is 1. Warning: you need to specify version number explicitly, otherwise parser may assume wrong version number and then parsing will fail. The VISIBLE attribute defines toolbar's visibility. Toolbar is visible by default, but you could hide it by setting VISIBLE to false. Warning: normal application should not use this attribute. The REFUSE attribute enumerates names of standard items which should not be added to your toolbar. Names should be separated by commas without spaces. See also "Standard toolbar items". \subsection TOOLBAR It contains the definition for all items in the toolbar. TOOLBAR tag could be used as root tag for backward compatibility. This tag have same attributes as INPUT-METHOD. \subsection ITEMS This tag contains definitions of all items which will be placed into layouts. \subsubsection BUTTON This tag will be constructed as MButton. The NAME attribute is used as a reference in the toolbar system. All buttons with the same NAME share their state. If two buttons have the same name then their state is defined by first one and then overriden (completely or partially) by second one. This feature allows to have consistent button state with different device orientation. All names starting with underscore are reserved for Input Method Framework. Warning: it is not recommended to create more than one button with the same name inside one layout. The GROUP attribute defines the group this button belongs to. The SHOWON attribute tells when the button is displayed. If the value is "selectedtext", it will be only displayed when there is a selected text. If the value is "always" then it is always displayed. Similar rule applies with HIDEON attribute, except that there is no "always" value. Buttons can be aligned within toolbar by using the ALIGNMENT attribute. By default, buttons are center-aligned. Possible other alignments are left or right. The ICON attribute holds the icon file name (absolute file name). The icon will be displayed in the center of the button. The SIZE attribute holds the icon size percentage. The icon will be resized according this attribute and the button size. The ICON_ID attribute holds the icon logical id to be displayed on button. ICON_ID has higher priority than ICON, so if both ICON and ICON_ID are specified, ICON_ID will be used. Note: only the ICON_ID of the icons loaded by meegotouch theme will be used. The TEXT attribute holds the text and TEXT_ID holds the logical id of the text. The TOGGLE attribute defines the type of the button whether it is a toggle button or not, by default the value is false. If the TOGGLE attribute is true, the PRESSED attribute holds the button state whether the button is pressed or not. The HIGHLIGHTED attribute selects which background image should be used. The ENABLED attribute holds whether the button is enabled. Default value is true. If it is set to false, the button will be disabled. The VISIBLE attribute defines the button's visibility. Normally, application does not need to specify this attribute. The button is visible by default, but application could hide it by setting VISIBLE to false. This attribute will override the SHOWON and HIDEON. Text inside button is always center-aligned. \subsubsection LABEL This tag will be constructed as MLabel. LABEL tag could have following attributes: NAME, GROUP, VISIBLE, SHOWON, HIDEON, ALIGMENT, TEXT and TEXT_ID. Every attribute has the same meaning as for BUTTON tag. Text inside labels can be horizontally aligned by using the CONTENT-ALIGNMENT attribute. By default, label text is center-aligned. Possible other content alignments are left or right. \subsubsubsection ACTIONS This tag holds a sequence of actions defined within. \subsubsubsubsection SENDKEYSEQUENCE The tag's value holds the key sequence to be sent in the format which is understood by QKeySequence to the text entry widget. \subsubsubsubsection SENDSTRING The tag's value holds the string to be sent to the text entry widget as committed text. \subsubsubsubsection SENDCOMMAND The tag's value holds the command to be sent to the text entry widget. The command would be widget specific. \subsubsubsubsection SHOWGROUP This tag defines that the action is to show the named group of buttons. \subsubsubsubsection HIDEGROUP This tag defines that the action is to hide the named group of buttons. \subsubsubsubsection COPY This tag defines that the action is to copy selected text. \subsubsubsubsection PASTE This tag defines that the action is to paste from clipboard. \subsubsubsubsection CLOSE This tag defines that the action is to close keyboard and removes focus from active text entry. \subsection Layout Layout describes the actual toolbar layout for a given screen orientation. If the layout doesn't have a portrait variant, the software shall use the landscape variant when the device is in portrait orientation. Each layout contains one row only. \subsubsection Row This tag defines one row in toolbar. It is not recommended to create more than one row for landscape orientation. Row may not be empty. Warning: this tag is deprecated and will be removed soon, because toolbar should have one row only. \subsubsection Item This tag defines which item should be placed into toolbar. NAME attribute selects correspondig item (button or label) which is defined in the Items section. \section Standard toolbar items Button "_close" closes keyboard and removes focus from active text entry. This button is right aligned. Button "_copypaste" copies selected text (if any) or pastes current clipboard content. This button is left aligned. Warning: you can use REFUSE to remove standard toolbar items. But you should not change the attributes of standard toolbar items. \section DTD \code ]> \endcode */ maliit-framework-0.99.1+git20151118+62bd54b/doc/tr.sed000066400000000000000000000000741262307254400214270ustar00rootroot00000000000000s/&/\&\#38\;\#38\;/g s//\&\#x003E\;/g maliit-framework-0.99.1+git20151118+62bd54b/doc/xmlize.pl000077500000000000000000000011371262307254400221560ustar00rootroot00000000000000#!/usr/bin/perl sub xml($) { $buffer = $_[0]; $buffer =~ s/^File: (.*) \(row: (\d+)\) (.*)/\t\\n\t\t$3\n\t\<\/Message\>\n/; return $buffer; } open(FIN,"doxygen.log"); open(FOUT,">doxygen.log.xml"); print FOUT "\n"; $buffer = ""; while () { chop; $row = $_; $row =~ s/&/&#38;/g; $row =~ s//>/g; if ( $row =~ /^File: / ) { if (length($buffer)>0) { print FOUT xml($buffer); $buffer = ""; } $buffer .= $row; } else { $buffer .= $row; } } print FOUT "\n"; close(FIN); close(FOUT); maliit-framework-0.99.1+git20151118+62bd54b/examples/000077500000000000000000000000001262307254400213555ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/README000066400000000000000000000007671262307254400222470ustar00rootroot00000000000000Note that the examples are compiled as part of the normal build, and have simple sanity tests found under tests/ All newly added examples must contain such a test. This is done to prevent bitrot. To make the examples buildable both as a part of the normal framework build, and as a stand-alone examples package, the BUILD_TYPE is used. The value "unittest" means normal framework build, and "skeleton" means stand-alone. When not in unittest mode, the build cannot refer to directories below examples/ maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/000077500000000000000000000000001262307254400223205ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/apps.pro000066400000000000000000000000461262307254400240050ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = plainqt maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/plainqt/000077500000000000000000000000001262307254400237705ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/plainqt/.gitignore000066400000000000000000000000421262307254400257540ustar00rootroot00000000000000maliit-exampleapp-plainqt plainqt maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/plainqt/mainwindow.cpp000066400000000000000000000135731262307254400266610ustar00rootroot00000000000000#include "mainwindow.h" #include #include #include #include #include #include namespace { const char * const TextPrompt = "Double-click this text area to invoke virtual keyboard ..."; const QString serverName("maliit-server"); //TODO: when maliit and example application is split out, look up in .pc file bool enableFullScreenMode() { return (qApp->arguments().contains("-fullscreen")); } } // namespace class MyTextEdit : public QTextEdit { private: bool was_focused; public: MyTextEdit() : QTextEdit(TextPrompt) , was_focused(false) {} protected: void focusInEvent(QFocusEvent *e) { toPlainText(); // On first text edit, clear pre-set TextPrompt: if (not was_focused && toPlainText() == QString(TextPrompt)) { was_focused = true; setText(""); } QTextEdit::focusInEvent(e); } }; MainWindow::MainWindow() : QMainWindow() , m_server_process(new QProcess(this)) , m_orientation_index(0) , m_grid_row(0) , m_grid(new QGridLayout) , m_start_server(new QPushButton) , m_rotate_keyboard(new QPushButton("Rotate input method")) { m_server_process->setProcessChannelMode(QProcess::ForwardedChannels); connect(m_server_process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(onServerStateChanged())); connect(m_start_server, SIGNAL(clicked()), this, SLOT(onStartServerClicked())); connect(m_rotate_keyboard, SIGNAL(clicked()), this, SLOT(onRotateKeyboardClicked())); initUI(); onServerStateChanged(); // Work around a bug in maliit input method support where primary orientation is always portrait windowHandle()->reportContentOrientationChange(windowHandle()->screen()->primaryOrientation()); } void MainWindow::initUI() { setWindowTitle("Maliit test application"); m_grid_row = 0; QHBoxLayout *buttons = new QHBoxLayout; buttons->addWidget(m_start_server); buttons->addWidget(m_rotate_keyboard); // Clicking the button will steal focus from the text edit, thus hiding // the virtual keyboard: buttons->addWidget(new QPushButton("Dismiss input method")); m_grid->addLayout(buttons, m_grid_row, 1); ++m_grid_row; // multi line: QLabel *label = 0; QTextEdit *entry = 0; m_grid->addWidget(label = new QLabel("multi line"), m_grid_row, 0); m_grid->addWidget(entry = new QTextEdit, m_grid_row, 1); ++m_grid_row; label->setToolTip("Qt::ImhNone"); entry->setInputMethodHints(Qt::ImhNone); entry->installEventFilter(this); // single line, emulating content types via Qt::InputMethodHints: insertIntoGrid("single line", Qt::ImhNone, "Qt::ImhNone"); insertIntoGrid("password", Qt::ImhHiddenText|Qt::ImhNoPredictiveText, "Qt::ImhHiddenText|Qt::ImhNoPredictiveText"); insertIntoGrid("numbers only", Qt::ImhFormattedNumbersOnly, "Qt::ImhFormattedNumbersOnly"); insertIntoGrid("dialer input", Qt::ImhDialableCharactersOnly, "Qt::ImhDialableCharactersOnly"); insertIntoGrid("symbol view", Qt::ImhPreferNumbers, "Qt::ImhPreferNumbers"); insertIntoGrid("e-mail", Qt::ImhEmailCharactersOnly, "Qt::ImhEmailCharactersOnly"); insertIntoGrid("website", Qt::ImhUrlCharactersOnly, "Qt::ImhUrlCharactersOnly"); // Don't want other buttons to steal focus: m_start_server->setFocusPolicy(Qt::NoFocus); m_rotate_keyboard->setFocusPolicy(Qt::NoFocus); QPushButton *close_app = new QPushButton("Close application"); m_grid->addWidget(close_app, m_grid_row, 1); ++m_grid_row; connect(close_app, SIGNAL(clicked()), this, SLOT(close())); setCentralWidget(new QWidget); centralWidget()->setLayout(m_grid); if (enableFullScreenMode()) { showFullScreen(); } else { show(); } } void MainWindow::insertIntoGrid(const QString &description, const Qt::InputMethodHints &hints, const QString &tooltip) { QLabel *label = 0; QLineEdit *entry = 0; m_grid->addWidget(label = new QLabel(description), m_grid_row, 0); m_grid->addWidget(entry = new QLineEdit, m_grid_row, 1); ++m_grid_row; label->setToolTip(tooltip); entry->setInputMethodHints(hints); entry->installEventFilter(this); } MainWindow::~MainWindow() { m_server_process->terminate(); } bool MainWindow::eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched) // Let the input method show up on focus-in, not on second click: if (event->type() == QFocusEvent::FocusIn) { qApp->inputMethod()->show(); } return false; } void MainWindow::onStartServerClicked() { if (m_server_process->state() != QProcess::NotRunning) { m_server_process->terminate(); } else { m_server_process->start(serverName, QStringList()); } } void MainWindow::onServerStateChanged() { switch (m_server_process->state()) { case QProcess::Running: m_start_server->setText("(running) Stop input method server"); break; case QProcess::Starting: m_start_server->setText("(starting) Stop input method server"); break; case QProcess::NotRunning: m_start_server->setText("(stopped) Start input method server"); break; default: break; } } void MainWindow::onRotateKeyboardClicked() { ++m_orientation_index; static const Qt::ScreenOrientation orientations[] = { Qt::LandscapeOrientation, Qt::PortraitOrientation, Qt::InvertedLandscapeOrientation, Qt::InvertedPortraitOrientation }; windowHandle()->reportContentOrientationChange(orientations[m_orientation_index % 4]); } maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/plainqt/mainwindow.h000066400000000000000000000021031262307254400263110ustar00rootroot00000000000000#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include #include class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(); virtual ~MainWindow(); bool eventFilter(QObject *watched, QEvent *event); private: Q_SLOT void onStartServerClicked(); Q_SLOT void onRotateKeyboardClicked(); Q_SLOT void onServerStateChanged(); private: void initUI(); void insertIntoGrid(const QString &description, const Qt::InputMethodHints &hints, const QString &tooltip = QString()); QProcess *m_server_process; int m_orientation_index; int m_grid_row; QGridLayout *const m_grid; QPushButton *const m_start_server; QPushButton *const m_rotate_keyboard; }; #endif // MAINWINDOW_H maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/plainqt/plainqt.cpp000066400000000000000000000012031262307254400261400ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mainwindow.h" #include int main(int argc, char** argv) { QApplication kit(argc, argv); MainWindow window; return kit.exec(); } maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/plainqt/plainqt.pro000066400000000000000000000020011262307254400261530ustar00rootroot00000000000000TEMPLATE = app TARGET = maliit-exampleapp-plainqt OBJECTS_DIR = .obj MOC_DIR = .moc DEPENDPATH += . BUILD_TYPE = unittest !contains(QT_MAJOR_VERSION, 5) { contains(BUILD_TYPE, skeleton) { CONFIG += link_pkgconfig PKGCONFIG += maliit INCLUDEPATH += $$system(pkg-config --cflags maliit | tr \' \' \'\\n\' | grep ^-I | cut -d I -f 2-) } } contains(BUILD_TYPE, unittest) { include(../../../config.pri) target.path = $$BINDIR INSTALLS += target !contains(QT_MAJOR_VERSION, 5) { # Used for testing purposes, can be deleted when used as a project skeleton # Build against in-tree libs TOP_DIR = ../../.. include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/maliit/libmaliit.pri) } } SOURCES += \ plainqt.cpp \ mainwindow.cpp \ HEADERS += \ mainwindow.h \ contains(QT_MAJOR_VERSION, 4) { QT += core gui } else { QT += core gui widgets } QMAKE_CLEAN += maliit-exampleapp-plainqt maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/qml/000077500000000000000000000000001262307254400231115ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/apps/qml/enterKeyCustomization.qml000066400000000000000000000005231262307254400302030ustar00rootroot00000000000000import QtQuick 2.0 Rectangle { width: 854 height: 486 color: "grey" TextInput { width: parent.width height: 50 font.pixelSize: 50 focus: true property variant __inputMethodExtensions: { 'enterKeyText': 'Enter', 'enterKeyHighlighted': true } } } maliit-framework-0.99.1+git20151118+62bd54b/examples/examples.pro000066400000000000000000000000521262307254400237120ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = apps plugins maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/000077500000000000000000000000001262307254400230365ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/000077500000000000000000000000001262307254400236405ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/cxx.pro000066400000000000000000000000611262307254400251610ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = helloworld override maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/000077500000000000000000000000001262307254400260135ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/helloworld.pro000066400000000000000000000022061262307254400307100ustar00rootroot00000000000000TEMPLATE = lib TARGET = cxxhelloworldplugin OBJECTS_DIR = .obj MOC_DIR = .moc CONFIG += debug plugin contains(QT_MAJOR_VERSION, 4) { QT += core gui } else { QT += core gui widgets } HEADERS += \ helloworldplugin.h \ helloworldinputmethod.h \ SOURCES += \ helloworldplugin.cpp \ helloworldinputmethod.cpp \ OTHER_FILES += \ helloworldplugin.json \ BUILD_TYPE = unittest contains(BUILD_TYPE, skeleton) { CONFIG += link_pkgconfig PKGCONFIG += maliit-plugins target.path += $$system(pkg-config --variable pluginsdir maliit-plugins) INCLUDEPATH += $$system(pkg-config --cflags maliit-plugins | tr \' \' \'\\n\' | grep ^-I | cut -d I -f 2-) INSTALLS += target } contains(BUILD_TYPE, unittest) { # Used for testing purposes, can be deleted when used as a project skeleton # Build against in-tree libs TOP_DIR = ../../../.. include($$TOP_DIR/config.pri) include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) target.path += $$MALIIT_TEST_PLUGINS_DIR/examples/cxx/helloworld INSTALLS += target } QMAKE_CLEAN += libcxxhelloworldplugin.so helloworldinputmethod.cpp000066400000000000000000000135511262307254400331010ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "helloworldinputmethod.h" #include #include #include #include namespace { const char * const exampleSubViewId("HelloWorldPluginSubview1"); class Surface : public QWidget { public: Surface(MAbstractInputMethodHost *host); }; Surface::Surface (MAbstractInputMethodHost *host) : QWidget() { host->registerWindow(windowHandle(), Maliit::PositionCenterBottom); setAutoFillBackground(false); setBackgroundRole(QPalette::NoRole); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } } HelloWorldInputMethod::HelloWorldInputMethod(MAbstractInputMethodHost *host) : MAbstractInputMethod(host) , surface(new Surface(host)) , mainWidget(new QPushButton(surface.data())) , showIsInhibited(false) , showRequested(false) { // Register setting QVariantMap buttonTextAttributes; buttonTextAttributes[Maliit::SettingEntryAttributes::defaultValue] = "Hello World!"; buttonText.reset(host->registerPluginSetting("button_text", QT_TR_NOOP("Button text"), Maliit::StringType, buttonTextAttributes)); connect(buttonText.data(), SIGNAL(valueChanged()), this, SLOT(handleButtonTextChanged())); // Set up UI mainWidget->setText(buttonText->value().toString()); connect(mainWidget, SIGNAL(clicked()), this, SLOT(handleButtonClicked())); // Used only for unittest/sanity test inputMethodHost()->sendCommitString("Maliit"); inputMethodHost()->sendPreeditString("Mali", QList(), 0, 6); } HelloWorldInputMethod::~HelloWorldInputMethod() {} // Slot for our Hello World button void HelloWorldInputMethod::handleButtonClicked() { inputMethodHost()->sendCommitString(mainWidget->text()); } void HelloWorldInputMethod::handleButtonTextChanged() { mainWidget->setText(buttonText->value().toString()); } void HelloWorldInputMethod::show() { showRequested = true; if (showIsInhibited) { return; } // Set size of our container to screen size const QSize screenSize = QApplication::desktop()->screenGeometry().size(); mainWidget->parentWidget()->resize(screenSize); // Set size of the input method const QRect imGeometry(0, screenSize.height() - 200, screenSize.width(), 200); mainWidget->setGeometry(imGeometry); // Tell input method server about our size inputMethodHost()->setScreenRegion(QRegion(mainWidget->geometry())); inputMethodHost()->setInputMethodArea(QRegion(mainWidget->geometry())); mainWidget->show(); } void HelloWorldInputMethod::hide() { if (!showRequested) { return; } showRequested = false; mainWidget->hide(); inputMethodHost()->setScreenRegion(QRegion()); inputMethodHost()->setInputMethodArea(QRegion()); } QList HelloWorldInputMethod::subViews(Maliit::HandlerState state) const { QList subViews; if (state == Maliit::OnScreen) { MAbstractInputMethod::MInputMethodSubView subView1; subView1.subViewId = exampleSubViewId; subView1.subViewTitle = "Example plugin subview 1"; subViews.append(subView1); } return subViews; } QString HelloWorldInputMethod::activeSubView(Maliit::HandlerState state) const { QString subView = (state == Maliit::OnScreen) ? exampleSubViewId : ""; return subView; } void HelloWorldInputMethod::setState(const QSet &state) { if (state.contains(Maliit::OnScreen)) { if (showRequested && !showIsInhibited) { mainWidget->show(); } } else { mainWidget->hide(); } } void HelloWorldInputMethod::handleClientChange() { if (showRequested) { hide(); } } void HelloWorldInputMethod::handleVisualizationPriorityChange(bool inhibitShow) { if (showIsInhibited == inhibitShow) { return; } showIsInhibited = inhibitShow; if (showRequested) { if (inhibitShow) { mainWidget->hide(); } else { mainWidget->show(); } } } void HelloWorldInputMethod::handleAppOrientationAboutToChange(int angle) { // Rotate your input method UI here Q_UNUSED(angle); } void HelloWorldInputMethod::handleAppOrientationChanged(int angle) { // Can typically be forwarded to handleAppOrientationAboutToChange // as long as that method will not do anything when newAngle == previousAngle Q_UNUSED(angle); } void HelloWorldInputMethod::update() { // empty default implementation } void HelloWorldInputMethod::reset() { // empty default implementation } void HelloWorldInputMethod::handleFocusChange(bool focusIn) { // empty default implementation Q_UNUSED(focusIn); } void HelloWorldInputMethod::switchContext(Maliit::SwitchDirection direction, bool enableAnimation) { // empty default implementation Q_UNUSED(direction); Q_UNUSED(enableAnimation); } void HelloWorldInputMethod::setPreedit(const QString &preeditString, int cursorPos) { // empty default implementation Q_UNUSED(preeditString); Q_UNUSED(cursorPos); } void HelloWorldInputMethod::setActiveSubView(const QString &subViewId, Maliit::HandlerState state) { // Ignored as input method only support one subview Q_UNUSED(subViewId); Q_UNUSED(state); } maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/helloworldinputmethod.h000066400000000000000000000060221262307254400326200ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef HELLO_WORLD_INPUT_METHOD_H #define HELLO_WORLD_INPUT_METHOD_H #include #include #include #include #include #include class HelloWorldInputMethod : public MAbstractInputMethod { Q_OBJECT public: HelloWorldInputMethod(MAbstractInputMethodHost *host); ~HelloWorldInputMethod(); //! \reimp /* Mandatory */ virtual void show(); virtual void hide(); virtual void handleVisualizationPriorityChange(bool priority); virtual void handleClientChange(); virtual void handleAppOrientationAboutToChange(int angle); virtual void handleAppOrientationChanged(int angle); virtual QList subViews(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void setActiveSubView(const QString &subViewId, Maliit::HandlerState state = Maliit::OnScreen); virtual QString activeSubView(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void setState(const QSet &state); /* Optional, often used */ virtual void update(); virtual void reset(); virtual void switchContext(Maliit::SwitchDirection direction, bool enableAnimation); virtual void handleFocusChange(bool focusIn); virtual void setPreedit(const QString &preeditString, int cursorPos); /* Optional, rarely used */ /* Using default implementations virtual bool imExtensionEvent(MImExtensionEvent *event); virtual void showLanguageNotification(); virtual void setKeyOverrides(const QMap > &overrides); virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); virtual void setKeyOverrides(const QMap > &overrides); virtual void handleMouseClickOnPreedit(const QPoint &pos, const QRect &preeditRect); */ //! \reimp_end private Q_SLOTS: void handleButtonClicked(); void handleButtonTextChanged(); private: QScopedPointer surface; QScopedPointer buttonText; QPushButton *mainWidget; bool showIsInhibited; bool showRequested; }; #endif // HELLO_WORLD_INPUT_METHOD_H maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/helloworldplugin.cpp000066400000000000000000000021721262307254400321130ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "helloworldplugin.h" #include "helloworldinputmethod.h" #include #include HelloWorldPlugin::HelloWorldPlugin() { /* This helloworld plugin is an on screen input method */ allowedStates << Maliit::OnScreen; } QString HelloWorldPlugin::name() const { return "HelloWorldPlugin"; } MAbstractInputMethod * HelloWorldPlugin::createInputMethod(MAbstractInputMethodHost *host) { return new HelloWorldInputMethod(host); } QSet HelloWorldPlugin::supportedStates() const { return allowedStates; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(cxxhelloworldplugin, HelloWorldPlugin) #endif maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/helloworldplugin.h000066400000000000000000000027201262307254400315570ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef HELLO_WORLD_PLUGIN_H #define HELLO_WORLD_PLUGIN_H #include #include #include // TODO: Licence. We need a license that leaves no doubt this code can be used for any purpose //! Example input method plugin that can be used as a base when developing new input method plugins class HelloWorldPlugin: public QObject, public Maliit::Plugins::InputMethodPlugin { Q_OBJECT Q_INTERFACES(Maliit::Plugins::InputMethodPlugin) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.maliit.examples.cxx.helloworldplugin" FILE "helloworldplugin.json") #endif public: HelloWorldPlugin(); //! \reimp virtual QString name() const; virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host); virtual QSet supportedStates() const; //! \reimp_end private: QSet allowedStates; }; #endif // HELLO_WORLD_PLUGIN_H maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/helloworld/helloworldplugin.json000066400000000000000000000000001262307254400322660ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/000077500000000000000000000000001262307254400254575ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/override.pro000066400000000000000000000021601262307254400300170ustar00rootroot00000000000000TEMPLATE = lib TARGET = cxxoverrideplugin OBJECTS_DIR = .obj MOC_DIR = .moc CONFIG += debug plugin contains(QT_MAJOR_VERSION, 4) { QT += core gui } else { QT += core gui widgets } HEADERS += \ overrideplugin.h \ overrideinputmethod.h \ SOURCES += \ overrideplugin.cpp \ overrideinputmethod.cpp \ OTHER_FILES += \ override.json \ BUILD_TYPE = unittest contains(BUILD_TYPE, skeleton) { CONFIG += link_pkgconfig PKGCONFIG += maliit-plugins target.path += $$system(pkg-config --variable pluginsdir maliit-plugins) INCLUDEPATH += $$system(pkg-config --cflags maliit-plugins | tr \' \' \'\\n\' | grep ^-I | cut -d I -f 2-) INSTALLS += target } contains(BUILD_TYPE, unittest) { # Used for testing purposes, can be deleted when used as a project skeleton # Build against in-tree libs TOP_DIR = ../../../.. include($$TOP_DIR/config.pri) include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) target.path += $$MALIIT_TEST_PLUGINS_DIR/examples/cxx/override INSTALLS += target } QMAKE_CLEAN += libcxxoverrideplugin.so maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/overrideinputmethod.cpp000066400000000000000000000167441262307254400322770ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "overrideinputmethod.h" #include #include #include #include #include namespace { const char * const overrideSubViewId("OverridePluginSubview1"); const char * const actionKeyName = "actionKey"; const char * const actionKeyLabel = "Enter"; class Surface : public QWidget { public: Surface(MAbstractInputMethodHost *host); }; Surface::Surface (MAbstractInputMethodHost *host) : QWidget() { host->registerWindow(windowHandle(), Maliit::PositionCenterBottom); setAutoFillBackground(false); setBackgroundRole(QPalette::NoRole); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } } OverrideInputMethod::OverrideInputMethod(MAbstractInputMethodHost *host) : MAbstractInputMethod(host) , surface(new Surface(host)) , mainWidget(new QPushButton(surface.data())) , showIsInhibited(false) , showRequested(false) , activeActionKeyOverride() { // Set up UI mainWidget->setText(actionKeyLabel); connect(mainWidget, SIGNAL(clicked()), this, SLOT(handleButtonClicked())); // Used only for unittest/sanity test inputMethodHost()->sendCommitString("Maliit"); inputMethodHost()->sendPreeditString("Mali", QList(), 0, 6); mainWidget->show(); } OverrideInputMethod::~OverrideInputMethod() {} // Slot for our action key void OverrideInputMethod::handleButtonClicked() { const QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); inputMethodHost()->sendKeyEvent(event); } void OverrideInputMethod::show() { showRequested = true; if (showIsInhibited) { return; } // Set size of the input method const QSize &screenSize = QApplication::desktop()->screenGeometry().size(); const QSize size(screenSize.width() - 200, 200); surface->setGeometry(QRect(QPoint((screenSize.width() - size.width()) / 2, screenSize.height() - size.height()), size)); mainWidget->resize(mainWidget->parentWidget()->size()); surface->show(); } void OverrideInputMethod::hide() { if (!showRequested) { return; } showRequested = false; surface->hide(); } QList OverrideInputMethod::subViews(Maliit::HandlerState state) const { QList subViews; if (state == Maliit::OnScreen) { MAbstractInputMethod::MInputMethodSubView subView1; subView1.subViewId = overrideSubViewId; subView1.subViewTitle = "Override plugin subview 1"; subViews.append(subView1); } return subViews; } QString OverrideInputMethod::activeSubView(Maliit::HandlerState state) const { QString subView = (state == Maliit::OnScreen) ? overrideSubViewId : ""; return subView; } void OverrideInputMethod::setState(const QSet &state) { if (state.contains(Maliit::OnScreen)) { if (showRequested && !showIsInhibited) { surface->show(); } } else { surface->hide(); } } void OverrideInputMethod::handleClientChange() { if (showRequested) { hide(); } } void OverrideInputMethod::handleVisualizationPriorityChange(bool inhibitShow) { if (showIsInhibited == inhibitShow) { return; } showIsInhibited = inhibitShow; if (showRequested) { if (inhibitShow) { surface->hide(); } else { surface->show(); } } } void OverrideInputMethod::handleAppOrientationAboutToChange(int angle) { // Rotate your input method UI here Q_UNUSED(angle); } void OverrideInputMethod::handleAppOrientationChanged(int angle) { // Can typically be forwarded to handleAppOrientationAboutToChange // as long as that method will not do anything when newAngle == previousAngle Q_UNUSED(angle); } void OverrideInputMethod::update() { // empty default implementation } void OverrideInputMethod::reset() { // empty default implementation } void OverrideInputMethod::handleFocusChange(bool focusIn) { // empty default implementation Q_UNUSED(focusIn); } void OverrideInputMethod::switchContext(Maliit::SwitchDirection direction, bool enableAnimation) { // empty default implementation Q_UNUSED(direction); Q_UNUSED(enableAnimation); } void OverrideInputMethod::setPreedit(const QString &preeditString, int cursorPos) { // empty default implementation Q_UNUSED(preeditString); Q_UNUSED(cursorPos); } void OverrideInputMethod::setActiveSubView(const QString &subViewId, Maliit::HandlerState state) { // Ignored as input method only support one subview Q_UNUSED(subViewId); Q_UNUSED(state); } void OverrideInputMethod::setKeyOverrides(const QMap > &overrides) { if (activeActionKeyOverride) { disconnect(activeActionKeyOverride.data(), SIGNAL(keyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes)), this, SLOT(onKeyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes))); activeActionKeyOverride.clear(); } QMap >::const_iterator actionKeyOverrideIter(overrides.find(actionKeyName)); if (actionKeyOverrideIter != overrides.end()) { QSharedPointer overrideShared = *actionKeyOverrideIter; if (overrideShared) { connect(overrideShared.data(), SIGNAL(keyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes)), this, SLOT(onKeyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes))); activeActionKeyOverride = overrideShared; } } updateActionKey(MKeyOverride::All); } void OverrideInputMethod::onKeyAttributesChanged(const QString &keyId, const MKeyOverride::KeyOverrideAttributes changedAttributes) { if (keyId == actionKeyName) { updateActionKey(changedAttributes); } } void OverrideInputMethod::updateActionKey (const MKeyOverride::KeyOverrideAttributes changedAttributes) { const bool useKeyOverride(activeActionKeyOverride); if (changedAttributes & MKeyOverride::Label) { bool useDefault(false); if (useKeyOverride) { const QString label(activeActionKeyOverride->label()); if (label.isEmpty()) { useDefault = true; } else { mainWidget->setText(label); } } else { useDefault = true; } if (useDefault) { mainWidget->setText(actionKeyLabel); } } if (changedAttributes & MKeyOverride::Icon) { // maybe later } if (changedAttributes & MKeyOverride::Highlighted) { // maybe later } if (changedAttributes & MKeyOverride::Enabled) { // maybe later } } maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/overrideinputmethod.h000066400000000000000000000062161262307254400317350ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef OVERRIDE_INPUT_METHOD_H #define OVERRIDE_INPUT_METHOD_H #include #include #include #include #include #include class OverrideInputMethod : public MAbstractInputMethod { Q_OBJECT public: OverrideInputMethod(MAbstractInputMethodHost *host); ~OverrideInputMethod(); //! \reimp /* Mandatory */ virtual void show(); virtual void hide(); virtual void handleVisualizationPriorityChange(bool priority); virtual void handleClientChange(); virtual void handleAppOrientationAboutToChange(int angle); virtual void handleAppOrientationChanged(int angle); virtual QList subViews(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void setActiveSubView(const QString &subViewId, Maliit::HandlerState state = Maliit::OnScreen); virtual QString activeSubView(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void setState(const QSet &state); /* Optional, often used */ virtual void update(); virtual void reset(); virtual void switchContext(Maliit::SwitchDirection direction, bool enableAnimation); virtual void handleFocusChange(bool focusIn); virtual void setPreedit(const QString &preeditString, int cursorPos); virtual void setKeyOverrides(const QMap > &overrides); /* Optional, rarely used */ /* Using default implementations virtual bool imExtensionEvent(MImExtensionEvent *event); virtual void showLanguageNotification(); virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); virtual void handleMouseClickOnPreedit(const QPoint &pos, const QRect &preeditRect); */ //! \reimp_end private Q_SLOTS: void handleButtonClicked(); void onKeyAttributesChanged(const QString &keyId, const MKeyOverride::KeyOverrideAttributes changedAttributes); private: void updateActionKey(const MKeyOverride::KeyOverrideAttributes changedAttributes); QScopedPointer surface; QPushButton *mainWidget; bool showIsInhibited; bool showRequested; QSharedPointer activeActionKeyOverride; }; #endif // OVERRIDE_INPUT_METHOD_H maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/overrideplugin.cpp000066400000000000000000000021421262307254400312200ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "overrideplugin.h" #include "overrideinputmethod.h" #include #include OverridePlugin::OverridePlugin() { /* This override plugin is an on screen input method */ allowedStates << Maliit::OnScreen; } QString OverridePlugin::name() const { return "OverridePlugin"; } MAbstractInputMethod * OverridePlugin::createInputMethod(MAbstractInputMethodHost *host) { return new OverrideInputMethod(host); } QSet OverridePlugin::supportedStates() const { return allowedStates; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(cxxoverrideplugin, OverridePlugin) #endif maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/overrideplugin.h000066400000000000000000000027001262307254400306650ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef OVERRIDE_PLUGIN_H #define OVERRIDE_PLUGIN_H #include #include #include // TODO: Licence. We need a license that leaves no doubt this code can be used for any purpose //! Override input method plugin that can be used as a base when developing new input method plugins class OverridePlugin: public QObject, public Maliit::Plugins::InputMethodPlugin { Q_OBJECT Q_INTERFACES(Maliit::Plugins::InputMethodPlugin) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.maliit.examples.cxx.overrideplugin" FILE "overrideplugin.json") #endif public: OverridePlugin(); //! \reimp virtual QString name() const; virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host); virtual QSet supportedStates() const; //! \reimp_end private: QSet allowedStates; }; #endif // OVERRIDE_PLUGIN_H maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/cxx/override/overrideplugin.json000066400000000000000000000000001262307254400313760ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/plugins.pro000066400000000000000000000000451262307254400252400ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = cxx qml maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/000077500000000000000000000000001262307254400236275ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/.gitignore000066400000000000000000000000061262307254400256130ustar00rootroot00000000000000qrc_* maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/000077500000000000000000000000001262307254400256225ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/CycleKey.qml000066400000000000000000000067731262307254400300620ustar00rootroot00000000000000/* * This file is part of meego-im-framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (directui@nokia.com) * * If you have questions regarding the use of this file, please contact * Nokia at directui@nokia.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ import QtQuick 2.0 Rectangle { /* * Use two properties for each key, one that contains all available labels, * one for the index. * Bind the key's label to the currently active cycle label (denoted by * index) and keep looping through the range of available labels. */ property variant cycle: {} property int index: 0 property string localPreeditBuffer: label.text property bool doubleClick: false width: 80 height: 60 border.width: 2 border.color: "black" color: "blue" // The key label, the displayed text is controlled through the cycle index. Text { id: label text: cycle[index] color: "white" font.pointSize: 20 anchors.centerIn: parent } // This timer resets key's background color to default ("blue"). Timer { id: resetTimeout interval: 100 repeat: false onTriggered: { parent.color = "blue" } } // This timer decides whether to commit current cycle key to application's // focus widget. Timer { id: commitTimeout interval: 500 repeat: false onTriggered: { doubleClick = false if (preeditBuffer.length > 0) parent.color = "orange" resetTimeout.restart() // Once committed, the preedit cannot be edited anymore: MInputMethodQuick.sendCommit(preeditBuffer) index = 0 preeditBuffer = "" } } MouseArea { anchors.fill: parent onPressed: { // Give a visual hint that this key is pressed: parent.color = "black" commitTimeout.stop // Commit current preedit buffer, if set by other key: if (preeditBuffer.length > 0 && localPreeditBuffer != preeditBuffer) MInputMethodQuick.sendCommit(preeditBuffer) localPreeditBuffer = "" preeditBuffer = "" // Change key's label if double click was detected: if (doubleClick) { index = cycle.length > 0 ? (index + 1) % cycle.length : 0 } doubleClick = true } onClicked: { // Change back key background color to default, as key was // released: parent.color = "blue" // Store label in (global) preedit buffer, save copy in local // buffer to decide whether preedit buffer was set by this key: preeditBuffer = label.text localPreeditBuffer = preeditBuffer // Send an updated string to application, called "preedit". It is // not committed yet and therefore can still be edited by the input // method plugin: MInputMethodQuick.sendPreedit(preeditBuffer) commitTimeout.restart() } } } maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/cyclekeys.pro000066400000000000000000000023701262307254400303410ustar00rootroot00000000000000TEMPLATE = lib TARGET = qmlcyclekeysplugin OBJECTS_DIR = .obj MOC_DIR = .moc CONFIG += debug plugin contains(QT_MAJOR_VERSION, 4) { QT = core gui declarative } else { QT = core gui widgets declarative } SOURCES += cyclekeysplugin.cpp HEADERS += cyclekeysplugin.h RESOURCES = cyclekeys.qrc OTHER_FILES += \ main.qml \ CycleKey.qml \ target.depends = $${PWD}/main.qml $${PWD}/CycleKey.qml BUILD_TYPE = unittest contains(BUILD_TYPE, skeleton) { CONFIG += link_pkgconfig PKGCONFIG += maliit-plugins-quick target.path += $$system(pkg-config --variable pluginsdir maliit-plugins) INCLUDEPATH += $$system(pkg-config --cflags maliit-plugins-quick | tr \' \' \'\\n\' | grep ^-I | cut -d I -f 2-) INSTALLS += target } contains(BUILD_TYPE, unittest) { # Used for testing purposes, can be deleted when used as a project skeleton # Build against in-tree libs TOP_DIR = ../../../.. include($$TOP_DIR/config.pri) include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) include($$TOP_DIR/maliit-plugins-quick/libmaliit-plugins-quick.pri) target.path += $$MALIIT_TEST_PLUGINS_DIR/examples/qml/cyclekeys INSTALLS += target } QMAKE_CLEAN += libqmlcyclekeysplugin.so maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/cyclekeys.qrc000066400000000000000000000001551262307254400303250ustar00rootroot00000000000000 main.qml CycleKey.qml maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/cyclekeysplugin.cpp000066400000000000000000000016171262307254400315450ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "cyclekeysplugin.h" #include #include namespace { const char * const filePath = "qrc:/main.qml"; const char * const pluginName = "CycleKeys"; } CycleKeys::CycleKeys() { Q_INIT_RESOURCE(cyclekeys); } QString CycleKeys::name() const { return pluginName; } QString CycleKeys::qmlFileName() const { return filePath; } Q_EXPORT_PLUGIN2(qmlcyclekeysplugin, CycleKeys) maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/cyclekeysplugin.h000066400000000000000000000016331262307254400312100ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef CYCLE_KEYS_PLUGIN_H #define CYCLE_KEYS_PLUGIN_H #include #include class CycleKeys : public QObject, public MInputMethodQuickPlugin { Q_OBJECT Q_INTERFACES(MInputMethodQuickPlugin Maliit::Plugins::InputMethodPlugin) public: CycleKeys(); //! \reimpl virtual QString name() const; virtual QString qmlFileName() const; //! \reimpl_end }; #endif // CYCLE_KEYS_PLUGIN_H maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/cyclekeys/main.qml000066400000000000000000000035701262307254400272660ustar00rootroot00000000000000/* * This file is part of meego-im-framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (directui@nokia.com) * * If you have questions regarding the use of this file, please contact * Nokia at directui@nokia.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ import QtQuick 2.0 Rectangle { id: canvas width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight color: "transparent" property string preeditBuffer Rectangle { id: imArea color: "grey" width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight * 0.5 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter Row { spacing: 6 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter CycleKey { id: key0 cycle: ["A", "b", "C"] } CycleKey { id: key1 cycle: ["1", "2", "3"] } CycleKey { id: key2 cycle: ["#", "?", "!"] } } } Component.onCompleted: { MInputMethodQuick.setInputMethodArea(Qt.rect(0, MInputMethodQuick.screenHeight - imArea.height, imArea.width, imArea.height)) /* Ignore this part, only used for sanity check when running tests. */ MInputMethodQuick.sendCommit("Maliit") MInputMethodQuick.sendPreedit("Maliit") } } maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/helloworld/000077500000000000000000000000001262307254400260025ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/helloworld/helloworld.pro000066400000000000000000000022151262307254400306770ustar00rootroot00000000000000# To avoid qmake from cleaning and trying to build # the .qml file with g++.... TEMPLATE = lib TARGET = dummy PLUGIN_FILE = helloworld.qml # Target for copying the qml file to build-dir build.target = $$OUT_PWD/$$PLUGIN_FILE build.output = $$OUT_PWD/$$PLUGIN_FILE build.depends = $$PWD/$$PLUGIN_FILE build.commands += cp $$PWD/$$PLUGIN_FILE $$OUT_PWD/$$PLUGIN_FILE PRE_TARGETDEPS += $$OUT_PWD/$$PLUGIN_FILE QMAKE_EXTRA_TARGETS += build # Install target plugin.files = $$OUT_PWD/$$PLUGIN_FILE plugin.CONFIG += no_check_exist # plugin.path # Different depending on BUILD_TYPE OTHER_FILES = $$PLUGIN_FILE BUILD_TYPE = unittest contains(BUILD_TYPE, skeleton) { CONFIG += link_pkgconfig PKGCONFIG += maliit-plugins-quick plugin.path += $$system(pkg-config --variable pluginsdir maliit-plugins) INSTALLS += plugin } contains(BUILD_TYPE, unittest) { # Used for testing purposes, can be deleted when used as a project skeleton # Build against in-tree libs TOP_DIR = ../../../.. include($$TOP_DIR/config.pri) plugin.path += $$MALIIT_TEST_PLUGINS_DIR/examples/qml/helloworld INSTALLS += plugin } QMAKE_CLEAN += libdummy.so* maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/helloworld/helloworld.qml000066400000000000000000000031651262307254400306750ustar00rootroot00000000000000/* * This file is part of meego-im-framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (directui@nokia.com) * * If you have questions regarding the use of this file, please contact * Nokia at directui@nokia.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ import QtQuick 2.0 Rectangle { id: canvas width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight color: "transparent" Rectangle { id: imArea width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight * 0.5 radius: 10 color: "grey" border.color: "black" border.width: 10 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter Text { id: buttonText text: "Hello World!" anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: MInputMethodQuick.sendCommit(buttonText.text) } } Component.onCompleted: { MInputMethodQuick.setInputMethodArea(Qt.rect(0, MInputMethodQuick.screenHeight - imArea.height, imArea.width, imArea.height)) MInputMethodQuick.sendCommit("Maliit") MInputMethodQuick.sendPreedit("Maliit") } } maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/override/000077500000000000000000000000001262307254400254465ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/override/override.pro000066400000000000000000000023131262307254400300060ustar00rootroot00000000000000TEMPLATE = lib TARGET = qmloverrideplugin OBJECTS_DIR = .obj MOC_DIR = .moc CONFIG += debug plugin contains(QT_MAJOR_VERSION, 4) { QT = core gui declarative } else { QT = core gui widgets declarative } SOURCES += overrideplugin.cpp HEADERS += overrideplugin.h RESOURCES = override.qrc target.depends = $$PWD/override.qml OTHER_FILES += \ override.qml \ BUILD_TYPE = unittest contains(BUILD_TYPE, skeleton) { CONFIG += link_pkgconfig PKGCONFIG += maliit-plugins-quick target.path += $$system(pkg-config --variable pluginsdir maliit-plugins) INCLUDEPATH += $$system(pkg-config --cflags maliit-plugins-quick | tr \' \' \'\\n\' | grep ^-I | cut -d I -f 2-) INSTALLS += target } contains(BUILD_TYPE, unittest) { # Used for testing purposes, can be deleted when used as a project skeleton # Build against in-tree libs TOP_DIR = ../../../.. include($$TOP_DIR/config.pri) include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) include($$TOP_DIR/maliit-plugins-quick/libmaliit-plugins-quick.pri) target.path += $$MALIIT_TEST_PLUGINS_DIR/examples/qml/override INSTALLS += target } QMAKE_CLEAN += libqmloverrideplugin.so maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/override/override.qml000066400000000000000000000054311262307254400300030ustar00rootroot00000000000000/* * This file is part of meego-im-framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (directui@nokia.com) * * If you have questions regarding the use of this file, please contact * Nokia at directui@nokia.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ import QtQuick 2.0 Rectangle { id: canvas width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight color: "transparent" Rectangle { id: labelChanger width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight * 0.25 radius: 10 color: "grey" border.color: "black" border.width: 10 anchors.bottom: imArea.top anchors.horizontalCenter: parent.horizontalCenter Text { id: changerText text: "Change action key to Return." anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: { if (MInputMethodQuick.actionKeyOverride.defaultLabel == "Enter") { changerText.text = "Change action key to Enter." MInputMethodQuick.actionKeyOverride.setDefaultLabel("Return") } else { changerText.text = "Change action key to Return." MInputMethodQuick.actionKeyOverride.setDefaultLabel("Enter") } } } } Rectangle { id: imArea width: MInputMethodQuick.screenWidth height: MInputMethodQuick.screenHeight * 0.25 radius: 10 color: "grey" border.color: "black" border.width: 10 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter Text { id: buttonText text: MInputMethodQuick.actionKeyOverride.label anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: MInputMethodQuick.activateActionKey() } } Component.onCompleted: { MInputMethodQuick.setInputMethodArea(Qt.rect(0, MInputMethodQuick.screenHeight - imArea.height - labelChanger.height, imArea.width, imArea.height + labelChanger.height)) MInputMethodQuick.actionKeyOverride.setDefaultLabel("Enter") MInputMethodQuick.sendCommit("Maliit") MInputMethodQuick.sendPreedit("Maliit") } } maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/override/override.qrc000066400000000000000000000001231262307254400277700ustar00rootroot00000000000000 override.qml maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/override/overrideplugin.cpp000066400000000000000000000017011262307254400312070ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "overrideplugin.h" #include #include #include namespace { const char * const filePath = "qrc:/override.qml"; const char * const pluginName = "OverridePlugin"; } OverridePlugin::OverridePlugin() { Q_INIT_RESOURCE(override); } QString OverridePlugin::name() const { return pluginName; } QString OverridePlugin::qmlFileName() const { return filePath; } Q_EXPORT_PLUGIN2(qmloverrideplugin, OverridePlugin) maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/override/overrideplugin.h000066400000000000000000000016361262307254400306630ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef OVERRIDE_PLUGIN_H #define OVERRIDE_PLUGIN_H #include #include class OverridePlugin : public QObject, public MInputMethodQuickPlugin { Q_OBJECT Q_INTERFACES(MInputMethodQuickPlugin Maliit::Plugins::InputMethodPlugin) public: OverridePlugin(); //! \reimpl virtual QString name() const; virtual QString qmlFileName() const; //! \reimpl_end }; #endif // OVERRIDE_PLUGIN_H maliit-framework-0.99.1+git20151118+62bd54b/examples/plugins/qml/qml.pro000066400000000000000000000000741262307254400251430ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = helloworld #cyclekeys override maliit-framework-0.99.1+git20151118+62bd54b/input-context/000077500000000000000000000000001262307254400223605ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/input-context/input-context.pro000066400000000000000000000007171262307254400257300ustar00rootroot00000000000000include (../config.pri) TOP_DIR = .. QT += dbus gui-private quick TEMPLATE = lib CONFIG += plugin TARGET = maliitplatforminputcontextplugin target.path = $$[QT_INSTALL_PLUGINS]/platforminputcontexts INSTALLS += target include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/connection/libmaliit-connection.pri) SOURCES += $$PWD/main.cpp \ $$PWD/minputcontext.cpp \ HEADERS += $$PWD/minputcontext.h \ OTHER_FILES += $$PWD/maliit.json maliit-framework-0.99.1+git20151118+62bd54b/input-context/main.cpp000066400000000000000000000022151262307254400240100ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). * * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include #include "minputcontext.h" class MaliitPlatformInputContextPlugin: public QPlatformInputContextPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QPlatformInputContextFactoryInterface_iid FILE "maliit.json") public: QPlatformInputContext *create(const QString&, const QStringList&); }; QPlatformInputContext *MaliitPlatformInputContextPlugin::create(const QString &system, const QStringList ¶mList) { Q_UNUSED(paramList); if (system.compare(system, QStringLiteral("maliit"), Qt::CaseInsensitive) == 0) { return new MInputContext; } return 0; } #include "main.moc" maliit-framework-0.99.1+git20151118+62bd54b/input-context/maliit.json000066400000000000000000000000351262307254400245300ustar00rootroot00000000000000{ "Keys": [ "maliit" ] } maliit-framework-0.99.1+git20151118+62bd54b/input-context/minputcontext.cpp000066400000000000000000000643501262307254400260150ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). * Copyright (C) 2013 Jolla Ltd. * * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "minputcontext.h" #include #include #include #include #include #include #include #include #include #include #include namespace { const int SoftwareInputPanelHideTimer = 100; const char * const InputContextName = "MInputContext"; int orientationAngle(Qt::ScreenOrientation orientation) { // Maliit uses orientations relative to screen, Qt relative to world // Note: doesn't work with inverted portrait or landscape as native screen orientation. static bool portraitRotated = qGuiApp->primaryScreen()->primaryOrientation() == Qt::PortraitOrientation; switch (orientation) { case Qt::PrimaryOrientation: // Urgh. case Qt::PortraitOrientation: return portraitRotated ? MInputContext::Angle0 : MInputContext::Angle270; case Qt::LandscapeOrientation: return portraitRotated ? MInputContext::Angle90 : MInputContext::Angle0; case Qt::InvertedPortraitOrientation: return portraitRotated ? MInputContext::Angle180 : MInputContext::Angle90; case Qt::InvertedLandscapeOrientation: return portraitRotated ? MInputContext::Angle270 : MInputContext::Angle180; } return MInputContext::Angle0; } } bool MInputContext::debug = false; MInputContext::MInputContext() : imServer(0), active(false), inputPanelState(InputPanelHidden), preeditCursorPos(-1), redirectKeys(false), currentFocusAcceptsInput(false) { QByteArray debugEnvVar = qgetenv("MALIIT_DEBUG"); if (!debugEnvVar.isEmpty() && debugEnvVar != "0") { qDebug() << "Creating Maliit input context"; debug = true; } QSharedPointer address(new Maliit::InputContext::DBus::DynamicAddress); imServer = new DBusServerConnection(address); sipHideTimer.setSingleShot(true); sipHideTimer.setInterval(SoftwareInputPanelHideTimer); connect(&sipHideTimer, SIGNAL(timeout()), SLOT(sendHideInputMethod())); connectInputMethodServer(); } MInputContext::~MInputContext() { delete imServer; } void MInputContext::connectInputMethodServer() { connect(imServer, SIGNAL(connected()), this, SLOT(onDBusConnection())); connect(imServer, SIGNAL(disconnected()), this, SLOT(onDBusDisconnection())); // Hook up incoming communication from input method server connect(imServer, SIGNAL(activationLostEvent()), this, SLOT(activationLostEvent())); connect(imServer, SIGNAL(imInitiatedHide()), this, SLOT(imInitiatedHide())); connect(imServer, SIGNAL(commitString(QString,int,int,int)), this, SLOT(commitString(QString,int,int,int))); connect(imServer, SIGNAL(updatePreedit(QString,QList,int,int,int)), this, SLOT(updatePreedit(QString,QList,int,int,int))); connect(imServer, SIGNAL(keyEvent(int,int,int,QString,bool,int,Maliit::EventRequestType)), this, SLOT(keyEvent(int,int,int,QString,bool,int,Maliit::EventRequestType))); connect(imServer, SIGNAL(updateInputMethodArea(QRect)), this, SLOT(updateInputMethodArea(QRect))); connect(imServer, SIGNAL(setGlobalCorrectionEnabled(bool)), this, SLOT(setGlobalCorrectionEnabled(bool))); connect(imServer, SIGNAL(getPreeditRectangle(QRect&,bool&)), this, SLOT(getPreeditRectangle(QRect&,bool&))); connect(imServer, SIGNAL(invokeAction(QString,QKeySequence)), this, SLOT(onInvokeAction(QString,QKeySequence))); connect(imServer, SIGNAL(setRedirectKeys(bool)), this, SLOT(setRedirectKeys(bool))); connect(imServer, SIGNAL(setDetectableAutoRepeat(bool)), this, SLOT(setDetectableAutoRepeat(bool))); connect(imServer, SIGNAL(setSelection(int,int)), this, SLOT(setSelection(int,int))); connect(imServer, SIGNAL(getSelection(QString&,bool&)), this, SLOT(getSelection(QString&, bool&))); connect(imServer, SIGNAL(setLanguage(QString)), this, SLOT(setLanguage(QString))); } bool MInputContext::isValid() const { return true; } void MInputContext::setLanguage(const QString &language) { QLocale newLocale(language); Qt::LayoutDirection oldDirection = inputDirection(); if (newLocale != inputLocale) { inputLocale = newLocale; emitLocaleChanged(); } Qt::LayoutDirection newDirection = inputDirection(); if (newDirection != oldDirection) { emitInputDirectionChanged(newDirection); } } void MInputContext::reset() { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; const bool hadPreedit = !preedit.isEmpty(); preedit.clear(); preeditCursorPos = -1; // reset input method server, preedit requires synchronization. // rationale: input method might be autocommitting existing preedit without // user interaction. imServer->reset(hadPreedit); } void MInputContext::commit() { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; const bool hadPreedit = !preedit.isEmpty(); if (hadPreedit) { QList attributes; if (preeditCursorPos >= 0) { bool valid = false; int start = cursorStartPosition(&valid); if (valid) { attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start + preeditCursorPos, 0, QVariant()); } } QInputMethodEvent event("", attributes); event.setCommitString(preedit); if (qGuiApp->focusObject()) { QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); } preedit.clear(); preeditCursorPos = -1; Q_EMIT preeditChanged(); } imServer->reset(hadPreedit); } void MInputContext::invokeAction(QInputMethod::Action action, int x) { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; if (!inputMethodAccepted()) return; if (action == QInputMethod::Click) { if (x < 0 || x >= preedit.length()) { reset(); return; } // To preserve the wire protocol, the "x" argument gets // transferred in widget state instead of being an extra // argument to mouseClickedOnPreedit(). QMap stateInformation = getStateInformation(); stateInformation["preeditClickPos"] = x; imServer->updateWidgetInformation(stateInformation, false); // FIXME: proper positions and preeditClickPos QRect preeditRect; QPoint globalPos; imServer->mouseClickedOnPreedit(globalPos, preeditRect); } else { QPlatformInputContext::invokeAction(action, x); } } void MInputContext::update(Qt::InputMethodQueries queries) { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; Q_UNUSED(queries) // fetching everything if (queries & Qt::ImPlatformData) { updateInputMethodExtensions(); } bool effectiveFocusChange = false; if (queries & Qt::ImEnabled) { bool newAcceptance = inputMethodAccepted(); if (newAcceptance && !active) { setFocusObject(QGuiApplication::focusObject()); return; } if (newAcceptance != currentFocusAcceptsInput) { currentFocusAcceptsInput = newAcceptance; effectiveFocusChange = true; } } // get the state information of currently focused widget, and pass it to input method server QMap stateInformation = getStateInformation(); imServer->updateWidgetInformation(stateInformation, effectiveFocusChange); } void MInputContext::updateServerOrientation(Qt::ScreenOrientation orientation) { if (active) { imServer->appOrientationChanged(orientationAngle(orientation)); } } void MInputContext::setFocusObject(QObject *focused) { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__ << focused; updateInputMethodExtensions(); QWindow *newFocusWindow = qGuiApp->focusWindow(); if (newFocusWindow != window.data()) { if (window) { disconnect(window.data(), SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)), this, SLOT(updateServerOrientation(Qt::ScreenOrientation))); } window = newFocusWindow; if (window) { connect(window.data(), SIGNAL(contentOrientationChanged(Qt::ScreenOrientation)), this, SLOT(updateServerOrientation(Qt::ScreenOrientation))); updateServerOrientation(window->contentOrientation()); } } bool oldAcceptInput = currentFocusAcceptsInput; currentFocusAcceptsInput = inputMethodAccepted(); if (!active && currentFocusAcceptsInput) { imServer->activateContext(); active = true; updateServerOrientation(newFocusWindow->contentOrientation()); } if (active && (currentFocusAcceptsInput || oldAcceptInput)) { const QMap stateInformation = getStateInformation(); imServer->updateWidgetInformation(stateInformation, true); } if (inputPanelState == InputPanelShowPending && currentFocusAcceptsInput) { sipHideTimer.stop(); imServer->showInputMethod(); inputPanelState = InputPanelShown; } } QString MInputContext::preeditString() { return preedit; } bool MInputContext::filterEvent(const QEvent *event) { bool eaten = false; switch (event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: if (!inputMethodAccepted()) { break; } if (redirectKeys) { const QKeyEvent *key = static_cast(event); imServer->processKeyEvent(key->type(), static_cast(key->key()), key->modifiers(), key->text(), key->isAutoRepeat(), key->count(), key->nativeScanCode(), key->nativeModifiers(), 0 /* currentKeyEventTime */); eaten = true; } break; default: break; } return eaten; } QRectF MInputContext::keyboardRect() const { return keyboardRectangle; } bool MInputContext::isAnimating() const { return false; // don't know here when input method server is actually doing transitions } void MInputContext::showInputPanel() { if (debug) qDebug() << __PRETTY_FUNCTION__; if (inputMethodAccepted()) { sipHideTimer.stop(); } if (!active || !inputMethodAccepted()) { // in case SIP request comes without a properly focused widget, we // don't ask input method server to be shown. It's done when the next widget // is focused, so the widget state information can be set. inputPanelState = InputPanelShowPending; } else { // note: could do this also if panel was hidden imServer->showInputMethod(); inputPanelState = InputPanelShown; } } void MInputContext::hideInputPanel() { if (debug) qDebug() << __PRETTY_FUNCTION__; sipHideTimer.start(); } bool MInputContext::isInputPanelVisible() const { return !keyboardRectangle.isEmpty(); } QLocale MInputContext::locale() const { return inputLocale; } Qt::LayoutDirection MInputContext::inputDirection() const { return inputLocale.textDirection(); } void MInputContext::sendHideInputMethod() { imServer->hideInputMethod(); inputPanelState = InputPanelHidden; } void MInputContext::activationLostEvent() { // This method is called when activation was gracefully lost. // There is similar cleaning up done in onDBusDisconnection. active = false; inputPanelState = InputPanelHidden; } void MInputContext::imInitiatedHide() { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; inputPanelState = InputPanelHidden; // remove focus on QtQuick2 QQuickItem *inputItem = qobject_cast(QGuiApplication::focusObject()); if (inputItem) { inputItem->setFocus(false); } } void MInputContext::commitString(const QString &string, int replacementStart, int replacementLength, int cursorPos) { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; if (imServer->pendingResets()) { return; } bool hadPreedit = !preedit.isEmpty(); preedit.clear(); preeditCursorPos = -1; int start = -1; if (cursorPos >= 0) { bool valid = false; int currentStart = cursorStartPosition(&valid); if (valid) { start = cursorPos + currentStart + replacementStart; } } if (start >= 0) { QList attributes; attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start, 0, QVariant()); QInputMethodEvent event("", attributes); event.setCommitString(string, replacementStart, replacementLength); if (qGuiApp->focusObject()) { QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); } } else { QInputMethodEvent event; event.setCommitString(string, replacementStart, replacementLength); if (qGuiApp->focusObject()) { QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); } } if (hadPreedit) { Q_EMIT preeditChanged(); } } void MInputContext::updatePreedit(const QString &string, const QList &preeditFormats, int replacementStart, int replacementLength, int cursorPos) { if (debug) { qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__ << "preedit:" << string << ", replacementStart:" << replacementStart << ", replacementLength:" << replacementLength << ", cursorPos:" << cursorPos; } if (imServer->pendingResets()) { return; } updatePreeditInternally(string, preeditFormats, replacementStart, replacementLength, cursorPos); } void MInputContext::updatePreeditInternally(const QString &string, const QList &preeditFormats, int replacementStart, int replacementLength, int cursorPos) { preedit = string; preeditCursorPos = cursorPos; QList attributes; Q_FOREACH (const Maliit::PreeditTextFormat &preeditFormat, preeditFormats) { QTextCharFormat format; // update style mode switch (preeditFormat.preeditFace) { case Maliit::PreeditNoCandidates: format.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline); format.setUnderlineColor(Qt::red); break; case Maliit::PreeditUnconvertible: format.setForeground(QBrush(QColor(128, 128, 128))); break; case Maliit::PreeditActive: format.setForeground(QBrush(QColor(153, 50, 204))); format.setFontWeight(QFont::Bold); break; case Maliit::PreeditKeyPress: case Maliit::PreeditDefault: format.setUnderlineStyle(QTextCharFormat::SingleUnderline); format.setUnderlineColor(QColor(0, 0, 0)); break; } attributes << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, preeditFormat.start, preeditFormat.length, format); } if (cursorPos >= 0) { attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPos, 1, QVariant()); } QInputMethodEvent event(string, attributes); if (replacementStart || replacementLength) { event.setCommitString("", replacementStart, replacementLength); } if (qGuiApp->focusObject()) { QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); } else { if (debug) qDebug() << __PRETTY_FUNCTION__; qWarning() << "No focused object, cannot update preedit." << "Wrong reset/preedit behaviour in active input method plugin?"; } Q_EMIT preeditChanged(); } void MInputContext::keyEvent(int type, int key, int modifiers, const QString &text, bool autoRepeat, int count, Maliit::EventRequestType requestType) { if (debug) qDebug() << InputContextName << "in" << __PRETTY_FUNCTION__; if (qGuiApp->focusWindow() != 0 && requestType != Maliit::EventRequestSignalOnly) { QEvent::Type eventType = static_cast(type); QKeyEvent event(eventType, key, static_cast(modifiers), text, autoRepeat, count); // need window instead of focus item so e.g. QQuickItem::keyPressEvent() gets properly called QGuiApplication::sendEvent(qGuiApp->focusWindow(), &event); } } void MInputContext::updateInputMethodArea(const QRect &rect) { bool wasVisible = isInputPanelVisible(); if (rect != keyboardRectangle) { keyboardRectangle = rect; emitKeyboardRectChanged(); if (wasVisible != isInputPanelVisible()) { emitInputPanelVisibleChanged(); } } } void MInputContext::setGlobalCorrectionEnabled(bool enabled) { Q_UNUSED(enabled) // not handling preedit injections, ignored } void MInputContext::getPreeditRectangle(QRect &rectangle, bool &valid) const { // not supported rectangle = QRect(); valid = false; return; } void MInputContext::onInvokeAction(const QString &action, const QKeySequence &sequence) { if (debug) qDebug() << InputContextName << __PRETTY_FUNCTION__ << "action" << action; // NOTE: currently not trying to trigger action directly static const Qt::KeyboardModifiers AllModifiers = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier; for (int i = 0; i < sequence.count(); i++) { const int key = sequence[i] & ~AllModifiers; const int modifiers = sequence[i] & AllModifiers; QString text(""); if (modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier) { text = QString(key); } keyEvent(QEvent::KeyPress, key, modifiers, text, false, 1); keyEvent(QEvent::KeyRelease, key, modifiers, text, false, 1); } } void MInputContext::onDBusDisconnection() { if (debug) qDebug() << __PRETTY_FUNCTION__; active = false; redirectKeys = false; updateInputMethodArea(QRect()); } void MInputContext::onDBusConnection() { if (debug) qDebug() << __PRETTY_FUNCTION__; // using one attribute extension for everything imServer->registerAttributeExtension(0, QString()); // Force activation, since setFocusObject may have been called after // onDBusDisconnection set active to false or before the dbus connection. active = false; if (inputMethodAccepted()) { setFocusObject(QGuiApplication::focusObject()); if (inputPanelState != InputPanelHidden) { imServer->showInputMethod(); inputPanelState = InputPanelShown; } } } void MInputContext::notifyOrientationAboutToChange(MInputContext::OrientationAngle angle) { // can get called from signal so cannot be sure we are really currently active if (active) { imServer->appOrientationAboutToChange(static_cast(angle)); } } void MInputContext::notifyOrientationChanged(MInputContext::OrientationAngle angle) { // can get called from signal so cannot be sure we are really currently active if (active) { imServer->appOrientationChanged(static_cast(angle)); } } Maliit::TextContentType MInputContext::contentType(Qt::InputMethodHints hints) const { Maliit::TextContentType type = Maliit::FreeTextContentType; hints &= Qt::ImhExclusiveInputMask; if (hints == Qt::ImhFormattedNumbersOnly || hints == Qt::ImhDigitsOnly) { type = Maliit::NumberContentType; } else if (hints == Qt::ImhDialableCharactersOnly) { type = Maliit::PhoneNumberContentType; } else if (hints == Qt::ImhEmailCharactersOnly) { type = Maliit::EmailContentType; } else if (hints == Qt::ImhUrlCharactersOnly) { type = Maliit::UrlContentType; } return type; } void MInputContext::setRedirectKeys(bool enabled) { redirectKeys = enabled; } void MInputContext::setDetectableAutoRepeat(bool enabled) { Q_UNUSED(enabled); if (debug) qWarning() << "Detectable autorepeat not supported."; } QMap MInputContext::getStateInformation() const { QMap stateInformation; stateInformation["focusState"] = inputMethodAccepted(); if (!inputMethodAccepted() || !qGuiApp->focusObject()) { return stateInformation; } QInputMethodQueryEvent query(Qt::ImQueryAll); QGuiApplication::sendEvent(qGuiApp->focusObject(), &query); QVariant queryResult; queryResult = query.value(Qt::ImSurroundingText); if (queryResult.isValid()) { stateInformation["surroundingText"] = queryResult.toString(); } queryResult = query.value(Qt::ImCursorPosition); if (queryResult.isValid()) { stateInformation["cursorPosition"] = queryResult.toInt(); } queryResult = query.value(Qt::ImAnchorPosition); if (queryResult.isValid()) { stateInformation["anchorPosition"] = queryResult.toInt(); } queryResult = query.value(Qt::ImHints); Qt::InputMethodHints hints = static_cast(queryResult.toUInt()); // content type value // Deprecated, replaced by just transmitting all hints (see below): // FIXME: Remove once MAbstractInputMethod API for this got deprecated/removed. stateInformation["contentType"] = contentType(hints); stateInformation["autocapitalizationEnabled"] = !(hints & Qt::ImhNoAutoUppercase); stateInformation["hiddenText"] = static_cast(hints & Qt::ImhHiddenText); stateInformation["predictionEnabled"] = !(hints & Qt::ImhNoPredictiveText); stateInformation["maliit-inputmethod-hints"] = QVariant(static_cast(hints)); // is text selected queryResult = query.value(Qt::ImCurrentSelection); if (queryResult.isValid()) { stateInformation["hasSelection"] = !(queryResult.toString().isEmpty()); } QWindow *window = qGuiApp->focusWindow(); if (window) { stateInformation["winId"] = static_cast(window->winId()); } queryResult = query.value(Qt::ImCursorRectangle); if (queryResult.isValid()) { QRect rect = queryResult.toRect(); rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(rect); if (window) { stateInformation["cursorRectangle"] = QRect(window->mapToGlobal(rect.topLeft()), rect.size()); } } stateInformation["toolbarId"] = 0; // Global extension id. And bad state parameter name for it. return stateInformation; } void MInputContext::setSelection(int start, int length) { if (!inputMethodAccepted()) return; QList attributes; attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, start, length, QVariant()); QInputMethodEvent event("", attributes); QGuiApplication::sendEvent(qGuiApp->focusObject(), &event); } void MInputContext::getSelection(QString &selection, bool &valid) const { selection.clear(); QString selectionText; valid = false; if (!inputMethodAccepted()) { return; } QInputMethodQueryEvent query(Qt::ImCurrentSelection); QGuiApplication::sendEvent(qGuiApp->focusObject(), &query); QVariant queryResult = query.value(Qt::ImCurrentSelection); valid = queryResult.isValid(); selectionText = queryResult.toString(); selection = selectionText; } int MInputContext::cursorStartPosition(bool *valid) { int start = -1; if (valid) { *valid = false; } if (!inputMethodAccepted()) { return start; } QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition); QGuiApplication::sendEvent(qGuiApp->focusObject(), &query); // obtain the cursor absolute position QVariant queryResult = query.value(Qt::ImCursorPosition); if (queryResult.isValid()) { int absCursorPos = queryResult.toInt(); // Fetch anchor position too but don't require it. queryResult = query.value(Qt::ImAnchorPosition); int absAnchorPos = queryResult.isValid() ? queryResult.toInt() : absCursorPos; // In case of selection, base cursorPos on start of it. start = qMin(absCursorPos, absAnchorPos); *valid = true; } return start; } void MInputContext::updateInputMethodExtensions() { if (!inputMethodAccepted()) { return; } if (debug) qDebug() << InputContextName << __PRETTY_FUNCTION__; QVariantMap extensions = qGuiApp->focusObject()->property("__inputMethodExtensions").toMap(); QVariant value; value = extensions.value("enterKeyIconSource"); imServer->setExtendedAttribute(0, "/keys", "actionKey", "icon", QVariant(value.toUrl().toString())); value = extensions.value("enterKeyText"); imServer->setExtendedAttribute(0, "/keys", "actionKey", "label", QVariant(value.toString())); value = extensions.value("enterKeyEnabled"); imServer->setExtendedAttribute(0, "/keys", "actionKey", "enabled", value.isValid() ? value.toBool() : true); value = extensions.value("enterKeyHighlighted"); imServer->setExtendedAttribute(0, "/keys", "actionKey", "highlighted", value.isValid() ? value.toBool() : false); } maliit-framework-0.99.1+git20151118+62bd54b/input-context/minputcontext.h000066400000000000000000000122051262307254400254520ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MINPUTCONTEXT_H #define MINPUTCONTEXT_H #include #include "dbusserverconnection.h" #include #include #include #include #include class MImServerConnection; class MInputContext : public QPlatformInputContext { Q_OBJECT // Exposing preedit state as an extension. Use only if you know what you're doing. Q_PROPERTY(QString preedit READ preeditString NOTIFY preeditChanged) public: enum OrientationAngle { Angle0 = 0, Angle90 = 90, Angle180 = 180, Angle270 = 270 }; MInputContext(); virtual ~MInputContext(); // reimplemented methods virtual bool isValid() const; virtual void reset(); virtual void commit(); virtual void update(Qt::InputMethodQueries); virtual void invokeAction(QInputMethod::Action, int cursorPosition); virtual bool filterEvent(const QEvent *event); virtual QRectF keyboardRect() const; virtual bool isAnimating() const; virtual void showInputPanel(); virtual void hideInputPanel(); virtual bool isInputPanelVisible() const; virtual QLocale locale() const; virtual Qt::LayoutDirection inputDirection() const; virtual void setFocusObject(QObject *object); QString preeditString(); public Q_SLOTS: // Hooked up to the input method server void activationLostEvent(); void imInitiatedHide(); void commitString(const QString &string, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); void updatePreedit(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); void keyEvent(int type, int key, int modifiers, const QString &text, bool autoRepeat, int count, Maliit::EventRequestType requestType = Maliit::EventRequestBoth); void updateInputMethodArea(const QRect &rect); void setGlobalCorrectionEnabled(bool); void getPreeditRectangle(QRect &rectangle, bool &valid) const; void onInvokeAction(const QString &action, const QKeySequence &sequence); void setRedirectKeys(bool enabled); void setDetectableAutoRepeat(bool enabled); void setSelection(int start, int length); void getSelection(QString &selection, bool &valid) const; void setLanguage(const QString &language); // End input method server connection slots. private Q_SLOTS: void sendHideInputMethod(); void updateServerOrientation(Qt::ScreenOrientation orientation); void onDBusDisconnection(); void onDBusConnection(); // Notify input method plugin about the application's active window prepare to change to a new orientation angle. void notifyOrientationAboutToChange(MInputContext::OrientationAngle orientation); // Notify input method plugin about new \a orientation angle of application's active window. // note: this method is called when the orientation change is finished void notifyOrientationChanged(MInputContext::OrientationAngle orientation); Q_SIGNALS: void preeditChanged(); private: Q_DISABLE_COPY(MInputContext) enum InputPanelState { InputPanelShowPending, // input panel showing requested, but activation pending InputPanelShown, InputPanelHidden }; void updatePreeditInternally(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); void connectInputMethodServer(); void updateInputMethodExtensions(); // returns content type corresponding to specified hints Maliit::TextContentType contentType(Qt::InputMethodHints hints) const; // returns state for currently focused widget, key is attribute name. QMap getStateInformation() const; // Gets cursor start position, relative to widget surrounding text. // Parameter valid set to false on failure. int cursorStartPosition(bool *valid); static bool debug; DBusServerConnection *imServer; bool active; // is connection active QPointer window; QRect keyboardRectangle; InputPanelState inputPanelState; // state for the input method server's software input panel /* Timer for hiding the current Software Input Panel. * This is mainly for switching directly between widgets that have input method enabled. */ QTimer sipHideTimer; QString preedit; int preeditCursorPos; bool redirectKeys; // redirect all hw key events to the input method or not QLocale inputLocale; bool currentFocusAcceptsInput; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/maliit-framework.pro000066400000000000000000000057441262307254400235450ustar00rootroot00000000000000include(./config.pri) !isEmpty(HELP) { # Output help help_string = \ Important build options: \ \\n\\t PREFIX : Install prefix (default: /usr) \ \\n\\t {BIN,LIB,INCLUDE,DOC}DIR : Install prefix for specific types of files \ \\n\\t MALIIT_DEFAULT_PLUGIN : Default onscreen (virtual) keyboard plugin \ \\n\\t MALIIT_DEFAULT_HW_PLUGIN : Default hardware keyboard plugin \ \\n\\t MALIIT_SERVER_ARGUMENTS : Arguments to use for starting maliit-server by D-Bus activation \ \\nRecognised CONFIG flags: \ \\n\\t nohwkeyboard : Disable the support for the hardware keyboard \ \\n\\t enable-contextkit : Build contextkit support (for monitoring hardware keyboard status) \ \\n\\t enable-dbus-activation : Enable dbus activation support for maliit-server \ \\n\\t notests : Do not build tests \ \\n\\t nodoc : Do not build documentation\ \\n\\t local-install : Install everything underneath PREFIX, nothing to system directories reported by GTK+, Qt, DBus etc. \ \\n\\t glib : Compile GDBus bindings \ \\n\\t wayland : Compile with support for wayland \ \\n\\t qt5-inputcontext : Compile with Qt5 input context, replaces the one currently provided by Qt \ \\n\\t noxcb : Compile without xcb support \ \\nInfluential environment variables: \ \\n\\t PKG_CONFIG_PATH : Override standard directories to look for pkg-config information \ \\nExamples: \ \\n\\t qmake \ \\n\\t qmake PREFIX=/usr LIBDIR=/usr/lib64 CONFIG+=notests \ \\n\\t qmake PREFIX=/usr MALIIT_DEFAULT_PLUGIN=libmykeyboard.so !build_pass:system(echo -e \"$$help_string\") } else { config_string = Tip: Run qmake HELP=1 for a list of all supported build options !build_pass:system(echo -e \"$$config_string\") } CONFIG += ordered TEMPLATE = subdirs contains(QT_MAJOR_VERSION, 4) { error("Qt 5 is required. For the Qt 4 input context see maliit-inputcontext-qt4. For a Qt 4 Maliit please use the 0.81 or 0.94-qt4 branches/release series instead") } SUBDIRS = common dbus_interfaces wayland { SUBDIRS += weston-protocols } SUBDIRS += connection glib { SUBDIRS += maliit-glib } SUBDIRS += src passthroughserver examples qt5-inputcontext { SUBDIRS += input-context } !nodoc { SUBDIRS += doc } !notests { SUBDIRS += tests } QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.CONFIG = recursive QMAKE_EXTRA_TARGETS += check check.target = check check.CONFIG = recursive DIST_NAME = $$MALIIT_PACKAGENAME-$$MALIIT_VERSION DIST_PATH = $$OUT_PWD/$$DIST_NAME TARBALL_SUFFIX = .tar.bz2 TARBALL_PATH = $$DIST_PATH$$TARBALL_SUFFIX # The 'make dist' target # Creates a tarball QMAKE_EXTRA_TARGETS += release release.target = release release.commands += git archive HEAD --prefix=$$DIST_NAME/ | bzip2 > $$TARBALL_PATH; release.commands += md5sum $$TARBALL_PATH | cut -d \' \' -f 1 > $$DIST_PATH\\.md5 OTHER_FILES += NEWS README INSTALL.local maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/000077500000000000000000000000001262307254400217315ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/.gitignore000066400000000000000000000002721262307254400237220ustar00rootroot00000000000000maliit-*.pc maliitserver.h maliitserver.c maliitcontext.h maliitcontext.c maliitmarshallers.h maliitmarshallers.c Makefile.* *.stamp maliit/ reference/ Maliit-1.0.gir Maliit-1.0.typelib maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/libmaliit-glib.pri000066400000000000000000000006101262307254400253230ustar00rootroot00000000000000# Use when a .pro file requires libmaliit-glib # The .pro file must define TOP_DIR to be a relative path # to the top-level source/build directory, and include config.pri LIBS += $$TOP_DIR/lib/$$maliitDynamicLib($${MALIIT_GLIB_LIB}) POST_TARGETDEPS += $$TOP_DIR/lib/$$maliitDynamicLib($${MALIIT_GLIB_LIB}) INCLUDEPATH += $$TOP_DIR CONFIG += link_pkgconfig PKGCONFIG += glib-2.0 gobject-2.0 maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliit-docs.xml000066400000000000000000000030231262307254400246560ustar00rootroot00000000000000 ]> Maliit Reference Manual for Maliit 1.0. The latest version of this documentation can be found on-line at http://www.maliit.org/docs/maliit/index.html. Maliit Object Hierarchy API Index Index of deprecated API maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliit-glib-docs.pro000066400000000000000000000064141262307254400256000ustar00rootroot00000000000000TOP_DIR = .. include(../config.pri) TEMPLATE=lib TARGET=dummy GOBJECTFILES += \ maliitattributeextension.c \ maliitattributeextension.h \ maliitinputmethod.c \ maliitinputmethod.h \ maliitsettingsmanager.c \ maliitsettingsmanager.h \ maliitsettingsentry.c \ maliitsettingsentry.h \ maliitpluginsettings.c \ maliitpluginsettings.h \ maliitsettingdata.c \ maliitsettingdata.h \ LIB_DIR = $$OUT_PWD/$$TOP_DIR/lib # The resulting html docs go into ./maliit, and the temporary build files to ./reference/ gtk_doc.name = gtk-doc gtk_doc.CONFIG += target_predeps no_link combine gtk_doc.output = $${OUT_PWD}/maliit/index.html gtk_doc.clean_commands = rm -rf $${OUT_PWD}/maliit $${OUT_PWD}/reference gtk_doc.input = GOBJECTFILES gtk_doc.commands += mkdir -p reference && gtk_doc.commands += cp $$PWD/maliit-sections.txt $$PWD/maliit-docs.xml $$OUT_PWD/reference && gtk_doc.commands += cd reference && gtk_doc.commands += gtkdoc-scan --module=maliit --source-dir=$${PWD} --rebuild-types && gtk_doc.commands += LD_LIBRARY_PATH=\"$${LIB_DIR}\" CFLAGS=\"$$system(pkg-config --cflags gio-2.0)\" LDFLAGS=\"-L$${LIB_DIR} -l$${MALIIT_GLIB_LIB} $$system(pkg-config --libs gio-2.0)\" gtk_doc.commands += gtkdoc-scangobj --module=maliit && gtk_doc.commands += gtkdoc-mkdb --module=maliit --source-dir=$${PWD} --output-format=xml && cd .. && gtk_doc.commands += mkdir -p maliit && cd maliit && gtkdoc-mkhtml maliit ../reference/maliit-docs.xml && cd .. && gtk_doc.commands += cd reference && gtkdoc-fixxref --module=maliit --module-dir=../maliit && cd .. gir_scanner.name = g-ir-scanner gir_scanner.CONFIG += no_link combine gir_scanner.output = $${OUT_PWD}/Maliit-1.0.gir gir_scanner.input = GOBJECTFILES gir_scanner.commands += LD_LIBRARY_PATH=\"$${LIB_DIR}\" g-ir-scanner --warn-all -n Maliit --no-libtool -L$${LIB_DIR} --library=maliit-glib --include=Gio-2.0 --pkg=gio-2.0 --pkg-export=maliit-glib-1.0 --nsversion=1.0 --output=${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} GIR_FILES = $${OUT_PWD}/Maliit-1.0.gir gir_compiler.name = g-ir-compiler gir_compiler.CONFIG += target_predeps no_link no_check_exist gir_compiler.output = $${OUT_PWD}/Maliit-1.0.typelib gir_compiler.input = GIR_FILES gir_compiler.commands += g-ir-compiler -m Maliit --output=${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} system(pkg-config gtk-doc) { docs.files = $${OUT_PWD}/maliit docs.path = $$DATADIR/gtk-doc/html docs.CONFIG += no_check_exist directory INSTALLS += docs QMAKE_EXTRA_COMPILERS += gtk_doc } system(pkg-config gobject-introspection-1.0) { GIR_DIR = $$system(pkg-config --variable=girdir gobject-introspection-1.0) TYPELIB_DIR = $$system(pkg-config --variable=typelibdir gobject-introspection-1.0) GIR_PREFIX = $$system(pkg-config --variable=prefix gobject-introspection-1.0) local-install { GIR_DIR = $$replace(GIR_DIR, $$GIR_PREFIX, $$PREFIX) TYPELIB_DIR = $$replace(TYPELIB_DIR, $$GIR_PREFIX, $$PREFIX) } gir.files = $${OUT_PWD}/Maliit-1.0.gir gir.path = $$GIR_DIR gir.CONFIG += no_check_exist typelib.files = $${OUT_PWD}/Maliit-1.0.typelib typelib.path = $$TYPELIB_DIR typelib.CONFIG += no_check_exist INSTALLS += gir typelib QMAKE_EXTRA_COMPILERS += gir_scanner gir_compiler } OTHER_FILES += maliit-sections.txt maliit-docs.xml maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliit-glib.pc.in000066400000000000000000000006231262307254400250550ustar00rootroot00000000000000prefix=@PREFIX@ exec_prefix=@PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: Maliit-GLib Description: Maliit provides a flexible and cross platform input method framework. It is usable on all MeeGo user experiences, and in other GNU/Linux distributions as well. Version: @MALIIT_VERSION@ Requires: gobject-2.0 gio-2.0 Cflags: -I${includedir}/@MALIIT_HEADER@ Libs: -L${libdir} -l@MALIIT_GLIB_LIB@ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliit-glib.pro000066400000000000000000000071741262307254400246560ustar00rootroot00000000000000TOP_DIR = .. include(../config.pri) VERSION = $$MALIIT_ABI_VERSION TEMPLATE = lib TARGET = $$TOP_DIR/lib/$${MALIIT_GLIB_LIB} CONFIG += link_pkgconfig PKGCONFIG += glib-2.0 gobject-2.0 gio-2.0 gio-unix-2.0 CONFIG -= qt QMAKE_CXXFLAGS_DEBUG+=-Wno-error=deprecated-declarations QMAKE_CFLAGS_DEBUG+=-Wno-error=deprecated-declarations HEADERSINSTALL += \ maliitattributeextension.h \ maliitattributeextensionregistry.h \ maliitinputmethod.h \ maliitsettingsmanager.h \ maliitsettingsentry.h \ maliitpluginsettings.h \ maliitsettingdata.h \ maliitbus.h \ maliitserver.h \ maliitcontext.h \ HEADERS += \ $$HEADERSINSTALL \ maliitattributeextensionprivate.h \ maliitmarshallers.h \ maliitpluginsettingsprivate.h \ maliitsettingsentryprivate.h \ SOURCES += \ maliitattributeextension.c \ maliitattributeextensionregistry.c \ maliitinputmethod.c \ maliitsettingsmanager.c \ maliitsettingsentry.c \ maliitpluginsettings.c \ maliitsettingdata.c \ maliitbus.c \ maliitserver.c \ maliitcontext.c \ target.path += $$LIBDIR headers.path += $$INCLUDEDIR/$$MALIIT_HEADER/maliit-glib headers.files += $$HEADERSINSTALL outputFiles(maliit-glib.pc) OTHER_FILES += \ maliit-glib.pc.in install_pkgconfig.path = $${LIBDIR}/pkgconfig install_pkgconfig.files = $$OUT_PWD/maliit-glib.pc INSTALLS += \ target \ headers \ install_pkgconfig \ # coverage flags are off per default, but can be turned on via qmake COV_OPTION=on for(OPTION,$$list($$lower($$COV_OPTION))){ isEqual(OPTION, on){ QMAKE_CFLAGS += -ftest-coverage -fprofile-arcs -fno-elide-constructors LIBS += -lgcov } } QMAKE_CLEAN += \ $$OBJECTS_DIR/*.gcno \ $$OBJECTS_DIR/*.gcda \ maliitmarshallers.h \ maliitmarshallers.c OTHER_FILES += \ libmaliit-glib.pri # generate marshallers GLIB_GENMARSHAL_LIST += maliitmarshallers.list OTHER_FILES += maliitmarshallers.list glib_genmarshal_header.name = glib-genmarshal header ${QMAKE_FILE_IN} glib_genmarshal_header.commands = glib-genmarshal --prefix=maliit_marshal --header --g-fatal-warnings ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} glib_genmarshal_header.output = ${QMAKE_FILE_IN_BASE}.h glib_genmarshal_header.variable_out = HEADERS glib_genmarshal_header.input = GLIB_GENMARSHAL_LIST glib_genmarshal_source.name = glib-genmarshal source ${QMAKE_FILE_IN} glib_genmarshal_source.commands = glib-genmarshal --prefix=maliit_marshal --body --g-fatal-warnings ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} glib_genmarshal_source.output = ${QMAKE_FILE_IN_BASE}.c glib_genmarshal_source.variable_out = SOURCES glib_genmarshal_source.input = GLIB_GENMARSHAL_LIST QMAKE_EXTRA_COMPILERS += glib_genmarshal_header glib_genmarshal_source include($$TOP_DIR/dbus_interfaces/dbus_interfaces.pri) PRE_TARGETDEPS += glib_server glib_context QMAKE_EXTRA_TARGETS += glib_server glib_context glib_server.commands = gdbus-codegen --interface-prefix com.meego \ --generate-c-code $$TOP_DIR/maliit-glib/maliitserver \ --c-namespace Maliit \ --annotate com.meego.inputmethod.uiserver1 org.gtk.GDBus.C.Name Server \ $$DBUS_SERVER_XML glib_context.commands = gdbus-codegen --interface-prefix com.meego \ --generate-c-code $$TOP_DIR/maliit-glib/maliitcontext \ --c-namespace Maliit \ --annotate com.meego.inputmethod.inputcontext1 org.gtk.GDBus.C.Name Context \ $$DBUS_CONTEXT_XML maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliit-sections.txt000066400000000000000000000115671262307254400256100ustar00rootroot00000000000000
maliitattributeextension MaliitAttributeExtension MaliitAttributeExtension MaliitAttributeExtensionClass maliit_attribute_extension_attach_to_object maliit_attribute_extension_get_attributes maliit_attribute_extension_get_filename maliit_attribute_extension_get_id maliit_attribute_extension_new maliit_attribute_extension_new_with_filename maliit_attribute_extension_set_attribute maliit_attribute_extension_update_attribute MALIIT_ATTRIBUTE_EXTENSION MALIIT_ATTRIBUTE_EXTENSION_CLASS MALIIT_ATTRIBUTE_EXTENSION_GET_CLASS MALIIT_IS_ATTRIBUTE_EXTENSION MALIIT_IS_ATTRIBUTE_EXTENSION_CLASS MALIIT_TYPE_ATTRIBUTE_EXTENSION MaliitAttributeExtensionPrivate maliit_attribute_extension_get_type
maliitattributeextensionprivate MALIIT_ATTRIBUTE_EXTENSION_DATA MALIIT_ATTRIBUTE_EXTENSION_DATA_QUARK maliit_attribute_extension_new_with_id
maliitattributeextensionregistry MaliitAttributeExtensionRegistry MaliitAttributeExtensionRegistry MaliitAttributeExtensionRegistryClass maliit_attribute_extension_registry_add_extension maliit_attribute_extension_registry_extension_changed maliit_attribute_extension_registry_get_extensions maliit_attribute_extension_registry_get_instance maliit_attribute_extension_registry_remove_extension maliit_attribute_extension_registry_update_attribute MALIIT_ATTRIBUTE_EXTENSION_REGISTRY MALIIT_ATTRIBUTE_EXTENSION_REGISTRY_CLASS MALIIT_ATTRIBUTE_EXTENSION_REGISTRY_GET_CLASS MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY_CLASS MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY MaliitAttributeExtensionRegistryPrivate maliit_attribute_extension_registry_get_type
maliitinputmethod MaliitInputMethod MaliitInputMethod MaliitInputMethodClass maliit_input_method_new maliit_input_method_get_area maliit_input_method_hide maliit_input_method_show MALIIT_INPUT_METHOD MALIIT_INPUT_METHOD_CLASS MALIIT_INPUT_METHOD_GET_CLASS MALIIT_IS_INPUT_METHOD MALIIT_IS_INPUT_METHOD_CLASS MALIIT_TYPE_INPUT_METHOD MaliitInputMethodPrivate maliit_input_method_get_type
maliitsettingsmanager MaliitSectionManager MaliitSettingsManager MaliitSettingsManagerClass maliit_settings_manager_new maliit_settings_manager_get_preferred_description_locale maliit_settings_manager_load_plugin_settings maliit_settings_manager_set_preferred_description_locale MALIIT_SETTINGS_MANAGER MALIIT_SETTINGS_MANAGER_CLASS MALIIT_SETTINGS_MANAGER_GET_CLASS MALIIT_IS_SETTINGS_MANAGER MALIIT_IS_SETTINGS_MANAGER_CLASS MALIIT_TYPE_SETTINGS_MANAGER MaliitSettingsManagerPrivate maliit_settings_manager_get_type
maliitsettingsentry MaliitSettingsEntry MaliitSettingsEntry MaliitSettingsEntryClass maliit_settings_entry_get_attributes maliit_settings_entry_get_description maliit_settings_entry_get_entry_type maliit_settings_entry_get_key maliit_settings_entry_get_value maliit_settings_entry_is_value_valid maliit_settings_entry_set_value maliit_settings_entry_is_current_value_valid MALIIT_IS_SETTINGS_ENTRY MALIIT_IS_SETTINGS_ENTRY_CLASS MALIIT_SETTINGS_ENTRY MALIIT_SETTINGS_ENTRY_CLASS MALIIT_SETTINGS_ENTRY_GET_CLASS MALIIT_TYPE_SETTINGS_ENTRY MaliitSettingsEntryPrivate maliit_settings_entry_get_type
maliitsettingsentryprivate maliit_settings_entry_new_from_dbus_data
maliitpluginsettings MaliitPluginSettings MaliitPluginSettings MaliitPluginSettingsClass maliit_plugin_settings_get_configuration_entries maliit_plugin_settings_get_description_language maliit_plugin_settings_get_plugin_description maliit_plugin_settings_get_plugin_name MALIIT_IS_PLUGIN_SETTINGS MALIIT_IS_PLUGIN_SETTINGS_CLASS MALIIT_PLUGIN_SETTINGS MALIIT_PLUGIN_SETTINGS_CLASS MALIIT_PLUGIN_SETTINGS_GET_CLASS MALIIT_TYPE_PLUGIN_SETTINGS MaliitPluginSettingsPrivate maliit_plugin_settings_get_type
maliitpluginsettingsprivate maliit_plugin_settings_new_from_dbus_data
maliitsettingdata Maliit setting data MaliitSettingsEntryType MALIIT_SETTING_DEFAULT_VALUE MALIIT_SETTING_VALUE_DOMAIN MALIIT_SETTING_VALUE_DOMAIN_DESCRIPTIONS MALIIT_SETTING_VALUE_RANGE_MAX MALIIT_SETTING_VALUE_RANGE_MIN maliit_validate_setting_value MALIIT_TYPE_SETTINGS_ENTRY_TYPE maliit_settings_entry_type_get_type
maliitmarshallers maliit_marshal_VOID__INT_INT_INT_INT maliit_marshal_VOID__INT_STRING maliit_marshal_VOID__INT_STRING_VARIANT maliit_marshal_VOID__STRING_VARIANT
maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitattributeextension.c000066400000000000000000000406561262307254400272500ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitattributeextension.h" #include "maliitattributeextensionprivate.h" #include "maliitattributeextensionregistry.h" #include "maliitmarshallers.h" /** * SECTION:maliitattributeextension * @short_description: attribute extensions * @title: MaliitAttributeExtension * @stability: Stable * @include: maliit/maliitattributeextension.h * * #MaliitAttributeExtension class can be used by application to * override some aspect of IM plugin currently used, like the looks of * action key. */ struct _MaliitAttributeExtensionPrivate { int id; gchar *filename; GHashTable *attributes; MaliitAttributeExtensionRegistry *registry; }; G_DEFINE_TYPE (MaliitAttributeExtension, maliit_attribute_extension, G_TYPE_OBJECT) enum { EXTENDED_ATTRIBUTE_CHANGED, LAST_SIGNAL }; enum { PROP_0, PROP_ID, PROP_FILENAME, PROP_ATTRIBUTES }; static guint signals[LAST_SIGNAL] = { 0 }; static void maliit_attribute_extension_finalize (GObject *object) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object); MaliitAttributeExtensionPrivate *priv = extension->priv; g_free (priv->filename); G_OBJECT_CLASS (maliit_attribute_extension_parent_class)->finalize (object); } static void maliit_attribute_extension_dispose (GObject *object) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object); MaliitAttributeExtensionPrivate *priv = extension->priv; if (priv->registry) { MaliitAttributeExtensionRegistry *registry = priv->registry; priv->registry = NULL; maliit_attribute_extension_registry_remove_extension (registry, extension); g_object_unref (registry); } if (priv->attributes) { GHashTable *attributes = priv->attributes; priv->attributes = NULL; g_hash_table_unref (attributes); } G_OBJECT_CLASS (maliit_attribute_extension_parent_class)->dispose (object); } static void maliit_attribute_extension_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object); MaliitAttributeExtensionPrivate *priv = extension->priv; switch (prop_id) { case PROP_ID: priv->id = g_value_get_int (value); break; case PROP_FILENAME: g_free (extension->priv->filename); priv->filename = g_value_dup_string (value); break; /* PROP_ATTRIBUTES is read only. */ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void maliit_attribute_extension_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object); MaliitAttributeExtensionPrivate *priv = extension->priv; switch (prop_id) { case PROP_ID: g_value_set_int (value, priv->id); break; case PROP_FILENAME: g_value_set_string (value, priv->filename); break; case PROP_ATTRIBUTES: g_value_set_boxed (value, priv->attributes); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void maliit_attribute_extension_constructed (GObject *object) { static int id_counter = 0; MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object); MaliitAttributeExtensionPrivate *priv = extension->priv; if (priv->id == 0) { priv->id = id_counter++; } maliit_attribute_extension_registry_add_extension (priv->registry, extension); G_OBJECT_CLASS (maliit_attribute_extension_parent_class)->constructed (object); } static void maliit_attribute_extension_class_init (MaliitAttributeExtensionClass *extension_class) { GObjectClass *g_object_class = G_OBJECT_CLASS (extension_class); g_object_class->finalize = maliit_attribute_extension_finalize; g_object_class->dispose = maliit_attribute_extension_dispose; g_object_class->set_property = maliit_attribute_extension_set_property; g_object_class->get_property = maliit_attribute_extension_get_property; g_object_class->constructed = maliit_attribute_extension_constructed; /** * MaliitAttributeExtension:id: * * ID of the extension. */ g_object_class_install_property (g_object_class, PROP_ID, g_param_spec_int ("id", "ID", /* TODO: mark as translatable? */ "ID of the extension", /* TODO: mark as translatable? */ G_MININT, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitAttributeExtension:id: * * Path to file where definitions of overrides are defined. */ g_object_class_install_property (g_object_class, PROP_FILENAME, g_param_spec_string ("filename", "Filename", /* TODO: mark as translatable? */ "Filename of the extension", /* TODO: mark as translatable? */ NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); g_object_class_install_property (g_object_class, PROP_ATTRIBUTES, g_param_spec_boxed ("attributes", "Attributes", /* TODO: mark as translatable? */ "Attributes overrides", /* TODO: mark as translatable? */ G_TYPE_HASH_TABLE, G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitAttributeExtension::extended-attribute-changed: * @extension: The #MaliitAttributeExtension emitting the signal. * @key: A string specifying the target for the attribute. * @value: A new value. * * Informs application that input method server has changed the * extended attribute. */ signals[EXTENDED_ATTRIBUTE_CHANGED] = g_signal_new ("extended-attribute-changed", MALIIT_TYPE_ATTRIBUTE_EXTENSION, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, maliit_marshal_VOID__STRING_VARIANT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT); g_type_class_add_private (extension_class, sizeof (MaliitAttributeExtensionPrivate)); } static void maliit_attribute_extension_init (MaliitAttributeExtension *extension) { MaliitAttributeExtensionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, MALIIT_TYPE_ATTRIBUTE_EXTENSION, MaliitAttributeExtensionPrivate); priv->id = 0; priv->filename = NULL; priv->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); priv->registry = maliit_attribute_extension_registry_get_instance (); extension->priv = priv; } /** * maliit_attribute_extension_new: * * Creates new attribute extension, which is not associated with any file. * * Returns: (transfer full): The newly created * #MaliitAttributeExtension. */ MaliitAttributeExtension * maliit_attribute_extension_new (void) { return MALIIT_ATTRIBUTE_EXTENSION (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION, NULL)); } /** * maliit_attribute_extension_new_with_id: (skip) * @id: An overriden id. * * Creates a new attribute extension with already existing id. Used * internally by #MaliitSettingsManager. * * Returns: (transfer full): The newly created * #MaliitAttributeExtension. */ MaliitAttributeExtension * maliit_attribute_extension_new_with_id (int id) { return MALIIT_ATTRIBUTE_EXTENSION (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION, "id", id, NULL)); } /** * maliit_attribute_extension_new_with_filename: * @filename: (transfer none) (type filename): Filename where overrides are stored. * * Creates new attribute extension, which is associated with file * given as @filename. * * Returns: (transfer full): The newly created * #MaliitAttributeExtension. */ MaliitAttributeExtension * maliit_attribute_extension_new_with_filename (const gchar *filename) { return MALIIT_ATTRIBUTE_EXTENSION (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION, "filename", filename, NULL)); } /** * maliit_attribute_extension_get_attributes: * @extension: (transfer none): The #MaliitAttributeExtension which attributes you want to get. * * Gets all attributes of this extension that were set previously with * maliit_attribute_extension_set_attribute(). * * Returns: (transfer none) (element-type utf8 GLib.Variant): The #GHashTable * containing strings as keys and #GVariants as values. Should not be * freed nor modified. */ GHashTable * maliit_attribute_extension_get_attributes (MaliitAttributeExtension *extension) { g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), NULL); return extension->priv->attributes; } /** * maliit_attribute_extension_get_filename: * @extension: (transfer none): The #MaliitAttributeExtension which filename you want to get. * * Gets filename of this extension that were set previously with * maliit_attribute_extension_new_with_filename(). * * Returns: (transfer none) (type filename): The string being a * filename of this extension or %NULL. Returned string should not be * freed nor modified. */ const gchar * maliit_attribute_extension_get_filename (MaliitAttributeExtension *extension) { g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), NULL); return extension->priv->filename; } /** * maliit_attribute_extension_get_id: * @extension: (transfer none): The #MaliitAttributeExtension which ID you want to get. * * Gets ID of this extension. * * Returns: The ID of this extension. */ int maliit_attribute_extension_get_id (MaliitAttributeExtension *extension) { g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), -1); return extension->priv->id; } /** * maliit_attribute_extension_update_attribute: * @extension: (transfer none): The #MaliitAttributeExtension which attribute you want to update. * @key: (transfer none): Attribute name to update. * @value: (transfer none): Attribute value to update. * * Updates the @extension's attribute described by @key with * @value. This function always emits a * #MaliitAttributeExtension::extended-attribute-changed signal. */ void maliit_attribute_extension_update_attribute (MaliitAttributeExtension *extension, const gchar *key, GVariant *value) { g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension)); g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); g_hash_table_replace (extension->priv->attributes, g_strdup (key), g_variant_ref (value)); g_signal_emit (extension, signals[EXTENDED_ATTRIBUTE_CHANGED], 0, key, value); } /** * maliit_attribute_extension_set_attribute: * @extension: (transfer none): The #MaliitAttributeExtension which attribute you want to set. * @key: (transfer none): Attribute name to update. * @value: (transfer none): Attribute value to update. * * Sets an attribute in @extension described by @key to value in @value. */ void maliit_attribute_extension_set_attribute (MaliitAttributeExtension *extension, const gchar *key, GVariant *value) { MaliitAttributeExtensionPrivate *priv; GHashTable *attributes; GVariant *orig_value; g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension)); g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); priv = extension->priv; attributes = priv->attributes; if (!g_hash_table_lookup_extended (attributes, key, NULL, (gpointer *)&orig_value) || !g_variant_equal (orig_value, value)) { g_hash_table_replace (attributes, g_strdup (key), g_variant_ref (value)); maliit_attribute_extension_registry_extension_changed (priv->registry, extension, key, value); } } /** * maliit_attribute_extension_attach_to_object: * @extension: (transfer none): The #MaliitAttributeExtension which you want to be attached. * @object: (transfer none): The #GObject to which @extension will be attached. * * Attaches @extension to @object, so input context can retrieve it * from @object. Note that attaching extensions to non-input * #GObjects does not have much sense. */ void maliit_attribute_extension_attach_to_object (MaliitAttributeExtension *extension, GObject *object) { g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension)); g_return_if_fail (G_IS_OBJECT (object)); g_object_set_qdata_full (object, MALIIT_ATTRIBUTE_EXTENSION_DATA_QUARK, extension, g_object_unref); } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitattributeextension.h000066400000000000000000000070161262307254400272460ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_ATTRIBUTE_EXTENSION_H #define MALIIT_GLIB_ATTRIBUTE_EXTENSION_H #include #include G_BEGIN_DECLS #define MALIIT_ATTRIBUTE_EXTENSION_DATA "maliit-attribute-extension" #define MALIIT_ATTRIBUTE_EXTENSION_DATA_QUARK (g_quark_from_string (MALIIT_ATTRIBUTE_EXTENSION_DATA)) #define MALIIT_TYPE_ATTRIBUTE_EXTENSION (maliit_attribute_extension_get_type()) #define MALIIT_ATTRIBUTE_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, MALIIT_TYPE_ATTRIBUTE_EXTENSION, MaliitAttributeExtension)) #define MALIIT_ATTRIBUTE_EXTENSION_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, MALIIT_TYPE_ATTRIBUTE_EXTENSION, MaliitAttributeExtensionClass)) #define MALIIT_IS_ATTRIBUTE_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, MALIIT_TYPE_ATTRIBUTE_EXTENSION)) #define MALIIT_IS_ATTRIBUTE_EXTENSION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, MALIIT_TYPE_ATTRIBUTE_EXTENSION)) #define MALIIT_ATTRIBUTE_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MALIIT_TYPE_ATTRIBUTE_EXTENSION, MaliitAttributeExtensionClass)) typedef struct _MaliitAttributeExtension MaliitAttributeExtension; typedef struct _MaliitAttributeExtensionClass MaliitAttributeExtensionClass; typedef struct _MaliitAttributeExtensionPrivate MaliitAttributeExtensionPrivate; struct _MaliitAttributeExtension { GObject parent; /*< private >*/ MaliitAttributeExtensionPrivate *priv; }; /** * MaliitAttributeExtensionClass: * @parent_class: The parent class. */ struct _MaliitAttributeExtensionClass { GObjectClass parent_class; }; GType maliit_attribute_extension_get_type (void) G_GNUC_CONST; MaliitAttributeExtension * maliit_attribute_extension_new (void); MaliitAttributeExtension * maliit_attribute_extension_new_with_filename (const gchar* filename); GHashTable * maliit_attribute_extension_get_attributes (MaliitAttributeExtension *extension); const gchar * maliit_attribute_extension_get_filename (MaliitAttributeExtension *extension); int maliit_attribute_extension_get_id (MaliitAttributeExtension *extension); void maliit_attribute_extension_update_attribute (MaliitAttributeExtension *extension, const gchar *key, GVariant *value); void maliit_attribute_extension_set_attribute (MaliitAttributeExtension *extension, const gchar *key, GVariant *value); void maliit_attribute_extension_attach_to_object (MaliitAttributeExtension *extension, GObject *object); G_END_DECLS #endif /* MALIIT_GLIB_ATTRIBUTE_EXTENSION_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitattributeextensionprivate.h000066400000000000000000000022401262307254400306330ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_ATTRIBUTE_EXTENSION_PRIVATE_H #define MALIIT_GLIB_ATTRIBUTE_EXTENSION_PRIVATE_H #include #include "maliitattributeextension.h" MaliitAttributeExtension * maliit_attribute_extension_new_with_id (int id); #endif /* MALIIT_GLIB_ATTRIBUTE_EXTENSION_PRIVATE_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitattributeextensionregistry.c000066400000000000000000000350461262307254400310360ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitattributeextensionregistry.h" #include "maliitbus.h" struct _MaliitAttributeExtensionRegistryPrivate { GHashTable *extensions; }; static MaliitAttributeExtensionRegistry *global_singleton; G_DEFINE_TYPE (MaliitAttributeExtensionRegistry, maliit_attribute_extension_registry, G_TYPE_OBJECT) static void maliit_attribute_extension_registry_finalize (GObject *object) { global_singleton = NULL; G_OBJECT_CLASS (maliit_attribute_extension_registry_parent_class)->finalize (object); } static void extension_notify (gpointer data, GObject *where_the_object_was) { MaliitAttributeExtensionRegistry *registry = MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (data); MaliitAttributeExtensionRegistryPrivate *priv = registry->priv; GHashTableIter iter; MaliitAttributeExtension *extension; g_hash_table_iter_init (&iter, priv->extensions); while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&extension)) { if ((gpointer)extension == (gpointer)where_the_object_was) { g_hash_table_iter_steal (&iter); break; } } } static void maliit_attribute_extension_registry_dispose (GObject *object) { MaliitAttributeExtensionRegistry *registry = MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (object); MaliitAttributeExtensionRegistryPrivate *priv = registry->priv; if (priv->extensions) { GHashTable *extensions = priv->extensions; priv->extensions = NULL; g_hash_table_unref (extensions); } G_OBJECT_CLASS (maliit_attribute_extension_registry_parent_class)->dispose (object); } static GObject* maliit_attribute_extension_registry_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; if (global_singleton) { object = g_object_ref (G_OBJECT (global_singleton)); } else { object = G_OBJECT_CLASS (maliit_attribute_extension_registry_parent_class)->constructor (type, n_params, params); /* We are doing an additional reference here, so object will not * be destroyed when last owner removes its reference. This is a * leak, but for now it ensures that singleton have a lifetime of * application. This needs to be fixed, when object lifetimes are * fixed in gtk-input-context. */ global_singleton = MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (g_object_ref (object)); } return object; } static void maliit_attribute_extension_registry_class_init (MaliitAttributeExtensionRegistryClass *registry_class) { GObjectClass *g_object_class = G_OBJECT_CLASS (registry_class); g_object_class->finalize = maliit_attribute_extension_registry_finalize; g_object_class->dispose = maliit_attribute_extension_registry_dispose; g_object_class->constructor = maliit_attribute_extension_registry_constructor; g_type_class_add_private (registry_class, sizeof (MaliitAttributeExtensionRegistryPrivate)); } static void extension_weak_unref (MaliitAttributeExtension *extension, MaliitAttributeExtensionRegistry *registry) { g_object_weak_unref (G_OBJECT (extension), extension_notify, registry); } static void extension_weak_unref_global (gpointer data) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (data); extension_weak_unref (extension, global_singleton); } static void register_all_extensions (MaliitServer *server, gpointer user_data) { MaliitAttributeExtensionRegistry *registry = user_data; GList *extensions = maliit_attribute_extension_registry_get_extensions (registry); GList *iter; GError *error = NULL; for (iter = extensions; iter; iter = iter->next) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (iter->data); if (maliit_server_call_register_attribute_extension_sync (server, maliit_attribute_extension_get_id (extension), maliit_attribute_extension_get_filename (extension), NULL, &error)) { GHashTable *attributes = maliit_attribute_extension_get_attributes (extension); GHashTableIter attributes_iter; gpointer key; gpointer value; g_hash_table_iter_init (&attributes_iter, attributes); while (g_hash_table_iter_next (&attributes_iter, &key, &value)) { maliit_attribute_extension_registry_extension_changed(registry, extension, key, value); } } else { g_warning ("Could not register an extension in mass registerer: %s", error->message); g_clear_error (&error); } } g_list_free (extensions); } static void connection_established (GObject *source_object G_GNUC_UNUSED, GAsyncResult *res, gpointer user_data) { GError *error = NULL; MaliitServer *server = maliit_get_server_finish (res, &error); if (server) { register_all_extensions (server, user_data); } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } } static void maliit_attribute_extension_registry_init (MaliitAttributeExtensionRegistry *registry) { MaliitAttributeExtensionRegistryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (registry, MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY, MaliitAttributeExtensionRegistryPrivate); priv->extensions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, extension_weak_unref_global); registry->priv = priv; maliit_get_server (NULL, connection_established, registry); } MaliitAttributeExtensionRegistry * maliit_attribute_extension_registry_get_instance (void) { return MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY, NULL)); } void maliit_attribute_extension_registry_add_extension (MaliitAttributeExtensionRegistry *registry, MaliitAttributeExtension *extension) { MaliitServer *server; GHashTable *extensions; gint id; GError *error = NULL; g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry)); g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension)); extensions = registry->priv->extensions; id = maliit_attribute_extension_get_id (extension); if (!g_hash_table_lookup_extended (extensions, GINT_TO_POINTER (id), NULL, NULL)) { g_object_weak_ref (G_OBJECT (extension), extension_notify, registry); g_hash_table_insert (extensions, GINT_TO_POINTER (id), extension); server = maliit_get_server_sync (NULL, &error); if (server) { if (!maliit_server_call_register_attribute_extension_sync (server, id, maliit_attribute_extension_get_filename (extension), NULL, &error)) { g_warning ("Unable to register extension: %s", error->message); g_clear_error (&error); } } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } } } void maliit_attribute_extension_registry_remove_extension (MaliitAttributeExtensionRegistry *registry, MaliitAttributeExtension *extension) { MaliitServer *server; GHashTable *extensions; gint id; GError *error = NULL; g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry)); g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension)); extensions = registry->priv->extensions; id = maliit_attribute_extension_get_id (extension); if (g_hash_table_lookup_extended (extensions, GINT_TO_POINTER (id), NULL, NULL)) { g_hash_table_remove (extensions, GINT_TO_POINTER (id)); server = maliit_get_server_sync (NULL, &error); if (server) { if (!maliit_server_call_unregister_attribute_extension_sync (server, id, NULL, &error)) { g_warning ("Unable to unregister extension: %s", error->message); g_clear_error (&error); } } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } } } /* For glib < 2.30 */ #ifndef G_VALUE_INIT #define G_VALUE_INIT { 0, { { 0 } } } #endif void maliit_attribute_extension_registry_extension_changed (MaliitAttributeExtensionRegistry *registry, MaliitAttributeExtension *extension, const gchar *key, GVariant *value) { MaliitServer *server; gchar **parts; GError *error = NULL; g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry)); g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension)); g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); parts = g_strsplit (key + 1, "/", 3); if (!parts) return; if (g_strv_length (parts) == 3) { gchar *target = g_strdup_printf ("/%s", parts[0]); server = maliit_get_server_sync (NULL, &error); if (server) { if (!maliit_server_call_set_extended_attribute_sync (server, maliit_attribute_extension_get_id (extension), target, parts[1], parts[2], value, NULL, &error)) { g_warning ("Unable to set extended attribute: %s", error->message); g_clear_error (&error); } } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } g_free (target); } else { g_warning("Key `%s' is not valid. It needs to be `/target/item/key'", key); } g_strfreev (parts); } static void fill_list_with_extensions (gpointer key G_GNUC_UNUSED, gpointer value, gpointer user_data) { MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (value); GList **list = (GList **)user_data; *list = g_list_prepend (*list, extension); } GList * maliit_attribute_extension_registry_get_extensions (MaliitAttributeExtensionRegistry *registry) { GList *list; g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry), NULL); list = NULL; g_hash_table_foreach (registry->priv->extensions, fill_list_with_extensions, &list); return list; } void maliit_attribute_extension_registry_update_attribute (MaliitAttributeExtensionRegistry *registry, gint id, const gchar *target, const gchar *target_item, const gchar *attribute, GVariant *value) { MaliitAttributeExtension *extension; g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry)); g_return_if_fail (id >= 0); g_return_if_fail (target != NULL); g_return_if_fail (target_item != NULL); g_return_if_fail (attribute != NULL); g_return_if_fail (value != NULL); if (g_hash_table_lookup_extended (registry->priv->extensions, GINT_TO_POINTER (id), NULL, (gpointer *)&extension)) { gchar *key = g_strdup_printf ("%s/%s/%s", target, target_item, attribute); maliit_attribute_extension_update_attribute (extension, key, value); g_free (key); } else { g_warning ("Extension %d was not found.", id); } } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitattributeextensionregistry.h000066400000000000000000000100161262307254400310310ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_ATTRIBUTE_EXTENSION_REGISTRY_H #define MALIIT_GLIB_ATTRIBUTE_EXTENSION_REGISTRY_H #include #include #include "maliitattributeextension.h" G_BEGIN_DECLS #define MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY (maliit_attribute_extension_registry_get_type()) #define MALIIT_ATTRIBUTE_EXTENSION_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY, MaliitAttributeExtensionRegistry)) #define MALIIT_ATTRIBUTE_EXTENSION_REGISTRY_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY, MaliitAttributeExtensionRegistryClass)) #define MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY)) #define MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY)) #define MALIIT_ATTRIBUTE_EXTENSION_REGISTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY, MaliitAttributeExtensionRegistryClass)) typedef struct _MaliitAttributeExtensionRegistry MaliitAttributeExtensionRegistry; typedef struct _MaliitAttributeExtensionRegistryClass MaliitAttributeExtensionRegistryClass; typedef struct _MaliitAttributeExtensionRegistryPrivate MaliitAttributeExtensionRegistryPrivate; struct _MaliitAttributeExtensionRegistry { GObject parent; /*< private >*/ MaliitAttributeExtensionRegistryPrivate *priv; }; /** * MaliitAttributeExtensionRegistryClass: * @parent_class: The parent class. */ struct _MaliitAttributeExtensionRegistryClass { GObjectClass parent_class; }; GType maliit_attribute_extension_registry_get_type (void) G_GNUC_CONST; MaliitAttributeExtensionRegistry * maliit_attribute_extension_registry_get_instance (void); void maliit_attribute_extension_registry_add_extension (MaliitAttributeExtensionRegistry *registry, MaliitAttributeExtension *extension); void maliit_attribute_extension_registry_remove_extension (MaliitAttributeExtensionRegistry *registry, MaliitAttributeExtension *extension); void maliit_attribute_extension_registry_extension_changed (MaliitAttributeExtensionRegistry *registry, MaliitAttributeExtension *extension, const gchar *key, GVariant *value); GList * maliit_attribute_extension_registry_get_extensions (MaliitAttributeExtensionRegistry *registry); void maliit_attribute_extension_registry_update_attribute (MaliitAttributeExtensionRegistry *registry, gint id, const gchar *target, const gchar *target_item, const gchar *attribute, GVariant *value); G_END_DECLS #endif /* MALIIT_GLIB_ATTRIBUTE_EXTENSION_REGISTRY_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitbus.c000066400000000000000000000230261262307254400240710ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2015 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitbus.h" #define ADDRESS_ENV "MALIIT_SERVER_ADDRESS" #define ADDRESS_BUS_NAME "org.maliit.server" #define ADDRESS_OBJECT_PATH "/org/maliit/server/address" #define ADDRESS_INTERFACE "org.maliit.Server.Address" #define ADDRESS_PROPERTY "address" #define SERVER_OBJECT_PATH "/com/meego/inputmethod/uiserver1" #define CONTEXT_OBJECT_PATH "/com/meego/inputmethod/inputcontext" static gchar *address; static GDBusConnection *bus; static MaliitServer *server; static MaliitContext *context; static const gchar * maliit_get_address_sync (gboolean verbose) { GDBusProxy *proxy; GVariant *property; GError *error = NULL; if (!address) { address = g_strdup (g_getenv (ADDRESS_ENV)); if (!address) { proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, NULL, ADDRESS_BUS_NAME, ADDRESS_OBJECT_PATH, ADDRESS_INTERFACE, NULL, &error); if (proxy) { property = g_dbus_proxy_get_cached_property (proxy, ADDRESS_PROPERTY); if (property) { address = g_strdup (g_variant_get_string (property, NULL)); g_variant_unref (property); } else if (verbose) g_warning ("Unable to find address property"); g_object_unref (proxy); } else if (verbose) { g_warning ("Unable to find bus address: %s", error->message); g_clear_error (&error); } } } return address; } static void maliit_get_bus (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (callback); if (!bus) g_dbus_connection_new_for_address (maliit_get_address_sync (TRUE), G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, cancellable, callback, user_data); else callback (NULL, NULL, user_data); } static GDBusConnection * maliit_get_bus_finish (GAsyncResult *res, GError **error) { if (!bus) bus = g_dbus_connection_new_for_address_finish (res, error); return bus; } static GDBusConnection * maliit_get_bus_sync (GCancellable *cancellable, GError **error) { if (!bus) bus = g_dbus_connection_new_for_address_sync (maliit_get_address_sync (TRUE), G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, cancellable, error); return bus; } void maliit_set_bus (GDBusConnection *bus_) { if (bus_ != bus) { g_clear_object (&context); g_clear_object (&server); g_clear_object (&bus); g_clear_pointer (&address, g_free); if (bus_) bus = g_object_ref (bus_); } } gboolean maliit_is_running (void) { gboolean running = FALSE; const gchar *address; GDBusConnection *bus; MaliitServer *server; address = maliit_get_address_sync (FALSE); if (address) { bus = maliit_get_bus_sync (NULL, NULL); if (bus) { server = maliit_server_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, NULL, SERVER_OBJECT_PATH, NULL, NULL); if (server) { running = TRUE; g_object_unref (server); } } } return running; } void maliit_get_server (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GDBusConnection *bus; GError *error = NULL; g_return_if_fail (callback); if (!server) { bus = maliit_get_bus_sync (cancellable, &error); if (bus) maliit_server_proxy_new (bus, G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, NULL, SERVER_OBJECT_PATH, cancellable, callback, user_data); else { g_warning ("Unable to connect to bus: %s", error->message); g_clear_error (&error); } } else callback (NULL, NULL, user_data); } MaliitServer * maliit_get_server_finish (GAsyncResult *res, GError **error) { if (!server) server = maliit_server_proxy_new_finish (res, error); return server; } MaliitServer * maliit_get_server_sync (GCancellable *cancellable, GError **error) { GDBusConnection *bus; if (!server) { bus = maliit_get_bus_sync (cancellable, error); if (bus) server = maliit_server_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, NULL, SERVER_OBJECT_PATH, cancellable, error); } return server; } static gboolean maliit_context_handle_plugin_settings_loaded (MaliitContext *context, GDBusMethodInvocation *invocation, GVariant *plugins G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { maliit_context_complete_plugin_settings_loaded (context, invocation); return TRUE; } static gboolean maliit_context_handle_update_input_method_area (MaliitContext *context, GDBusMethodInvocation *invocation, gint x G_GNUC_UNUSED, gint y G_GNUC_UNUSED, gint width G_GNUC_UNUSED, gint height G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { maliit_context_complete_update_input_method_area (context, invocation); return TRUE; } void maliit_get_context (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_return_if_fail (callback); maliit_get_bus (cancellable, callback, user_data); } MaliitContext * maliit_get_context_finish (GAsyncResult *res, GError **error) { maliit_get_bus_finish (res, error); return maliit_get_context_sync (NULL, error); } MaliitContext * maliit_get_context_sync (GCancellable *cancellable, GError **error) { GDBusConnection *bus; if (!context) { bus = maliit_get_bus_sync (cancellable, error); if (bus) { context = maliit_context_skeleton_new (); g_signal_connect_after (context, "handle-plugin-settings-loaded", G_CALLBACK (maliit_context_handle_plugin_settings_loaded), NULL); g_signal_connect_after (context, "handle-update-input-method-area", G_CALLBACK (maliit_context_handle_update_input_method_area), NULL); if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (context), bus, CONTEXT_OBJECT_PATH, error)) g_clear_object (&context); } } return context; } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitbus.h000066400000000000000000000041701262307254400240750ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2015 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_BUS_H #define MALIIT_GLIB_BUS_H #include #include "maliitserver.h" #include "maliitcontext.h" G_BEGIN_DECLS gboolean maliit_is_running (void); void maliit_get_server (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); MaliitServer * maliit_get_server_finish (GAsyncResult *res, GError **error); MaliitServer * maliit_get_server_sync (GCancellable *cancellable, GError **error); void maliit_get_context (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); MaliitContext * maliit_get_context_finish (GAsyncResult *res, GError **error); MaliitContext * maliit_get_context_sync (GCancellable *cancellable, GError **error); G_END_DECLS #endif /* MALIIT_GLIB_BUS_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitbusprivate.h000066400000000000000000000021041262307254400254630ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2015 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_BUS_PRIVATE_H #define MALIIT_GLIB_BUS_PRIVATE_H #include G_BEGIN_DECLS void maliit_set_bus (GDBusConnection *bus); G_END_DECLS #endif /* MALIIT_GLIB_BUS_PRIVATE_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitinputmethod.c000066400000000000000000000210371262307254400256400ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitinputmethod.h" #include "maliitmarshallers.h" #include "maliitbus.h" /** * SECTION:maliitinputmethod * @short_description: input method handling * @title: MaliitInputMethod * @stability: Stable * @include: maliit/maliitinputmethod.h * * #MaliitInputMethod class can be used by application to query * maliit-server for currently shown IM plugin area and to request * maliit-server to show or hide the IM plugin. */ struct _MaliitInputMethodPrivate { int area[4]; MaliitServer *maliit_proxy; }; G_DEFINE_TYPE (MaliitInputMethod, maliit_input_method, G_TYPE_OBJECT) enum { AREA_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void maliit_input_method_finalize (GObject *object) { G_OBJECT_CLASS (maliit_input_method_parent_class)->finalize (object); } static void maliit_input_method_dispose (GObject *object) { GError *error = NULL; MaliitInputMethod *input_method = MALIIT_INPUT_METHOD (object); MaliitInputMethodPrivate *priv = input_method->priv; MaliitContext *context = maliit_get_context_sync (NULL, &error); if (context) { g_signal_handlers_disconnect_by_data (context, input_method); } else { g_warning ("Unable to connect to context: %s", error->message); g_clear_error (&error); } g_clear_object (&priv->maliit_proxy); G_OBJECT_CLASS (maliit_input_method_parent_class)->dispose (object); } static void maliit_input_method_class_init (MaliitInputMethodClass *input_method_class) { GObjectClass *g_object_class = G_OBJECT_CLASS (input_method_class); g_object_class->finalize = maliit_input_method_finalize; g_object_class->dispose = maliit_input_method_dispose; /** * MaliitInputMethod::area-changed: * @input_method: The #MaliitInputMethod emitting the signal. * @x: X coordinate of new input method area's top-left corner. * @y: Y coordinate of new input method area's top-left corner. *. * @width: Width of new input method area. * @height: Height of new input method area. * * Informs application that the input method area (area on the screen * occupied by a virtual keyboard) is changed. */ signals[AREA_CHANGED] = g_signal_new ("area-changed", MALIIT_TYPE_INPUT_METHOD, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, maliit_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); g_type_class_add_private (input_method_class, sizeof (MaliitInputMethodPrivate)); } static gboolean update_input_method_area(MaliitInputMethod *input_method, GDBusMethodInvocation *invocation G_GNUC_UNUSED, int x, int y, int width, int height, gpointer user_data G_GNUC_UNUSED) { input_method->priv->area[0] = x; input_method->priv->area[1] = y; input_method->priv->area[2] = width; input_method->priv->area[3] = height; g_signal_emit(input_method, signals[AREA_CHANGED], 0, x, y, width, height); return FALSE; } static void maliit_input_method_init (MaliitInputMethod *input_method) { MaliitInputMethodPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (input_method, MALIIT_TYPE_INPUT_METHOD, MaliitInputMethodPrivate); MaliitContext *context; GError *error = NULL; priv->area[0] = priv->area[1] = 0; priv->area[2] = priv->area[3] = 0; priv->maliit_proxy = maliit_get_server_sync (NULL, &error); if (priv->maliit_proxy) { g_object_ref (priv->maliit_proxy); } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } input_method->priv = priv; context = maliit_get_context_sync (NULL, &error); if (context) { g_signal_connect_swapped (context, "handle-update-input-method-area", G_CALLBACK (update_input_method_area), input_method); } else { g_warning ("Unable to connect to context: %s", error->message); g_clear_error (&error); } } /** * maliit_input_method_new: * * Returns a new maliit input method. * * Returns: (transfer full): A new #MaliitInputMethod. */ MaliitInputMethod * maliit_input_method_new (void) { return MALIIT_INPUT_METHOD (g_object_new (MALIIT_TYPE_INPUT_METHOD, NULL)); } /** * maliit_input_method_get_area: * @input_method: (transfer none): The #MaliitInputMethod which input method area you want to get. * @x: (out): X coordinate of current input method area's top-left corner. * @y: (out): Y coordinate of current input method area's top-left corner. * @width: (out): Width of current input method area. * @height: (out): Height of current input method area. * * Get the current input method area in @x, @y, @width and @height. */ void maliit_input_method_get_area (MaliitInputMethod *input_method, int *x, int *y, int *width, int *height) { g_return_if_fail (MALIIT_IS_INPUT_METHOD (input_method)); if (x) *x = input_method->priv->area[0]; if (y) *y = input_method->priv->area[1]; if (width) *width = input_method->priv->area[2]; if (height) *height = input_method->priv->area[3]; } /** * maliit_input_method_show: * @input_method: (transfer none): The #MaliitInputMethod which you want to show. * * Request to explicitly show the Maliit virtual keyboard. */ void maliit_input_method_show (MaliitInputMethod *input_method) { GError *error = NULL; g_return_if_fail (MALIIT_IS_INPUT_METHOD (input_method)); g_return_if_fail (input_method->priv->maliit_proxy); if (!maliit_server_call_activate_context_sync (input_method->priv->maliit_proxy, NULL, &error)) { g_warning ("Unable to activate context: %s", error->message); g_clear_error (&error); } if (!maliit_server_call_show_input_method_sync (input_method->priv->maliit_proxy, NULL, &error)) { g_warning ("Unable to show input method: %s", error->message); g_clear_error (&error); } } /** * maliit_input_method_hide: * @input_method: (transfer none): The #MaliitInputMethod which you want to hide. * * Request to explicitly hide the Maliit virtual keyboard. */ void maliit_input_method_hide (MaliitInputMethod *input_method) { GError *error = NULL; g_return_if_fail (MALIIT_IS_INPUT_METHOD (input_method)); g_return_if_fail (input_method->priv->maliit_proxy); if (!maliit_server_call_activate_context_sync (input_method->priv->maliit_proxy, NULL, &error)) { g_warning ("Unable to activate context: %s", error->message); g_clear_error (&error); } if (!maliit_server_call_hide_input_method_sync (input_method->priv->maliit_proxy, NULL, &error)) { g_warning ("Unable to hide input method: %s", error->message); g_clear_error (&error); } } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitinputmethod.h000066400000000000000000000050201262307254400256370ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_INPUT_METHOD_H #define MALIIT_GLIB_INPUT_METHOD_H #include #include G_BEGIN_DECLS #define MALIIT_TYPE_INPUT_METHOD (maliit_input_method_get_type()) #define MALIIT_INPUT_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, MALIIT_TYPE_INPUT_METHOD, MaliitInputMethod)) #define MALIIT_INPUT_METHOD_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, MALIIT_TYPE_INPUT_METHOD, MaliitInputMethodClass)) #define MALIIT_IS_INPUT_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, MALIIT_TYPE_INPUT_METHOD)) #define MALIIT_IS_INPUT_METHOD_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, MALIIT_TYPE_INPUT_METHOD)) #define MALIIT_INPUT_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MALIIT_TYPE_INPUT_METHOD, MaliitInputMethodClass)) typedef struct _MaliitInputMethod MaliitInputMethod; typedef struct _MaliitInputMethodClass MaliitInputMethodClass; typedef struct _MaliitInputMethodPrivate MaliitInputMethodPrivate; struct _MaliitInputMethod { GObject parent; /*< private >*/ MaliitInputMethodPrivate *priv; }; /** * MaliitInputMethodClass: * @parent_class: The parent class. */ struct _MaliitInputMethodClass { GObjectClass parent_class; }; GType maliit_input_method_get_type (void) G_GNUC_CONST; MaliitInputMethod * maliit_input_method_new (void); void maliit_input_method_get_area (MaliitInputMethod *input_method, int *x, int *y, int *width, int *height); void maliit_input_method_show (MaliitInputMethod *input_method); void maliit_input_method_hide (MaliitInputMethod *input_method); G_END_DECLS #endif /* MALIIT_GLIB_INPUT_METHOD_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitmarshallers.list000066400000000000000000000001211262307254400263350ustar00rootroot00000000000000VOID:STRING,VARIANT VOID:INT,STRING VOID:INT,STRING,VARIANT VOID:INT,INT,INT,INT maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitpluginsettings.c000066400000000000000000000343771262307254400263720ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitpluginsettingsprivate.h" #include "maliitsettingsentryprivate.h" /** * SECTION:maliitpluginsettings * @short_description: plugin settings * @title: MaliitPluginSettings * @see_also: #MaliitSettingsEntry, #MaliitSettingsManager * @stability: Stable * @include: maliit/maliitpluginsettings.h * * The #MaliitPluginSettings is a class holding general plugin * information like name, description and configuration entries. */ struct _MaliitPluginSettingsPrivate { gchar *description_language; gchar *plugin_name; gchar *plugin_description; GPtrArray *entries; }; G_DEFINE_TYPE (MaliitPluginSettings, maliit_plugin_settings, G_TYPE_OBJECT) enum { PROP_0, PROP_DESCRIPTION_LANGUAGE, PROP_PLUGIN_NAME, PROP_PLUGIN_DESCRIPTION, PROP_CONFIGURATION_ENTRIES }; static void maliit_plugin_settings_finalize (GObject *object) { MaliitPluginSettings *settings = MALIIT_PLUGIN_SETTINGS (object); MaliitPluginSettingsPrivate *priv = settings->priv; g_free (priv->description_language); g_free (priv->plugin_name); g_free (priv->plugin_description); G_OBJECT_CLASS (maliit_plugin_settings_parent_class)->finalize (object); } static void maliit_plugin_settings_dispose (GObject *object) { MaliitPluginSettings *settings = MALIIT_PLUGIN_SETTINGS (object); MaliitPluginSettingsPrivate *priv = settings->priv; if (priv->entries) { GPtrArray *entries = priv->entries; priv->entries = NULL; g_ptr_array_unref (entries); } G_OBJECT_CLASS (maliit_plugin_settings_parent_class)->dispose (object); } static void maliit_plugin_settings_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MaliitPluginSettings *settings = MALIIT_PLUGIN_SETTINGS (object); MaliitPluginSettingsPrivate *priv = settings->priv; switch (prop_id) { case PROP_DESCRIPTION_LANGUAGE: g_free (priv->description_language); priv->description_language = g_value_dup_string (value); break; case PROP_PLUGIN_NAME: g_free (priv->plugin_name); priv->plugin_name = g_value_dup_string (value); break; case PROP_PLUGIN_DESCRIPTION: g_free (priv->plugin_description); priv->plugin_description = g_value_dup_string (value); break; case PROP_CONFIGURATION_ENTRIES: if (priv->entries) { g_ptr_array_unref (priv->entries); } priv->entries = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void maliit_plugin_settings_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MaliitPluginSettings *settings = MALIIT_PLUGIN_SETTINGS (object); MaliitPluginSettingsPrivate *priv = settings->priv; switch (prop_id) { case PROP_DESCRIPTION_LANGUAGE: g_value_set_string (value, priv->description_language); break; case PROP_PLUGIN_NAME: g_value_set_string (value, priv->plugin_name); break; case PROP_PLUGIN_DESCRIPTION: g_value_set_string (value, priv->plugin_description); break; case PROP_CONFIGURATION_ENTRIES: g_value_set_boxed (value, priv->entries); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void maliit_plugin_settings_class_init (MaliitPluginSettingsClass *settings_class) { GObjectClass *g_object_class = G_OBJECT_CLASS (settings_class); g_object_class->finalize = maliit_plugin_settings_finalize; g_object_class->dispose = maliit_plugin_settings_dispose; g_object_class->set_property = maliit_plugin_settings_set_property; g_object_class->get_property = maliit_plugin_settings_get_property; /** * MaliitPluginSettings:description-language: * * Language of the plugin description. */ g_object_class_install_property (g_object_class, PROP_DESCRIPTION_LANGUAGE, g_param_spec_string ("description-language", "Description language", /* TODO: mark as translatable? */ "Language of the plugin description", /* TODO: mark as translatable? */ "en", G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitPluginSettings:plugin-name: * * Name of the plugin. */ g_object_class_install_property (g_object_class, PROP_PLUGIN_NAME, g_param_spec_string ("plugin-name", "Plugin name", /* TODO: mark as translatable? */ "Name of the plugin", /* TODO: mark as translatable? */ "unknown", G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitPluginSettings:plugin-description: * * Description of the plugin. */ g_object_class_install_property (g_object_class, PROP_PLUGIN_DESCRIPTION, g_param_spec_string ("plugin-description", "Plugin description", /* TODO: mark as translatable? */ "Description of the plugin", /* TODO: mark as translatable? */ "", G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /* TODO: this property appears as array of gpointers in gir file. * I have no clue how to fix it. */ /** * MaliitPluginSettings:configuration-entries: (element-type Maliit.SettingsEntry) * * List of configuration entries of the plugin. */ g_object_class_install_property (g_object_class, PROP_CONFIGURATION_ENTRIES, g_param_spec_boxed ("configuration-entries", "Configuration entries", /* TODO: mark as translatable? */ "List of configuration entries of the plugin", /* TODO: mark as translatable? */ G_TYPE_PTR_ARRAY, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); g_type_class_add_private (settings_class, sizeof (MaliitPluginSettingsPrivate)); } static void maliit_plugin_settings_init (MaliitPluginSettings *settings) { MaliitPluginSettingsPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (settings, MALIIT_TYPE_PLUGIN_SETTINGS, MaliitPluginSettingsPrivate); priv->description_language = NULL; priv->plugin_name = NULL; priv->plugin_description = NULL; priv->entries = NULL; settings->priv = priv; } static GPtrArray * configuration_entries_from_dbus_g_variant (GVariant *dbus_entries, MaliitAttributeExtension *extension) { GPtrArray *configuration_entries = g_ptr_array_sized_new (g_variant_n_children (dbus_entries)); guint iter; g_ptr_array_set_free_func (configuration_entries, g_object_unref); for (iter = 0; iter < g_variant_n_children (dbus_entries); ++iter) { GVariant *info = g_variant_get_child_value (dbus_entries, iter); g_ptr_array_add (configuration_entries, maliit_settings_entry_new_from_dbus_data (info, extension)); g_variant_unref (info); } return configuration_entries; } /** * maliit_plugin_settings_new_from_dbus_data: (skip) * @plugin_info: A #GVariant of DBus provenance containing plugin information. * @extension: A #MaliitAttributeExtensions for #MaliitAttributeSettingsEntry instances. * * Creates new settings settings. This is used internally only by * #MaliitSettingsManager. * * Returns: The newly created #MaliitPluginSettings. */ MaliitPluginSettings * maliit_plugin_settings_new_from_dbus_data (GVariant *plugin_info, MaliitAttributeExtension *extension) { const gchar *description_language; const gchar *plugin_name; const gchar *plugin_description; GVariant *plugin_entries; GPtrArray *configuration_entries; MaliitPluginSettings *settings; g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), NULL); g_variant_get (plugin_info, "(&s&s&si@a(ssibva{sv}))", &description_language, &plugin_name, &plugin_description, NULL, &plugin_entries); configuration_entries = configuration_entries_from_dbus_g_variant (plugin_entries, extension); settings = MALIIT_PLUGIN_SETTINGS (g_object_new (MALIIT_TYPE_PLUGIN_SETTINGS, "description-language", description_language, "plugin-name", plugin_name, "plugin-description", plugin_description, "configuration-entries", configuration_entries, NULL)); g_ptr_array_unref (configuration_entries); g_variant_unref (plugin_entries); return settings; } /** * maliit_plugin_settings_get_description_language: * @settings: (transfer none): The #MaliitPluginSettings. * * Gets language of the plugin description. * * Returns: (transfer none): A language. Returned value should not be modified nor freed. */ const gchar * maliit_plugin_settings_get_description_language (MaliitPluginSettings *settings) { g_return_val_if_fail (MALIIT_IS_PLUGIN_SETTINGS (settings), NULL); return settings->priv->description_language; } /** * maliit_plugin_settings_get_plugin_name: * @settings: (transfer none): The #MaliitPluginSettings. * * Gets name of the plugin. * * Returns: (transfer none): A name. Returned value should not be modified nor freed. */ const gchar * maliit_plugin_settings_get_plugin_name (MaliitPluginSettings *settings) { g_return_val_if_fail (MALIIT_IS_PLUGIN_SETTINGS (settings), NULL); return settings->priv->plugin_name; } /** * maliit_plugin_settings_get_plugin_description: * @settings: (transfer none): The #MaliitPluginSettings. * * Gets description of the plugin. * * Returns: (transfer none): A description. Returned value should not be modified nor freed. */ const gchar * maliit_plugin_settings_get_plugin_description (MaliitPluginSettings *settings) { g_return_val_if_fail (MALIIT_IS_PLUGIN_SETTINGS (settings), NULL); return settings->priv->plugin_description; } /** * maliit_plugin_settings_get_configuration_entries: * @settings: (transfer none): The #MaliitPluginSettings. * * Gets configuration entries of the plugin * * Returns: (transfer none) (element-type Maliit.SettingsEntry): Configuration entries. Returned value should not be modified nor freed. */ GPtrArray * maliit_plugin_settings_get_configuration_entries (MaliitPluginSettings *settings) { g_return_val_if_fail (MALIIT_IS_PLUGIN_SETTINGS (settings), NULL); return settings->priv->entries; } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitpluginsettings.h000066400000000000000000000051501262307254400263620ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_PLUGIN_SETTINGS_H #define MALIIT_GLIB_PLUGIN_SETTINGS_H #include #include G_BEGIN_DECLS #define MALIIT_TYPE_PLUGIN_SETTINGS (maliit_plugin_settings_get_type()) #define MALIIT_PLUGIN_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, MALIIT_TYPE_PLUGIN_SETTINGS, MaliitPluginSettings)) #define MALIIT_PLUGIN_SETTINGS_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, MALIIT_TYPE_PLUGIN_SETTINGS, MaliitPluginSettingsClass)) #define MALIIT_IS_PLUGIN_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, MALIIT_TYPE_PLUGIN_SETTINGS)) #define MALIIT_IS_PLUGIN_SETTINGS_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, MALIIT_TYPE_PLUGIN_SETTINGS)) #define MALIIT_PLUGIN_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MALIIT_TYPE_PLUGIN_SETTINGS, MaliitPluginSettingsClass)) typedef struct _MaliitPluginSettings MaliitPluginSettings; typedef struct _MaliitPluginSettingsClass MaliitPluginSettingsClass; typedef struct _MaliitPluginSettingsPrivate MaliitPluginSettingsPrivate; struct _MaliitPluginSettings { GObject parent; /*< private >*/ MaliitPluginSettingsPrivate *priv; }; /** * MaliitPluginSettingsClass: * @parent_class: The parent class. */ struct _MaliitPluginSettingsClass { GObjectClass parent_class; }; GType maliit_plugin_settings_get_type (void) G_GNUC_CONST; const gchar * maliit_plugin_settings_get_description_language (MaliitPluginSettings *settings); const gchar * maliit_plugin_settings_get_plugin_name (MaliitPluginSettings *settings); const gchar * maliit_plugin_settings_get_plugin_description (MaliitPluginSettings *settings); GPtrArray * maliit_plugin_settings_get_configuration_entries (MaliitPluginSettings *settings); G_END_DECLS #endif /* MALIIT_GLIB_PLUGIN_SETTINGS_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitpluginsettingsprivate.h000066400000000000000000000024331262307254400277560ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_PLUGIN_SETTINGS_PRIVATE_H #define MALIIT_GLIB_PLUGIN_SETTINGS_PRIVATE_H #include "maliitattributeextension.h" #include "maliitpluginsettings.h" G_BEGIN_DECLS MaliitPluginSettings * maliit_plugin_settings_new_from_dbus_data (GVariant *plugin_info, MaliitAttributeExtension *extension); G_END_DECLS #endif /* MALIIT_GLIB_PLUGIN_SETTINGS_PRIVATE_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingdata.c000066400000000000000000000162241262307254400256110ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitsettingdata.h" /** * SECTION:maliitsettingdata * @short_description: miscellaneous setting functions and types * @title: Maliit settings misc * @see_also: #MaliitSettingsEntry, #MaliitPluginSettings * @stability: Stable * @include: maliit/maliitsettingdata.h * * Here #MaliitSettingsEntryType, attribute keys and * maliit_validate_setting_value() are specified. */ /** * MaliitSettingsEntryType: * @MALIIT_STRING_TYPE: Entry is a string. * @MALIIT_INT_TYPE: Entry is an integer. * @MALIIT_BOOL_TYPE: Entry is a boolean. * @MALIIT_STRING_LIST_TYPE: Entry is a list of strings. * @MALIIT_INT_LIST_TYPE: Entry is a list of integers. * * This enum describes type of settings entry. */ static const GEnumValue maliit_settings_entry_type_values[] = { { MALIIT_STRING_TYPE, "MALIIT_STRING_TYPE", "string-type" }, { MALIIT_INT_TYPE, "MALIIT_INT_TYPE", "int-type" }, { MALIIT_BOOL_TYPE, "MALIIT_BOOL_TYPE", "bool-type" }, { MALIIT_STRING_LIST_TYPE, "MALIIT_STRING_LIST_TYPE", "string-list-type" }, { MALIIT_INT_LIST_TYPE, "MALIIT_INT_LIST_TYPE", "int-list-type" }, { 0, NULL, NULL } }; GType maliit_settings_entry_type_get_type (void) { static GType type = G_TYPE_INVALID; if (type == G_TYPE_INVALID) { type = g_enum_register_static ("MaliitSettingsEntryType", maliit_settings_entry_type_values); } return type; } static gboolean check_single_value_domain(GVariant *value, GVariant *domain) { gsize array_len = g_variant_n_children(domain); gboolean equal = FALSE; gsize iter; for (iter = 0; iter < array_len && !equal; ++iter) { GVariant *child = g_variant_get_child_value(domain, iter); equal = g_variant_equal(value, child); g_variant_unref(child); } return equal; } static gboolean check_variant_value_domain(GVariant *value, GVariant *domain) { if (!domain) { return TRUE; } if (!g_variant_is_of_type(domain, G_VARIANT_TYPE_ARRAY)) { return FALSE; } return check_single_value_domain(value, domain); } static gboolean check_variant_array_domain(GVariant *values, GVariant *domain) { gsize iter; gsize array_len; gboolean correct; if (!domain) { return TRUE; } if (!g_variant_is_of_type(domain, G_VARIANT_TYPE_ARRAY)) { return FALSE; } array_len = g_variant_n_children(values); correct = TRUE; for (iter = 0; iter < array_len && correct; ++iter) { GVariant *child = g_variant_get_child_value(values, iter); correct = check_single_value_domain(child, domain); g_variant_unref (child); } return correct; } static gboolean check_single_value_range(GVariant *value, GVariant *range_min, GVariant *range_max) { if (range_min) { if (!g_variant_is_of_type(range_min, G_VARIANT_TYPE_INT32) || g_variant_get_int32(range_min) > g_variant_get_int32(value)) { return FALSE; } } if (range_max) { if (!g_variant_is_of_type(range_max, G_VARIANT_TYPE_INT32) || g_variant_get_int32(range_max) < g_variant_get_int32(value)) { return FALSE; } } return TRUE; } static gboolean check_variant_value_range(GVariant *value, GVariant *range_min, GVariant *range_max) { if (!range_min && !range_max) { return TRUE; } return check_single_value_range(value, range_min, range_max); } static gboolean check_variant_array_range(GVariant *values, GVariant *range_min, GVariant *range_max) { gsize iter; gsize values_len; gboolean correct; if (!range_min && !range_max) { return TRUE; } correct = TRUE; values_len = g_variant_n_children(values); for (iter = 0; iter < values_len && correct; ++iter) { GVariant *child = g_variant_get_child_value(values, iter); correct = check_single_value_range(child, range_min, range_max); g_variant_unref (child); } return correct; } static gboolean check_variant_array_is_int_array(GVariant *values) { gsize array_len = g_variant_n_children(values); gsize iter; gboolean correct = TRUE; for (iter = 0; iter < array_len && correct; ++iter) { GVariant *child = g_variant_get_child_value(values, iter); correct = g_variant_is_of_type(child, G_VARIANT_TYPE_INT32); g_variant_unref(child); } return correct; } /** * maliit_validate_setting_value: * @type: a #MaliitSettingsEntryType to validate against. * @attributes: (transfer none) (element-type utf8 GLib.Variant): Attributes to validate. * @value: (transfer none): A #GVariant to validate. * * Validate the value for a plugin setting entry. * * Returns: %TRUE if @value and @attributes are valid for given @type. */ gboolean maliit_validate_setting_value(MaliitSettingsEntryType type, GHashTable *attributes, GVariant *value) { GVariant *domain = g_hash_table_lookup(attributes, MALIIT_SETTING_VALUE_DOMAIN); GVariant *range_min = g_hash_table_lookup(attributes, MALIIT_SETTING_VALUE_RANGE_MIN); GVariant *range_max = g_hash_table_lookup(attributes, MALIIT_SETTING_VALUE_RANGE_MAX); switch (type) { case MALIIT_STRING_TYPE: return (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) && check_variant_value_domain(value, domain)); case MALIIT_INT_TYPE: return (g_variant_is_of_type(value, G_VARIANT_TYPE_INT32) && check_variant_value_domain(value, domain) && check_variant_value_range(value, range_min, range_max)); case MALIIT_BOOL_TYPE: return g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN); case MALIIT_STRING_LIST_TYPE: return (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY) && check_variant_array_domain(value, domain)); case MALIIT_INT_LIST_TYPE: return (g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY) && check_variant_array_is_int_array(value) && check_variant_array_domain(value, domain) && check_variant_array_range(value, range_min, range_max)); default: return FALSE; } } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingdata.h000066400000000000000000000051121262307254400256100ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_SETTING_DATA_H #define MALIIT_GLIB_SETTING_DATA_H #include #include G_BEGIN_DECLS typedef enum { MALIIT_STRING_TYPE = 1, MALIIT_INT_TYPE = 2, MALIIT_BOOL_TYPE = 3, MALIIT_STRING_LIST_TYPE = 4, MALIIT_INT_LIST_TYPE = 5 } MaliitSettingsEntryType; /** * MALIIT_SETTING_VALUE_DOMAIN: * * Name of setting entry attribute which holds the list of values that * can be assigned to the entry. */ #define MALIIT_SETTING_VALUE_DOMAIN "valueDomain" /** * MALIIT_SETTING_VALUE_DOMAIN_DESCRIPTIONS: * * Name of setting entry attribute which holds the descriptions for * the values in MALIIT_SETTING_VALUE_DOMAIN(). */ #define MALIIT_SETTING_VALUE_DOMAIN_DESCRIPTIONS "valueDomainDescriptions" /** * MALIIT_SETTING_VALUE_RANGE_MIN: * * Name of setting entry attribute which holds the minimum valid value * (inclusive) for an integer property. */ #define MALIIT_SETTING_VALUE_RANGE_MIN "valueRangeMin" /** * MALIIT_SETTING_VALUE_RANGE_MAX: * * Name of setting entry attribute which holds the maximum valid value * (inclusive) for an integer property. */ #define MALIIT_SETTING_VALUE_RANGE_MAX "valueRangeMax" /** * MALIIT_SETTING_DEFAULT_VALUE: * * Name of setting entry attribute which holds the default value for a setting entry. */ #define MALIIT_SETTING_DEFAULT_VALUE "defaultValue" #define MALIIT_TYPE_SETTINGS_ENTRY_TYPE maliit_settings_entry_type_get_type () GType maliit_settings_entry_type_get_type (void) G_GNUC_CONST; gboolean maliit_validate_setting_value(MaliitSettingsEntryType type, GHashTable *attributes, GVariant *value); G_END_DECLS #endif /* MALIIT_GLIB_SETTING_DATA_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingsentry.c000066400000000000000000000535331262307254400262300ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitpluginsettingsprivate.h" #include "maliitsettingsentryprivate.h" /** * SECTION:maliitsettingsentry * @short_description: settings entry * @title: MaliitSettingsEntry * @see_also: #MaliitSettingsEntry, #MaliitPluginSettings * @stability: Stable * @include: maliit/maliitsettingsentry.h * * The #MaliitSettingsEntry is a class holding single plugin * setting. It can be one of several available types * (#MaliitSettingsEntryType). It can also have some attributes like * value domain (MALIIT_SETTING_VALUE_DOMAIN()), default value * (MALIIT_SETTING_DEFAULT_VALUE) and value ranges * (MALIIT_SETTING_VALUE_RANGE_MIN() and * MALIIT_SETTING_VALUE_RANGE_MAX()). */ struct _MaliitSettingsEntryPrivate { MaliitAttributeExtension *extension; gchar *description; gchar *extension_key; MaliitSettingsEntryType type; gboolean valid; GHashTable *attributes; guint extension_signal_id; }; G_DEFINE_TYPE (MaliitSettingsEntry, maliit_settings_entry, G_TYPE_OBJECT) enum { PROP_0, PROP_EXTENSION, PROP_DESCRIPTION, PROP_EXTENSION_KEY, PROP_TYPE, PROP_VALID, PROP_VALUE, PROP_ATTRIBUTES }; enum { VALUE_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void maliit_settings_entry_finalize (GObject *object) { MaliitSettingsEntry *entry = MALIIT_SETTINGS_ENTRY (object); MaliitSettingsEntryPrivate *priv = entry->priv; g_free (priv->description); g_free (priv->extension_key); G_OBJECT_CLASS (maliit_settings_entry_parent_class)->finalize (object); } static void maliit_settings_entry_dispose (GObject *object) { MaliitSettingsEntry *entry = MALIIT_SETTINGS_ENTRY (object); MaliitSettingsEntryPrivate *priv = entry->priv; if (priv->extension_signal_id) { if (priv->extension) { g_signal_handler_disconnect (priv->extension, priv->extension_signal_id); } priv->extension_signal_id = 0; } g_clear_object (&priv->extension); if (priv->attributes) { GHashTable *attributes = priv->attributes; priv->attributes = NULL; g_hash_table_unref (attributes); } G_OBJECT_CLASS (maliit_settings_entry_parent_class)->dispose (object); } static void maliit_settings_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MaliitSettingsEntry *entry = MALIIT_SETTINGS_ENTRY (object); MaliitSettingsEntryPrivate *priv = entry->priv; switch (prop_id) { case PROP_EXTENSION: if (priv->extension) { g_object_unref (priv->extension); } priv->extension = g_value_dup_object (value); break; case PROP_DESCRIPTION: g_free (priv->description); priv->description = g_value_dup_string (value); break; case PROP_EXTENSION_KEY: g_free (priv->extension_key); priv->extension_key = g_value_dup_string (value); break; case PROP_TYPE: priv->type = g_value_get_enum (value); break; case PROP_VALID: priv->valid = g_value_get_boolean (value); break; case PROP_VALUE: maliit_settings_entry_set_value (entry, g_value_get_variant (value)); break; case PROP_ATTRIBUTES: if (priv->attributes) { g_hash_table_unref (priv->attributes); } priv->attributes = g_value_dup_boxed (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void maliit_settings_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MaliitSettingsEntry *entry = MALIIT_SETTINGS_ENTRY (object); MaliitSettingsEntryPrivate *priv = entry->priv; switch (prop_id) { /* PROP_EXTENSION is write only, construction only - omitted here */ case PROP_DESCRIPTION: g_value_set_string (value, priv->description); break; case PROP_EXTENSION_KEY: g_value_set_string (value, priv->extension_key); break; case PROP_TYPE: g_value_set_enum (value, priv->type); break; case PROP_VALID: g_value_set_boolean (value, priv->valid); break; case PROP_VALUE: g_value_set_variant (value, maliit_settings_entry_get_value (entry)); break; case PROP_ATTRIBUTES: g_value_set_boxed (value, priv->attributes); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void value_changed(MaliitSettingsEntry *entry, const gchar *key, GVariant *value G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { if (!g_strcmp0 (key, entry->priv->extension_key)) { g_signal_emit(entry, signals[VALUE_CHANGED], 0); } } static void maliit_settings_entry_constructed (GObject *object) { MaliitSettingsEntry *entry = MALIIT_SETTINGS_ENTRY (object); MaliitSettingsEntryPrivate *priv = entry->priv; if (priv->extension) { priv->extension_signal_id = g_signal_connect_swapped (priv->extension, "extended-attribute-changed", G_CALLBACK (value_changed), entry); } } static void maliit_settings_entry_class_init (MaliitSettingsEntryClass *entry_class) { GObjectClass *g_object_class = G_OBJECT_CLASS (entry_class); g_object_class->finalize = maliit_settings_entry_finalize; g_object_class->dispose = maliit_settings_entry_dispose; g_object_class->set_property = maliit_settings_entry_set_property; g_object_class->get_property = maliit_settings_entry_get_property; g_object_class->constructed = maliit_settings_entry_constructed; /** * MaliitSettingsEntry:extension: * * #MaliitAttributeExtension used by this entry. */ g_object_class_install_property (g_object_class, PROP_EXTENSION, g_param_spec_object ("extension", "Extension", /* TODO: mark as translatable? */ "Extension used by this entry", /* TODO: mark as translatable? */ MALIIT_TYPE_ATTRIBUTE_EXTENSION, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry:description: * * Description of the entry. */ g_object_class_install_property (g_object_class, PROP_DESCRIPTION, g_param_spec_string ("description", "Description", /* TODO: mark as translatable? */ "Description of the entry", /* TODO: mark as translatable? */ "", G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry:extension-key: * * Key of the entry. */ g_object_class_install_property (g_object_class, PROP_EXTENSION_KEY, g_param_spec_string ("extension-key", "Extension key", /* TODO: mark as translatable? */ "Key of the entry.", /* TODO: mark as translatable? */ "", G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry:type: * * Type of the entry */ g_object_class_install_property (g_object_class, PROP_TYPE, g_param_spec_enum ("type", "Type", /* TODO: mark as translatable? */ "Type if the entry", /* TODO: mark as translatable? */ MALIIT_TYPE_SETTINGS_ENTRY_TYPE, MALIIT_STRING_TYPE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry:valid: * * Whether entry's value is valid. */ g_object_class_install_property (g_object_class, PROP_VALID, g_param_spec_boolean ("valid", "Valid", /* TODO: mark as translatable? */ "Whether entry's value is valid", /* TODO: mark as translatable? */ FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry:value: * * Value of the entry. */ g_object_class_install_property (g_object_class, PROP_VALUE, g_param_spec_variant ("value", "Value", /* TODO: mark as translatable? */ "Value of the entry", /* TODO: mark as translatable? */ G_VARIANT_TYPE_ANY, g_variant_new_int32 (0), G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry:attributes: * * Attributes of the entry. */ g_object_class_install_property (g_object_class, PROP_ATTRIBUTES, g_param_spec_boxed ("attributes", "Attributes", /* TODO: mark as translatable? */ "Attributes of the entry", /* TODO: mark as translatable? */ G_TYPE_HASH_TABLE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); /** * MaliitSettingsEntry::value-changed: * @entry: The #MaliitSettingsEntry emitting the signal. * * Emitted when value of the entry was changed in the plugin. */ signals[VALUE_CHANGED] = g_signal_new ("value-changed", MALIIT_TYPE_SETTINGS_ENTRY, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (entry_class, sizeof (MaliitSettingsEntryPrivate)); } static void maliit_settings_entry_init (MaliitSettingsEntry *entry) { MaliitSettingsEntryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (entry, MALIIT_TYPE_SETTINGS_ENTRY, MaliitSettingsEntryPrivate); priv->extension = NULL; priv->description = NULL; priv->extension_key = NULL; priv->type = MALIIT_STRING_TYPE; priv->valid = FALSE; priv->attributes = NULL; priv->extension_signal_id = 0; entry->priv = priv; } static GHashTable * attributes_from_dbus_g_variant (GVariant *dbus_attributes) { GHashTable *attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); GVariantIter iter; gchar *key; GVariant *value; g_variant_iter_init (&iter, dbus_attributes); while (g_variant_iter_next (&iter, "{sv}", &key, &value)) { g_hash_table_replace (attributes, key, value); } return attributes; } /** * maliit_settings_entry_new_from_dbus_data: (skip) * @info: (transfer none): A #GVariant of DBus provenance containing entry information. * @extension: (transfer none): A #MaliitAttributeExtensions for #MaliitAttributeSettingsEntry instance. * * Creates new settings entry. This is used internally only by * #MaliitPluginSettings. * * Returns: (transfer full): The newly created #MaliitSettingsEntry. */ MaliitSettingsEntry * maliit_settings_entry_new_from_dbus_data (GVariant *info, MaliitAttributeExtension *extension) { const gchar *description; const gchar *extension_key; MaliitSettingsEntryType type; gboolean valid; GVariant *value; GVariant *attrs; GHashTable *attributes; MaliitSettingsEntry *entry; g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), NULL); g_variant_get (info, "(&s&sib@v@a{sv})", &description, &extension_key, &type, &valid, &value, &attrs); attributes = attributes_from_dbus_g_variant (attrs); entry = MALIIT_SETTINGS_ENTRY (g_object_new (MALIIT_TYPE_SETTINGS_ENTRY, "extension", extension, "description", description, "extension-key", extension_key, "type", type, "valid", valid, "value", value, "attributes", attributes, NULL)); g_hash_table_unref (attributes); g_variant_unref (attrs); g_variant_unref (value); return entry; } /** * maliit_settings_entry_get_description: * @entry: (transfer none): The #MaliitSettingsEntry. * * Gets description of the entry. * * Returns: (transfer none): A description. Returned value should not be modified nor freed. */ const gchar * maliit_settings_entry_get_description (MaliitSettingsEntry *entry) { g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), NULL); return entry->priv->description; } /** * maliit_settings_entry_get_key: * @entry: (transfer none): The #MaliitSettingsEntry. * * Gets key of the entry. * * Returns: (transfer none): A key. Returned value should not be modified nor freed. */ const gchar * maliit_settings_entry_get_key (MaliitSettingsEntry *entry) { g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), NULL); return entry->priv->extension_key; } /** * maliit_settings_entry_get_entry_type: * @entry: (transfer none): The #MaliitSettingsEntry. * * Gets type of the entry. * * Returns: A type. */ MaliitSettingsEntryType maliit_settings_entry_get_entry_type (MaliitSettingsEntry *entry) { g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), MALIIT_STRING_TYPE); return entry->priv->type; } /** * maliit_settings_entry_is_current_value_valid: * @entry: (transfer none): The #MaliitSettingsEntry. * * Gets whether current value of the entry is valid. * * Returns: %TRUE if valid, otherwise %FALSE */ gboolean maliit_settings_entry_is_current_value_valid (MaliitSettingsEntry *entry) { g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), FALSE); return entry->priv->valid; } /** * maliit_settings_entry_get_value: * @entry: (transfer none): The #MaliitSettingsEntry. * * Gets value of the entry. Check its validity with * maliit_settings_entry_is_current_value_valid() before using it. * * Returns: (transfer none): A value. */ GVariant * maliit_settings_entry_get_value (MaliitSettingsEntry *entry) { GHashTable *attributes; MaliitSettingsEntryPrivate *priv; g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), NULL); priv = entry->priv; attributes = maliit_attribute_extension_get_attributes (priv->extension); return g_hash_table_lookup (attributes, priv->extension_key); } /** * maliit_settings_entry_set_value: * @entry: (transfer none): The #MaliitSettingsEntry. * @value: (transfer none): The #GVariant. * * Sets a new value of the entry. Before setting new value, validate * it with maliit_settings_entry_is_value_valid(). */ void maliit_settings_entry_set_value (MaliitSettingsEntry *entry, GVariant *value) { MaliitSettingsEntryPrivate *priv; g_return_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry)); priv = entry->priv; maliit_attribute_extension_set_attribute (priv->extension, priv->extension_key, value); } /** * maliit_settings_entry_is_value_valid: * @entry: (transfer none): The #MaliitSettingsEntry. * @value: (transfer none): The #GVariant * * Checks whether the value is valid one for the entry. * * Returns: %TRUE if valid, otherwise %FALSE. */ gboolean maliit_settings_entry_is_value_valid (MaliitSettingsEntry *entry, GVariant *value) { MaliitSettingsEntryPrivate *priv; g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), FALSE); priv = entry->priv; return maliit_validate_setting_value (priv->type, priv->attributes, value); } /** * maliit_settings_entry_get_attributes: * @entry: (transfer none): The #MaliitSettingsEntry. * * Gets attributes of the entry. The keys of the attributes are * MALIIT_SETTING_VALUE_DOMAIN(), * MALIIT_SETTING_VALUE_DOMAIN_DESCRIPTIONS(), * MALIIT_SETTING_VALUE_RANGE_MIN(), MALIIT_SETTING_VALUE_RANGE_MAX() * and MALIIT_SETTING_DEFAULT_VALUE(). Note that these keys don't have * to exist in attributes. * * Returns: (transfer none) (element-type utf8 GLib.Variant): Attributes. Returned value should not be modified nor freed. */ GHashTable * maliit_settings_entry_get_attributes (MaliitSettingsEntry *entry) { g_return_val_if_fail (MALIIT_IS_SETTINGS_ENTRY (entry), NULL); return entry->priv->attributes; } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingsentry.h000066400000000000000000000057271262307254400262370ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_SETTINGS_ENTRY_H #define MALIIT_GLIB_SETTINGS_ENTRY_H #include #include #include "maliitsettingdata.h" G_BEGIN_DECLS #define MALIIT_TYPE_SETTINGS_ENTRY (maliit_settings_entry_get_type()) #define MALIIT_SETTINGS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, MALIIT_TYPE_SETTINGS_ENTRY, MaliitSettingsEntry)) #define MALIIT_SETTINGS_ENTRY_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, MALIIT_TYPE_SETTINGS_ENTRY, MaliitSettingsEntryClass)) #define MALIIT_IS_SETTINGS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, MALIIT_TYPE_SETTINGS_ENTRY)) #define MALIIT_IS_SETTINGS_ENTRY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, MALIIT_TYPE_SETTINGS_ENTRY)) #define MALIIT_SETTINGS_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MALIIT_TYPE_SETTINGS_ENTRY, MaliitSettingsEntryClass)) typedef struct _MaliitSettingsEntry MaliitSettingsEntry; typedef struct _MaliitSettingsEntryClass MaliitSettingsEntryClass; typedef struct _MaliitSettingsEntryPrivate MaliitSettingsEntryPrivate; struct _MaliitSettingsEntry { GObject parent; /*< private >*/ MaliitSettingsEntryPrivate *priv; }; /** * MaliitSettingsEntryClass: * @parent_class: The parent class. */ struct _MaliitSettingsEntryClass { GObjectClass parent_class; }; GType maliit_settings_entry_get_type (void) G_GNUC_CONST; const gchar * maliit_settings_entry_get_description (MaliitSettingsEntry *entry); const gchar * maliit_settings_entry_get_key (MaliitSettingsEntry *entry); MaliitSettingsEntryType maliit_settings_entry_get_entry_type (MaliitSettingsEntry *entry); gboolean maliit_settings_entry_is_current_value_valid (MaliitSettingsEntry *entry); GVariant * maliit_settings_entry_get_value (MaliitSettingsEntry *entry); void maliit_settings_entry_set_value (MaliitSettingsEntry *entry, GVariant *value); gboolean maliit_settings_entry_is_value_valid (MaliitSettingsEntry *entry, GVariant *value); GHashTable * maliit_settings_entry_get_attributes (MaliitSettingsEntry *entry); G_END_DECLS #endif /* MALIIT_GLIB_SETTINGS_ENTRY_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingsentryprivate.h000066400000000000000000000024151262307254400276210ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_SETTINGS_ENTRY_PRIVATE_H #define MALIIT_GLIB_SETTINGS_ENTRY_PRIVATE_H #include "maliitattributeextension.h" #include "maliitsettingsentry.h" G_BEGIN_DECLS MaliitSettingsEntry * maliit_settings_entry_new_from_dbus_data (GVariant *info, MaliitAttributeExtension *extension); G_END_DECLS #endif /* MALIIT_GLIB_SETTINGS_ENTRY_PRIVATE_H */ maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingsmanager.c000066400000000000000000000276221262307254400265010ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "maliitsettingsmanager.h" #include "maliitpluginsettingsprivate.h" #include "maliitattributeextensionprivate.h" #include "maliitbus.h" /** * SECTION:maliitsettingsmanager * @short_description: settings manager * @title: MaliitSettingsManager * @see_also: #MaliitSettingsEntry, #MaliitPluginSettings * @stability: Stable * @include: maliit/maliitsettingsmanager.h * * The #MaliitSettingsManager handles requesting and receiving plugin * settings from maliit-server and notifying when those settings has * changed. */ static gchar* preferred_description_locale = 0; struct _MaliitSettingsManagerPrivate { MaliitAttributeExtension *settings_list_changed; guint attribute_changed_signal_id; }; G_DEFINE_TYPE (MaliitSettingsManager, maliit_settings_manager, G_TYPE_OBJECT) enum { PLUGIN_SETTINGS_RECEIVED, CONNECTED, DISCONNECTED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void maliit_settings_manager_finalize (GObject *object) { G_OBJECT_CLASS (maliit_settings_manager_parent_class)->finalize (object); } static void maliit_settings_manager_dispose (GObject *object) { GError *error = NULL; MaliitSettingsManager *manager = MALIIT_SETTINGS_MANAGER (object); MaliitContext *context = maliit_get_context_sync (NULL, &error); if (context) { g_signal_handlers_disconnect_by_data (context, manager); } else { g_warning ("Unable to connect to context: %s", error->message); g_clear_error (&error); } if (manager->priv->settings_list_changed) { g_signal_handlers_disconnect_by_data (manager->priv->settings_list_changed, manager); } g_clear_object (&manager->priv->settings_list_changed); G_OBJECT_CLASS (maliit_settings_manager_parent_class)->dispose (object); } static void maliit_settings_manager_class_init (MaliitSettingsManagerClass *manager_class) { GObjectClass *g_object_class = G_OBJECT_CLASS (manager_class); g_object_class->finalize = maliit_settings_manager_finalize; g_object_class->dispose = maliit_settings_manager_dispose; /** * MaliitSettingsManager::plugin-settings-received: * @manager: The #MaliitSettingsManager emitting the signal. * @settings: (type GLib.List) (element-type Maliit.PluginSettings): Gotten settings. * * Emitted after call to * maliit_settings_manager_load_plugin_settings() and when the * plugin list changes on the server. */ signals[PLUGIN_SETTINGS_RECEIVED] = g_signal_new ("plugin-settings-received", MALIIT_TYPE_SETTINGS_MANAGER, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * MaliitSettingsManager::connected: * @manager: The #MaliitSettingsManager emitting the signal. * * Emitted when connection to maliit-server is established. */ signals[CONNECTED] = g_signal_new ("connected", MALIIT_TYPE_SETTINGS_MANAGER, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * MaliitSettingsManager::disconnected: * @manager: The #MaliitSettingsManager emitting the signal. * * Emitted when connection to maliit-server is broken. * * Deprecated: 0.99.0: This signal will no longer be emitted. */ signals[DISCONNECTED] = g_signal_new ("disconnected", MALIIT_TYPE_SETTINGS_MANAGER, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (manager_class, sizeof (MaliitSettingsManagerPrivate)); } static void on_connection_established (MaliitSettingsManager *manager, gpointer user_data G_GNUC_UNUSED) { g_signal_emit(manager, signals[CONNECTED], 0); } static gboolean on_plugins_loaded (MaliitSettingsManager *manager, GDBusMethodInvocation *invocation G_GNUC_UNUSED, GVariant *plugin_settings, gpointer user_data G_GNUC_UNUSED) { guint iter; GList *result; GHashTable *extensions; GVariant *plugin_info; if (!plugin_settings) { return FALSE; } result = NULL; extensions = g_hash_table_new (g_direct_hash, g_direct_equal); for (iter = 0; iter < g_variant_n_children (plugin_settings); ++iter) { const gchar *plugin_name; int extension_id; g_variant_get_child (plugin_settings, iter, "(&s&s&si@a(ssibva{sv}))", NULL, &plugin_name, NULL, &extension_id, NULL); if (!g_strcmp0(plugin_name, "@settings")) { MaliitSettingsManagerPrivate *priv = manager->priv; if (priv->attribute_changed_signal_id) { if (priv->settings_list_changed) { g_signal_handler_disconnect (priv->settings_list_changed, priv->attribute_changed_signal_id); g_clear_object (&priv->settings_list_changed); } priv->attribute_changed_signal_id = 0; } priv->settings_list_changed = maliit_attribute_extension_new_with_id (extension_id); priv->attribute_changed_signal_id = g_signal_connect_swapped (priv->settings_list_changed, "extended-attribute-changed", G_CALLBACK (maliit_settings_manager_load_plugin_settings), manager); } else { MaliitAttributeExtension *extension = g_hash_table_lookup (extensions, GINT_TO_POINTER (extension_id)); if (!extension) { extension = maliit_attribute_extension_new_with_id (extension_id); g_hash_table_insert (extensions, GINT_TO_POINTER (extension_id), extension); } plugin_info = g_variant_get_child_value (plugin_settings, iter); result = g_list_prepend (result, maliit_plugin_settings_new_from_dbus_data (plugin_info, extension)); g_variant_unref (plugin_info); } } result = g_list_reverse (result); g_signal_emit (manager, signals[PLUGIN_SETTINGS_RECEIVED], 0, result); g_list_free_full (result, g_object_unref); return FALSE; } static void connection_established (GObject *source_object G_GNUC_UNUSED, GAsyncResult *res, gpointer user_data) { GError *error = NULL; MaliitServer *server = maliit_get_server_finish (res, &error); if (server) { on_connection_established (user_data, server); } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } } static void maliit_settings_manager_init (MaliitSettingsManager *manager) { MaliitSettingsManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, MALIIT_TYPE_SETTINGS_MANAGER, MaliitSettingsManagerPrivate); MaliitContext *context; GError *error = NULL; priv->settings_list_changed = NULL; priv->attribute_changed_signal_id = 0; manager->priv = priv; maliit_get_server (NULL, connection_established, manager); context = maliit_get_context_sync (NULL, &error); if (context) { g_signal_connect_swapped (context, "handle-plugin-settings-loaded", G_CALLBACK (on_plugins_loaded), manager); } else { g_warning ("Unable to connect to context: %s", error->message); g_clear_error (&error); } } /** * maliit_settings_manager_new: * * Creates new settings manager. * * Returns: (transfer full): The newly created * #MaliitSettingsManager. */ MaliitSettingsManager * maliit_settings_manager_new (void) { return MALIIT_SETTINGS_MANAGER (g_object_new (MALIIT_TYPE_SETTINGS_MANAGER, NULL)); } /** * maliit_settings_manager_load_plugin_settings: * @manager: (transfer none): The #MaliitSettingsManager. * * Request the list of settings from maliit-server. * The settings will be returned async via the MaliitServerManager::plugin-settings-received signal */ void maliit_settings_manager_load_plugin_settings (MaliitSettingsManager *manager) { MaliitServer *server; GError *error = NULL; g_return_if_fail (MALIIT_IS_SETTINGS_MANAGER (manager)); server = maliit_get_server_sync (NULL, &error); if (server) { if (!maliit_server_call_load_plugin_settings_sync (server, maliit_settings_manager_get_preferred_description_locale (), NULL, &error)) { g_warning ("Unable to load plugin settings: %s", error->message); g_clear_error (&error); } } else { g_warning ("Unable to connect to server: %s", error->message); g_clear_error (&error); } } /** * maliit_settings_manager_set_preferred_description_locale: * @locale_name: (transfer none): The new preferred locale. * * Sets the preferred locale for human-readable descriptions. The setting is * valid for all instances of #MaliitSettingsManager in the process. * Note that the server may not always be able to return info in the requested locale. */ void maliit_settings_manager_set_preferred_description_locale (const gchar *locale_name) { g_return_if_fail (locale_name != NULL); if (preferred_description_locale) { g_free (preferred_description_locale); } preferred_description_locale = g_strdup (locale_name); } /** * maliit_settings_manager_get_preferred_description_locale: * * Gets the preferred locale for human-readable description. * * Returns: (transfer none): The string being a current preferred * locale. Returned string should not be freed nor modified. */ const gchar * maliit_settings_manager_get_preferred_description_locale (void) { if (!preferred_description_locale) { preferred_description_locale = g_strdup("en"); } return preferred_description_locale; } maliit-framework-0.99.1+git20151118+62bd54b/maliit-glib/maliitsettingsmanager.h000066400000000000000000000051121262307254400264740ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_GLIB_SETTINGS_MANAGER_H #define MALIIT_GLIB_SETTINGS_MANAGER_H #include #include G_BEGIN_DECLS #define MALIIT_TYPE_SETTINGS_MANAGER (maliit_settings_manager_get_type()) #define MALIIT_SETTINGS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, MALIIT_TYPE_SETTINGS_MANAGER, MaliitSettingsManager)) #define MALIIT_SETTINGS_MANAGER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, MALIIT_TYPE_SETTINGS_MANAGER, MaliitSettingsManagerClass)) #define MALIIT_IS_SETTINGS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, MALIIT_TYPE_SETTINGS_MANAGER)) #define MALIIT_IS_SETTINGS_MANAGER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE(obj, MALIIT_TYPE_SETTINGS_MANAGER)) #define MALIIT_SETTINGS_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MALIIT_TYPE_SETTINGS_MANAGER, MaliitSettingsManagerClass)) typedef struct _MaliitSettingsManager MaliitSettingsManager; typedef struct _MaliitSettingsManagerClass MaliitSettingsManagerClass; typedef struct _MaliitSettingsManagerPrivate MaliitSettingsManagerPrivate; struct _MaliitSettingsManager { GObject parent; /*< private >*/ MaliitSettingsManagerPrivate *priv; }; /** * MaliitSettingsManagerClass: * @parent_class: The parent class. */ struct _MaliitSettingsManagerClass { GObjectClass parent_class; }; GType maliit_settings_manager_get_type (void) G_GNUC_CONST; MaliitSettingsManager * maliit_settings_manager_new (void); void maliit_settings_manager_load_plugin_settings (MaliitSettingsManager *manager); void maliit_settings_manager_set_preferred_description_locale (const gchar *locale_name); const gchar * maliit_settings_manager_get_preferred_description_locale (void); G_END_DECLS #endif /* MALIIT_GLIB_SETTINGS_MANAGER_H */ maliit-framework-0.99.1+git20151118+62bd54b/passthroughserver/000077500000000000000000000000001262307254400233355ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/passthroughserver/.gitignore000066400000000000000000000000401262307254400253170ustar00rootroot00000000000000meego-im-uiserver maliit-server maliit-framework-0.99.1+git20151118+62bd54b/passthroughserver/devices.txt000066400000000000000000000001251262307254400255160ustar00rootroot00000000000000touch /dev/input/event2 0 2774 0 1568 0 1 touch /dev/input/event3 0 2774 0 1568 0 1 maliit-framework-0.99.1+git20151118+62bd54b/passthroughserver/main.cpp000066400000000000000000000106441262307254400247720ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include "connectionfactory.h" #include "mimserver.h" #include "mimserveroptions.h" #ifndef NOXCB #include "xcbplatform.h" #endif #ifdef HAVE_WAYLAND #include "waylandplatform.h" #endif // HAVE_WAYLAND #include "unknownplatform.h" #include #include namespace { void disableMInputContextPlugin() { // none is a special value for QT_IM_MODULE, which disables loading of any // input method module in Qt 5. setenv("QT_IM_MODULE", "none", true); } bool isDebugEnabled() { static int debugEnabled = -1; if (debugEnabled == -1) { QByteArray debugEnvVar = qgetenv("MALIIT_DEBUG"); if (!debugEnvVar.isEmpty() && debugEnvVar != "0") { debugEnabled = 1; } else { debugEnabled = 0; } } return debugEnabled == 1; } void outputMessagesToStdErr(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_UNUSED(context); QByteArray utf_text(msg.toUtf8()); const char *raw(utf_text.constData()); switch (type) { case QtDebugMsg: if (isDebugEnabled()) { fprintf(stderr, "DEBUG: %s\n", raw); } break; #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) case QtInfoMsg: fprintf(stderr, "INFO: %s\n", raw); break; #endif case QtWarningMsg: fprintf(stderr, "WARNING: %s\n", raw); break; case QtCriticalMsg: fprintf(stderr, "CRITICAL: %s\n", raw); break; case QtFatalMsg: fprintf(stderr, "FATAL: %s\n", raw); abort(); } } QSharedPointer createConnection(const MImServerConnectionOptions &options) { #ifdef HAVE_WAYLAND if (QGuiApplication::platformName().startsWith("wayland")) { return QSharedPointer(Maliit::createWestonIMProtocolConnection()); } else #endif if (options.overriddenAddress.isEmpty()) { return QSharedPointer(Maliit::DBus::createInputContextConnectionWithDynamicAddress()); } else { return QSharedPointer(Maliit::DBus::createInputContextConnectionWithFixedAddress(options.overriddenAddress, options.allowAnonymous)); } } QSharedPointer createPlatform() { #ifdef HAVE_WAYLAND if (QGuiApplication::platformName().startsWith("wayland")) { return QSharedPointer(new Maliit::WaylandPlatform); } else #endif #ifndef NOXCB if (QGuiApplication::platformName() == "xcb") { return QSharedPointer(new Maliit::XCBPlatform); } else { #else { #endif return QSharedPointer(new Maliit::UnknownPlatform); } } } // unnamed namespace int main(int argc, char **argv) { qInstallMessageHandler(outputMessagesToStdErr); // QT_IM_MODULE, MApplication and QtMaemo5Style all try to load // MInputContext, which is fine for the application. For the passthrough // server itself, we absolutely need to prevent that. disableMInputContextPlugin(); MImServerCommonOptions serverCommonOptions; MImServerConnectionOptions connectionOptions; const bool allRecognized = parseCommandLine(argc, argv); if (serverCommonOptions.showHelp) { printHelpMessage(); return 1; } else if (not allRecognized) { printHelpMessage(); } QGuiApplication app(argc, argv); // Input Context Connection QSharedPointer icConnection(createConnection(connectionOptions)); QSharedPointer platform(createPlatform()); // The actual server MImServer::configureSettings(MImServer::PersistentSettings); MImServer imServer(icConnection, platform); Q_UNUSED(imServer); return app.exec(); } maliit-framework-0.99.1+git20151118+62bd54b/passthroughserver/passthroughserver.pro000066400000000000000000000014221262307254400276540ustar00rootroot00000000000000include(../config.pri) TOP_DIR = .. TEMPLATE = app TARGET = $$MALIIT_SERVER target.path = $$BINDIR DEPENDPATH += . include($$TOP_DIR/src/libmaliit-plugins.pri) include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/connection/libmaliit-connection.pri) SOURCES += main.cpp QT += core gui # coverage flags are off per default, but can be turned on via qmake COV_OPTION=on for(OPTION,$$list($$lower($$COV_OPTION))){ isEqual(OPTION, on){ QMAKE_CXXFLAGS += -ftest-coverage -fprofile-arcs -fno-elide-constructors LIBS += -lgcov } } QMAKE_CLEAN += *.gcno *.gcda INSTALLS += target QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.depends += $$TARGET QMAKE_EXTRA_TARGETS += check check.target = check check.depends += $$TARGET maliit-framework-0.99.1+git20151118+62bd54b/src/000077500000000000000000000000001262307254400203265ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/src/.gitignore000066400000000000000000000001711262307254400223150ustar00rootroot00000000000000meegoimframework.prf MeegoImFramework.pc meego-im-framework.schemas maliit-framework.schemas maliit*-*.pc config.h *.prf maliit-framework-0.99.1+git20151118+62bd54b/src/README000066400000000000000000000000001262307254400211740ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/src/abstractplatform.cpp000066400000000000000000000012311262307254400243770ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "abstractplatform.h" namespace Maliit { AbstractPlatform::~AbstractPlatform() {} void AbstractPlatform::setApplicationWindow(QWindow *window, WId appWindowId) { Q_UNUSED(window) Q_UNUSED(appWindowId) } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/abstractplatform.h000066400000000000000000000017561262307254400240600ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_ABSTRACT_PLATFORM_H #define MALIIT_ABSTRACT_PLATFORM_H #include #include class QRegion; namespace Maliit { class AbstractPlatform { public: virtual ~AbstractPlatform(); virtual void setupInputPanel(QWindow* window, Maliit::Position position) = 0; virtual void setInputRegion(QWindow* window, const QRegion& region) = 0; virtual void setApplicationWindow(QWindow *window, WId appWindowId); }; } // namespace Maliit #endif // MALIIT_ABSTRACT_PLATFORM_H maliit-framework-0.99.1+git20151118+62bd54b/src/config.h.in000066400000000000000000000015611262307254400223540ustar00rootroot00000000000000/* * This file is part of meego-im-framework * * * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (directui@nokia.com) * * If you have questions regarding the use of this file, please contact * Nokia at directui@nokia.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_CONFIG_H #define MALIIT_CONFIG_H #define MALIIT_DEFAULT_HW_PLUGIN "@MALIIT_DEFAULT_HW_PLUGIN@" #define MALIIT_ENABLE_MULTITOUCH @MALIIT_ENABLE_MULTITOUCH@ #define MALIIT_DEFAULT_PLUGIN "@MALIIT_DEFAULT_PLUGIN@" #define MALIIT_DEFAULT_SUBVIEW "@MALIIT_DEFAULT_SUBVIEW@" #endifmaliit-framework-0.99.1+git20151118+62bd54b/src/libmaliit-plugins.pri000066400000000000000000000005611262307254400244710ustar00rootroot00000000000000# Use when a .pro file requires libmaliit-plugins # The .pro file must define TOP_DIR to be a relative path # to the top-level source/build directory, and include config.pri INCLUDEPATH += $$TOP_DIR/src $$OUT_PWD/$$TOP_DIR/src LIBS += $$TOP_DIR/lib/$$maliitDynamicLib($${MALIIT_PLUGINS_LIB}) POST_TARGETDEPS += $$TOP_DIR/lib/$$maliitDynamicLib($${MALIIT_PLUGINS_LIB}) maliit-framework-0.99.1+git20151118+62bd54b/src/maliit-defines.prf.in000066400000000000000000000005151262307254400243370ustar00rootroot00000000000000# This fime contains macro definitions that might be needed for plugins. # It is made separated, so one can load it eagerly with load() function # without risk to affect building part. MALIIT_PREFIX=@PREFIX@ MALIIT_PLUGINS_DIR = @MALIIT_PLUGINS_DIR@ MALIIT_PLUGINS_DATA_DIR = @MALIIT_PLUGINS_DATA_DIR@ MALIIT_INSTALL_LIBS = @LIBDIR@ maliit-framework-0.99.1+git20151118+62bd54b/src/maliit-plugins.pc.in000066400000000000000000000010271262307254400242150ustar00rootroot00000000000000prefix=@PREFIX@ exec_prefix=@PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ pluginsdir=@MALIIT_PLUGINS_DIR@ pluginsdatadir=@MALIIT_PLUGINS_DATA_DIR@ factorypluginsdir=@MALIIT_FACTORY_PLUGINS_DIR@ Name: Maliit Plugins Description: Maliit provides a flexible and cross platform input method framework. It is usable on all MeeGo user experiences, and in other GNU/Linux distributions as well. Version: @MALIIT_VERSION@ Requires: maliit-framework Cflags: -I${includedir}/@MALIIT_PLUGINS_HEADER@ Libs: -L${libdir} -l@MALIIT_PLUGINS_LIB@ maliit-framework-0.99.1+git20151118+62bd54b/src/maliit-plugins.prf.in000066400000000000000000000001711262307254400244010ustar00rootroot00000000000000LIBS *= -L@LIBDIR@ -l@MALIIT_PLUGINS_LIB@ INCLUDEPATH *= @INCLUDEDIR@/@MALIIT_PLUGINS_HEADER@ CONFIG *= maliit-framework maliit-framework-0.99.1+git20151118+62bd54b/src/maliit-server.pc.in000066400000000000000000000006521262307254400240450ustar00rootroot00000000000000prefix=@PREFIX@ exec_prefix=@PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ pluginsdir=@MALIIT_PLUGINS_DIR@ pluginsdatadir=@MALIIT_PLUGINS_DATA_DIR@ factorypluginsdir=@MALIIT_FACTORY_PLUGINS_DIR@ Name: Maliit Server Description: Library for embedding the Maliit IM Server Version: @MALIIT_VERSION@ Requires: maliit-framework maliit-plugins maliit-connection Cflags: -I${includedir}/@MALIIT_SERVER_HEADER@ Libs: -L${libdir} maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/000077500000000000000000000000001262307254400216055ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/000077500000000000000000000000001262307254400232665ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/abstractinputmethod.cpp000066400000000000000000000111671262307254400300640ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include class MAbstractInputMethodPrivate { public: MAbstractInputMethodPrivate(MAbstractInputMethodHost *imHost, MAbstractInputMethod *parent); ~MAbstractInputMethodPrivate(); MAbstractInputMethodHost *imHost; }; MAbstractInputMethodPrivate::MAbstractInputMethodPrivate(MAbstractInputMethodHost *imHost, MAbstractInputMethod *parent) : imHost(imHost) { Q_UNUSED(parent) } MAbstractInputMethodPrivate::~MAbstractInputMethodPrivate() { } /////////////// MAbstractInputMethod::MAbstractInputMethod(MAbstractInputMethodHost *host) : QObject(0), // MAbstractInputMethod is not deleted by mainWindow d_ptr(new MAbstractInputMethodPrivate(host, this)) { } MAbstractInputMethod::~MAbstractInputMethod() { delete d_ptr; } MAbstractInputMethodHost * MAbstractInputMethod::inputMethodHost() const { Q_D(const MAbstractInputMethod); return d->imHost; } void MAbstractInputMethod::show() { // empty default implementation } void MAbstractInputMethod::hide() { // empty default implementation } void MAbstractInputMethod::setPreedit(const QString &, int) { // empty default implementation } void MAbstractInputMethod::update() { // empty default implementation } void MAbstractInputMethod::reset() { // empty default implementation } void MAbstractInputMethod::handleMouseClickOnPreedit(const QPoint &pos, const QRect &preeditRect) { // empty default implementation Q_UNUSED(pos); Q_UNUSED(preeditRect); } void MAbstractInputMethod::handleFocusChange(bool /* focusIn */) { // empty default implementation } void MAbstractInputMethod::handleVisualizationPriorityChange(bool priority) { // empty default implementation Q_UNUSED(priority); } void MAbstractInputMethod::handleAppOrientationAboutToChange(int angle) { // empty default implementation Q_UNUSED(angle); } void MAbstractInputMethod::handleAppOrientationChanged(int angle) { // empty default implementation Q_UNUSED(angle); } void MAbstractInputMethod::processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 /* nativeScanCode */, quint32 /* nativeModifiers */, unsigned long /*time*/) { // default implementation, just sendKeyEvent back inputMethodHost()->sendKeyEvent(QKeyEvent(keyType, keyCode, modifiers, text, autoRepeat, count)); } void MAbstractInputMethod::setState(const QSet &state) { // empty default implementation Q_UNUSED(state); } void MAbstractInputMethod::handleClientChange() { // empty default implementation } void MAbstractInputMethod::switchContext(Maliit::SwitchDirection direction, bool enableAnimation) { // empty default implementation Q_UNUSED(direction); Q_UNUSED(enableAnimation); } QList MAbstractInputMethod::subViews(Maliit::HandlerState state) const { Q_UNUSED(state); QList sVs; return sVs; } void MAbstractInputMethod::setActiveSubView(const QString &subViewId, Maliit::HandlerState state) { // empty default implementation Q_UNUSED(subViewId); Q_UNUSED(state); } QString MAbstractInputMethod::activeSubView(Maliit::HandlerState state) const { Q_UNUSED(state); return QString(); } void MAbstractInputMethod::showLanguageNotification() { // empty default implementation } void MAbstractInputMethod::setKeyOverrides(const QMap > &overrides) { // empty default implementation Q_UNUSED(overrides); } bool MAbstractInputMethod::imExtensionEvent(MImExtensionEvent *event) { Q_UNUSED(event); return false; // event not handled as default } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/abstractinputmethod.h000066400000000000000000000240121262307254400275220ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MABSTRACTINPUTMETHOD_H #define MABSTRACTINPUTMETHOD_H #include #include #include #include #include class QRegion; class QPoint; class QRect; class MAbstractInputMethodHost; class MAbstractInputMethodPrivate; class MKeyOverride; class MImExtensionEvent; /*! \ingroup pluginapi * \brief A base class for input methods. * * Defines the interface which input method framework uses for passing commands * received from the applications to plugins. Communication in the other * direction, from the input method plugin to the framework, is done using the * MAbstractInputMethodHost object returned from inputMethodHost(). */ class MAbstractInputMethod: public QObject { Q_OBJECT public: /*! * MInputMethodSubView defines an input method subview with an identifier \a subViewId * and a title \a subViewTitle. * * The subview is a view which provided by this input method. The view could be a view of one * language, or one keyboard, it depends on the input method. Each subview has an identifier * and title. The subview title will be shown in the input method settings, and * should be a localized string. */ struct MInputMethodSubView { QString subViewId; QString subViewTitle; }; /*! Constructor * * \param host serves as communication link to framework and application. Managed by framework. */ explicit MAbstractInputMethod(MAbstractInputMethodHost *host); virtual ~MAbstractInputMethod(); /*! \brief Returns input method host. */ MAbstractInputMethodHost *inputMethodHost() const; /*! \brief Show request. * * The input method should normally show its UI on this call, unless * handleVisualizationPriorityChange(bool) was called with a true value. * \sa handleVisualizationPriorityChange(bool) */ virtual void show(); /*! \brief Hide request. * * The input method must hide itself when this is called. */ virtual void hide(); /*! \brief Notifies input method about predit string changes. * * This method informs the input method about preedit and the cursor * position. The input method can fully control the preedit * and the cursor inside it: whether and where to show * cursor inside preedit, and how the preedit string should be styled. * \sa MAbstractInputMethodHost::sendPreeditString() * * \param preeditString preedit string * \param cursorPos the cursor position inside preedit. */ virtual void setPreedit(const QString &preeditString, int cursorPos); /*! \brief State update notification. * * General update notification. Called in addition to the specific methods. */ virtual void update(); /*! \brief Reset notification. */ virtual void reset(); /*! \brief Notifies input method about mouse click on the preedit string. * * Reimplementing this method is optional. It is used by Meego Keyboard. */ virtual void handleMouseClickOnPreedit(const QPoint &pos, const QRect &preeditRect); /*! \brief Notifies input method about focus changes on application side. * * Reimplementhing this method is optional. * * \param focusIn true - focus has entered a widget, false - focus has left a widget */ virtual void handleFocusChange(bool focusIn); /*! \brief Notifies that the focus widget in application changed visualization priority. * * This method is used by the framework to allow the input method to be dismissed while a widget is focused. * Further calls to show() when priority is true should not show the input method. * When priority is set to false again, and the input method is not in hidden state, * the input method should be shown. * * \param priority If true, the application has priority, and the input method should not be shown. */ virtual void handleVisualizationPriorityChange(bool priority); /*! \brief Target application is about to change orientation. * * The input method usually changes its own orientation according to this. * Note that this method might not be called when the input method shown for the first time. * \sa handleAppOrientationChanged(int angle) * * \param angle The angle in degrees. Possible values: 0, 90, 180, 270. 0 is the normal orientation of the display server. */ virtual void handleAppOrientationAboutToChange(int angle); /*! \brief Target application already finish changing orientation. * * \param angle The angle in degrees. Possible values: 0, 90, 180, 270. 0 is the normal orientation of the display server. */ virtual void handleAppOrientationChanged(int angle); /*! * \brief Process a key event redirected from hardware keyboard to input method. * * This is called only if one has enabled redirection by calling * \a MInputContextConnection::setRedirectKeys. * * Reimplementing this method is optional. It can be used to implement input methods * that handle hardware keyboard. */ virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); /*! * \brief This method is called to inform about keyboard status changes * * For example: Hardware keyboard is opened or closed, BT keyboard is connected or * disconnected. * * \param state set of current states for this plugin */ virtual void setState(const QSet &state); /*! \brief This method is called when target client (application) has changed. */ virtual void handleClientChange(); /*! * \brief Switch context to given direction * * If the input method arranges the subviews horizontally (like Meego Keyboard does) it * should first try to change its subviews in the direction indicated. If there are no * more subviews in the given direction, MInputMethodHost::switchPlugin(Maliit::SwitchDirection ) * should be called. * * \param direction Switching direction * \param enableAnimation Contains true if swipe should be animated */ virtual void switchContext(Maliit::SwitchDirection direction, bool enableAnimation); /*! \brief Returns all subviews (IDs and titles) which are supported for \a state. * * Implement this function to return the subviews which are supported by this input * method for the specified state. An input method must return at least one subview * for a supported state. */ virtual QList subViews(Maliit::HandlerState state = Maliit::OnScreen) const; /*! * \brief Sets \a subViewId as the active subview for \a state. * * Implement this method to set the active subview. Input method plugins manager will call * this method when active subview for specified state is changed from the input method * settings. * * \param subViewId the identifier of subview. * \param state the state which \a subViewId belongs to. */ virtual void setActiveSubView(const QString &subViewId, Maliit::HandlerState state = Maliit::OnScreen); /*! * \brief Returns current active subview ID for \a state. * * Implement this method to inform input method plugins manager about current active subview * for specified state. */ virtual QString activeSubView(Maliit::HandlerState state = Maliit::OnScreen) const; /*! \brief Show notification to user informing about current language/subview * * Reimplementing this method is optional. */ virtual void showLanguageNotification(); /*! * \brief Uses custom key overrides which are defined by given parameter. * * Reimplementing this method is optional. It is used in Meego Keyboard * to provide context aware keys that can be customized from the application * side. * * \param overrides Pointer to key override definitions. An empty map means * that no key override exists, and that the normal values should be used. */ virtual void setKeyOverrides(const QMap > &overrides); /*! * \brief handles extension event not covered by a dedicated method. * * Must return true if event is handled, otherwise false. * Extensions can be registered on the application side, and will be passed through to * the input method, allowing to add integration points between application and input method. * Reimplementing this method is optional. * * \param event event to handle */ virtual bool imExtensionEvent(MImExtensionEvent *event); Q_SIGNALS: /*! * \brief Inform that active subview is changed to \a subViewId for \a state. * * Must be emitted when plugin changes the active subview for specified state. * * \param subViewId the identifier of the new subview. * \param state the state which \a subViewId belongs to. */ void activeSubViewChanged(const QString &subViewId, Maliit::HandlerState state = Maliit::OnScreen); private: Q_DISABLE_COPY(MAbstractInputMethod) Q_DECLARE_PRIVATE(MAbstractInputMethod) MAbstractInputMethodPrivate * const d_ptr; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/abstractinputmethodhost.cpp000066400000000000000000000027441262307254400307630ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include class MAbstractInputMethodHostPrivate { public: MAbstractInputMethodHostPrivate(); ~MAbstractInputMethodHostPrivate(); }; MAbstractInputMethodHostPrivate::MAbstractInputMethodHostPrivate() { } MAbstractInputMethodHostPrivate::~MAbstractInputMethodHostPrivate() { } MAbstractInputMethodHost::MAbstractInputMethodHost(QObject *parent) : QObject(parent), d(new MAbstractInputMethodHostPrivate) { // nothing } MAbstractInputMethodHost::~MAbstractInputMethodHost() { delete d; } bool MAbstractInputMethodHost::hiddenText(bool &valid) { valid = false; return false; } QPixmap MAbstractInputMethodHost::background() const { return QPixmap(); } QList MAbstractInputMethodHost::surroundingSubViewDescriptions(Maliit::HandlerState /*state*/) const { return QList(); } void MAbstractInputMethodHost::setLanguage(const QString &/*language*/) { } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/abstractinputmethodhost.h000066400000000000000000000264061262307254400304310ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MABSTRACTINPUTMETHODHOST_H #define MABSTRACTINPUTMETHODHOST_H #include #include #include #include #include #include class QString; class QRegion; class QKeyEvent; class MImPluginDescription; class MImSubViewDescription; class MAbstractInputMethodHostPrivate; namespace Maliit { namespace Plugins { class AbstractPluginSetting; } } /*! \ingroup maliitserver * \brief Provides an interface for input method instances to connect to the environment. * * MAbstractInputMethodHost provides methods MAbstractInputMethod instances can use * for interacting with the application that is using input method services and * the input method framework state itself. * * \note this is not meant to be derived by the input method framework users; * the concrete implementations are provided by the framework. */ class MAbstractInputMethodHost: public QObject { Q_OBJECT public: explicit MAbstractInputMethodHost(QObject *parent = 0); virtual ~MAbstractInputMethodHost(); /*! * \brief returns content type for focused widget if output parameter valid is true, * value matches enum M::TextContentType */ virtual int contentType(bool &valid) = 0; /*! * \brief returns input method correction hint if output parameter valid is true. */ virtual bool correctionEnabled(bool &valid) = 0; /*! * \brief returns input method word prediction hint if output parameter valid is true. */ virtual bool predictionEnabled(bool &valid) = 0; /*! * \brief returns input method auto-capitalization hint if output parameter valid is true. */ virtual bool autoCapitalizationEnabled(bool &valid) = 0; /*! * \brief get surrounding text and cursor position information */ virtual bool surroundingText(QString &text, int &cursorPosition) = 0; /*! * \brief returns true if there is selecting text */ virtual bool hasSelection(bool &valid) = 0; /*! * \brief get input method mode */ virtual int inputMethodMode(bool &valid) = 0; /*! * \brief get preedit rectangle */ virtual QRect preeditRectangle(bool &valid) = 0; /*! * \brief get cursor rectangle */ virtual QRect cursorRectangle(bool &valid) = 0; /*! * \brief returns the position of the selection anchor. * * This may be less or greater than cursor position, depending on which side of selection * the cursor is. If there is no selection, it returns the same as cursor position. */ virtual int anchorPosition(bool &valid) = 0; /*! * \brief true if text input is being made hidden, e.g. with password fields */ virtual bool hiddenText(bool &valid); /*! * \brief returns the selecting text */ virtual QString selection(bool &valid) = 0; /*! * \brief Registers a window in server. * * Should be called for every QWindow created by plugin before calling * create on it. Note that this function set some flags on the window, so be * careful to not reset them by accident. */ virtual void registerWindow (QWindow *window, Maliit::Position position) = 0; /*! * \brief returns a pixmap that needs to be drawn as the background of the * input method. Pixmap contains the application's window contents. */ QPixmap background() const; Q_SIGNALS: //! This signal is emitted when input method plugins are loaded or unloaded void pluginsChanged(); public Q_SLOTS: /*! * \brief Updates pre-edit string in the application widget * * \param string The new pre-edit string * \param preeditFormats Selects visual stylings for each part of preedit * \param replacementStart The position at which characters are to be replaced relative * from the start of the preedit string. * \param replacementLength The number of characters to be replaced in the preedit string. * \param cursorPos The cursur position inside preedit */ virtual void sendPreeditString(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1) = 0; /*! * \brief Updates commit string in the application widget, and set cursor position. * * \param string The string to be committed * \param replaceStart The position at which characters are to be replaced relative * from the start of the preedit string. * \param replaceLength The number of characters to be replaced in the preedit string. * \param cursorPos The cursor position to be set. the cursorPos is the position relative * to commit string start. Negative values are used as commit string end position. * Cursor position is applied AFTER committing text. This means the position might be * different than intended because of active validators etc. */ virtual void sendCommitString(const QString &string, int replaceStart = 0, int replaceLength = 0, int cursorPos = -1) = 0; /*! * \brief Sends key event to the application * * This method is used to deliver the key event to active widget. * A \a MInputMethodState::keyPress or \a MInputMethodState::keyRelease * event is also emitted. Depending on the value of \a requestType * parameter, a Qt::KeyEvent and/or a signal is emitted. * \param keyEvent The event to send * \param signalOnly only the signal should be emitted. */ virtual void sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType = Maliit::EventRequestBoth) = 0; /*! * \brief Notifies about hiding initiated by the input method. */ virtual void notifyImInitiatedHiding() = 0; /*! * \brief calls actions like "copy" or "paste" on the focused text entry. * * \param action The action to call * \param sequence The fall-back key sequence when action is not available */ virtual void invokeAction(const QString &action, const QKeySequence &sequence) = 0; /*! * \brief Set if the input method wants to process all raw key events * from hardware keyboard (via \a processKeyEvent calls). */ virtual void setRedirectKeys(bool enabled) = 0; /*! * \brief Set detectable autorepeat for X on/off * * Detectable autorepeat means that instead of press, release, press, release, press, * release... sequence of key events you get press, press, press, release key events * when a key is repeated. The setting is X client specific. This is intended to be * used when key event redirection is enabled with \a setRedirectKeys. */ virtual void setDetectableAutoRepeat(bool enabled) = 0; /*! * \brief set global correction option enable/disable */ virtual void setGlobalCorrectionEnabled(bool enabled) = 0; /*! * Asks environment to change active plugin according to \a direction. */ virtual void switchPlugin(Maliit::SwitchDirection direction) = 0; /*! * Asks environment to change active plugin to specified one. * \param pluginName Name for plugin which will be activated */ virtual void switchPlugin(const QString &pluginName) = 0; /*! * Reserves screen area for input method. Mouse events on top of this * area do not fall through to the application * * \param region the new region * \param window window for which region applies. If zero, first registered window is used. */ virtual void setScreenRegion(const QRegion ®ion, QWindow *window = 0) = 0; /*! * Sets part of the screen area covered by the input method that * should be avoided by the application receiving input in order not to be * obscured. * * For now this region must be so simple that its bounding box can be * effectively used as the avoidance area. * * \param region the new region * \param window window for which input method area applies. If zero, first registered window is used. */ virtual void setInputMethodArea(const QRegion ®ion, QWindow *window = 0) = 0; /*! *\brief Sets selection text from \a start with \a length in the application widget. */ virtual void setSelection(int start, int length) = 0; /*! * \brief Locks application orientation. * * \deprecated Not implemented */ virtual void setOrientationAngleLocked(bool lock) = 0; public: /*! * \brief Return information about loaded input method plugins which could work in specified \a state. * * \sa MImPluginDesription */ virtual QList pluginDescriptions(Maliit::HandlerState state) const = 0; /*! * \brief returns the current cursor position within the preedit region */ virtual int preeditClickPos(bool &valid) const { Q_UNUSED(valid); return 0; } /*! * \brief Return information about enabled subviews which are neighbors * (previous and next) of current active subview. * * Previous subview is described by first list item, next * subview is defined by last list item. * Returned list is empty if there is exactly one enabled subview. * * \sa MImSubViewDescription */ virtual QList surroundingSubViewDescriptions(Maliit::HandlerState state) const; /*! * \brief Sets current input method language. * \param language ICU format locale ID string * * This can be used as a hint to determine text direction in input fields, for example. */ virtual void setLanguage(const QString &language); /*! * \brief Register a new plugin setting * \param key name for the entry * \param type value type * \param attributes attribute map, the same used in SettingsEntry * * Returns an object (owned by the plugin) that can be used to manipulate the setting entry. * * \sa Maliit::SettingEntryAttributes * \sa Maliit::SettingsEntry */ virtual Maliit::Plugins::AbstractPluginSetting *registerPluginSetting(const QString &key, const QString &description, Maliit::SettingEntryType type, const QVariantMap &attributes) = 0; private: Q_DISABLE_COPY(MAbstractInputMethodHost) Q_DECLARE_PRIVATE(MAbstractInputMethodHost) MAbstractInputMethodHostPrivate *d; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/abstractpluginsetting.h000066400000000000000000000040731262307254400300630ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Mattia Barbon * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MALIIT_PLUGIN_SETTINGS_H #define MALIIT_PLUGIN_SETTINGS_H #include namespace Maliit { namespace Plugins { /*! \ingroup maliitserver * \brief A generic interface to access plugin configuration values */ class AbstractPluginSetting : public QObject { Q_OBJECT public: //! Returns the key of this item, as given to MAbstractInputMethodHost::registerPluginSetting() virtual QString key() const = 0; //! Returns the current value of this item, as a QVariant. virtual QVariant value() const = 0; /*! Returns the current value of this item, as a QVariant. If * there is no value for this item, return \a def instead. */ virtual QVariant value(const QVariant &def) const = 0; /*! Set the value of this item to \a val. If string \a val fails for any reason, the current value is not changed and nothing happens. */ virtual void set(const QVariant &val) = 0; /*! Unset this item. This is equivalent to \code item.set(QVariant(QVariant::Invalid)); \endcode */ virtual void unset() = 0; //! Emitted when the value of this item has changed. Q_SIGNAL void valueChanged(); }; } } #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/attributeextension.cpp000066400000000000000000000024371262307254400277400ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include #include MAttributeExtensionPrivate::MAttributeExtensionPrivate() : id() { } MAttributeExtension::MAttributeExtension(const MAttributeExtensionId &id, const QString &) : d_ptr(new MAttributeExtensionPrivate()) { Q_D(MAttributeExtension); d->id = id; d->keyOverrideData = QSharedPointer(new MKeyOverrideData()); } MAttributeExtension::~MAttributeExtension() { delete d_ptr; } MAttributeExtensionId MAttributeExtension::id() const { Q_D(const MAttributeExtension); return d->id; } QSharedPointer MAttributeExtension::keyOverrideData() const { Q_D(const MAttributeExtension); return d->keyOverrideData; } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/attributeextension.h000066400000000000000000000026451262307254400274060ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MATTRIBUTEEXTENSION_H #define MATTRIBUTEEXTENSION_H #include #include #include class MAttributeExtensionId; class MAttributeExtensionPrivate; class MKeyOverrideData; /*! \ingroup pluginapi * \brief Attribute extension. */ class MAttributeExtension : public QObject { Q_OBJECT Q_DISABLE_COPY(MAttributeExtension) public: /*! * \brief Constructor */ MAttributeExtension(const MAttributeExtensionId &id, const QString &fileName); /*! * \brief Destructor */ ~MAttributeExtension(); MAttributeExtensionId id() const; //! Return the pointer to key override data. QSharedPointer keyOverrideData() const; protected: Q_DECLARE_PRIVATE(MAttributeExtension) MAttributeExtensionPrivate *const d_ptr; friend class MAttributeExtensionManager; friend class Ut_MAttributeExtension; friend class Ut_MAttributeExtensionManager; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/attributeextension_p.h000066400000000000000000000015661262307254400277260ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MATTRIBUTEEXTENSION_P_H #define MATTRIBUTEEXTENSION_P_H #include #include "mattributeextensionid.h" class MKeyOverrideData; class MAttributeExtensionPrivate { public: Q_DECLARE_PUBLIC(MAttributeExtension) MAttributeExtensionPrivate(); private: MAttributeExtensionId id; QSharedPointer keyOverrideData; MAttributeExtension *q_ptr; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/extensionevent.cpp000066400000000000000000000021171262307254400270510ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include MImExtensionEventPrivate::~MImExtensionEventPrivate() {} MImExtensionEvent::MImExtensionEvent(Type type) : d_ptr(new MImExtensionEventPrivate) { d_ptr->type = type; } MImExtensionEvent::MImExtensionEvent(MImExtensionEventPrivate *dd, Type type) : d_ptr(dd) { d_ptr->type = type; } MImExtensionEvent::~MImExtensionEvent() { Q_D(MImExtensionEvent); delete d; } MImExtensionEvent::Type MImExtensionEvent::type() const { Q_D(const MImExtensionEvent); return d->type; } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/extensionevent.h000066400000000000000000000025201262307254400265140ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMEXTENSIONEVENT_H #define MIMEXTENSIONEVENT_H #include class MImExtensionEventPrivate; /*! \ingroup pluginapi * \brief Base class for extending signaling from input method system to * plugins. * * This event can be subclassed for future additions. * * \sa MAbstractInputMethod::imExtensionEvent(MImExtensionEvent *event) */ class MImExtensionEvent { public: //! Defines valid types for input method extension event enum Type { None, Update }; explicit MImExtensionEvent(Type type); virtual ~MImExtensionEvent(); //! Returns the type of the event Type type() const; protected: MImExtensionEvent(MImExtensionEventPrivate *dd, Type type); MImExtensionEventPrivate * const d_ptr; private: Q_DISABLE_COPY(MImExtensionEvent) Q_DECLARE_PRIVATE(MImExtensionEvent) }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/extensionevent_p.h000066400000000000000000000013351262307254400270360ustar00rootroot00000000000000#ifndef MIMEXTENSIONEVENT_P_H #define MIMEXTENSIONEVENT_P_H /* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include class MImExtensionEventPrivate { public: virtual ~MImExtensionEventPrivate(); MImExtensionEvent::Type type; }; #endif // MIMEXTENSIONEVENT_P_H maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/inputmethodplugin.h000066400000000000000000000036241262307254400272230ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MINPUTMETHODPLUGIN_H #define MINPUTMETHODPLUGIN_H #include #include #include #include class MAbstractInputMethod; class MAbstractInputMethodHost; namespace Maliit { namespace Plugins { /*! \ingroup pluginapi * \brief An interface class for all input method plugins. * * To create a virtual keyboard / input method plugin, re-implement the virtual * functions and instantiate the input method implementation in the * createInputMethod() method. Make sure your plugin links against the m im * framework library as well. */ class InputMethodPlugin { public: /*! \brief Implement this function to return the identifier for this input method. */ virtual QString name() const = 0; /*! \brief Creates and returns the MAbstractInputMethod object for * this plugin. This function will be only called once and the allocated * resources will be owned by the input method server. */ virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host) = 0; /*! * \brief Returns set of states which could be handled by this plugin. * * WARNING: If result is empty then this plugin will not be loaded * during startup. */ virtual QSet supportedStates() const = 0; }; } } Q_DECLARE_INTERFACE(Maliit::Plugins::InputMethodPlugin, "org.maliit.plugins.InputMethodPlugin/1.1") #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/keyoverride.cpp000066400000000000000000000053551262307254400263320ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include MKeyOverridePrivate::MKeyOverridePrivate() : highlighted(false), enabled(true) { } void MKeyOverridePrivate::assign(const MKeyOverridePrivate &other) { keyId = other.keyId; label = other.label; icon = other.icon; highlighted = other.highlighted; enabled = other.enabled; } MKeyOverride::MKeyOverride(const QString &keyId) : QObject(), d_ptr(new MKeyOverridePrivate) { d_ptr->keyId = keyId; } MKeyOverride::MKeyOverride(const MKeyOverride &other) : QObject(), d_ptr(new MKeyOverridePrivate) { *this = other; } MKeyOverride::~MKeyOverride() { delete d_ptr; } const MKeyOverride & MKeyOverride::operator=(const MKeyOverride &other) { Q_D(MKeyOverride); d->assign(*other.d_ptr); return *this; } QString MKeyOverride::keyId() const { Q_D(const MKeyOverride); return d->keyId; } QString MKeyOverride::label() const { Q_D(const MKeyOverride); return d->label; } QString MKeyOverride::icon() const { Q_D(const MKeyOverride); return d->icon; } bool MKeyOverride::highlighted() const { Q_D(const MKeyOverride); return d->highlighted; } bool MKeyOverride::enabled() const { Q_D(const MKeyOverride); return d->enabled; } void MKeyOverride::setLabel(const QString &label) { Q_D(MKeyOverride); if (d->label != label) { d->label = label; Q_EMIT labelChanged(label); Q_EMIT keyAttributesChanged(keyId(), Label); } } void MKeyOverride::setIcon(const QString &icon) { Q_D(MKeyOverride); if (d->icon != icon) { d->icon = icon; Q_EMIT iconChanged(icon); Q_EMIT keyAttributesChanged(keyId(), Icon); } } void MKeyOverride::setHighlighted(bool highlighted) { Q_D(MKeyOverride); if (d->highlighted != highlighted) { d->highlighted = highlighted; Q_EMIT highlightedChanged(highlighted); Q_EMIT keyAttributesChanged(keyId(), Highlighted); } } void MKeyOverride::setEnabled(bool enabled) { Q_D(MKeyOverride); if (d->enabled != enabled) { d->enabled = enabled; Q_EMIT enabledChanged(enabled); Q_EMIT keyAttributesChanged(keyId(), Enabled); } } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/keyoverride.h000066400000000000000000000074321262307254400257750ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MKEYOVERRIDE_H #define MKEYOVERRIDE_H #include #include #include #include class MKeyOverridePrivate; /*! \ingroup maliitserver * \brief MKeyOverride is used to store key attribute overrides for virtual keyboard. */ class MKeyOverride : public QObject { Q_OBJECT Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged) Q_PROPERTY(bool highlighted READ highlighted WRITE setHighlighted NOTIFY highlightedChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) public: //! Defines all the attributes of an key override. enum KeyOverrideAttribute { Label = 0x1, Icon = 0x2, Highlighted = 0x4, Enabled = 0x8, All = Label | Icon | Highlighted | Enabled }; Q_DECLARE_FLAGS(KeyOverrideAttributes, KeyOverrideAttribute) /*! * \brief Constructor */ explicit MKeyOverride(const QString &keyId); /*! * \brief Copy constructor */ MKeyOverride(const MKeyOverride&); /*! * \brief Destructor */ virtual ~MKeyOverride(); /* * \brief Assignment operator */ const MKeyOverride &operator=(const MKeyOverride &other); /*! * \brief Returns the key id. */ QString keyId() const; //! Returns text from the key QString label() const; //! Returns icon name QString icon() const; //! Return true if the key is highlighted; otherwise return false. bool highlighted() const; //! Return true if the key is enabled; otherwise return false. bool enabled() const; public Q_SLOTS: //! Sets text for the key void setLabel(const QString &label); //! Sets icon name void setIcon(const QString &icon); /*! * \brief Set highlighted state for item * */ void setHighlighted(bool highlighted); /*! * \brief If \a enabled is true, the key is enabled; otherwise, it is disabled. * */ void setEnabled(bool enabled); Q_SIGNALS: /*! * \brief Emitted when some attributes of the key are changed. * * This signal is emitted after attribute specific signal. * * \param keyId, the key id. * \param changedAttributes Specifies the changed attributes. \sa KeyOverrideAttribute */ void keyAttributesChanged(const QString &keyId, const MKeyOverride::KeyOverrideAttributes changedAttributes); /*! * \brief Emitted when label is changed. * * This signal is emitted before keyAttributesChanged signal. */ void labelChanged(const QString &label); /*! * \brief Emitted when icon is changed. * * This signal is emitted before keyAttributesChanged signal. */ void iconChanged(const QString &icon); /*! * \brief Emitted when highlighted is changed. * * This signal is emitted before keyAttributesChanged signal. */ void highlightedChanged(bool highlighted); /*! * \brief Emitted when enabled is changed. * * This signal is emitted before keyAttributesChanged signal. */ void enabledChanged(bool enabled); private: Q_DECLARE_PRIVATE(MKeyOverride) MKeyOverridePrivate *const d_ptr; friend class Ut_MKeyOverride; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/keyoverride_p.h000066400000000000000000000015011262307254400263030ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MKEYOVERRIDE_P_H #define MKEYOVERRIDE_P_H #include class MWidgetData; class MKeyOverridePrivate { Q_DISABLE_COPY(MKeyOverridePrivate) public: MKeyOverridePrivate(); void assign(const MKeyOverridePrivate &other); QString keyId; QString label; QString icon; bool highlighted; bool enabled; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/keyoverridedata.cpp000066400000000000000000000027531262307254400271630ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include namespace { inline bool keyOverrideLessThan(const QSharedPointer &k1, const QSharedPointer &k2) { return (k1->keyId() < k2->keyId()); }; } MKeyOverrideData::MKeyOverrideData() { } MKeyOverrideData::~MKeyOverrideData() { } QList > MKeyOverrideData::keyOverrides() const { QList > results = mKeyOverrides.values(); qSort(results.begin(), results.end(), keyOverrideLessThan); return results; } bool MKeyOverrideData::createKeyOverride(const QString &keyId) { if (!mKeyOverrides.contains(keyId)) { QSharedPointer keyOverride; keyOverride = QSharedPointer(new MKeyOverride(keyId)); mKeyOverrides.insert(keyId, keyOverride); return true; } return false; } QSharedPointer MKeyOverrideData::keyOverride(const QString &keyId) const { return mKeyOverrides.value(keyId); } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/keyoverridedata.h000066400000000000000000000030301262307254400266150ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MKEYOVERRIDEDATA_H #define MKEYOVERRIDEDATA_H #include #include #include #include #include /*! \ingroup maliitserver * \brief Corresponds to the key overrides. */ class MKeyOverrideData : public QObject { Q_OBJECT Q_DISABLE_COPY(MKeyOverrideData) public: /*! * \brief Constructor */ MKeyOverrideData(); /*! * \brief Destructor */ ~MKeyOverrideData(); /* * \brief Return all key overrides in this key override data. * The returned list is sorted by key Id. */ QList > keyOverrides() const; //! Returns true if a new key override is created. bool createKeyOverride(const QString &keyId); //! Returns pointer to the key override for given \a keyId QSharedPointer keyOverride(const QString &keyId) const; protected: typedef QMap > KeyOverrides; KeyOverrides mKeyOverrides; friend class Ut_MKeyOverrideData; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/plugindescription.cpp000066400000000000000000000036041262307254400275370ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include //! \internal class MImPluginDescriptionPrivate { public: //! Construct new instance. //! \param plugin Reference to loaded plugin. MImPluginDescriptionPrivate(const Maliit::Plugins::InputMethodPlugin &plugin); public: //! Plugin name. QString pluginName; //! Contains true if this plugin is enabled onscreen plugin. bool enabled; }; //! \internal_end MImPluginDescriptionPrivate::MImPluginDescriptionPrivate(const Maliit::Plugins::InputMethodPlugin &plugin) : pluginName(plugin.name()), enabled(true) { } MImPluginDescription::MImPluginDescription(const Maliit::Plugins::InputMethodPlugin &plugin) : d_ptr(new MImPluginDescriptionPrivate(plugin)) { } MImPluginDescription::MImPluginDescription(const MImPluginDescription &other) : d_ptr(new MImPluginDescriptionPrivate(*other.d_ptr)) { } MImPluginDescription::~MImPluginDescription() { delete d_ptr; } void MImPluginDescription::operator=(const MImPluginDescription &other) { *d_ptr = *other.d_ptr; } QString MImPluginDescription::name() const { Q_D(const MImPluginDescription); return d->pluginName; } bool MImPluginDescription::enabled() const { Q_D(const MImPluginDescription); return d->enabled; } void MImPluginDescription::setEnabled(bool newEnabled) { Q_D(MImPluginDescription); d->enabled = newEnabled; } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/plugindescription.h000066400000000000000000000030421262307254400272000ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMPLUGINDESCRIPTION_H #define MIMPLUGINDESCRIPTION_H #include class MImPluginDescriptionPrivate; namespace Maliit { namespace Plugins { class InputMethodPlugin; } } /*! \ingroup maliitserver * \brief Provides information about loaded input method plugin */ class MImPluginDescription { public: //! Copy constructor. MImPluginDescription(const MImPluginDescription &other); //! Destructor. virtual ~MImPluginDescription(); //! Assignment operator void operator=(const MImPluginDescription &other); //! Return plugin name. QString name() const; //! \brief Return true if this plugin is enabled by settings. bool enabled() const; private: //! Constructor //! \param plugin Reference to loaded plugin. explicit MImPluginDescription(const Maliit::Plugins::InputMethodPlugin &plugin); //! Set enabled state to given value. void setEnabled(bool newEnabled); Q_DECLARE_PRIVATE(MImPluginDescription) MImPluginDescriptionPrivate * const d_ptr; friend class MIMPluginManagerPrivate; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/subviewdescription.cpp000066400000000000000000000043071262307254400277260ustar00rootroot00000000000000#include //! \internal class MImSubViewDescriptionPrivate { public: //! Construct new instance. MImSubViewDescriptionPrivate(const QString &pluginId, const QString &subViewId, const QString &subViewTitle); friend bool operator==(const MImSubViewDescriptionPrivate &left, const MImSubViewDescriptionPrivate &right); public: //! Plugin ID. QString pluginId; //! Subview ID QString id; //! Subview title QString title; }; //! \internal_end MImSubViewDescriptionPrivate::MImSubViewDescriptionPrivate(const QString &pluginId, const QString &subViewId, const QString &subViewTitle) : pluginId(pluginId), id(subViewId), title(subViewTitle) { } bool operator==(const MImSubViewDescriptionPrivate &left, const MImSubViewDescriptionPrivate &right) { return (left.pluginId == right.pluginId && left.id == right.id && left.title == right.title); } MImSubViewDescription::MImSubViewDescription(const QString &pluginId, const QString &subViewId, const QString &subViewTitle) : d_ptr(new MImSubViewDescriptionPrivate(pluginId, subViewId, subViewTitle)) { } MImSubViewDescription::MImSubViewDescription(const MImSubViewDescription &other) : d_ptr(new MImSubViewDescriptionPrivate(*other.d_ptr)) { } MImSubViewDescription::~MImSubViewDescription() { delete d_ptr; } void MImSubViewDescription::operator=(const MImSubViewDescription &other) { *d_ptr = *other.d_ptr; } bool operator==(const MImSubViewDescription &left, const MImSubViewDescription &right) { return *left.d_ptr == *right.d_ptr; } QString MImSubViewDescription::pluginId() const { Q_D(const MImSubViewDescription); return d->pluginId; } QString MImSubViewDescription::id() const { Q_D(const MImSubViewDescription); return d->id; } QString MImSubViewDescription::title() const { Q_D(const MImSubViewDescription); return d->title; } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/subviewdescription.h000066400000000000000000000032761262307254400273770ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSUBVIEWDESCRIPTION_H #define MIMSUBVIEWDESCRIPTION_H #include class MImSubViewDescriptionPrivate; /*! \ingroup maliitserver * \brief Query the current subview properties. */ class MImSubViewDescription { public: //! Copy constructor. MImSubViewDescription(const MImSubViewDescription &other); //! Destructor. virtual ~MImSubViewDescription(); //! Assignment operator void operator=(const MImSubViewDescription &other); //! Returns true if \a left and \a right describe the same subview. friend bool operator==(const MImSubViewDescription &left, const MImSubViewDescription &right); //! Return plugin id. QString pluginId() const; //! Return subview id QString id() const; //! Return subview title QString title() const; private: //! Constructor //! \param plugin Reference to loaded plugin. explicit MImSubViewDescription(const QString &pluginId, const QString &subViewId, const QString &subViewTitle); Q_DECLARE_PRIVATE(MImSubViewDescription) MImSubViewDescriptionPrivate * const d_ptr; friend class MIMPluginManagerPrivate; }; #endif // MIMSUBVIEWDESCRIPTION_H maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/updateevent.cpp000066400000000000000000000070601262307254400263210ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include #include #include MImUpdateEventPrivate::MImUpdateEventPrivate() : update() , changedProperties() , lastHints(Qt::ImhNone) {} MImUpdateEventPrivate::MImUpdateEventPrivate(const QMap &newUpdate, const QStringList &newChangedProperties, const Qt::InputMethodHints &newLastHints) : update(newUpdate) , changedProperties(newChangedProperties) , lastHints(newLastHints) {} bool MImUpdateEventPrivate::isFlagSet(Qt::InputMethodHint hint, bool *changed) const { bool result = false; if (update.contains(Maliit::Internal::inputMethodHints)) { const Qt::InputMethodHints hints(static_cast( update.value(Maliit::Internal::inputMethodHints).toInt())); result = (hints & hint); } if (changed) { *changed = (result != ((lastHints & hint) != 0)); } return result; } QVariant MImUpdateEventPrivate::extractProperty(const QString &key, bool *changed) const { if (changed) { *changed = changedProperties.contains(key); } return update.value(key); } MImUpdateEvent::MImUpdateEvent(const QMap &update, const QStringList &changedProperties) : MImExtensionEvent(new MImUpdateEventPrivate(update, changedProperties, Qt::InputMethodHints()), MImExtensionEvent::Update) {} MImUpdateEvent::MImUpdateEvent(const QMap &update, const QStringList &changedProperties, const Qt::InputMethodHints &lastHints) : MImExtensionEvent(new MImUpdateEventPrivate(update, changedProperties, lastHints), MImExtensionEvent::Update) {} QVariant MImUpdateEvent::value(const QString &key) const { Q_D(const MImUpdateEvent); return d->update.value(key); } QStringList MImUpdateEvent::propertiesChanged() const { Q_D(const MImUpdateEvent); return d->changedProperties; } Qt::InputMethodHints MImUpdateEvent::hints(bool *changed) const { Q_D(const MImUpdateEvent); return static_cast( d->extractProperty(Maliit::Internal::inputMethodHints, changed).toInt()); } bool MImUpdateEvent::westernNumericInputEnforced(bool *changed) const { Q_D(const MImUpdateEvent); return d->extractProperty(Maliit::InputMethodQuery::westernNumericInputEnforced, changed).toBool(); } bool MImUpdateEvent::preferNumbers(bool *changed) const { Q_D(const MImUpdateEvent); return d->isFlagSet(Qt::ImhPreferNumbers, changed); } bool MImUpdateEvent::translucentInputMethod(bool *changed) const { Q_D(const MImUpdateEvent); return d->extractProperty(Maliit::InputMethodQuery::translucentInputMethod, changed).toBool(); } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/updateevent.h000066400000000000000000000057071262307254400257740ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMUPDATEEVENT_H #define MIMUPDATEEVENT_H #include #include class MImUpdateEventPrivate; class MImUpdateReceiver; /*! \ingroup pluginapi * \brief Monitor the input method properties sent by the application. */ class MImUpdateEvent : public MImExtensionEvent { public: //! C'tor //! \param update the map containing all properties. //! \param propertiesChanged a string list of changed properties. explicit MImUpdateEvent(const QMap &update, const QStringList &propertiesChanged); //! C'tor //! \param update the map containing all properties. //! \param propertiesChanged a string list of changed properties. //! \param lastHints the last input method hints, as compared to the new //! ones in the updates map. Necessary to detect whether a flag //! flipped between update event. explicit MImUpdateEvent(const QMap &update, const QStringList &propertiesChanged, const Qt::InputMethodHints &lastHints); //! Returns invalid QVariant if key is invalid. QVariant value(const QString &key) const; //! Returns list of keys that have changed, compared to last update event. QStringList propertiesChanged() const; //! Returns the focus widget's input method hints. //! \param changed whether this value changed with this event. Qt::InputMethodHints hints(bool *changed = 0) const; //! Returns whether western numeric input should be shown, overridding //! language-specific numeric inputs. //! False by default. //! \param changed whether this value changed with this event. bool westernNumericInputEnforced(bool *changed = 0) const; //! Returns whether input field has Qt::ImhPreferNumbers hint set. //! False by default. //! \param changed whether this value changed with this event. bool preferNumbers(bool *changed = 0) const; //! Returns whether the input method should be styled translucently. Useful //! when apps need to display a lot of information, for example terminals. //! False by default. //! \param changed whether this value changed with this event. bool translucentInputMethod(bool *changed = 0) const; private: Q_DISABLE_COPY(MImUpdateEvent) Q_DECLARE_PRIVATE(MImUpdateEvent) friend class MImUpdateReceiver; // Allows receiver to copy PIMPL instance. }; #endif // MIMUPDATEEVENT_H maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/updateevent_p.h000066400000000000000000000023771262307254400263130ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMUPDATEEVENT_P_H #define MIMUPDATEEVENT_P_H #include #include class MImUpdateEventPrivate : public MImExtensionEventPrivate { public: QMap update; QStringList changedProperties; Qt::InputMethodHints lastHints; explicit MImUpdateEventPrivate(); explicit MImUpdateEventPrivate(const QMap &newUpdate, const QStringList &newChangedProperties, const Qt::InputMethodHints &newLastHints); bool isFlagSet(Qt::InputMethodHint hint, bool *changed = 0) const; QVariant extractProperty(const QString &key, bool *changed = 0) const; }; #endif // MIMUPDATEEVENT_P_H maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/updatereceiver.cpp000066400000000000000000000046571262307254400270150ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include #include #include #include // Choosing inheritance instead of typedef, as we might want to add // receiver-specific data later. class MImUpdateReceiverPrivate : public MImUpdateEventPrivate {}; MImUpdateReceiver::MImUpdateReceiver(QObject *parent) : QObject(parent) , d_ptr(new MImUpdateReceiverPrivate) {} MImUpdateReceiver::~MImUpdateReceiver() { // TODO: Find out why using QScopedPointer for the PIMPL fails to compile. delete d_ptr; } void MImUpdateReceiver::process(MImUpdateEvent *ev) { if (not ev) { return; } // TODO: Replace this ever-growing, switch-like structure with a more // concise solution, based on Qt reflection (via QMetaObject and Qt // properties). Q_D(MImUpdateReceiver); d->changedProperties = ev->d_func()->changedProperties; d->update = ev->d_func()->update; bool changed = false; bool value = ev->westernNumericInputEnforced(&changed); if (changed) { Q_EMIT westernNumericInputEnforcedChanged(value); } changed = false; value = ev->preferNumbers(&changed); if (changed) { Q_EMIT preferNumbersChanged(value); } changed = false; value = ev->translucentInputMethod(&changed); if (changed) { Q_EMIT translucentInputMethodChanged(value); } } bool MImUpdateReceiver::westernNumericInputEnforced() const { Q_D(const MImUpdateReceiver); return d->extractProperty(Maliit::InputMethodQuery::westernNumericInputEnforced).toBool(); } bool MImUpdateReceiver::preferNumbers() const { Q_D(const MImUpdateReceiver); return d->isFlagSet(Qt::ImhPreferNumbers); } bool MImUpdateReceiver::translucentInputMethod() const { Q_D(const MImUpdateReceiver); return d->extractProperty(Maliit::InputMethodQuery::translucentInputMethod).toBool(); } maliit-framework-0.99.1+git20151118+62bd54b/src/maliit/plugins/updatereceiver.h000066400000000000000000000050351262307254400264510ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMUPDATERECEIVER_H #define MIMUPDATERECEIVER_H #include class MImUpdateReceiverPrivate; class MImUpdateEvent; /*! \ingroup pluginapi * \brief An example that turns data-polling from events into data-pushing via * properties and change notifications. * * Used in combination with MImUpdateEvents: The event is propagated down to * the final component, where it is then processed by an event receiver. The * receiver therefore acts as an endpoint for events, allowing the actual * consumers of input method properties to listen to property changes. Using * this approach, consumers are completely decoupled from the event propagation * itself. Event receivers implemented in plugins are supposed to be more * specialized than the generic MImUpdateReceiver. They can be designed to only * carry the properties that are required for a given endpoint. The life time * of event receivers usually exceeds the life time of events, which makes it * possible to keep signal connections between consumers and event receivers * alive. */ class MImUpdateReceiver : public QObject { Q_OBJECT Q_DISABLE_COPY(MImUpdateReceiver) Q_DECLARE_PRIVATE(MImUpdateReceiver) Q_PROPERTY(bool westernNumericInputEnforced READ westernNumericInputEnforced NOTIFY westernNumericInputEnforcedChanged) Q_PROPERTY(bool preferNumbers READ preferNumbers NOTIFY preferNumbersChanged) Q_PROPERTY(bool translucentInputMethod READ translucentInputMethod NOTIFY translucentInputMethodChanged) public: explicit MImUpdateReceiver(QObject *parent = 0); virtual ~MImUpdateReceiver(); void process(MImUpdateEvent *ev); bool westernNumericInputEnforced() const; bool preferNumbers() const; bool translucentInputMethod() const; Q_SIGNALS: void westernNumericInputEnforcedChanged(bool value); void preferNumbersChanged(bool value); void translucentInputMethodChanged(bool value); private: MImUpdateReceiverPrivate *const d_ptr; }; #endif // MIMUPDATERECEIVER_H maliit-framework-0.99.1+git20151118+62bd54b/src/mattributeextensionid.cpp000066400000000000000000000030211262307254400254600ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mattributeextensionid.h" #include namespace { const int InvalidId = -1; const int StandardId = -2; } MAttributeExtensionId::MAttributeExtensionId() : m_id(InvalidId) { } MAttributeExtensionId::MAttributeExtensionId(int id, const QString &service) : m_id(id), m_service(service) { } MAttributeExtensionId MAttributeExtensionId::standardAttributeExtensionId() { return MAttributeExtensionId(StandardId, QString()); } bool MAttributeExtensionId::isValid() const { return m_id >= 0 && !m_service.isEmpty(); } bool MAttributeExtensionId::operator==(const MAttributeExtensionId &other) const { return (m_id == other.m_id) && (m_service == other.m_service); } bool MAttributeExtensionId::operator!=(const MAttributeExtensionId &other) const { return !operator==(other); } QString MAttributeExtensionId::service() const { return m_service; } int MAttributeExtensionId::id() const { return m_id; } uint qHash(const MAttributeExtensionId &id) { return qHash(QPair(id.m_id, id.m_service)); } maliit-framework-0.99.1+git20151118+62bd54b/src/mattributeextensionid.h000066400000000000000000000035741262307254400251420ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MATTRIBUTEEXTENSIONID_H #define MATTRIBUTEEXTENSIONID_H #include #include #include //! \internal /*! \ingroup maliitserver * \brief Contains global unique identifier for an attribute extension. * * Such identifiers are generated by MAttributeExtensionManager::generateId. */ class MAttributeExtensionId { public: //! Construct invalid identifier. MAttributeExtensionId(); //! Construct identifier with given application \a id and \a service name. MAttributeExtensionId(int id, const QString &service); //! Return identifier for standard attribute extension static MAttributeExtensionId standardAttributeExtensionId(); //! Return true if identifier is valid. bool isValid() const; //! Returns true if \a other is equal to this object bool operator==(const MAttributeExtensionId &other) const; //! Returns true if \a other is not equal to this object bool operator!=(const MAttributeExtensionId &other) const; //! \return service part of the ID, given to constructor QString service() const; //! Id given by application int id() const; private: //! Id given by application int m_id; //! Unique application identifier QString m_service; friend uint qHash(const MAttributeExtensionId &id); }; //! Returns hash value for given \a id uint qHash(const MAttributeExtensionId &id); //! \internal_end #endif maliit-framework-0.99.1+git20151118+62bd54b/src/mattributeextensionmanager.cpp000066400000000000000000000255131262307254400265100ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mattributeextensionmanager.h" #include #include #include #include #include #include namespace { const QString DefaultConfigurationPath = QString::fromLatin1(MALIIT_EXTENSIONS_DIR); const char * const PreferredDomainSettingName(MALIIT_CONFIG_ROOT"preferred_domain"); const char * const DomainItemName("_domain"); const char * const KeysExtensionString("/keys"); const char * const ToolbarExtensionString("/toolbar"); const char * const GlobalExtensionString("/"); const char * const ToolbarIdAttribute = "toolbarId"; const char * const ToolbarAttribute = "toolbar"; const char * const FocusStateAttribute = "focusState"; } MAttributeExtensionManager::MAttributeExtensionManager() : copyPasteStatus(Maliit::InputMethodNoCopyPaste) { } MAttributeExtensionManager::~MAttributeExtensionManager() { } QList MAttributeExtensionManager::attributeExtensionIdList() const { return attributeExtensions.keys(); } QSharedPointer MAttributeExtensionManager::attributeExtension(const MAttributeExtensionId &id) const { AttributeExtensionContainer::const_iterator iterator(attributeExtensions.find(id)); if (iterator != attributeExtensions.end()) return iterator.value(); return QSharedPointer(); } bool MAttributeExtensionManager::contains(const MAttributeExtensionId &id) const { return attributeExtensions.contains(id); } void MAttributeExtensionManager::setCopyPasteState(bool copyAvailable, bool pasteAvailable) { Maliit::CopyPasteState newStatus = Maliit::InputMethodNoCopyPaste; if (copyAvailable) { newStatus = Maliit::InputMethodCopy; } else if (pasteAvailable) { newStatus = Maliit::InputMethodPaste; } if (copyPasteStatus == newStatus) return; copyPasteStatus = newStatus; switch (newStatus) { case Maliit::InputMethodNoCopyPaste: break; case Maliit::InputMethodCopy: break; case Maliit::InputMethodPaste: break; } } void MAttributeExtensionManager::registerAttributeExtension(const MAttributeExtensionId &id, const QString &fileName) { if (!id.isValid() || attributeExtensions.contains(id)) return; // Only register default extension in the case of empty string. // Don't register extension if user makes a typo in the file name. if (!fileName.isEmpty()) { QString absoluteFileName = fileName; QFileInfo info(absoluteFileName); if (info.isRelative()) absoluteFileName = DefaultConfigurationPath + info.fileName(); if (!QFile::exists(absoluteFileName)) return; } QSharedPointer attributeExtension(new MAttributeExtension(id, fileName)); if (attributeExtension) { attributeExtensions.insert(id, attributeExtension); } } void MAttributeExtensionManager::unregisterAttributeExtension(const MAttributeExtensionId &id) { AttributeExtensionContainer::iterator iterator(attributeExtensions.find(id)); if (iterator == attributeExtensions.end()) { return; } attributeExtensions.remove(id); } void MAttributeExtensionManager::setToolbarItemAttribute(const MAttributeExtensionId &id, const QString &itemName, const QString &attribute, const QVariant &value) { setExtendedAttribute(id, ToolbarExtensionString, itemName, attribute, value); } QMap > MAttributeExtensionManager::keyOverrides( const MAttributeExtensionId &id) const { QList > overrides; QSharedPointer extension = attributeExtension(id); if (extension) { overrides = extension->keyOverrideData()->keyOverrides(); } QMap > overridesMap; Q_FOREACH (const QSharedPointer &override, overrides) { overridesMap.insert(override->keyId(), override); } return overridesMap; } void MAttributeExtensionManager::setExtendedAttribute(const MAttributeExtensionId &id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value) { if (target == GlobalExtensionString) { Q_EMIT globalAttributeChanged(id, targetItem, attribute, value); return; } if (!id.isValid() || attribute.isEmpty() || targetItem.isEmpty() || !value.isValid()) return; QSharedPointer extension = attributeExtension(id); if (!extension) { qWarning() << "Extended attribute change with invalid id"; return; } if (target == KeysExtensionString) { // create key override if not exist. bool newKeyOverrideCreated = extension->keyOverrideData()->createKeyOverride(targetItem); QSharedPointer keyOverride = extension->keyOverrideData()->keyOverride(targetItem); Q_ASSERT(keyOverride); const QByteArray byteArray = attribute.toLatin1(); const char * const c_str = byteArray.data(); // Ignore l10n lengthvariants in QStrings for labels, always pick longest variant (first) if (attribute == "label") { QString label = value.toString(); label = label.split(QChar(0x9c)).first(); const QVariant newValue(label); keyOverride->setProperty(c_str, newValue); } else { keyOverride->setProperty(c_str, value); } // Q_EMIT signal to notify the new key override is created. if (newKeyOverrideCreated) { Q_EMIT keyOverrideCreated(); } } else { qWarning() << "Invalid or incompatible attribute extension target:" << target; } } void MAttributeExtensionManager::handleClientDisconnect(unsigned int clientId) { // unregister toolbars registered by the lost connection const QString service(QString::number(clientId)); QSet::iterator i(attributeExtensionIds.begin()); while (i != attributeExtensionIds.end()) { if ((*i).service() == service) { unregisterAttributeExtension(*i); i = attributeExtensionIds.erase(i); } else { ++i; } } } void MAttributeExtensionManager::handleExtendedAttributeUpdate(unsigned int clientId, int id, const QString &target, const QString &targetName, const QString &attribute, const QVariant &value) { MAttributeExtensionId globalId(id, QString::number(clientId)); if (globalId.isValid() && attributeExtensionIds.contains(globalId)) { setExtendedAttribute(globalId, target, targetName, attribute, value); } } void MAttributeExtensionManager::handleAttributeExtensionRegistered(unsigned int clientId, int id, const QString &attributeExtension) { MAttributeExtensionId globalId(id, QString::number(clientId)); if (globalId.isValid() && !attributeExtensionIds.contains(globalId)) { registerAttributeExtension(globalId, attributeExtension); attributeExtensionIds.insert(globalId); } } void MAttributeExtensionManager::handleAttributeExtensionUnregistered(unsigned int clientId, int id) { MAttributeExtensionId globalId(id, QString::number(clientId)); if (globalId.isValid() && attributeExtensionIds.contains(globalId)) { unregisterAttributeExtension(globalId); attributeExtensionIds.remove(globalId); } } void MAttributeExtensionManager::handleWidgetStateChanged(unsigned int clientId, const QMap &newState, const QMap &oldState, bool focusChanged) { Q_UNUSED(oldState); // toolbar change MAttributeExtensionId oldAttributeExtensionId; MAttributeExtensionId newAttributeExtensionId; oldAttributeExtensionId = attributeExtensionId; QVariant variant = newState[ToolbarIdAttribute]; if (variant.isValid()) { // map toolbar id from local to global newAttributeExtensionId = MAttributeExtensionId(variant.toInt(), QString::number(clientId)); } if (!newAttributeExtensionId.isValid()) { newAttributeExtensionId = MAttributeExtensionId::standardAttributeExtensionId(); } variant = newState[FocusStateAttribute]; if (not variant.isValid()) { qCritical() << __PRETTY_FUNCTION__ << "Invalid focus state"; } bool widgetFocusState = variant.toBool(); // compare the toolbar id (global) if (oldAttributeExtensionId != newAttributeExtensionId) { QString toolbarFile = newState[ToolbarAttribute].toString(); if (!contains(newAttributeExtensionId) && !toolbarFile.isEmpty()) { // register toolbar if toolbar manager does not contain it but // toolbar file is not empty. This can reload the toolbar data // if im-uiserver crashes. // XXX: should not happen, the input context is reponsible for registering // and resending the toolbar information on server reconnect qWarning() << "Unregistered toolbar found in widget information"; variant = newState[ToolbarIdAttribute]; if (variant.isValid()) { const int toolbarLocalId = variant.toInt(); // FIXME: brittle to call the signal handler directly like this handleAttributeExtensionRegistered(clientId, toolbarLocalId, toolbarFile); } } Q_EMIT attributeExtensionIdChanged(newAttributeExtensionId); // store the new used toolbar id(global). attributeExtensionId = newAttributeExtensionId; } // this happens when we focus on a text widget with no attribute extensions. else if (focusChanged && widgetFocusState) { Q_EMIT attributeExtensionIdChanged(newAttributeExtensionId); } } maliit-framework-0.99.1+git20151118+62bd54b/src/mattributeextensionmanager.h000066400000000000000000000147041262307254400261550ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MATTRIBUTEEXTENSIONMANAGER_H #define MATTRIBUTEEXTENSIONMANAGER_H #include #include #include #include #include #include #include #include #include "mattributeextensionid.h" #include "mimsettings.h" //! \internal /*! \ingroup maliitserver \brief The MAttributeExtensionManager class manager the virtual keyboard attribute extensions. AttributeExtensionManager loads and manages not only the toolbars which are registered by applications, but also the copy/paste button and key overrides. */ class MAttributeExtensionManager : public QObject { Q_OBJECT Q_DISABLE_COPY(MAttributeExtensionManager) public: /*! * \brief Default constructor. */ MAttributeExtensionManager(); /*! *\brief Destructor. */ virtual ~MAttributeExtensionManager(); /*! * \brief Register an input method attribute extension which is defined in \a fileName with the unique identifier \a id. * AttributeExtensionManager can load a attribute extension's content according \a id and \a fileName, and cache it for the * future use. The \a id should be unique, and the \a fileName is the absolute file name of the attribute extension. */ void registerAttributeExtension(const MAttributeExtensionId &id, const QString &fileName); /*! * \brief Unregister an input method attribute extension which unique identifier is \a id. * AttributeExtensionManager will remove the cached widget according \a id. */ void unregisterAttributeExtension(const MAttributeExtensionId &id); /*! * \brief Sets the \a attribute for the \a item in the custom toolbar which has the unique \a id to \a value. */ void setToolbarItemAttribute(const MAttributeExtensionId &id, const QString &item, const QString &attribute, const QVariant &value); /*! *\brief Returns widget data definition for gived \a id. */ QSharedPointer attributeExtension(const MAttributeExtensionId &id) const; /*! *\brief Returns key overrides definition for gived \a id. */ QMap > keyOverrides(const MAttributeExtensionId &id) const; /*! *\brief Returns whether registered attribute extensions contain \a id. */ bool contains(const MAttributeExtensionId &id) const; /*! *\brief Sets the \a attribute of the \a targetItem in the attribute extension \a target which has unique\a id to \a value. */ void setExtendedAttribute(const MAttributeExtensionId &id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); public Q_SLOTS: /*! * \brief Set copy/paste button state: hide it, show copy or show paste * \param copyAvailable True if text is selected * \param pasteAvailable True if clipboard content is not empty */ void setCopyPasteState(bool copyAvailable, bool pasteAvailable); void handleClientDisconnect(unsigned int clientId); void handleAttributeExtensionRegistered(unsigned int clientId, int id, const QString &attributeExtension); void handleAttributeExtensionUnregistered(unsigned int clientId, int id); void handleExtendedAttributeUpdate(unsigned int clientId, int id, const QString &target, const QString &targetName, const QString &attribute, const QVariant &value); void handleWidgetStateChanged(unsigned int clientId, const QMap &newState, const QMap &oldState, bool focusChanged); Q_SIGNALS: //! This signal is emited when a new key override is created. void keyOverrideCreated(); //! Emitted when attribute extension has changed void attributeExtensionIdChanged(const MAttributeExtensionId &id); /*! * \brief This signal is emitted when application wants to change global attribute * that affects the whole input methods framework. * \param id the attribute extension id * \param targetItem Item name * \param attribute Attribute name * \param value New attribute value */ void globalAttributeChanged(const MAttributeExtensionId &id, const QString &targetItem, const QString &attribute, const QVariant &value); /* * \brief Emitted when attribute is changed by framework or plugin. * \param id the unique identifier of a registered extended attribute. * \param target a string specifying the target for the attribute. * \param targetItem the item name. * \param attribute attribute to be changed. * \param value new value. * \sa handleExtendedAttributeUpdate() */ void notifyExtensionAttributeChanged(int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); private: /*! * \brief Returns a list of the id for all attribute extensions' ids. */ QList attributeExtensionIdList() const; typedef QHash > AttributeExtensionContainer; //! all registered attribute extensions AttributeExtensionContainer attributeExtensions; MAttributeExtensionId attributeExtensionId; //current attribute extension id QSet attributeExtensionIds; //all attribute extension ids //! Copy/paste button status Maliit::CopyPasteState copyPasteStatus; friend class Ut_MAttributeExtensionManager; }; //! \internal_end #endif maliit-framework-0.99.1+git20151118+62bd54b/src/mimhwkeyboardtracker.cpp000066400000000000000000000145171262307254400252600ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ // This file is based on mkeyboardstatetracker.cpp from libmeegotouch #include #include #include #include "mimhwkeyboardtracker.h" #include "mimhwkeyboardtracker_p.h" /* bit array ops */ #define BITS2BYTES(x) ((((x) - 1) / 8) + 1) #define TEST_BIT(bit, array) (array[(bit) / 8] & (1 << (bit) % 8)) namespace { const char * const keyboardPresent("/maemo/InternalKeyboard/Present"); const char * const keyboardOpen("/maemo/InternalKeyboard/Open"); } MImHwKeyboardTrackerPrivate::MImHwKeyboardTrackerPrivate(MImHwKeyboardTracker *q_ptr) : #ifdef HAVE_CONTEXTSUBSCRIBER keyboardOpenProperty(), #elif defined(Q_WS_MAEMO_5) keyboardOpenConf("/system/osso/af/slide-open"), #else evdevTabletModePending(-1), evdevTabletMode(0), #endif present(false) { #ifdef HAVE_CONTEXTSUBSCRIBER ContextProperty keyboardPresentProperty(keyboardPresent); keyboardOpenProperty.reset(new ContextProperty(keyboardOpen)); keyboardPresentProperty.waitForSubscription(true); keyboardOpenProperty->waitForSubscription(true); present = keyboardPresentProperty.value().toBool(); if (present) { QObject::connect(keyboardOpenProperty.data(), SIGNAL(valueChanged()), q_ptr, SIGNAL(stateChanged())); } else { keyboardOpenProperty.reset(); } #elif defined(Q_WS_MAEMO_5) present = true; QObject::connect(&keyboardOpenConf, SIGNAL(valueChanged()), q_ptr, SIGNAL(stateChanged())); #else Q_UNUSED(q_ptr); QObject::connect(this, SIGNAL(stateChanged()), q_ptr, SIGNAL(stateChanged())); detectEvdev(); #endif } void MImHwKeyboardTrackerPrivate::detectEvdev() { // Use udev to enumerate all input devices, using evdev on each device to // find the first device offering a SW_TABLET_MODE switch. If found, this // switch is used to determine keyboard presence. struct udev_list_entry *device; struct udev_list_entry *devices; struct udev *udev = udev_new(); if (!udev) return; struct udev_enumerate *enumerate = udev_enumerate_new(udev); if (!enumerate) { udev_unref(udev); return; } udev_enumerate_add_match_subsystem(enumerate, "input"); udev_enumerate_add_match_property(enumerate, "ID_INPUT", "1"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(device, devices) { const char *syspath = udev_list_entry_get_name(device); struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath); const char *device = udev_device_get_devnode(udev_device); if (device) tryEvdevDevice(device); udev_device_unref(udev_device); if (present) break; } udev_enumerate_unref(enumerate); udev_unref(udev); } void MImHwKeyboardTrackerPrivate::evdevEvent() { // Parse the evdev event and look for SW_TABLET_MODE status. struct input_event ev; qint64 len = evdevFile->read((char *) &ev, sizeof(ev)); if (len != sizeof(ev)) return; // We wait for a SYN before "committing" the new state, just in case. if (ev.type == EV_SW && ev.code == SW_TABLET_MODE) { evdevTabletModePending = ev.value; } else if (ev.type == EV_SYN && ev.code == SYN_REPORT && evdevTabletModePending != -1) { evdevTabletMode = evdevTabletModePending; evdevTabletModePending = -1; Q_EMIT stateChanged(); } } void MImHwKeyboardTrackerPrivate::tryEvdevDevice(const char *device) { QFile *qfile = new QFile(this); unsigned char evbits[BITS2BYTES(EV_MAX)]; int fd; qfile->setFileName(device); if (!qfile->open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { delete qfile; return; } fd = qfile->handle(); if (fd == -1) { delete qfile; return; } if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evbits) < 0) { delete qfile; return; } // Check that this input device has switches if (!TEST_BIT(EV_SW, evbits)) { delete qfile; return; } unsigned char swbit[BITS2BYTES(EV_MAX)]; if (ioctl(fd, EVIOCGBIT(EV_SW, SW_CNT), swbit) < 0) { delete qfile; return; } // Check that there is a tablet mode switch here if (!TEST_BIT(SW_TABLET_MODE, swbit)) { delete qfile; return; } // Found an appropriate device - start monitoring it QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, qfile); sn->setEnabled(true); QObject::connect(sn, SIGNAL(activated(int)), this, SLOT(evdevEvent())); evdevFile = qfile; present = true; // Initialise initial tablet mode state unsigned long state[BITS2BYTES(SW_MAX)]; if (ioctl(fd, EVIOCGSW(SW_MAX), state) < 0) return; evdevTabletMode = TEST_BIT(SW_TABLET_MODE, state); } MImHwKeyboardTrackerPrivate::~MImHwKeyboardTrackerPrivate() { } MImHwKeyboardTracker::MImHwKeyboardTracker() : QObject(), d_ptr(new MImHwKeyboardTrackerPrivate(this)) { } MImHwKeyboardTracker::~MImHwKeyboardTracker() { } bool MImHwKeyboardTracker::isPresent() const { Q_D(const MImHwKeyboardTracker); return d->present; } bool MImHwKeyboardTracker::isOpen() const { Q_D(const MImHwKeyboardTracker); if (!d->present) { return false; } #ifdef HAVE_CONTEXTSUBSCRIBER return d->keyboardOpenProperty->value().toBool(); #elif defined(Q_WS_MAEMO_5) return d->keyboardOpenConf.value().toBool(); #else // If we found a talet mode switch, we report that the hardware keyboard // is available when the system is not in tablet mode (switch closed), // and is not available otherwise (switch open). if (d->evdevFile) return !d->evdevTabletMode; return false; #endif } maliit-framework-0.99.1+git20151118+62bd54b/src/mimhwkeyboardtracker.h000066400000000000000000000033221262307254400247150ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ // This file is based on mkeyboardstatetracker.h from libmeegotouch #ifndef MIMKEYBOARDSTATETRACKER_H #define MIMKEYBOARDSTATETRACKER_H #include #include class MImHwKeyboardTrackerPrivate; //! \internal /*! \ingroup maliitserver * \brief Class responsible for tracking the hardware keyboard properties and * signaling events. * * Singleton class. Using isPresent() queries whether the device supports * hardware keyboard or not. If hardware keyboard is supported, using isOpen() * to query its current state. Signal stateChanged will be emitted when the * hardware keyboard state is changed. */ class MImHwKeyboardTracker : public QObject { Q_OBJECT public: MImHwKeyboardTracker(); virtual ~MImHwKeyboardTracker(); //! \brief Returns whether device has a hardware keyboard. bool isPresent() const; //! \brief Returns whether hardware keyboard is opened. bool isOpen() const; Q_SIGNALS: //! \brief Emitted whenever the hardware keyboard state changed. void stateChanged(); private: const QScopedPointer d_ptr; Q_DISABLE_COPY(MImHwKeyboardTracker) Q_DECLARE_PRIVATE(MImHwKeyboardTracker) }; //! \internal_end #endif // MIMKEYBOARDSTATETRACKER_H maliit-framework-0.99.1+git20151118+62bd54b/src/mimhwkeyboardtracker_p.h000066400000000000000000000026471262307254400252450ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ // This file is based on mkeyboardstatetracker_p.h from libmeegotouch #ifndef MIMHWKEYBOARDTRACKER_P_H #define MIMHWKEYBOARDTRACKER_P_H #include #ifdef HAVE_CONTEXTSUBSCRIBER #include #include #else # ifdef Q_WS_MAEMO_5 # include "mimsettings.h" # endif #endif class MImHwKeyboardTracker; class MImHwKeyboardTrackerPrivate : public QObject { Q_OBJECT public: explicit MImHwKeyboardTrackerPrivate(MImHwKeyboardTracker *q_ptr); ~MImHwKeyboardTrackerPrivate(); void detectEvdev(); void tryEvdevDevice(const char *device); #ifdef HAVE_CONTEXTSUBSCRIBER QScopedPointer keyboardOpenProperty; #elif defined(Q_WS_MAEMO_5) MImSettings keyboardOpenConf; #endif QFile *evdevFile; int evdevTabletModePending; bool evdevTabletMode; bool present; public Q_SLOTS: void evdevEvent(); Q_SIGNALS: void stateChanged(); }; #endif // MIMHWKEYBOARDTRACKER_P_H maliit-framework-0.99.1+git20151118+62bd54b/src/mimhwkeyboardtracker_stub.cpp000066400000000000000000000016171262307254400263120ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Gianni Valdambrini * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimhwkeyboardtracker.h" class MImHwKeyboardTrackerPrivate : public QObject { public: explicit MImHwKeyboardTrackerPrivate(); }; MImHwKeyboardTrackerPrivate::MImHwKeyboardTrackerPrivate() { } MImHwKeyboardTracker::MImHwKeyboardTracker() : QObject(), d_ptr(new MImHwKeyboardTrackerPrivate) { } MImHwKeyboardTracker::~MImHwKeyboardTracker() { } bool MImHwKeyboardTracker::isPresent() const { return false; } bool MImHwKeyboardTracker::isOpen() const { return false; } maliit-framework-0.99.1+git20151118+62bd54b/src/mimonscreenplugins.cpp000066400000000000000000000233521262307254400247600ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimonscreenplugins.h" #include "config.h" #include #include #include #include #include #include using namespace std::tr1::placeholders; namespace { const char * const EnabledSubViews = MALIIT_CONFIG_ROOT"onscreen/enabled"; const char * const ActiveSubView = MALIIT_CONFIG_ROOT"onscreen/active"; bool equalPlugin(const MImOnScreenPlugins::SubView &subView, const QString &plugin) { return subView.plugin == plugin; } bool notEqualPlugin(const MImOnScreenPlugins::SubView &subView, const QString &plugin) { return subView.plugin != plugin; } QStringList toSettings(const QList &subViews) { QStringList result; Q_FOREACH(const MImOnScreenPlugins::SubView &subView, subViews) { result.push_back(subView.plugin + ":" + subView.id); } return result; } QList fromSettings(const QStringList& list) { QList result; Q_FOREACH (const QString &value, list) { QString plugin = value.section(':', 0, 0); QString subview = value.section(':', 1, -1); result.push_back(MImOnScreenPlugins::SubView(plugin, subview)); } return result; } QSet findEnabledPlugins(const QList &enabledSubViews) { QSet result; Q_FOREACH (const MImOnScreenPlugins::SubView &subView, enabledSubViews) { result.insert(subView.plugin); } return result; } } MImOnScreenPlugins::SubView::SubView() : plugin() , id() {} MImOnScreenPlugins::SubView::SubView(const QString &new_plugin, const QString &new_id) : plugin(new_plugin) , id(new_id) {} bool MImOnScreenPlugins::SubView::operator==(const MImOnScreenPlugins::SubView &other) const { return (plugin == other.plugin && id == other.id); } MImOnScreenPlugins::MImOnScreenPlugins(): QObject(), mAvailableSubViews(), mEnabledSubViews(), mLastEnabledSubViews(), mActiveSubView(), mEnabledSubViewsSettings(EnabledSubViews), mActiveSubViewSettings(ActiveSubView), mAllSubviewsEnabled(false) { connect(&mEnabledSubViewsSettings, SIGNAL(valueChanged()), this, SLOT(updateEnabledSubviews())); connect(&mActiveSubViewSettings, SIGNAL(valueChanged()), this, SLOT(updateActiveSubview())); updateEnabledSubviews(); updateActiveSubview(); } bool MImOnScreenPlugins::isEnabled(const QString &plugin) const { QList mEnabledAndAvailableSubViews; std::remove_copy_if(mEnabledSubViews.begin(), mEnabledSubViews.end(), std::back_inserter(mEnabledAndAvailableSubViews), std::tr1::bind(&MImOnScreenPlugins::isSubViewUnavailable, this, _1)); return std::find_if(mEnabledAndAvailableSubViews.begin(), mEnabledAndAvailableSubViews.end(), std::tr1::bind(equalPlugin, _1, plugin)) != mEnabledAndAvailableSubViews.end(); } bool MImOnScreenPlugins::isSubViewEnabled(const SubView &subView) const { return mEnabledSubViews.contains(subView); } QList MImOnScreenPlugins::enabledSubViews() const { return mEnabledSubViews; } QList MImOnScreenPlugins::enabledSubViews(const QString &plugin) const { QList result; std::remove_copy_if(mEnabledSubViews.begin(), mEnabledSubViews.end(), std::back_inserter(result), std::tr1::bind(notEqualPlugin, _1, plugin)); return result; } void MImOnScreenPlugins::setEnabledSubViews(const QList &subViews) { mEnabledSubViewsSettings.set(QVariant(toSettings(subViews))); } void MImOnScreenPlugins::setAutoEnabledSubViews(const QList &subViews) { // Update the enabled subviews list without saving the configuration to disk mEnabledSubViews = subViews; } void MImOnScreenPlugins::updateAvailableSubViews(const QList &availableSubViews) { mAvailableSubViews = availableSubViews; autoDetectActiveSubView(); } bool MImOnScreenPlugins::isSubViewAvailable(const SubView &subview) const { return mAvailableSubViews.contains(subview); } bool MImOnScreenPlugins::isSubViewUnavailable(const SubView &subview) const { return !mAvailableSubViews.contains(subview); } void MImOnScreenPlugins::updateEnabledSubviews() { const QStringList &list = mEnabledSubViewsSettings.value().toStringList(); const QList oldEnabledSubviews = mEnabledSubViews; mEnabledSubViews = fromSettings(list); // Changed subviews cause emission of enabledPluginsChanged() signal // because some subview from the setting might not really exists and therefore // changed subview might have implications to enabled plugins. if (mEnabledSubViews != oldEnabledSubviews) { Q_EMIT enabledPluginsChanged(); } } void MImOnScreenPlugins::updateActiveSubview() { const QString &active = mActiveSubViewSettings.value().toString(); if (active.isEmpty()) { mActiveSubView = MImOnScreenPlugins::SubView(MALIIT_DEFAULT_PLUGIN); return; } const QList &activeList = fromSettings(QStringList() << active); const MImOnScreenPlugins::SubView &subView = activeList.first(); if (mActiveSubView == subView) { return; } setAutoActiveSubView(subView); } const MImOnScreenPlugins::SubView MImOnScreenPlugins::activeSubView() { return mActiveSubView; } void MImOnScreenPlugins::setActiveSubView(const MImOnScreenPlugins::SubView &subView) { if (mActiveSubView == subView) return; mActiveSubView = subView; QList subViews; subViews << subView; mActiveSubViewSettings.set(toSettings(subViews)); Q_EMIT activeSubViewChanged(); } void MImOnScreenPlugins::setAutoActiveSubView(const MImOnScreenPlugins::SubView &subView) { // Update the active subview without writing the configuration to disk if (mActiveSubView == subView) return; mActiveSubView = subView; Q_EMIT activeSubViewChanged(); } void MImOnScreenPlugins::setAllSubViewsEnabled(bool enable) { if (mAllSubviewsEnabled != enable) { mAllSubviewsEnabled = enable; if (mAllSubviewsEnabled) { mLastEnabledSubViews = mEnabledSubViews; } else { if (not mLastEnabledSubViews.contains(mActiveSubView)) { mLastEnabledSubViews.append(mActiveSubView); } } setEnabledSubViews(mAllSubviewsEnabled ? mAvailableSubViews : mLastEnabledSubViews); } } void MImOnScreenPlugins::autoDetectActiveSubView() { // If no subviews are enabled by the configuration, try to auto-detect // them. if (enabledSubViews().empty()) { autoDetectEnabledSubViews(); } // If we still don't have an enabled subview, enable the first available // one. if (enabledSubViews().empty()) { MImOnScreenPlugins::SubView subView = mAvailableSubViews.first(); setAutoEnabledSubViews(QList() << subView); } // If we have an active subview in the configuration, check that it is // enabled // If we don't have an active subview, auto-activate the first enabled // one. if (mActiveSubView.id.isEmpty() || !isSubViewEnabled(mActiveSubView)) { MImOnScreenPlugins::SubView subView = enabledSubViews().first(); setAutoActiveSubView(subView); } } void MImOnScreenPlugins::autoDetectEnabledSubViews() { const QString &plugin = mActiveSubView.plugin; QList to_enable; // Try to auto-detect subviews for the selected plugin by looking for // subviews that coincide with the languages selected for use on the // system. // FIXME: This works for the keyboard plugin, but won't work everywhere. // The methodology for auto-configuring subviews should be somehow // plugin-dictated. QStringList langs = QLocale::system().uiLanguages(); Q_FOREACH (QString lang, langs) { // Convert to lower case, remove any .utf8 suffix, and use _ as // the separator between language and country. lang = lang.split('.')[0].toLower().replace("-", "_"); MImOnScreenPlugins::SubView subView(plugin, lang); // First try the language code as-is if (isSubViewAvailable(subView) && !to_enable.contains(subView)) { to_enable << subView; continue; } // See if we get a match if we expand "de" to "de_de" if (!lang.contains('_')) { subView.id = lang + "_" + lang; if (isSubViewAvailable(subView) && !to_enable.contains(subView)) { to_enable << subView; } continue; } // See if we get a match if we trim "de_at" to "de" subView.id = lang.split("_").first(); if (isSubViewAvailable(subView) && !to_enable.contains(subView)) { to_enable << subView; } } if (!to_enable.isEmpty()) { setAutoEnabledSubViews(to_enable); } } maliit-framework-0.99.1+git20151118+62bd54b/src/mimonscreenplugins.h000066400000000000000000000047531262307254400244310ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMONSCREENPLUGINS_H #define MIMONSCREENPLUGINS_H #include #include #include #include #include #include "mimsettings.h" /*! \ingroup maliitserver * \brief Check the current status of plugins for a subview. */ class MImOnScreenPlugins: public QObject { Q_OBJECT public: class SubView { public: QString plugin; QString id; explicit SubView(); explicit SubView(const QString &new_plugin, const QString &new_id = NULL); bool operator==(const SubView &other) const; }; explicit MImOnScreenPlugins(); bool isEnabled(const QString &plugin) const; QList enabledSubViews(const QString &plugin) const; QList enabledSubViews() const; bool isSubViewEnabled(const SubView &subview) const; void setEnabledSubViews(const QList &subViews); void setAutoEnabledSubViews(const QList &subViews); void updateAvailableSubViews(const QList &availableSubViews); bool isSubViewAvailable(const SubView &subview) const; bool isSubViewUnavailable(const SubView &subview) const; const SubView activeSubView(); void setActiveSubView(const SubView &subView); void setAutoActiveSubView(const SubView &subView); void setAllSubViewsEnabled(bool enable); Q_SIGNALS: void activeSubViewChanged(); void enabledPluginsChanged(); private Q_SLOTS: void updateEnabledSubviews(); void updateActiveSubview(); private: void autoDetectActiveSubView(); void autoDetectEnabledSubViews(); private: QList mAvailableSubViews; QList mEnabledSubViews; QList mLastEnabledSubViews; SubView mActiveSubView; MImSettings mEnabledSubViewsSettings; MImSettings mActiveSubViewSettings; QSet enabledPlugins; //should be updated when mEnabledSubViews is changed bool mAllSubviewsEnabled; }; Q_DECLARE_METATYPE(MImOnScreenPlugins::SubView) #endif // MIMENABLEDPLUGINS_H maliit-framework-0.99.1+git20151118+62bd54b/src/mimpluginmanager.cpp000066400000000000000000001612331262307254400243740ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * Copyright (C) 2012 Canonical Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimpluginmanager.h" #include "mimpluginmanager_p.h" #include #include "mattributeextensionmanager.h" #include "msharedattributeextensionmanager.h" #include #include "mimsettings.h" #include "mimhwkeyboardtracker.h" #include #include "mimsubviewoverride.h" #include "maliit/namespaceinternal.h" #include #include "windowgroup.h" #include #include #include #include #include #include #include namespace { const QString DefaultPluginLocation(MALIIT_PLUGINS_DIR); const char * const VisualizationAttribute = "visualizationPriority"; const char * const FocusStateAttribute = "focusState"; const QString ConfigRoot = MALIIT_CONFIG_ROOT; const QString MImPluginPaths = ConfigRoot + "paths"; const QString MImPluginDisabled = ConfigRoot + "disabledpluginfiles"; const QString PluginRoot = MALIIT_CONFIG_ROOT"plugins"; const QString PluginSettings = MALIIT_CONFIG_ROOT"pluginsettings"; const QString MImAccesoryEnabled = MALIIT_CONFIG_ROOT"accessoryenabled"; const char * const InputMethodItem = "inputMethod"; const char * const LoadAll = "loadAll"; } MIMPluginManagerPrivate::MIMPluginManagerPrivate(const QSharedPointer &connection, const QSharedPointer &platform, MIMPluginManager *p) : parent(p), mICConnection(connection), imAccessoryEnabledConf(0), q_ptr(0), visible(false), onScreenPlugins(), lastOrientation(0), attributeExtensionManager(new MAttributeExtensionManager), sharedAttributeExtensionManager(new MSharedAttributeExtensionManager), m_platform(platform) { inputSourceToNameMap[Maliit::Hardware] = "hardware"; inputSourceToNameMap[Maliit::Accessory] = "accessory"; } MIMPluginManagerPrivate::~MIMPluginManagerPrivate() { qDeleteAll(handlerToPluginConfs); } void MIMPluginManagerPrivate::loadPlugins() { Q_Q(MIMPluginManager); MImOnScreenPlugins::SubView activeSubView = onScreenPlugins.activeSubView(); // Load active plugin first Q_FOREACH (QString path, paths) { const QDir &dir(path); if (loadPlugin(dir, activeSubView.plugin)) break; } // Load all other plugins Q_FOREACH (QString path, paths) { const QDir &dir(path); QStringList pluginFiles = dir.entryList(QDir::Files); Q_FOREACH (const QString &fileName, pluginFiles) { if (fileName == activeSubView.plugin) continue; loadPlugin(dir, fileName); } // end Q_FOREACH file in path } // end Q_FOREACH path in paths if (plugins.empty()) { qWarning("No plugins were found. Stopping."); std::exit(0); } const QList &availableSubViews = availablePluginsAndSubViews(); onScreenPlugins.updateAvailableSubViews(availableSubViews); Q_EMIT q->pluginsChanged(); } bool MIMPluginManagerPrivate::loadPlugin(const QDir &dir, const QString &fileName) { Q_Q(MIMPluginManager); if (blacklist.contains(fileName)) { qWarning() << __PRETTY_FUNCTION__ << fileName << "is on the blacklist, skipped."; return false; } Maliit::Plugins::InputMethodPlugin *plugin = 0; if (QFileInfo(fileName).suffix() == "qml") { plugin = new Maliit::InputMethodQuickPlugin(dir.filePath(fileName), m_platform); if (!plugin) { qWarning() << __PRETTY_FUNCTION__ << "Could not create a plugin for: " << fileName; } } else { // TODO: skip already loaded plugin ids (fileName) QPluginLoader load(dir.absoluteFilePath(fileName)); QObject *pluginInstance = load.instance(); if (!pluginInstance) { qWarning() << __PRETTY_FUNCTION__ << "Error loading plugin from" << dir.absoluteFilePath(fileName) << load.errorString(); return false; } plugin = qobject_cast(pluginInstance); if (!plugin) { qWarning() << __PRETTY_FUNCTION__ << pluginInstance->metaObject()->className() << "is not a Maliit::Server::InputMethodPlugin."; return false; } } if (plugin->supportedStates().isEmpty()) { qWarning() << __PRETTY_FUNCTION__ << "Plugin does not support any state." << plugin->name() << dir.absoluteFilePath(fileName); return false; } QSharedPointer windowGroup(new Maliit::WindowGroup(m_platform)); MInputMethodHost *host = new MInputMethodHost(mICConnection, q, windowGroup, fileName, plugin->name()); MAbstractInputMethod *im = plugin->createInputMethod(host); QObject::connect(q, SIGNAL(pluginsChanged()), host, SIGNAL(pluginsChanged())); // only add valid plugin descriptions if (!im) { qWarning() << __PRETTY_FUNCTION__ << "Creation of InputMethod failed:" << plugin->name() << dir.absoluteFilePath(fileName); delete host; return false; } PluginDescription desc = { im, host, PluginState(), Maliit::SwitchUndefined, fileName, windowGroup }; // Connect surface group signals QObject::connect(windowGroup.data(), SIGNAL(inputMethodAreaChanged(QRegion)), mICConnection.data(), SLOT(updateInputMethodArea(QRegion))); plugins.insert(plugin, desc); host->setInputMethod(im); Q_EMIT q->pluginLoaded(); return true; } void MIMPluginManagerPrivate::activatePlugin(Maliit::Plugins::InputMethodPlugin *plugin) { Q_Q(MIMPluginManager); if (!plugin || activePlugins.contains(plugin)) { return; } MAbstractInputMethod *inputMethod = 0; activePlugins.insert(plugin); inputMethod = plugins.value(plugin).inputMethod; plugins.value(plugin).imHost->setEnabled(true); Q_ASSERT(inputMethod); QObject::connect(inputMethod, SIGNAL(activeSubViewChanged(QString, Maliit::HandlerState)), q, SLOT(_q_setActiveSubView(QString, Maliit::HandlerState))); inputMethod->handleAppOrientationChanged(lastOrientation); targets.insert(inputMethod); } void MIMPluginManagerPrivate::addHandlerMap(Maliit::HandlerState state, const QString &pluginId) { Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, plugins.keys()) { if (plugins.value(plugin).pluginId == pluginId) { handlerToPlugin[state] = plugin; return; } } qWarning() << __PRETTY_FUNCTION__ << "Could not find plugin:" << pluginId; } MImPluginSettingsInfo MIMPluginManagerPrivate::globalSettings() const { QStringList domain, descriptions; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, plugins.keys()) { const MIMPluginManagerPrivate::PluginDescription &descr = plugins[plugin]; QList subviews = descr.inputMethod->subViews(); Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &subview, subviews) { domain.append(descr.pluginId + ":" + subview.subViewId); descriptions.append(plugin->name() + " - " + subview.subViewTitle); } } MImPluginSettingsEntry active_subviews; active_subviews.extension_key = MALIIT_CONFIG_ROOT"onscreen/active"; active_subviews.description = QT_TRANSLATE_NOOP("maliit", "Active subview"); active_subviews.type = Maliit::StringType; active_subviews.attributes[Maliit::SettingEntryAttributes::valueDomain] = domain; active_subviews.attributes[Maliit::SettingEntryAttributes::valueDomainDescriptions] = descriptions; MImPluginSettingsEntry enabled_subviews; enabled_subviews.extension_key = MALIIT_CONFIG_ROOT"onscreen/enabled"; enabled_subviews.description = QT_TRANSLATE_NOOP("maliit", "Enabled subviews"); enabled_subviews.type = Maliit::StringListType; enabled_subviews.attributes[Maliit::SettingEntryAttributes::valueDomain] = domain; enabled_subviews.attributes[Maliit::SettingEntryAttributes::valueDomainDescriptions] = descriptions; MImPluginSettingsInfo global; global.plugin_description = QT_TRANSLATE_NOOP("maliit", "Global"); global.plugin_name = "server"; global.extension_id = MSharedAttributeExtensionManager::PluginSettings; global.entries.append(active_subviews); global.entries.append(enabled_subviews); return global; } void MIMPluginManagerPrivate::registerSettings() { // not exposed to final user, merely used to listen for settings list changes MImPluginSettingsInfo settings_list; settings_list.plugin_name = "@settings"; settings_list.extension_id = MSharedAttributeExtensionManager::PluginSettingsList; registerSettings(settings_list); // global settings registerSettings(globalSettings()); } void MIMPluginManagerPrivate::registerSettings(const MImPluginSettingsInfo &info) { bool found = false; for (int i = 0; i < settings.size(); ++i) { if (settings[i].plugin_name == info.plugin_name) { found = true; settings[i].entries.append(info.entries); break; } } // No setting info for this plugin yet: add the whole entry if (!found) { settings.append(info); } Q_FOREACH (const MImPluginSettingsEntry &entry, info.entries) { sharedAttributeExtensionManager->registerPluginSetting(entry.extension_key, entry.type, entry.attributes); } } void MIMPluginManagerPrivate::setActiveHandlers(const QSet &states) { QSet activatedPlugins; MAbstractInputMethod *inputMethod = 0; //clear all cached states before activating new one for (Plugins::iterator iterator = plugins.begin(); iterator != plugins.end(); ++iterator) { iterator->state.clear(); } //activate new plugins Q_FOREACH (Maliit::HandlerState state, states) { HandlerMap::const_iterator iterator = handlerToPlugin.find(state); Maliit::Plugins::InputMethodPlugin *plugin = 0; if (iterator != handlerToPlugin.end()) { plugin = iterator.value(); if (!activePlugins.contains(plugin)) { activatePlugin(plugin); } inputMethod = plugins.value(plugin).inputMethod; if (plugin && inputMethod) { plugins[plugin].state << state; activatedPlugins.insert(plugin); } } } // notify plugins about new states Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, activatedPlugins) { PluginDescription desc = plugins.value(plugin); desc.inputMethod->setState(desc.state); if (visible) { desc.windowGroup->activate(); desc.inputMethod->show(); } } // deactivate unnecessary plugins QSet previousActive = activePlugins; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, previousActive) { if (!activatedPlugins.contains(plugin)) { deactivatePlugin(plugin); //activePlugins is modified here } } } QSet MIMPluginManagerPrivate::activeHandlers() const { QSet handlers; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, activePlugins) { handlers << handlerToPlugin.key(plugin); } return handlers; } void MIMPluginManagerPrivate::deactivatePlugin(Maliit::Plugins::InputMethodPlugin *plugin) { Q_Q(MIMPluginManager); if (!plugin || !activePlugins.contains(plugin)) { return; } MAbstractInputMethod *inputMethod = 0; activePlugins.remove(plugin); inputMethod = plugins.value(plugin).inputMethod; Q_ASSERT(inputMethod); inputMethod->hide(); inputMethod->reset(); // this call disables normal behaviour on inputMethod->hide plugins.value(plugin).imHost->setEnabled(false); plugins[plugin].state = PluginState(); QObject::disconnect(inputMethod, 0, q, 0); targets.remove(inputMethod); } void MIMPluginManagerPrivate::replacePlugin(Maliit::SwitchDirection direction, Maliit::Plugins::InputMethodPlugin *source, Plugins::iterator replacement, const QString &subViewId) { PluginState state; if (source) state = plugins.value(source).state; else state << Maliit::OnScreen; MAbstractInputMethod *switchedTo = 0; deactivatePlugin(source); activatePlugin(replacement.key()); switchedTo = replacement->inputMethod; replacement->state = state; switchedTo->setState(state); if (state.contains(Maliit::OnScreen) && !subViewId.isNull()) { switchedTo->setActiveSubView(subViewId); } else if (replacement->lastSwitchDirection == direction || (replacement->lastSwitchDirection == Maliit::SwitchUndefined && direction == Maliit::SwitchBackward)) { // we should enforce plugin to switch context if one of following conditions is true: // 1) if we have plugin A and B, and subviews A.0, A.1, A.2 and B.0, and B.0 is active, // and A.2 was active before B.0, then if we switch forward to plugin A, we want to start with subview A.0, not A.2 // 2) if we have plugin A and B, and subviews A.0, A.1, A.2 and B.0, and B.0 is active, // and plugin A was not active since start of meego-im-uiserver, // then if we switch back to plugin A, we want to start with subview A.2, not A.0 switchedTo->switchContext(direction, false); } if (source) { plugins[source].lastSwitchDirection = direction; } QMap > keyOverrides = attributeExtensionManager->keyOverrides(toolbarId); switchedTo->setKeyOverrides(keyOverrides); if (visible) { ensureActivePluginsVisible(DontShowInputMethod); switchedTo->show(); switchedTo->showLanguageNotification(); } if (state.contains(Maliit::OnScreen)) { if (activeSubViewIdOnScreen != switchedTo->activeSubView(Maliit::OnScreen)) { // activeSubViewIdOnScreen is invalid, should be initialized. activeSubViewIdOnScreen = switchedTo->activeSubView(Maliit::OnScreen); } // Save the last active subview onScreenPlugins.setActiveSubView(MImOnScreenPlugins::SubView(replacement->pluginId, activeSubViewIdOnScreen)); } } bool MIMPluginManagerPrivate::switchPlugin(Maliit::SwitchDirection direction, MAbstractInputMethod *initiator) { if (direction != Maliit::SwitchForward && direction != Maliit::SwitchBackward) { return true; //do nothing for this direction } //Find plugin initiated this switch Plugins::iterator iterator(plugins.begin()); for (; iterator != plugins.end(); ++iterator) { if (iterator->inputMethod == initiator) { break; } } if (iterator == plugins.end()) { return false; } Plugins::iterator source = iterator; //find next inactive plugin and activate it for (int n = 0; n < plugins.size() - 1; ++n) { if (direction == Maliit::SwitchForward) { ++iterator; if (iterator == plugins.end()) { iterator = plugins.begin(); } } else if (direction == Maliit::SwitchBackward) { // Backward if (iterator == plugins.begin()) { iterator = plugins.end(); } --iterator; } if (trySwitchPlugin(direction, source.key(), iterator)) { return true; } } return false; } bool MIMPluginManagerPrivate::switchPlugin(const QString &pluginId, MAbstractInputMethod *initiator, const QString &subViewId) { //Find plugin initiated this switch Plugins::iterator iterator(plugins.begin()); for (; iterator != plugins.end(); ++iterator) { if (iterator->inputMethod == initiator) { break; } } Plugins::iterator source = iterator; // find plugin specified by name for (iterator = plugins.begin(); iterator != plugins.end(); ++iterator) { if (plugins.value(iterator.key()).pluginId == pluginId) { break; } } if (iterator == plugins.end()) { qWarning() << __PRETTY_FUNCTION__ << pluginId << "could not be found"; return false; } if (source == iterator) { return true; } if (source == plugins.end()) { qDebug() << __PRETTY_FUNCTION__ << pluginId << "could not find initiator"; return trySwitchPlugin(Maliit::SwitchUndefined, 0, iterator, subViewId); } return trySwitchPlugin(Maliit::SwitchUndefined, source.key(), iterator, subViewId); } bool MIMPluginManagerPrivate::trySwitchPlugin(Maliit::SwitchDirection direction, Maliit::Plugins::InputMethodPlugin *source, Plugins::iterator replacement, const QString &subViewId) { Maliit::Plugins::InputMethodPlugin *newPlugin = replacement.key(); if (activePlugins.contains(newPlugin)) { qDebug() << __PRETTY_FUNCTION__ << plugins.value(newPlugin).pluginId << "is already active"; return false; } if (!newPlugin) { qWarning() << __PRETTY_FUNCTION__ << "new plugin invalid"; return false; } // switch to other plugin if it could handle any state // handled by current plugin just now PluginState currentState; if (source) { currentState = plugins.value(source).state; } const PluginState &supportedStates = newPlugin->supportedStates(); if (!supportedStates.contains(currentState)) { qDebug() << __PRETTY_FUNCTION__ << plugins.value(newPlugin).pluginId << "does not contain state"; return false; } if (plugins.value(source).state.contains(Maliit::OnScreen)) { // if plugin which is to be switched needs to support OnScreen, the subviews should not be empty. if (!onScreenPlugins.isEnabled(plugins.value(newPlugin).pluginId)) { qDebug() << __PRETTY_FUNCTION__ << plugins.value(newPlugin).pluginId << "not enabled"; return false; } } changeHandlerMap(source, newPlugin, newPlugin->supportedStates()); replacePlugin(direction, source, replacement, subViewId); return true; } QString MIMPluginManagerPrivate::inputSourceName(Maliit::HandlerState source) const { return inputSourceToNameMap.value(source); } void MIMPluginManagerPrivate::changeHandlerMap(Maliit::Plugins::InputMethodPlugin *origin, Maliit::Plugins::InputMethodPlugin *replacement, QSet states) { Q_FOREACH (Maliit::HandlerState state, states) { if (state == Maliit::OnScreen) { continue; } HandlerMap::iterator iterator = handlerToPlugin.find(state); if (iterator != handlerToPlugin.end() && *iterator == origin) { *iterator = replacement; //for unit tests // Update settings entry to record new plugin for handler map. // This should be done after real changing the handler map, // to prevent _q_syncHandlerMap also being called to change handler map. MImSettings setting(PluginRoot + "/" + inputSourceName(state)); setting.set(plugins.value(replacement).pluginId); } } } QStringList MIMPluginManagerPrivate::loadedPluginsNames() const { QStringList result; Q_FOREACH (const PluginDescription &desc, plugins.values()) { result.append(desc.pluginId); } return result; } QStringList MIMPluginManagerPrivate::loadedPluginsNames(Maliit::HandlerState state) const { QStringList result; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, plugins.keys()) { if (plugin->supportedStates().contains(state)) result.append(plugins.value(plugin).pluginId); } return result; } QList MIMPluginManagerPrivate::pluginDescriptions(Maliit::HandlerState state) const { QList result; const Plugins::const_iterator end = plugins.constEnd(); for (Plugins::const_iterator iterator(plugins.constBegin()); iterator != end; ++iterator) { const Maliit::Plugins::InputMethodPlugin * const plugin = iterator.key(); if (plugin && plugin->supportedStates().contains(state)) { result.append(MImPluginDescription(*plugin)); if (state == Maliit::OnScreen) { result.last().setEnabled(onScreenPlugins.isEnabled(iterator->pluginId)); } } } return result; } MIMPluginManagerPrivate::Plugins::const_iterator MIMPluginManagerPrivate::findEnabledPlugin(Plugins::const_iterator current, Maliit::SwitchDirection direction, Maliit::HandlerState state) const { MIMPluginManagerPrivate::Plugins::const_iterator iterator = current; MIMPluginManagerPrivate::Plugins::const_iterator result = plugins.constEnd(); for (int n = 0; n < plugins.size() - 1; ++n) { if (direction == Maliit::SwitchForward) { ++iterator; if (iterator == plugins.end()) { iterator = plugins.begin(); } } else if (direction == Maliit::SwitchBackward) { // Backward if (iterator == plugins.begin()) { iterator = plugins.end(); } --iterator; } Maliit::Plugins::InputMethodPlugin *otherPlugin = iterator.key(); Q_ASSERT(otherPlugin); const MIMPluginManagerPrivate::PluginState &supportedStates = otherPlugin->supportedStates(); if (!supportedStates.contains(state)) { continue; } if (state == Maliit::OnScreen && not onScreenPlugins.isEnabled(iterator->pluginId)) { continue; } result = iterator; break; } return result; } void MIMPluginManagerPrivate::filterEnabledSubViews(QMap &subViews, const QString &pluginId, Maliit::HandlerState state) const { QMap::iterator iterator = subViews.begin(); while(iterator != subViews.end()) { MImOnScreenPlugins::SubView subView(pluginId, iterator.key()); if (state != Maliit::OnScreen || onScreenPlugins.isSubViewEnabled(subView)) { ++iterator; } else { iterator = subViews.erase(iterator); } } } void MIMPluginManagerPrivate::append(QList &list, const QMap &map, const QString &pluginId) const { for(QMap::const_iterator iterator = map.constBegin(); iterator != map.constEnd(); ++iterator) { MImSubViewDescription desc(pluginId, iterator.key(), iterator.value()); list.append(desc); } } QList MIMPluginManagerPrivate::surroundingSubViewDescriptions(Maliit::HandlerState state) const { QList result; Maliit::Plugins::InputMethodPlugin *plugin = activePlugin(state); if (!plugin) { return result; } Plugins::const_iterator iterator = plugins.find(plugin); Q_ASSERT(iterator != plugins.constEnd()); QString pluginId = iterator->pluginId; QString subViewId = iterator->inputMethod->activeSubView(state); QMap subViews = availableSubViews(pluginId, state); filterEnabledSubViews(subViews, pluginId, state); if (plugins.size() == 1 && subViews.size() == 1) { // there is one subview only return result; } QList enabledSubViews; Plugins::const_iterator otherPlugin; otherPlugin = findEnabledPlugin(iterator, Maliit::SwitchBackward, state); if (otherPlugin != plugins.constEnd()) { QMap prevSubViews = availableSubViews(otherPlugin->pluginId); filterEnabledSubViews(prevSubViews, otherPlugin->pluginId, state); append(enabledSubViews, prevSubViews, otherPlugin->pluginId); } append(enabledSubViews, subViews, pluginId); otherPlugin = findEnabledPlugin(iterator, Maliit::SwitchForward, state); if (otherPlugin != plugins.constEnd()) { QMap prevSubViews = availableSubViews(otherPlugin->pluginId); filterEnabledSubViews(prevSubViews, otherPlugin->pluginId, state); append(enabledSubViews, prevSubViews, otherPlugin->pluginId); } if (enabledSubViews.size() == 1) { return result; //there is no other enabled subview } const QMap::const_iterator subViewIterator = subViews.find(subViewId); if (subViewIterator == subViews.constEnd()) { return result; } MImSubViewDescription current(pluginId, subViewId, *subViewIterator); const int index = enabledSubViews.indexOf(current); Q_ASSERT(index >= 0); const int prevIndex = index > 0 ? index - 1 : enabledSubViews.size() - 1; result.append(enabledSubViews.at(prevIndex)); const int nextIndex = index < (enabledSubViews.size() - 1) ? index + 1 : 0; result.append(enabledSubViews.at(nextIndex)); return result; } QStringList MIMPluginManagerPrivate::activePluginsNames() const { QStringList result; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, activePlugins) { result.append(plugins.value(plugin).pluginId); } return result; } QString MIMPluginManagerPrivate::activePluginsName(Maliit::HandlerState state) const { Maliit::Plugins::InputMethodPlugin *plugin = activePlugin(state); if (!plugin) return QString(); return plugins.value(plugin).pluginId; } void MIMPluginManagerPrivate::loadHandlerMap() { Q_Q(MIMPluginManager); QSignalMapper *signalMapper = new QSignalMapper(q); // Queries all children under PluginRoot, each is a setting entry that maps an // input source to a plugin that handles it const QStringList &handler(MImSettings(PluginRoot).listEntries()); InputSourceToNameMap::const_iterator end = inputSourceToNameMap.constEnd(); for (InputSourceToNameMap::const_iterator i(inputSourceToNameMap.constBegin()); i != end; ++i) { const QString &settingsKey(PluginRoot + "/" + i.value()); if (!handler.contains(settingsKey)) continue; MImSettings *handlerItem = new MImSettings(settingsKey); handlerToPluginConfs.append(handlerItem); const QString &pluginName = handlerItem->value().toString(); addHandlerMap(i.key(), pluginName); QObject::connect(handlerItem, SIGNAL(valueChanged()), signalMapper, SLOT(map())); signalMapper->setMapping(handlerItem, i.key()); } QObject::connect(signalMapper, SIGNAL(mapped(int)), q, SLOT(_q_syncHandlerMap(int))); } void MIMPluginManagerPrivate::_q_syncHandlerMap(int state) { const Maliit::HandlerState source = static_cast(state); Maliit::Plugins::InputMethodPlugin *currentPlugin = activePlugin(source); MImSettings setting(PluginRoot + "/" + inputSourceName(source)); const QString pluginId = setting.value().toString(); // already synchronized. if (currentPlugin && pluginId == plugins.value(currentPlugin).pluginId) { return; } Maliit::Plugins::InputMethodPlugin *replacement = 0; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, plugins.keys()) { if (plugins.value(plugin).pluginId == pluginId) { replacement = plugin; break; } } if (replacement) { // switch plugin if handler is changed. MAbstractInputMethod *inputMethod = plugins.value(currentPlugin).inputMethod; addHandlerMap(static_cast(state), pluginId); if (!switchPlugin(pluginId, inputMethod)) { qWarning() << __PRETTY_FUNCTION__ << ", switching to plugin:" << pluginId << " failed"; } } } void MIMPluginManagerPrivate::_q_onScreenSubViewChanged() { const MImOnScreenPlugins::SubView &subView = onScreenPlugins.activeSubView(); Maliit::Plugins::InputMethodPlugin *currentPlugin = activePlugin(Maliit::OnScreen); if (currentPlugin && subView.plugin == plugins.value(currentPlugin).pluginId && activePlugins.contains(currentPlugin)) { qDebug() << __PRETTY_FUNCTION__ << "just switch subview"; _q_setActiveSubView(subView.id, Maliit::OnScreen); return; } Maliit::Plugins::InputMethodPlugin *replacement = 0; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, plugins.keys()) { if (plugins.value(plugin).pluginId == subView.plugin) { replacement = plugin; break; } } if (replacement) { // switch plugin if handler is changed. MAbstractInputMethod *inputMethod = 0; if (activePlugins.contains(currentPlugin)) inputMethod = plugins.value(currentPlugin).inputMethod; addHandlerMap(Maliit::OnScreen, subView.plugin); if (!switchPlugin(subView.plugin, inputMethod, subView.id)) { qWarning() << __PRETTY_FUNCTION__ << ", switching to plugin:" << subView.plugin << " failed"; } } } Maliit::Plugins::InputMethodPlugin *MIMPluginManagerPrivate::activePlugin(Maliit::HandlerState state) const { Maliit::Plugins::InputMethodPlugin *plugin = 0; HandlerMap::const_iterator iterator = handlerToPlugin.find(state); if (iterator != handlerToPlugin.constEnd()) { plugin = iterator.value(); } return plugin; } void MIMPluginManagerPrivate::_q_setActiveSubView(const QString &subViewId, Maliit::HandlerState state) { // now we only support active subview for OnScreen state. if (state != Maliit::OnScreen) { qWarning() << "Unsupported state:" << state << " for active subview"; return; } if (subViewId.isEmpty()) { return; } Maliit::Plugins::InputMethodPlugin *plugin = activePlugin(Maliit::OnScreen); if (!plugin) { qDebug() << __PRETTY_FUNCTION__ << "No active plugin"; return; } // Check whether active plugin is matching const QString &activePluginId = plugins.value(plugin).pluginId; if (activePluginId != onScreenPlugins.activeSubView().plugin) { // TODO? qWarning() << __PRETTY_FUNCTION__ << plugins.value(plugin).pluginId << "!=" << onScreenPlugins.activeSubView().plugin; return; } // Check whether subView is enabled if (!onScreenPlugins.isSubViewEnabled(MImOnScreenPlugins::SubView(activePluginId, subViewId))) { qWarning() << __PRETTY_FUNCTION__ << activePluginId << subViewId << "is not enabled"; return; } // Check whether this subView is supported by current active plugin. MAbstractInputMethod *inputMethod = plugins.value(plugin).inputMethod; Q_ASSERT(inputMethod); if (!inputMethod) { qDebug() << __PRETTY_FUNCTION__ << "No input method"; return; } Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &subView, inputMethod->subViews(Maliit::OnScreen)) { if (subView.subViewId == subViewId) { activeSubViewIdOnScreen = subViewId; if (inputMethod->activeSubView(Maliit::OnScreen) != activeSubViewIdOnScreen) { inputMethod->setActiveSubView(activeSubViewIdOnScreen, Maliit::OnScreen); } // Save the last active subview if (onScreenPlugins.activeSubView().id != subViewId) { onScreenPlugins.setActiveSubView(MImOnScreenPlugins::SubView(activePluginId, subViewId)); } break; } } } void MIMPluginManagerPrivate::showActivePlugins() { visible = true; ensureActivePluginsVisible(ShowInputMethod); } void MIMPluginManagerPrivate::hideActivePlugins() { visible = false; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, activePlugins) { plugins.value(plugin).inputMethod->hide(); plugins.value(plugin).windowGroup->deactivate(Maliit::WindowGroup::HideDelayed); } } void MIMPluginManagerPrivate::ensureActivePluginsVisible(ShowInputMethodRequest request) { Plugins::iterator iterator(plugins.begin()); for (; iterator != plugins.end(); ++iterator) { if (activePlugins.contains(iterator.key())) { iterator.value().windowGroup->activate(); if (request == ShowInputMethod) { iterator.value().inputMethod->show(); } } else { iterator.value().windowGroup->deactivate(Maliit::WindowGroup::HideImmediate); } } } QMap MIMPluginManagerPrivate::availableSubViews(const QString &plugin, Maliit::HandlerState state) const { QMap subViews; Plugins::const_iterator iterator(plugins.constBegin()); for (; iterator != plugins.constEnd(); ++iterator) { if (plugins.value(iterator.key()).pluginId == plugin) { if (iterator->inputMethod) { Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &subView, iterator->inputMethod->subViews(state)) { subViews.insert(subView.subViewId, subView.subViewTitle); } } break; } } return subViews; } QList MIMPluginManagerPrivate::availablePluginsAndSubViews(Maliit::HandlerState state) const { QList pluginsAndSubViews; Plugins::const_iterator iterator(plugins.constBegin()); for (; iterator != plugins.constEnd(); ++iterator) { if (iterator->inputMethod) { const QString plugin = plugins.value(iterator.key()).pluginId; Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &subView, iterator->inputMethod->subViews(state)) { pluginsAndSubViews.append(MImOnScreenPlugins::SubView(plugin, subView.subViewId)); } } } return pluginsAndSubViews; } QString MIMPluginManagerPrivate::activeSubView(Maliit::HandlerState state) const { QString subView; Maliit::Plugins::InputMethodPlugin *currentPlugin = activePlugin(state); if (currentPlugin) { subView = plugins.value(currentPlugin).inputMethod->activeSubView(state); } return subView; } void MIMPluginManagerPrivate::setActivePlugin(const QString &pluginId, Maliit::HandlerState state) { if (state == Maliit::OnScreen) { const QList &subViews = onScreenPlugins.enabledSubViews(pluginId); if (subViews.empty()) { qDebug() << __PRETTY_FUNCTION__ << pluginId << "has no enabled subviews"; return; } const MImOnScreenPlugins::SubView &subView = subViews.first(); onScreenPlugins.setActiveSubView(subView); // Even when the onScreen plugins where the same it does not mean the onScreen plugin // is the active one (that could be a plugin from another state) so make sure the current // onScreen plugin get loaded. _q_onScreenSubViewChanged(); return; } MImSettings currentPluginConf(PluginRoot + "/" + inputSourceName(state)); if (!pluginId.isEmpty() && currentPluginConf.value().toString() != pluginId) { // check whether the pluginName is valid Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, plugins.keys()) { if (plugins.value(plugin).pluginId == pluginId) { currentPluginConf.set(pluginId); // Force call _q_syncHandlerMap() even though we already connect // _q_syncHandlerMap() with MImSettings valueChanged(). Because if the // request comes from different threads, the _q_syncHandlerMap() // won't be called at once. This means the synchronization of // handler map could be delayed if we don't force call it. _q_syncHandlerMap(state); break; } } } } /////////////// // actual class MIMPluginManager::MIMPluginManager(const QSharedPointer& icConnection, const QSharedPointer &platform) : QObject(), d_ptr(new MIMPluginManagerPrivate(icConnection, platform, this)) { Q_D(MIMPluginManager); d->q_ptr = this; // Connect connection to our handlers connect(d->mICConnection.data(), SIGNAL(showInputMethodRequest()), this, SLOT(showActivePlugins())); connect(d->mICConnection.data(), SIGNAL(hideInputMethodRequest()), this, SLOT(hideActivePlugins())); connect(d->mICConnection.data(), SIGNAL(resetInputMethodRequest()), this, SLOT(resetInputMethods())); connect(d->mICConnection.data(), SIGNAL(activeClientDisconnected()), this, SLOT(handleClientChange())); connect(d->mICConnection.data(), SIGNAL(clientActivated(uint)), this, SLOT(handleClientChange())); connect(d->mICConnection.data(), SIGNAL(contentOrientationAboutToChangeCompleted(int)), this, SLOT(handleAppOrientationAboutToChange(int))); connect(d->mICConnection.data(), SIGNAL(contentOrientationChangeCompleted(int)), this, SLOT(handleAppOrientationChanged(int))); connect(d->mICConnection.data(), SIGNAL(preeditChanged(QString,int)), this, SLOT(handlePreeditChanged(QString,int))); connect(d->mICConnection.data(), SIGNAL(mouseClickedOnPreedit(QPoint,QRect)), this, SLOT(handleMouseClickOnPreedit(QPoint,QRect))); connect(d->mICConnection.data(), SIGNAL(receivedKeyEvent(QEvent::Type,Qt::Key,Qt::KeyboardModifiers,QString,bool,int,quint32,quint32,ulong)), this, SLOT(processKeyEvent(QEvent::Type,Qt::Key,Qt::KeyboardModifiers,QString,bool,int,quint32,quint32,ulong))); connect(d->mICConnection.data(), SIGNAL(widgetStateChanged(uint,QMap,QMap,bool)), this, SLOT(handleWidgetStateChanged(uint,QMap,QMap,bool))); // Connect connection and MAttributeExtensionManager connect(d->mICConnection.data(), SIGNAL(copyPasteStateChanged(bool,bool)), d->attributeExtensionManager.data(), SLOT(setCopyPasteState(bool, bool))); connect(d->mICConnection.data(), SIGNAL(widgetStateChanged(uint,QMap,QMap,bool)), d->attributeExtensionManager.data(), SLOT(handleWidgetStateChanged(uint,QMap,QMap,bool))); connect(d->mICConnection.data(), SIGNAL(attributeExtensionRegistered(uint, int, QString)), d->attributeExtensionManager.data(), SLOT(handleAttributeExtensionRegistered(uint, int, QString))); connect(d->mICConnection.data(), SIGNAL(attributeExtensionUnregistered(uint, int)), d->attributeExtensionManager.data(), SLOT(handleAttributeExtensionUnregistered(uint, int))); connect(d->mICConnection.data(), SIGNAL(extendedAttributeChanged(uint, int, QString, QString, QString, QVariant)), d->attributeExtensionManager.data(), SLOT(handleExtendedAttributeUpdate(uint, int, QString, QString, QString, QVariant))); connect(d->attributeExtensionManager.data(), SIGNAL(notifyExtensionAttributeChanged(int, QString, QString, QString, QVariant)), d->mICConnection.data(), SLOT(notifyExtendedAttributeChanged(int, QString, QString, QString, QVariant))); connect(d->mICConnection.data(), SIGNAL(clientDisconnected(uint)), d->attributeExtensionManager.data(), SLOT(handleClientDisconnect(uint))); connect(d->mICConnection.data(), SIGNAL(attributeExtensionRegistered(uint, int, QString)), d->sharedAttributeExtensionManager.data(), SLOT(handleAttributeExtensionRegistered(uint, int, QString))); connect(d->mICConnection.data(), SIGNAL(attributeExtensionUnregistered(uint, int)), d->sharedAttributeExtensionManager.data(), SLOT(handleAttributeExtensionUnregistered(uint, int))); connect(d->mICConnection.data(), SIGNAL(extendedAttributeChanged(uint, int, QString, QString, QString, QVariant)), d->sharedAttributeExtensionManager.data(), SLOT(handleExtendedAttributeUpdate(uint, int, QString, QString, QString, QVariant))); connect(d->sharedAttributeExtensionManager.data(), SIGNAL(notifyExtensionAttributeChanged(QList, int, QString, QString, QString, QVariant)), d->mICConnection.data(), SLOT(notifyExtendedAttributeChanged(QList, int, QString, QString, QString, QVariant))); connect(d->mICConnection.data(), SIGNAL(clientDisconnected(uint)), d->sharedAttributeExtensionManager.data(), SLOT(handleClientDisconnect(uint))); connect(d->mICConnection.data(), SIGNAL(pluginSettingsRequested(int,QString)), this, SLOT(pluginSettingsRequested(int,QString))); connect(d->mICConnection.data(), SIGNAL(focusChanged(WId)), this, SLOT(handleAppFocusChanged(WId))); // Connect from MAttributeExtensionManager to our handlers connect(d->attributeExtensionManager.data(), SIGNAL(attributeExtensionIdChanged(const MAttributeExtensionId &)), this, SLOT(setToolbar(const MAttributeExtensionId &))); connect(d->attributeExtensionManager.data(), SIGNAL(keyOverrideCreated()), this, SLOT(updateKeyOverrides())); connect(d->attributeExtensionManager.data(), SIGNAL(globalAttributeChanged(MAttributeExtensionId,QString,QString,QVariant)), this, SLOT(onGlobalAttributeChanged(MAttributeExtensionId,QString,QString,QVariant))); d->paths = MImSettings(MImPluginPaths).value(QStringList(DefaultPluginLocation)).toStringList(); d->blacklist = MImSettings(MImPluginDisabled).value().toStringList(); d->loadPlugins(); d->loadHandlerMap(); d->registerSettings(); connect(&d->onScreenPlugins, SIGNAL(activeSubViewChanged()), this, SLOT(_q_onScreenSubViewChanged())); d->_q_onScreenSubViewChanged(); connect(&d->onScreenPlugins, SIGNAL(enabledPluginsChanged()), this, SIGNAL(pluginsChanged())); if (d->hwkbTracker.isPresent()) { connect(&d->hwkbTracker, SIGNAL(stateChanged()), this, SLOT(updateInputSource()), Qt::UniqueConnection); } d->imAccessoryEnabledConf = new MImSettings(MImAccesoryEnabled, this); connect(d->imAccessoryEnabledConf, SIGNAL(valueChanged()), this, SLOT(updateInputSource())); updateInputSource(); } MIMPluginManager::~MIMPluginManager() { Q_D(MIMPluginManager); delete d; } QStringList MIMPluginManager::loadedPluginsNames() const { Q_D(const MIMPluginManager); return d->loadedPluginsNames(); } QStringList MIMPluginManager::loadedPluginsNames(Maliit::HandlerState state) const { Q_D(const MIMPluginManager); return d->loadedPluginsNames(state); } QList MIMPluginManager::pluginDescriptions(Maliit::HandlerState state) const { Q_D(const MIMPluginManager); return d->pluginDescriptions(state); } QList MIMPluginManager::surroundingSubViewDescriptions(Maliit::HandlerState state) const { Q_D(const MIMPluginManager); return d->surroundingSubViewDescriptions(state); } QStringList MIMPluginManager::activePluginsNames() const { Q_D(const MIMPluginManager); return d->activePluginsNames(); } QString MIMPluginManager::activePluginsName(Maliit::HandlerState state) const { Q_D(const MIMPluginManager); return d->activePluginsName(state); } void MIMPluginManager::updateInputSource() { Q_D(MIMPluginManager); // Hardware and Accessory can work together. // OnScreen is mutually exclusive to Hardware and Accessory. QSet handlers = d->activeHandlers(); if (d->hwkbTracker.isOpen()) { // hw keyboard is on handlers.remove(Maliit::OnScreen); handlers.insert(Maliit::Hardware); } else { // hw keyboard is off handlers.remove(Maliit::Hardware); handlers.insert(Maliit::OnScreen); } if (d->imAccessoryEnabledConf->value().toBool()) { handlers.remove(Maliit::OnScreen); handlers.insert(Maliit::Accessory); } else { handlers.remove(Maliit::Accessory); } if (!handlers.isEmpty()) { d->setActiveHandlers(handlers); } } void MIMPluginManager::switchPlugin(Maliit::SwitchDirection direction, MAbstractInputMethod *initiator) { Q_D(MIMPluginManager); if (initiator) { if (!d->switchPlugin(direction, initiator)) { // no next plugin, just switch context initiator->switchContext(direction, true); } } } void MIMPluginManager::switchPlugin(const QString &name, MAbstractInputMethod *initiator) { Q_D(MIMPluginManager); if (initiator) { if (!d->switchPlugin(name, initiator)) { qWarning() << __PRETTY_FUNCTION__ << ", switching to plugin:" << name << " failed"; } } } void MIMPluginManager::setAllSubViewsEnabled(bool enable) { Q_D(MIMPluginManager); d->onScreenPlugins.setAllSubViewsEnabled(enable); } void MIMPluginManager::setToolbar(const MAttributeExtensionId &id) { Q_D(MIMPluginManager); // Record MAttributeExtensionId for switch Plugin d->toolbarId = id; QMap > keyOverrides = d->attributeExtensionManager->keyOverrides(id); bool focusStateOk(false); const bool focusState(d->mICConnection->focusState(focusStateOk)); if (!focusStateOk) { qCritical() << __PRETTY_FUNCTION__ << ": focus state is invalid."; } const bool mapEmpty(keyOverrides.isEmpty()); // setKeyOverrides are not called when keyOverrides map is empty // and no widget is focused - we do not want to update keys because either // vkb is not visible or another input widget is focused in, so its // extension attribute will be used in a moment. without this, some vkbs // may have some flickering - first it could show default label and a // fraction of second later - an overriden label. const bool callKeyOverrides(!(!focusState && mapEmpty)); Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, d->activePlugins) { if (callKeyOverrides) { d->plugins.value(plugin).inputMethod->setKeyOverrides(keyOverrides); } } } void MIMPluginManager::showActivePlugins() { Q_D(MIMPluginManager); d->showActivePlugins(); } void MIMPluginManager::hideActivePlugins() { Q_D(MIMPluginManager); d->hideActivePlugins(); } QMap MIMPluginManager::availableSubViews(const QString &plugin, Maliit::HandlerState state) const { Q_D(const MIMPluginManager); return d->availableSubViews(plugin, state); } QString MIMPluginManager::activeSubView(Maliit::HandlerState state) const { Q_D(const MIMPluginManager); return d->activeSubView(state); } void MIMPluginManager::setActivePlugin(const QString &pluginName, Maliit::HandlerState state) { Q_D(MIMPluginManager); d->setActivePlugin(pluginName, state); } void MIMPluginManager::setActiveSubView(const QString &subViewId, Maliit::HandlerState state) { Q_D(MIMPluginManager); d->_q_setActiveSubView(subViewId, state); } void MIMPluginManager::updateKeyOverrides() { Q_D(MIMPluginManager); QMap > keyOverrides = d->attributeExtensionManager->keyOverrides(d->toolbarId); Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, d->activePlugins) { d->plugins.value(plugin).inputMethod->setKeyOverrides(keyOverrides); } } void MIMPluginManager::handleAppOrientationAboutToChange(int angle) { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->handleAppOrientationAboutToChange(angle); } } void MIMPluginManager::handleAppOrientationChanged(int angle) { Q_D(MIMPluginManager); d->lastOrientation = angle; Q_FOREACH (MAbstractInputMethod *target, targets()) { target->handleAppOrientationChanged(angle); } } void MIMPluginManager::handleAppFocusChanged(WId id) { Q_D(MIMPluginManager); MIMPluginManagerPrivate::Plugins::iterator i = d->plugins.begin(); while (i != d->plugins.end()) { i.value().windowGroup.data()->setApplicationWindow(id); ++i; } } void MIMPluginManager::handleClientChange() { // notify plugins Q_FOREACH (MAbstractInputMethod *target, targets()) { target->handleClientChange(); } } void MIMPluginManager::handleWidgetStateChanged(unsigned int clientId, const QMap &newState, const QMap &oldState, bool focusChanged) { Q_UNUSED(clientId); // check visualization change bool oldVisualization = false; bool newVisualization = false; QVariant variant = oldState[VisualizationAttribute]; if (variant.isValid()) { oldVisualization = variant.toBool(); } variant = newState[VisualizationAttribute]; if (variant.isValid()) { newVisualization = variant.toBool(); } // update state QStringList changedProperties; for (QMap::const_iterator iter = newState.constBegin(); iter != newState.constEnd(); ++iter) { if (oldState.value(iter.key()) != iter.value()) { changedProperties.append(iter.key()); } } variant = newState[FocusStateAttribute]; const bool widgetFocusState = variant.toBool(); if (focusChanged) { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->handleFocusChange(widgetFocusState); } } // call notification methods if needed if (oldVisualization != newVisualization) { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->handleVisualizationPriorityChange(newVisualization); } } const Qt::InputMethodHints lastHints = static_cast(newState.value(Maliit::Internal::inputMethodHints).toInt()); MImUpdateEvent ev(newState, changedProperties, lastHints); // general notification last Q_FOREACH (MAbstractInputMethod *target, targets()) { if (not changedProperties.isEmpty()) { (void) target->imExtensionEvent(&ev); } target->update(); } // Make sure windows get hidden when no longer focus if (not widgetFocusState) { hideActivePlugins(); } } void MIMPluginManager::handleMouseClickOnPreedit(const QPoint &pos, const QRect &preeditRect) { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->handleMouseClickOnPreedit(pos, preeditRect); } } void MIMPluginManager::handlePreeditChanged(const QString &text, int cursorPos) { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->setPreedit(text, cursorPos); } } void MIMPluginManager::resetInputMethods() { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->reset(); } } void MIMPluginManager::processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time) { Q_FOREACH (MAbstractInputMethod *target, targets()) { target->processKeyEvent(keyType, keyCode, modifiers, text, autoRepeat, count, nativeScanCode, nativeModifiers, time); } } QSet MIMPluginManager::targets() { Q_D(MIMPluginManager); return d->targets; } void MIMPluginManager::onGlobalAttributeChanged(const MAttributeExtensionId &id, const QString &targetItem, const QString &attribute, const QVariant &value) { Q_D(MIMPluginManager); if (targetItem == InputMethodItem && attribute == LoadAll) { if (value.toBool()) { if (const QSharedPointer &extension = d->attributeExtensionManager->attributeExtension(id)) { // Create an object that is bound to the life time of the // attribute extension (through QObject ownership hierarchy). // Upon destruction, it will reset the all-subviews-enabled // override. (void) new MImSubViewOverride(&d->onScreenPlugins, extension.data()); } } setAllSubViewsEnabled(value.toBool()); } } void MIMPluginManager::pluginSettingsRequested(int clientId, const QString &descriptionLanguage) { Q_D(MIMPluginManager); QList settings = d->settings; for (int i = 0; i < settings.count(); ++i) { QList &entries = settings[i].entries; // TODO translate descriptions using descriptionLanguage settings[i].description_language = descriptionLanguage; for (int j = 0; j < entries.count(); ++j) { // TODO translate descriptions using descriptionLanguage entries[j].value = MImSettings(entries[j].extension_key).value(entries[j].attributes.value(Maliit::SettingEntryAttributes::defaultValue)); } } d->mICConnection->pluginSettingsLoaded(clientId, settings); } AbstractPluginSetting *MIMPluginManager::registerPluginSetting(const QString &pluginId, const QString &pluginDescription, const QString &key, const QString &description, Maliit::SettingEntryType type, const QVariantMap &attributes) { Q_D(MIMPluginManager); MImPluginSettingsEntry entry; entry.description = description; entry.type = type; entry.extension_key = PluginSettings + "/" + pluginId + "/" + key; entry.attributes = attributes; MImPluginSettingsInfo info; info.plugin_name = pluginId; info.plugin_description = pluginDescription; info.extension_id = MSharedAttributeExtensionManager::PluginSettings; info.entries.append(entry); d->registerSettings(info); return new PluginSetting(key, entry.extension_key, entry.attributes.value(Maliit::SettingEntryAttributes::defaultValue)); } PluginSetting::PluginSetting(const QString &shortKey, const QString &fullKey, const QVariant &value) : pluginKey(shortKey), setting(fullKey), defaultValue(value) { connect(&setting, SIGNAL(valueChanged()), this, SIGNAL(valueChanged())); } QString PluginSetting::key() const { return pluginKey; } QVariant PluginSetting::value() const { return setting.value(defaultValue); } QVariant PluginSetting::value(const QVariant &def) const { return setting.value(def.isValid() ? def : defaultValue); } void PluginSetting::set(const QVariant &val) { setting.set(val); } void PluginSetting::unset() { setting.unset(); } #include "moc_mimpluginmanager.cpp" maliit-framework-0.99.1+git20151118+62bd54b/src/mimpluginmanager.h000066400000000000000000000151051262307254400240350ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMPLUGINMANAGER_H #define MIMPLUGINMANAGER_H #include #include #include #include #include #include #include "mattributeextensionid.h" #include "minputcontextconnection.h" class QRegion; class MIMPluginManagerPrivate; class MAttributeExtensionId; class MAbstractInputMethod; class MAttributeExtensionManager; namespace Maliit { class AbstractPlatform; namespace Plugins { class AbstractPluginSetting; } } using Maliit::Plugins::AbstractPluginSetting; //! \internal /*! \ingroup maliitserver * \brief Manager of MInputMethodPlugin instances. * \note this class is not considered stable API */ class MIMPluginManager: public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "com.meego.inputmethodpluginmanager1") public: /*! * \Brief Constructs object MIMPluginManager */ MIMPluginManager(const QSharedPointer &icConnection, const QSharedPointer &platform); virtual ~MIMPluginManager(); //! Returns names of loaded plugins QStringList loadedPluginsNames() const; //! Returns names of loaded plugins which support \a state QStringList loadedPluginsNames(Maliit::HandlerState state) const; //! \brief Return information about loaded input method plugins which could work in specified \a state. QList pluginDescriptions(Maliit::HandlerState state) const; //! \brief Return information about previous, current and next subviews. //! //! \sa MAbstractInputMethodHost::surroundingSubViewDescriptions() QList surroundingSubViewDescriptions(Maliit::HandlerState state) const; //! Returns names of activated plugins QStringList activePluginsNames() const; //! Returns names of activated plugin for \a state QString activePluginsName(Maliit::HandlerState state) const; //! Returns all subviews (IDs and titles) of loaded plugins which support \a state. QMap availableSubViews(const QString &plugin, Maliit::HandlerState state = Maliit::OnScreen) const; //! Returns the ID of active subview of the activated plugin for \a state. QString activeSubView(Maliit::HandlerState state) const; //! Sets \a pluginName as the activated plugin for \a state. void setActivePlugin(const QString &pluginName, Maliit::HandlerState state); //! Sets \a subViewId as the active subview of the activated plugin for \a state. void setActiveSubView(const QString &subViewId, Maliit::HandlerState state); //! Switches plugin in according to given \a direction void switchPlugin(Maliit::SwitchDirection direction, MAbstractInputMethod *initiator); //! Switches active plugin to inactive plugin with given \a name void switchPlugin(const QString &name, MAbstractInputMethod *initiator); //! Enables all installed subviews void setAllSubViewsEnabled(bool enable); //! Register a setting entry for the specified plugin AbstractPluginSetting *registerPluginSetting(const QString &pluginId, const QString &pluginDescription, const QString &key, const QString &description, Maliit::SettingEntryType type, const QVariantMap &attributes); Q_SIGNALS: //! This signal is emitted when input method plugins are loaded, unloaded, //! enabled or disabled void pluginsChanged(); void pluginLoaded(); public Q_SLOTS: //! Show active plugins. void showActivePlugins(); //! Hide active plugins. void hideActivePlugins(); void resetInputMethods(); private Q_SLOTS: //! Update and activate input source. void updateInputSource(); //! Set toolbar to active plugin with given \a id void setToolbar(const MAttributeExtensionId &id); //! Update the key overrides for active plugin. void updateKeyOverrides(); void handleAppOrientationChanged(int angle); void handleAppOrientationAboutToChange(int angle); void handleAppFocusChanged(WId id); void handleClientChange(); void handleWidgetStateChanged(unsigned int clientId, const QMap &newState, const QMap &oldState, bool focusChanged); void handleMouseClickOnPreedit(const QPoint &pos, const QRect &preeditRect); void handlePreeditChanged(const QString &text, int cursorPos); void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode, Qt::KeyboardModifiers modifiers, const QString &text, bool autoRepeat, int count, quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time); void pluginSettingsRequested(int clientId, const QString &descriptionLanguage); /*! * \brief Handle global attribute change * \param id id of the attribute extension that triggered this change * \param targetItem Item name * \param attribute Attribute name * \param value New attribute value */ void onGlobalAttributeChanged(const MAttributeExtensionId &id, const QString &targetItem, const QString &attribute, const QVariant &value); private: QSet targets(); protected: MIMPluginManagerPrivate *const d_ptr; private: Q_DISABLE_COPY(MIMPluginManager) Q_DECLARE_PRIVATE(MIMPluginManager) Q_PRIVATE_SLOT(d_func(), void _q_syncHandlerMap(int)) Q_PRIVATE_SLOT(d_func(), void _q_setActiveSubView(const QString &, Maliit::HandlerState)) Q_PRIVATE_SLOT(d_func(), void _q_onScreenSubViewChanged()) friend class Ut_MIMPluginManager; friend class Ut_MIMPluginManagerConfig; friend class Ft_MIMPluginManager; friend class Ut_MIMSettingsDialog; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/mimpluginmanager_p.h000066400000000000000000000172061262307254400243600ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMPLUGINMANAGER_P_H #define MIMPLUGINMANAGER_P_H #include #include "mattributeextensionid.h" #include "minputmethodhost.h" #include "mimonscreenplugins.h" #include "mimsettings.h" #include "mimhwkeyboardtracker.h" #include #include #include "windowgroup.h" #include "abstractplatform.h" #include namespace Maliit { namespace Plugins { class InputMethodPlugin; } } class MInputContextConnection; class MIMPluginManager; class MAttributeExtensionManager; class MSharedAttributeExtensionManager; class MImSettings; class MAbstractInputMethod; class MIMPluginManagerAdaptor; /* Internal class only! Interfaces here change, internal developers only*/ class PluginSetting : public Maliit::Plugins::AbstractPluginSetting { Q_OBJECT public: PluginSetting(const QString &shortKey, const QString &fullKey, const QVariant &value); virtual QString key() const; virtual QVariant value() const; virtual QVariant value(const QVariant &def) const; virtual void set(const QVariant &val); virtual void unset(); private: QString pluginKey; MImSettings setting; QVariant defaultValue; }; /* Internal class only! Interfaces here change, internal developers only*/ class MIMPluginManagerPrivate { Q_DECLARE_PUBLIC(MIMPluginManager) public: typedef QSet PluginState; enum ShowInputMethodRequest { DontShowInputMethod, ShowInputMethod }; struct PluginDescription { MAbstractInputMethod *inputMethod; MInputMethodHost *imHost; PluginState state; Maliit::SwitchDirection lastSwitchDirection; QString pluginId; // the library filename is used as ID QSharedPointer windowGroup; }; typedef QMap Plugins; typedef QSet ActivePlugins; typedef QMap HandlerMap; MIMPluginManagerPrivate(const QSharedPointer& connection, const QSharedPointer &platform, MIMPluginManager *p); virtual ~MIMPluginManagerPrivate(); void autoDetectEnabledSubViews(const QString &plugin); void activatePlugin(Maliit::Plugins::InputMethodPlugin *plugin); void loadPlugins(); bool loadPlugin(const QDir &dir, const QString &fileName); void addHandlerMap(Maliit::HandlerState state, const QString &pluginName); void registerSettings(); void registerSettings(const MImPluginSettingsInfo &info); MImPluginSettingsInfo globalSettings() const; void setActiveHandlers(const QSet &states); QSet activeHandlers() const; void deactivatePlugin(Maliit::Plugins::InputMethodPlugin *plugin); void replacePlugin(Maliit::SwitchDirection direction, Maliit::Plugins::InputMethodPlugin *source, Plugins::iterator replacement, const QString &subViewId); bool switchPlugin(Maliit::SwitchDirection direction, MAbstractInputMethod *initiator); bool switchPlugin(const QString &name, MAbstractInputMethod *initiator, const QString &subViewId = QString()); bool trySwitchPlugin(Maliit::SwitchDirection direction, Maliit::Plugins::InputMethodPlugin *source, Plugins::iterator replacement, const QString &subViewId = QString()); void changeHandlerMap(Maliit::Plugins::InputMethodPlugin *origin, Maliit::Plugins::InputMethodPlugin *replacement, QSet states); QStringList loadedPluginsNames() const; QStringList loadedPluginsNames(Maliit::HandlerState state) const; QList pluginDescriptions(Maliit::HandlerState) const; Plugins::const_iterator findEnabledPlugin(Plugins::const_iterator current, Maliit::SwitchDirection direction, Maliit::HandlerState state) const; void filterEnabledSubViews(QMap &subViews, const QString &pluginId, Maliit::HandlerState state) const; void append(QList &list, const QMap &map, const QString &pluginId) const; QList surroundingSubViewDescriptions(Maliit::HandlerState state) const; QStringList activePluginsNames() const; QString activePluginsName(Maliit::HandlerState state) const; void loadHandlerMap(); Maliit::Plugins::InputMethodPlugin *activePlugin(Maliit::HandlerState state) const; void hideActivePlugins(); void showActivePlugins(); void ensureActivePluginsVisible(ShowInputMethodRequest request); /*! * This method is called when one of the handler map settings have changed * to synchronize the handlerToPluginConfs. * \param state (can be cast to Maliit::HandlerState) indicates which state of the * handler map is changed. */ void _q_syncHandlerMap(int state); /*! * \brief This method is called when activeSubview is changed by settings or plugin. */ void _q_setActiveSubView(const QString &, Maliit::HandlerState); /*! * \brief Called in response to changed active on screen subview key change */ void _q_onScreenSubViewChanged(); QMap availableSubViews(const QString &plugin, Maliit::HandlerState state = Maliit::OnScreen) const; QList availablePluginsAndSubViews(Maliit::HandlerState state = Maliit::OnScreen) const; QString activeSubView(Maliit::HandlerState state) const; void setActivePlugin(const QString &pluginName, Maliit::HandlerState state); QString inputSourceName(Maliit::HandlerState source) const; MIMPluginManager *parent; QSharedPointer mICConnection; Plugins plugins; ActivePlugins activePlugins; QSet targets; QList settings; QStringList paths; QStringList blacklist; HandlerMap handlerToPlugin; QList handlerToPluginConfs; MImSettings *imAccessoryEnabledConf; QString activeSubViewIdOnScreen; MIMPluginManagerAdaptor *adaptor; MIMPluginManager *q_ptr; bool visible; typedef QMap InputSourceToNameMap; InputSourceToNameMap inputSourceToNameMap; MAttributeExtensionId toolbarId; MImOnScreenPlugins onScreenPlugins; MImHwKeyboardTracker hwkbTracker; int lastOrientation; QScopedPointer attributeExtensionManager; QScopedPointer sharedAttributeExtensionManager; QSharedPointer m_platform; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/src/mimserver.cpp000066400000000000000000000034471262307254400230530ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimserver.h" #include "mimpluginmanager.h" #include "mimsettings.h" class MImServerPrivate { public: explicit MImServerPrivate(); // Manager for loading and handling all plugins MIMPluginManager *pluginManager; // Connection to application side (input-context) QSharedPointer icConnection; private: Q_DISABLE_COPY(MImServerPrivate) }; MImServerPrivate::MImServerPrivate() {} MImServer::MImServer(const QSharedPointer &icConnection, const QSharedPointer &platform, QObject *parent) : QObject(parent) , d_ptr(new MImServerPrivate) { Q_D(MImServer); d->icConnection = icConnection; d->pluginManager = new MIMPluginManager(d->icConnection, platform); } MImServer::~MImServer() { } void MImServer::configureSettings(MImServer::SettingsType settingsType) { switch (settingsType) { case TemporarySettings: MImSettings::setPreferredSettingsType(MImSettings::TemporarySettings); break; case PersistentSettings: MImSettings::setPreferredSettingsType(MImSettings::PersistentSettings); break; default: qCritical() << __PRETTY_FUNCTION__ << "Invalid value for preferredSettingType." << settingsType; } } maliit-framework-0.99.1+git20151118+62bd54b/src/mimserver.h000066400000000000000000000030471262307254400225140ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSERVER_H #define MIMSERVER_H #include #include class MInputContextConnection; class MImServerPrivate; namespace Maliit { class AbstractPlatform; } // namespace Maliit /* MImServer: The Maliit Input Method Server * * Consumers of MImServer are responsible for creating a QApplication (for the mainloop), * and an MInputContextConnection for communication with clients, and for starting the mainloop. * Everything else is handled by the server. */ class MImServer : public QObject { Q_OBJECT public: enum SettingsType { TemporarySettings, PersistentSettings }; public: explicit MImServer(const QSharedPointer &icConnection, const QSharedPointer &platform, QObject *parent = 0); ~MImServer(); static void configureSettings(MImServer::SettingsType settingsType); private: Q_DISABLE_COPY(MImServer) Q_DECLARE_PRIVATE(MImServer) const QScopedPointer d_ptr; }; #endif // MIMSERVER_H maliit-framework-0.99.1+git20151118+62bd54b/src/mimserveroptions.cpp000066400000000000000000000272721262307254400244710ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimserveroptions.h" #include #include #include #include #include #include namespace { struct CommandLineParameter { const char * name; const char * description; }; CommandLineParameter AvailableConnectionParameters[] = { { "-allow-anonymous", "Allow anonymous/unauthenticated use of DBus interface"}, { "-override-address", "Override the DBus peer-to-peer address for input-context"} }; struct IgnoredParameter { const char * name; bool hasArgument; } IgnoredParameters [] = { // Following parameters are used by Qt, so we should not show error messages or help about it { "-style", true }, { "-session", true }, { "-graphicssystem", true }, { "-testability", true }, { "-qdevel", false }, { "-reverse", false }, { "-stylesheet", false }, { "-widgetcount", false }, { "-qdebug", false }, { "-software", false }, { "-qws", false }, { "-sync", false } }; const char * programName = "meego-im-uiserver"; /*! \internal * \brief Base class for parsers. */ struct MImServerOptionsParserBase : public QSharedData { MImServerOptionsParserBase(void *options); virtual ~MImServerOptionsParserBase(); //! Result of parameter parsing enum ParsingResult { //! Parameter was not recognized Invalid = -1, //! Parameter was recognized Ok, }; /*! * \brief Parse one \a parameter from command line. * \param[in] next Next parameter if it exists, otherwise 0. * It should be used if current \a parameter should have argument. * \param[out] argumentCount Amount of arguments which follow \a paramter. * Current implementation assumes that it should 0 or 1. * \return Ok if \a parameter is recognized by this parser * and should not be passed to other parsers, otherwise Invalid. */ virtual ParsingResult parseParameter(const char * parameter, const char * next, int *argumentCount) = 0; /*! * \brief Print options which could be recognized by this parser. */ virtual void printAvailableOptions(const char *format) = 0; void *options() const; private: void *serverOptions; }; typedef QExplicitlySharedDataPointer ParserBasePtr; QList parsers; //! Unregister parser associated with given \a options. void unregisterParser(void *options) { QList::iterator iterator = parsers.begin(); while (iterator != parsers.end()) { if ((*iterator)->options() == options) { iterator = parsers.erase(iterator); } else { ++iterator; } } } //! \brief Parser of common command line parameters struct MImServerCommonOptionsParser : public MImServerOptionsParserBase { MImServerCommonOptionsParser(MImServerCommonOptions *options); //! \reimp virtual ParsingResult parseParameter(const char * parameter, const char * next, int *argumentCount); virtual void printAvailableOptions(const char *format); //! \reimp_end private: MImServerCommonOptions *storage; }; /*! * \brief Parser of command line parameters for the server<->input context connection */ struct MImServerConnectionOptionsParser : public MImServerOptionsParserBase { /*! \brief Construct new instance. * Object should be created when application starts and should stay alive until moment * when application will exit, so it is recommnded to create it in main(). * \note It does not makes sense tp create more than one object of this class. */ MImServerConnectionOptionsParser(MImServerConnectionOptions *options); //! \reimp virtual ParsingResult parseParameter(const char * parameter, const char * next, int *argumentCount); virtual void printAvailableOptions(const char *format); //! \reimp_end private: MImServerConnectionOptions *storage; }; struct MImServerIgnoredOptions { MImServerIgnoredOptions(); ~MImServerIgnoredOptions(); }; struct MImServerIgnoredOptionsParser : public MImServerOptionsParserBase { MImServerIgnoredOptionsParser(MImServerIgnoredOptions *options); //! \reimp virtual ParsingResult parseParameter(const char * parameter, const char * next, int *argumentCount); virtual void printAvailableOptions(const char *format); //! \reimp_end }; //! \internal_end // Always instantiate error suppressor, so main() should not worry about it MImServerIgnoredOptions IgnoredOptions; const char * const HelpFormat = "%-30s\t%s\n"; } // namespace /////////////// // parser interface MImServerOptionsParserBase::MImServerOptionsParserBase(void *options) : serverOptions(options) { } MImServerOptionsParserBase::~MImServerOptionsParserBase() { } void* MImServerOptionsParserBase::options() const { return serverOptions; } bool parseCommandLine(int argc, const char * const * argv) { bool allRecognized = true; if (argc > 0) { programName = argv[0]; } for (int n = 1; n < argc; ++n) { const char * const parameter = argv[n]; const char * const next = (n < argc - 1) ? argv[n + 1] : 0; MImServerOptionsParserBase::ParsingResult parsingResult = MImServerOptionsParserBase::Invalid; Q_FOREACH (const ParserBasePtr &base, parsers) { int skippedParameters = 0; parsingResult = base->parseParameter(parameter, next, &skippedParameters); if (parsingResult == MImServerOptionsParserBase::Ok) { n += skippedParameters; break; } } if (parsingResult == MImServerOptionsParserBase::Invalid) { fprintf(stderr, "Invalid parameter '%s'\n", argv[n]); allRecognized = false; } } return allRecognized; } void printHelpMessage() { fprintf(stderr, "\nUsage: %s [options]\n", programName); fprintf(stderr, "Available options:\n"); Q_FOREACH (const ParserBasePtr &base, parsers) { base->printAvailableOptions(HelpFormat); } // parsers will not be used anymore, // therefore we can destroy them all parsers.clear(); } /////////////// // parser for ignored options MImServerIgnoredOptionsParser::MImServerIgnoredOptionsParser(MImServerIgnoredOptions *options) : MImServerOptionsParserBase(options) { } MImServerOptionsParserBase::ParsingResult MImServerIgnoredOptionsParser::parseParameter(const char *parameter, const char *, int *argumentCount) { const int count = sizeof(IgnoredParameters) / sizeof(IgnoredParameters[0]); ParsingResult result = Invalid; *argumentCount = 0; for (int i = 0; i < count; ++i) { if (!strcmp(parameter, IgnoredParameters[i].name)) { result = Ok; *argumentCount = IgnoredParameters[i].hasArgument ? 1 : 0; break; } } return result; } void MImServerIgnoredOptionsParser::printAvailableOptions(const char *) { // nothing to print } MImServerIgnoredOptions::MImServerIgnoredOptions() { const ParserBasePtr p(new MImServerIgnoredOptionsParser(this)); parsers.append(p); } MImServerIgnoredOptions::~MImServerIgnoredOptions() { unregisterParser(this); } /////////////// // parser for common options MImServerCommonOptionsParser::MImServerCommonOptionsParser(MImServerCommonOptions *options) : MImServerOptionsParserBase(options), storage(options) { } MImServerOptionsParserBase::ParsingResult MImServerCommonOptionsParser::parseParameter(const char *parameter, const char *, int *argumentCount) { *argumentCount = 0; if (!strcmp("-help", parameter)) { storage->showHelp = true; return Ok; } return Invalid; } void MImServerCommonOptionsParser::printAvailableOptions(const char *format) { fprintf(stderr, format, "-help", "Show usage information"); } MImServerCommonOptions::MImServerCommonOptions() : showHelp(false) { const ParserBasePtr p(new MImServerCommonOptionsParser(this)); parsers.append(p); } MImServerCommonOptions::~MImServerCommonOptions() { unregisterParser(this); } MImServerConnectionOptionsParser::MImServerConnectionOptionsParser(MImServerConnectionOptions *options) : MImServerOptionsParserBase(options) , storage(options) { } MImServerOptionsParserBase::ParsingResult MImServerConnectionOptionsParser::parseParameter(const char *parameter, const char *next, int *argumentCount) { const int count = sizeof(AvailableConnectionParameters) / sizeof(AvailableConnectionParameters[0]); ParsingResult result = Invalid; for (int i = 0; i < count; ++i) { const char * const availableParameter = AvailableConnectionParameters[i].name; if (!strcmp(parameter, availableParameter)) { result = Ok; if (!strcmp(parameter, "-allow-anonymous")) { storage->allowAnonymous = true; *argumentCount = 0; } else if (!strcmp(parameter, "-override-address")) { if (next) { storage->overriddenAddress = QString::fromUtf8(next); *argumentCount = 1; } else { fprintf(stderr, "ERROR: No argument passed to -override-address\n"); *argumentCount = 0; } } else { fprintf(stderr, "ERROR: connection option %s declared but unhandled\n", parameter); } break; } } return result; } void MImServerConnectionOptionsParser::printAvailableOptions(const char *format) { const int count = sizeof(AvailableConnectionParameters) / sizeof(AvailableConnectionParameters[0]); for (int i = 0; i < count; ++i) { if (AvailableConnectionParameters[i].description) { fprintf(stderr, format, AvailableConnectionParameters[i].name, AvailableConnectionParameters[i].description); } } } MImServerConnectionOptions::MImServerConnectionOptions() : allowAnonymous(false) { const ParserBasePtr p(new MImServerConnectionOptionsParser(this)); parsers.append(p); } MImServerConnectionOptions::~MImServerConnectionOptions() { unregisterParser(this); } maliit-framework-0.99.1+git20151118+62bd54b/src/mimserveroptions.h000066400000000000000000000026131262307254400241260ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSERVEROPTIONS_H #define MIMSERVEROPTIONS_H #include #include //! \internal /*! \brief Parse command line arguments and update values of members * of this class. * \param argc Amount of arguments. * \param argv Command line parameters. * \return true if all parameters were recognized by parser */ bool parseCommandLine(int argc, const char * const * argv); //! Display help message to the screen. void printHelpMessage(); struct MImServerConnectionOptions { public: MImServerConnectionOptions(); ~MImServerConnectionOptions(); //! Contains true if user asks for help or provided incorrect parameter bool allowAnonymous; QString overriddenAddress; }; struct MImServerCommonOptions { public: MImServerCommonOptions(); ~MImServerCommonOptions(); //! Contains true if user asks for help or provided incorrect parameter bool showHelp; }; //! \internal_end #endif maliit-framework-0.99.1+git20151118+62bd54b/src/mimsettings.cpp000066400000000000000000000067121262307254400234030ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimsettings.h" #include "mimsettingsqsettings.h" #include "config.h" #include #include #include #include #include typedef MImSettingsQSettingsBackendFactory MImSettingsDefaultPersistentBackendFactory; QScopedPointer MImSettings::factory; MImSettings::SettingsType MImSettings::preferredSettingsType = MImSettings::InvalidSettings; MImSettingsBackend::MImSettingsBackend(QObject *parent) : QObject(parent) { } MImSettingsBackend::~MImSettingsBackend() { } MImSettingsBackendFactory::~MImSettingsBackendFactory() { } QString MImSettings::key() const { return backend->key(); } QVariant MImSettings::value() const { return backend->value(QVariant()); } QVariant MImSettings::value(const QVariant &def) const { return backend->value(def); } void MImSettings::set(const QVariant &val) { if (val.isValid()) { backend->set(val); } else { backend->unset(); } } void MImSettings::unset() { backend->unset(); } QList MImSettings::listDirs() const { return backend->listDirs(); } QList MImSettings::listEntries() const { return backend->listEntries(); } MImSettings::MImSettings(const QString &key, QObject *parent) : QObject(parent) { if (!factory) { MImSettingsBackendFactory *newFactory = 0; switch (preferredSettingsType) { case TemporarySettings: // Might be possible with other backends as well, // but it does not matter as the settings will be temporary // and not visible to others anyway newFactory = new MImSettingsQSettingsTemporaryBackendFactory; break; case PersistentSettings: newFactory = new MImSettingsDefaultPersistentBackendFactory; break; case InvalidSettings: qFatal("No settings type specified. " "Call MImSettings::setPreferredSettingsType() before making use of MImSettings."); break; default: qCritical() << __PRETTY_FUNCTION__ << "Invalid value for preferredSettingType." << preferredSettingsType; } MImSettings::setImplementationFactory(newFactory); } backend.reset(factory->create(key, this)); connect(backend.data(), SIGNAL(valueChanged()), this, SIGNAL(valueChanged())); } MImSettings::~MImSettings() { } void MImSettings::setPreferredSettingsType(SettingsType setting) { preferredSettingsType = setting; factory.reset(); } void MImSettings::setImplementationFactory(MImSettingsBackendFactory *newFactory) { factory.reset(newFactory); } QHash MImSettings::defaults() { QHash defaults; defaults[MALIIT_CONFIG_ROOT"plugins/hardware"] = MALIIT_DEFAULT_HW_PLUGIN; defaults[MALIIT_CONFIG_ROOT"accessoryenabled"] = false; defaults[MALIIT_CONFIG_ROOT"multitouch/enabled"] = MALIIT_ENABLE_MULTITOUCH; return defaults; } maliit-framework-0.99.1+git20151118+62bd54b/src/mimsettings.h000066400000000000000000000161041262307254400230440ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSETTINGS_H #define MIMSETTINGS_H #ifndef MALIIT_FRAMEWORK_USE_INTERNAL_API #error Internal API only. #else #include #include #include #include //! \internal /*! \ingroup maliitserver \brief Implements a storage backend for MImSettings */ class MImSettingsBackend : public QObject { Q_OBJECT public: /*! Initialized a MImSettingsBackend. */ explicit MImSettingsBackend(QObject *parent = 0); /*! Finalizes a MImSettingsBackend. */ virtual ~MImSettingsBackend(); /*! Returns the key of this item, as given to MImSettings constructor. \sa MImSettings::key() */ virtual QString key() const = 0; /*! Returns the current value of this item, as a QVariant. If there is no value for this item, return \a def instead. The implementation is: - return the value associated to the key (if present) - otherwise return the value listed in MImSettings::getDefaults() (if present) - otherwise return the passed-in default value \sa MImSettings::value() */ virtual QVariant value(const QVariant &def) const = 0; /*! Set the value of this item to \a val. Must emit valueChanged() if the new value differs from the old one. \param val The new value (is always a valid QVariant). \sa MImSettings::set() */ virtual void set(const QVariant &val) = 0; /*! Unset this item. Must emit valueChanged() if it deletes the entry. This backend method is called both for MImSettings::unset() and MImSettings::set(QVariant()). \sa MImSettings::unset() \sa MImSettings::set() */ virtual void unset() = 0; /*! Return a list of the directories below this item. The returned strings are absolute key names like "/myapp/settings". A directory is a key that has children. \sa MImSettings::listDirs() */ virtual QList listDirs() const = 0; /*! Return a list of entries below this item. The returned strings are absolute key names like "/myapp/settings/first". A entry is a key that has a value. \sa MImSettings::listEntries() */ virtual QList listEntries() const = 0; Q_SIGNALS: /*! Emitted when the value is changed or unset. \sa MImSettingsBackend::valueChanged() */ void valueChanged(); }; //! \internal /*! \ingroup maliitserver \brief Factory for MImSettings backend implementations */ class MImSettingsBackendFactory { public: /*! Creates a backend instance for the specified key. */ virtual ~MImSettingsBackendFactory(); virtual MImSettingsBackend *create(const QString &key, QObject *parent) = 0; }; //! \internal /*! \ingroup maliitserver \brief MImSettings is a generic interface to access configuration values Creating a MImSettings instance gives you access to a single configuration key. You can get and set its value, and connect to its valueChanged() signal to be notified about changes. The value of the key is returned to you as a QVariant, and you pass in a QVariant when setting the value. Before making use of MImSettings, you must call MImSettings::setPreferredSettingsType(). \warning MImSettings is not reentrant. */ class MImSettings : public QObject { Q_OBJECT public: enum SettingsType { InvalidSettings, TemporarySettings, PersistentSettings }; public: /*! Initializes a MImSettings to access the configuratin key denoted by \a key. Key names are formatted like Unix filesystem paths (es. like "/myapp/settings/first"). \param key The name of the key. \param parent Parent object */ explicit MImSettings(const QString &key, QObject *parent = 0); /*! Finalizes a MImSettings. */ virtual ~MImSettings(); /*! Returns the key of this item, as given to the constructor. */ QString key() const; /*! Returns the current value of this item, as a QVariant. */ QVariant value() const; /*! Returns the current value of this item, as a QVariant. If * there is no value for this item, return \a def instead. */ QVariant value(const QVariant &def) const; /*! Set the value of this item to \a val. If string \a val fails for any reason, the current value is not changed and nothing happens. When the new value is different from the old value, the changedValue() signal is emitted on this MImSettings and on all other MImSettings instances for the same key. Depending on the backend, the signals might be emitted immediatly or the next time the main event loop runs. \param val The new value. */ void set(const QVariant &val); /*! Unset this item. This is equivalent to \code item.set(QVariant(QVariant::Invalid)); \endcode */ void unset(); /*! Return a list of the directories below this item. The returned strings are absolute key names like "/myapp/settings". A directory is a key that has children. The same key might also have a value, but that is confusing and best avoided. */ QList listDirs() const; /*! Return a list of entries below this item. The returned strings are absolute key names like "/myapp/settings/first". A entry is a key that has a value. The same key might also have children, but that is confusing and is best avoided. */ QList listEntries() const; /*! Set the factory used to create backend implementations. Should be called at most once at startup, and is meant to be used only for tests. Takes ownership of the passed instance. */ static void setImplementationFactory(MImSettingsBackendFactory *factory); /*! Set the preferred settings type for backend implementations * * Should be called at most once at startup, before creating MImSetting instances. * This is not honored if using setImplementationFactory() manually. */ static void setPreferredSettingsType(SettingsType setting); /*! Return the default values used for some keys */ static QHash defaults(); Q_SIGNALS: /*! Emitted when the value of this item has changed. */ void valueChanged(); private: QScopedPointer backend; static QScopedPointer factory; static SettingsType preferredSettingsType; }; //! \internal_end #endif // MALIIT_FRAMEWORK_USE_INTERNAL_API #endif // MIMSETTINGS_H maliit-framework-0.99.1+git20151118+62bd54b/src/mimsettingsqsettings.cpp000066400000000000000000000125141262307254400253420ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimsettingsqsettings.h" #include #include typedef QList Items; typedef QHash ItemMap; namespace { const QString Organization = "maliit.org"; const QString Application = "server"; QList makeAbsolute(const QString &prefix, const QList &entries) { QList absolute; Q_FOREACH (const QString &path, entries) { absolute.append(prefix + "/" + path); } return absolute; } } struct MImSettingsQSettingsBackendPrivate { QString key; static ItemMap registry; QSettings *settingsInstance; void registerInstance(MImSettingsQSettingsBackend *instance) { registry[key].append(instance); } void unregisterInstance(MImSettingsQSettingsBackend *instance) { ItemMap::iterator items = registry.find(key); items->removeOne(instance); if (items->isEmpty()) registry.erase(items); } void notify() { // use QPointer to avoid referencing a deleted object in case // one slot deletes another MImSettings instance for this key QList > items; ItemMap::iterator it = registry.find(key); Q_FOREACH (MImSettingsQSettingsBackend *item, *it) { items.append(item); } Q_FOREACH (MImSettingsQSettingsBackend *item, items) { if (item) Q_EMIT item->valueChanged(); } } }; ItemMap MImSettingsQSettingsBackendPrivate::registry; QString MImSettingsQSettingsBackend::key() const { Q_D(const MImSettingsQSettingsBackend); return d->key; } QVariant MImSettingsQSettingsBackend::value(const QVariant &def) const { Q_D(const MImSettingsQSettingsBackend); if (!d->settingsInstance->contains(d->key)) return MImSettings::defaults().value(d->key, def); return d->settingsInstance->value(d->key, def); } void MImSettingsQSettingsBackend::set(const QVariant &val) { Q_D(MImSettingsQSettingsBackend); if (val == d->settingsInstance->value(d->key)) return; d->settingsInstance->setValue(d->key, val); d->settingsInstance->sync(); d->notify(); } void MImSettingsQSettingsBackend::unset() { Q_D(MImSettingsQSettingsBackend); if (!d->settingsInstance->contains(d->key)) return; d->settingsInstance->remove(d->key); d->settingsInstance->sync(); d->notify(); } QList MImSettingsQSettingsBackend::listDirs() const { Q_D(const MImSettingsQSettingsBackend); d->settingsInstance->beginGroup(d->key); QList result = makeAbsolute(d->key, d->settingsInstance->childGroups()); d->settingsInstance->endGroup(); return result; } QList MImSettingsQSettingsBackend::listEntries() const { Q_D(const MImSettingsQSettingsBackend); d->settingsInstance->beginGroup(d->key); QList result = makeAbsolute(d->key, d->settingsInstance->childKeys()); d->settingsInstance->endGroup(); return result; } MImSettingsQSettingsBackend::MImSettingsQSettingsBackend(QSettings *settingsInstance, const QString &key, QObject *parent) : MImSettingsBackend(parent), d_ptr(new MImSettingsQSettingsBackendPrivate) { Q_D(MImSettingsQSettingsBackend); d->key = key; d->settingsInstance = settingsInstance; d->registerInstance(this); } MImSettingsQSettingsBackend::~MImSettingsQSettingsBackend() { Q_D(MImSettingsQSettingsBackend); d->unregisterInstance(this); } /* QSettings backend backed by the native settings store for the Maliit Server org. and app. */ MImSettingsQSettingsBackendFactory::MImSettingsQSettingsBackendFactory() : mSettings(Organization, Application) {} MImSettingsQSettingsBackendFactory::MImSettingsQSettingsBackendFactory(const QString &organization, const QString &application) : mSettings(organization, application) {} MImSettingsQSettingsBackendFactory::~MImSettingsQSettingsBackendFactory() { } MImSettingsBackend *MImSettingsQSettingsBackendFactory::create(const QString &key, QObject *parent) { return new MImSettingsQSettingsBackend(&mSettings, key, parent); } /* QSettings backend backed by a temporary file */ MImSettingsQSettingsTemporaryBackendFactory::MImSettingsQSettingsTemporaryBackendFactory() : mTempFile() { // Force backing file to be created, otherwise fileName() returns empty mTempFile.open(); mTempFile.close(); mSettings.reset(new QSettings(mTempFile.fileName(), QSettings::IniFormat)); } MImSettingsQSettingsTemporaryBackendFactory::~MImSettingsQSettingsTemporaryBackendFactory() { } MImSettingsBackend *MImSettingsQSettingsTemporaryBackendFactory::create(const QString &key, QObject *parent) { return new MImSettingsQSettingsBackend(mSettings.data(), key, parent); } maliit-framework-0.99.1+git20151118+62bd54b/src/mimsettingsqsettings.h000066400000000000000000000043131262307254400250050ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSETTINGSQSETTINGS_H #define MIMSETTINGSQSETTINGS_H #include "mimsettings.h" #include #include #include //! \internal struct MImSettingsQSettingsBackendPrivate; class MImSettingsQSettingsBackend : public MImSettingsBackend { Q_OBJECT public: explicit MImSettingsQSettingsBackend(QSettings *settingsInstance, const QString &key, QObject *parent = 0); virtual ~MImSettingsQSettingsBackend(); virtual QString key() const; virtual QVariant value(const QVariant &def) const; virtual void set(const QVariant &val); virtual void unset(); virtual QList listDirs() const; virtual QList listEntries() const; private: QScopedPointer d_ptr; Q_DISABLE_COPY(MImSettingsQSettingsBackend) Q_DECLARE_PRIVATE(MImSettingsQSettingsBackend) }; //! \internal class MImSettingsQSettingsBackendFactory : public MImSettingsBackendFactory { public: explicit MImSettingsQSettingsBackendFactory(); explicit MImSettingsQSettingsBackendFactory(const QString &organization, const QString &application); virtual ~MImSettingsQSettingsBackendFactory(); virtual MImSettingsBackend *create(const QString &key, QObject *parent); private: QSettings mSettings; }; class MImSettingsQSettingsTemporaryBackendFactory : public MImSettingsBackendFactory { public: explicit MImSettingsQSettingsTemporaryBackendFactory(); virtual ~MImSettingsQSettingsTemporaryBackendFactory(); virtual MImSettingsBackend *create(const QString &key, QObject *parent); private: QTemporaryFile mTempFile; QScopedPointer mSettings; }; #endif // MIMSETTINGSQSETTINGS_H maliit-framework-0.99.1+git20151118+62bd54b/src/mimsubviewoverride.cpp000066400000000000000000000017151262307254400247650ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "mimsubviewoverride.h" #include "mimonscreenplugins.h" MImSubViewOverride::MImSubViewOverride(MImOnScreenPlugins *plugins, QObject *parent) : QObject(parent) , mPlugins(plugins) {} MImSubViewOverride::~MImSubViewOverride() { // This will undo the effects of any other active attribute extension that // currently enabled all subviews! if (not mPlugins.isNull()) { mPlugins.data()->setAllSubViewsEnabled(false); } } maliit-framework-0.99.1+git20151118+62bd54b/src/mimsubviewoverride.h000066400000000000000000000020511262307254400244240ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MIMSUBVIEWOVERRIDE_H #define MIMSUBVIEWOVERRIDE_H #include #include class MImOnScreenPlugins; //! \internal //! \ingroup maliitserver //! \brief A handle class for the enable-all-subviews override which disables the override upon destruction. class MImSubViewOverride : public QObject { Q_OBJECT public: explicit MImSubViewOverride(MImOnScreenPlugins *plugins, QObject *parent = 0); virtual ~MImSubViewOverride(); private: const QPointer mPlugins; }; #endif // MIMSUBVIEWOVERRIDE_H maliit-framework-0.99.1+git20151118+62bd54b/src/minputmethodhost.cpp000066400000000000000000000150221262307254400244450ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "minputmethodhost.h" #include "minputcontextconnection.h" #include "mimpluginmanager.h" #include #include "windowgroup.h" #include MInputMethodHost::MInputMethodHost(const QSharedPointer &inputContextConnection, MIMPluginManager *pluginManager, const QSharedPointer &windowGroup, const QString &plugin, const QString &description) : MAbstractInputMethodHost(), connection(inputContextConnection), pluginManager(pluginManager), inputMethod(0), enabled(false), pluginId(plugin), pluginDescription(description), mWindowGroup(windowGroup) { // nothing } MInputMethodHost::~MInputMethodHost() { // nothing } void MInputMethodHost::setEnabled(bool enabled) { this->enabled = enabled; } void MInputMethodHost::setInputMethod(MAbstractInputMethod *inputMethod) { this->inputMethod = inputMethod; } int MInputMethodHost::contentType(bool &valid) { return connection->contentType(valid); } bool MInputMethodHost::correctionEnabled(bool &valid) { return connection->correctionEnabled(valid); } bool MInputMethodHost::predictionEnabled(bool &valid) { return connection->predictionEnabled(valid); } bool MInputMethodHost::autoCapitalizationEnabled(bool &valid) { return connection->autoCapitalizationEnabled(valid); } bool MInputMethodHost::surroundingText(QString &text, int &cursorPosition) { return connection->surroundingText(text, cursorPosition); } bool MInputMethodHost::hasSelection(bool &valid) { return connection->hasSelection(valid); } QString MInputMethodHost::selection(bool &valid) { return connection->selection(valid); } void MInputMethodHost::registerWindow (QWindow *window, Maliit::Position position) { mWindowGroup->setupWindow(window, position); } int MInputMethodHost::preeditClickPos(bool &valid) const { return connection->preeditClickPos(valid); } int MInputMethodHost::inputMethodMode(bool &valid) { return connection->inputMethodMode(valid); } QRect MInputMethodHost::preeditRectangle(bool &valid) { return connection->preeditRectangle(valid); } QRect MInputMethodHost::cursorRectangle(bool &valid) { return connection->cursorRectangle(valid); } bool MInputMethodHost::hiddenText(bool &valid) { return connection->hiddenText(valid); } void MInputMethodHost::sendPreeditString(const QString &string, const QList &preeditFormats, int replacementStart, int replacementLength, int cursorPos) { if (enabled) { connection->sendPreeditString(string, preeditFormats, replacementStart, replacementLength, cursorPos); } } void MInputMethodHost::sendCommitString(const QString &string, int replaceStart, int replaceLength, int cursorPos) { if (enabled) { connection->sendCommitString(string, replaceStart, replaceLength, cursorPos); } } void MInputMethodHost::sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType) { if (enabled) { connection->sendKeyEvent(keyEvent, requestType); } } void MInputMethodHost::notifyImInitiatedHiding() { if (enabled) { connection->notifyImInitiatedHiding(); } } void MInputMethodHost::invokeAction(const QString &action, const QKeySequence &sequence) { if (enabled) { connection->invokeAction(action, sequence); } } void MInputMethodHost::setRedirectKeys(bool redirectEnabled) { if (enabled) { connection->setRedirectKeys(redirectEnabled); } } void MInputMethodHost::setDetectableAutoRepeat(bool autoRepeatEnabled) { if (enabled) { connection->setDetectableAutoRepeat(autoRepeatEnabled); } } void MInputMethodHost::setGlobalCorrectionEnabled(bool correctionEnabled) { if (enabled) { connection->setGlobalCorrectionEnabled(correctionEnabled); } } void MInputMethodHost::switchPlugin(Maliit::SwitchDirection direction) { if (enabled) { pluginManager->switchPlugin(direction, inputMethod); } } void MInputMethodHost::switchPlugin(const QString &pluginName) { if (enabled) { pluginManager->switchPlugin(pluginName, inputMethod); } } void MInputMethodHost::setScreenRegion(const QRegion ®ion, QWindow *window) { mWindowGroup->setScreenRegion(region, window); } void MInputMethodHost::setInputMethodArea(const QRegion ®ion, QWindow *window) { mWindowGroup->setInputMethodArea(region, window); } void MInputMethodHost::setSelection(int start, int length) { if (enabled) { connection->setSelection(start, length); } } QList MInputMethodHost::pluginDescriptions(Maliit::HandlerState state) const { return pluginManager->pluginDescriptions(state); } QList MInputMethodHost::surroundingSubViewDescriptions(Maliit::HandlerState state) const { return pluginManager->surroundingSubViewDescriptions(state); } void MInputMethodHost::setLanguage(const QString &language) { if (enabled) { connection->setLanguage(language); } } void MInputMethodHost::setOrientationAngleLocked(bool) { // NOT implemented. } int MInputMethodHost::anchorPosition(bool &valid) { return connection->anchorPosition(valid); } AbstractPluginSetting *MInputMethodHost::registerPluginSetting(const QString &key, const QString &description, Maliit::SettingEntryType type, const QVariantMap &attributes) { return pluginManager->registerPluginSetting(pluginId, pluginDescription, key, description, type, attributes); } maliit-framework-0.99.1+git20151118+62bd54b/src/minputmethodhost.h000066400000000000000000000112011262307254400241050ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MINPUTMETHODHOST_H #define MINPUTMETHODHOST_H #include class MInputContextConnection; class MIMPluginManager; class MAbstractInputMethod; namespace Maliit { class WindowGroup; } // namespace Maliit class QRegion; using Maliit::Plugins::AbstractPluginSetting; /*! \internal * \ingroup maliitserver * \brief Interface implementation for connecting input method instances to the environment. */ class MInputMethodHost: public MAbstractInputMethodHost { Q_OBJECT public: MInputMethodHost(const QSharedPointer& inputContextConnection, MIMPluginManager *pluginManager, const QSharedPointer &window_group, const QString &plugin, const QString &description); virtual ~MInputMethodHost(); //! if enabled, the plugin associated with this host are allowed to communicate void setEnabled(bool enabled); //! associate input method with this host instance. //! Multiple calls is (currently) undefined behavior. void setInputMethod(MAbstractInputMethod *inputMethod); // \reimp virtual int contentType(bool &valid); virtual bool correctionEnabled(bool &valid); virtual bool predictionEnabled(bool &valid); virtual bool autoCapitalizationEnabled(bool &valid); virtual bool surroundingText(QString &text, int &cursorPosition); virtual bool hasSelection(bool &valid); virtual int inputMethodMode(bool &valid); virtual QRect preeditRectangle(bool &valid); virtual QRect cursorRectangle(bool &valid); virtual int anchorPosition(bool &valid); virtual bool hiddenText(bool &valid); virtual QString selection(bool &valid); virtual void registerWindow (QWindow *window, Maliit::Position position); virtual void sendPreeditString(const QString &string, const QList &preeditFormats, int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); virtual void sendCommitString(const QString &string, int replaceStart = 0, int replaceLength = 0, int cursorPos = -1); virtual void sendKeyEvent(const QKeyEvent &keyEvent, Maliit::EventRequestType requestType = Maliit::EventRequestBoth); virtual void notifyImInitiatedHiding(); virtual void invokeAction(const QString &action, const QKeySequence &sequence); virtual void setRedirectKeys(bool enabled); virtual void setDetectableAutoRepeat(bool enabled); virtual void setGlobalCorrectionEnabled(bool enabled); virtual void switchPlugin(Maliit::SwitchDirection direction); virtual void switchPlugin(const QString &pluginName); virtual void setScreenRegion(const QRegion ®ion, QWindow *window = 0); virtual void setInputMethodArea(const QRegion ®ion, QWindow *window = 0); virtual void setSelection(int start, int length); virtual QList pluginDescriptions(Maliit::HandlerState state) const; virtual int preeditClickPos(bool &valid) const; virtual QList surroundingSubViewDescriptions(Maliit::HandlerState state) const; virtual void setLanguage(const QString &language); //! Only empty implementation provided. virtual void setOrientationAngleLocked(bool lock); virtual AbstractPluginSetting *registerPluginSetting(const QString &key, const QString &description, Maliit::SettingEntryType type, const QVariantMap &attributes); // \reimp_end private: Q_DISABLE_COPY(MInputMethodHost) QSharedPointer connection; MIMPluginManager *pluginManager; MAbstractInputMethod *inputMethod; bool enabled; QString pluginId; QString pluginDescription; QSharedPointer mWindowGroup; }; //! \internal_end #endif maliit-framework-0.99.1+git20151118+62bd54b/src/msharedattributeextensionmanager.cpp000066400000000000000000000070351262307254400276760ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "msharedattributeextensionmanager.h" #include "mimsettings.h" struct MSharedAttributeExtensionManagerPluginSetting { MSharedAttributeExtensionManagerPluginSetting(const QString &key, Maliit::SettingEntryType type, QVariantMap attributes) : setting(key), type(type), attributes(attributes) { } MImSettings setting; Maliit::SettingEntryType type; QVariantMap attributes; }; MSharedAttributeExtensionManager::MSharedAttributeExtensionManager() { } MSharedAttributeExtensionManager::~MSharedAttributeExtensionManager() { } void MSharedAttributeExtensionManager::registerPluginSetting(const QString &fullName, Maliit::SettingEntryType type, QVariantMap attributes) { QString key = fullName.section(1, -1); QSharedPointer value(new MSharedAttributeExtensionManagerPluginSetting(key, type, attributes)); sharedAttributeExtensions[key] = value; connect(&value.data()->setting, SIGNAL(valueChanged()), this, SLOT(attributeValueChanged())); } void MSharedAttributeExtensionManager::handleClientDisconnect(unsigned int clientId) { clientIds.removeOne(clientId); } void MSharedAttributeExtensionManager::handleAttributeExtensionRegistered(unsigned int clientId, int id, const QString &attributeExtension) { Q_UNUSED(attributeExtension); if (id != PluginSettings) return; if (clientIds.contains(clientId)) return; clientIds.append(clientId); } void MSharedAttributeExtensionManager::handleAttributeExtensionUnregistered(unsigned int clientId, int id) { if (id != PluginSettings) return; clientIds.removeOne(clientId); } void MSharedAttributeExtensionManager::handleExtendedAttributeUpdate(unsigned int clientId, int id, const QString &target, const QString &targetName, const QString &attribute, const QVariant &value) { Q_UNUSED(clientId); if (id != PluginSettings) return; QString key = QString::fromLatin1("%1/%2/%3").arg(target, targetName, attribute); SharedAttributeExtensionContainer::iterator it = sharedAttributeExtensions.find(key); if (it == sharedAttributeExtensions.end()) return; // TODO error notification if (!validateSettingValue(it->data()->type, it->data()->attributes, value)) return; it->data()->setting.set(value); } void MSharedAttributeExtensionManager::attributeValueChanged() { MImSettings *value = qobject_cast(sender()); if (!value) return; if (sharedAttributeExtensions.find(value->key()) == sharedAttributeExtensions.end()) return; const QString fullName = value->key(); const QString &target = QString::fromLatin1("/") + fullName.section('/', 1, 1); const QString &targetItem = fullName.section('/', 2, -2); const QString &attribute = fullName.section('/', -1, -1); Q_EMIT notifyExtensionAttributeChanged(clientIds, PluginSettings, target, targetItem, attribute, value->value()); } maliit-framework-0.99.1+git20151118+62bd54b/src/msharedattributeextensionmanager.h000066400000000000000000000056721262307254400273500ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Mattia Barbon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MSHAREDATTRIBUTEEXTENSIONMANAGER_H #define MSHAREDATTRIBUTEEXTENSIONMANAGER_H #include #include #include #include class MSharedAttributeExtensionManagerPluginSetting; //! \internal /*! \ingroup maliitserver * \brief Manages attribute extensions shared between clients. * * Currently handles only plugin settings, backed by MImSettings. */ class MSharedAttributeExtensionManager : public QObject { Q_OBJECT public: enum ReservedExtensionIds { PluginSettings = -3, PluginSettingsList = -4 }; MSharedAttributeExtensionManager(); virtual ~MSharedAttributeExtensionManager(); /*! * \brief Add a new setting entry to the extension manager * * \sa Maliit::SettingsEntry, MImPluginSettingsEntry */ void registerPluginSetting(const QString &fullName, Maliit::SettingEntryType type, QVariantMap attributes); public Q_SLOTS: void handleClientDisconnect(unsigned int clientId); void handleAttributeExtensionRegistered(unsigned int clientId, int id, const QString &attributeExtension); void handleAttributeExtensionUnregistered(unsigned int clientId, int id); void handleExtendedAttributeUpdate(unsigned int clientId, int id, const QString &target, const QString &targetName, const QString &attribute, const QVariant &value); Q_SIGNALS: /*! * \brief Emitted when setting value is changed * \param clientIds list of clients subscribed to the value * \param id the unique identifier of a registered extended attribute. * \param target a string specifying the target for the attribute. * \param targetItem the item name. * \param attribute attribute to be changed. * \param value new value. */ void notifyExtensionAttributeChanged(const QList &clientIds, int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value); private: Q_SLOT void attributeValueChanged(); typedef QHash > SharedAttributeExtensionContainer; //! all registered attribute extensions SharedAttributeExtensionContainer sharedAttributeExtensions; QList clientIds; }; #endif // MSHAREDATTRIBUTEEXTENSIONMANAGER_H maliit-framework-0.99.1+git20151118+62bd54b/src/quick/000077500000000000000000000000001262307254400214425ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/src/quick/inputmethodquick.cpp000066400000000000000000000435101262307254400255460ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "inputmethodquick.h" #include "keyoverridequick.h" #include "maliitquick.h" #include #include #include "abstractplatform.h" #include #include #include #include #include namespace Maliit { namespace { const char * const actionKeyName = "actionKey"; QQuickView *createWindow(MAbstractInputMethodHost *host) { QScopedPointer view(new QQuickView); QSurfaceFormat format = view->requestedFormat(); format.setAlphaBufferSize(8); view->setFormat(format); view->setColor(QColor(Qt::transparent)); host->registerWindow(view.data(), Maliit::PositionCenterBottom); return view.take(); } } // unnamed namespace class InputMethodQuickPrivate { Q_DECLARE_PUBLIC(InputMethodQuick) public: InputMethodQuick *const q_ptr; QScopedPointer surface; QRect inputMethodArea; int appOrientation; bool haveFocus; //! current active state Maliit::HandlerState activeState; //! In practice show() and hide() correspond to application SIP (close) //! requests. We track the current shown/SIP requested state using these variables. bool sipRequested; bool sipIsInhibited; QSharedPointer actionKeyOverride; QSharedPointer sentActionKeyOverride; bool active; bool m_surroundingTextValid; QString m_surroundingText; int m_cursorPosition; int m_anchorPosition; bool m_hasSelection; int m_contentType; bool m_predictionEnabled; bool m_autoCapitalizationEnabled; bool m_hiddenText; QSharedPointer m_platform; InputMethodQuickPrivate(MAbstractInputMethodHost *host, InputMethodQuick *im, const QSharedPointer &platform) : q_ptr(im) , surface(createWindow(host)) , appOrientation(0) , haveFocus(false) , activeState(Maliit::OnScreen) , sipRequested(false) , sipIsInhibited(false) , actionKeyOverride(new KeyOverrideQuick()) , sentActionKeyOverride() , active(false) , m_surroundingTextValid(false) , m_cursorPosition(-1) , m_anchorPosition(-1) , m_hasSelection(false) , m_contentType(MaliitQuick::FreeTextContentType) , m_predictionEnabled(true) , m_autoCapitalizationEnabled(true) , m_hiddenText(false) , m_platform(platform) { Q_ASSERT(surface); updateActionKey(MKeyOverride::All); surface->engine()->addImportPath(MALIIT_PLUGINS_DATA_DIR); surface->engine()->rootContext()->setContextProperty("MInputMethodQuick", im); } ~InputMethodQuickPrivate() {} void handleInputMethodAreaUpdate(MAbstractInputMethodHost *host, const QRegion ®ion) { if (not host) { return; } host->setInputMethodArea(region, surface.data()); } void updateActionKey(const MKeyOverride::KeyOverrideAttributes changedAttributes) { actionKeyOverride->applyOverride(sentActionKeyOverride, changedAttributes); } }; InputMethodQuick::InputMethodQuick(MAbstractInputMethodHost *host, const QString &qmlFileName, const QSharedPointer &platform) : MAbstractInputMethod(host) , d_ptr(new InputMethodQuickPrivate(host, this, platform)) { Q_D(InputMethodQuick); d->surface->setSource(QUrl::fromLocalFile(qmlFileName)); propagateScreenSize(); } InputMethodQuick::~InputMethodQuick() {} void InputMethodQuick::handleFocusChange(bool focusIn) { Q_D(InputMethodQuick); d->haveFocus = focusIn; Q_EMIT focusTargetChanged(focusIn); } void InputMethodQuick::show() { Q_D(InputMethodQuick); d->sipRequested = true; if (d->sipIsInhibited) { return; } handleAppOrientationChanged(d->appOrientation); if (d->activeState == Maliit::OnScreen) { d->surface->setGeometry(QRect(QPoint(), QGuiApplication::primaryScreen()->availableSize())); d->surface->show(); setActive(true); } } void InputMethodQuick::hide() { Q_D(InputMethodQuick); if (!d->sipRequested) { return; } d->sipRequested = false; setActive(false); const QRegion r; d->handleInputMethodAreaUpdate(inputMethodHost(), r); } void InputMethodQuick::update() { Q_D(InputMethodQuick); bool emitSurroundingText = false; bool emitSurroundingTextValid = false; bool emitCursorPosition = false; bool emitAnchorPosition = false; bool emitSelection = false; bool emitContentType = false; bool emitAutoCapitalization = false; bool emitPredictionEnabled = false; bool emitHiddenText = false; QString newSurroundingText; int newCursorPosition = -1; inputMethodHost()->surroundingText(newSurroundingText, newCursorPosition); if (newSurroundingText != d->m_surroundingText) { d->m_surroundingText = newSurroundingText; emitSurroundingText = true; } bool newSurroundingTextValid = !newSurroundingText.isNull(); if (newSurroundingTextValid != d->m_surroundingTextValid) { d->m_surroundingTextValid = newSurroundingTextValid; emitSurroundingTextValid = true; } if (newCursorPosition != d->m_cursorPosition) { d->m_cursorPosition = newCursorPosition; emitCursorPosition = true; } bool valid; int newAnchorPosition = inputMethodHost()->anchorPosition(valid); if (!valid) { newAnchorPosition = -1; } if (newAnchorPosition != d->m_anchorPosition) { d->m_anchorPosition = newAnchorPosition; emitAnchorPosition = true; } bool newHasSelection = inputMethodHost()->hasSelection(valid); if (!valid) { newHasSelection = false; } if (newHasSelection != d->m_hasSelection) { d->m_hasSelection = newHasSelection; emitSelection = true; } int newContentType = inputMethodHost()->contentType(valid); if (!valid) { newContentType = MaliitQuick::FreeTextContentType; } if (newContentType != d->m_contentType) { d->m_contentType = newContentType; emitContentType = true; } bool newAutoCapitalizationEnabled = inputMethodHost()->autoCapitalizationEnabled(valid); if (!valid) { newAutoCapitalizationEnabled = true; } if (newAutoCapitalizationEnabled != d->m_autoCapitalizationEnabled) { d->m_autoCapitalizationEnabled = newAutoCapitalizationEnabled; emitAutoCapitalization = true; } bool newPredictionEnabled = inputMethodHost()->predictionEnabled(valid); if (!valid) { newPredictionEnabled = true; } if (newPredictionEnabled != d->m_predictionEnabled) { d->m_predictionEnabled = newPredictionEnabled; emitPredictionEnabled = true; } bool newHiddenText = inputMethodHost()->hiddenText(valid); if (!valid) { newHiddenText = false; } if (newHiddenText != d->m_hiddenText) { d->m_hiddenText = newHiddenText; emitHiddenText = true; } if (emitSurroundingText) { Q_EMIT surroundingTextChanged(); } if (emitSurroundingTextValid) { Q_EMIT surroundingTextValidChanged(); } if (emitCursorPosition) { Q_EMIT cursorPositionChanged(); } if (emitAnchorPosition) { Q_EMIT anchorPositionChanged(); } if (emitSelection) { Q_EMIT hasSelectionChanged(); } if (emitContentType) { Q_EMIT contentTypeChanged(); } if (emitAutoCapitalization) { Q_EMIT autoCapitalizationChanged(); } if (emitPredictionEnabled) { Q_EMIT predictionEnabledChanged(); } if (emitHiddenText) { Q_EMIT hiddenTextChanged(); } Q_EMIT editorStateUpdate(); } void InputMethodQuick::reset() { Q_EMIT inputMethodReset(); } void InputMethodQuick::handleAppOrientationChanged(int angle) { Q_D(InputMethodQuick); MAbstractInputMethod::handleAppOrientationChanged(angle); if (d->appOrientation != angle) { d->appOrientation = angle; // When emitted, QML Plugin will realice a state // change and update InputMethodArea. Don't propagate those changes except if // VkB is currently showed Q_EMIT appOrientationChanged(d->appOrientation); if (d->sipRequested && !d->sipIsInhibited) { d->handleInputMethodAreaUpdate(inputMethodHost(), inputMethodArea().toRect()); } } } void InputMethodQuick::setState(const QSet &state) { Q_D(InputMethodQuick); if (state.isEmpty()) { return; } if (state.contains(Maliit::OnScreen)) { d->activeState = Maliit::OnScreen; if (d->sipRequested && !d->sipIsInhibited) { show(); // Force reparent of client widgets. } } else { setActive(false); // Allow client to make use of InputMethodArea const QRegion r; d->handleInputMethodAreaUpdate(inputMethodHost(), r); d->activeState = *state.begin(); } } void InputMethodQuick::handleClientChange() { Q_D(InputMethodQuick); if (d->sipRequested) { setActive(false); } } void InputMethodQuick::handleVisualizationPriorityChange(bool inhibitShow) { Q_D(InputMethodQuick); if (d->sipIsInhibited == inhibitShow) { return; } d->sipIsInhibited = inhibitShow; if (d->sipRequested) { if (inhibitShow) { setActive(false); } else { setActive(true); } } } void InputMethodQuick::propagateScreenSize() { const QSize screenSize(QGuiApplication::primaryScreen()->availableSize()); Q_EMIT screenWidthChanged(screenSize.width()); Q_EMIT screenHeightChanged(screenSize.height()); } int InputMethodQuick::screenHeight() const { return QGuiApplication::primaryScreen()->availableSize().height(); } int InputMethodQuick::screenWidth() const { return QGuiApplication::primaryScreen()->availableSize().width(); } int InputMethodQuick::appOrientation() const { Q_D(const InputMethodQuick); return d->appOrientation; } QRectF InputMethodQuick::inputMethodArea() const { Q_D(const InputMethodQuick); return d->inputMethodArea; } void InputMethodQuick::setInputMethodArea(const QRectF &area) { Q_D(InputMethodQuick); if (d->inputMethodArea != area.toRect()) { d->inputMethodArea = area.toRect(); d->handleInputMethodAreaUpdate(inputMethodHost(), d->inputMethodArea); Q_EMIT inputMethodAreaChanged(d->inputMethodArea); } } void InputMethodQuick::setScreenRegion(const QRect ®ion) { Q_D(InputMethodQuick); inputMethodHost()->setScreenRegion(region, d->surface.data()); } void InputMethodQuick::sendPreedit(const QString &text, const QVariant &preeditFormats, int replacementStart, int replacementLength, int cursorPos) { QList formatList; if (text.length() > 0 && !preeditFormats.isValid()) { // Fallback formatList.append(Maliit::PreeditTextFormat(0, text.length(), Maliit::PreeditDefault)); } else if (text.length() > 0 && preeditFormats.type() == QVariant::Int) { // format with one type Maliit::PreeditTextFormat format(0, text.length(), static_cast(preeditFormats.toInt())); formatList.append(format); } else if (preeditFormats.type() == QVariant::List) { // formatting as list of three ints: type, start, length QVariantList list = preeditFormats.toList(); for (int i = 0; i < list.size(); ++i) { QVariantList formatTuple = list.at(i).toList(); Maliit::PreeditFace face = Maliit::PreeditDefault; int start = 0; int length = 0; if (formatTuple.length() < 3) { qWarning() << "MInputMethodQuick.sendPreedit() got formatting tuple with less than three parameters"; continue; } face = static_cast(formatTuple.at(0).toInt()); start = qBound(0, formatTuple.at(1).toInt(), text.length()); length = qBound(0, formatTuple.at(2).toInt(), text.length() - start); formatList.append(Maliit::PreeditTextFormat(start, length, face)); } } inputMethodHost()->sendPreeditString(text, formatList, replacementStart, replacementLength, cursorPos); } void InputMethodQuick::sendKey(int key, int modifiers, const QString &text, int type) { if (type == MaliitQuick::KeyPress || type == MaliitQuick::KeyClick) { QKeyEvent event(QEvent::KeyPress, key, (~(Qt::KeyboardModifiers(Qt::NoModifier))) & modifiers, text); inputMethodHost()->sendKeyEvent(event); } if (type == MaliitQuick::KeyRelease || type == MaliitQuick::KeyClick) { QKeyEvent event(QEvent::KeyRelease, key, (~(Qt::KeyboardModifiers(Qt::NoModifier))) & modifiers, text); inputMethodHost()->sendKeyEvent(event); } } void InputMethodQuick::sendCommit(const QString &text, int replaceStart, int replaceLength, int cursorPos) { if (text == "\b") { QKeyEvent event(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); inputMethodHost()->sendKeyEvent(event); } else if ((text == "\r\n") || (text == "\n") || (text == "\r")) { QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); inputMethodHost()->sendKeyEvent(event); } else { inputMethodHost()->sendCommitString(text, replaceStart, replaceLength, cursorPos); } } void InputMethodQuick::pluginSwitchRequired(int switchDirection) { inputMethodHost()->switchPlugin( static_cast(switchDirection)); } void InputMethodQuick::userHide() { hide(); inputMethodHost()->notifyImInitiatedHiding(); } void InputMethodQuick::setKeyOverrides(const QMap > &overrides) { Q_D(InputMethodQuick); const QMap >::const_iterator iter(overrides.find(actionKeyName)); if (d->sentActionKeyOverride) { disconnect(d->sentActionKeyOverride.data(), SIGNAL(keyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes)), this, SLOT(onSentActionKeyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes))); d->sentActionKeyOverride.clear(); } if (iter != overrides.end()) { QSharedPointer sentActionKeyOverride(*iter); if (sentActionKeyOverride) { d->sentActionKeyOverride = sentActionKeyOverride; connect(d->sentActionKeyOverride.data(), SIGNAL(keyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes)), this, SLOT(onSentActionKeyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes))); } } d->updateActionKey(MKeyOverride::All); } QList InputMethodQuick::subViews(Maliit::HandlerState state) const { Q_UNUSED(state); MAbstractInputMethod::MInputMethodSubView sub_view; sub_view.subViewId = ""; sub_view.subViewTitle = ""; QList sub_views; sub_views << sub_view; return sub_views; } void InputMethodQuick::onSentActionKeyAttributesChanged(const QString &, const MKeyOverride::KeyOverrideAttributes changedAttributes) { Q_D(InputMethodQuick); d->updateActionKey(changedAttributes); } KeyOverrideQuick* InputMethodQuick::actionKeyOverride() const { Q_D(const InputMethodQuick); return d->actionKeyOverride.data(); } void InputMethodQuick::activateActionKey() { sendKey(Qt::Key_Return, 0, "\r", MaliitQuick::KeyClick); } bool InputMethodQuick::isActive() const { Q_D(const InputMethodQuick); return d->active; } void InputMethodQuick::setActive(bool enable) { Q_D(InputMethodQuick); if (d->active != enable) { d->active = enable; Q_EMIT activeChanged(); } } bool InputMethodQuick::surroundingTextValid() { Q_D(InputMethodQuick); return d->m_surroundingTextValid; } QString InputMethodQuick::surroundingText() { // Note: fetching value instead of using member variable for allowing connection side to // modify text when sending commit. QString text; int position; inputMethodHost()->surroundingText(text, position); return text; } int InputMethodQuick::cursorPosition() { // see ::surroundingText() QString text; int position; inputMethodHost()->surroundingText(text, position); return position; } int InputMethodQuick::anchorPosition() { Q_D(InputMethodQuick); return d->m_anchorPosition; } bool InputMethodQuick::hasSelection() { Q_D(InputMethodQuick); return d->m_hasSelection; } int InputMethodQuick::contentType() { Q_D(InputMethodQuick); return d->m_contentType; } bool InputMethodQuick::predictionEnabled() { Q_D(InputMethodQuick); return d->m_predictionEnabled; } bool InputMethodQuick::autoCapitalizationEnabled() { Q_D(InputMethodQuick); return d->m_autoCapitalizationEnabled; } bool InputMethodQuick::hiddenText() { Q_D(InputMethodQuick); return d->m_hiddenText; } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/quick/inputmethodquick.h000066400000000000000000000221621262307254400252130ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_INPUT_METHOD_QUICK_H #define MALIIT_INPUT_METHOD_QUICK_H #include #include #include "maliitquick.h" #include #include #include #include #include namespace Maliit { class AbstractPlatform; class InputMethodQuickPrivate; class KeyOverrideQuick; //! \brief Maliit::InputMethodQuick is used for QML-based input method plugins. //! //! It defines the interface between framework, applications and QML-based input //! methods. Instead of allowing QML-based input methods to use the //! MAbstractInputMethodHost interface directly, this class will forward the //! necessary requests. //! QML-based input methods on the other hand can use the properties of this //! class to respond to requests from the framework. class InputMethodQuick : public MAbstractInputMethod { Q_OBJECT //! Propagates screen width to QML components. Q_PROPERTY(int screenWidth READ screenWidth NOTIFY screenWidthChanged) //! Propagates screen height to QML components. Q_PROPERTY(int screenHeight READ screenHeight NOTIFY screenHeightChanged) //! Propagates application orientation to QML components. Q_PROPERTY(int appOrientation READ appOrientation NOTIFY appOrientationChanged) //! Propagates action key override to QML components. Q_PROPERTY(Maliit::KeyOverrideQuick *actionKeyOverride READ actionKeyOverride NOTIFY actionKeyOverrideChanged) //! Property for whether input method is active Q_PROPERTY(bool active READ isActive NOTIFY activeChanged) Q_PROPERTY(bool surroundingTextValid READ surroundingTextValid NOTIFY surroundingTextValidChanged) Q_PROPERTY(QString surroundingText READ surroundingText NOTIFY surroundingTextChanged) Q_PROPERTY(int cursorPosition READ cursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(int anchorPosition READ anchorPosition NOTIFY anchorPositionChanged) Q_PROPERTY(bool hasSelection READ hasSelection NOTIFY hasSelectionChanged) Q_PROPERTY(int contentType READ contentType NOTIFY contentTypeChanged) Q_PROPERTY(bool predictionEnabled READ predictionEnabled NOTIFY predictionEnabledChanged) Q_PROPERTY(bool autoCapitalizationEnabled READ autoCapitalizationEnabled NOTIFY autoCapitalizationChanged) Q_PROPERTY(bool hiddenText READ hiddenText NOTIFY hiddenTextChanged) public: //! Constructor //! \param host serves as communication link to framework and application. Managed by framework. //! \param qmlFileName the QML file that will be loaded. //! \param platform implementation used for e.g. setting input panel region. explicit InputMethodQuick(MAbstractInputMethodHost *host, const QString &qmlFileName, const QSharedPointer &platform); virtual ~InputMethodQuick(); //! \reimp virtual void show(); virtual void hide(); virtual void update(); virtual void reset(); virtual void handleVisualizationPriorityChange(bool priority); virtual void handleClientChange(); virtual void handleAppOrientationChanged(int angle); virtual void setState(const QSet &state); virtual void setKeyOverrides(const QMap > &overrides); virtual void handleFocusChange(bool focusIn); QList subViews(Maliit::HandlerState state) const; //! \reimp_end //! Propagates screen size to QML components. void propagateScreenSize(); //! Returns screen height. int screenHeight() const; //! Returns screen width. int screenWidth() const; //! Returns application orientation. int appOrientation() const; //! Returns input method area. QRectF inputMethodArea() const; //! Sets input method area. Called by QML components. //! area the area consumed by the QML input method. On transitions can reserve target area at start. Q_INVOKABLE void setInputMethodArea(const QRectF &area); //! Sets area input method is actually using from the screen. Q_INVOKABLE void setScreenRegion(const QRect ®ion); //! Returns action key override. KeyOverrideQuick *actionKeyOverride() const; //! Activates action key, that is - sends enter keypress. Q_INVOKABLE void activateActionKey(); //! Return true on input method expected to be shown bool isActive() const; //! Sets input method expected to be shown/hidden void setActive(bool enable); bool surroundingTextValid(); QString surroundingText(); int cursorPosition(); int anchorPosition(); bool hasSelection(); int contentType(); bool predictionEnabled(); bool autoCapitalizationEnabled(); bool hiddenText(); Q_SIGNALS: //! Emitted when screen height changes. void screenHeightChanged(int height); //! Emitted when screen width changes. void screenWidthChanged(int width); //! Emitted when application orientation changes. void appOrientationChanged(int angle); //! Emitted when input method area changes. void inputMethodAreaChanged(const QRect &area); //! Emitted when key action override changes. void actionKeyOverrideChanged(MKeyOverride *override); void activeChanged(); //! Emitted when focus target changes. activeEditor is true if there's an active editor afterwards. void focusTargetChanged(bool activeEditor); //! Emitted when input method state was reset from application side. void inputMethodReset(); //! Emitted last when editor state has updated. In addition change signals are emitted for distinct property changes. void editorStateUpdate(); void surroundingTextValidChanged(); void surroundingTextChanged(); void cursorPositionChanged(); void anchorPositionChanged(); void hasSelectionChanged(); void contentTypeChanged(); void predictionEnabledChanged(); void autoCapitalizationChanged(); void hiddenTextChanged(); public Q_SLOTS: //! Sends preedit string. Called by QML components. See also MAbstractInputMethodHost::sendPreeditString() //! \param text the preedit string. //! \param preeditFormats Selects visual stylings for each part of preedit. The value can be either: //! Maliit.PreeditFace for applying one style for whole string or list of lists containing [PreeditFace, start, length] //! \param replacementStart The position at which characters are to be replaced relative //! from the start of the preedit string. //! \param replacementLength The number of characters to be replaced in the preedit string. //! \param cursorPos The cursur position inside preedit void sendPreedit(const QString &text, const QVariant &preeditFormats = QVariant(), int replacementStart = 0, int replacementLength = 0, int cursorPos = -1); //! Sends an arbitrary key, optionally with modifiers. //! \param key the Qt keycode to be sent, e.g., Qt.Key_Up. //! \param modifiers optional modifiers to send along, like Qt.ControlModifier. //! \param text an optional text to send along with the QKeyEvent. //! \param type MaliitQuick.KeyPress, KeyRelease or KeyClick for both void sendKey(int key, int modifiers = 0, const QString &text = QString(), int type = MaliitQuick::KeyClick); //! Sends commit string. Called by QML components. For params, see also MAbstractInputMethodHost::sendCommitString() //! \param text the commit string. //! \param replaceStart The position at which characters are to be replaced relative to the start of the //! preedit string. //! \param replaceLength The number of characters to be replaced in the preedit string. //! \param cursorPos The cursor position to be set, relative to commit string start. //! Negative values are used as commit string end position. void sendCommit(const QString &text, int replaceStart = 0, int replaceLength = 0, int cursorPos = -1); //! Tells the framework to switch plugins. Called by QML components. void pluginSwitchRequired(int switchDirection); //! Tells the framework to close keyboard. Called by QML components. void userHide(); private: Q_DISABLE_COPY(InputMethodQuick) Q_DECLARE_PRIVATE(InputMethodQuick) const QScopedPointer d_ptr; private Q_SLOTS: //! Propagates change to QML. void onSentActionKeyAttributesChanged(const QString &keyId, const MKeyOverride::KeyOverrideAttributes changedAttributes); }; } // namespace Maliit #endif // MALIIT_INPUT_METHOD_QUICK_H maliit-framework-0.99.1+git20151118+62bd54b/src/quick/inputmethodquickplugin.cpp000066400000000000000000000047471262307254400267760ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "inputmethodquickplugin.h" #include "inputmethodquick.h" #include "maliitquick.h" #include "keyoverridequick.h" #include "abstractplatform.h" #include #include namespace Maliit { class InputMethodQuickPluginPrivate { public: QSharedPointer m_platform; const QString m_filename; const QString m_basename; QSet m_supported_states; InputMethodQuickPluginPrivate(const QString &filename, const QSharedPointer &platform) : m_platform (platform), m_filename(filename), m_basename(QFileInfo(filename).baseName()), m_supported_states() { m_supported_states << Maliit::OnScreen << Maliit::Hardware; } }; InputMethodQuickPlugin::InputMethodQuickPlugin(const QString &filename, const QSharedPointer &platform) : d_ptr(new InputMethodQuickPluginPrivate(filename, platform)) { qmlRegisterUncreatableType("com.meego.maliitquick", 1, 0, "Maliit", "This is the class used to export Maliit Enums"); // this do not have to be included to use it, but it have to be // registered. qmlRegisterUncreatableType ( "com.meego.maliitquick.keyoverridequick", 1, 0, "KeyOverrideQuick", "This registers KeyOverrideQuick" ); } InputMethodQuickPlugin::~InputMethodQuickPlugin() {} MAbstractInputMethod *InputMethodQuickPlugin::createInputMethod(MAbstractInputMethodHost *host) { Q_D(InputMethodQuickPlugin); return new InputMethodQuick(host, d->m_filename, d->m_platform); } QSet InputMethodQuickPlugin::supportedStates() const { Q_D(const InputMethodQuickPlugin); return d->m_supported_states; } QString InputMethodQuickPlugin::name() const { Q_D(const InputMethodQuickPlugin); return d->m_basename; } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/quick/inputmethodquickplugin.h000066400000000000000000000042101262307254400264240ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_INPUT_METHOD_QUICK_PLUGIN_H #define MALIIT_INPUT_METHOD_QUICK_PLUGIN_H #include #include #include #include #include namespace Maliit { class AbstractPlatform; class InputMethodQuickPluginPrivate; //! \brief Creates an input method plugin that allows to use QML. //! //! To create a QML-based virtual keyboard or input method plugin, just drop the //! QML file in plugin directory. If there are more QML files for the plugin //! then make sure to put them into some subdirectory or otherwise Maliit server //! will try to load them as well as separate plugins. //! The QML components can communicate with the framework through the //! Maliit::InputMethodQuick context. //! If the provided Maliit::InputMethodQuick class is not sufficient, then //! reimplement Maliit::InputMethodQuickPlugin::createInputMethodSettings as //! well and create a custom MAbstractInputMethod instance there. class InputMethodQuickPlugin : public Maliit::Plugins::InputMethodPlugin { public: InputMethodQuickPlugin(const QString &filename, const QSharedPointer &platform); virtual ~InputMethodQuickPlugin(); //! \reimp virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host); virtual QSet supportedStates() const; virtual QString name() const; //! \reimp_end private: Q_DISABLE_COPY(InputMethodQuickPlugin) Q_DECLARE_PRIVATE(InputMethodQuickPlugin) const QScopedPointer d_ptr; }; } // namespace Maliit #endif // MALIIT_INPUT_METHOD_QUICK_PLUGIN_H maliit-framework-0.99.1+git20151118+62bd54b/src/quick/keyoverridequick.cpp000066400000000000000000000206401262307254400255350ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include "keyoverridequick.h" #include "keyoverridequick_p.h" namespace Maliit { KeyOverrideQuickPrivate::KeyOverrideQuickPrivate(const QString &label, const QString &icon, bool highlighted, bool enabled) : actualLabel(), actualIcon(), actualHighlighted(false), actualEnabled(false), defaultLabel(label), defaultIcon(icon), defaultHighlighted(highlighted), defaultEnabled(enabled), labelIsOverriden(false), iconIsOverriden(false), highlightedIsOverriden(false), enabledIsOverriden(false) {} KeyOverrideQuick::KeyOverrideQuick() : QObject(), d_ptr(new KeyOverrideQuickPrivate("", "", false, true)) {} KeyOverrideQuick::~KeyOverrideQuick() {} QString KeyOverrideQuick::label() const { Q_D(const KeyOverrideQuick); return d->actualLabel; } QString KeyOverrideQuick::icon() const { Q_D(const KeyOverrideQuick); return d->actualIcon; } bool KeyOverrideQuick::highlighted() const { Q_D(const KeyOverrideQuick); return d->actualHighlighted; } bool KeyOverrideQuick::enabled() const { Q_D(const KeyOverrideQuick); return d->actualEnabled; } QString KeyOverrideQuick::defaultLabel() const { Q_D(const KeyOverrideQuick); return d->defaultLabel; } QString KeyOverrideQuick::defaultIcon() const { Q_D(const KeyOverrideQuick); return d->defaultIcon; } bool KeyOverrideQuick::defaultHighlighted() const { Q_D(const KeyOverrideQuick); return d->defaultHighlighted; } bool KeyOverrideQuick::defaultEnabled() const { Q_D(const KeyOverrideQuick); return d->defaultEnabled; } void KeyOverrideQuick::overrideLabel(const QString &label) { setLabel(label, true); } void KeyOverrideQuick::overrideIcon(const QString &icon) { setIcon(icon, true); } void KeyOverrideQuick::overrideHighlighted(bool highlighted) { setHighlighted(highlighted, true); } void KeyOverrideQuick::overrideEnabled(bool enabled) { setEnabled(enabled, true); } void KeyOverrideQuick::setDefaultLabel(const QString &label) { Q_D(KeyOverrideQuick); if (d->defaultLabel != label) { d->defaultLabel = label; Q_EMIT defaultLabelChanged(label); } if (not d->labelIsOverriden) { useDefaultLabel(); } } void KeyOverrideQuick::setDefaultIcon(const QString &icon) { Q_D(KeyOverrideQuick); if (d->defaultIcon != icon) { d->defaultIcon = icon; Q_EMIT defaultIconChanged(icon); } if (not d->iconIsOverriden) { useDefaultIcon(); } } void KeyOverrideQuick::setDefaultHighlighted(bool highlighted) { Q_D(KeyOverrideQuick); if (d->defaultHighlighted != highlighted) { d->defaultHighlighted = highlighted; Q_EMIT defaultHighlightedChanged(highlighted); } if (not d->highlightedIsOverriden) { useDefaultHighlighted(); } } void KeyOverrideQuick::setDefaultEnabled(bool enabled) { Q_D(KeyOverrideQuick); if (d->defaultEnabled != enabled) { d->defaultEnabled = enabled; Q_EMIT defaultEnabledChanged(enabled); } if (not d->enabledIsOverriden) { useDefaultEnabled(); } } void KeyOverrideQuick::setLabel(const QString &label, bool overriden) { Q_D(KeyOverrideQuick); d->labelIsOverriden = overriden; if (d->actualLabel != label) { d->actualLabel = label; Q_EMIT labelChanged(label); } } void KeyOverrideQuick::setIcon(const QString &icon, bool overriden) { Q_D(KeyOverrideQuick); d->iconIsOverriden = overriden; if (d->actualIcon != icon) { d->actualIcon = icon; Q_EMIT iconChanged(icon); } } void KeyOverrideQuick::setHighlighted(bool highlighted, bool overriden) { Q_D(KeyOverrideQuick); d->highlightedIsOverriden = overriden; if (d->actualHighlighted != highlighted) { d->actualHighlighted = highlighted; Q_EMIT highlightedChanged(highlighted); } } void KeyOverrideQuick::setEnabled(bool enabled, bool overriden) { Q_D(KeyOverrideQuick); d->enabledIsOverriden = overriden; if (d->actualEnabled != enabled) { d->actualEnabled = enabled; Q_EMIT enabledChanged(enabled); } } void KeyOverrideQuick::useDefaultLabel() { Q_D(KeyOverrideQuick); setLabel(d->defaultLabel, false); } void KeyOverrideQuick::useDefaultIcon() { Q_D(KeyOverrideQuick); setIcon(d->defaultIcon, false); } void KeyOverrideQuick::useDefaultHighlighted() { Q_D(KeyOverrideQuick); setHighlighted(d->defaultHighlighted, false); } void KeyOverrideQuick::useDefaultEnabled() { Q_D(KeyOverrideQuick); setEnabled(d->defaultEnabled, false); } void KeyOverrideQuick::applyOverride(const QSharedPointer& keyOverride, const MKeyOverride::KeyOverrideAttributes changedAttributes) { Q_D(KeyOverrideQuick); enum { UseOverride, UseDefault, UseEmpty, UseActual } iconAction(UseEmpty), labelAction(UseEmpty); if (keyOverride) { // label and icon are mutually exclusive. // icons are preferred over labels. // overrides are preferred over defaults. // default value for either icon or label have to be set. // otherwise, it is a programming error. if (not keyOverride->icon().isEmpty()) { iconAction = UseOverride; } else if (not keyOverride->label().isEmpty()) { labelAction = UseOverride; } else if (not d->defaultIcon.isEmpty()) { iconAction = UseDefault; } else if (not d->defaultLabel.isEmpty()) { labelAction = UseDefault; } else { qCritical() << __PRETTY_FUNCTION__ << "- Both label and icon have no default value."; } if (changedAttributes & MKeyOverride::Highlighted) { overrideHighlighted(keyOverride->highlighted()); } if (changedAttributes & MKeyOverride::Enabled) { overrideEnabled(keyOverride->enabled()); } } else { // if no key override is passed then we just set defaults. // this case should happen only at the beginning or when we change focus // to non-input widget from input widget with an attribute extension // attached to it. this of course means that if both default label and // default icon are empty then the key will be empty. but we allow this, // because such situation could happen at the beginning. obviously we // expect a plugin to actually set a default value before it is shown. if (not d->defaultIcon.isEmpty()) { iconAction = UseDefault; } else { labelAction = UseDefault; } if (changedAttributes & MKeyOverride::Highlighted) { useDefaultHighlighted(); } if (changedAttributes & MKeyOverride::Enabled) { useDefaultEnabled(); } } switch (iconAction) { case UseOverride: overrideIcon(keyOverride->icon()); break; case UseDefault: useDefaultIcon(); break; case UseEmpty: overrideIcon(QString()); break; case UseActual: break; default: qCritical() << __PRETTY_FUNCTION__ << "- unknown enum value for iconAction:" << static_cast (iconAction); } switch (labelAction) { case UseOverride: overrideLabel(keyOverride->label()); break; case UseDefault: useDefaultLabel(); break; case UseEmpty: overrideLabel(QString()); break; case UseActual: break; default: qCritical() << __PRETTY_FUNCTION__ << "- unknown enum value for labelAction:" << static_cast (labelAction); } } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/quick/keyoverridequick.h000066400000000000000000000122521262307254400252020ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_QUICK_KEY_OVERRIDE_H #define MALIIT_QUICK_KEY_OVERRIDE_H #include #include #include #include namespace Maliit { class KeyOverrideQuickPrivate; //! KeyOverrideQuick stores some attributes of a key for QtQuick virtual keyboard. class KeyOverrideQuick : public QObject { Q_OBJECT Q_DISABLE_COPY(KeyOverrideQuick) // actual properties Q_PROPERTY(QString label READ label WRITE overrideLabel NOTIFY labelChanged) Q_PROPERTY(QString icon READ icon WRITE overrideIcon NOTIFY iconChanged) Q_PROPERTY(bool highlighted READ highlighted WRITE overrideHighlighted NOTIFY highlightedChanged) Q_PROPERTY(bool enabled READ enabled WRITE overrideEnabled NOTIFY enabledChanged) // default properties Q_PROPERTY(QString defaultLabel READ defaultLabel WRITE setDefaultLabel NOTIFY defaultLabelChanged) Q_PROPERTY(QString defaultIcon READ defaultIcon WRITE setDefaultIcon NOTIFY defaultIconChanged) Q_PROPERTY(bool defaultHighlighted READ defaultHighlighted WRITE setDefaultHighlighted NOTIFY defaultHighlightedChanged) Q_PROPERTY(bool defaultEnabled READ defaultEnabled WRITE setDefaultEnabled NOTIFY defaultEnabledChanged) public: //! Constructor. KeyOverrideQuick(); //! Destructor. virtual ~KeyOverrideQuick(); //! Returns text from the key QString label() const; //! Returns icon name QString icon() const; //! Return true if the key is highlighted; otherwise return false. bool highlighted() const; //! Return true if the key is enabled; otherwise return false. bool enabled() const; //! Returns default text from the key QString defaultLabel() const; //! Returns default icon name QString defaultIcon() const; //! Return true if the key is by default highlighted; otherwise return false. bool defaultHighlighted() const; //! Return true if the key is by default enabled; otherwise return false. bool defaultEnabled() const; public Q_SLOTS: //! Applies overrides given in \a keyOverride. void applyOverride(const QSharedPointer& keyOverride, const MKeyOverride::KeyOverrideAttributes changedAttributes); //! Override actual label. void overrideLabel(const QString &label); //! Override actual icon. void overrideIcon(const QString &icon); //! Override actual highlighted. void overrideHighlighted(bool highlighted); //! Override actual enabled. void overrideEnabled(bool enabled); //! Set default text for the key. void setDefaultLabel(const QString &label); //! Set default icon name. void setDefaultIcon(const QString &icon); //! Set default highlighted state for item. void setDefaultHighlighted(bool highlighted); //! Set default enabled state for item. void setDefaultEnabled(bool enabled); //! Set actual label to use a default one. void useDefaultLabel(); //! Set actual icon to use a default one. void useDefaultIcon(); //! Set actual highlighted to use a default one. void useDefaultHighlighted(); //! Set actual enabled to use a default one. void useDefaultEnabled(); Q_SIGNALS: //! Emitted when actual label is changed. void labelChanged(const QString &label); //! Emitted when actual icon is changed. void iconChanged(const QString &icon); //! Emitted when actual highlighted is changed. void highlightedChanged(bool highlighted); //! Emitted when actual enabled is changed. void enabledChanged(bool enabled); //! Emitted when default label is changed. void defaultLabelChanged(const QString &label); //! Emitted when default icon is changed. void defaultIconChanged(const QString &icon); //! Emitted when default highlighted is changed. void defaultHighlightedChanged(bool highlighted); //! Emitted when default enabled is changed. void defaultEnabledChanged(bool enabled); private: //! Sets actual label and marks it as either overriden or default. void setLabel(const QString &label, bool overriden); //! Sets actual icon and marks it as either overriden or default. void setIcon(const QString &icon, bool overriden); //! Sets actual highlighted and marks it as either overriden or default. void setHighlighted(bool highlighted, bool overriden); //! Sets actual enabled and marks it as either overriden or default. void setEnabled(bool enabled, bool overriden); Q_DECLARE_PRIVATE(KeyOverrideQuick) const QScopedPointer d_ptr; }; } // namespace Maliit #endif // MALIIT_QUICK_KEY_OVERRIDE_H maliit-framework-0.99.1+git20151118+62bd54b/src/quick/keyoverridequick_p.h000066400000000000000000000023251262307254400255210ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_QUICK_KEY_OVERRIDE_P_H #define MALIIT_QUICK_KEY_OVERRIDE_P_H namespace Maliit { class KeyOverrideQuickPrivate { Q_DISABLE_COPY(KeyOverrideQuickPrivate) public: KeyOverrideQuickPrivate(const QString &label, const QString &icon, bool highlighted, bool enabled); QString actualLabel; QString actualIcon; bool actualHighlighted; bool actualEnabled; QString defaultLabel; QString defaultIcon; bool defaultHighlighted; bool defaultEnabled; bool labelIsOverriden; bool iconIsOverriden; bool highlightedIsOverriden; bool enabledIsOverriden; }; } // namespace Maliit #endif // MALIIT_QUICK_KEY_OVERRIDE_P_H maliit-framework-0.99.1+git20151118+62bd54b/src/quick/maliitquick.h000066400000000000000000000034541262307254400241350ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_KEYBOARD_QUICK_H #define MALIIT_KEYBOARD_QUICK_H #include #include //! \brief MaliitQuick exposes Maliit enums to QML-based input methods class MaliitQuick: public QObject { Q_OBJECT Q_ENUMS(SwitchDirection) Q_ENUMS(ContentType) Q_ENUMS(KeyEvent) Q_ENUMS(PreeditFace) public: //! This enum defines direction of plugin switching enum SwitchDirection { SwitchUndefined = Maliit::SwitchUndefined, //!< Special value for uninitialized variables SwitchForward = Maliit::SwitchForward, //!< Activate next plugin SwitchBackward = Maliit::SwitchBackward //!< Activate previous plugin }; enum ContentType { FreeTextContentType = Maliit::FreeTextContentType, NumberContentType = Maliit::NumberContentType, PhoneNumberContentType = Maliit::PhoneNumberContentType, EmailContentType = Maliit::EmailContentType, UrlContentType = Maliit::UrlContentType, CustomContentType = Maliit::CustomContentType }; enum KeyEvent { KeyPress, KeyRelease, KeyClick }; enum PreeditFace { PreeditDefault = Maliit::PreeditDefault, PreeditNoCandidates = Maliit::PreeditNoCandidates, PreeditKeyPress = Maliit::PreeditKeyPress }; }; #endif // MALIIT_KEYBOARD_QUICK_H maliit-framework-0.99.1+git20151118+62bd54b/src/src.pro000066400000000000000000000124241262307254400216420ustar00rootroot00000000000000include(../config.pri) TOP_DIR = .. VERSION = $$MALIIT_ABI_VERSION TEMPLATE = lib TARGET = $$TOP_DIR/lib/$$MALIIT_PLUGINS_LIB # Input PLUGIN_HEADERS_PUBLIC = \ maliit/plugins/inputmethodplugin.h \ maliit/plugins/abstractinputmethod.h \ maliit/plugins/abstractinputmethodhost.h \ maliit/plugins/keyoverride.h \ maliit/plugins/keyoverridedata.h \ maliit/plugins/attributeextension.h \ maliit/plugins/extensionevent.h \ maliit/plugins/updateevent.h \ maliit/plugins/updatereceiver.h \ maliit/plugins/plugindescription.h \ maliit/plugins/subviewdescription.h \ maliit/plugins/abstractpluginsetting.h \ PLUGIN_SOURCES += \ maliit/plugins/abstractinputmethod.cpp \ maliit/plugins/abstractinputmethodhost.cpp \ maliit/plugins/keyoverride.cpp \ maliit/plugins/keyoverridedata.cpp \ maliit/plugins/attributeextension.cpp \ maliit/plugins/extensionevent.cpp \ maliit/plugins/updateevent.cpp \ maliit/plugins/updatereceiver.cpp \ maliit/plugins/plugindescription.cpp \ maliit/plugins/subviewdescription.cpp \ PLUGIN_HEADERS_PRIVATE += \ maliit/plugins/keyoverride_p.h \ maliit/plugins/attributeextension_p.h \ maliit/plugins/extensionevent_p.h \ maliit/plugins/updateevent_p.h \ SERVER_HEADERS_PUBLIC += \ mimserver.h \ SERVER_SOURCES += \ mimserver.cpp \ SERVER_HEADERS_PRIVATE += \ mimpluginmanager.h \ mimpluginmanager_p.h \ minputmethodhost.h \ mattributeextensionid.h \ mattributeextensionmanager.h \ msharedattributeextensionmanager.h \ mimhwkeyboardtracker.h \ mimonscreenplugins.h \ mimsubviewoverride.h \ mimserveroptions.h \ windowgroup.h \ windowdata.h \ abstractplatform.h \ unknownplatform.h \ SERVER_SOURCES += \ mimpluginmanager.cpp \ minputmethodhost.cpp \ mattributeextensionid.cpp \ mattributeextensionmanager.cpp \ msharedattributeextensionmanager.cpp \ mimonscreenplugins.cpp \ mimsubviewoverride.cpp \ mimserveroptions.cpp \ windowgroup.cpp \ windowdata.cpp \ abstractplatform.cpp \ unknownplatform.cpp \ !noxcb { SERVER_HEADERS_PRIVATE += xcbplatform.h SERVER_SOURCES += xcbplatform.cpp PKGCONFIG += xcb xcb-xfixes } wayland { SERVER_HEADERS_PRIVATE += waylandplatform.h SERVER_SOURCES += waylandplatform.cpp } SETTINGS_HEADERS_PRIVATE += \ mimsettingsqsettings.h \ mimsettings.h \ SETTINGS_SOURCES += \ mimsettings.cpp \ mimsettingsqsettings.cpp \ QUICK_HEADERS_PRIVATE += \ quick/maliitquick.h \ quick/inputmethodquick.h \ quick/inputmethodquickplugin.h \ quick/keyoverridequick.h \ quick/keyoverridequick_p.h \ QUICK_SOURCES += \ quick/inputmethodquick.cpp \ quick/inputmethodquickplugin.cpp \ quick/keyoverridequick.cpp \ !nohwkeyboard { SERVER_HEADERS_PRIVATE += mimhwkeyboardtracker_p.h SERVER_SOURCES += mimhwkeyboardtracker.cpp enable-contextkit { PKGCONFIG += contextsubscriber-1.0 DEFINES += HAVE_CONTEXTSUBSCRIBER } else { # libudev needed by non-contextkit MImHwKeyboardTracker PKGCONFIG += libudev } } else { SERVER_SOURCES += mimhwkeyboardtracker_stub.cpp } HEADERS += \ $$PLUGIN_HEADERS_PUBLIC \ $$PLUGIN_HEADERS_PRIVATE \ $$SERVER_HEADERS_PUBLIC \ $$SERVER_HEADERS_PRIVATE \ $$SETTINGS_HEADERS_PRIVATE \ $$QUICK_HEADERS_PRIVATE SOURCES += \ $$PLUGIN_SOURCES \ $$SERVER_SOURCES \ $$SETTINGS_SOURCES \ $$QUICK_SOURCES CONFIG += link_pkgconfig QT = core gui gui-private dbus qml quick # coverage flags are off per default, but can be turned on via qmake COV_OPTION=on for(OPTION,$$list($$lower($$COV_OPTION))){ isEqual(OPTION, on){ QMAKE_CXXFLAGS += -ftest-coverage -fprofile-arcs -fno-elide-constructors LIBS += -lgcov } } OBJECTS_DIR = .obj MOC_DIR = .moc QMAKE_CLEAN += $$OBJECTS_DIR/*.gcno $$OBJECTS_DIR/*.gcda target.path += $$LIBDIR plugins_headers.path += $$INCLUDEDIR/$$MALIIT_PLUGINS_HEADER/maliit/plugins plugins_headers.files += $$PLUGIN_HEADERS_PUBLIC server_headers.path += $$INCLUDEDIR/$$MALIIT_SERVER_HEADER server_headers.files += $$SERVER_HEADERS_PUBLIC OTHER_FILES += \ maliit-server.pc.in \ maliit-plugins.pc.in \ libmaliit-plugins.pri OTHER_FILES += \ config.h.in \ maliit-plugins.prf.in \ maliit-defines.prf.in \ outputFiles(config.h maliit-defines.prf maliit-plugins.prf maliit-plugins.pc maliit-server.pc) install_pkgconfig.path = $${LIBDIR}/pkgconfig install_pkgconfig.files += \ $$OUT_PWD/MeegoImFramework.pc \ $$OUT_PWD/maliit-plugins.pc \ $$OUT_PWD/maliit-server.pc \ install_prf.path = $$MALIIT_INSTALL_PRF install_prf.files = $$OUT_PWD/maliit-plugins.prf $$OUT_PWD/maliit-defines.prf INSTALLS += \ target \ plugins_headers \ server_headers \ install_prf \ install_pkgconfig \ include($$TOP_DIR/weston-protocols/libmaliit-weston-protocols.pri) include($$TOP_DIR/connection/libmaliit-connection.pri) include($$TOP_DIR/common/libmaliit-common.pri) maliit-framework-0.99.1+git20151118+62bd54b/src/unknownplatform.cpp000066400000000000000000000015461262307254400243040ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "unknownplatform.h" namespace Maliit { void UnknownPlatform::setupInputPanel(QWindow* window, Maliit::Position position) { Q_UNUSED(window); Q_UNUSED(position); // nothing to do. } void UnknownPlatform::setInputRegion(QWindow* window, const QRegion& region) { Q_UNUSED(window); Q_UNUSED(region); // nothing to do. } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/unknownplatform.h000066400000000000000000000015551262307254400237510ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_UNKNOWN_PLATFORM_H #define MALIIT_UNKNOWN_PLATFORM_H #include "abstractplatform.h" namespace Maliit { class UnknownPlatform : public AbstractPlatform { public: virtual void setupInputPanel(QWindow* window, Maliit::Position position); virtual void setInputRegion(QWindow* window, const QRegion& region); }; } // namespace Maliit #endif // MALIIT_UNKNOWN_PLATFORM_H maliit-framework-0.99.1+git20151118+62bd54b/src/waylandplatform.cpp000066400000000000000000000160211262307254400242360ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include "qwayland-input-method.h" #include #include #include #include #include #include #include "waylandplatform.h" #include "windowdata.h" namespace { QtWayland::wl_input_panel_surface::position maliitToWestonPosition(Maliit::Position position) { switch (position) { case Maliit::PositionCenterBottom: return QtWayland::wl_input_panel_surface::position_center_bottom; default: qWarning() << "Weston only supports center bottom position for top-level surfaces."; return QtWayland::wl_input_panel_surface::position_center_bottom; } } } // unnamed namespace namespace Maliit { class WaylandPlatformPrivate { public: WaylandPlatformPrivate(); ~WaylandPlatformPrivate(); void handleRegistryGlobal(uint32_t name, const char *interface, uint32_t version); void handleRegistryGlobalRemove(uint32_t name); void setupInputSurface(QWindow *window, Maliit::Position position, bool avoid_crash = false); struct wl_registry *m_registry; QScopedPointer m_panel; uint32_t m_panel_name; QVector m_scheduled_windows; }; namespace { void registryGlobal(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { qDebug() << __PRETTY_FUNCTION__; WaylandPlatformPrivate *d = static_cast(data); Q_UNUSED(registry); d->handleRegistryGlobal(name, interface, version); } void registryGlobalRemove(void *data, wl_registry *registry, uint32_t name) { qDebug() << __PRETTY_FUNCTION__; WaylandPlatformPrivate *d = static_cast(data); Q_UNUSED(registry); d->handleRegistryGlobalRemove(name); } const wl_registry_listener maliit_registry_listener = { registryGlobal, registryGlobalRemove }; } // unnamed namespace WaylandPlatformPrivate::WaylandPlatformPrivate() : m_registry(0), m_panel(0), m_panel_name(0), m_scheduled_windows() { wl_display *display = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("display")); if (!display) { qCritical() << __PRETTY_FUNCTION__ << "Failed to get a display."; return; } m_registry = wl_display_get_registry(display); wl_registry_add_listener(m_registry, &maliit_registry_listener, this); // QtWayland will do dispatching for us. } WaylandPlatformPrivate::~WaylandPlatformPrivate() { if (m_registry) { wl_registry_destroy (m_registry); } } void WaylandPlatformPrivate::handleRegistryGlobal(uint32_t name, const char *interface, uint32_t version) { Q_UNUSED(version); qDebug() << __PRETTY_FUNCTION__ << "Name:" << name << "Interface:" << interface; if (!strcmp(interface, "wl_input_panel")) { #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) m_panel.reset(new QtWayland::wl_input_panel(m_registry, name, 1)); #else m_panel.reset(new QtWayland::wl_input_panel(m_registry, name)); #endif m_panel_name = name; Q_FOREACH (const WindowData& data, m_scheduled_windows) { setupInputSurface(data.m_window, data.m_position, true); } m_scheduled_windows.clear(); } } void WaylandPlatformPrivate::handleRegistryGlobalRemove(uint32_t name) { qDebug() << __PRETTY_FUNCTION__ << "Name:" << name; if (m_panel and m_panel_name == name) { m_panel.reset(); } } void WaylandPlatformPrivate::setupInputSurface(QWindow *window, Maliit::Position position, bool avoid_crash) { struct wl_surface *surface = avoid_crash ? 0 : static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window)); struct wl_output *output = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForScreen("output", QGuiApplication::primaryScreen())); if (!surface) { if (avoid_crash) { qDebug() << "Creating surface to avoid crash in QtWayland"; } else { qDebug() << "No wl_surface, calling create."; } qDebug() << __PRETTY_FUNCTION__ << "WId:" << window->winId(); window->create(); } surface = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window)); qDebug() << __PRETTY_FUNCTION__ << "WId:" << window->winId(); if (!surface) { qDebug() << __PRETTY_FUNCTION__ << "Still no surface, giving up."; return; } struct wl_input_panel_surface *ip_surface = m_panel->get_input_panel_surface(surface); QtWayland::wl_input_panel_surface::position weston_position = maliitToWestonPosition(position); wl_input_panel_surface_set_toplevel(ip_surface, output, weston_position); } WaylandPlatform::WaylandPlatform() : d_ptr(new WaylandPlatformPrivate) {} void WaylandPlatform::setupInputPanel(QWindow* window, Maliit::Position position) { // we ignore non toplevel surfaces if (not window or window->parent()) { return; } Q_D(WaylandPlatform); // If we have an input panel, we set up the surface now. Otherwise we // schedule it for later. if (d->m_panel) { d->setupInputSurface(window, position); } else { d->m_scheduled_windows.append(WindowData(window, position)); } } void WaylandPlatform::setInputRegion(QWindow* window, const QRegion& region) { if (not window) { return; } QPlatformNativeInterface *wliface = QGuiApplication::platformNativeInterface(); wl_compositor *wlcompositor = static_cast(wliface->nativeResourceForIntegration("compositor")); wl_region *wlregion = wl_compositor_create_region(wlcompositor); Q_FOREACH (const QRect &rect, region.rects()) { wl_region_add(wlregion, rect.x(), rect.y(), rect.width(), rect.height()); } wl_surface *wlsurface = static_cast(wliface->nativeResourceForWindow("surface", window)); wl_surface_set_input_region(wlsurface, wlregion); wl_region_destroy(wlregion); } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/waylandplatform.h000066400000000000000000000020431262307254400237020ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_WAYLAND_PLATFORM_H #define MALIIT_WAYLAND_PLATFORM_H #include #include "abstractplatform.h" namespace Maliit { class WaylandPlatformPrivate; class WaylandPlatform : public AbstractPlatform { Q_DECLARE_PRIVATE(WaylandPlatform) public: WaylandPlatform(); virtual void setupInputPanel(QWindow* window, Maliit::Position position); virtual void setInputRegion(QWindow* window, const QRegion& region); private: QScopedPointer d_ptr; }; } // namespace Maliit #endif // MALIIT_WAYLAND_PLATFORM_H maliit-framework-0.99.1+git20151118+62bd54b/src/windowdata.cpp000066400000000000000000000012771262307254400232020ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "windowdata.h" namespace Maliit { WindowData::WindowData() : m_window(), m_position(Maliit::PositionCenterBottom) {} WindowData::WindowData(QWindow *window, Maliit::Position position) : m_window(window), m_position(position) {} } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/windowdata.h000066400000000000000000000016061262307254400226430ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_WINDOW_DATA_H #define MALIIT_WINDOW_DATA_H #include #include #include #include namespace Maliit { struct WindowData { // apparently QVector::append() needs it... WindowData(); WindowData(QWindow *window, Maliit::Position position); QPointer m_window; Maliit::Position m_position; QRegion m_inputMethodArea; }; } // namespace Maliit #endif // MALIIT_WINDOW_DATA_H maliit-framework-0.99.1+git20151118+62bd54b/src/windowgroup.cpp000066400000000000000000000113121262307254400234140ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include "abstractplatform.h" #include "windowgroup.h" namespace Maliit { WindowGroup::WindowGroup(const QSharedPointer &platform) : m_platform(platform), m_active(false) { m_hideTimer.setSingleShot(true); m_hideTimer.setInterval(2000); connect(&m_hideTimer, SIGNAL(timeout()), this, SLOT(hideWindows())); } WindowGroup::~WindowGroup() {} void WindowGroup::activate() { m_active = true; m_hideTimer.stop(); } void WindowGroup::deactivate(HideMode mode) { if (m_active) { m_active = false; if (mode == HideImmediate) { hideWindows(); } else { m_hideTimer.start(); } } } void WindowGroup::setupWindow(QWindow *window, Maliit::Position position) { if (window) { if (not containsWindow(window)) { QWindow *parent = window->parent (); if (parent and not containsWindow(parent)) { qWarning () << "Plugin is misbehaving - tried to register a window with yet-unregistered parent!"; return; } m_window_list.append (WindowData(window, position)); window->setFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus); connect (window, SIGNAL (visibleChanged(bool)), this, SLOT (onVisibleChanged(bool))); connect (window, SIGNAL (heightChanged(int)), this, SLOT (updateInputMethodArea())); connect (window, SIGNAL (widthChanged(int)), this, SLOT (updateInputMethodArea())); connect (window, SIGNAL (xChanged(int)), this, SLOT (updateInputMethodArea())); connect (window, SIGNAL (yChanged(int)), this, SLOT (updateInputMethodArea())); m_platform->setupInputPanel(window, position); updateInputMethodArea(); } } } void WindowGroup::setScreenRegion(const QRegion ®ion, QWindow *window) { if (window == 0 && m_window_list.size() > 0) { window = m_window_list.at(0).m_window.data(); } m_platform->setInputRegion(window, region); } void WindowGroup::setInputMethodArea(const QRegion ®ion, QWindow *window) { if (window == 0 && m_window_list.size() > 0) { window = m_window_list.at(0).m_window.data(); } for (int i = 0; i < m_window_list.size(); ++i) { WindowData &data = m_window_list[i]; if (data.m_window == window) { data.m_inputMethodArea = region; break; } } if (m_active) { updateInputMethodArea(); } } void WindowGroup::setApplicationWindow(WId id) { Q_FOREACH (const WindowData &data, m_window_list) { if (data.m_window and not data.m_window->parent()) { m_platform->setApplicationWindow(data.m_window, id); } } } void WindowGroup::onVisibleChanged(bool visible) { if (m_active) { updateInputMethodArea(); } else if (visible) { QWindow *window = qobject_cast(sender()); if (window) { qWarning () << "An inactive plugin is misbehaving - tried to show a window!"; window->setVisible (false); } } } void WindowGroup::updateInputMethodArea() { QRegion new_area; Q_FOREACH (const WindowData &data, m_window_list) { if (data.m_window and not data.m_window->parent() and data.m_window->isVisible() and not data.m_inputMethodArea.isEmpty()) { new_area |= data.m_inputMethodArea.translated(data.m_window->position()); } } if (new_area != m_last_im_area) { m_last_im_area = new_area; Q_EMIT inputMethodAreaChanged(m_last_im_area); } } bool WindowGroup::containsWindow(QWindow *window) { Q_FOREACH (const WindowData &data, m_window_list) { if (data.m_window == window) { return true; } } return false; } void WindowGroup::hideWindows() { m_hideTimer.stop(); Q_FOREACH (const WindowData &data, m_window_list) { if (data.m_window) { data.m_window->setVisible (false); } } updateInputMethodArea(); } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/windowgroup.h000066400000000000000000000033661262307254400230730ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_SERVER_WINDOW_GROUP_H #define MALIIT_SERVER_WINDOW_GROUP_H #include #include #include #include #include #include #include "windowdata.h" #include class QWindow; namespace Maliit { class AbstractPlatform; class WindowGroupPrivate; class WindowGroup : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(WindowGroup) public: enum HideMode { HideImmediate, HideDelayed }; WindowGroup(const QSharedPointer &platform); ~WindowGroup(); void activate(); void deactivate(HideMode mode); void setupWindow(QWindow *window, Maliit::Position position); void setScreenRegion(const QRegion ®ion, QWindow *window); void setInputMethodArea(const QRegion ®ion, QWindow *window); void setApplicationWindow(WId id); Q_SIGNALS: void inputMethodAreaChanged(const QRegion &inputMethodArea); private Q_SLOTS: void hideWindows(); void onVisibleChanged(bool visible); void updateInputMethodArea(); private: bool containsWindow(QWindow *window); QSharedPointer m_platform; QVector m_window_list; QRegion m_last_im_area; bool m_active; QTimer m_hideTimer; }; } // namespace Maliit #endif // MALIIT_SERVER_WINDOW_GROUP_H maliit-framework-0.99.1+git20151118+62bd54b/src/xcbplatform.cpp000066400000000000000000000104421262307254400233540ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include #include #include #include #include #include #include #include #include "xcbplatform.h" namespace Maliit { void XCBPlatform::setupInputPanel(QWindow* window, Maliit::Position position) { Q_UNUSED(position); if (not window) { return; } // set window type as input, supported by at least mcompositor QPlatformNativeInterface *xcbiface = QGuiApplication::platformNativeInterface(); xcb_connection_t *xcbConnection = static_cast(xcbiface->nativeResourceForWindow("connection", window)); if (!xcbConnection) { qWarning("Unable to get Xcb connection"); return; } const char * windowType = "_NET_WM_WINDOW_TYPE"; const char * windowTypeInput = "_NET_WM_WINDOW_TYPE_INPUT"; xcb_intern_atom_cookie_t windowTypeCookie = xcb_intern_atom(xcbConnection, false, strlen(windowType), windowType); xcb_intern_atom_cookie_t typeInputCookie = xcb_intern_atom(xcbConnection, false, strlen(windowTypeInput), windowTypeInput); xcb_atom_t windowTypeAtom; xcb_atom_t windowTypeInputAtom; xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcbConnection, windowTypeCookie, 0); if (reply) { windowTypeAtom = reply->atom; free(reply); } else { qWarning("Unable to fetch window type atom"); return; } reply = xcb_intern_atom_reply(xcbConnection, typeInputCookie, 0); if (reply) { windowTypeInputAtom = reply->atom; free(reply); } else { qWarning("Unable to fetch window type input atom"); return; } xcb_change_property(xcbConnection, XCB_PROP_MODE_REPLACE, window->winId(), windowTypeAtom, XCB_ATOM_ATOM, 32, 1, &windowTypeInputAtom); } void XCBPlatform::setInputRegion(QWindow* window, const QRegion& region) { if (not window) { return; } QVector xcbrects; const QVector rects(region.rects()); xcbrects.reserve(rects.size()); Q_FOREACH (const QRect &rect, rects) { xcb_rectangle_t xcbrect; xcbrect.x = rect.x(); xcbrect.y = rect.y(); xcbrect.width = rect.width(); xcbrect.height = rect.height(); xcbrects.append (xcbrect); } QPlatformNativeInterface *xcbiface = QGuiApplication::platformNativeInterface(); xcb_connection_t *xcbconnection = static_cast(xcbiface->nativeResourceForWindow("connection", window)); xcb_xfixes_region_t xcbregion = xcb_generate_id(xcbconnection); xcb_xfixes_create_region(xcbconnection, xcbregion, xcbrects.size(), xcbrects.constData()); xcb_window_t xcbwindow = window->winId(); xcb_xfixes_set_window_shape_region(xcbconnection, xcbwindow, XCB_SHAPE_SK_BOUNDING, 0, 0, 0); xcb_xfixes_set_window_shape_region(xcbconnection, xcbwindow, XCB_SHAPE_SK_INPUT, 0, 0, xcbregion); xcb_xfixes_destroy_region(xcbconnection, xcbregion); } void XCBPlatform::setApplicationWindow(QWindow *window, WId appWindowId) { qDebug() << "Xcb platform setting transient target" << QString("0x%1").arg(QString::number(appWindowId, 16)) << "for" << QString("0x%1").arg(QString::number(window->winId(), 16)); QPlatformNativeInterface *xcbiface = QGuiApplication::platformNativeInterface(); xcb_connection_t *xcbConnection = static_cast(xcbiface->nativeResourceForWindow("connection", window)); xcb_change_property(xcbConnection, XCB_PROP_MODE_REPLACE, window->winId(), XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1, &appWindowId); } } // namespace Maliit maliit-framework-0.99.1+git20151118+62bd54b/src/xcbplatform.h000066400000000000000000000016461262307254400230270ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2013 Openismus GmbH * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MALIIT_XCB_PLATFORM_H #define MALIIT_XCB_PLATFORM_H #include "abstractplatform.h" namespace Maliit { class XCBPlatform : public AbstractPlatform { public: virtual void setupInputPanel(QWindow* window, Maliit::Position position); virtual void setInputRegion(QWindow* window, const QRegion& region); virtual void setApplicationWindow(QWindow *window, WId appWindowId); }; } // namespace Maliit #endif // MALIIT_XCB_PLATFORM_H maliit-framework-0.99.1+git20151118+62bd54b/tests/000077500000000000000000000000001262307254400207015ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/.gitignore000066400000000000000000000000611262307254400226660ustar00rootroot00000000000000*.log.xml tests.xml gen-tests-xml.sh runtests.sh maliit-framework-0.99.1+git20151118+62bd54b/tests/common_check.pri000066400000000000000000000015231262307254400240430ustar00rootroot00000000000000contains(QT_MAJOR_VERSION, 4) { unittest_arguments += -graphicssystem raster } qws { unittest_arguments += -qws } QMAKE_EXTRA_TARGETS += check check.target = check check.commands = \ TESTING_IN_SANDBOX=1 \ TESTPLUGIN_PATH=../plugins \ TESTDATA_PATH=$$PWD \ LD_LIBRARY_PATH=../../lib:../../lib/plugins:../plugins:$(LD_LIBRARY_PATH) \ ./$$TARGET $$unittest_arguments check.depends += $$TARGET QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.commands = ../rt.sh $$TARGET check-xml.depends += $$TARGET # coverage flags are off per default, but can be turned on via qmake COV_OPTION=on for(OPTION,$$list($$lower($$COV_OPTION))){ isEqual(OPTION, on){ QMAKE_CXXFLAGS += -ftest-coverage -fprofile-arcs LIBS += -lgcov } } QMAKE_CLEAN += $$OBJECTS_DIR/*.gcno $$OBJECTS_DIR/*.gcda maliit-framework-0.99.1+git20151118+62bd54b/tests/common_top.pri000066400000000000000000000013031262307254400235640ustar00rootroot00000000000000include(../config.pri) OBJECTS_DIR = .obj MOC_DIR = .moc UTILS_DIR = ../utils QT = core testlib QMAKE_CLEAN += *.log *~ target.path = $$MALIIT_TEST_LIBDIR/$$TARGET INSTALLS += target DEFINES += MALIIT_TEST_DATA_PATH=\\\"$$MALIIT_TEST_LIBDIR\\\" TOP_DIR = ../.. SRC_DIR = $$TOP_DIR/src INCLUDEPATH += . \ $$TOP_DIR \ $$SRC_DIR \ $$TOP_DIR/common \ $$TOP_DIR/connection \ $$UTILS_DIR \ HEADERS += \ $$UTILS_DIR/core-utils.h \ SOURCES += \ $$UTILS_DIR/core-utils.cpp \ code_coverage_option=off for(OPTION,$$list($$lower($$COV_OPTION))){ isEqual(OPTION, on){ code_coverage_option=on } } maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/000077500000000000000000000000001262307254400236015ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/dummyimplugin.cpp000066400000000000000000000011171262307254400272050ustar00rootroot00000000000000#include "dummyimplugin.h" #include "dummyinputmethod.h" #include DummyImPlugin::DummyImPlugin() { allowedStates << Maliit::OnScreen << Maliit::Hardware << Maliit::Accessory; } QString DummyImPlugin::name() const { return "DummyImPlugin"; } MAbstractInputMethod * DummyImPlugin::createInputMethod(MAbstractInputMethodHost *host) { return new DummyInputMethod(host); } QSet DummyImPlugin::supportedStates() const { return allowedStates; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(dummyimplugin, DummyImPlugin) #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/dummyimplugin.h000066400000000000000000000014351262307254400266550ustar00rootroot00000000000000#ifndef DUMMYIMPLUGIN_H #define DUMMYIMPLUGIN_H #include #include //! Dummy input method plugin for ut_mimpluginloader class DummyImPlugin: public QObject, public Maliit::Plugins::InputMethodPlugin { Q_OBJECT Q_INTERFACES(Maliit::Plugins::InputMethodPlugin) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.maliit.tests.dummyimplugin" FILE "dummyimplugin.json") #endif public: DummyImPlugin(); //! \reimp virtual QString name() const; virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host); virtual QSet supportedStates() const; //! \reimp_end public: QSet allowedStates; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/dummyimplugin.json000066400000000000000000000000001262307254400273620ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/dummyimplugin.pro000066400000000000000000000016421262307254400272260ustar00rootroot00000000000000include(../../config.pri) TOP_DIR = ../.. TEMPLATE = lib TARGET = ../plugins/dummyimplugin DEPENDPATH += . include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) CONFIG += plugin HEADERS += \ dummyimplugin.h \ dummyinputmethod.h \ SOURCES += \ dummyimplugin.cpp \ dummyinputmethod.cpp \ OTHER_FILES += \ dummyimplugin.json \ target.path += $$MALIIT_TEST_LIBDIR/plugins INVALIDPLUGINS = ../plugins/libinvalidplugin.so invalidplugins.path = $$MALIIT_TEST_LIBDIR/plugins invalidplugins.files = $$INVALIDPLUGINS INSTALLS += target invalidplugins QMAKE_CLEAN += ../plugins/libdummyimplugin.so QMAKE_EXTRA_TARGETS += check check.target = check check.command = $$system(true) QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.command = $$system(true) QMAKE_EXTRA_TARGETS += memcheck memcheck.target = memcheck memcheck.command = $$system(true) maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/dummyinputmethod.cpp000066400000000000000000000050601262307254400277220ustar00rootroot00000000000000#include "dummyinputmethod.h" #include #include #include DummyInputMethod::DummyInputMethod(MAbstractInputMethodHost *host) : MAbstractInputMethod(host), setStateCount(0), switchContextCallCount(0), directionParam(Maliit::SwitchUndefined), enableAnimationParam(false), pluginsChangedSignalCount(0) { MAbstractInputMethod::MInputMethodSubView sv1; sv1.subViewId = "dummyimsv1"; sv1.subViewTitle = "dummimysv1"; sViews.append(sv1); MAbstractInputMethod::MInputMethodSubView sv2; sv2.subViewId = "dummyimsv2"; sv2.subViewTitle = "dummyimsv2"; sViews.append(sv2); MAbstractInputMethod::MInputMethodSubView sv3; sv3.subViewId = "dummyimsv3"; sv3.subViewTitle = "dummyimsv3"; sViews.append(sv3); activeSView = "dummyimsv1"; connect(host, SIGNAL(pluginsChanged()), this, SLOT(onPluginsChange())); } void DummyInputMethod::setState(const QSet &state) { qDebug() << __PRETTY_FUNCTION__ << state; ++setStateCount; setStateParam = state; QTimer::singleShot(10000, this, SLOT(switchMe())); } void DummyInputMethod::switchMe() { qDebug() << __PRETTY_FUNCTION__; inputMethodHost()->switchPlugin(Maliit::SwitchForward); } void DummyInputMethod::switchMe(const QString &name) { qDebug() << __PRETTY_FUNCTION__; inputMethodHost()->switchPlugin(name); } void DummyInputMethod::onPluginsChange() { ++pluginsChangedSignalCount; } void DummyInputMethod::switchContext(Maliit::SwitchDirection direction, bool enableAnimation) { ++switchContextCallCount; directionParam = direction; enableAnimationParam = enableAnimation; } QList DummyInputMethod::subViews(Maliit::HandlerState state) const { qDebug() << __PRETTY_FUNCTION__; QList svs; if (state == Maliit::OnScreen) { svs = sViews; } return svs; } void DummyInputMethod::setActiveSubView(const QString &sVId, Maliit::HandlerState state) { qDebug() << __PRETTY_FUNCTION__; if (state == Maliit::OnScreen) { Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &sv, sViews) { if (sv.subViewId == sVId) { activeSView = sVId; } } } } QString DummyInputMethod::activeSubView(Maliit::HandlerState state) const { qDebug() << __PRETTY_FUNCTION__; if (state == Maliit::OnScreen) return activeSView; else return QString(); } maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin/dummyinputmethod.h000066400000000000000000000024751262307254400273760ustar00rootroot00000000000000#ifndef DUMMYINPUTMETHOD_H #define DUMMYINPUTMETHOD_H #include #include class DummyInputMethod : public MAbstractInputMethod { Q_OBJECT public: DummyInputMethod(MAbstractInputMethodHost *host); //! \reimp virtual void setState(const QSet &state); virtual void switchContext(Maliit::SwitchDirection direction, bool enableAnimation); virtual QList subViews(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void setActiveSubView(const QString &, Maliit::HandlerState state = Maliit::OnScreen); virtual QString activeSubView(Maliit::HandlerState state = Maliit::OnScreen) const; //! \reimp_end public: int setStateCount; QSet setStateParam; int switchContextCallCount; Maliit::SwitchDirection directionParam; bool enableAnimationParam; int pluginsChangedSignalCount; public Q_SLOTS: void switchMe(); void switchMe(const QString &name); private Q_SLOTS: void onPluginsChange(); private: QList sViews; QString activeSView; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin2/000077500000000000000000000000001262307254400236635ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin2/dummyimplugin2.cpp000066400000000000000000000010211262307254400273430ustar00rootroot00000000000000#include "dummyimplugin2.h" #include QString DummyImPlugin2::name() const { return "DummyImPlugin2"; } MAbstractInputMethod * DummyImPlugin2::createInputMethod(MAbstractInputMethodHost *) { return 0; } QSet DummyImPlugin2::supportedStates() const { QSet result; result << Maliit::OnScreen << Maliit::Hardware << Maliit::Accessory; return result; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(dummyimplugin2, DummyImPlugin2) #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin2/dummyimplugin2.h000066400000000000000000000013241262307254400270160ustar00rootroot00000000000000#ifndef DUMMYIMPLUGIN2_H #define DUMMYIMPLUGIN2_H #include #include //! Dummy input method plugin for ut_mimpluginloader class DummyImPlugin2: public QObject, public Maliit::Plugins::InputMethodPlugin { Q_OBJECT Q_INTERFACES(Maliit::Plugins::InputMethodPlugin) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.maliit.tests.dummyimplugin2" FILE "dummyimplugin2.json") #endif public: //! \reimp virtual QString name() const; virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host); virtual QSet supportedStates() const; //! \reimp_end }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin2/dummyimplugin2.json000066400000000000000000000000001262307254400275260ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin2/dummyimplugin2.pro000066400000000000000000000012761262307254400273750ustar00rootroot00000000000000include(../../config.pri) TOP_DIR = ../.. TEMPLATE = lib TARGET = ../plugins/dummyimplugin2 DEPENDPATH += . include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) CONFIG += plugin HEADERS += dummyimplugin2.h SOURCES += dummyimplugin2.cpp OTHER_FILES += dummyimplugin2.json target.path += $$MALIIT_TEST_LIBDIR/plugins INSTALLS += target QMAKE_CLEAN += ../plugins/libdummyimplugin2.so QMAKE_EXTRA_TARGETS += check check.target = check check.command = $$system(true) QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.command = $$system(true) QMAKE_EXTRA_TARGETS += memcheck memcheck.target = memcheck memcheck.command = $$system(true) maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/000077500000000000000000000000001262307254400236645ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/dummyimplugin3.cpp000066400000000000000000000011611262307254400273520ustar00rootroot00000000000000#include "dummyimplugin3.h" #include "dummyinputmethod3.h" #include DummyImPlugin3::DummyImPlugin3() : setStateCount(0) { allowedStates << Maliit::OnScreen << Maliit::Hardware << Maliit::Accessory; } QString DummyImPlugin3::name() const { return "DummyImPlugin3"; } MAbstractInputMethod * DummyImPlugin3::createInputMethod(MAbstractInputMethodHost *host) { return new DummyInputMethod3(host); } QSet DummyImPlugin3::supportedStates() const { return allowedStates; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(dummyimplugin3, DummyImPlugin3) #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/dummyimplugin3.h000066400000000000000000000015501262307254400270210ustar00rootroot00000000000000#ifndef DUMMYIMPLUGIN3_H #define DUMMYIMPLUGIN3_H #include #include //! Dummy input method plugin for ut_mimpluginloader class DummyImPlugin3: public QObject, public Maliit::Plugins::InputMethodPlugin { Q_OBJECT Q_INTERFACES(Maliit::Plugins::InputMethodPlugin) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.maliit.tests.dummyimplugin3" FILE "dummyimplugin3.json") #endif public: DummyImPlugin3(); //! \reimp virtual QString name() const; virtual MAbstractInputMethod *createInputMethod(MAbstractInputMethodHost *host); virtual QSet supportedStates() const; //! \reimp_end public: int setStateCount; QList setStateParam; QSet allowedStates; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/dummyimplugin3.json000066400000000000000000000000001262307254400275300ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/dummyimplugin3.pro000066400000000000000000000014161262307254400273730ustar00rootroot00000000000000include(../../config.pri) TOP_DIR = ../.. TEMPLATE = lib TARGET = ../plugins/dummyimplugin3 DEPENDPATH += . include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) CONFIG += plugin HEADERS += \ dummyimplugin3.h \ dummyinputmethod3.h \ SOURCES += \ dummyimplugin3.cpp \ dummyinputmethod3.cpp \ OTHER_FILES += \ dummyimplugin3.json \ target.path += $$MALIIT_TEST_LIBDIR/plugins INSTALLS += target QMAKE_CLEAN += ../plugins/libdummyimplugin3.so QMAKE_EXTRA_TARGETS += check check.target = check check.command = $$system(true) QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.command = $$system(true) QMAKE_EXTRA_TARGETS += memcheck memcheck.target = memcheck memcheck.command = $$system(true) maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/dummyinputmethod3.cpp000066400000000000000000000052331262307254400300720ustar00rootroot00000000000000#include "dummyinputmethod3.h" #include #include #include void DummyInputMethod3::addSubView(const QString &id, const QString &title) { MAbstractInputMethod::MInputMethodSubView sv; sv.subViewId = id; sv.subViewTitle = title; sViews.append(sv); } DummyInputMethod3::DummyInputMethod3(MAbstractInputMethodHost *host) : MAbstractInputMethod(host), setStateCount(0), switchContextCallCount(0), directionParam(Maliit::SwitchUndefined), enableAnimationParam(false) { addSubView("dummyim3sv1", "dummyim3sv1"); addSubView("dummyim3sv2", "dummyim3sv2"); addSubView("en_gb", "en_gb"); addSubView("es", "es"); addSubView("fr_fr", "fr_fr"); activeSView = "dummyim3sv1"; // Register setting QVariantMap settingAttributes; settingAttributes[Maliit::SettingEntryAttributes::defaultValue] = "Test"; setting.reset(host->registerPluginSetting("setting", QT_TR_NOOP("Example setting"), Maliit::StringType, settingAttributes)); connect(setting.data(), SIGNAL(valueChanged()), this, SLOT(handleSettingChanged())); } void DummyInputMethod3::setState(const QSet &state) { qDebug() << __PRETTY_FUNCTION__ << state; ++setStateCount; setStateParam = state; } void DummyInputMethod3::switchContext(Maliit::SwitchDirection direction, bool enableAnimation) { ++switchContextCallCount; directionParam = direction; enableAnimationParam = enableAnimation; } QList DummyInputMethod3::subViews(Maliit::HandlerState state) const { qDebug() << __PRETTY_FUNCTION__; QList svs; if (state == Maliit::OnScreen) { svs = sViews; } return svs; } void DummyInputMethod3::setActiveSubView(const QString &sVId, Maliit::HandlerState state) { qDebug() << __PRETTY_FUNCTION__; if (state == Maliit::OnScreen) { Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &sv, sViews) { if (sv.subViewId == sVId) { activeSView = sVId; } } } } QString DummyInputMethod3::activeSubView(Maliit::HandlerState state) const { qDebug() << __PRETTY_FUNCTION__; if (state == Maliit::OnScreen) return activeSView; else return QString(); } void DummyInputMethod3::show() { inputMethodHost()->setScreenRegion(QRegion(0, 0, 100, 100)); Q_EMIT showCalled(); } void DummyInputMethod3::handleSettingChanged() { localSettingValue = setting->value(); } maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugin3/dummyinputmethod3.h000066400000000000000000000026751262307254400275460ustar00rootroot00000000000000#ifndef DUMMYINPUTMETHOD3_H #define DUMMYINPUTMETHOD3_H #include #include #include class DummyInputMethod3 : public MAbstractInputMethod { Q_OBJECT public: DummyInputMethod3(MAbstractInputMethodHost *host); //! \reimp virtual void setState(const QSet &state); virtual void switchContext(Maliit::SwitchDirection direction, bool enableAnimation); virtual QList subViews(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void setActiveSubView(const QString &, Maliit::HandlerState state = Maliit::OnScreen); virtual QString activeSubView(Maliit::HandlerState state = Maliit::OnScreen) const; virtual void show(); //! \reimp_end public: int setStateCount; QSet setStateParam; int switchContextCallCount; Maliit::SwitchDirection directionParam; bool enableAnimationParam; QVariant localSettingValue; QScopedPointer setting; Q_SIGNALS: void showCalled(); private: Q_SLOT void handleSettingChanged(); void addSubView(const QString &id, const QString &title); QList sViews; QString activeSView; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyimplugins.pri000066400000000000000000000003571262307254400245050ustar00rootroot00000000000000 LIBS += \ -L$$TOP_DIR/tests/plugins \ -ldummyimplugin \ -ldummyimplugin2 \ -ldummyimplugin3 \ INCLUDEPATH += \ $$TOP_DIR/tests/dummyimplugin \ $$TOP_DIR/tests/dummyimplugin2 \ $$TOP_DIR/tests/dummyimplugin3 \ maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyplugin/000077500000000000000000000000001262307254400232535ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyplugin/dummyplugin.cpp000066400000000000000000000003101262307254400263230ustar00rootroot00000000000000#include "dummyplugin.h" #include QString DummyPlugin::name() { return "DummyPlugin"; } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(dummyplugin, DummyPlugin) #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyplugin/dummyplugin.h000066400000000000000000000011311262307254400257720ustar00rootroot00000000000000#ifndef DUMMYPLUGIN_H #define DUMMYPLUGIN_H #include class DummyPluginInterface { public: virtual QString name() = 0; }; Q_DECLARE_INTERFACE(DummyPluginInterface, "DummyPluginInterface/1.0") //! Dummy plugin class for ut_mimpluginloader class DummyPlugin: public QObject, public DummyPluginInterface { Q_OBJECT Q_INTERFACES(DummyPluginInterface) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) Q_PLUGIN_METADATA(IID "org.maliit.tests.dummyplugin" FILE "dummyplugin.json") #endif public: virtual QString name(); }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyplugin/dummyplugin.json000066400000000000000000000000001262307254400265060ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/dummyplugin/dummyplugin.pro000066400000000000000000000012571262307254400263540ustar00rootroot00000000000000include(../../config.pri) TOP_DIR = ../.. TEMPLATE = lib TARGET = ../plugins/dummyplugin DEPENDPATH += . include($$TOP_DIR/common/libmaliit-common.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) CONFIG += plugin HEADERS += dummyplugin.h SOURCES += dummyplugin.cpp OTHER_FILES += dummyplugin.json target.path += $$MALIIT_TEST_LIBDIR/plugins INSTALLS += target QMAKE_CLEAN += ../plugins/libdummyplugin.so QMAKE_EXTRA_TARGETS += check check.target = check check.command = $$system(true) QMAKE_EXTRA_TARGETS += check-xml check-xml.target = check-xml check-xml.command = $$system(true) QMAKE_EXTRA_TARGETS += memcheck memcheck.target = memcheck memcheck.command = $$system(true) maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_exampleplugin/000077500000000000000000000000001262307254400242445ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_exampleplugin/.gitignore000066400000000000000000000000211262307254400262250ustar00rootroot00000000000000ft_exampleplugin maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_exampleplugin/ft_exampleplugin.cpp000066400000000000000000000043071262307254400303170ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "ft_exampleplugin.h" #include "core-utils.h" #include "gui-utils.h" #include #include #include #include #include class MIndicatorServiceClient {}; void Ft_ExamplePlugin::initTestCase() { } void Ft_ExamplePlugin::cleanupTestCase() { } void Ft_ExamplePlugin::init() {} void Ft_ExamplePlugin::cleanup() {} void Ft_ExamplePlugin::testFunction_data() { QTest::addColumn("testPluginPath"); // QTest::newRow("Hello world") // << "helloworld/libcxxhelloworldplugin.so"; // QTest::newRow("Override") // << "override/libcxxoverrideplugin.so"; } void Ft_ExamplePlugin::testFunction() { QSKIP("Currently there are no example plugins to test"); QFETCH(QString, testPluginPath); const QDir pluginDir = MaliitTestUtils::isTestingInSandbox() ? QDir(IN_TREE_TEST_PLUGIN_DIR"/cxx") : QDir(MALIIT_TEST_PLUGINS_DIR"/examples/cxx"); const QString pluginPath = pluginDir.absoluteFilePath(testPluginPath); const QString pluginId = QFileInfo(testPluginPath).baseName(); QVERIFY(pluginDir.exists(pluginPath)); QPluginLoader loader(pluginPath); QObject *pluginInstance = loader.instance(); QVERIFY(pluginInstance != 0); Maliit::Plugins::InputMethodPlugin *plugin = qobject_cast(pluginInstance); QVERIFY(plugin != 0); MaliitTestUtils::TestInputMethodHost host(pluginId, plugin->name()); plugin->createInputMethod(&host); QCOMPARE(host.lastCommit, QString("Maliit")); QCOMPARE(host.sendCommitCount, 1); QCOMPARE(host.lastPreedit, QString("Mali")); QCOMPARE(host.sendPreeditCount, 1); } QTEST_MAIN(Ft_ExamplePlugin) maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_exampleplugin/ft_exampleplugin.h000066400000000000000000000015011262307254400277550ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef FT_EXAMPLEPLUGIN_H #define FT_EXAMPLEPLUGIN_H #include #include class Ft_ExamplePlugin : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testFunction_data(); void testFunction(); }; #endif // FT_EXAMPLEPLUGIN_H maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_exampleplugin/ft_exampleplugin.pro000066400000000000000000000006761262307254400303420ustar00rootroot00000000000000include(../common_top.pri) IN_TREE_TEST_PLUGIN_DIR = $$OUT_PWD/../../examples/plugins DEFINES += IN_TREE_TEST_PLUGIN_DIR=\\\"$${IN_TREE_TEST_PLUGIN_DIR}\\\" QT += gui include(../../src/libmaliit-plugins.pri) # For MImInputContextConnection pulled in by TestInputMethodHost include(../../connection/libmaliit-connection.pri) # Input HEADERS += \ ft_exampleplugin.h \ SOURCES += \ ft_exampleplugin.cpp \ include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_mimpluginmanager/000077500000000000000000000000001262307254400247265ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_mimpluginmanager/.gitignore000066400000000000000000000000241262307254400267120ustar00rootroot00000000000000ft_mimpluginmanager maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_mimpluginmanager/ft_mimpluginmanager.cpp000066400000000000000000000266461262307254400314750ustar00rootroot00000000000000#include "ft_mimpluginmanager.h" #include "mkeyboardstatetracker_stub.h" #include "dummyimplugin.h" #include "dummyimplugin3.h" #include "dummyinputmethod.h" #include "dummyinputmethod3.h" #include "core-utils.h" #include "mimsettingsqsettings.h" #include #include #include #include #include #include #include #include #include namespace { const QString pluginName = "DummyImPlugin"; const QString pluginName3 = "DummyImPlugin3"; const QString pluginId = "libdummyimplugin.so"; const QString pluginId3 = "libdummyimplugin3.so"; const QString EnabledPluginsKey = MALIIT_CONFIG_ROOT"onscreen/enabled"; const QString ActivePluginKey = MALIIT_CONFIG_ROOT"onscreen/active"; const QString ConfigRoot = MALIIT_CONFIG_ROOT; const QString MImPluginPaths = ConfigRoot + "paths"; const QString MImPluginActive = ConfigRoot + "activeplugins"; const QString MImPluginDisabled = ConfigRoot + "disabledpluginfiles"; const QString PluginRoot = MALIIT_CONFIG_ROOT"plugins/"; const QString PluginSettings = MALIIT_CONFIG_ROOT"pluginsettings"; const QString MImAccesoryEnabled = MALIIT_CONFIG_ROOT"accessoryenabled"; const MImPluginDescription* findPluginDescriptions(const QList &list, const QString &pluginName) { Q_FOREACH (const MImPluginDescription &desc, list) { if (desc.name() == pluginName) { return &desc; } } return 0; } } // Initialization............................................................ void Ft_MIMPluginManager::initTestCase() { MImSettings::setPreferredSettingsType(MImSettings::TemporarySettings); } void Ft_MIMPluginManager::cleanupTestCase() { } void Ft_MIMPluginManager::init() { MImSettings(MImPluginPaths).set(MaliitTestUtils::getTestPluginPath()); MImSettings(MImPluginDisabled).set(QStringList("libdummyimplugin2.so")); MImSettings(MImPluginActive).set(QStringList("DummyImPlugin")); MImSettings(PluginRoot + "hardware").set(pluginId); MImSettings(PluginRoot + "accessory").set(pluginId3); MImSettings enabledPluginsSettings(EnabledPluginsKey); QStringList enabledPlugins; enabledPlugins << pluginId + ":" + "dummyimsv1"; enabledPlugins << pluginId + ":" + "dummyimsv2"; enabledPlugins << pluginId3 + ":" + "dummyim3sv1"; enabledPlugins << pluginId3 + ":" + "dummyim3sv2"; enabledPluginsSettings.set(enabledPlugins); MImSettings activePluginSettings(ActivePluginKey); QString activePlugin; activePlugin = pluginId + ":" + "dummyimsv1"; activePluginSettings.set(activePlugin); gMKeyboardStateTrackerStub->setOpenState(false); MImSettings(MImAccesoryEnabled).set(QVariant(false)); QSharedPointer icConnection(new MInputContextConnection); subject = new MIMPluginManager(icConnection, QSharedPointer(new Maliit::UnknownPlatform)); } void Ft_MIMPluginManager::cleanup() { delete subject; } // Test methods.............................................................. void Ft_MIMPluginManager::testLoadPlugins() { QStringList loadedPlugins = subject->loadedPluginsNames(); QCOMPARE(loadedPlugins.count(), 2); QVERIFY(loadedPlugins.contains(pluginId)); QVERIFY(loadedPlugins.contains(pluginId3)); QStringList activePlugins = subject->activePluginsNames(); QCOMPARE(activePlugins.count(), 1); QCOMPARE(activePlugins.first(), pluginId); } void Ft_MIMPluginManager::testSwitchPluginState() { MImSettings(MImAccesoryEnabled).set(QVariant(true)); QStringList loadedPlugins = subject->loadedPluginsNames(); QCOMPARE(loadedPlugins.count(), 2); QVERIFY(loadedPlugins.contains(pluginId)); QVERIFY(loadedPlugins.contains(pluginId3)); QStringList activePlugins = subject->activePluginsNames(); QCOMPARE(activePlugins.count(), 1); QCOMPARE(activePlugins.first(), pluginId3); } void Ft_MIMPluginManager::testMultiplePlugins() { //QSKIP("This test fails to activate > 1 plugins, for unknown reasons.", SkipAll); gMKeyboardStateTrackerStub->setOpenState(true); MImSettings(MImAccesoryEnabled).set(QVariant(true)); QStringList loadedPlugins = subject->loadedPluginsNames(); QCOMPARE(loadedPlugins.count(), 2); QVERIFY(loadedPlugins.contains(pluginId)); QVERIFY(loadedPlugins.contains(pluginId3)); QStringList activePlugins = subject->activePluginsNames(); QCOMPARE(activePlugins.count(), 2); QVERIFY(activePlugins.contains(pluginId)); QVERIFY(activePlugins.contains(pluginId3)); } void Ft_MIMPluginManager::testSwitchPluginBySignal() { DummyImPlugin *plugin = 0; QPointer inputMethod = 0; for (MIMPluginManagerPrivate::Plugins::iterator iterator(subject->d_ptr->plugins.begin()); iterator != subject->d_ptr->plugins.end(); ++iterator) { if (pluginName == iterator.key()->name()) { plugin = dynamic_cast(iterator.key()); } } QVERIFY(plugin != 0); inputMethod = dynamic_cast(subject->d_ptr->plugins[plugin].inputMethod); QVERIFY(inputMethod != 0); inputMethod->switchMe(); QStringList activePlugins = subject->activePluginsNames(); QCOMPARE(activePlugins.count(), 1); QVERIFY(activePlugins.contains(pluginId3)); QVERIFY(inputMethod != 0); } void Ft_MIMPluginManager::testSwitchToSpecifiedPlugin() { DummyImPlugin *plugin = 0; QPointer inputMethod = 0; for (MIMPluginManagerPrivate::Plugins::iterator iterator(subject->d_ptr->plugins.begin()); iterator != subject->d_ptr->plugins.end(); ++iterator) { if (pluginName == iterator.key()->name()) { plugin = dynamic_cast(iterator.key()); } } QVERIFY(plugin != 0); inputMethod = dynamic_cast(subject->d_ptr->plugins[plugin].inputMethod); QVERIFY(inputMethod != 0); inputMethod->switchMe(pluginId3); QStringList activePlugins = subject->activePluginsNames(); QCOMPARE(activePlugins.count(), 1); QVERIFY(activePlugins.contains(pluginId3)); QVERIFY(inputMethod != 0); } void Ft_MIMPluginManager::testPluginDescriptions() { QSignalSpy spy(subject, SIGNAL(pluginsChanged())); QVERIFY(spy.isValid()); MImSettings enabledPluginsSettings(EnabledPluginsKey); QStringList enabledPlugins; const MImPluginDescription *description = 0; enabledPlugins << pluginId + ":" + "dummyimsv1"; enabledPluginsSettings.set(enabledPlugins); QCOMPARE(spy.count(), 1); description = findPluginDescriptions(subject->pluginDescriptions(Maliit::OnScreen), pluginName); QVERIFY(description); QVERIFY(description->enabled()); description = findPluginDescriptions(subject->pluginDescriptions(Maliit::OnScreen), pluginName3); QVERIFY(description); QVERIFY(!description->enabled()); description = 0; enabledPlugins << pluginId + ":" + "dummyimsv2"; enabledPluginsSettings.set(enabledPlugins); QCOMPARE(spy.count(), 2); description = findPluginDescriptions(subject->pluginDescriptions(Maliit::OnScreen), pluginName); QVERIFY(description); QVERIFY(description->enabled()); description = findPluginDescriptions(subject->pluginDescriptions(Maliit::OnScreen), pluginName3); QVERIFY(description); QVERIFY(!description->enabled()); description = 0; enabledPlugins << pluginId3 + ":" + "dummyim3sv2"; enabledPluginsSettings.set(enabledPlugins); QCOMPARE(spy.count(), 3); description = findPluginDescriptions(subject->pluginDescriptions(Maliit::OnScreen), pluginName); QVERIFY(description); QVERIFY(description->enabled()); description = findPluginDescriptions(subject->pluginDescriptions(Maliit::OnScreen), pluginName3); QVERIFY(description); QVERIFY(description->enabled()); description = 0; //at least we should not crash here enabledPluginsSettings.set(QStringList()); } Q_DECLARE_METATYPE(QList) void Ft_MIMPluginManager::testPluginSetting() { qRegisterMetaType >(); QString pluginId; QSignalSpy spy(subject->d_ptr->sharedAttributeExtensionManager.data(), SIGNAL(notifyExtensionAttributeChanged(QList,int,QString,QString,QString,QVariant))); QList arguments; DummyImPlugin3 *plugin = 0; DummyInputMethod3 *inputMethod = 0; for (MIMPluginManagerPrivate::Plugins::iterator iterator(subject->d_ptr->plugins.begin()); iterator != subject->d_ptr->plugins.end(); ++iterator) { if (pluginName3 == iterator.key()->name()) { plugin = dynamic_cast(iterator.key()); pluginId = iterator.value().pluginId; } } QVERIFY(plugin != 0); inputMethod = dynamic_cast(subject->d_ptr->plugins[plugin].inputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->setting->value(), QVariant("Test")); QString settingKey = PluginSettings + "/" + pluginId + "/setting"; // tests // - that plugin settings are registered in a per-plugin namespace // - that they are correctly registered in the shared attribute extension manager // - that the data returned to clients reflects plugin settings // - that changing setting value notifies both subscribed clients and the plugin // setting registered in global setting list bool setting_registered = false; Q_FOREACH (const MImPluginSettingsInfo &info, subject->d_ptr->settings) { if (info.plugin_name == pluginId) { setting_registered = true; QCOMPARE(info.plugin_description, QString("DummyImPlugin3")); QCOMPARE(info.entries.count(), 1); QCOMPARE(info.entries[0].description, QString("Example setting")); QCOMPARE(info.entries[0].extension_key, settingKey); QCOMPARE(info.entries[0].type, Maliit::StringType); QCOMPARE(info.entries[0].attributes[Maliit::SettingEntryAttributes::defaultValue], QVariant("Test")); break; } } QVERIFY(setting_registered); // simulate client susbcription subject->d_ptr->sharedAttributeExtensionManager->handleAttributeExtensionRegistered(12, MSharedAttributeExtensionManager::PluginSettings, settingKey); MImSettings setting(settingKey); // setting the value from the server setting.set("Test1"); QCOMPARE(spy.count(), 1); QCOMPARE(inputMethod->setting->value(), QVariant("Test1")); QCOMPARE(inputMethod->localSettingValue, QVariant("Test1")); arguments = spy[0]; QCOMPARE(arguments[2], QVariant("/maliit")); QCOMPARE(arguments[3], QVariant("pluginsettings/" + pluginId)); QCOMPARE(arguments[4], QVariant("setting")); QCOMPARE(arguments[5].value(), QVariant("Test1")); // setting the value from the plugin inputMethod->setting->set("Test2"); QCOMPARE(spy.count(), 2); QCOMPARE(setting.value(), QVariant("Test2")); QCOMPARE(inputMethod->localSettingValue, QVariant("Test2")); arguments = spy[1]; QCOMPARE(arguments[2], QVariant("/maliit")); QCOMPARE(arguments[3], QVariant("pluginsettings/" + pluginId)); QCOMPARE(arguments[4], QVariant("setting")); QCOMPARE(arguments[5].value(), QVariant("Test2")); } QTEST_MAIN(Ft_MIMPluginManager) maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_mimpluginmanager/ft_mimpluginmanager.h000066400000000000000000000011371262307254400311260ustar00rootroot00000000000000#ifndef FT_MIMPLUGINLOADER_H #define FT_MIMPLUGINLOADER_H #include #include class MIMPluginManager; class QGraphicsScene; class Ft_MIMPluginManager : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testLoadPlugins(); void testSwitchPluginState(); void testMultiplePlugins(); void testSwitchPluginBySignal(); void testSwitchToSpecifiedPlugin(); void testPluginDescriptions(); void testPluginSetting(); private: MIMPluginManager *subject; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/ft_mimpluginmanager/ft_mimpluginmanager.pro000066400000000000000000000007631262307254400315030ustar00rootroot00000000000000include(../common_top.pri) QT += gui INCLUDEPATH += \ ../stubs # Input HEADERS += \ ft_mimpluginmanager.h \ ../stubs/mkeyboardstatetracker_stub.h \ ../stubs/fakeproperty.h \ SOURCES += \ ft_mimpluginmanager.cpp \ ../stubs/fakeproperty.cpp \ include($$TOP_DIR/src/libmaliit-plugins.pri) # For MImInputContextConnection pulled in by TestInputMethodHost include($$TOP_DIR/connection/libmaliit-connection.pri) include(../dummyimplugins.pri) include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/qtestlib2junitxml.xsl000066400000000000000000000052451262307254400251430ustar00rootroot00000000000000 Standard maliit-framework-0.99.1+git20151118+62bd54b/tests/sanitychecks/000077500000000000000000000000001262307254400233715ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/sanitychecks/.gitignore000066400000000000000000000000151262307254400253550ustar00rootroot00000000000000sanitychecks maliit-framework-0.99.1+git20151118+62bd54b/tests/sanitychecks/sanitychecks.cpp000066400000000000000000000026001262307254400265630ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "sanitychecks.h" #include "core-utils.h" void DeferredSignalEmitter::emitSignal() { Q_EMIT deferredSignal(); } void SanityChecks::initTestCase() { } void SanityChecks::cleanupTestCase() { } void SanityChecks::init() { } void SanityChecks::cleanup() { } /* Verify that it is possible for asyncronous work to happen using the Qt eventloop: * A callback registered with QTimer:singleShot should be called from the * event loop when creating a QEventloop and executing it. */ void SanityChecks::testAsyncronousCallbacks() { DeferredSignalEmitter emitter; QSignalSpy signalSpy(&emitter, SIGNAL(deferredSignal())); QTimer::singleShot(0, &emitter, SLOT(emitSignal())); QCOMPARE(signalSpy.count(), 0); // Utilty function that executes a QEventLoop MaliitTestUtils::waitForSignal(&emitter, SIGNAL(deferredSignal()), 1000); QCOMPARE(signalSpy.count(), 1); } QTEST_MAIN(SanityChecks) maliit-framework-0.99.1+git20151118+62bd54b/tests/sanitychecks/sanitychecks.h000066400000000000000000000020431262307254400262310ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef SANITYCHECKS_H #define SANITYCHECKS_H #include #include // Will emit the signal from the Qt event loop after being fired. class DeferredSignalEmitter : public QObject { Q_OBJECT public: Q_SIGNAL void deferredSignal(); Q_SLOT void emitSignal(); }; // Tests the assumptions that the unittests rely on. class SanityChecks : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testAsyncronousCallbacks(); }; #endif // SANITYCHECKS_H maliit-framework-0.99.1+git20151118+62bd54b/tests/sanitychecks/sanitychecks.pro000066400000000000000000000002111262307254400265750ustar00rootroot00000000000000include(../common_top.pri) # Input HEADERS += \ sanitychecks.h \ SOURCES += \ sanitychecks.cpp \ include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/stubs/000077500000000000000000000000001262307254400220415ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/stubs/fakeproperty.cpp000066400000000000000000000016751262307254400252710ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "fakeproperty.h" #include FakeProperty::FakeProperty(const QString &key, QObject *parent) : keyName(key), keyValue(QVariant()) { Q_UNUSED(parent); } FakeProperty::~FakeProperty() { } void FakeProperty::setValue(const QVariant &value) { bool changed = false; if (keyValue != value) changed = true; keyValue = value; if (changed) Q_EMIT valueChanged(); } QVariant FakeProperty::value() { return keyValue; } maliit-framework-0.99.1+git20151118+62bd54b/tests/stubs/fakeproperty.h000066400000000000000000000023051262307254400247250ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef FAKEPROPERTY_H #define FAKEPROPERTY_H #include #include #include /** * This file defines FakeGConf class that can be used to store settings * in treelike structure, like MImSettings does. All settings are * stored in-memory only and are valid during the lifetime of FakeGConf * instance. */ /*! * \brief Simple in-memory version of gconf settings database. */ class FakeProperty : public QObject { Q_OBJECT public: FakeProperty(const QString &key, QObject *parent = 0); virtual ~FakeProperty(); QString key() const; void setValue(const QVariant &v); QVariant value(); Q_SIGNALS: void valueChanged(); private: QString keyName; QVariant keyValue; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/stubs/mkeyboardstatetracker_stub.h000066400000000000000000000053141262307254400276440ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef MKEYBOARDSTATETRACKER_STUB_H #define MKEYBOARDSTATETRACKER_STUB_H #include #include "fakeproperty.h" #include "mimhwkeyboardtracker.h" #include "mimhwkeyboardtracker_p.h" /** * MKeyboardStateTracker stub class. * To fake MKeyboardStateTracker operations, derive from this class * and implement the methods you want to fake. Instantiate your * derived stub class and assign it to gMKeyboardStateTracker * global variable. */ class MImHwKeyboardTrackerStub { public: MImHwKeyboardTrackerStub(); virtual void mimHwKeyboardTrackerConstructor(const MImHwKeyboardTracker *instance); virtual bool isPresent(); virtual bool isOpen(); virtual void setOpenState(bool state); protected: FakeProperty openProperty; }; MImHwKeyboardTrackerStub::MImHwKeyboardTrackerStub() : openProperty("/maemo/InternalKeyboard/Open") { } void MImHwKeyboardTrackerStub::mimHwKeyboardTrackerConstructor(const MImHwKeyboardTracker *instance) { openProperty.setValue(QVariant(false)); QObject::connect(&openProperty, SIGNAL(valueChanged()), instance, SIGNAL(stateChanged())); } bool MImHwKeyboardTrackerStub::isPresent() { return true; } bool MImHwKeyboardTrackerStub::isOpen() { return openProperty.value().toBool(); } void MImHwKeyboardTrackerStub::setOpenState(bool state) { openProperty.setValue(QVariant(state)); } MImHwKeyboardTrackerStub gDefaultMKeyboardStateTrackerStub; /** * This is the stub class instance used by the system. If you want to alter behaviour, * derive your stub class from MKeyboardStateTrackerStub, implement the methods you want to * fake, create an instance of your stub class and assign the instance into this global variable. */ MImHwKeyboardTrackerStub *gMKeyboardStateTrackerStub = &gDefaultMKeyboardStateTrackerStub; /** * These are the proxy method implementations of MKeyboardStateTracker. They will * call the stub object methods of the gMKeyboardStateTracker. */ MImHwKeyboardTracker::MImHwKeyboardTracker() { gMKeyboardStateTrackerStub->mimHwKeyboardTrackerConstructor(this); } bool MImHwKeyboardTracker::isPresent() const { return gMKeyboardStateTrackerStub->isPresent(); } bool MImHwKeyboardTracker::isOpen() const { return gMKeyboardStateTrackerStub->isOpen(); } #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/tests.pro000066400000000000000000000012531262307254400225660ustar00rootroot00000000000000include(../config.pri) CONFIG += ordered TEMPLATE = subdirs SUBDIRS += \ dummyimplugin \ dummyimplugin2 \ dummyimplugin3 \ dummyplugin \ sanitychecks \ ut_mattributeextensionmanager \ ut_mkeyoverride \ ft_exampleplugin \ ut_mimsettings \ ut_mimonscreenplugins \ ut_minputmethodquickplugin \ ut_mimserveroptions \ glib { SUBDIRS += ut_maliit_glib_settings } SUBDIRS += \ ut_mimpluginmanager \ ut_mimpluginmanagerconfig \ ft_mimpluginmanager \ QMAKE_EXTRA_TARGETS += check check.target = check check.CONFIG = recursive maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_maliit_glib_settings/000077500000000000000000000000001262307254400256055ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_maliit_glib_settings/.gitignore000066400000000000000000000000301262307254400275660ustar00rootroot00000000000000ut_maliit_glib_settings maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_maliit_glib_settings/mockmaliitserver.c000066400000000000000000000144021262307254400313320ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "mockmaliitserver.h" #include #include #include #include #include #define SERVER_OBJECT_PATH "/com/meego/inputmethod/uiserver1" #define CONTEXT_OBJECT_PATH "/com/meego/inputmethod/inputcontext" struct _MockMaliitServerPriv { GDBusConnection *server_connection; GDBusConnection *client_connection; MaliitServer *server; MaliitContext *context; GThread *thread; GMainContext *thread_context; GMainLoop *thread_loop; GCond thread_cond; GMutex thread_mutex; }; /* Record the call, and respond with a list of settings */ gboolean load_plugin_settings (MaliitServer *server, GDBusMethodInvocation *invocation, const gchar *locale_name G_GNUC_UNUSED, gpointer user_data) { MockMaliitServer *self = user_data; self->load_plugin_settings_called = TRUE; maliit_server_complete_load_plugin_settings(server, invocation); return TRUE; } static gboolean start_server(gpointer user_data) { MockMaliitServer *self = user_data; g_main_context_push_thread_default(self->priv->thread_context); g_mutex_lock(&self->priv->thread_mutex); self->priv->server = maliit_server_skeleton_new(); g_assert_true(g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(self->priv->server), self->priv->server_connection, SERVER_OBJECT_PATH, NULL)); g_signal_connect(self->priv->server, "handle-load-plugin-settings", G_CALLBACK(load_plugin_settings), self); g_cond_signal(&self->priv->thread_cond); g_mutex_unlock(&self->priv->thread_mutex); g_main_context_pop_thread_default(self->priv->thread_context); return G_SOURCE_REMOVE; } static gpointer run_server_thread(gpointer data) { MockMaliitServer *self = data; g_main_context_push_thread_default(self->priv->thread_context); g_main_context_invoke(self->priv->thread_context, start_server, self); self->priv->thread_loop = g_main_loop_new(self->priv->thread_context, FALSE); g_main_loop_run(self->priv->thread_loop); g_main_loop_unref(self->priv->thread_loop); self->priv->thread_loop = NULL; g_main_context_pop_thread_default(self->priv->thread_context); return NULL; } MockMaliitServer * mock_maliit_server_new() { MockMaliitServer *self = g_new0(MockMaliitServer, 1); int server_to_client[2] = { 0 }; int client_to_server[2] = { 0 }; GInputStream *server_input_stream; GOutputStream *server_output_stream; GIOStream *server_stream; GInputStream *client_input_stream; GOutputStream *client_output_stream; GIOStream *client_stream; self->priv = g_new0(MockMaliitServerPriv, 1); g_assert_true(pipe(server_to_client) == 0); g_assert_true(pipe(client_to_server) == 0); server_input_stream = g_unix_input_stream_new(client_to_server[0], TRUE); server_output_stream = g_unix_output_stream_new(server_to_client[1], TRUE); server_stream = g_simple_io_stream_new(server_input_stream, server_output_stream); g_object_unref(server_output_stream); g_object_unref(server_input_stream); self->priv->server_connection = g_dbus_connection_new_sync(server_stream, NULL, G_DBUS_CONNECTION_FLAGS_NONE, NULL, NULL, NULL); g_object_unref(server_stream); g_assert_nonnull(self->priv->server_connection); client_input_stream = g_unix_input_stream_new(server_to_client[0], TRUE); client_output_stream = g_unix_output_stream_new(client_to_server[1], TRUE); client_stream = g_simple_io_stream_new(client_input_stream, client_output_stream); g_object_unref(client_output_stream); g_object_unref(client_input_stream); self->priv->client_connection = g_dbus_connection_new_sync(client_stream, NULL, G_DBUS_CONNECTION_FLAGS_NONE, NULL, NULL, NULL); g_object_unref(client_stream); g_assert_nonnull(self->priv->client_connection); self->priv->thread_context = g_main_context_new(); self->priv->thread = g_thread_new(NULL, run_server_thread, self); g_mutex_lock(&self->priv->thread_mutex); while (!self->priv->server) { g_cond_wait(&self->priv->thread_cond, &self->priv->thread_mutex); } g_mutex_unlock(&self->priv->thread_mutex); return self; } void mock_maliit_server_free(MockMaliitServer *self) { g_clear_object(&self->priv->context); g_clear_object(&self->priv->server); g_clear_object(&self->priv->client_connection); g_clear_object(&self->priv->server_connection); g_free(self->priv); g_free(self); } GDBusConnection * mock_maliit_server_get_bus(MockMaliitServer *self) { return self->priv->client_connection; } maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_maliit_glib_settings/mockmaliitserver.h000066400000000000000000000025571262307254400313470ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 MOCKMALIITSERVER_H #define MOCKMALIITSERVER_H #include #include typedef struct _MockMaliitServerPriv MockMaliitServerPriv; typedef struct { gboolean load_plugin_settings_called; MockMaliitServerPriv *priv; GVariant *settings; /* To be set by tests */ } MockMaliitServer; MockMaliitServer *mock_maliit_server_new(); void mock_maliit_server_free(MockMaliitServer *self); GDBusConnection *mock_maliit_server_get_bus(MockMaliitServer *server); #endif // MOCKMALIITSERVER_H maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_maliit_glib_settings/ut_maliit_glib_settings.c000066400000000000000000000132311262307254400326550ustar00rootroot00000000000000/* This file is part of Maliit framework * * Copyright (C) 2012 Canonical Ltd * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the licence, 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 #include #include "../../maliit-glib/maliitbusprivate.h" #include "mockmaliitserver.h" /** * ut_maliit_glib_settings: Unit tests for the settings API of maliit-glib * * Testing is done using the public API of maliit-glib. * maliit-server is mocked out due to the difficulties of hosting it in * the tests and connecting the client to it (pulls in DBus session). * * --------------- ------------------ * | maliit-glib | | MOCK | * | settings | Connection API | maliit-server | * | component | <----------> | | * --------------- ------------------ */ /* * TODO: * * - Test that maliit_settings_entry_is_value_valid returns FALSE for incorrect values, * and TRUE for correct values; for all of the different setting types. * Simply need to enumerate a set of data and expected result * Each data pair should be registered as a separate test * This can be done with g_test_add_data_func * * - Test that the plugin settings are received correctly, * and that the MaliitSettingsEntry APIs give access to the data. * Can be done the same way as test_load_plugins_settings_returns_settings, * but populating the MockMaliitServer::settings with DBus data. * Verify result through: * maliit_settings_entry_get_description * maliit_settings_entry_get_key * maliit_settings_entry_get_entry_type * maliit_settings_entry_get_value * maliit_settings_entry_get_attributes * maliit_settings_entry_is_current_value_valid * * - Test that maliit_settings_manager_set_preferred_description_locale() * results in the server replying with descriptions in that locale. * Can be done by passing fake Bus settings data, including descriptions * and implementing in MockMaliitServer a translation mechanism that respects * the preferred locale. * * - Test that setting a value using maliit_settings_entry_set_value * results in the server being called with the updated value. * Can be done by observing meego_im_proxy_set_extended_attribute * (wrap this implementation detail in MockMaliitServer) * * - Test that when a setting entry is updated on server side, * the client is notified through MaliitSettingsEntry::value-changed. * Can be done by emulating the meego_imcontext_notify_extended_attribute_changed * from maliit-server (add to MockMaliitServer) */ /** * Test that #MaliitSettingsManager has a default for preferred_description_locale */ void test_preferred_description_locale_default(void) { const gchar *preferred_description_locale = maliit_settings_manager_get_preferred_description_locale(); g_assert_cmpstr(preferred_description_locale, ==, "en"); } /** * Test that #MaliitSettingsManager has a default for preferred_description_locale */ void test_preferred_description_locale_set_get_roundtrip(void) { const char *expected = "no_NB"; maliit_settings_manager_set_preferred_description_locale(expected); const gchar *actual = maliit_settings_manager_get_preferred_description_locale(); g_assert_cmpstr(actual, ==, expected); } void add_gobject_ref_gfunc(gpointer data, gpointer user_data G_GNUC_UNUSED) { g_object_ref(data); } /** * Test that calling maliit_settings_manager_load_plugins will return * a list of settings through the MaliitSettingsManager::plugin-settings-received signal */ void test_load_plugins_settings_returns_settings(void) { MockMaliitServer *server; MaliitSettingsManager *manager; server = mock_maliit_server_new(); server->settings = g_variant_new_parsed("@a(sssia(ssibva{sv})) [('a', 'b', 'c', 42, [])]"); maliit_set_bus(mock_maliit_server_get_bus(server)); manager = maliit_settings_manager_new(); maliit_settings_manager_load_plugin_settings(manager); g_assert(server->load_plugin_settings_called); g_object_unref(manager); maliit_set_bus(NULL); mock_maliit_server_free(server); } void on_signal_received(gpointer instance G_GNUC_UNUSED, gpointer user_data) { gboolean *received = (gboolean *)user_data; *received = TRUE; } int main (int argc, char **argv) { g_test_init(&argc, &argv, NULL); #if !(GLIB_CHECK_VERSION(2, 35, 0)) g_type_init(); #endif g_test_add_func("/ut_maliit_glib_settings/MaliitSettingsManager/preferred_description_locale/default", test_preferred_description_locale_default); g_test_add_func("/ut_maliit_glib_settings/MaliitSettingsManager/preferred_description_locale/set-get-roundtrip", test_preferred_description_locale_set_get_roundtrip); g_test_add_func("/ut_maliit_glib_settings/MaliitSettingsManager/load_plugin_settings/returns-settings", test_load_plugins_settings_returns_settings); return g_test_run(); } ut_maliit_glib_settings.pro000066400000000000000000000004161262307254400331550ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_maliit_glib_settingsinclude(../common_top.pri) CONFIG += link_pkgconfig PKGCONFIG += gio-unix-2.0 SOURCES += \ ut_maliit_glib_settings.c \ mockmaliitserver.c \ HEADERS += \ mockmaliitserver.h include ($$TOP_DIR/maliit-glib/libmaliit-glib.pri) include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mattributeextensionmanager/000077500000000000000000000000001262307254400270615ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mattributeextensionmanager/.gitignore000066400000000000000000000000361262307254400310500ustar00rootroot00000000000000ut_mattributeextensionmanager maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mattributeextensionmanager/toolbar1.xml000066400000000000000000000035161262307254400313330ustar00rootroot00000000000000 maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanager/ut_mimpluginmanager.cpp000066400000000000000000001043041262307254400315170ustar00rootroot00000000000000#include "ut_mimpluginmanager.h" #include "dummyimplugin.h" #include "dummyimplugin3.h" #include "dummyinputmethod.h" #include "dummyinputmethod3.h" #include "minputcontextconnection.h" #include "mimsettingsqsettings.h" #include "core-utils.h" #include #include #include #include #include #include #include #include #include #include #include #include "mattributeextensionmanager.h" #include "msharedattributeextensionmanager.h" typedef QSet HandlerStates; Q_DECLARE_METATYPE(HandlerStates); Q_DECLARE_METATYPE(Maliit::HandlerState); namespace { const QString ConfigRoot = MALIIT_CONFIG_ROOT; const QString MImPluginPaths = ConfigRoot + "paths"; const QString MImPluginDisabled = ConfigRoot + "disabledpluginfiles"; const QString PluginRoot = MALIIT_CONFIG_ROOT"plugins/"; const QString EnabledPluginsKey = MALIIT_CONFIG_ROOT"onscreen/enabled"; const QString ActivePluginKey = MALIIT_CONFIG_ROOT"onscreen/active"; const QString pluginName = "DummyImPlugin"; const QString pluginName2 = "DummyImPlugin2"; const QString pluginName3 = "DummyImPlugin3"; const QString pluginId = "libdummyimplugin.so"; const QString pluginId2 = "libdummyimplugin2.so"; const QString pluginId3 = "libdummyimplugin3.so"; const QString testDirectory = "/ut_mimpluginmanager"; QString Toolbar1 = "/toolbar1.xml"; QString Toolbar2 = "/toolbar2.xml"; const QStringList DefaultEnabledPlugins = QStringList() << pluginId + ":" + "dummyimsv1" << pluginId + ":" + "dummyimsv2" << pluginId3 + ":" + "dummyim3sv1" << pluginId3 + ":" + "dummyim3sv2"; const QStringList DefaultActivePlugin = QStringList() << pluginId + ":" + "dummyimsv1"; const QStringList DefaultBlackList = QStringList() << "libdummyimplugin2.so" << "libmeego-keyboard.so"; } class MInputContextTestConnection : public MInputContextConnection { public: MInputContextTestConnection() : pluginSettingsLoaded_called(0), notifyExtendedAttributeChanged_called(0) { } void pluginSettingsLoaded(int clientId, const QList &info) { pluginSettingsLoaded_called++; pluginSettingsLoaded_clientId = clientId; pluginSettingsLoaded_settings = info; } void notifyExtendedAttributeChanged(const QList &clientIds, int id, const QString &target, const QString &targetItem, const QString &attribute, const QVariant &value) { Q_UNUSED(id); notifyExtendedAttributeChanged_called++; notifyExtendedAttributeChanged_clientIds = clientIds; notifyExtendedAttributeChanged_key = QString("%1/%2/%3").arg(target).arg(targetItem).arg(attribute); notifyExtendedAttributeChanged_value = value; } int pluginSettingsLoaded_called; int pluginSettingsLoaded_clientId; QList pluginSettingsLoaded_settings; int notifyExtendedAttributeChanged_called; QList notifyExtendedAttributeChanged_clientIds; QString notifyExtendedAttributeChanged_key; QVariant notifyExtendedAttributeChanged_value; }; void Ut_MIMPluginManager::initTestCase() { Toolbar1 = MaliitTestUtils::getTestDataPath() + testDirectory + Toolbar1; QVERIFY2(QFile(Toolbar1).exists(), "toolbar1.xml does not exist"); Toolbar2 = MaliitTestUtils::getTestDataPath() + testDirectory + Toolbar2; QVERIFY2(QFile(Toolbar2).exists(), "toolbar2.xml does not exist"); MImSettings::setPreferredSettingsType(MImSettings::TemporarySettings); } void Ut_MIMPluginManager::cleanupTestCase() { } void Ut_MIMPluginManager::init() { MImSettings pathConf(MImPluginPaths); pathConf.set(MaliitTestUtils::getTestPluginPath()); MImSettings blackListConf(MImPluginDisabled); blackListConf.set(DefaultBlackList); MImSettings enabledPluginsSettings(EnabledPluginsKey); enabledPluginsSettings.set(DefaultEnabledPlugins); MImSettings activePluginSettings(ActivePluginKey); activePluginSettings.set(DefaultActivePlugin); QSharedPointer icConnection(new MInputContextTestConnection); manager = new MIMPluginManager(icConnection, QSharedPointer(new Maliit::UnknownPlatform)); connection = icConnection.data(); subject = manager->d_ptr; QVERIFY(subject->activePlugins.size() == 1); Maliit::Plugins::InputMethodPlugin *plugin = 0; plugin = *subject->activePlugins.begin(); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); DummyInputMethod *inputMethod = 0; MAbstractInputMethod *abstractInputMethod = 0; abstractInputMethod = subject->plugins[plugin].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->pluginsChangedSignalCount, 1); inputMethod->setStateCount = 0; } void Ut_MIMPluginManager::cleanup() { delete manager; manager = 0; subject = 0; } // Test methods.............................................................. void Ut_MIMPluginManager::testLoadPlugins() { Maliit::Plugins::InputMethodPlugin *plugin = 0; Maliit::Plugins::InputMethodPlugin *plugin3 = 0; // Initial load based on settings -> DummyImPlugin loaded and activated, // DummyImPlugin3 loaded, DummyPlugin2 not loaded (skipped). Also, // DummyPlugin ignored (it is currently left loaded but even though that // might better be fixed, it is not relevant to this test) and // libinvalidplugin not loaded. The only "test" for these two is that the // test does not crash. (One may also observe the warning/debug messages // concerning loading of those two plugins.) Q_FOREACH(Maliit::Plugins::InputMethodPlugin * plugin, subject->plugins.keys()) { qDebug() << plugin->name(); } QCOMPARE(subject->plugins.size(), 2); QCOMPARE(subject->activePlugins.size(), 1); plugin = *subject->activePlugins.begin(); QCOMPARE(plugin->name(), pluginName); bool dummyImPluginFound = false; bool dummyImPlugin3Found = false; Q_FOREACH(Maliit::Plugins::InputMethodPlugin * plugin, subject->plugins.keys()) { if (plugin->name() == "DummyImPlugin") { dummyImPluginFound = true; } else if (plugin->name() == "DummyImPlugin3") { dummyImPlugin3Found = true; plugin3 = plugin; } } QVERIFY(dummyImPluginFound); QVERIFY(dummyImPlugin3Found); // Try to activate DummyImPlugin again -> ignored subject->activatePlugin(plugin); QCOMPARE(subject->plugins.size(), 2); QVERIFY(subject->activePlugins.size() == 1); plugin = *subject->activePlugins.begin(); QCOMPARE(plugin->name(), pluginName); // Try to activate DummyImPlugin3 -> activated subject->activatePlugin(plugin3); QCOMPARE(subject->plugins.size(), 2); QVERIFY(subject->activePlugins.size() == 2); dummyImPluginFound = false; dummyImPlugin3Found = false; Q_FOREACH(plugin, subject->plugins.keys()) { if (plugin->name() == "DummyImPlugin") { dummyImPluginFound = true; } else if (plugin->name() == "DummyImPlugin3") { dummyImPlugin3Found = true; } } QVERIFY(dummyImPluginFound); QVERIFY(dummyImPlugin3Found); } void Ut_MIMPluginManager::testAddHandlerMap() { Maliit::Plugins::InputMethodPlugin *plugin = 0; subject->addHandlerMap(Maliit::OnScreen, pluginId); subject->addHandlerMap(Maliit::Hardware, pluginId); subject->addHandlerMap(Maliit::Accessory, pluginId3); plugin = subject->handlerToPlugin[Maliit::OnScreen]; QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); plugin = subject->handlerToPlugin[Maliit::Hardware]; QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); plugin = subject->handlerToPlugin[Maliit::Accessory]; QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName3); } void Ut_MIMPluginManager::testSwitchPluginState() { QSet actualState; DummyImPlugin *plugin = 0; DummyImPlugin3 *plugin3 = 0; MAbstractInputMethod *abstractInputMethod = 0; DummyInputMethod *inputMethod = 0; DummyInputMethod3 *inputMethod3 = 0; subject->addHandlerMap(Maliit::OnScreen, pluginId); subject->addHandlerMap(Maliit::Hardware, pluginId); subject->addHandlerMap(Maliit::Accessory, pluginId3); actualState << Maliit::OnScreen; QVERIFY(subject->activePlugins.size() == 1); subject->setActiveHandlers(actualState); QCOMPARE(subject->activePlugins.size(), 1); plugin = dynamic_cast(*subject->activePlugins.begin()); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); abstractInputMethod = subject->plugins[plugin].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->setStateCount, 1); inputMethod->setStateCount = 0; QCOMPARE(inputMethod->setStateParam.size(), 1); QCOMPARE(*inputMethod->setStateParam.begin(), Maliit::OnScreen); actualState.clear(); actualState << Maliit::Hardware; subject->setActiveHandlers(actualState); QCOMPARE(subject->activePlugins.size(), 1); plugin = dynamic_cast(*subject->activePlugins.begin()); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); abstractInputMethod = subject->plugins[plugin].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->setStateCount, 1); inputMethod->setStateCount = 0; QCOMPARE(inputMethod->setStateParam.size(), 1); QCOMPARE(*inputMethod->setStateParam.begin(), Maliit::Hardware); actualState.clear(); actualState << Maliit::Accessory; subject->setActiveHandlers(actualState); QCOMPARE(subject->activePlugins.size(), 1); plugin3 = dynamic_cast(*subject->activePlugins.begin()); QVERIFY(plugin3 != 0); QCOMPARE(plugin3->name(), pluginName3); abstractInputMethod = subject->plugins[plugin3].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod3 = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod3 != 0); QCOMPARE(inputMethod3->setStateCount, 1); inputMethod3->setStateCount = 0; QCOMPARE(inputMethod3->setStateParam.size(), 1); QCOMPARE(*inputMethod3->setStateParam.begin(), Maliit::Accessory); } void Ut_MIMPluginManager::testMultiplePlugins() { QSet actualState; DummyImPlugin *plugin = 0; DummyImPlugin3 *plugin3 = 0; int pluginCount = 0; int plugin3Count = 0; MAbstractInputMethod *abstractInputMethod = 0; DummyInputMethod *inputMethod = 0; DummyInputMethod3 *inputMethod3 = 0; subject->addHandlerMap(Maliit::OnScreen, pluginId); subject->addHandlerMap(Maliit::Hardware, pluginId); subject->addHandlerMap(Maliit::Accessory, pluginId3); actualState << Maliit::Accessory << Maliit::Hardware; subject->setActiveHandlers(actualState); QCOMPARE(subject->activePlugins.size(), 2); Q_FOREACH(Maliit::Plugins::InputMethodPlugin * p, subject->activePlugins) { plugin3 = dynamic_cast(p); if (plugin3 != 0) { ++plugin3Count; QCOMPARE(plugin3->name(), pluginName3); abstractInputMethod = subject->plugins[p].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod3 = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod3 != 0); QCOMPARE(inputMethod3->setStateCount, 1); inputMethod3->setStateCount = 0; QCOMPARE(inputMethod3->setStateParam.size(), 1); QCOMPARE(*inputMethod3->setStateParam.begin(), Maliit::Accessory); } plugin = dynamic_cast(p); if (plugin != 0) { ++pluginCount; QCOMPARE(plugin->name(), pluginName); abstractInputMethod = subject->plugins[p].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->setStateCount, 1); inputMethod->setStateCount = 0; QCOMPARE(inputMethod->setStateParam.size(), 1); QCOMPARE(*inputMethod->setStateParam.begin(), Maliit::Hardware); } } QCOMPARE(pluginCount, 1); QCOMPARE(plugin3Count, 1); } void Ut_MIMPluginManager::testExistInputMethod() { MIMPluginManagerPrivate::Plugins::iterator iterator; QSet actualState; subject->addHandlerMap(Maliit::OnScreen, pluginId); subject->addHandlerMap(Maliit::Hardware, pluginId); subject->addHandlerMap(Maliit::Accessory, pluginId3); actualState << Maliit::OnScreen; subject->setActiveHandlers(actualState); actualState.clear(); actualState << Maliit::Accessory; subject->setActiveHandlers(actualState); for (iterator = subject->plugins.begin(); iterator != subject->plugins.end(); ++iterator) { // no matter the plugin is active or not, the inputmethod object is not empty. if (!iterator.key()->supportedStates().isEmpty()) { QVERIFY(iterator.value().inputMethod != 0); } } } void Ut_MIMPluginManager::testPluginSwitcher_data() { QTest::addColumn("state"); QTest::newRow("OnScreen") << Maliit::OnScreen; QTest::newRow("Hardware") << Maliit::Hardware; QTest::newRow("Accessory") << Maliit::Accessory; } void Ut_MIMPluginManager::testPluginSwitcher() { QFETCH(Maliit::HandlerState, state); QSet actualState; DummyImPlugin *plugin = 0; DummyImPlugin3 *plugin3 = 0; MAbstractInputMethod *abstractInputMethod = 0; QPointer inputMethod = 0; QPointer inputMethod3 = 0; subject->addHandlerMap(Maliit::Hardware, pluginId); subject->addHandlerMap(Maliit::OnScreen, pluginId); subject->addHandlerMap(Maliit::Accessory, pluginId); // search for loaded plugins for (MIMPluginManagerPrivate::Plugins::iterator iterator(subject->plugins.begin()); iterator != subject->plugins.end(); ++iterator) { if (iterator.key() == 0) { continue; } if (pluginName == iterator.key()->name()) { plugin = dynamic_cast(iterator.key()); } else if (pluginName3 == iterator.key()->name()) { plugin3 = dynamic_cast(iterator.key()); } } QVERIFY(plugin != 0); QVERIFY(plugin3 != 0); QVERIFY(subject->plugins.contains(plugin)); inputMethod = dynamic_cast(subject->plugins[plugin].inputMethod); actualState << state; QVERIFY(subject->activePlugins.size() == 1); subject->setActiveHandlers(actualState); // nothing should be changed subject->switchPlugin(Maliit::SwitchUndefined, inputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->switchContextCallCount, 0); QCOMPARE(subject->plugins[plugin].lastSwitchDirection, Maliit::SwitchUndefined); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin == *subject->activePlugins.begin()); // switch forward subject->switchPlugin(Maliit::SwitchForward, inputMethod); QCOMPARE(subject->plugins[plugin].lastSwitchDirection, Maliit::SwitchForward); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin3 == *subject->activePlugins.begin()); abstractInputMethod = subject->plugins[plugin3].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod3 = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod3 != 0); QCOMPARE(inputMethod3->switchContextCallCount, 0); QCOMPARE(inputMethod3->setStateCount, 1); inputMethod3->setStateCount = 0; QCOMPARE(inputMethod3->setStateParam.size(), 1); QCOMPARE(*inputMethod3->setStateParam.begin(), state); checkHandlerMap(state, pluginId3); //switch backward inputMethod->setStateCount = 0; subject->switchPlugin(Maliit::SwitchBackward, inputMethod3); QCOMPARE(subject->plugins[plugin3].lastSwitchDirection, Maliit::SwitchBackward); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin == *subject->activePlugins.begin()); abstractInputMethod = subject->plugins[plugin].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->switchContextCallCount, 0); QCOMPARE(inputMethod->setStateCount, 1); inputMethod->setStateCount = 0; QCOMPARE(inputMethod->setStateParam.size(), 1); QCOMPARE(*inputMethod->setStateParam.begin(), state); checkHandlerMap(state, pluginId); // ... again subject->switchPlugin(Maliit::SwitchBackward, inputMethod); QCOMPARE(subject->plugins[plugin].lastSwitchDirection, Maliit::SwitchBackward); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin3 == *subject->activePlugins.begin()); abstractInputMethod = subject->plugins[plugin3].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod3 = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod3 != 0); QCOMPARE(inputMethod3->switchContextCallCount, 1); inputMethod3->switchContextCallCount = 0; QCOMPARE(inputMethod3->directionParam, Maliit::SwitchBackward); QVERIFY(inputMethod3->enableAnimationParam == false); QCOMPARE(inputMethod3->setStateCount, 1); inputMethod3->setStateCount = 0; QCOMPARE(inputMethod3->setStateParam.size(), 1); QCOMPARE(*inputMethod3->setStateParam.begin(), state); checkHandlerMap(state, pluginId3); // try to switch to plugin which could not support the same state // nothing should be changed plugin->allowedStates.clear(); subject->switchPlugin(Maliit::SwitchBackward, inputMethod3); plugin->allowedStates << Maliit::OnScreen << Maliit::Hardware << Maliit::Accessory; // restore default configuration QCOMPARE(subject->plugins[plugin3].lastSwitchDirection, Maliit::SwitchBackward); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin3 == *subject->activePlugins.begin()); QVERIFY(inputMethod3 != 0); abstractInputMethod = inputMethod3; QVERIFY(abstractInputMethod == subject->plugins[plugin3].inputMethod); QCOMPARE(inputMethod3->switchContextCallCount, 0); QCOMPARE(inputMethod3->setStateCount, 0); inputMethod3->setStateCount = 0; checkHandlerMap(state, pluginId3); } void Ut_MIMPluginManager::checkHandlerMap(int handler, const QString &name) { if (handler != Maliit::OnScreen) { const QString key = QString(PluginRoot + subject->inputSourceName(static_cast(handler))); MImSettings setting(key); QCOMPARE(setting.value().toString(), name); } } void Ut_MIMPluginManager::testSwitchToSpecifiedPlugin() { const Maliit::HandlerState state = Maliit::OnScreen; QSet actualState; DummyImPlugin *plugin = 0; DummyImPlugin3 *plugin3 = 0; MAbstractInputMethod *abstractInputMethod = 0; QPointer inputMethod = 0; QPointer inputMethod3 = 0; MImSettings lastActiveSubviewSetting(ActivePluginKey); subject->addHandlerMap(Maliit::OnScreen, pluginId); subject->addHandlerMap(Maliit::Hardware, pluginId); subject->addHandlerMap(Maliit::Accessory, pluginId); // search for loaded plugins for (MIMPluginManagerPrivate::Plugins::iterator iterator(subject->plugins.begin()); iterator != subject->plugins.end(); ++iterator) { if (pluginName == iterator.key()->name()) { plugin = dynamic_cast(iterator.key()); } else if (pluginName3 == iterator.key()->name()) { plugin3 = dynamic_cast(iterator.key()); } } QVERIFY(plugin != 0); QVERIFY(plugin3 != 0); inputMethod = dynamic_cast(subject->plugins[plugin].inputMethod); actualState << state; QVERIFY(subject->activePlugins.size() == 1); subject->setActiveHandlers(actualState); // nothing should be changed subject->switchPlugin(pluginId, inputMethod); QCOMPARE(QString("dummyimsv1"), lastActiveSubviewSetting.value().toString().section(':', 1)); QVERIFY(inputMethod != 0); QCOMPARE(inputMethod->switchContextCallCount, 0); QCOMPARE(subject->plugins[plugin].lastSwitchDirection, Maliit::SwitchUndefined); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin == *subject->activePlugins.begin()); Q_FOREACH (Maliit::Plugins::InputMethodPlugin *handler, subject->handlerToPlugin.values()) { QVERIFY(handler == plugin); } QCOMPARE(lastActiveSubviewSetting.value().toString().section(':', 1), QString("dummyimsv1")); // switch to another plugin subject->switchPlugin(pluginId3, inputMethod); QCOMPARE(lastActiveSubviewSetting.value().toString().section(':', 1), QString("dummyim3sv1")); QCOMPARE(subject->plugins[plugin].lastSwitchDirection, Maliit::SwitchUndefined); QVERIFY(inputMethod != 0); QCOMPARE(subject->activePlugins.count(), 1); QVERIFY(plugin3 == *subject->activePlugins.begin()); abstractInputMethod = subject->plugins[plugin3].inputMethod; QVERIFY(abstractInputMethod != 0); inputMethod3 = dynamic_cast(abstractInputMethod); QVERIFY(inputMethod3 != 0); QCOMPARE(inputMethod3->switchContextCallCount, 1); QCOMPARE(inputMethod3->directionParam, Maliit::SwitchUndefined); QCOMPARE(inputMethod3->setStateCount, 1); inputMethod3->setStateCount = 0; QCOMPARE(inputMethod3->setStateParam.size(), 1); QCOMPARE(*inputMethod3->setStateParam.begin(), state); Q_FOREACH (Maliit::Plugins::InputMethodPlugin *handler, subject->handlerToPlugin.values()) { qDebug() << handler << plugin3; QVERIFY(handler == plugin3); } } void Ut_MIMPluginManager::testSwitchShow_data() { QTest::addColumn("visible"); QTest::addColumn("showCount"); QTest::newRow("visible") << true << 1; QTest::newRow("hidden") << false << 0; } // see NB#296576 - Vkb is not shown in text field, when swype keyboard is enabled & disabled in a scenario // switching a plugin will call show on the new one, // if that happens while vkb is shown (which is correct), // and shortly after vkb is hidden (which is incorrect) void Ut_MIMPluginManager::testSwitchShow() { QFETCH(bool, visible); QFETCH(int, showCount); // preparation MImSettings enabledPluginsSettings(EnabledPluginsKey); enabledPluginsSettings.set(QStringList() << pluginId3 + ":" + "dummyim3sv1" << pluginId + ":" + "dummyimsv1"); subject->setActivePlugin(pluginId, Maliit::OnScreen); subject->showActivePlugins(); // current input method MAbstractInputMethod *im = 0; // the other input method, we will watch it DummyInputMethod3 *dummyIm3 = 0; Q_FOREACH (MIMPluginManagerPrivate::PluginDescription pd, subject->plugins.values()) { MAbstractInputMethod *imi = pd.inputMethod; Q_FOREACH (MAbstractInputMethod::MInputMethodSubView v, imi->subViews()) { if (v.subViewId == "dummyimsv1") { im = imi; } if (v.subViewId == "dummyim3sv1") { dummyIm3 = qobject_cast(imi); } } } QVERIFY(im != 0); QVERIFY(dummyIm3 != 0); // end of preparation if (!visible) { subject->hideActivePlugins(); } QSignalSpy shown(dummyIm3, SIGNAL(showCalled())); // swithching to the dummyIm3 subject->switchPlugin(Maliit::SwitchForward, im); QCOMPARE(shown.size(), showCount); } void Ut_MIMPluginManager::testSetActivePlugin() { QVERIFY(subject->activePlugins.size() == 1); Maliit::Plugins::InputMethodPlugin *plugin = 0; plugin = *subject->activePlugins.begin(); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); subject->setActivePlugin(pluginId3, Maliit::OnScreen); // check settings entry MImSettings handlerItem(ActivePluginKey); QCOMPARE(handlerItem.value().toString().section(':', 0, 0), pluginId3); QVERIFY(subject->activePlugins.size() == 1); plugin = *subject->activePlugins.begin(); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName3); } void Ut_MIMPluginManager::testSubViews() { QList subViews; Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, subject->plugins.keys()) { subViews += subject->plugins[plugin].inputMethod->subViews(Maliit::OnScreen); } // only has subviews for Maliit::OnScreen QCOMPARE(subViews.count(), 8); subViews.clear(); Q_FOREACH (Maliit::Plugins::InputMethodPlugin *plugin, subject->plugins.keys()) { subViews += subject->plugins[plugin].inputMethod->subViews(Maliit::Hardware); } // doesn't have subviews for Hardware QCOMPARE(subViews.count(), 0); } void Ut_MIMPluginManager::testActiveSubView() { QVERIFY(subject->activePlugins.size() == 1); Maliit::Plugins::InputMethodPlugin *plugin = 0; plugin = *subject->activePlugins.begin(); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName); QCOMPARE(subject->activeSubView(Maliit::OnScreen), QString("dummyimsv1")); subject->_q_setActiveSubView(QString("dummyimsv2"), Maliit::OnScreen); QCOMPARE(subject->activeSubView(Maliit::OnScreen), QString("dummyimsv2")); subject->setActivePlugin(pluginId3, Maliit::OnScreen); QCOMPARE(subject->activePlugins.size(), 1); plugin = *subject->activePlugins.begin(); QVERIFY(plugin != 0); QCOMPARE(plugin->name(), pluginName3); QCOMPARE(subject->activeSubView(Maliit::OnScreen), QString("dummyim3sv1")); subject->_q_setActiveSubView(QString("dummyim3sv2"), Maliit::OnScreen); QCOMPARE(subject->activeSubView(Maliit::OnScreen), QString("dummyim3sv2")); } void Ut_MIMPluginManager::testLoadedPluginsInfo_data() { QTest::addColumn("expectedPlugins"); QTest::addColumn("state"); QTest::newRow("OnScreen") << (QStringList() << pluginName << pluginName3) << Maliit::OnScreen; QTest::newRow("Hardware") << (QStringList() << pluginName) << Maliit::Hardware; } void Ut_MIMPluginManager::testLoadedPluginsInfo() { QFETCH(QStringList, expectedPlugins); QFETCH(Maliit::HandlerState, state); QStringList foundPlugins; DummyImPlugin3 *plugin3 = 0; // search for loaded plugins for (MIMPluginManagerPrivate::Plugins::iterator iterator(subject->plugins.begin()); iterator != subject->plugins.end(); ++iterator) { if (iterator.key() == 0) { continue; } if (pluginName3 == iterator.key()->name()) { plugin3 = dynamic_cast(iterator.key()); } } QVERIFY(plugin3 != 0); plugin3->allowedStates.clear(); plugin3->allowedStates << Maliit::OnScreen; QList list = subject->pluginDescriptions(state); QCOMPARE(list.count(), expectedPlugins.count()); Q_FOREACH(const MImPluginDescription &info, list) { QVERIFY(expectedPlugins.contains(info.name())); // check for duplicates QVERIFY(!foundPlugins.contains(info.name())); foundPlugins.append(info.name()); } } void Ut_MIMPluginManager::testSubViewsInfo_data() { QTest::addColumn("enabledPlugins"); QTest::addColumn("activeSubView"); QTest::addColumn("expectedTitles"); QTest::newRow("no subviews") << QStringList() // at least we should not crash here << "dummyimsv1" << QStringList(); QTest::newRow("one subview") << (QStringList() << pluginId + ":" + "dummyimsv1") << "dummyimsv1" << QStringList(); QTest::newRow("two subviews") << (QStringList() << pluginId + ":" + "dummyimsv1" << pluginId + ":" + "dummyimsv2") << "dummyimsv1" << (QStringList() << "dummyimsv2" << "dummyimsv2"); QTest::newRow("sv1") << DefaultEnabledPlugins << "dummyimsv1" << (QStringList() << "dummyim3sv2" << "dummyimsv2"); // last test case have to use DefaultEnabledPlugins to restore default settings QTest::newRow("sv2") << DefaultEnabledPlugins << "dummyimsv2" << (QStringList() << "dummimysv1" << "dummyim3sv1"); } void Ut_MIMPluginManager::testSubViewsInfo() { QFETCH(QStringList, enabledPlugins); QFETCH(QString, activeSubView); QFETCH(QStringList, expectedTitles); MImSettings enabledPluginsSettings(EnabledPluginsKey); enabledPluginsSettings.set(enabledPlugins); subject->_q_setActiveSubView(activeSubView, Maliit::OnScreen); QVERIFY(subject->activeSubView(Maliit::OnScreen) == activeSubView); QList subViewDescriptions = subject->surroundingSubViewDescriptions(Maliit::OnScreen); QCOMPARE(subViewDescriptions.size(), expectedTitles.size()); for(int n = 0; n < subViewDescriptions.size(); ++n) { QCOMPARE(subViewDescriptions.at(n).title(), expectedTitles.at(n)); } } void Ut_MIMPluginManager::testEnableAllSubviews() { //load all subviews provided by all available plugins manager->setAllSubViewsEnabled(true); handleMessages(); // enumerate all subviews provided by all available plugins QStringList allSubViews; Q_FOREACH(Maliit::Plugins::InputMethodPlugin * p, subject->plugins.keys()) { Q_FOREACH (const MAbstractInputMethod::MInputMethodSubView &s, subject->plugins[p].inputMethod->subViews(Maliit::OnScreen)) { allSubViews << subject->plugins[p].pluginId + ":" + s.subViewId; } } MImSettings enabledPluginsSettings(EnabledPluginsKey); QStringList enabledSubViews = enabledPluginsSettings.value().value(); // every available subview should be enabled for (int n = 0; n < allSubViews.count() - 1; ++n) { int index = enabledSubViews.indexOf(allSubViews.at(n + 1)); QVERIFY(index > 0); } } void Ut_MIMPluginManager::handleMessages() { QTest::qWait(100); while (QCoreApplication::hasPendingEvents()) { QCoreApplication::processEvents(); } } void Ut_MIMPluginManager::testPluginSettingsList() { manager->pluginSettingsRequested(42, QString()); QCOMPARE(connection->pluginSettingsLoaded_called, 1); QCOMPARE(connection->pluginSettingsLoaded_clientId, 42); QVERIFY(connection->pluginSettingsLoaded_settings.count() >= 2); MImPluginSettingsInfo server, list; Q_FOREACH (const MImPluginSettingsInfo &plugin, connection->pluginSettingsLoaded_settings) { if (plugin.plugin_name == "@settings") list = plugin; else if (plugin.plugin_name == "server") server = plugin; } QVERIFY(!server.plugin_name.isEmpty() && !list.plugin_name.isEmpty()); QCOMPARE(list.extension_id, (int)MSharedAttributeExtensionManager::PluginSettingsList); QCOMPARE(server.extension_id, (int)MSharedAttributeExtensionManager::PluginSettings); QVERIFY(server.entries.count() >= 2); } void Ut_MIMPluginManager::testPluginSettingsUpdate() { manager->pluginSettingsRequested(42, QString()); QCOMPARE(connection->pluginSettingsLoaded_called, 1); QCOMPARE(connection->pluginSettingsLoaded_clientId, 42); MImPluginSettingsInfo server; MImPluginSettingsEntry enabled; QString test_key = "/maliit/onscreen/active"; QVariant original_value, new_value; Q_FOREACH (const MImPluginSettingsInfo &plugin, connection->pluginSettingsLoaded_settings) { if (plugin.plugin_name != "server") continue; server = plugin; Q_FOREACH (const MImPluginSettingsEntry &entry, plugin.entries) { if (entry.extension_key == test_key) enabled = entry; } } original_value = enabled.value; QVERIFY(!enabled.description.isEmpty()); QVERIFY(enabled.value.isValid()); QCOMPARE(enabled.value, MImSettings(test_key).value()); QCOMPARE(enabled.type, Maliit::StringType); Q_FOREACH (const QVariant &v, enabled.attributes[Maliit::SettingEntryAttributes::valueDomain].toList()) { if (v != original_value) { new_value = v; break; } } subject->sharedAttributeExtensionManager->handleAttributeExtensionRegistered(42, server.extension_id, QString()); subject->sharedAttributeExtensionManager->handleAttributeExtensionRegistered(43, server.extension_id, QString()); // change value from client subject->sharedAttributeExtensionManager->handleExtendedAttributeUpdate(42, server.extension_id, "/maliit", "onscreen", "active", new_value); QCOMPARE(connection->notifyExtendedAttributeChanged_called, 1); QCOMPARE(connection->notifyExtendedAttributeChanged_clientIds, QList() << 42 << 43); QCOMPARE(connection->notifyExtendedAttributeChanged_key, test_key); QCOMPARE(connection->notifyExtendedAttributeChanged_value, new_value); // check unsubscription subject->sharedAttributeExtensionManager->handleAttributeExtensionUnregistered(43, server.extension_id); // change value from server MImSettings(test_key).set(original_value); QCOMPARE(connection->notifyExtendedAttributeChanged_called, 2); QCOMPARE(connection->notifyExtendedAttributeChanged_clientIds, QList() << 42); QCOMPARE(connection->notifyExtendedAttributeChanged_key, test_key); QCOMPARE(connection->notifyExtendedAttributeChanged_value, original_value); } QTEST_MAIN(Ut_MIMPluginManager) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanager/ut_mimpluginmanager.h000066400000000000000000000024541262307254400311670ustar00rootroot00000000000000#ifndef UT_MIMPLUGINLOADER_H #define UT_MIMPLUGINLOADER_H #include "mimserveroptions.h" #include #include class MIMPluginManager; class MIMPluginManagerPrivate; class MInputContextTestConnection; class QDBusInterface; class Ut_MIMPluginManager : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testLoadPlugins(); void testAddHandlerMap(); void testSwitchPluginState(); void testMultiplePlugins(); void testExistInputMethod(); void testPluginSwitcher_data(); void testPluginSwitcher(); void testSwitchToSpecifiedPlugin(); void testSwitchShow_data(); void testSwitchShow(); void testSetActivePlugin(); void testSubViews(); void testActiveSubView(); void testLoadedPluginsInfo_data(); void testLoadedPluginsInfo(); void testSubViewsInfo_data(); void testSubViewsInfo(); void testEnableAllSubviews(); void testPluginSettingsList(); void testPluginSettingsUpdate(); private: void handleMessages(); QString pluginPath; MIMPluginManager *manager; MIMPluginManagerPrivate *subject; MInputContextTestConnection *connection; void checkHandlerMap(int handler, const QString &name); }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanager/ut_mimpluginmanager.pro000066400000000000000000000007131262307254400315340ustar00rootroot00000000000000include(../common_top.pri) QT += gui INCLUDEPATH += ../stubs \ # Input HEADERS += \ ut_mimpluginmanager.h \ SOURCES += \ ut_mimpluginmanager.cpp \ include(../dummyimplugins.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) # For MImInputContextConnection pulled in by TestInputMethodHost include($$TOP_DIR/connection/libmaliit-connection.pri) target.files += \ $$TARGET \ toolbar1.xml \ toolbar2.xml \ include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanagerconfig/000077500000000000000000000000001262307254400261335ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanagerconfig/.gitignore000066400000000000000000000000321262307254400301160ustar00rootroot00000000000000ut_mimpluginmanagerconfig ut_mimpluginmanagerconfig.cpp000066400000000000000000000132321262307254400340130ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanagerconfig/* * This file is part of Maliit framework * * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "ut_mimpluginmanagerconfig.h" #include "dummyimplugin.h" #include "dummyimplugin3.h" #include "dummyinputmethod.h" #include "dummyinputmethod3.h" #include "minputcontextconnection.h" #include "mimsettingsqsettings.h" #include "core-utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "mattributeextensionmanager.h" #include "msharedattributeextensionmanager.h" using namespace std::tr1; typedef QSet HandlerStates; Q_DECLARE_METATYPE(HandlerStates); Q_DECLARE_METATYPE(Maliit::HandlerState); namespace { const QString ConfigRoot = MALIIT_CONFIG_ROOT; const QString MImPluginPaths = ConfigRoot + "paths"; const QString EnabledPluginsKey = MALIIT_CONFIG_ROOT"onscreen/enabled"; const QString ActivePluginKey = MALIIT_CONFIG_ROOT"onscreen/active"; const QString pluginName = "DummyImPlugin"; const QString pluginName2 = "DummyImPlugin2"; const QString pluginName3 = "DummyImPlugin3"; const QString pluginId = "libdummyimplugin.so"; const QString pluginId2 = "libdummyimplugin2.so"; const QString pluginId3 = "libdummyimplugin3.so"; const QStringList DefaultEnabledPlugins = QStringList() << pluginId + ":" + "dummyimsv1" << pluginId + ":" + "dummyimsv2" << pluginId3 + ":" + "dummyim3sv1" << pluginId3 + ":" + "dummyim3sv2"; } void Ut_MIMPluginManagerConfig::initTestCase() { MImSettings::setPreferredSettingsType(MImSettings::TemporarySettings); } void Ut_MIMPluginManagerConfig::cleanupTestCase() { } void Ut_MIMPluginManagerConfig::init() { MImSettings pathConf(MImPluginPaths); pathConf.set(MaliitTestUtils::getTestPluginPath()); connection = new MInputContextConnection; enabledPluginSettings = new MImSettings(EnabledPluginsKey); activePluginSettings = new MImSettings(ActivePluginKey); } void Ut_MIMPluginManagerConfig::cleanup() { delete manager; delete connection; delete enabledPluginSettings; delete activePluginSettings; manager = 0; subject = 0; } // Test methods.............................................................. void Ut_MIMPluginManagerConfig::testNoActiveSubView() { enabledPluginSettings->set(DefaultEnabledPlugins); activePluginSettings->unset(); QSharedPointer icConnection(connection); manager = new MIMPluginManager(icConnection, QSharedPointer(new Maliit::UnknownPlatform)); subject = manager->d_ptr; // The first enabled subview should have been auto-selected as the // active subview MImOnScreenPlugins::SubView subView = subject->onScreenPlugins.activeSubView(); QCOMPARE(subView.plugin + ":" + subView.id, DefaultEnabledPlugins.first()); } void Ut_MIMPluginManagerConfig::testEmptyConfig() { enabledPluginSettings->unset(); activePluginSettings->unset(); QSharedPointer icConnection(connection); manager = new MIMPluginManager(icConnection, QSharedPointer(new Maliit::UnknownPlatform)); subject = manager->d_ptr; // One subview should have been auto-activated and enabled. MImOnScreenPlugins& plugins = subject->onScreenPlugins; MImOnScreenPlugins::SubView active = plugins.activeSubView(); QList enabled = plugins.enabledSubViews(active.plugin); QCOMPARE(enabled.size(), 1); QCOMPARE(enabled.first(), active); } void Ut_MIMPluginManagerConfig::autoLanguageSubView() { // Force autodetection of enabled plugins in DummyPlugin3 enabledPluginSettings->unset(); activePluginSettings->set(QStringList() << pluginId3 + ":"); QSharedPointer icConnection(connection); manager = new MIMPluginManager(icConnection, QSharedPointer(new Maliit::UnknownPlatform)); subject = manager->d_ptr; MImOnScreenPlugins& plugins = subject->onScreenPlugins; QList enabled = plugins.enabledSubViews(pluginId3); // Expect 3 results; ur_PK should have been skipped (no match) QCOMPARE(enabled.size(), 3); // First one should be en_gb - simple match QCOMPARE(enabled[0].id, QString("en_gb")); // Check that we matched after stripping the country code QCOMPARE(enabled[1].id, QString("es")); // Check that we matched after auto-adding the country code QCOMPARE(enabled[2].id, QString("fr_fr")); } int main(int argc, char **argv) { // Provide our own main function so that we can override LANGUAGE // before Qt gets loaded. // FIXME: Find a cleaner way to set LANGUAGE env that allows us to use // QTEST_MAIN macro again. setenv("LANGUAGE", "en_GB.utf8:ur_PK.utf8:es_NI.utf8:fr", 1); Ut_MIMPluginManagerConfig test; // Qt5 crashes when not supplying argc & argv. // TODO: File bug report. QTest::qExec(&test, argc, argv); return 0; } ut_mimpluginmanagerconfig.h000066400000000000000000000023441262307254400334620ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanagerconfig/* * This file is part of Maliit framework * * * Copyright (C) 2012 One Laptop per Child Association * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef UT_MIMPLUGINMANAGERCONFIG_H #define UT_MIMPLUGINMANAGERCONFIG_H #include "mimserveroptions.h" #include "mimsettingsqsettings.h" #include #include #include class MIMPluginManager; class MIMPluginManagerPrivate; class MInputContextConnection; class QDBusInterface; class Ut_MIMPluginManagerConfig : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testNoActiveSubView(); void testEmptyConfig(); void autoLanguageSubView(); private: QString pluginPath; MImSettings *enabledPluginSettings; MImSettings *activePluginSettings; MIMPluginManager *manager; MIMPluginManagerPrivate *subject; MInputContextConnection *connection; }; #endif ut_mimpluginmanagerconfig.pro000066400000000000000000000006611262307254400340330ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimpluginmanagerconfiginclude(../common_top.pri) QT += gui INCLUDEPATH += ../stubs \ # Input HEADERS += \ ut_mimpluginmanagerconfig.h \ SOURCES += \ ut_mimpluginmanagerconfig.cpp \ include(../dummyimplugins.pri) include($$TOP_DIR/src/libmaliit-plugins.pri) # For MImInputContextConnection pulled in by TestInputMethodHost include($$TOP_DIR/connection/libmaliit-connection.pri) target.files += \ $$TARGET \ include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimserveroptions/000077500000000000000000000000001262307254400250365ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimserveroptions/.gitignore000066400000000000000000000000251262307254400270230ustar00rootroot00000000000000ut_mimserveroptions maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimserveroptions/ut_mimserveroptions.cpp000066400000000000000000000061351262307254400317040ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "ut_mimserveroptions.h" #include #include #include #include #include #include struct Args { int argc; const char *argv[16]; // argc must not be greater that size of this array }; Q_DECLARE_METATYPE(Args); Q_DECLARE_METATYPE(MImServerCommonOptions); namespace { Args Help = { 2, { "", "-help" } }; Args HelpPlusInvalid = { 3, { "", "-help", "-invalid-parameter" } }; Args Invalid = { 2, { "", "-invalid-parameter" } }; Args Nothing = { 0, { 0 } }; Args ProgramNameOnly = { 1, { "name" } }; Args BypassedParameter = { 1, { "name", "-help" } }; Args Ignored = { 15, { "", "-style", "STYLE", "-session", "SESSION", "-graphicssystem", "GRAPHICSSYSTEM", "-testability", "TESTABILITY", "-qdevel", "-reverse", "-stylesheet", "-widgetcount", "-qdebug", "-software" } }; bool operator==(const MImServerCommonOptions &x, const MImServerCommonOptions &y) { return (x.showHelp == y.showHelp); } } void Ut_MImServerOptions::initTestCase() { } void Ut_MImServerOptions::cleanupTestCase() { } void Ut_MImServerOptions::init() { } void Ut_MImServerOptions::cleanup() { commonOptions = MImServerCommonOptions(); } void Ut_MImServerOptions::testCommonOptions_data() { QTest::addColumn("args"); QTest::addColumn("expectedCommonOptions"); QTest::addColumn("expectedRecognition"); MImServerCommonOptions helpEnabled; helpEnabled.showHelp = true; QTest::newRow("help") << Help << helpEnabled << true; QTest::newRow("help+invalid") << HelpPlusInvalid << helpEnabled << false; MImServerCommonOptions helpDisabled; QTest::newRow("invalid") << Invalid << helpDisabled << false; // at least we should not crash with such parameters QTest::newRow("nothing") << Nothing << helpDisabled << true; QTest::newRow("bypassed parameter") << BypassedParameter << helpDisabled << true; QTest::newRow("program name only") << ProgramNameOnly << helpDisabled << true; QTest::newRow("ignored") << Ignored << helpDisabled << true; } void Ut_MImServerOptions::testCommonOptions() { QFETCH(Args, args); QFETCH(MImServerCommonOptions, expectedCommonOptions); QFETCH(bool, expectedRecognition); bool everythingRecognized = parseCommandLine(args.argc, args.argv); QCOMPARE(everythingRecognized, expectedRecognition); QCOMPARE(commonOptions, expectedCommonOptions); } QTEST_MAIN(Ut_MImServerOptions) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimserveroptions/ut_mimserveroptions.h000066400000000000000000000016161262307254400313500ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef UT_MIMSERVEROPTIONS_H #define UT_MIMSERVEROPTIONS_H #include #include #include class Ut_MImServerOptions : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testCommonOptions_data(); void testCommonOptions(); private: MImServerCommonOptions commonOptions; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimserveroptions/ut_mimserveroptions.pro000066400000000000000000000003011262307254400317070ustar00rootroot00000000000000include(../common_top.pri) include(../../src/libmaliit-plugins.pri) # Input HEADERS += \ ut_mimserveroptions.h \ SOURCES += \ ut_mimserveroptions.cpp \ include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimsettings/000077500000000000000000000000001262307254400237545ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimsettings/.gitignore000066400000000000000000000000171262307254400257420ustar00rootroot00000000000000ut_mimsettings maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimsettings/ut_mimsettings.cpp000066400000000000000000000152711262307254400275410ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "ut_mimsettings.h" #include "mimsettings.h" #include "mimsettingsqsettings.h" namespace { const QString Organization = "maliit.org"; const QString Application = "server"; } void Ut_MImSettings::initTestCase() { MImSettings::setImplementationFactory(new MImSettingsQSettingsBackendFactory); } void Ut_MImSettings::cleanupTestCase() { } // the test code is generic, by writing a backend-specific // init()/cleanup() pair it could be reused for multiple backends void Ut_MImSettings::init() { cleanup(); QSettings settings(Organization, Application); settings.beginGroup("ut_mimsettings"); settings.beginGroup("group"); settings.setValue("integer", 42); settings.setValue("string", "forty-two"); settings.endGroup(); settings.beginGroup("group2"); settings.setValue("integer", 43); settings.setValue("string", "forty-three"); settings.endGroup(); } void Ut_MImSettings::cleanup() { QSettings settings(Organization, Application); settings.beginGroup("ut_mimsettings"); Q_FOREACH (QString key, settings.childKeys()) { settings.remove(key); } Q_FOREACH (QString key, settings.childGroups()) { settings.remove(key); } } // Test methods.............................................................. void Ut_MImSettings::testValue() { MImSettings integer("/ut_mimsettings/group/integer"); MImSettings string("/ut_mimsettings/group/string"); MImSettings empty("/ut_mimsettings/group/empty"); // basic test for value QCOMPARE(integer.key(), QString("/ut_mimsettings/group/integer")); QCOMPARE(integer.value().toInt(), 42); QCOMPARE(string.key(), QString("/ut_mimsettings/group/string")); QCOMPARE(string.value().toString(), QString("forty-two")); // check default value handling QVERIFY(!empty.value().isValid()); QCOMPARE(empty.value(42).toInt(), 42); QCOMPARE(empty.value("forty-two").toString(), QString("forty-two")); QVERIFY(!empty.value().isValid()); QCOMPARE(integer.value(12).toInt(), 42); QCOMPARE(string.value(12).toString(), QString("forty-two")); } void Ut_MImSettings::testModifyValue() { MImSettings integer("/ut_mimsettings/group/integer"); MImSettings integer2("/ut_mimsettings/group/integer"); MImSettings string("/ut_mimsettings/group/string"); MImSettings string2("/ut_mimsettings/group/string"); // basic set tests QCOMPARE(integer.value().toInt(), 42); integer.set(43); QCOMPARE(integer.value().toInt(), 43); QCOMPARE(integer2.value().toInt(), 43); QCOMPARE(string.value().toString(), QString("forty-two")); string.set("forty-three"); QCOMPARE(string.value().toString(), QString("forty-three")); QCOMPARE(string2.value().toString(), QString("forty-three")); // basic unset tests integer.unset(); QVERIFY(!integer.value().isValid()); QVERIFY(!integer2.value().isValid()); string.unset(); QVERIFY(!string.value().isValid()); QVERIFY(!string2.value().isValid()); } void Ut_MImSettings::testModifyValueNotification() { MImSettings integer("/ut_mimsettings/group/integer"); MImSettings integer2("/ut_mimsettings/group/integer"); MImSettings string("/ut_mimsettings/group/string"); MImSettings string2("/ut_mimsettings/group/string"); QSignalSpy spy_integer(&integer, SIGNAL(valueChanged())); QSignalSpy spy_integer2(&integer2, SIGNAL(valueChanged())); QSignalSpy spy_string(&string, SIGNAL(valueChanged())); QSignalSpy spy_string2(&string2, SIGNAL(valueChanged())); integer.set(43); QCOMPARE(spy_integer.count(), 1); QCOMPARE(spy_integer2.count(), 1); QCOMPARE(spy_string.count(), 0); QCOMPARE(spy_string2.count(), 0); integer.set(43); QCOMPARE(spy_integer.count(), 1); QCOMPARE(spy_integer2.count(), 1); QCOMPARE(spy_string.count(), 0); QCOMPARE(spy_string2.count(), 0); integer.set(42); QCOMPARE(spy_integer.count(), 2); QCOMPARE(spy_integer2.count(), 2); QCOMPARE(spy_string.count(), 0); QCOMPARE(spy_string2.count(), 0); integer2.unset(); QCOMPARE(spy_integer.count(), 3); QCOMPARE(spy_integer2.count(), 3); QCOMPARE(spy_string.count(), 0); QCOMPARE(spy_string2.count(), 0); string.unset(); QCOMPARE(spy_integer.count(), 3); QCOMPARE(spy_integer2.count(), 3); QCOMPARE(spy_string.count(), 1); QCOMPARE(spy_string2.count(), 1); string.unset(); QCOMPARE(spy_integer.count(), 3); QCOMPARE(spy_integer2.count(), 3); QCOMPARE(spy_string.count(), 1); QCOMPARE(spy_string2.count(), 1); } void Ut_MImSettings::testUnsetValue() { MImSettings integer("/ut_mimsettings/group/integer"); MImSettings group("/ut_mimsettings/group"); QSignalSpy spy_integer(&integer, SIGNAL(valueChanged())); // unset(), then set(Qvariant()) integer.unset(); QVERIFY(!integer.value().isValid()); QCOMPARE(group.listEntries(), QList() << "/ut_mimsettings/group/string"); QCOMPARE(spy_integer.count(), 1); integer.set(QVariant()); QCOMPARE(spy_integer.count(), 1); // set(Qvariant()), then unset() integer.set(42); spy_integer.clear(); integer.set(QVariant()); QVERIFY(!integer.value().isValid()); QCOMPARE(group.listEntries(), QList() << "/ut_mimsettings/group/string"); QCOMPARE(spy_integer.count(), 1); integer.unset(); QCOMPARE(spy_integer.count(), 1); } void Ut_MImSettings::testListDirs() { QCOMPARE(MImSettings("/ut_mimsettings").listDirs(), QList() << "/ut_mimsettings/group" << "/ut_mimsettings/group2"); QCOMPARE(MImSettings("/ut_mimsettings/group").listDirs(), QList()); QCOMPARE(MImSettings("/ut_mimsettings/dummy").listDirs(), QList()); } void Ut_MImSettings::testListEntries() { QCOMPARE(MImSettings("/ut_mimsettings").listEntries(), QList()); QCOMPARE(MImSettings("/ut_mimsettings/group").listEntries(), QList() << "/ut_mimsettings/group/integer" << "/ut_mimsettings/group/string"); QCOMPARE(MImSettings("/ut_mimsettings/dummy").listEntries(), QList()); } QTEST_MAIN(Ut_MImSettings) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimsettings/ut_mimsettings.h000066400000000000000000000016241262307254400272030ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef UT_MIMSETTINGS_H #define UT_MIMSETTINGS_H #include #include class Ut_MImSettings : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testValue(); void testModifyValue(); void testUnsetValue(); void testModifyValueNotification(); void testListDirs(); void testListEntries(); }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mimsettings/ut_mimsettings.pro000066400000000000000000000003621262307254400275520ustar00rootroot00000000000000include(../common_top.pri) # Input HEADERS += \ ut_mimsettings.h \ SOURCES += \ ut_mimsettings.cpp \ include($$TOP_DIR/src/libmaliit-plugins.pri) include($$TOP_DIR/connection/libmaliit-connection.pri) include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_minputmethodquickplugin/000077500000000000000000000000001262307254400264025ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_minputmethodquickplugin/.gitignore000066400000000000000000000000761262307254400303750ustar00rootroot00000000000000ut_minputmethodquickplugin qrc_ut_minputmethodquickplugin.cpp ut_minputmethodquickplugin.cpp000066400000000000000000000062441262307254400345360ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_minputmethodquickplugin/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "ut_minputmethodquickplugin.h" #include "core-utils.h" #include "gui-utils.h" #include #include #include #include #include class MIndicatorServiceClient {}; void Ut_MInputMethodQuickPlugin::initTestCase() { } void Ut_MInputMethodQuickPlugin::cleanupTestCase() { } void Ut_MInputMethodQuickPlugin::init() {} void Ut_MInputMethodQuickPlugin::cleanup() {} void Ut_MInputMethodQuickPlugin::testQmlSetup_data() { QTest::addColumn("testPluginPath"); QTest::newRow("Hello world") << "helloworld/helloworld.qml"; // TODO Adapt plugins for Qt 5 #if 0 QTest::newRow("Cycle keys") << "cyclekeys/libqmlcyclekeysplugin.so"; QTest::newRow("Override") << "override/libqmloverrideplugin.so"; #endif } /* This test currently tests both the qml example found in examples/ * and the minputmethodquick interface, since the test is so simple. * If more tests are added, it might make sense to make these two * things tested in separate tests. */ void Ut_MInputMethodQuickPlugin::testQmlSetup() { QFETCH(QString, testPluginPath); const QDir pluginDir = MaliitTestUtils::isTestingInSandbox() ? QDir(IN_TREE_TEST_PLUGIN_DIR"/qml") : QDir(MALIIT_TEST_PLUGINS_DIR"/examples/qml"); const QString pluginPath = pluginDir.absoluteFilePath(testPluginPath); const QString pluginId = QFileInfo(testPluginPath).baseName(); QVERIFY(pluginDir.exists(pluginPath)); QObject *pluginInstance = 0; Maliit::Plugins::InputMethodPlugin *plugin = 0; if (pluginPath.endsWith(".qml")) { plugin = new Maliit::InputMethodQuickPlugin(pluginPath, QSharedPointer(new Maliit::UnknownPlatform)); } else { QPluginLoader loader(pluginPath); pluginInstance = loader.instance(); QVERIFY(pluginInstance != 0); plugin = qobject_cast(pluginInstance); } QVERIFY(plugin != 0); MaliitTestUtils::TestInputMethodHost host(pluginId, plugin->name()); Maliit::InputMethodQuick *testee = static_cast( plugin->createInputMethod(&host)); QVERIFY(not testee->inputMethodArea().isEmpty()); QCOMPARE(testee->inputMethodArea(), QRectF(0, qRound(testee->screenHeight() * 0.5), testee->screenWidth(), qRound(testee->screenHeight() * 0.5))); QCOMPARE(host.lastCommit, QString("Maliit")); QCOMPARE(host.sendCommitCount, 1); QCOMPARE(host.lastPreedit, QString("Maliit")); QCOMPARE(host.sendPreeditCount, 1); } QTEST_MAIN(Ut_MInputMethodQuickPlugin) ut_minputmethodquickplugin.h000066400000000000000000000016551262307254400342040ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_minputmethodquickplugin/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef UT_MINPUTMETHODQUICKPLUGIN_H #define UT_MINPUTMETHODQUICKPLUGIN_H #include #include #include class MIMApplication; class Ut_MInputMethodQuickPlugin : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testQmlSetup_data(); void testQmlSetup(); private: QApplication *app; }; #endif // UT_MINPUTMETHODQUICKPLUGIN_H ut_minputmethodquickplugin.pro000066400000000000000000000010261262307254400345450ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_minputmethodquickplugininclude(../common_top.pri) QT += quick # For MImInputContextConnection pulled in by TestInputMethodHost include($$TOP_DIR/connection/libmaliit-connection.pri) IN_TREE_TEST_PLUGIN_DIR = $${OUT_PWD}/../../examples/plugins DEFINES += IN_TREE_TEST_PLUGIN_DIR=\\\"$${IN_TREE_TEST_PLUGIN_DIR}\\\" # Input HEADERS += \ ut_minputmethodquickplugin.h \ ../utils/gui-utils.h \ SOURCES += \ ut_minputmethodquickplugin.cpp \ ../utils/gui-utils.cpp \ include($$TOP_DIR/src/libmaliit-plugins.pri) include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mkeyoverride/000077500000000000000000000000001262307254400241165ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mkeyoverride/.gitignore000066400000000000000000000000201262307254400260760ustar00rootroot00000000000000ut_mkeyoverride maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mkeyoverride/ut_mkeyoverride.cpp000066400000000000000000000047131262307254400300440ustar00rootroot00000000000000#include "ut_mkeyoverride.h" #include #include #include #include #include #include namespace { } Q_DECLARE_METATYPE(MKeyOverride::KeyOverrideAttributes) void Ut_MKeyOverride::initTestCase() { qRegisterMetaType< MKeyOverride::KeyOverrideAttribute >("MKeyOverride::KeyOverrideAttribute"); qRegisterMetaType< MKeyOverride::KeyOverrideAttributes >("MKeyOverride::KeyOverrideAttributes"); } void Ut_MKeyOverride::cleanupTestCase() { } void Ut_MKeyOverride::init() { keyId = QString("testKey"); subject = new MKeyOverride(keyId); } void Ut_MKeyOverride::cleanup() { delete subject; subject = 0; } void Ut_MKeyOverride::testSetProperty() { QSignalSpy spy(subject, SIGNAL(keyAttributesChanged(QString, MKeyOverride::KeyOverrideAttributes))); QVERIFY(spy.isValid()); subject->setProperty("label", QVariant(QString("some text"))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().count(), 2); QCOMPARE(spy.first().first().toString(), keyId); QCOMPARE(spy.first().last().value(), MKeyOverride::KeyOverrideAttributes(MKeyOverride::Label)); QCOMPARE(subject->label(), QString("some text")); spy.clear(); subject->setProperty("icon", QVariant(QString("some text"))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().count(), 2); QCOMPARE(spy.first().first().toString(), keyId); QCOMPARE(spy.first().last().value(), MKeyOverride::KeyOverrideAttributes(MKeyOverride::Icon)); QCOMPARE(subject->icon(), QString("some text")); spy.clear(); subject->setProperty("highlighted", QVariant(true)); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().count(), 2); QCOMPARE(spy.first().first().toString(), keyId); QCOMPARE(spy.first().last().value(), MKeyOverride::KeyOverrideAttributes(MKeyOverride::Highlighted)); QCOMPARE(subject->highlighted(), true); spy.clear(); subject->setProperty("enabled", QVariant(false)); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().count(), 2); QCOMPARE(spy.first().first().toString(), keyId); QCOMPARE(spy.first().last().value(), MKeyOverride::KeyOverrideAttributes(MKeyOverride::Enabled)); QCOMPARE(subject->enabled(), false); spy.clear(); } QTEST_MAIN(Ut_MKeyOverride) maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mkeyoverride/ut_mkeyoverride.h000066400000000000000000000005731262307254400275110ustar00rootroot00000000000000#ifndef UT_MKEYOVERRIDE_H #define UT_MKEYOVERRIDE_H #include #include class MKeyOverride; class Ut_MKeyOverride : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void init(); void cleanup(); void testSetProperty(); private: MKeyOverride *subject; QString keyId; }; #endif maliit-framework-0.99.1+git20151118+62bd54b/tests/ut_mkeyoverride/ut_mkeyoverride.pro000066400000000000000000000004541262307254400300600ustar00rootroot00000000000000include(../common_top.pri) INCLUDEPATH += ../stubs \ # Input HEADERS += \ ut_mkeyoverride.h \ SOURCES += \ ut_mkeyoverride.cpp \ QT += dbus CONFIG += plugin include($$TOP_DIR/src/libmaliit-plugins.pri) include($$TOP_DIR/connection/libmaliit-connection.pri) include(../common_check.pri) maliit-framework-0.99.1+git20151118+62bd54b/tests/utils/000077500000000000000000000000001262307254400220415ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/tests/utils/core-utils.cpp000066400000000000000000000104771262307254400246440ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "core-utils.h" #include #include #include namespace { const QString TestingInSandboxEnvVariable("TESTING_IN_SANDBOX"); const QString GlobalTestPluginPath(MALIIT_TEST_PLUGINS_DIR); const QString TestPluginPathEnvVariable("TESTPLUGIN_PATH"); const QString GlobalTestDataPath(MALIIT_TEST_DATA_PATH); const QString TestDataPathEnvVariable("TESTDATA_PATH"); // If the environment variable envVar has a value, set *path to this value // Returns true on success, false on error bool setPathFromEnvironmentVariable(QString *path, QString envVar) { const QStringList env(QProcess::systemEnvironment()); int index = env.indexOf(QRegExp('^' + envVar + "=.*", Qt::CaseInsensitive)); if (index != -1) { QString pathCandidate = env.at(index); pathCandidate = pathCandidate.remove( QRegExp('^' + envVar + '=', Qt::CaseInsensitive)); if (!pathCandidate.isEmpty()) { *path = pathCandidate; return true; } else { qCritical() << "Invalid " << envVar << " environment variable.\n"; return false; } } return true; } } namespace MaliitTestUtils { /* Return true if we are testing against the repository tree, or false if testing against installed software. */ bool isTestingInSandbox() { bool testingInSandbox = false; const QStringList env(QProcess::systemEnvironment()); int index = env.indexOf(QRegExp('^' + TestingInSandboxEnvVariable + "=.*", Qt::CaseInsensitive)); if (index != -1) { QString statusCandidate = env.at(index); statusCandidate = statusCandidate.remove( QRegExp('^' + TestingInSandboxEnvVariable + '=', Qt::CaseInsensitive)); bool statusOk = false; int status = statusCandidate.toInt(&statusOk); if (statusOk && (status == 0 || status == 1)) { testingInSandbox = (status == 1); } else { qCritical() << "Invalid " << TestingInSandboxEnvVariable << " environment variable.\n"; } } return testingInSandbox; } // Use either global test plugin directory or TESTPLUGIN_PATH, if it is // set (to local sandbox's plugin directory by makefile, at least). // // Returns a null QString on failure QString getTestPluginPath() { QString pluginPath = GlobalTestPluginPath; bool success = setPathFromEnvironmentVariable(&pluginPath, TestPluginPathEnvVariable); if (!success) { return QString(); } if (!QDir("./").exists(pluginPath)) { qCritical("Test plugin directory does not exist."); return QString(); } return pluginPath; } // Use either global test plugin directory or TESTDATA_PATH, if it is // set (to local sandbox's plugin directory by makefile, at least). // // The test data path is the base directory where the tests directories (like ut_mtoolbardata) reside. // // Returns a null QString on failure QString getTestDataPath() { QString dataPath = GlobalTestDataPath; bool success = setPathFromEnvironmentVariable(&dataPath, TestDataPathEnvVariable); if (!success) { return QString(); } if (!QDir("./").exists(dataPath)) { qCritical("Test data directory does not exist."); return QString(); } return dataPath; } // Wait for signal or timeout; use SIGNAL macro for signal void waitForSignal(const QObject* object, const char* signal, int timeout) { QEventLoop eventLoop; QObject::connect(object, signal, &eventLoop, SLOT(quit())); QTimer::singleShot(timeout, &eventLoop, SLOT(quit())); eventLoop.exec(); } void waitAndProcessEvents(int waitTime) { QTest::qWait(waitTime); while (QCoreApplication::instance()->hasPendingEvents()) { QCoreApplication::instance()->processEvents(); } } } maliit-framework-0.99.1+git20151118+62bd54b/tests/utils/core-utils.h000066400000000000000000000015071262307254400243030ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef CORE_UTILS_H__ #define CORE_UTILS_H__ #include #include namespace MaliitTestUtils { bool isTestingInSandbox(); QString getTestPluginPath(); QString getTestDataPath(); void waitForSignal(const QObject* object, const char* signal, int timeout); void waitAndProcessEvents(int waitTime); } #endif // CORE_UTILS_H__ maliit-framework-0.99.1+git20151118+62bd54b/tests/utils/gui-utils.cpp000066400000000000000000000011361262307254400244700ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #include "gui-utils.h" #include #include #include #include namespace MaliitTestUtils { } maliit-framework-0.99.1+git20151118+62bd54b/tests/utils/gui-utils.h000066400000000000000000000066261262307254400241460ustar00rootroot00000000000000/* * This file is part of Maliit framework * * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * * Contact: maliit-discuss@lists.maliit.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * and appearing in the file LICENSE.LGPL included in the packaging * of this file. */ #ifndef GUI_UTILS_H__ #define GUI_UTILS_H__ #include #include #include #include #include #include namespace MaliitTestUtils { class TestPluginSetting : public Maliit::Plugins::AbstractPluginSetting { public: TestPluginSetting(const QString &key) : settingKey(key) {} QString key() const { return settingKey; } QVariant value() const { return QVariant(); } QVariant value(const QVariant &def) const { return def; } void set(const QVariant &val) { Q_UNUSED(val); } void unset() {} private: QString settingKey; }; class TestInputMethodHost : public MInputMethodHost { public: QString lastCommit; int sendCommitCount; QString lastPreedit; int sendPreeditCount; TestInputMethodHost(const QString &plugin, const QString &description) : MInputMethodHost(QSharedPointer(new MInputContextConnection), 0, QSharedPointer(new Maliit::WindowGroup(QSharedPointer(new Maliit::UnknownPlatform))), plugin, description) , sendCommitCount(0) , sendPreeditCount(0) {} void sendCommitString(const QString &string, int start, int length, int cursorPos) { lastCommit = string; ++sendCommitCount; MInputMethodHost::sendCommitString(string, start, length, cursorPos); } void sendPreeditString(const QString &string, const QList &preeditFormats, int start, int length, int cursorPos) { lastPreedit = string; ++sendPreeditCount; MInputMethodHost::sendPreeditString(string, preeditFormats, start, length, cursorPos); } AbstractPluginSetting *registerPluginSetting(const QString &key, const QString &description, Maliit::SettingEntryType type, const QVariantMap &attributes) { Q_UNUSED(description); Q_UNUSED(type); Q_UNUSED(attributes); return new TestPluginSetting(key); } }; } // For cases where we need to run code _before_ QGuiApplication is created #define MALIIT_TESTUTILS_GUI_MAIN_WITH_SETUP(TestObject, setupFunc) \ int main(int argc, char *argv[]) \ { \ setupFunc();\ QGuiApplication app(argc, argv);\ Q_UNUSED(app);\ TestObject tc;\ return QTest::qExec(&tc, argc, argv);\ } #endif // UTILS_H__ maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/000077500000000000000000000000001262307254400231005ustar00rootroot00000000000000maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/.gitignore000066400000000000000000000002021262307254400250620ustar00rootroot00000000000000/wayland-input-method-client-protocol.h /wayland-input-method-protocol.c /wayland-text-client-protocol.h /wayland-text-protocol.c maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/dummy.cpp000066400000000000000000000001341262307254400247350ustar00rootroot00000000000000#include "wayland-input-method-client-protocol.h" #include "wayland-text-client-protocol.h" maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/input-method.xml000066400000000000000000000300331262307254400262360ustar00rootroot00000000000000 Copyright © 2012, 2013 Intel Corporation Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the copyright holders not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. The copyright holders make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Corresponds to a text model on input method side. An input method context is created on text mode activation on the input method side. It allows to receive information about the text model from the application via events. Input method contexts do not keep state after deactivation and should be destroyed after deactivation is handled. Text is generally UTF-8 encoded, indices and lengths are in bytes. Serials are used to synchronize the state between the text input and an input method. New serials are sent by the text input in the commit_state request and are used by the input method to indicate the known text input state in events like preedit_string, commit_string, and keysym. The text input can then ignore events from the input method which are based on an outdated state (for example after a reset). Send the commit string text for insertion to the application. The text to commit could be either just a single character after a key press or the result of some composing (pre-edit). It could be also an empty text when some text should be removed (see delete_surrounding_text) or when the input cursor should be moved (see cursor_position). Any previously set composing text will be removed. Send the pre-edit string text to the application text input. The commit text can be used to replace the preedit text on reset (for example on unfocus). Also previously sent preedit_style and preedit_cursor requests are processed bt the text_input also. Sets styling information on composing text. The style is applied for length in bytes from index relative to the beginning of the composing text (as byte offset). Multiple styles can be applied to a composing text. This request should be sent before sending preedit_string request. Sets the cursor position inside the composing text (as byte offset) relative to the start of the composing text. When index is negative no cursor should be displayed. This request should be sent before sending preedit_string request. This request will be handled on text_input side as part of a directly following commit_string request. Sets the cursor and anchor to a new position. Index is the new cursor position in bytess (when >= 0 relative to the end of inserted text else relative to beginning of inserted text). Anchor is the new anchor position in bytes (when >= 0 relative to the end of inserted text, else relative to beginning of inserted text). When there should be no selected text anchor should be the same as index. This request will be handled on text_input side as part of a directly following commit_string request. Notify when a key event was sent. Key events should not be used for normal text input operations, which should be done with commit_string, delete_surrounfing_text, etc. The key event follows the wl_keyboard key event convention. Sym is a XKB keysym, state a wl_keyboard key_state. Allows an input method to receive hardware keyboard input and process key events to generate text events (with pre-edit) over the wire. This allows input methods which compose multiple key events for inputting text like it is done for CJK languages. Should be used when filtering key events with grab_keyboard. When the wl_keyboard::key event is not processed by the input method itself and should be sent to the client instead, forward it with this request. The arguments should be the ones from the wl_keyboard::key event. For generating custom key events use the keysym request instead. Should be used when filtering key events with grab_keyboard. When the wl_keyboard::modifiers event should be also send to the client, forward it with this request. The arguments should be the ones from the wl_keyboard::modifiers event. The plain surrounding text around the input position. Cursor is the position in bytes within the surrounding text relative to the beginning of the text. Anchor is the position in bytes of the selection anchor within the surrounding text relative to the beginning of the text. If there is no selected text anchor is the same as cursor. An input method object is responsible to compose text in response to input from hardware or virtual keyboards. There is one input method object per seat. On activate there is a new input method context object created which allows the input method to communicate with the text model. A text model was activated. Creates an input method context object which allows communication with the text model. The text model corresponding to the context argument was deactivated. The input method context should be destroyed after deactivation is handled. Only one client can bind this interface at a time. A keybaord surface is only shown, when a text model is active An overlay panel is shown near the input cursor above the application window when a text model is active. maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/libmaliit-weston-protocols.pri000066400000000000000000000007521262307254400311250ustar00rootroot00000000000000# Use when a .pro file requires libmaliit-weston-protocols # The .pro file must define TOP_DIR to be a relative path # to the top-level source/build directory, and include config.pri wayland { LIBS += $$TOP_DIR/lib/$$maliitStaticLib(maliit-weston-protocols) POST_TARGETDEPS += $$TOP_DIR/lib/$$maliitStaticLib(maliit-weston-protocols) INCLUDEPATH += $$TOP_DIR/weston-protocols $$OUT_PWD/$$TOP_DIR/weston-protocols CONFIG += link_pkgconfig PKGCONFIG += wayland-client } maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/text.xml000066400000000000000000000374731262307254400246240ustar00rootroot00000000000000 Copyright © 2012, 2013 Intel Corporation Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of the copyright holders not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. The copyright holders make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. An object used for text input. Adds support for text input and input methods to applications. A text-input object is created from a wl_text_input_manager and corresponds typically to a text entry in an application. Requests are used to activate/deactivate the text-input object and set state information like surrounding and selected text or the content type. The information about entered text is sent to the text-input object via the pre-edit and commit events. Using this interface removes the need for applications to directly process hardware key events and compose text out of them. Text is generally UTF-8 encoded, indices and lengths are in bytes. Serials are used to synchronize the state between the text input and an input method. New serials are sent by the text input in the commit_state request and are used by the input method to indicate the known text input state in events like preedit_string, commit_string, and keysym. The text input can then ignore events from the input method which are based on an outdated state (for example after a reset). Requests the text-input object to be activated (typically when the text entry gets focus). The seat argument is a wl_seat which maintains the focus for this activation. The surface argument is a wl_surface assigned to the text-input object and tracked for focus lost. The enter event is emitted on successful activation. Requests the text-input object to be deactivated (typically when the text entry lost focus). The seat argument is a wl_seat which was used for activation. Requests input panels (virtual keyboard) to show. Requests input panels (virtual keyboard) to hide. Should be called by an editor widget when the input state should be reset, for example after the text was changed outside of the normal input method flow. Sets the plain surrounding text around the input position. Text is UTF-8 encoded. Cursor is the byte offset within the surrounding text. Anchor is the byte offset of the selection anchor within the surrounding text. If there is no selected text anchor is the same as cursor. Content hint is a bitmask to allow to modify the behavior of the text input. The content purpose allows to specify the primary purpose of a text input. This allows an input method to show special purpose input panels with extra characters or to disallow some characters. Sets the content purpose and content hint. While the purpose is the basic purpose of an input field, the hint flags allow to modify some of the behavior. When no content type is explicitly set, a normal content purpose with default hints (auto completion, auto correction, auto capitalization) should be assumed. Sets a specific language. This allows for example a virtual keyboard to show a language specific layout. The "language" argument is a RFC-3066 format language tag. It could be used for example in a word processor to indicate language of currently edited document or in an instant message application which tracks languages of contacts. Notify the text-input object when it received focus. Typically in response to an activate request. Notify the text-input object when it lost focus. Either in response to a deactivate request or when the assigned surface lost focus or was destroyed. Transfer an array of 0-terminated modifiers names. The position in the array is the index of the modifier as used in the modifiers bitmask in the keysym event. Notify when the visibility state of the input panel changed. Notify when a new composing text (pre-edit) should be set around the current cursor position. Any previously set composing text should be removed. The commit text can be used to replace the preedit text on reset (for example on unfocus). The text input should also handle all preedit_style and preedit_cursor events occuring directly before preedit_string. Sets styling information on composing text. The style is applied for length bytes from index relative to the beginning of the composing text (as byte offset). Multiple styles can be applied to a composing text by sending multiple preedit_styling events. This event is handled as part of a following preedit_string event. Sets the cursor position inside the composing text (as byte offset) relative to the start of the composing text. When index is a negative number no cursor is shown. This event is handled as part of a following preedit_string event. Notify when text should be inserted into the editor widget. The text to commit could be either just a single character after a key press or the result of some composing (pre-edit). It could be also an empty text when some text should be removed (see delete_surrounding_text) or when the input cursor should be moved (see cursor_position). Any previously set composing text should be removed. Notify when the cursor or anchor position should be modified. This event should be handled as part of a following commit_string event. Notify when the text around the current cursor position should be deleted. Index is relative to the current cursor (in bytes). Length is the length of deleted text (in bytes). This event should be handled as part of a following commit_string event. Notify when a key event was sent. Key events should not be used for normal text input operations, which should be done with commit_string, delete_surrounding_text, etc. The key event follows the wl_keyboard key event convention. Sym is a XKB keysym, state a wl_keyboard key_state. Modifiers are a mask for effective modifiers (where the modifier indices are set by the modifiers_map event) Sets the language of the input text. The "language" argument is a RFC-3066 format language tag. Sets the text direction of input text. It is mainly needed for showing input cursor on correct side of the editor when there is no input yet done and making sure neutral direction text is laid out properly. A factory for text-input objects. This object is a global singleton. Creates a new text-input object. maliit-framework-0.99.1+git20151118+62bd54b/weston-protocols/weston-protocols.pro000066400000000000000000000007631262307254400271710ustar00rootroot00000000000000include(../config.pri) TOP_DIR = .. VERSION = $$MALIIT_ABI_VERSION TEMPLATE = lib TARGET = $$TOP_DIR/lib/maliit-weston-protocols CONFIG += staticlib wayland { load(wayland-scanner) # to force generation of headers. SOURCES = dummy.cpp WAYLANDCLIENTSOURCES += \ $$IN_PWD/input-method.xml \ $$IN_PWD/text.xml CONFIG += link_pkgconfig PKGCONFIG += wayland-client } OTHER_FILES += \ libmaliit-weston-protocols.pri \ input-method.xml \ text.xml