pax_global_header00006660000000000000000000000064122044653130014512gustar00rootroot0000000000000052 comment=e24553c6bf42fc8dffe3a4ab341e42469059d62c gromit-mpx-1.1/000077500000000000000000000000001220446531300134565ustar00rootroot00000000000000gromit-mpx-1.1/.gitignore000066400000000000000000000002731220446531300154500ustar00rootroot00000000000000*.o .deps/ /aclocal.m4 /autom4te.cache/ /compile /config.h /config.h.in /config.log /config.status /configure /depcomp /install-sh /missing /src/gromit-mpx /stamp-h1 Makefile Makefile.in gromit-mpx-1.1/AUTHORS000066400000000000000000000001071220446531300145240ustar00rootroot00000000000000Simon Budig Christian Beier gromit-mpx-1.1/COPYING000066400000000000000000000431151220446531300145150ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. 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 Program or any portion of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, 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 Program, 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 Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) 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; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, 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 executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or 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 counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program 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. 5. 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 Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. 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 Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program 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 Program. 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. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program 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. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies 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 Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively 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) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. gromit-mpx-1.1/ChangeLog000066400000000000000000000715511220446531300152410ustar00rootroot00000000000000commit 2d0542bdca5f1ba2d5fad8b0b7dfc4cddd9f4e1a Author: Christian Beier Date: Sun Aug 18 14:23:55 2013 +0200 Update README with more precise build instructions. commit 1f3714d8d0f178d2267d3d3b6db678a2420fc7bb Merge: e3af81c 78cfa4f Author: Christian Beier Date: Tue Aug 13 10:51:59 2013 -0700 Merge pull request #1 from barak/upstream-tweaks Merge work done by Barak A. Pearlmutter: autotools update, icon and desktop file update, silence compiler warnings etc. commit 78cfa4fdb33d41123997fe77a15a51afc97e8bad Author: Barak A. Pearlmutter Date: Tue Aug 13 00:42:21 2013 +0200 update URL to new upstream home commit fd49ec62fe87c540c8f029a3aa0cdacf9fc2d4c6 Merge: e9fe472 e3af81c Author: Barak A. Pearlmutter Date: Tue Aug 13 00:35:02 2013 +0200 Merge branch 'upstream' into upstream-tweaks commit e3af81c48baba3cd12538d94c670e5e6f7fcf0bd Author: Christian Beier Date: Tue Aug 13 00:04:29 2013 +0200 Rename Gromit mentions in stderr to Gromit-MPX. commit 142c4ed39d66d4ae613bb5987f3bda517406eb6c Author: Christian Beier Date: Tue Aug 13 00:02:27 2013 +0200 Do not use a leading . for files stored in $XDG_CONFIG_HOME. commit e9fe4723bd263e50f6bc2af7afe2e7fd719d35bc Author: Barak A. Pearlmutter Date: Sat Feb 16 23:52:42 2013 +0000 line thickener menu item commit 1e45014a2bbb352f666e87983f7c6fb987aff69b Author: Barak A. Pearlmutter Date: Mon Feb 11 10:12:36 2013 +0000 thicken MPX on icon for visibility commit 726aed3a2baa83a80e88c519c8fdb891a79e4d33 Author: Barak A. Pearlmutter Date: Fri Feb 8 14:22:01 2013 +0000 remove debian subdirectory from package proper commit 07a3eed9489a63f8542ae1cab846516fd8f4d964 Author: Barak A. Pearlmutter Date: Fri Feb 8 14:21:43 2013 +0000 move man page into package proper commit fd0df3ba22d9f493c7199e66b9ba1ca3b37f7a26 Author: Barak A. Pearlmutter Date: Sun Feb 10 23:14:50 2013 +0000 add cpp macro DEFAULT_HOTKEY that can be -D'ed at compile time commit 8798bbec36f4798fd3bca68030e15e917d42da03 Author: Barak A. Pearlmutter Date: Sun Feb 10 15:19:31 2013 +0000 change font of "MPX" in scalable icon commit 2f6c3c759aff912f680188e7889d44a3dfc053d9 Author: Barak A. Pearlmutter Date: Thu Feb 7 16:46:53 2013 +0000 Add "MPX" to scalable icon. commit 358b6c43bb19b7fd852ab1eec07caf2895298251 Author: Barak A. Pearlmutter Date: Thu Feb 7 16:38:59 2013 +0000 Add scalable icon, copied from debian gromit git repo; inform Makefile.am The scalable icon is installed in .../icons/scalable/apps/ commit 7ed810b2185df1cc5d3af919260e03787c2ce1e2 Author: Barak A. Pearlmutter Date: Thu Feb 7 10:37:42 2013 +0000 Git ignore build debris. commit aa95fa9407228a26d1110216ce2eb8f1b5411caf Author: Barak A. Pearlmutter Date: Thu Feb 7 10:36:18 2013 +0000 Update autotools. Delete autogen.sh as this script is unnecessary. Just use: autoreconf --install Run autoupdate, autoscan. Remove gromit_mpxdocdir; docdir is standard and points to the correct package-specific documentation directory. Remove -lm from Makefile.am, instead support in configure.ac Appropriate AC_SUBSTs are done inside PKG_CHECK_MODULES, can remove from configure.ac. Pass libraries from configure to make via standard interface: LIBS. Prune configure.ac debugging support (-DDEBUG is unused) and migrate remaining extra compiler warning options to Makefile.am. Add correct package bug report pointer and homepage. Delete INSTALL, as it is created by autoreconf (if foreign is removed.) Automake maintainer-mode is goo is deprecated, remove. commit 753fc6e876f502dc3556f6ee3098dd161840ba62 Author: Barak A. Pearlmutter Date: Thu Feb 7 16:05:33 2013 +0000 Snarf desktop file tweaks from repo: git://github.com/pld-linux/gromit commit ac6aeebe20173ea3a7435f6b5447849b3b688450 Author: Barak A. Pearlmutter Date: Thu Feb 7 11:04:37 2013 +0000 Address desktop-file-validate issues. commit fe1c5b1ad0fbee9768c0e954ec9c0ab9c22e0bc8 Author: Barak A. Pearlmutter Date: Thu Feb 7 15:55:56 2013 +0000 Remove unused variable have_key. commit f6296ed45397d38bb531cd4e738ced3e8babc132 Author: Barak A. Pearlmutter Date: Thu Feb 7 15:52:28 2013 +0000 Silence sign/size compiler warnings. commit 5b224b9792ccdb52f50740ca3c124331bf707049 Author: Christian Beier Date: Mon Sep 3 16:33:29 2012 +0200 Use XDG .config dir for user config file. commit 335ff721b4416a4d5cd03a987f81716101e03540 Author: Christian Beier Date: Mon Sep 3 16:25:39 2012 +0200 Only grab master devices. If we grab slaves as well, we get no input at all. commit 58bdef4d49ab4269fedda55e825ce8ad8a62076c Author: Monty Montgomery Date: Mon Sep 3 16:03:47 2012 +0200 Add reasonably complete support for slave devices. The current code doesn't see slave devices. I'm guessing it all worked when you originally updated the code since most of the support was already there, but it got broken by further shifts in the XI2 model. 1) I have a thinkpad tablet and the old gromit (which otherwise worked rather poorly) let me configure the trackpad/touchpoint/touchscreen/wacom pen and wacom eraser separately. Gromit-mpx only sees 'Virtual Core Pointer'. This patch adds (updates?) slave visibility through XI2. 2) Proximity events are deprecated (they're still in the headers but do nothing). I've eliminated that code and gone to a strategy of doing 'proximity' events through mouse motion. commit e5d460eca4ccc3021ddd3eb8ea7aa08700afc21a Author: Christian Beier Date: Mon Sep 3 15:49:41 2012 +0200 Enable silent make if available. commit 16a8dfcf8909f74ee303d23d33a5bf304ff42918 Author: Monty Montgomery Date: Mon Sep 3 15:18:44 2012 +0200 Reduce the requested height in the size_request by one. The GNOME3 panel doesn't hide then when gromit-mpx is activated. It looks like the panel is doing this on purpose because we're on top and it thinks we want full screen. commit 13d2e8e19868737d80fe6c1d9ab480cddb62eb1c Author: Christian Beier Date: Thu Oct 27 01:50:53 2011 +0200 Add libm to linker flags. commit 761b882b422a4fcb7ce556a40e04a356bbc906dc Author: Christian Beier Date: Thu Jul 14 00:01:56 2011 +0200 Add libx11 dependency since we're using XSync(). commit f2d99ce4d55374cd0d7901f6db30fe4593d7e346 Author: Christian Beier Date: Mon May 9 18:37:21 2011 +0200 Fix crash when grabbed device goes away. commit 31219f4243849174ebcac230b726333f8fb97e66 Author: Christian Beier Date: Fri Apr 29 18:40:44 2011 +0200 Get rid of extra build flags. commit 73c52d654c9e54f73d0a05dc5134d8544a6a68a1 Author: Christian Beier Date: Fri Apr 29 18:37:46 2011 +0200 Use XSync() instead of gdk_flush(). commit baa86b20462083bbb03b7239a463cddf1f3c26d3 Author: Christian Beier Date: Fri Apr 29 18:36:17 2011 +0200 Fix build dep. commit 43f73854d457856064df21dab7381cc97bb005ac Author: Christian Beier Date: Sat Feb 12 17:52:01 2011 +0100 Some more tray icon work. commit e8e09bd806bbbe1f4dab0e1b1e442c075c043bda Author: Christian Beier Date: Sat Feb 12 16:33:07 2011 +0100 Fix a runtime warning. commit 0403cae96db2b44e5361c96f9a1d8d36922a4db2 Author: Christian Beier Date: Sat Feb 12 16:26:59 2011 +0100 First stab at tray icon. commit acebbb960fcb7b8aa562292e6e6b6391818baa01 Author: Christian Beier Date: Thu Feb 10 23:59:33 2011 +0100 Last ChangeLog update for 1.0. commit a0341543c2e0f1e008d798d70f9d80c89ba6cc81 Author: Christian Beier Date: Thu Feb 10 23:52:15 2011 +0100 Make debian packaging lintian conform. commit ec91795dc79e5d31a4122a9a1853caed9696cffb Author: Christian Beier Date: Thu Feb 10 23:42:35 2011 +0100 Small fix to manpage. commit 8702b40b71698e30aa7bc65329ecfe9df5e9e0ce Author: Christian Beier Date: Thu Feb 10 23:31:27 2011 +0100 Update ChangeLog. commit 794c2ddd6c60620608d68aa9bfca2e6dcc8288cd Author: Christian Beier Date: Thu Feb 10 23:27:08 2011 +0100 Bring manpage up to date. commit f56f54fb5862042f300ff51713a03beede912f25 Author: Christian Beier Date: Thu Feb 10 23:21:34 2011 +0100 Update debian packaging. commit 725f8727a07e1385e8c16b01db93ff6878165254 Author: Christian Beier Date: Thu Feb 10 23:12:54 2011 +0100 Raise version to 1.0 commit d1542b0893a6f99fda8a79526b7a035be3997b35 Author: Christian Beier Date: Thu Feb 10 23:12:11 2011 +0100 Raise GTK version requirement. commit 94486f4aa9588565bddaa9684ae85a4c5a8db63d Author: Christian Beier Date: Mon Jan 31 19:41:48 2011 +0100 Adapt to changed GTK3 API. commit a3e8cbd1505fbd86e2e36e29136c90d5ee43cb3d Author: Christian Beier Date: Thu Jan 27 18:14:09 2011 +0100 Use a PNG icon instead of XPM. commit 29ae56a653fb8e5b486f7356b9c6e708740713e6 Author: Christian Beier Date: Thu Jan 27 17:44:26 2011 +0100 Adapt README, update NEWS. commit 62df11b02a8ec9d0c7a345a2dfe5236e6da631a2 Author: Christian Beier Date: Thu Jan 27 16:41:03 2011 +0100 Turn of anti-aliasing when running non-composited. commit de2613eae0214082c75d8132060ab1680aa084e2 Author: Christian Beier Date: Thu Jan 27 16:04:03 2011 +0100 Remove commented out code. commit 39f9608635e15257e8fc5f802be18ecfaac33ec7 Author: Christian Beier Date: Thu Jan 27 16:01:52 2011 +0100 Rename data->shape. commit 232007b03a78a0acef6b67ab73c7b44323a4bdc8 Author: Christian Beier Date: Thu Jan 27 15:56:44 2011 +0100 Rename shape_gc and fg_color. commit 709a2a77937ea1214de8f2cda6ed697ac590fd11 Author: Christian Beier Date: Thu Jan 27 15:47:10 2011 +0100 Remove unneeded define. commit 37b30ef249b09fa2ce06e697cbccba07158eb0f7 Author: Christian Beier Date: Thu Jan 27 14:11:16 2011 +0100 Handle compositing support change. Invalidate window when needed. commit 2f0528a2bafb056d2afaf709f16bcf6f164d5c03 Author: Christian Beier Date: Thu Jan 27 00:02:55 2011 +0100 Remove obsolete README part. commit b146e4314763013f641beacddce367732bab386e Author: Christian Beier Date: Thu Jan 27 00:00:00 2011 +0100 Set input shape mask every time we change the shape. commit 1d7c2acddf8508c8df3dc93f9329868584e21646 Author: Christian Beier Date: Wed Jan 26 23:10:35 2011 +0100 Remove unneeded changing of window background colour. commit 46ab12cf8715b44fa6c4350fa2865fd0397bc5ea Author: Christian Beier Date: Wed Jan 26 22:42:47 2011 +0100 Fix some warnings. commit 0e649b7028edf37f44681729b42b703a8a861262 Author: Christian Beier Date: Wed Jan 26 22:08:14 2011 +0100 Draw with 75% opacity to make annotations slightly transparent. commit 29013ae51a89c271a2d5eacc288c7148845b1217 Author: Christian Beier Date: Wed Jan 26 21:12:57 2011 +0100 Make use of XCOMPOSITE where available. Really fast drawing! commit b88b4134ca0153ebe08f65c556fb16bf0e02ae67 Author: Christian Beier Date: Wed Jan 26 21:07:36 2011 +0100 Update NEWS. commit 5e4b3f1b7c80ac34cd6fb862734ea9cc61f4855e Author: Christian Beier Date: Wed Jan 26 21:05:51 2011 +0100 Set drawn stuff transparent for input. commit 4cfaa61e1ffa77aa9c56da767ee29291331fd8e3 Author: Christian Beier Date: Wed Jan 26 00:04:45 2011 +0100 Possibility to add an alpha channel to main window. commit 89c1985b87f62b71d5bbbc2be442ea0a6cc07550 Author: Christian Beier Date: Tue Jan 25 19:39:16 2011 +0100 Update TODO. commit 34221c550a982294795b8c16282d69787ae31120 Author: Christian Beier Date: Fri Jan 21 00:04:01 2011 +0100 Get rid of that extra drawing widget. commit a7aa282f51749ca99d5e7f22092ad90e602929f2 Author: Christian Beier Date: Thu Jan 20 23:46:33 2011 +0100 Update NEWS + TODO. commit 92cebc419ec2c0761f1d3ef69c7645a08e34d4ea Author: Christian Beier Date: Thu Jan 20 23:01:08 2011 +0100 Get rid of one useless drawing context. Fix arrow drawing as well. commit 47bbd2706bb85bbcc0f59fa2451b4c910dbb52ad Author: Christian Beier Date: Thu Jan 20 22:01:59 2011 +0100 Fix redraw after unhide. Before, everything was restored with the same colour. commit d31fded484482740dabc251ef21d45821dc202c2 Author: Christian Beier Date: Thu Jan 20 21:35:23 2011 +0100 Use right signal. commit 65834551d1c949cfbeceb1745139c7a8547df3f9 Author: Christian Beier Date: Thu Jan 20 20:38:43 2011 +0100 Update TODO. commit 80998c31107dd4fb26b08eb04b005e4ca7895971 Author: Christian Beier Date: Thu Jan 20 20:12:42 2011 +0100 refactor (once again) commit bc7a694ab9ce5883f526511d571697ec4cde99cf Author: Christian Beier Date: Thu Jan 20 19:53:35 2011 +0100 Make it work after screen resize. commit 776f2279797fc742ca6e11456eb8826c05e2c921 Author: Christian Beier Date: Thu Jan 20 17:30:43 2011 +0100 Add some debug output. commit db0614a33fadaf428a8c65874760efd267d9c531 Author: Christian Beier Date: Thu Jan 20 17:11:48 2011 +0100 Another potential memleak. commit 1fdde85ed325f8b76c1bd77da4bad3a3b68ab01b Author: Christian Beier Date: Thu Jan 20 17:06:56 2011 +0100 Plug memleak in shape combine. commit 5c867d636260157bf13f5ff048ee421dae6f5381 Author: Christian Beier Date: Thu Jan 20 17:00:48 2011 +0100 PLug memleak in device init. commit 6b2b04597990755f46aa9ea402e56f79cc5fa478 Author: Christian Beier Date: Thu Jan 20 16:45:10 2011 +0100 Update TODO. commit faa8f7c9023a062419322e7662ecbe6d79131b54 Author: Christian Beier Date: Thu Jan 20 16:22:24 2011 +0100 Make clear_screen() work again. commit 39b3029a711b20f2a50862749a82447a40e0b7be Author: Christian Beier Date: Thu Jan 20 16:00:16 2011 +0100 Revert "Revert "Zero devdata->motion_time on ungrab."" This reverts commit baec3333beb16b5746b85f392889fef54ee5293e. Ooops. commit 77e13e17511ce4e02b702c4403764ad8eb8e3c48 Author: Christian Beier Date: Thu Jan 20 15:56:12 2011 +0100 Fix typo. commit baec3333beb16b5746b85f392889fef54ee5293e Author: Christian Beier Date: Thu Jan 20 15:54:44 2011 +0100 Revert "Zero devdata->motion_time on ungrab." This reverts commit ea3a22879686c1dd3f7042c2a6950289e5b50ac2. commit 517872da06bf419363ca26849c1040ee5f7741b5 Author: Christian Beier Date: Thu Jan 20 15:49:43 2011 +0100 The great big GTK3 compatibility commit. Hopefully the last one. Next for some cleanup. commit 68cf6140e77bb7d3d5dac432a9edb45fb1eaf77b Author: Christian Beier Date: Tue Nov 16 00:46:30 2010 +0100 Change hotkey to F9. commit ea3a22879686c1dd3f7042c2a6950289e5b50ac2 Author: Christian Beier Date: Mon Nov 8 23:09:38 2010 +0100 Zero devdata->motion_time on ungrab. This works around a (gtk?) bug where after grab, ungrab, grab the button down event is lost, letting gromit-mpx draw from last_* coords (dating from before the ungrab) to current position. Gahh. commit 6a9ac468e278f4f9c704ea8693894d306b838a74 Author: Christian Beier Date: Thu Oct 21 19:31:11 2010 +0200 Fix crash on screen change. commit 4d84d1885a0c7ca59969d4adb6090d7ba37fe9f9 Author: Christian Beier Date: Thu Oct 21 19:11:44 2010 +0200 Big refactoring. Fix some memleaks, fewer LOC. commit 8933904af9a77f62d2f5df4ae0b9a87f5b97cab8 Author: Christian Beier Date: Thu Oct 21 18:00:31 2010 +0200 Some more UGLY workarounds. commit bc4ebd8d20d18d719c133adc0300c94544ebb33d Author: Christian Beier Date: Tue Oct 19 15:10:08 2010 +0200 Workaround buggy getting of attached keyboard via GDK. commit 02f54532eb5b97bfee37379f84d2bbdcf3d74082 Author: Christian Beier Date: Tue Oct 19 13:00:11 2010 +0200 Make cursor xpms const char*. commit f051158999b8961ec66d18abc6f24e118ef439bc Author: Christian Beier Date: Tue Oct 19 12:58:00 2010 +0200 Include hotspot in cursor xpm's. commit 82fa00996eb775c5631b1e3365d0b9d002614faf Merge: 3462a28 dfb94a9 Author: Christian Beier Date: Tue Oct 19 12:55:15 2010 +0200 Merge branch 'master' of github.com:bk138/gromit-mpx commit 3462a2861b561fa3290cd13628ff12358329aec8 Author: Christian Beier Date: Tue Oct 19 12:54:51 2010 +0200 Better cursors. commit dfb94a9bcb004559a4bd3f7a7448555fbee2eb6f Author: Christian Beier Date: Tue Oct 12 13:28:49 2010 +0200 Remove most of commented out code. commit 250be7259e513c199964684579d277b2721461d9 Author: Christian Beier Date: Thu Oct 7 15:35:13 2010 +0200 Update TODO. commit 7c788f840478245fc3c816d42bbb41fc9fd48053 Author: Christian Beier Date: Mon Sep 6 18:07:27 2010 +0200 Move config file related define to config.h commit a335295f88b826d9e40d54e5551ce66ac9a3325c Author: Christian Beier Date: Mon Sep 6 17:58:28 2010 +0200 Remove gromit_ prefix from all functions. commit 1e186a1b3d3b9f235a8b0a8bc4b7ea539b095096 Author: Christian Beier Date: Mon Sep 6 17:47:48 2010 +0200 Some more cleanup. commit 4a30de31a5b8576d651aa6951cb728ea481e3747 Author: Christian Beier Date: Mon Sep 6 17:41:48 2010 +0200 Better callback function names. commit a14109e6965fe7b0850e21e557ff3c9d78961d99 Author: Christian Beier Date: Mon Sep 6 17:25:46 2010 +0200 Make colour change on modifier keys when mouse button down and moving. commit 4902110671d6056884f6899b9520202e5c7e452e Author: Christian Beier Date: Mon Sep 6 17:17:08 2010 +0200 Update TODO. commit a09faa7341e408c572344ee0d241611cb8710425 Author: Christian Beier Date: Mon Sep 6 17:04:55 2010 +0200 Workaround grey line being drawn on startup. commit 7e77e0cebbb82546f073ec74e9a6e98bd155743d Author: Christian Beier Date: Mon Sep 6 15:15:08 2010 +0200 Workaround broken device cursor setting. commit 64470a84b61902d03ca4286a6f39804d509c7ae0 Author: Christian Beier Date: Sat Sep 4 16:59:16 2010 +0200 Make Eraser work again. But cursor still not changed. GTK bug? commit ba8ad5d48cae735b5cbc1d078f052c3c51d7f4dd Author: Christian Beier Date: Sat Sep 4 16:39:38 2010 +0200 Re-add some formerly removed lines as comments. commit 6927a26c64c21d73de4e03a4e2c6aa1cf8c4d405 Author: Christian Beier Date: Fri Sep 3 18:49:44 2010 +0200 Some debug output. commit 58abfab08255669f5482b5cfeb35f1c42c58602c Author: Christian Beier Date: Fri Sep 3 18:32:30 2010 +0200 First early stab at porting to Cairo. TODO: * eraser * clean startup without grey line * code cleanup commit 583c9782d074603e22bd9ccea132e38420a08a36 Author: Christian Beier Date: Tue Jun 22 14:22:34 2010 +0200 Update manpage. commit b4e3f55b3304bc82db2bcc27527cbba8a9066e51 Author: Christian Beier Date: Tue Jun 22 14:13:22 2010 +0200 Add debian packaging. commit 3bd11f237a490bc64a7acc4cbc1f8ebbc81c8c4f Author: Christian Beier Date: Tue Jun 22 14:11:36 2010 +0200 Add .desktop file and icon, rename config file. commit b5aff5e7687dcc425cd5df27bd661fc328a8c3eb Author: Christian Beier Date: Tue Jun 15 14:18:43 2010 +0200 Use GTK/GDK accessor functions throughout the code. commit 9be68d0ef0c1f6563987ccc63b71fb8db84fa5fc Author: Christian Beier Date: Fri Jun 11 16:02:44 2010 +0200 Act on master pointer add or removal. commit 6d495414eb1a4d3329d5af02330364e5d8192db7 Author: Christian Beier Date: Wed Jun 2 17:14:35 2010 +0200 Re-add gromit_select_tool() call to paintto(). commit e922ef293f2b6667eadf675012d7800fef3decdb Merge: 376e0d6 cf273c5 Author: Christian Beier Date: Wed Jun 2 16:39:15 2010 +0200 Merge branch 'master' of github.com:bk138/gromit-mpx Resolved conflicts: TODO commit 376e0d6179635ced4c8d9724727d6d8764984f94 Author: Christian Beier Date: Wed Jun 2 16:36:11 2010 +0200 Grab hotkey per-device! With XIAllMasterDevices it doesn't seem to work. Anyway, we now have per-device hotkey handling! commit 5d177b7d072ed6aae32ff2eeb581aca64f5c6f52 Author: Christian Beier Date: Wed Jun 2 14:19:12 2010 +0200 Revert "Remove XInput stuff from build system." This reverts commit fc6841192289a53dd7682053c1171c15051c7d83. commit cf273c5558f3638c2095ebb78ef48571b6d53a0b Author: Christian Beier Date: Thu May 27 20:59:29 2010 +0200 Update README and TODO. commit 6d0f5822e14ffb9dc59bbdcb08f765f64fd7f639 Author: Christian Beier Date: Wed May 26 15:32:02 2010 +0200 Change some C++ style comments to proper C style. commit 647543d90735ab5d25190581d615fbaa5f4d9e35 Author: Christian Beier Date: Tue May 25 16:14:20 2010 +0200 Change toggle_grab() to take a GdkDevice* arg. And fix a segfault in gromit_acquire_grab(). commit 99222701a808ca7b0dc23b8f7148abb82ed3099b Author: Christian Beier Date: Tue May 25 15:07:15 2010 +0200 Add device getter to hotkey handler. commit cf80650446a00c5b64a3477ee9d42ac8921b1cf8 Author: Christian Beier Date: Tue May 25 13:39:44 2010 +0200 Update TODO. commit fc6841192289a53dd7682053c1171c15051c7d83 Author: Christian Beier Date: Tue May 25 12:41:43 2010 +0200 Remove XInput stuff from build system. commit dbe41ece078af8b2863b2aadc4f310d4f3e1442b Author: Christian Beier Date: Tue May 25 12:39:17 2010 +0200 Split out config file parsing into extra files. commit 6bacd6064d82ccb1701e84492caf35dd6716ffad Author: Christian Beier Date: Tue May 25 11:59:32 2010 +0200 Change cursor whith the grab call. commit a50f3944d20c89655fd8283c0d1bd79f32e782a1 Author: Christian Beier Date: Tue May 25 11:37:52 2010 +0200 Really fix device indexing. commit 6844981cea48e9e2ef0a27adddd3993ed6881895 Author: Christian Beier Date: Tue May 25 11:09:56 2010 +0200 Remove last Xinput remnants. commit c1f977b83af3ae6531b2724158c95e9155fac6d4 Author: Christian Beier Date: Tue May 25 10:58:18 2010 +0200 Adapt grab index to device order. commit c3d87b89029c615d799bf2c2180fde1c997defd2 Author: Christian Beier Date: Tue May 25 10:39:43 2010 +0200 Use GDK cursors again. commit 21bc55cf904039fe4662a7c350a05b3ac83baf86 Author: Christian Beier Date: Tue May 25 10:28:51 2010 +0200 Re-enable gdk_device_get_history() usage. commit 11b4b8b9c2f19989c787ece8b69991b5d3fb6278 Author: Christian Beier Date: Tue May 25 09:20:36 2010 +0200 Remove device_id member from device data. commit 68e905e0cc2f534c346789e503f50df8c70b77d1 Author: Christian Beier Date: Tue May 25 09:19:53 2010 +0200 Add -DGTK_MULTIDEVICE_SAFE to CFLAGS. commit 87c5e7c7913b52ed80c7ea41a2c3a9ce752c91d9 Author: Christian Beier Date: Tue May 25 00:44:32 2010 +0200 Make it build with GTK3. commit 52a68771f0bb7d51234586d51c8ad7948a7a4cd2 Author: Christian Beier Date: Mon May 24 23:10:33 2010 +0200 Raise GTK+ requirement to GTK+-3.0. commit 50345a3eecc17281c9c8e5568e931fe14f6cd6d7 Author: Christian Beier Date: Thu Apr 15 23:02:11 2010 +0200 More README updates. commit 41c1569edfa93e7a0fc375842e2251410a8ff733 Author: Christian Beier Date: Thu Apr 15 22:53:48 2010 +0200 Update ChangeLog. commit 9dc89a7bde08a6ca68e8029867cad00b1b4ed567 Author: Christian Beier Date: Thu Apr 15 22:53:28 2010 +0200 Really update README. commit 5b1849c033f60e942cc708e6476a33cad00f5299 Author: Christian Beier Date: Thu Apr 15 22:46:57 2010 +0200 Update README. commit d94add6dfeb8de6f176c4b423cc26f84db807305 Author: Christian Beier Date: Thu Nov 19 01:34:29 2009 +0100 some more callback refactoring. commit 27056d1ee8ce1d8b6215de685427e5ffb9ba8911 Author: Christian Beier Date: Thu Nov 19 01:26:23 2009 +0100 move callbacks into seperate files. commit 4ec7362f6e84c6845211cb19703e2a4ee0766c0e Author: Christian Beier Date: Thu Nov 19 00:51:10 2009 +0100 autotoolize! commit 0158463b8a718d88e7c897d6e429e31c3e26cbda Author: Christian Beier Date: Wed Nov 18 23:57:26 2009 +0100 remove gtk patch. commit ae96f1a94aad3b1e66717e25d0eb8b033ef68987 Author: Christian Beier Date: Wed Nov 18 23:57:01 2009 +0100 support changing screen dimension. commit 45c0bbc6b6f05c2ba7e9de584f7640197922a0b5 Author: Christian Beier Date: Wed Nov 18 23:38:40 2009 +0100 Makefile: add etags target. commit 6426d49246c8d86d2e76520f146fbf00045710bd Author: Christian Beier Date: Fri Aug 21 00:50:07 2009 +0200 rename gromit.c to gromit-mpx.c commit f455a1d0eee7760f47ff703b3b0fa0d482b73bdb Author: Christian Beier Date: Wed Jul 8 15:47:11 2009 +0200 only toggle virtual core pointer if hotkey pressed. commit bc2adc0875d704ba2565971aefc2171d5dfeee96 Author: Christian Beier Date: Mon Jul 6 17:11:00 2009 +0200 port over to XI2. commit 47aaec03698268601e33388e9fd9fbdbf51a819e Author: Christian Beier Date: Tue Jun 30 19:14:29 2009 +0200 add gdk patch to repo. commit 26c3ca9e307901c24fa46cb6ea81e0591c5a07ef Author: Christian Beier Date: Fri May 15 00:00:11 2009 +0200 remove select_tool() call in paintto(). gtk doesn't seem to set the button masks in event state, so we would always revert to standard tool again if the pointer moves. makes it now inpossible to draw multi- coloured lines, but so what.... commit ea07f5d4aebbc2aeb176f6d80a63632442688b61 Author: Christian Beier Date: Thu May 14 23:31:59 2009 +0200 add myself to copyright (c). commit de60cd8a7f78b285860e9fbda49a3b95f3f14dda Author: Christian Beier Date: Thu May 14 23:31:34 2009 +0200 add notes about gtk patch. commit db3f29f613770c4ddfc14e6578a425ce3f52d604 Author: Christian Beier Date: Thu May 14 23:26:51 2009 +0200 add README.MPX commit 61b14d252566dc4b91d53a6681392bc0e5f1750d Author: Christian Beier Date: Thu May 14 23:13:00 2009 +0200 remove all XINPUT2 ifdefs. we're gromit-mpx anyway! for pre-XI2, people can use the original gromit... commit 11dd8860942c986d1aa2d5b2f0e3beb277c72d08 Author: Christian Beier Date: Thu May 14 21:14:15 2009 +0200 initial import. gromit-mpx-1.1/Makefile.am000066400000000000000000000012071220446531300155120ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in SUBDIRS = src doc_DATA = \ README\ AUTHORS\ ChangeLog\ NEWS Applicationsdir = $(datadir)/applications/ Applications_DATA = data/gromit-mpx.desktop pixmapdir = $(datadir)/pixmaps pixmap_DATA = data/gromit-mpx.png \ data/gromit-mpx.xpm man_MANS = gromit-mpx.1 scalabledir = $(datadir)/icons/hicolor/scalable/apps scalable_DATA = data/gromit-mpx.svg configdir = $(sysconfdir)/gromit-mpx config_DATA = data/gromit-mpx.cfg EXTRA_DIST = $(doc_DATA) \ $(Applications_DATA) \ $(pixmap_DATA) \ $(config_DATA) \ COPYING gromit-mpx-1.1/NEWS000066400000000000000000000006661220446531300141650ustar00rootroot00000000000000 Gromit-MPX 1.1 * Added reasonably complete support for slave devices thanks to Monty Montgomery. * Tweaked build system, packaging, icon thanks to Barak A. Pearlmutter. * Fixed some crashes. Gromit-MPX 1.0 * Concurrent multi-user operation using GTK3 with Multi-Pointer-X. * Drawn annotations do not intercept mouse clicks. * Makes use of the Composite extension where available to allow for really fast drawing.gromit-mpx-1.1/README000066400000000000000000000133211220446531300143360ustar00rootroot00000000000000Gromit-MPX ---------- Gromit-MPX is a multi-pointer port of the original Gromit annotation tool (http://www.home.unix-ag.org/simon/gromit) by Simon Budig . It enables graphical annotations with several pointers at once and is A LOT faster since it uses the XCOMPOSITE extension where available. Also, it does not inhibit Drag-and-Drop like the original Gromit tool. What is it? ----------- Gromit-MPX (GRaphics Over MIscellaneous Things) is a small tool to make annotations on the screen. Its main use is for making presentations of some application. Normally, you would have to move the mouse pointer around the point of interest until hopefully everybody noticed it. With Gromit-MPX, you can draw everywhere onto the screen, highlighting some button or area. How to use it ------------- You can operate Gromit-MPX using its tray icon, but since you typically want to use the program you are demonstrating and highlighting something is a short interruption of your workflow, Gromit-MPX can be toggled on and off on the fly via a hotkey: Per default, it grabs the "F9" key, so that no other application can use it and it is available to Gromit-MPX only. The available commands are: F9: toggle painting SHIFT-F9: clear screen CTRL-F9: toggle visibility ALT-F9: Quit Gromit-MPX. You can specify the key to grab via "gromit-mpx --key ". Specifying an empty string or "none" for the keysym will prevent gromit from grabbing a key. Alternatively you can invoke Gromit-MPX with various arguments to control an already running Gromit-MPX . Usage: gromit-mpx --quit will cause the main Gromit-Mpx-MPX process to quit (or "-q") gromit-mpx --toggle will toggle the grabbing of the cursor (or "-t") gromit-mpx --visibility will toggle the visibility of the window (or "-v") gromit-mpx --clear will clear the screen (or "-c") If activated Gromit-MPX prevents you from using other programs with the mouse. You can press the button and paint on the screen. Key presses (except the "F9"-Key, see above) will still reach the currently active window but it may be difficult to change the window-focus without mouse... The next "gromit-mpx --toggle" will deactivate Gromit-MPX and you can use your programs as usual - only the painted regions will be obscured. Gromit-MPX is pressure sensitive, if you are using properly configured XInput-Devices you can draw lines with varying width. It is possible to erase something with the other end of the (Wacom) pen. Building it ----------- Gromit-MPX is small and lightweight. It needs GTK+3 to build. Simply type "configure", "make" and "make install". If you checked out from git instead of using the tarball, an "autoreconf --install" is needed to setup the build system. Configuration: ------------- Gromit-MPX is configurable via the file ".gromit-mpx.cfg" in your Homedirectory. Here you can specify which Device/Button/Modifier combination invokes which tool. See the file "gromitconf" distributed with this program for an example. An overview on the syntax: # Comments can be either # Shell-Style or /* C-Style. */ This entry defines the tool "red Pen", a pen with size 7 and color red. You can specify the color in X-Style: e.g. "#FF0033" or colors from rgb.txt. "red Pen" = PEN (size=7 color="red"); The following Entries copy an existing configuration (in this case "red Pen") and modify the color. "blue Pen" = "red Pen" (color="blue"); "yellow Pen" = "red Pen" (color="yellow"); You can also draw lines that end in an arrow head. For this you have to specify "arrowsize". This is a factor relative to the width of the line. For reasonable arrowheads start with 1. "blue Pen" = "blue Arrow" (arrowsize=2); An "ERASER" is a tool that erases the drawings on screen. The color parameter is not important. "Eraser" = ERASER (size = 75); A "RECOLOR"-Tool changes the color of the drawing without changing the shape. Try it out to see the effect. "green Marker" = RECOLOR (color = "Limegreen"); If you define a tool with the same name as an input-device (see the output of "xsetpointer -l", if there is a "SWITCH"-Tool it is uninteresting...) this input-device uses this tool. Additionally you can limit the Scope to specific combinations of Mousebuttons (1,2,3,4,5 or Button1,...,Button5) and Modifiers (SHIFT, CONTROL, ALT, META, while ALT==META). "Core Pointer" = "red Pen"; "Core Pointer"[SHIFT] = "blue Pen"; "Core Pointer"[CONTROL] = "yellow Pen"; "Core Pointer"[2] = "green Marker"; "Core Pointer"[Button3] = "Eraser"; The descision, which tool to use follows a simple policy: a) Buttons are more important than Modifiers b) Low number Buttons are more important than higher ones c) Modifiers: SHIFT > CONTROL > ALT/META. d) Gromit-MPX tries partial matches: If you define "Core Pointer"[] and "Core Pointer"[SHIFT, CONTROL] and only SHIFT actually is pressed, Gromit-MPX will use the second definition if there is no "Core Pointer"[SHIFT] definition. Same logic goes for the buttons. Potential Problems: ------------------ When there is no compositing manager such as Compiz or xcompmgr running, Gromit-MPX falls back to a legacy drawing mode. This may drastically slow down your X-Server, especially when you draw very thin lines. It makes heavy use of the shape extension, which is quite expensive if you paint a complex pattern on screen. Especially terminal-programs tend to scroll incredibly slow if something is painted over their window. Like the original Gromit, this program is distributed under the Gnu General Public License. See the file COPYING for details. Thanks to Simon for the groundwork done! Christian Beier gromit-mpx-1.1/TODO000066400000000000000000000001731220446531300141470ustar00rootroot00000000000000 * tray icon * intro screen * runtime option to not show annotation on every virtual desktop * spot memleaks * code cleanupgromit-mpx-1.1/configure.ac000066400000000000000000000016561220446531300157540ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([gromit-mpx],[1.1],[Christian Beier ],[gromit-mpx],[https://github.com/bk138/gromit-mpx]) AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_SRCDIR([src/gromit-mpx.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O AC_HEADER_STDC PKG_PROG_PKG_CONFIG([0.20]) # Checks for libraries. # check for gtk PKG_CHECK_MODULES([GTK3], [gtk+-3.0 >= 2.99.3]) # check for XInput PKG_CHECK_MODULES([XINPUT2], [xi >= 1.3]) # check for X PKG_CHECK_MODULES([X11], [x11]) # check for math AC_CHECK_LIB([m], [atan2]) # export linker flags in the right order LIBS="$GTK3_LIBS $XINPUT2_LIBS $X11_LIBS $LIBS" # *************************************************************************** # finally # *************************************************************************** AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT gromit-mpx-1.1/data/000077500000000000000000000000001220446531300143675ustar00rootroot00000000000000gromit-mpx-1.1/data/gromit-mpx.cfg000066400000000000000000000010221220446531300171460ustar00rootroot00000000000000# Default gromit-mpx configuration # taken from Totem's telestrator mode config # added default entries "red Pen" = PEN (size=5 color="red"); "blue Pen" = "red Pen" (color="blue"); "yellow Pen" = "red Pen" (color="yellow"); "green Marker" = PEN (size=6 color="green" arrowsize=1); "Eraser" = ERASER (size = 75); "default" = "red Pen"; "default"[SHIFT] = "blue Pen"; "default"[CONTROL] = "yellow Pen"; "default"[2] = "green Marker"; "default"[Button3] = "Eraser"; gromit-mpx-1.1/data/gromit-mpx.desktop000066400000000000000000000004161220446531300200660ustar00rootroot00000000000000[Desktop Entry] Exec=gromit-mpx Icon=gromit-mpx Name=Gromit-MPX Type=Application Comment=GRaphics Over MIscelaneous Things, a multi pointer annotation tool Comment[pl]=Program do rysowania bezpoÅ›rednio po ekranie Terminal=false StartupNotify=false Categories=Graphics; gromit-mpx-1.1/data/gromit-mpx.png000066400000000000000000000014051220446531300172000ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ ÑU:…IDATXý—?hQÆ/Zj¢pWˆH$\@H%œw"H"n‘Wb}‚,¬Å  ¢hƒâ‚ˆî©$#),±ˆ¸"Ž¢26oÃäyëî™Í<îÞŸyß73ïͼ…mŠÀ°À+_ÚGì„\h¬)À÷5Û¦ÖšY{oè zÌÚŠÀ·,ÁÏ l(ðEÞrÀG(àƒä!ý¡¿'PÊ |H m7jä%%Çòsä)- Ü˼.ðØÏüšrû—¤k¶ô=ŸÈ¸ °¬ÀŸämù˜SHúò&ºuá¼pw[ð `—›7ðòK30®†ÓiÊõ½]‚ž´åw%æM0›´AY`U)ìíâÐ6TªŽmI!(ûlÿŽvÒ{¸ u¦~sª ؓƒϊm=amÍɺ­9kÓxý¸HQ]ÐІ¡akÇŒJå©CÉj—‡þp×ÀRä`ÄÎ}ïæGLŸn3ôÙ}<µïåéå"ßÀ(@E¼0ZÐ4~1úßi\±%øû«âµÜ=´NÓøÅž¬2ZpãëÃÀøs·1çªâµã¿vIjpM ÐiãH!ÎÒM™ü4 Œ šçº!® ¹×ÐuÛßò8½thÉ@?7—Õ’*×z÷\˜­ÆxÁý2NGýêÔÀ±ÊÔ@é÷ÃqÏÒ£ãÀc› ×êŠxaÓøE’"7i;4óÈ›gÀÀ;àÒ}ä©r`ü@ a‰f*=–íàðÓÉß5K®fÛa57cþ!q×-ñú T’*›ÀÅ,¿Œþɶé1ðñIEND®B`‚gromit-mpx-1.1/data/gromit-mpx.svg000066400000000000000000000160731220446531300172220ustar00rootroot00000000000000 image/svg+xml MPX gromit-mpx-1.1/data/gromit-mpx.xpm000066400000000000000000000025061220446531300172230ustar00rootroot00000000000000/* XPM */ static char *gromit_mpx[] = { /* columns rows colors chars-per-pixel */ "32 32 6 1 ", " c #FF0000", ". c #FF7522", "X c #3BFF49", "o c #FF8D29", "O c #FF8F2A", "+ c None", /* pixels */ "+++++++++++++++++ ++++++++", "++++++++++++++ ++ +++++++", "+++++++++++++ +++++++ +++++++", "++++++++++++ ++++++++++++++++", "++++++++++ ++++++++++++++++++", "+++++++++ +++++++++++++++++++", "++++++++ +++++++++++++++++++++", "+++++++ ++++++++++++++++++++++", "++++++ +++++++++++++++++++++++", "++++++ +++++++++++++++++++++++", "++++ ++++++++++++++++++++++++", "++++ +++++++++++++++++++++++++", "+++ +++++++++++++++++++++++++", "+++ ++++++++++++++++++++++++++", "++ +++++++++++++++++++++++++++", "++ +++++++++++++++ +++++++++", "+ ++++++++++++++ +++++++", "+ +++++++++++ +++++++", "+ +++++++++ +++++++", " +++++++++ +++ +++++++", " ++++++++ ++ +++++++", " ++++++++ ++++ ++ +++++++", " ++++++++++++++++ + ++++++++", " ++XXX+++XXX++XXXXXX XX++++XX+", " ++XXX+++XXX++XXO +XX XX++XX++", " ++XXXX+XXXX++XX XX XX++XX++", " ++XX+X+X+XX++XX.+OXX++XXXX+++", " +XX+XXX+XX XXXXXX+++XXXX+++", "+ +XX++X++XX XX++++++XX++XX++", "+ XX + XX XX++++++XX++XX++", "++ XX XX +XX+++++XX++++XX+", "+++ ++++++++++++++++++++" }; gromit-mpx-1.1/gromit-mpx.1000066400000000000000000000071761220446531300156560ustar00rootroot00000000000000.\" Hey, vim: ft=nroff .TH GROMIT-MPX 1 "February 10, 2011" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME Gromit-MPX \- Presentation helper to make annotations on screen .SH SYNOPSIS .B gromit\-mpx .RI [ options ] .br .SH DESCRIPTION \fBGromit-MPX\fP enables you to make multi-pointer annotations on your screen. It can run in the background and be activated on demand to let you draw over all your currently running applications. The drawing will stay on screen as long as you want, you can continue to use your applications while the drawing is visible. .br \fBGromit-MPX\fP is XInput-Aware, so if you have a graphic tablet you can draw lines with different strength, colour, erase things, etc. .br Since you typically want to use the program you are demonstrating and highlighting something is a short interruption of you workflow, Gromit-MPX is activated by either a hotkey or a repeated invocation of Gromit-MPX (the latter can e.g. used by other applications or your windowmanager). .br .SH KEYBOARD CONTROL By default, Gromit-MPX grabs the "F9" key (this can be changed using the "\-\-key" option), making it unavailable to other application. The available shortcuts are: .TP .B F9 toggle painting .TP .B SHIFT-F9 clear screen .TP .B CTRL-F9 toggle visibility .TP .B ALT-F9 quit Gromit-MPX .PP .SH OPTIONS (STARTUP) A short summary of the available commandline arguments for invoking Gromit-MPX, see below for the options to control an already running Gromit-MPX process: .TP .B \-a, \-\-active start Gromit-MPX and immediately activate it. .TP .B \-k , \-\-key will change the key used to grab the mouse. can e.g. be "F9", "F12", "Control_R" or "Print". To determine the keysym for different keys you can use the \fBxev\fP(1) command. You can specify "none" to prevent Gromit-MPX from grabbing a key. .TP .B \-K , \-\-keycode will change the key used to grab the mouse. Under rare circumstances identifying the key with the keysym can fail. You can then use the keycode to specify the key uniquely. To determine the keycode for different keys you can use the \fBxev\fP(1) command. .TP .B \-d, \-\-debug gives some debug output. .SH OPTIONS (CONTROL) A sort summary of the available commandline arguments to control an already running Gromit-MPX process, see above for the options available to start Gromit-MPX. .TP .B \-q, \-\-quit will cause the main Gromit-MPX process to quit. .TP .B \-t, \-\-toggle will toggle the grabbing of the cursor. .TP .B \-v, \-\-visibility will toggle the visibility of the window. .TP .B \-c, \-\-clear will clear the screen. .SH BUGS When there is no compositing manager such as Compiz or xcompmgr running, Gromit-MPX falls back to a legacy drawing mode. This may drastically slow down your X-Server, especially when you draw very thin lines. It makes heavy use of the shape extension, which is quite expensive if you paint a complex pattern on screen. Especially terminal-programs tend to scroll incredibly slow if something is painted over their window. .SH AUTHORS Simon Budig Christian Beier .PP This manual page was written by Pierre Chifflier and Simon Budig for the original Gromit and extended for Gromit-MPX by Christian Beier. gromit-mpx-1.1/src/000077500000000000000000000000001220446531300142455ustar00rootroot00000000000000gromit-mpx-1.1/src/Makefile.am000066400000000000000000000005701220446531300163030ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in AM_CFLAGS = -Wall -Wextra -Wno-unused-parameter AM_CPPFLAGS = \ $(GTK3_CFLAGS) \ $(XINPUT2_CFLAGS) \ $(X11_CFLAGS) bin_PROGRAMS = gromit-mpx gromit_mpx_SOURCES = \ gromit-mpx.c \ gromit-mpx.h \ callbacks.c \ callbacks.h \ config.c \ config.h \ input.c \ input.h \ erase_cursor.xpm \ paint_cursor.xpm gromit-mpx-1.1/src/callbacks.c000066400000000000000000000445501220446531300163400ustar00rootroot00000000000000/* * Gromit-MPX -- a program for painting on the screen * * Gromit Copyright (C) 2000 Simon Budig * * Gromit-MPX Copyright (C) 2009,2010 Christian Beier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include "gromit-mpx.h" #include "input.h" #include "callbacks.h" #include "config.h" gboolean on_expose (GtkWidget *widget, cairo_t* cr, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: got draw event\n"); cairo_save (cr); cairo_set_source_surface (cr, data->backbuffer, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_restore (cr); return TRUE; } gboolean on_configure (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: got configure event\n"); return TRUE; } void on_screen_changed(GtkWidget *widget, GdkScreen *previous_screen, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: got screen-changed event\n"); GdkScreen *screen = gtk_widget_get_screen(GTK_WIDGET (widget)); GdkVisual *visual = gdk_screen_get_rgba_visual(screen); if (visual == NULL) visual = gdk_screen_get_system_visual (screen); gtk_widget_set_visual (widget, visual); } void on_monitors_changed ( GdkScreen *screen, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: screen size changed!\n"); // get new sizes data->width = gdk_screen_get_width (data->screen); data->height = gdk_screen_get_height (data->screen); // change size gtk_widget_set_size_request(GTK_WIDGET(data->win), data->width, data->height); // try to set transparent for input cairo_region_t* r = cairo_region_create(); gtk_widget_input_shape_combine_region(data->win, r); cairo_region_destroy(r); /* recreate the shape surface */ cairo_surface_t *new_shape = cairo_image_surface_create(CAIRO_FORMAT_ARGB32 ,data->width, data->height); cairo_t *cr = cairo_create (new_shape); cairo_set_source_surface (cr, data->backbuffer, 0, 0); cairo_paint (cr); cairo_destroy (cr); cairo_surface_destroy(data->backbuffer); data->backbuffer = new_shape; /* these depend on the shape surface */ GHashTableIter it; gpointer value; g_hash_table_iter_init (&it, data->tool_config); while (g_hash_table_iter_next (&it, NULL, &value)) paint_context_free(value); g_hash_table_remove_all(data->tool_config); parse_config(data); // also calls paint_context_new() :-( data->default_pen = paint_context_new (data, GROMIT_PEN, data->red, 7, 0); data->default_eraser = paint_context_new (data, GROMIT_ERASER, data->red, 75, 0); if(!data->composited) // set shape { cairo_region_t* r = gdk_cairo_region_create_from_surface(data->backbuffer); gtk_widget_shape_combine_region(data->win, r); cairo_region_destroy(r); } setup_input_devices(data); gtk_widget_show_all (data->win); } void on_composited_changed ( GdkScreen *screen, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: got composited-changed event\n"); data->composited = gdk_screen_is_composited (data->screen); if(data->composited) { // undo shape gtk_widget_shape_combine_region(data->win, NULL); // re-apply transparency gtk_window_set_opacity(GTK_WINDOW(data->win), 0.75); } // set anti-aliasing GHashTableIter it; gpointer value; g_hash_table_iter_init (&it, data->tool_config); while (g_hash_table_iter_next (&it, NULL, &value)) { GromitPaintContext *context = value; cairo_set_antialias(context->paint_ctx, data->composited ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); } GdkRectangle rect = {0, 0, data->width, data->height}; gdk_window_invalidate_rect(gtk_widget_get_window(data->win), &rect, 0); } void on_clientapp_selection_get (GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data) { GromitData *data = (GromitData *) user_data; gchar *ans = ""; if(data->debug) g_printerr("DEBUG: clientapp received request.\n"); if (gtk_selection_data_get_target(selection_data) == GA_TOGGLEDATA) { ans = data->clientdata; } gtk_selection_data_set (selection_data, gtk_selection_data_get_target(selection_data), 8, (guchar*)ans, strlen (ans)); } void on_clientapp_selection_received (GtkWidget *widget, GtkSelectionData *selection_data, guint time, gpointer user_data) { GromitData *data = (GromitData *) user_data; /* If someone has a selection for us, Gromit is already running. */ if(gtk_selection_data_get_data_type(selection_data) == GDK_NONE) data->client = 0; else data->client = 1; gtk_main_quit (); } static float line_thickener = 0; gboolean on_buttonpress (GtkWidget *win, GdkEventButton *ev, gpointer user_data) { GromitData *data = (GromitData *) user_data; gdouble pressure = 0.5; /* get the data for this device */ GdkDevice *master = ev->device; GromitDeviceData *masterdata = g_hash_table_lookup(data->devdatatable, master); GdkDevice *slave = gdk_event_get_source_device ((GdkEvent *) ev); GromitDeviceData *slavedata = g_hash_table_lookup(data->devdatatable, slave); if(data->debug) g_printerr("DEBUG: Device '%s': Button %i Down at (x,y)=(%.2f : %.2f)\n", gdk_device_get_name(slave), ev->button, ev->x, ev->y); if (!masterdata->is_grabbed) return FALSE; /* See GdkModifierType. Am I fixing a Gtk misbehaviour??? */ ev->state |= 1 << (ev->button + 7); if (ev->state != masterdata->state || ev->state != slavedata->state || masterdata->lastslave != slave) select_tool (data, master, slave, ev->state); slavedata->lastx = ev->x; slavedata->lasty = ev->y; slavedata->motion_time = ev->time; if (gdk_device_get_source(slave) == GDK_SOURCE_MOUSE) { data->maxwidth = slavedata->cur_context->width; } else { gdk_event_get_axis ((GdkEvent *) ev, GDK_AXIS_PRESSURE, &pressure); data->maxwidth = (CLAMP (pressure * pressure + line_thickener,0,1) * (double) slavedata->cur_context->width); } if (ev->button <= 5) draw_line (data, slave, ev->x, ev->y, ev->x, ev->y); coord_list_prepend (data, slave, ev->x, ev->y, data->maxwidth); return TRUE; } gboolean on_motion (GtkWidget *win, GdkEventMotion *ev, gpointer user_data) { GromitData *data = (GromitData *) user_data; GdkTimeCoord **coords = NULL; gint nevents; int i; gdouble pressure = 0.5; /* get the data for this device */ GdkDevice *master = ev->device; GromitDeviceData *masterdata = g_hash_table_lookup(data->devdatatable, master); if (!masterdata->is_grabbed) return FALSE; GdkDevice *slave = gdk_event_get_source_device ((GdkEvent *) ev); GromitDeviceData *slavedata = g_hash_table_lookup(data->devdatatable, slave); if (ev->state != masterdata->state || ev->state != slavedata->state || masterdata->lastslave != slave) select_tool (data, master, slave, ev->state); if(!(ev->state & (GDK_BUTTON1_MASK| GDK_BUTTON2_MASK| GDK_BUTTON3_MASK| GDK_BUTTON4_MASK| GDK_BUTTON5_MASK))) return TRUE; gdk_device_get_history (slave, ev->window, slavedata->motion_time, ev->time, &coords, &nevents); if(!data->xinerama && nevents > 0) { for (i=0; i < nevents; i++) { gdouble x, y; gdk_device_get_axis (slave, coords[i]->axes, GDK_AXIS_PRESSURE, &pressure); if (pressure > 0) { if (gdk_device_get_source(slave) == GDK_SOURCE_MOUSE) data->maxwidth = slavedata->cur_context->width; else data->maxwidth = (CLAMP (pressure * pressure + line_thickener, 0, 1) * (double) slavedata->cur_context->width); gdk_device_get_axis(slave, coords[i]->axes, GDK_AXIS_X, &x); gdk_device_get_axis(slave, coords[i]->axes, GDK_AXIS_Y, &y); draw_line (data, slave, slavedata->lastx, slavedata->lasty, x, y); coord_list_prepend (data, slave, x, y, data->maxwidth); slavedata->lastx = x; slavedata->lasty = y; } } slavedata->motion_time = coords[nevents-1]->time; g_free (coords); } /* always paint to the current event coordinate. */ gdk_event_get_axis ((GdkEvent *) ev, GDK_AXIS_PRESSURE, &pressure); if (pressure > 0) { if (gdk_device_get_source(slave) == GDK_SOURCE_MOUSE) data->maxwidth = slavedata->cur_context->width; else data->maxwidth = (CLAMP (pressure * pressure + line_thickener,0,1) * (double)slavedata->cur_context->width); if(slavedata->motion_time > 0) { draw_line (data, slave, slavedata->lastx, slavedata->lasty, ev->x, ev->y); coord_list_prepend (data, slave, ev->x, ev->y, data->maxwidth); } } slavedata->lastx = ev->x; slavedata->lasty = ev->y; slavedata->motion_time = ev->time; return TRUE; } gboolean on_buttonrelease (GtkWidget *win, GdkEventButton *ev, gpointer user_data) { GromitData *data = (GromitData *) user_data; /* get the data for this device */ GdkDevice *master = ev->device; GromitDeviceData *masterdata = g_hash_table_lookup(data->devdatatable, master); GdkDevice *slave = gdk_event_get_source_device ((GdkEvent *) ev); GromitDeviceData *slavedata = g_hash_table_lookup(data->devdatatable, slave); if(data->debug) g_printerr("DEBUG: Device '%s': Button %i Up at (x,y)=(%.2f : %.2f)\n", gdk_device_get_name(slave), ev->button, ev->x, ev->y); gfloat direction = 0; gint width = 0; if(slavedata->cur_context) width = slavedata->cur_context->arrowsize * slavedata->cur_context->width / 2; if ((ev->x != slavedata->lastx) || (ev->y != slavedata->lasty)) on_motion(win, (GdkEventMotion *) ev, user_data); if (!masterdata->is_grabbed) return FALSE; if (slavedata->cur_context->arrowsize != 0 && coord_list_get_arrow_param (data, slave, width * 3, &width, &direction)) draw_arrow (data, slave, ev->x, ev->y, width, direction); coord_list_free (data, slave); return TRUE; } /* Remote control */ void on_mainapp_selection_get (GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data) { GromitData *data = (GromitData *) user_data; gchar *uri = "OK"; if(gtk_selection_data_get_target(selection_data) == GA_TOGGLE) { /* ask back client for device id */ gtk_selection_convert (data->win, GA_DATA, GA_TOGGLEDATA, time); gtk_main(); /* Wait for the response */ } else if (gtk_selection_data_get_target(selection_data) == GA_VISIBILITY) toggle_visibility (data); else if (gtk_selection_data_get_target(selection_data) == GA_CLEAR) clear_screen (data); else if (gtk_selection_data_get_target(selection_data) == GA_RELOAD) setup_input_devices(data); else if (gtk_selection_data_get_target(selection_data) == GA_QUIT) gtk_main_quit (); else uri = "NOK"; gtk_selection_data_set (selection_data, gtk_selection_data_get_target(selection_data), 8, (guchar*)uri, strlen (uri)); } void on_mainapp_selection_received (GtkWidget *widget, GtkSelectionData *selection_data, guint time, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(gtk_selection_data_get_length(selection_data) < 0) { if(data->debug) g_printerr("DEBUG: mainapp got no answer back from client.\n"); } else { if(gtk_selection_data_get_target(selection_data) == GA_TOGGLEDATA ) { intptr_t dev_nr = strtoull((gchar*)gtk_selection_data_get_data(selection_data), NULL, 10); if(data->debug) g_printerr("DEBUG: mainapp got toggle id '%ld' back from client.\n", (long)dev_nr); if(dev_nr < 0) toggle_grab(data, NULL); /* toggle all */ else { /* find dev numbered dev_nr */ GHashTableIter it; gpointer value; GromitDeviceData* devdata = NULL; g_hash_table_iter_init (&it, data->devdatatable); while (g_hash_table_iter_next (&it, NULL, &value)) { devdata = value; if(devdata->index == dev_nr) break; else devdata = NULL; } if(devdata) toggle_grab(data, devdata->device); else g_printerr("ERROR: No device at index %ld.\n", (long)dev_nr); } } } gtk_main_quit (); } void on_device_removed (GdkDeviceManager *device_manager, GdkDevice *device, gpointer user_data) { GromitData *data = (GromitData *) user_data; GdkInputSource hardware_type = gdk_device_get_source(device); if( hardware_type == GDK_SOURCE_KEYBOARD || gdk_device_get_n_axes(device) < 2) return; if(data->debug) g_printerr("DEBUG: device '%s' removed\n", gdk_device_get_name(device)); setup_input_devices(data); } void on_device_added (GdkDeviceManager *device_manager, GdkDevice *device, gpointer user_data) { GromitData *data = (GromitData *) user_data; GdkInputSource hardware_type = gdk_device_get_source(device); if( hardware_type == GDK_SOURCE_KEYBOARD || gdk_device_get_n_axes(device) < 2) return; if(data->debug) g_printerr("DEBUG: device '%s' added\n", gdk_device_get_name(device)); setup_input_devices(data); } static void on_clear (GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; clear_screen(data); } static void on_toggle_vis(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; toggle_visibility(data); } static void on_thicker_lines(GtkMenuItem *menuitem, gpointer user_data) { line_thickener += 0.1; } static void on_thinner_lines(GtkMenuItem *menuitem, gpointer user_data) { line_thickener -= 0.1; if (line_thickener < -1) line_thickener = -1; } void on_trayicon_activate (GtkStatusIcon *status_icon, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: trayicon activated\n"); /* create the menu */ GtkWidget *menu = gtk_menu_new (); /* Create the menu items */ GtkWidget* toggle_paint_item = gtk_image_menu_item_new_with_label ("Toggle Painting"); GtkWidget* clear_item = gtk_image_menu_item_new_with_label ("Clear Screen"); GtkWidget* toggle_vis_item = gtk_image_menu_item_new_with_label ("Toggle Visibility"); GtkWidget* thicker_lines_item = gtk_image_menu_item_new_with_label ("Thicker Lines"); GtkWidget* thinner_lines_item = gtk_image_menu_item_new_with_label ("Thinner Lines"); /* Add them to the menu */ gtk_menu_shell_append (GTK_MENU_SHELL (menu), toggle_paint_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), clear_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), toggle_vis_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), thicker_lines_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), thinner_lines_item); /* Attach the callback functions to the respective activate signal */ // TODO add per-device submenu for toggle_paint_item g_signal_connect(G_OBJECT (clear_item), "activate", G_CALLBACK (on_clear), data); g_signal_connect(G_OBJECT (toggle_vis_item), "activate", G_CALLBACK (on_toggle_vis), data); g_signal_connect(G_OBJECT (thicker_lines_item), "activate", G_CALLBACK (on_thicker_lines), data); g_signal_connect(G_OBJECT (thinner_lines_item), "activate", G_CALLBACK (on_thinner_lines), data); /* We do need to show menu items */ gtk_widget_show (toggle_paint_item); gtk_widget_show (clear_item); gtk_widget_show (toggle_vis_item); gtk_widget_show (thicker_lines_item); gtk_widget_show (thinner_lines_item); /* show menu */ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); } void on_trayicon_menu (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data) { GromitData *data = (GromitData *) user_data; if(data->debug) g_printerr("DEBUG: trayicon menu popup\n"); /* create the menu */ GtkWidget *menu = gtk_menu_new (); /* Create the menu items */ //TODO option menu GtkWidget* sep_item = gtk_separator_menu_item_new(); GtkWidget* quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); /* Add them to the menu */ gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit_item); /* Attach the callback functions to the respective activate signal */ g_signal_connect(G_OBJECT (quit_item), "activate", G_CALLBACK (gtk_main_quit), NULL); /* We do need to show menu items */ gtk_widget_show (sep_item); gtk_widget_show (quit_item); /* show menu */ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); } gromit-mpx-1.1/src/callbacks.h000066400000000000000000000061101220446531300163330ustar00rootroot00000000000000/* * Gromit-MPX -- a program for painting on the screen * * Gromit Copyright (C) 2000 Simon Budig * * Gromit-MPX Copyright (C) 2009,2010 Christian Beier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef CALLBACKS_H #define CALLBACKS_H #include #include #include gboolean on_expose (GtkWidget *widget, cairo_t* cr, gpointer user_data); gboolean on_configure (GtkWidget *widget, GdkEventExpose *event, gpointer user_data); void on_screen_changed(GtkWidget *widget, GdkScreen *previous_screen, gpointer user_data); void on_monitors_changed(GdkScreen *screen, gpointer user_data); void on_composited_changed(GdkScreen *screen, gpointer user_data); void on_clientapp_selection_get (GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data); void on_clientapp_selection_received (GtkWidget *widget, GtkSelectionData *selection_data, guint time, gpointer user_data); gboolean on_buttonpress (GtkWidget *win, GdkEventButton *ev, gpointer user_data); gboolean on_motion (GtkWidget *win, GdkEventMotion *ev, gpointer user_data); gboolean on_buttonrelease (GtkWidget *win, GdkEventButton *ev, gpointer user_data); gboolean on_proximity_in (GtkWidget *win, GdkEventProximity *ev, gpointer user_data); gboolean on_proximity_out (GtkWidget *win, GdkEventProximity *ev, gpointer user_data); void on_mainapp_selection_get (GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data); void on_mainapp_selection_received (GtkWidget *widget, GtkSelectionData *selection_data, guint time, gpointer user_data); void on_device_removed (GdkDeviceManager *device_manager, GdkDevice *device, gpointer user_data); void on_device_added (GdkDeviceManager *device_manager, GdkDevice *device, gpointer user_data); void on_trayicon_activate (GtkStatusIcon *status_icon, gpointer user_data); void on_trayicon_menu (GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data); #endif gromit-mpx-1.1/src/config.c000066400000000000000000000263631220446531300156700ustar00rootroot00000000000000/* * Gromit-MPX -- a program for painting on the screen * * Gromit Copyright (C) 2000 Simon Budig * * Gromit-MPX Copyright (C) 2009,2010 Christian Beier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include "gromit-mpx.h" /* * Functions for parsing the Configuration-file */ static gchar* parse_name (GScanner *scanner) { GTokenType token; guint buttons = 0; guint modifier = 0; guint len = 0; gchar *name; token = g_scanner_cur_token(scanner); if (token != G_TOKEN_STRING) { g_scanner_unexp_token (scanner, G_TOKEN_STRING, NULL, NULL, NULL, "aborting", TRUE); exit (1); } len = strlen (scanner->value.v_string); name = g_strndup (scanner->value.v_string, len + 3); token = g_scanner_get_next_token (scanner); /* * Are there any options to limit the scope of the definition? */ if (token == G_TOKEN_LEFT_BRACE) { g_scanner_set_scope (scanner, 1); scanner->config->int_2_float = 0; modifier = buttons = 0; while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_RIGHT_BRACE) { if (token == G_TOKEN_SYMBOL) { if ((intptr_t) scanner->value.v_symbol < 11) buttons |= 1 << ((intptr_t) scanner->value.v_symbol - 1); else modifier |= 1 << ((intptr_t) scanner->value.v_symbol - 11); } else if (token == G_TOKEN_INT) { if (scanner->value.v_int <= 5 && scanner->value.v_int > 0) buttons |= 1 << (scanner->value.v_int - 1); else g_printerr ("Only Buttons 1-5 are supported!\n"); } else { g_printerr ("skipped token\n"); } } g_scanner_set_scope (scanner, 0); scanner->config->int_2_float = 1; token = g_scanner_get_next_token (scanner); } name [len] = 124; name [len+1] = buttons + 64; name [len+2] = modifier + 48; name [len+3] = 0; return name; } void parse_config (GromitData *data) { GromitPaintContext *context=NULL; GromitPaintContext *context_template=NULL; GScanner *scanner; GTokenType token; gchar *filename; int file; gchar *name, *copy; GromitPaintType type; GdkColor *fg_color=NULL; guint width, arrowsize; filename = g_strjoin (G_DIR_SEPARATOR_S, g_get_user_config_dir(), "gromit-mpx.cfg", NULL); file = open (filename, O_RDONLY); if (file < 0) { /* try global config file */ g_free (filename); filename = g_strdup ("/etc/gromit-mpx/gromit-mpx.cfg"); file = open (filename, O_RDONLY); if (file < 0) { g_printerr ("Could not open %s: %s\n", filename, g_strerror (errno)); g_free (filename); return; } } scanner = g_scanner_new (NULL); scanner->input_name = filename; scanner->config->case_sensitive = 0; scanner->config->scan_octal = 0; scanner->config->identifier_2_string = 0; scanner->config->char_2_token = 1; scanner->config->numbers_2_int = 1; scanner->config->int_2_float = 1; g_scanner_scope_add_symbol (scanner, 0, "PEN", (gpointer) GROMIT_PEN); g_scanner_scope_add_symbol (scanner, 0, "ERASER", (gpointer) GROMIT_ERASER); g_scanner_scope_add_symbol (scanner, 0, "RECOLOR",(gpointer) GROMIT_RECOLOR); g_scanner_scope_add_symbol (scanner, 1, "BUTTON1", (gpointer) 1); g_scanner_scope_add_symbol (scanner, 1, "BUTTON2", (gpointer) 2); g_scanner_scope_add_symbol (scanner, 1, "BUTTON3", (gpointer) 3); g_scanner_scope_add_symbol (scanner, 1, "BUTTON4", (gpointer) 4); g_scanner_scope_add_symbol (scanner, 1, "BUTTON5", (gpointer) 5); g_scanner_scope_add_symbol (scanner, 1, "SHIFT", (gpointer) 11); g_scanner_scope_add_symbol (scanner, 1, "CONTROL", (gpointer) 12); g_scanner_scope_add_symbol (scanner, 1, "META", (gpointer) 13); g_scanner_scope_add_symbol (scanner, 1, "ALT", (gpointer) 13); g_scanner_scope_add_symbol (scanner, 2, "size", (gpointer) 1); g_scanner_scope_add_symbol (scanner, 2, "color", (gpointer) 2); g_scanner_scope_add_symbol (scanner, 2, "arrowsize", (gpointer) 3); g_scanner_set_scope (scanner, 0); scanner->config->scope_0_fallback = 0; g_scanner_input_file (scanner, file); token = g_scanner_get_next_token (scanner); while (token != G_TOKEN_EOF) { /* * New tool definition */ if (token == G_TOKEN_STRING) { name = parse_name (scanner); token = g_scanner_cur_token(scanner); if (token != G_TOKEN_EQUAL_SIGN) { g_scanner_unexp_token (scanner, G_TOKEN_EQUAL_SIGN, NULL, NULL, NULL, "aborting", TRUE); exit (1); } token = g_scanner_get_next_token (scanner); /* defaults */ type = GROMIT_PEN; width = 7; arrowsize = 0; fg_color = data->red; if (token == G_TOKEN_SYMBOL) { type = (GromitPaintType) scanner->value.v_symbol; token = g_scanner_get_next_token (scanner); } else if (token == G_TOKEN_STRING) { copy = parse_name (scanner); token = g_scanner_cur_token(scanner); context_template = g_hash_table_lookup (data->tool_config, copy); if (context_template) { type = context_template->type; width = context_template->width; arrowsize = context_template->arrowsize; fg_color = context_template->paint_color; } else { g_printerr ("WARNING: Unable to copy \"%s\": " "not yet defined!\n", copy); } } else { g_printerr ("Expected Tool-definition " "or name of template tool\n"); exit (1); } /* Are there any tool-options? */ if (token == G_TOKEN_LEFT_PAREN) { GdkColor *color = NULL; g_scanner_set_scope (scanner, 2); scanner->config->int_2_float = 1; token = g_scanner_get_next_token (scanner); while (token != G_TOKEN_RIGHT_PAREN) { if (token == G_TOKEN_SYMBOL) { if ((intptr_t) scanner->value.v_symbol == 1) { token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) { g_printerr ("Missing \"=\"... aborting\n"); exit (1); } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_FLOAT) { g_printerr ("Missing Size (float)... aborting\n"); exit (1); } width = (guint) (scanner->value.v_float + 0.5); } else if ((intptr_t) scanner->value.v_symbol == 2) { token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) { g_printerr ("Missing \"=\"... aborting\n"); exit (1); } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_STRING) { g_printerr ("Missing Color (string)... " "aborting\n"); exit (1); } color = g_malloc (sizeof (GdkColor)); if (gdk_color_parse (scanner->value.v_string, color)) { fg_color = color; } else { g_printerr ("Unable to parse color. " "Keeping default.\n"); g_free (color); } color = NULL; } else if ((intptr_t) scanner->value.v_symbol == 3) { token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_EQUAL_SIGN) { g_printerr ("Missing \"=\"... aborting\n"); exit (1); } token = g_scanner_get_next_token (scanner); if (token != G_TOKEN_FLOAT) { g_printerr ("Missing Arrowsize (float)... " "aborting\n"); exit (1); } arrowsize = scanner->value.v_float; } else { g_printerr ("Unknown tool type?????\n"); } } else { g_printerr ("skipped token!!!\n"); } token = g_scanner_get_next_token (scanner); } g_scanner_set_scope (scanner, 0); token = g_scanner_get_next_token (scanner); } /* * Finally we expect a semicolon */ if (token != ';') { g_printerr ("Expected \";\"\n"); exit (1); } context = paint_context_new (data, type, fg_color, width, arrowsize); g_hash_table_insert (data->tool_config, name, context); } else { g_printerr ("Expected name of Tool to define\n"); exit(1); } token = g_scanner_get_next_token (scanner); } g_scanner_destroy (scanner); close (file); g_free (filename); } gromit-mpx-1.1/src/config.h000066400000000000000000000023511220446531300156640ustar00rootroot00000000000000/* * Gromit-MPX -- a program for painting on the screen * * Gromit Copyright (C) 2000 Simon Budig * * Gromit-MPX Copyright (C) 2009,2010 Christian Beier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef CONFIG_H #define CONFIG_H #include "gromit-mpx.h" /* fallback device name for config file */ #define DEFAULT_DEVICE_NAME "default" void parse_config (GromitData *data); /* fallback hot key, if not specified on command line or in config file */ #ifndef DEFAULT_HOTKEY #define DEFAULT_HOTKEY "F9" #endif #endif gromit-mpx-1.1/src/erase_cursor.xpm000066400000000000000000000023371220446531300174740ustar00rootroot00000000000000/* XPM */ #define erase_cursor_x_hot 14 #define erase_cursor_y_hot 14 const char * erase_cursor_xpm[] = { "31 31 3 1", " c None", ". c #000000", "+ c #FFFFFF", " ......... ", " ....+++++++.... ", " ...+++ +++... ", " ..++ ++.. ", " ..+ +.. ", " ..+ +.. ", " .+ +. ", " ..+ +.. ", " .+ +. ", " .+ +. ", "..+ +.. ", ".+ +. ", ".+ +. ", ".+ +. ", ".+ +. ", ".+ +. ", ".+ +. ", ".+ +. ", "..+ +.. ", " .+ +. ", " .+ +. ", " ..+ +.. ", " .+ +. ", " ..+ +.. ", " ..+ +.. ", " ..++ ++.. ", " ...+++ +++... ", " ....+++++++.... ", " ......... ", " ", " "}; gromit-mpx-1.1/src/gromit-mpx.c000066400000000000000000000716541220446531300165310ustar00rootroot00000000000000/* * Gromit-MPX -- a program for painting on the screen * * Gromit Copyright (C) 2000 Simon Budig * * Gromit-MPX Copyright (C) 2009,2010 Christian Beier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include "callbacks.h" #include "config.h" #include "input.h" #include "gromit-mpx.h" #include "paint_cursor.xpm" #include "erase_cursor.xpm" GromitPaintContext *paint_context_new (GromitData *data, GromitPaintType type, GdkColor *paint_color, guint width, guint arrowsize) { GromitPaintContext *context; context = g_malloc (sizeof (GromitPaintContext)); context->type = type; context->width = width; context->arrowsize = arrowsize; context->paint_color = paint_color; context->paint_ctx = cairo_create (data->backbuffer); gdk_cairo_set_source_color(context->paint_ctx, paint_color); if(!data->composited) cairo_set_antialias(context->paint_ctx, CAIRO_ANTIALIAS_NONE); cairo_set_line_width(context->paint_ctx, width); cairo_set_line_cap(context->paint_ctx, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(context->paint_ctx, CAIRO_LINE_JOIN_ROUND); if (type == GROMIT_ERASER) cairo_set_operator(context->paint_ctx, CAIRO_OPERATOR_CLEAR); else if (type == GROMIT_RECOLOR) cairo_set_operator(context->paint_ctx, CAIRO_OPERATOR_ATOP); else /* GROMIT_PEN */ cairo_set_operator(context->paint_ctx, CAIRO_OPERATOR_OVER); return context; } void paint_context_print (gchar *name, GromitPaintContext *context) { g_printerr ("Tool name: \"%-20s\": ", name); switch (context->type) { case GROMIT_PEN: g_printerr ("Pen, "); break; case GROMIT_ERASER: g_printerr ("Eraser, "); break; case GROMIT_RECOLOR: g_printerr ("Recolor, "); break; default: g_printerr ("UNKNOWN, "); break; } g_printerr ("width: %3d, ", context->width); g_printerr ("arrowsize: %.2f, ", context->arrowsize); g_printerr ("color: #%02X%02X%02X\n", context->paint_color->red >> 8, context->paint_color->green >> 8, context->paint_color->blue >> 8); } void paint_context_free (GromitPaintContext *context) { cairo_destroy(context->paint_ctx); g_free (context); } void coord_list_prepend (GromitData *data, GdkDevice* dev, gint x, gint y, gint width) { /* get the data for this device */ GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); GromitStrokeCoordinate *point; point = g_malloc (sizeof (GromitStrokeCoordinate)); point->x = x; point->y = y; point->width = width; devdata->coordlist = g_list_prepend (devdata->coordlist, point); } void coord_list_free (GromitData *data, GdkDevice* dev) { /* get the data for this device */ GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); GList *ptr; ptr = devdata->coordlist; while (ptr) { g_free (ptr->data); ptr = ptr->next; } g_list_free (devdata->coordlist); devdata->coordlist = NULL; } gboolean coord_list_get_arrow_param (GromitData *data, GdkDevice *dev, gint search_radius, gint *ret_width, gfloat *ret_direction) { gint x0, y0, r2, dist; gboolean success = FALSE; GromitStrokeCoordinate *cur_point, *valid_point; /* get the data for this device */ GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); GList *ptr = devdata->coordlist; gfloat width; valid_point = NULL; if (ptr) { cur_point = ptr->data; x0 = cur_point->x; y0 = cur_point->y; r2 = search_radius * search_radius; dist = 0; while (ptr && dist < r2) { ptr = ptr->next; if (ptr) { cur_point = ptr->data; dist = (cur_point->x - x0) * (cur_point->x - x0) + (cur_point->y - y0) * (cur_point->y - y0); width = cur_point->width * devdata->cur_context->arrowsize; if (width * 2 <= dist && (!valid_point || valid_point->width < cur_point->width)) valid_point = cur_point; } } if (valid_point) { *ret_width = MAX (valid_point->width * devdata->cur_context->arrowsize, 2); *ret_direction = atan2 (y0 - valid_point->y, x0 - valid_point->x); success = TRUE; } } return success; } void hide_window (GromitData *data) { if (!data->hidden) { /* save grab state of each device */ GHashTableIter it; gpointer value; GromitDeviceData* devdata; g_hash_table_iter_init (&it, data->devdatatable); while (g_hash_table_iter_next (&it, NULL, &value)) { devdata = value; devdata->was_grabbed = devdata->is_grabbed; } data->hidden = 1; release_grab (data, NULL); /* release all */ gtk_widget_hide (data->win); if(data->debug) g_printerr ("DEBUG: Hiding window.\n"); } } void show_window (GromitData *data) { if (data->hidden) { gtk_widget_show (data->win); data->hidden = 0; /* restore grab state of each device */ GHashTableIter it; gpointer value; GromitDeviceData* devdata; g_hash_table_iter_init (&it, data->devdatatable); while (g_hash_table_iter_next (&it, NULL, &value)) { devdata = value; if(devdata->was_grabbed) acquire_grab (data, devdata->device); } if(data->debug) g_printerr ("DEBUG: Showing window.\n"); } gdk_window_raise (gtk_widget_get_window(data->win)); } void toggle_visibility (GromitData *data) { if (data->hidden) show_window (data); else hide_window (data); } void clear_screen (GromitData *data) { cairo_t *cr = cairo_create(data->backbuffer); cairo_set_source_rgba(cr, 0, 0, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_destroy(cr); GdkRectangle rect = {0, 0, data->width, data->height}; gdk_window_invalidate_rect(gtk_widget_get_window(data->win), &rect, 0); if(!data->composited) { cairo_region_t* r = gdk_cairo_region_create_from_surface(data->backbuffer); gtk_widget_shape_combine_region(data->win, r); cairo_region_destroy(r); // try to set transparent for input r = cairo_region_create(); gtk_widget_input_shape_combine_region(data->win, r); cairo_region_destroy(r); } data->painted = 0; if(data->debug) g_printerr ("DEBUG: Cleared screen.\n"); } gint reshape (gpointer user_data) { GromitData *data = (GromitData *) user_data; if (data->modified && !data->composited) { if (gtk_events_pending () && data->delayed < 5) { data->delayed++ ; } else { cairo_region_t* r = gdk_cairo_region_create_from_surface(data->backbuffer); gtk_widget_shape_combine_region(data->win, r); cairo_region_destroy(r); // try to set transparent for input r = cairo_region_create(); gtk_widget_input_shape_combine_region(data->win, r); cairo_region_destroy(r); data->modified = 0; data->delayed = 0; } } return 1; } void select_tool (GromitData *data, GdkDevice *master, GdkDevice *slave, guint state) { guint buttons = 0, modifier = 0, len = 0, default_len = 0; guint req_buttons = 0, req_modifier = 0; guint i, j, success = 0; GromitPaintContext *context = NULL; guchar *name; guchar *default_name; /* get the data for this device */ GromitDeviceData *masterdata = g_hash_table_lookup(data->devdatatable, master); GromitDeviceData *slavedata = g_hash_table_lookup(data->devdatatable, slave); if (slave) { len = strlen (gdk_device_get_name(slave)); name = (guchar*) g_strndup (gdk_device_get_name(slave), len + 3); default_len = strlen(DEFAULT_DEVICE_NAME); default_name = (guchar*) g_strndup (DEFAULT_DEVICE_NAME, default_len + 3); /* Extract Button/Modifiers from state (see GdkModifierType) */ req_buttons = (state >> 8) & 31; req_modifier = (state >> 1) & 7; if (state & GDK_SHIFT_MASK) req_modifier |= 1; name [len] = 124; name [len+3] = 0; default_name [default_len] = 124; default_name [default_len+3] = 0; /* 0, 1, 3, 7, 15, 31 */ context = NULL; i=-1; do { i++; buttons = req_buttons & ((1 << i)-1); j=-1; do { j++; modifier = req_modifier & ((1 << j)-1); name [len+1] = buttons + 64; name [len+2] = modifier + 48; default_name [default_len+1] = buttons + 64; default_name [default_len+2] = modifier + 48; if(data->debug) g_printerr("DEBUG: Looking up context %s\n", name); context = g_hash_table_lookup (data->tool_config, name); if(context) { if(data->debug) g_printerr("DEBUG: Context %s set\n", name); slavedata->cur_context = context; success = 1; } else /* try default_name */ if((context = g_hash_table_lookup (data->tool_config, default_name))) { if(data->debug) g_printerr("DEBUG: Default context %s set\n", default_name); slavedata->cur_context = context; success = 1; } } while (j<=3 && req_modifier >= (1u << j)); } while (i<=5 && req_buttons >= (1u << i)); g_free (name); g_free (default_name); if (!success) { if (gdk_device_get_source(slave) == GDK_SOURCE_ERASER) slavedata->cur_context = data->default_eraser; else slavedata->cur_context = data->default_pen; } } else g_printerr ("ERROR: Attempt to select nonexistent device!\n"); GdkCursor *cursor; if(slavedata->cur_context && slavedata->cur_context->type == GROMIT_ERASER) cursor = data->erase_cursor; else cursor = data->paint_cursor; if(data->debug) g_printerr("DEBUG: Setting cursor %p\n",cursor); //FIXME! Should be: //gdk_window_set_cursor(gtk_widget_get_window(data->win), cursor); // doesn't work during a grab? gdk_device_grab(master, gtk_widget_get_window(data->win), GDK_OWNERSHIP_NONE, FALSE, GROMIT_MOUSE_EVENTS, cursor, GDK_CURRENT_TIME); masterdata->lastslave = slave; masterdata->state = state; slavedata->state = state; } void draw_line (GromitData *data, GdkDevice *dev, gint x1, gint y1, gint x2, gint y2) { GdkRectangle rect; GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); rect.x = MIN (x1,x2) - data->maxwidth / 2; rect.y = MIN (y1,y2) - data->maxwidth / 2; rect.width = ABS (x1-x2) + data->maxwidth; rect.height = ABS (y1-y2) + data->maxwidth; if(data->debug) g_printerr("DEBUG: draw line from %d %d to %d %d\n", x1, y1, x2, y2); if (devdata->cur_context->paint_ctx) { cairo_set_line_width(devdata->cur_context->paint_ctx, data->maxwidth); cairo_set_line_cap(devdata->cur_context->paint_ctx, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(devdata->cur_context->paint_ctx, CAIRO_LINE_JOIN_ROUND); cairo_move_to(devdata->cur_context->paint_ctx, x1, y1); cairo_line_to(devdata->cur_context->paint_ctx, x2, y2); cairo_stroke(devdata->cur_context->paint_ctx); data->modified = 1; gdk_window_invalidate_rect(gtk_widget_get_window(data->win), &rect, 0); } data->painted = 1; } void draw_arrow (GromitData *data, GdkDevice *dev, gint x1, gint y1, gint width, gfloat direction) { GdkRectangle rect; GdkPoint arrowhead [4]; /* get the data for this device */ GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); width = width / 2; /* I doubt that calculating the boundary box more exact is very useful */ rect.x = x1 - 4 * width - 1; rect.y = y1 - 4 * width - 1; rect.width = 8 * width + 2; rect.height = 8 * width + 2; arrowhead [0].x = x1 + 4 * width * cos (direction); arrowhead [0].y = y1 + 4 * width * sin (direction); arrowhead [1].x = x1 - 3 * width * cos (direction) + 3 * width * sin (direction); arrowhead [1].y = y1 - 3 * width * cos (direction) - 3 * width * sin (direction); arrowhead [2].x = x1 - 2 * width * cos (direction); arrowhead [2].y = y1 - 2 * width * sin (direction); arrowhead [3].x = x1 - 3 * width * cos (direction) - 3 * width * sin (direction); arrowhead [3].y = y1 + 3 * width * cos (direction) - 3 * width * sin (direction); if (devdata->cur_context->paint_ctx) { cairo_set_line_width(devdata->cur_context->paint_ctx, 1); cairo_set_line_cap(devdata->cur_context->paint_ctx, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(devdata->cur_context->paint_ctx, CAIRO_LINE_JOIN_ROUND); cairo_move_to(devdata->cur_context->paint_ctx, arrowhead[0].x, arrowhead[0].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[1].x, arrowhead[1].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[2].x, arrowhead[2].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[3].x, arrowhead[3].y); cairo_fill(devdata->cur_context->paint_ctx); gdk_cairo_set_source_color(devdata->cur_context->paint_ctx, data->black); cairo_move_to(devdata->cur_context->paint_ctx, arrowhead[0].x, arrowhead[0].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[1].x, arrowhead[1].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[2].x, arrowhead[2].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[3].x, arrowhead[3].y); cairo_line_to(devdata->cur_context->paint_ctx, arrowhead[0].x, arrowhead[0].y); cairo_stroke(devdata->cur_context->paint_ctx); gdk_cairo_set_source_color(devdata->cur_context->paint_ctx, devdata->cur_context->paint_color); data->modified = 1; gdk_window_invalidate_rect(gtk_widget_get_window(data->win), &rect, 0); } data->painted = 1; } /* * Functions for handling various (GTK+)-Events */ /* Keyboard control */ gint key_press_event (GtkWidget *grab_widget, GdkEventKey *event, gpointer func_data) { GromitData *data = (GromitData *) func_data; GdkDevice *dev = gdk_event_get_device((GdkEvent*)event); if (event->type == GDK_KEY_PRESS && event->hardware_keycode == data->hot_keycode) { if(data->debug) g_printerr("DEBUG: Received hotkey press from device '%s'\n", gdk_device_get_name(dev)); if (event->state & GDK_SHIFT_MASK) clear_screen (data); else if (event->state & GDK_CONTROL_MASK) toggle_visibility (data); else if (event->state & GDK_MOD1_MASK) gtk_main_quit (); else { /* GAAAH */ gint kbd_dev_id = -1; g_object_get(dev, "device-id", &kbd_dev_id, NULL); XIDeviceInfo* devinfo; int devicecount = 0; gint ptr_dev_id = -1; devinfo = XIQueryDevice(GDK_DISPLAY_XDISPLAY(data->display), kbd_dev_id, &devicecount); if(devicecount) ptr_dev_id = devinfo->attachment; XIFreeDeviceInfo(devinfo); GdkDeviceManager *device_manager = gdk_display_get_device_manager(data->display); GList *devices, *d; gint some_dev_id; GdkDevice *some_device = NULL; devices = gdk_device_manager_list_devices(device_manager, GDK_DEVICE_TYPE_MASTER); for(d = devices; d; d = d->next) { some_device = (GdkDevice *) d->data; g_object_get(some_device, "device-id", &some_dev_id, NULL); if(some_dev_id == ptr_dev_id) break; } toggle_grab(data, some_device); } return TRUE; } return FALSE; } void main_do_event (GdkEventAny *event, GromitData *data) { if ((event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) && event->window == data->root && ((GdkEventKey *) event)->hardware_keycode == data->hot_keycode) { /* redirect the event to our main window, so that GTK+ doesn't * throw it away (there is no GtkWidget for the root window...) */ event->window = gtk_widget_get_window(data->win); g_object_ref (gtk_widget_get_window(data->win)); } gtk_main_do_event ((GdkEvent *) event); } void setup_main_app (GromitData *data, gboolean activate) { /* COLOURS */ g_free(data->white); g_free(data->black); g_free(data->red); data->white = g_malloc (sizeof (GdkColor)); data->black = g_malloc (sizeof (GdkColor)); data->red = g_malloc (sizeof (GdkColor)); gdk_color_parse ("#FFFFFF", data->white); gdk_color_parse ("#000000", data->black); gdk_color_parse ("#FF0000", data->red); /* CURSORS */ GdkPixbuf* paint_cursor_pixbuf = gdk_pixbuf_new_from_xpm_data(paint_cursor_xpm); data->paint_cursor = gdk_cursor_new_from_pixbuf(data->display, paint_cursor_pixbuf, paint_cursor_x_hot, paint_cursor_y_hot); g_object_unref (paint_cursor_pixbuf); GdkPixbuf* erase_cursor_pixbuf = gdk_pixbuf_new_from_xpm_data(erase_cursor_xpm); data->erase_cursor = gdk_cursor_new_from_pixbuf(data->display, erase_cursor_pixbuf, erase_cursor_x_hot, erase_cursor_y_hot); g_object_unref (erase_cursor_pixbuf); /* DRAWING AREA */ /* SHAPE SURFACE*/ cairo_surface_destroy(data->backbuffer); data->backbuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32 ,data->width, data->height); /* EVENTS */ gtk_widget_add_events (data->win, GROMIT_WINDOW_EVENTS); g_signal_connect (data->win, "draw", G_CALLBACK (on_expose), data); g_signal_connect (data->win,"configure_event", G_CALLBACK (on_configure), data); g_signal_connect (data->win,"screen-changed", G_CALLBACK (on_screen_changed), data); g_signal_connect (data->screen,"monitors_changed", G_CALLBACK (on_monitors_changed), data); g_signal_connect (data->screen,"composited-changed", G_CALLBACK (on_composited_changed), data); g_signal_connect (gdk_display_get_device_manager (data->display), "device-added", G_CALLBACK (on_device_added), data); g_signal_connect (gdk_display_get_device_manager (data->display), "device-removed", G_CALLBACK (on_device_removed), data); g_signal_connect (data->win, "motion_notify_event", G_CALLBACK (on_motion), data); g_signal_connect (data->win, "button_press_event", G_CALLBACK (on_buttonpress), data); g_signal_connect (data->win, "button_release_event", G_CALLBACK (on_buttonrelease), data); /* disconnect previously defined selection handlers */ g_signal_handlers_disconnect_by_func (data->win, G_CALLBACK (on_clientapp_selection_get), data); g_signal_handlers_disconnect_by_func (data->win, G_CALLBACK (on_clientapp_selection_received), data); /* and re-connect them to mainapp functions */ g_signal_connect (data->win, "selection_get", G_CALLBACK (on_mainapp_selection_get), data); g_signal_connect (data->win, "selection_received", G_CALLBACK (on_mainapp_selection_received), data); if(!data->composited) // set initial shape { cairo_region_t* r = gdk_cairo_region_create_from_surface(data->backbuffer); gtk_widget_shape_combine_region(data->win, r); cairo_region_destroy(r); } /* reset settings from client setup */ gtk_selection_remove_all (data->win); gtk_selection_owner_set (data->win, GA_CONTROL, GDK_CURRENT_TIME); gtk_selection_add_target (data->win, GA_CONTROL, GA_STATUS, 0); gtk_selection_add_target (data->win, GA_CONTROL, GA_QUIT, 1); gtk_selection_add_target (data->win, GA_CONTROL, GA_ACTIVATE, 2); gtk_selection_add_target (data->win, GA_CONTROL, GA_DEACTIVATE, 3); gtk_selection_add_target (data->win, GA_CONTROL, GA_TOGGLE, 4); gtk_selection_add_target (data->win, GA_CONTROL, GA_VISIBILITY, 5); gtk_selection_add_target (data->win, GA_CONTROL, GA_CLEAR, 6); gtk_selection_add_target (data->win, GA_CONTROL, GA_RELOAD, 7); /* * Parse Config file */ data->tool_config = g_hash_table_new (g_str_hash, g_str_equal); parse_config (data); if (data->debug) g_hash_table_foreach (data->tool_config, parse_print_help, NULL); /* FIND HOTKEY KEYCODE */ if (data->hot_keyval) { GdkKeymap *keymap; GdkKeymapKey *keys; gint n_keys; guint keyval; if (strlen (data->hot_keyval) > 0 && strcasecmp (data->hot_keyval, "none") != 0) { keymap = gdk_keymap_get_for_display (data->display); keyval = gdk_keyval_from_name (data->hot_keyval); if (!keyval || !gdk_keymap_get_entries_for_keyval (keymap, keyval, &keys, &n_keys)) { g_printerr ("cannot find the key \"%s\"\n", data->hot_keyval); exit (1); } data->hot_keycode = keys[0].keycode; g_free (keys); } } /* INPUT DEVICES */ data->devdatatable = g_hash_table_new(NULL, NULL); setup_input_devices (data); gtk_widget_show_all (data->win); data->painted = 0; hide_window (data); data->timeout_id = g_timeout_add (20, reshape, data); data->modified = 0; data->default_pen = paint_context_new (data, GROMIT_PEN, data->red, 7, 0); data->default_eraser = paint_context_new (data, GROMIT_ERASER, data->red, 75, 0); gdk_event_handler_set ((GdkEventFunc) main_do_event, data, NULL); gtk_key_snooper_install (key_press_event, data); if (activate) acquire_grab (data, NULL); /* grab all */ /* TRAY ICON */ data->trayicon = gtk_status_icon_new_from_file("/usr/share/pixmaps/gromit-mpx.png"); gtk_status_icon_set_tooltip_text (data->trayicon, "Gromit-MPX"); g_signal_connect (data->trayicon, "activate", G_CALLBACK (on_trayicon_activate), data); g_signal_connect (data->trayicon, "popup-menu", G_CALLBACK (on_trayicon_menu), data); } void parse_print_help (gpointer key, gpointer value, gpointer user_data) { paint_context_print ((gchar *) key, (GromitPaintContext *) value); } int app_parse_args (int argc, char **argv, GromitData *data) { gint i; gchar *arg; gboolean wrong_arg = FALSE; gboolean activate = FALSE; data->hot_keyval = DEFAULT_HOTKEY; data->hot_keycode = 0; for (i=1; i < argc ; i++) { arg = argv[i]; if (strcmp (arg, "-a") == 0 || strcmp (arg, "--active") == 0) { activate = TRUE; } else if (strcmp (arg, "-d") == 0 || strcmp (arg, "--debug") == 0) { data->debug = 1; } else if (strcmp (arg, "-k") == 0 || strcmp (arg, "--key") == 0) { if (i+1 < argc) { data->hot_keyval = argv[i+1]; data->hot_keycode = 0; i++; } else { g_printerr ("-k requires an Key-Name as argument\n"); wrong_arg = TRUE; } } else if (strcmp (arg, "-K") == 0 || strcmp (arg, "--keycode") == 0) { if (i+1 < argc && atoi (argv[i+1]) > 0) { data->hot_keyval = NULL; data->hot_keycode = atoi (argv[i+1]); i++; } else { g_printerr ("-K requires an keycode > 0 as argument\n"); wrong_arg = TRUE; } } else { g_printerr ("Unknown Option for Gromit-MPX startup: \"%s\"\n", arg); wrong_arg = TRUE; } if (wrong_arg) { g_printerr ("Please see the Gromit-MPX manpage for the correct usage\n"); exit (1); } } return activate; } /* * Main programs */ int main_client (int argc, char **argv, GromitData *data) { GdkAtom action = GDK_NONE; gint i; gchar *arg; gboolean wrong_arg = FALSE; for (i=1; i < argc ; i++) { arg = argv[i]; action = GDK_NONE; if (strcmp (arg, "-d") == 0 || strcmp (arg, "--debug") == 0) { data->debug = 1; } else if (strcmp (arg, "-t") == 0 || strcmp (arg, "--toggle") == 0) { action = GA_TOGGLE; if (i+1 < argc && argv[i+1][0] != '-') /* there is an id supplied */ { data->clientdata = argv[i+1]; ++i; } else data->clientdata = "-1"; /* default to grab all */ } else if (strcmp (arg, "-v") == 0 || strcmp (arg, "--visibility") == 0) { action = GA_VISIBILITY; } else if (strcmp (arg, "-q") == 0 || strcmp (arg, "--quit") == 0) { action = GA_QUIT; } else if (strcmp (arg, "-c") == 0 || strcmp (arg, "--clear") == 0) { action = GA_CLEAR; } else if (strcmp (arg, "-r") == 0 || strcmp (arg, "--reload") == 0) { action = GA_RELOAD; } else { g_printerr ("Unknown Option to control a running Gromit-MPX process: \"%s\"\n", arg); wrong_arg = TRUE; } if (!wrong_arg && action != GDK_NONE) { gtk_selection_convert (data->win, GA_CONTROL, action, GDK_CURRENT_TIME); gtk_main (); /* Wait for the response */ } else if(wrong_arg) { g_printerr ("Please see the Gromit-MPX manpage for the correct usage\n"); return 1; } } return 0; } int main (int argc, char **argv) { GromitData *data; gtk_init (&argc, &argv); data = g_malloc0(sizeof (GromitData)); /* init basic stuff */ data->display = gdk_display_get_default (); data->screen = gdk_display_get_default_screen (data->display); data->xinerama = gdk_screen_get_n_monitors (data->screen) > 1; data->composited = gdk_screen_is_composited (data->screen); data->root = gdk_screen_get_root_window (data->screen); data->width = gdk_screen_get_width (data->screen); data->height = gdk_screen_get_height (data->screen); /* init our window */ data->win = gtk_window_new (GTK_WINDOW_POPUP); // this trys to set an alpha channel on_screen_changed(data->win, NULL, data); gtk_window_fullscreen(GTK_WINDOW(data->win)); gtk_window_set_skip_taskbar_hint(GTK_WINDOW(data->win), TRUE); gtk_window_set_opacity(GTK_WINDOW(data->win), 0.75); gtk_widget_set_app_paintable (data->win, TRUE); gtk_window_set_decorated (GTK_WINDOW (data->win), FALSE); gtk_widget_set_size_request (GTK_WIDGET (data->win), data->width, data->height-1); gtk_widget_add_events (data->win, GROMIT_WINDOW_EVENTS); g_signal_connect (data->win, "delete-event", gtk_main_quit, NULL); g_signal_connect (data->win, "destroy", gtk_main_quit, NULL); /* the selection event handlers will be overwritten if we become a mainapp */ g_signal_connect (data->win, "selection_received", G_CALLBACK (on_clientapp_selection_received), data); g_signal_connect (data->win, "selection_get", G_CALLBACK (on_clientapp_selection_get), data); gtk_widget_realize (data->win); // try to set transparent for input cairo_region_t* r = cairo_region_create(); gtk_widget_input_shape_combine_region(data->win, r); cairo_region_destroy(r); gtk_selection_owner_set (data->win, GA_DATA, GDK_CURRENT_TIME); gtk_selection_add_target (data->win, GA_DATA, GA_TOGGLEDATA, 1007); /* Try to get a status message. If there is a response gromit * is already active. */ gtk_selection_convert (data->win, GA_CONTROL, GA_STATUS, GDK_CURRENT_TIME); gtk_main (); /* Wait for the response */ if (data->client) return main_client (argc, argv, data); /* Main application */ setup_main_app (data, app_parse_args (argc, argv, data)); gtk_main (); release_grab(data, NULL); /* ungrab all */ g_free (data); return 0; } gromit-mpx-1.1/src/gromit-mpx.h000066400000000000000000000110771220446531300165270ustar00rootroot00000000000000/* * Gromit -- a program for painting on the screen * Copyright (C) 2000 Simon Budig * * MPX modifications Copyright (C) 2009 Christian Beier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef GROMIT_MPX_H #define GROMIT_MPX_H #include #include #include #include #define GROMIT_MOUSE_EVENTS ( GDK_POINTER_MOTION_MASK | \ GDK_BUTTON_MOTION_MASK | \ GDK_BUTTON_PRESS_MASK | \ GDK_BUTTON_RELEASE_MASK ) #define GROMIT_WINDOW_EVENTS ( GROMIT_MOUSE_EVENTS | GDK_EXPOSURE_MASK ) /* Atoms used to control Gromit */ #define GA_CONTROL gdk_atom_intern ("Gromit/control", FALSE) #define GA_STATUS gdk_atom_intern ("Gromit/status", FALSE) #define GA_QUIT gdk_atom_intern ("Gromit/quit", FALSE) #define GA_ACTIVATE gdk_atom_intern ("Gromit/activate", FALSE) #define GA_DEACTIVATE gdk_atom_intern ("Gromit/deactivate", FALSE) #define GA_TOGGLE gdk_atom_intern ("Gromit/toggle", FALSE) #define GA_VISIBILITY gdk_atom_intern ("Gromit/visibility", FALSE) #define GA_CLEAR gdk_atom_intern ("Gromit/clear", FALSE) #define GA_RELOAD gdk_atom_intern ("Gromit/reload", FALSE) #define GA_DATA gdk_atom_intern ("Gromit/data", FALSE) #define GA_TOGGLEDATA gdk_atom_intern ("Gromit/toggledata", FALSE) typedef enum { GROMIT_PEN, GROMIT_ERASER, GROMIT_RECOLOR } GromitPaintType; typedef struct { GromitPaintType type; guint width; gfloat arrowsize; GdkColor *paint_color; cairo_t *paint_ctx; gdouble pressure; } GromitPaintContext; typedef struct { gint x; gint y; gint width; } GromitStrokeCoordinate; typedef struct { gdouble lastx; gdouble lasty; guint32 motion_time; GList* coordlist; GdkDevice* device; guint index; guint state; GromitPaintContext *cur_context; gboolean is_grabbed; gboolean was_grabbed; GdkDevice* lastslave; } GromitDeviceData; typedef struct { GtkWidget *win; GtkStatusIcon *trayicon; GdkCursor *paint_cursor; GdkCursor *erase_cursor; GdkDisplay *display; GdkScreen *screen; gboolean xinerama; gboolean composited; GdkWindow *root; gchar *hot_keyval; guint hot_keycode; GdkColor *white; GdkColor *black; GdkColor *red; GromitPaintContext *default_pen; GromitPaintContext *default_eraser; GHashTable *tool_config; cairo_surface_t *backbuffer; GHashTable *devdatatable; gboolean all_grabbed; guint timeout_id; guint modified; guint delayed; guint maxwidth; guint width; guint height; guint client; guint painted; gboolean hidden; gboolean debug; gchar *clientdata; } GromitData; void toggle_visibility (GromitData *data); void hide_window (GromitData *data); void show_window (GromitData *data); void parse_print_help (gpointer key, gpointer value, gpointer user_data); void select_tool (GromitData *data, GdkDevice *master, GdkDevice *slave, guint state); void draw_line (GromitData *data, GdkDevice *dev, gint x1, gint y1, gint x2, gint y2); void draw_arrow (GromitData *data, GdkDevice *dev, gint x1, gint y1, gint width, gfloat direction); void clear_screen (GromitData *data); gboolean coord_list_get_arrow_param (GromitData *data, GdkDevice *dev, gint search_radius, gint *ret_width, gfloat *ret_direction); void coord_list_prepend (GromitData *data, GdkDevice* dev, gint x, gint y, gint width); void coord_list_free (GromitData *data, GdkDevice* dev); GromitPaintContext *paint_context_new (GromitData *data, GromitPaintType type, GdkColor *fg_color, guint width, guint arrowsize); void paint_context_free (GromitPaintContext *context); #endif gromit-mpx-1.1/src/input.c000066400000000000000000000174071220446531300155610ustar00rootroot00000000000000 /* * Functions for setting up (parts of) the application */ #include #include #include "input.h" void setup_input_devices (GromitData *data) { /* ungrab all */ release_grab (data, NULL); /* and clear our own device data list */ GHashTableIter it; gpointer value; g_hash_table_iter_init (&it, data->devdatatable); while (g_hash_table_iter_next (&it, NULL, &value)) g_free(value); g_hash_table_remove_all(data->devdatatable); /* get devices */ GdkDeviceManager *device_manager = gdk_display_get_device_manager(data->display); GList *devices, *d; int i = 0; devices = g_list_concat(gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER), gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE)); for(d = devices; d; d = d->next) { GdkDevice *device = (GdkDevice *) d->data; /* only enable devices with 2 ore more axes */ if (gdk_device_get_source(device) != GDK_SOURCE_KEYBOARD && gdk_device_get_n_axes(device) >= 2) { gdk_device_set_mode (device, GDK_MODE_SCREEN); GromitDeviceData *devdata; devdata = g_malloc0(sizeof (GromitDeviceData)); devdata->device = device; devdata->index = i; /* get attached keyboard and grab the hotkey */ if (!data->hot_keycode) { g_printerr("ERROR: Grabbing hotkey from attached keyboard " "of '%s' failed, no hotkey defined.\n", gdk_device_get_name(device)); g_free(devdata); continue; } /* if this is a slave device, we need the master */ GdkDevice *kdevice=device; if(gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_SLAVE) kdevice=gdk_device_get_associated_device (device); gint dev_id = -1; g_object_get(kdevice, "device-id", &dev_id, NULL); gint kbd_dev_id = -1; XIDeviceInfo* devinfo; int devicecount = 0; devinfo = XIQueryDevice(GDK_DISPLAY_XDISPLAY(data->display), dev_id, &devicecount); if(devicecount) kbd_dev_id = devinfo->attachment; XIFreeDeviceInfo(devinfo); if(kbd_dev_id != -1) { if(data->debug) g_printerr("DEBUG: Grabbing hotkey from keyboard '%d' .\n", kbd_dev_id); XIEventMask mask; unsigned char bits[4] = {0,0,0,0}; mask.mask = bits; mask.mask_len = sizeof(bits); XISetMask(bits, XI_KeyPress); XISetMask(bits, XI_KeyRelease); XIGrabModifiers modifiers[] = {{XIAnyModifier, 0}}; int nmods = 1; gdk_error_trap_push (); XIGrabKeycode( GDK_DISPLAY_XDISPLAY(data->display), kbd_dev_id, data->hot_keycode, GDK_WINDOW_XID(data->root), GrabModeAsync, GrabModeAsync, True, &mask, nmods, modifiers); XSync(GDK_DISPLAY_XDISPLAY(data->display), False); if(gdk_error_trap_pop()) { g_printerr("ERROR: Grabbing hotkey from keyboard device %d failed.\n", kbd_dev_id); g_free(devdata); continue; } } g_hash_table_insert(data->devdatatable, device, devdata); g_printerr ("Enabled Device %d: \"%s\", (Type: %d)\n", i++, gdk_device_get_name(device), gdk_device_get_source(device)); } } g_printerr ("Now %d enabled devices.\n", g_hash_table_size(data->devdatatable)); } void release_grab (GromitData *data, GdkDevice *dev) { if(!dev) /* this means release all grabs */ { GHashTableIter it; gpointer value; GromitDeviceData* devdata; g_hash_table_iter_init (&it, data->devdatatable); while (g_hash_table_iter_next (&it, NULL, &value)) { devdata = value; if(devdata->is_grabbed) { gdk_error_trap_push(); gdk_device_ungrab(devdata->device, GDK_CURRENT_TIME); XSync(GDK_DISPLAY_XDISPLAY(data->display), False); if(gdk_error_trap_pop()) g_printerr("WARNING: Ungrabbing device '%s' failed.\n", gdk_device_get_name(devdata->device)); devdata->is_grabbed = 0; /* workaround buggy GTK3 ? */ devdata->motion_time = 0; } } data->all_grabbed = 0; if(data->debug) g_printerr ("DEBUG: Ungrabbed all Devices.\n"); return; } /* get the data for this device */ GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); if (devdata->is_grabbed) { gdk_device_ungrab(devdata->device, GDK_CURRENT_TIME); devdata->is_grabbed = 0; /* workaround buggy GTK3 ? */ devdata->motion_time = 0; if(data->debug) g_printerr ("DEBUG: Ungrabbed Device '%s'.\n", gdk_device_get_name(devdata->device)); } if (!data->painted) hide_window (data); } void acquire_grab (GromitData *data, GdkDevice *dev) { show_window (data); if(!dev) /* this means grab all */ { GHashTableIter it; gpointer value; GromitDeviceData* devdata = NULL; g_hash_table_iter_init (&it, data->devdatatable); while (g_hash_table_iter_next (&it, NULL, &value)) { GdkCursor *cursor; devdata = value; if(devdata->is_grabbed || gdk_device_get_device_type(devdata->device) == GDK_DEVICE_TYPE_SLAVE) continue; if(devdata->cur_context && devdata->cur_context->type == GROMIT_ERASER) cursor = data->erase_cursor; else cursor = data->paint_cursor; if(gdk_device_grab(devdata->device, gtk_widget_get_window(data->win), GDK_OWNERSHIP_NONE, FALSE, GROMIT_MOUSE_EVENTS, cursor, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS) { /* this probably means the device table is outdated, e.g. this device doesn't exist anymore */ g_printerr("Error grabbing Device '%s' while grabbing all, ignoring.\n", gdk_device_get_name(devdata->device)); continue; } devdata->is_grabbed = 1; } data->all_grabbed = 1; if(data->debug) g_printerr("DEBUG: Grabbed all Devices.\n"); return; } GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); if (!devdata->is_grabbed) { GdkCursor *cursor; if(devdata->cur_context && devdata->cur_context->type == GROMIT_ERASER) cursor = data->erase_cursor; else cursor = data->paint_cursor; if(gdk_device_grab(devdata->device, gtk_widget_get_window(data->win), GDK_OWNERSHIP_NONE, FALSE, GROMIT_MOUSE_EVENTS, cursor, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS) { /* this probably means the device table is outdated, e.g. this device doesn't exist anymore */ g_printerr("Error grabbing device '%s', rescanning device list.\n", gdk_device_get_name(devdata->device)); setup_input_devices(data); return; } devdata->is_grabbed = 1; if(data->debug) g_printerr("DEBUG: Grabbed Device '%s'.\n", gdk_device_get_name(devdata->device)); } } void toggle_grab (GromitData *data, GdkDevice* dev) { if(dev == NULL) /* toggle all */ { if (data->all_grabbed) release_grab (data, NULL); else acquire_grab (data, NULL); return; } GromitDeviceData *devdata = g_hash_table_lookup(data->devdatatable, dev); if(devdata) { if(devdata->is_grabbed) release_grab (data, devdata->device); else acquire_grab (data, devdata->device); } else g_printerr("ERROR: No such device '%s' in internal table.\n", gdk_device_get_name(dev)); } gromit-mpx-1.1/src/input.h000066400000000000000000000004241220446531300155550ustar00rootroot00000000000000 #ifndef INPUT_H #define INPUT_H #include "gromit-mpx.h" void setup_input_devices (GromitData *data); void release_grab (GromitData *data, GdkDevice *dev); void acquire_grab (GromitData *data, GdkDevice *dev); void toggle_grab (GromitData *data, GdkDevice *dev); #endif gromit-mpx-1.1/src/paint_cursor.xpm000066400000000000000000000023371220446531300175100ustar00rootroot00000000000000/* XPM */ #define paint_cursor_x_hot 14 #define paint_cursor_y_hot 14 const char * paint_cursor_xpm[] = { "31 31 3 1", " c None", ". c #FFFFFF", "+ c #000000", " . ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " + ", " ", " ", " ", " ", "......... ......... ", " ++++++++ +++++++++ ", " ", " ", " ", " ", " ", " . ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " + ", " "};