pax_global_header00006660000000000000000000000064130131515220014503gustar00rootroot0000000000000052 comment=a835decff6d0186bd96075bca8ed31144f2ff9e2 gromit-mpx-1.2/000077500000000000000000000000001301315152200134505ustar00rootroot00000000000000gromit-mpx-1.2/.gitignore000066400000000000000000000004441301315152200154420ustar00rootroot00000000000000*.o .deps/ /aclocal.m4 /autom4te.cache/ /build-config.h /build-config.h.in /compile /config.h /config.h.in /config.log /config.status /configure /depcomp /install-sh /missing /src/gromit-mpx /stamp-h1 Makefile Makefile.in /.idea/ /Build/ /cmake-build-debug/ *~ /Build_Release/ /Build_Debug/ gromit-mpx-1.2/.travis.yml000066400000000000000000000005121301315152200155570ustar00rootroot00000000000000language: c dist: trusty sudo: required # install build dependencies before_install: - sudo apt-get install automake libgtk-3-dev libappindicator3-dev libxi-dev # before build script, run autoreconf before_script: autoreconf -fiv # Default is "./configure && make && make test", but no tests yet script: "./configure && make"gromit-mpx-1.2/AUTHORS000066400000000000000000000001071301315152200145160ustar00rootroot00000000000000Simon Budig Christian Beier gromit-mpx-1.2/CMakeLists.txt000066400000000000000000000035331301315152200162140ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0) project(Gromit_MPX LANGUAGES C) set(target_name gromit-mpx) set(version 1.2) set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter") configure_file(build-config.h_cmake_in build-config.h) find_package(PkgConfig) pkg_check_modules(gtk3 REQUIRED "gtk+-3.0 >= 2.99.3") pkg_check_modules(appindicator3 REQUIRED "appindicator3-0.1 >= 0.4.92") pkg_check_modules(xinput REQUIRED "xi >= 1.3") pkg_check_modules(x11 REQUIRED x11) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${gtk3_INCLUDE_DIRS} ${appindicator3_INCLUDE_DIRS} ${xinput_INCLUDE_DIRS} ${x11_INCLUDE_DIRS} ) link_directories( ${gtk3_LIBRARY_DIRS} ${appindicator3_LIBRARY_DIRS} ${xinput_LIBRARY_DIRS} ${x11_LIBRARY_DIRS} ) set(sources src/callbacks.c src/callbacks.h src/config.c src/config.h src/gromit-mpx.c src/gromit-mpx.h src/input.c src/input.h ) add_executable(${target_name} ${sources}) target_link_libraries(${target_name} ${gtk3_LIBRARIES} ${appindicator3_LIBRARIES} ${xinput_LIBRARIES} ${x11_LIBRARIES} -lm ) install(TARGETS ${target_name} RUNTIME DESTINATION bin) install(FILES data/gromit-mpx.desktop DESTINATION share/applications) install(FILES data/gromit-mpx.cfg DESTINATION etc/gromit-mpx) install(FILES README.md AUTHORS ChangeLog NEWS DESTINATION share/doc/gromit-mpx) install(FILES gromit-mpx.1 DESTINATION share/man/man1) install(FILES data/gromit-mpx.png data/gromit-mpx.xpm DESTINATION share/pixmaps) install(FILES data/gromit-mpx.svg DESTINATION share/icons/hicolor/scalable/apps) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) gromit-mpx-1.2/COPYING000066400000000000000000000431151301315152200145070ustar00rootroot00000000000000 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.2/ChangeLog000066400000000000000000001325101301315152200152240ustar00rootroot00000000000000commit c2b4d4a044edea046494e6c628c01ea26e8246a5 Author: Christian Beier Date: Wed Nov 16 22:34:09 2016 +0100 Make the line thickness changer applicable to mouse drawing as well. This commit removes the special mouse handling by settings default pressure to full-on. Thus, dynamic line thickness will be taken into account for mouse events as well now. commit 5b50ba374d5c46e5cc3ee3e9e5d9d3501e6ce5ad Author: Christian Beier Date: Wed Nov 16 20:04:38 2016 +0100 CMake: mark all libs as required. commit d38cb4217a9eb42178285a12716bd4308bebcd8d Author: Christian Beier Date: Wed Nov 16 11:51:10 2016 +0100 Update man page a bit. commit 1b6c55804e80a1483cdf66afaa7c1e6db101c25a Author: Christian Beier Date: Tue Nov 15 20:13:59 2016 +0100 Fix help dialog formatting. Was broken by 463afe30133b5e8cc814c77aef4e186696d55eca. commit fc00515902d387dc4b99c6aa5eb80f04cc714d14 Author: Christian Beier Date: Tue Nov 15 19:42:53 2016 +0100 Update NEWS. commit 806562e917c1a148e36be56fe427c1fc93967928 Author: Christian Beier Date: Tue Nov 15 19:25:31 2016 +0100 Update TODO. commit b09bc0117fd65965570771360e8854c52e35f920 Merge: 8cf5da1 ce06532 Author: Christian Beier Date: Tue Nov 15 19:22:38 2016 +0100 Merge pull request #33 from russel/cmake-build Add a first cut at a CMake build system commit ce065329e314ee63564ea0d36fdd72e0626b5296 Author: Russel Winder Date: Sun Nov 13 08:10:09 2016 +0000 Add a first cut at a CMake build system – allows for use of CLion as IDE. commit 8cf5da19e10cab9b985e84852942a2e1b6cea1cb Author: Christian Beier Date: Mon Nov 14 10:46:46 2016 +0100 TravisCI: add a build badge to README.md. commit 35bb13f2846f32add7700c4a14981020d8417e2e Author: Christian Beier Date: Mon Nov 14 10:43:35 2016 +0100 TravisCI: switch to a more recent Ubuntu. commit 4d72eb7c0f1827626261590a04b55e07a58e6918 Author: Christian Beier Date: Mon Nov 14 09:26:04 2016 +0100 Add automake to Travis build deps. commit ac31c08f81452b3834a922658b3468e6a961d12d Author: Christian Beier Date: Mon Nov 14 09:19:07 2016 +0100 Add a .travis.yml file. commit 7a3c494425d70e37076f86c18380f29ed017da41 Merge: a3bd7ab 620bc36 Author: Christian Beier Date: Mon Nov 14 08:57:18 2016 +0100 Merge pull request #34 from barak/upstream minor matters noted while packaging latest development version commit 620bc3677d130722a235035052c74b81a0c1ac7e Author: Barak A. Pearlmutter Date: Sun Nov 13 23:05:43 2016 +0000 add desktop file keywords, silencing lintian tag desktop-entry-lacks-keywords-entry commit 463afe30133b5e8cc814c77aef4e186696d55eca Author: Barak A. Pearlmutter Date: Sun Nov 13 22:35:01 2016 +0000 address gcc -Werror=format-security commit 545f5e84265fc1e18927d8b2f453c77b1c8e66ad Author: Barak A. Pearlmutter Date: Sun Nov 13 22:28:06 2016 +0000 AX_CFLAGS_WARN_ALL and automake subdir-objects commit 13a967101475409d57fb96a6514683b3d5cc0e75 Author: Barak A. Pearlmutter Date: Sun Nov 13 22:12:33 2016 +0000 git ignore build debris commit a3bd7ab8028d4544d7396e9bcf69abdf2862356a Author: Christian Beier Date: Sun Nov 13 01:04:29 2016 +0100 Only use the X11-specific bits in input device setup when actually running on an X11 display. commit efb3e4a603e33487c9b51e9eb92e65ba42555a4a Author: Christian Beier Date: Sat Nov 12 20:34:40 2016 +0100 Use a commonly available font for the SVG icon. commit 6ca9dc53a55e07bcb9c4edc0870664017a1d6487 Author: Christian Beier Date: Sat Nov 12 20:29:58 2016 +0100 Update SVG icon. commit 20dee4f7aac4da4fa1c45c53b9da19846175eef5 Author: Christian Beier Date: Sat Nov 12 20:10:58 2016 +0100 Convert the tray icon code to be compatible to Ubuntu-Unity. commit b9df54f24b9100653268423039c3acdab28a1a78 Author: Christian Beier Date: Sun Oct 16 17:57:30 2016 +0200 Add a poor man's help dialog displaying at least the hot key commands. commit b98a9ef9da63afa1093d15dea5e606f4c9921126 Author: Christian Beier Date: Sun Oct 16 15:50:03 2016 +0200 Add (still empty) help menu item. commit 9db0439a2ec9ec9ad79827ad0cf8c15530c462c6 Author: Christian Beier Date: Sun Oct 16 14:03:39 2016 +0200 Version up. commit 519767765d9bf91e85a6f09776ffc82460268e16 Author: Christian Beier Date: Sun Oct 16 14:03:03 2016 +0200 Get the About dialog version from the build system. commit 5fc19c7f68fa4151b7e3bf20824e31bfb1d308a4 Author: Christian Beier Date: Sat Oct 15 16:51:28 2016 +0200 Rework try icon menu to be device-specific. Problem though is that GDK always reports the core pointer, event if another master clicked the menu. mhhh. commit f83c153ea76e17825ddbfc333754eb208a5deb28 Author: Christian Beier Date: Fri Oct 14 16:43:56 2016 +0200 Revert "flatten into single Makefile.am" This reverts commit 2bb6f900f144332b08016d390450fc42b7d8f889. It made developing cumbersome as make has to be called from outside the source directory. commit d632a9a823500bc650e8e9c526216fc9199eaebe Author: Christian Beier Date: Fri Oct 14 15:04:53 2016 +0200 Fix two more warnings. commit 917d8c10f11db115d328ed5738056d536bbfb34f Author: Christian Beier Date: Fri Oct 14 15:03:30 2016 +0200 Convert all deprecated GdkColor stuff to GdkRGBA. commit 04bb86fa5bb82ee0443dbfe4fbef7a1739467df2 Author: Christian Beier Date: Fri Oct 14 14:38:42 2016 +0200 Add an About dialog. Version still hardcoded... commit c8ea7dd4e0fc54e4d54093a6bdf8d9235622af4c Author: Christian Beier Date: Mon Oct 10 20:16:58 2016 +0200 Rework ther systray icon find logic to something that actually works. commit 4ebf4c89f29a14a764e6667cd74166546e132899 Author: Christian Beier Date: Mon Oct 10 10:23:44 2016 +0200 Fix path to installed systray icons. commit 721dd2afc936a1322beae43fba970d29bbd82501 Author: Christian Beier Date: Mon Oct 10 10:20:46 2016 +0200 Use the SVG icon for the tray. commit 52ffa118ff4c2f8923681198507301a2e55b5165 Author: Christian Beier Date: Mon Oct 10 10:20:25 2016 +0200 Fix font and clipping on SVG icon. commit 7bc446198a164ad10f7936aa883f0b5f1808ff30 Author: Christian Beier Date: Mon Oct 10 10:03:19 2016 +0200 Change the SVG icon to more resemble the original PNG one. commit ded5df902b3b1b4c674e9edf65981c747b218318 Author: Christian Beier Date: Mon Oct 10 09:52:10 2016 +0200 Try to load tray icon from different locations. commit 3ed28df1135898529b78e94a3dcaba7bc015187d Author: Christian Beier Date: Sun Oct 9 15:58:29 2016 +0200 Replace some more deprecated calls in callbacks.c. commit 1ec34cfeedec9504ccd6e559ca42b176de344c79 Author: Christian Beier Date: Sun Oct 9 15:56:57 2016 +0200 Replace some deprecated GTK/GDK functions. commit 7bc5f21fd2f8033320d927c5765e47705a9dd81f Author: Christian Beier Date: Sat Oct 8 18:34:45 2016 +0200 Get rid of the X11 intrinsics to find the paired device in snoop_key_press(). commit 53f981df8e469f1e3c2c19fd2ae1eec0c2d80619 Author: Christian Beier Date: Sat Oct 8 17:12:30 2016 +0200 Add a motion debug log. commit 6d463e7a7b38c74ea5ba7d29ca672fad9b965a87 Merge: 2abb29b 7374264 Author: Christian Beier Date: Fri Oct 7 01:18:59 2016 +0200 Merge pull request #26 from tobias47n9e/patch-1 README: Add some required packages for building commit 73742645a5d55bba88c23024d1c883457be8af34 Author: Tobias Schönberg Date: Thu Oct 6 20:57:24 2016 +0200 README: Add some required packages for building commit 2abb29b9ba6aeee5644602bf65aba44664b16e03 Merge: 98e92c2 2bb6f90 Author: Christian Beier Date: Thu Aug 27 12:29:01 2015 +0200 Merge pull request #21 from barak/tweaks Tweaks from barak commit 98e92c282e160889db2c17330945e897cd59093a Merge: fe9f718 bb5688e Author: Christian Beier Date: Mon Aug 24 12:35:47 2015 +0200 Merge pull request #20 from Tuxilero/master Opacity support commit bb5688e9cee6551d66c2c4ae5479aad352d411a1 Author: Lukas Hermann Date: Sat Aug 22 17:50:48 2015 +0200 Update README.md commit ecb5d9f022bd736190d7d0c91ecb2f8aefcce496 Merge: 344c69a 4ea5ed0 Author: Lukáš Hermann Date: Fri Aug 21 13:50:05 2015 +0200 Merge branch 'master' of https://github.com/Tuxilero/gromit-mpx commit 344c69a2fd59db2070b5f8f4ec8d84393655802d Author: Lukáš Hermann Date: Fri Aug 21 13:49:33 2015 +0200 Opacity menu entry, argument fix commit 4ea5ed078c4df3f666a61a349c003b4d8baa20a0 Author: Lukas Hermann Date: Fri Aug 21 11:58:57 2015 +0200 Update README.md commit 188dd42cbf1db93606e4108f1f52500279f42a4d Author: Lukáš Hermann Date: Fri Aug 21 11:57:07 2015 +0200 Opacity support commit fe9f718c932aea8828a06f5df096c52d8d08f57b Merge: a506290 bb51710 Author: Christian Beier Date: Sun May 10 18:03:09 2015 +0200 Merge pull request #17 from wavexx/minwidth Add minsize as a pen setting (defaulting to 1). commit 2bb6f900f144332b08016d390450fc42b7d8f889 Author: Barak A. Pearlmutter Date: Thu May 7 16:19:24 2015 +0100 flatten into single Makefile.am commit db7d9bf8990b4b7b56d53b031fe30c19795cb9e2 Author: Barak A. Pearlmutter Date: Thu May 7 16:13:48 2015 +0100 fix clipped svg icon commit 5a7f6333b06e268b0d83e10c2c725d888f9cff1f Author: Barak A. Pearlmutter Date: Thu May 7 16:03:50 2015 +0100 update construct in configure.ac commit bb51710f4f3371480030ae7f9d6da91a1f37e6ea Author: Yuri D'Elia Date: Thu May 7 14:39:03 2015 +0200 Add minwidth as a pen setting (defaulting to 1). commit a506290adff369962a4eab3c2865285221af223e Author: Christian Beier Date: Tue Feb 3 14:01:04 2015 +0100 Add debug output if user conf file not found. commit a9a76ac0c97ef3852c22c099e59145a576101d67 Merge: 964b161 05a2c0b Author: Christian Beier Date: Sun Mar 30 06:38:05 2014 +0200 Merge pull request #14 from barak/upstream install README.md commit 05a2c0bff71d5747b599a04727d428e89ce40fa0 Merge: fb3c7f8 964b161 Author: Barak A. Pearlmutter Date: Sat Mar 29 22:40:24 2014 +0000 Merge remote-tracking branch 'upstream/master' into upstream commit 964b1615700b5c84c5fc8a1d41e86092bb4876a2 Merge: 4f9e690 16aba76 Author: Christian Beier Date: Sat Mar 29 06:37:58 2014 +0100 Merge pull request #13 from mehmetaergun/patch-2 typo fix without the i commit 16aba766e6d3a7e7c5df296e6d208c51e859895f Author: Mehmet Atif Ergun Date: Sat Mar 29 00:33:44 2014 -0400 typo fix without the i commit fb3c7f8f54961226d9cde7f137522b90f9d4e7d3 Author: Barak A. Pearlmutter Date: Thu Mar 20 13:46:14 2014 +0000 inform build system that README is now README.md commit 4f9e690f2b98743fcc2164e0c666372a54101725 Merge: 2bac387 a7ba808 Author: Christian Beier Date: Wed Mar 19 15:16:08 2014 +0100 Merge pull request #11 from barak/upstream Upstream commit a7ba80827b0a14682dacd99758f1cc727ed73b91 Author: Barak A. Pearlmutter Date: Wed Mar 19 13:31:00 2014 +0000 further markdown-ify README.md commit 59573f69df610295a918408a45fca2c4edd07b50 Author: Barak A. Pearlmutter Date: Wed Mar 19 13:27:11 2014 +0000 markdown-ify README.md commit e9ee9c5689be5da8df89c8f3fd18b3a8e0b94772 Author: Barak A. Pearlmutter Date: Wed Mar 19 13:05:20 2014 +0000 mv README README.md commit aa7be9975835e9e3c86c50470f812e9adc34f111 Author: Barak A. Pearlmutter Date: Wed Mar 19 12:58:45 2014 +0000 trim whitespace in README commit 2bac387a5bf84029ce69a0f33757b4c6fe52372a Merge: 6112ffa 41c09e1 Author: Christian Beier Date: Tue Mar 18 12:38:00 2014 +0100 Merge pull request #10 from TaoK/patch-1 Update README to reference similar tools commit 41c09e16f35f2247a22727add4896cd2f873d8f9 Author: Tao Klerks Date: Mon Mar 17 15:58:25 2014 -0400 Update README to reference similar tools Adding some references to equivalent or similar utilities for Windows (and Linux) works both ways - would make it easier to find this if you know the windows tools, and helps those who (like me) find the Linux utility but have a hard time finding the windows equivalent. commit 6112ffaa144b37fd785475976de23db652acedf1 Author: Christian Beier Date: Mon Nov 4 18:14:41 2013 +0100 Put the backend check into the backend specific file. commit 717b7d6d241209d7565b7141695c8c01b8bda52d Author: Christian Beier Date: Mon Nov 4 17:33:04 2013 +0100 Add GDK platform support check. commit 64a46929326323f32eb99625e8b2253fcbea8273 Author: Christian Beier Date: Sat Nov 2 15:15:26 2013 +0100 Move X11 specific stuff into input.c, prepping for native Wayland support some time. commit 1e4e806d46c6836b57531eefc83fb6b0a9d6db52 Merge: 1f34d32 42c44ca Author: Christian Beier Date: Thu Oct 17 13:35:53 2013 -0700 Merge pull request #8 from nwhitehead/undo Add simple undo functionality. commit 42c44caa4f505454d08898a34694cac759ab686e Author: Nathan Whitehead Date: Wed Oct 16 12:03:55 2013 -0700 Document undo/redo hotkey binding. commit a649282cf2532751b26e448f444efa6573380852 Author: Nathan Whitehead Date: Wed Oct 16 11:57:50 2013 -0700 Add undo/redo hotkey. Press of undo hotkey is undo, shift-press is redo. No action when window is hidden. commit 974cb7bbf7f94eb6f061a3a1042935e93e268eb7 Author: Nathan Whitehead Date: Wed Oct 16 11:07:00 2013 -0700 Add undo/redo menu items to systray menu. commit d05872ea6ef9ff508877abba184b0589b496257f Author: Nathan Whitehead Date: Wed Oct 16 10:34:04 2013 -0700 Update documentation for undo/redo. commit 3f94c3e1fce50c46a2223b52a5160f62f5160f14 Author: Nathan Whitehead Date: Wed Oct 16 10:24:38 2013 -0700 Add multiple levels of undo/redo. Allows undo/redo using --undo and --redo commands. Currently preallocates large surfaces to save entire drawing state, wastes memory. commit bc7b69e463c87559162f82b1529dbc2a20cb1624 Author: Nathan Whitehead Date: Wed Oct 16 00:12:22 2013 -0700 Add simple undo functionality. An extra backing surface is used to record the screen state between strokes. Adds "gromit-mpx --undo" and "gromit-mpx --redo" commands. Both have the same effect, swap undo backing surface and current backing surface. Prepares for future multiple levels of undo and redo. commit 1f34d327397f0fa6d1c8171fe3beb4f3eaaf393f Merge: e24553c 51043ae Author: Christian Beier Date: Sat Aug 31 08:27:10 2013 -0700 Merge pull request #4 from AlisterH/patch-1 Update README: correct references to the config file and its location commit 51043aeef906412fb66856d8fa8c7ca32604ccdd Author: AlisterH Date: Sat Aug 31 16:39:02 2013 +1200 Update README: correct references to the config file and its location commit e24553c6bf42fc8dffe3a4ab341e42469059d62c Author: Christian Beier Date: Mon Aug 19 20:58:19 2013 +0200 Update version to 1.1. commit 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.2/Makefile.am000066400000000000000000000012121301315152200155000ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in SUBDIRS = src doc_DATA = \ README.md\ 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.2/NEWS000066400000000000000000000014031301315152200141450ustar00rootroot00000000000000 Gromit-MPX 1.2 * Added undo/redo functionality thanks to Nathan Whitehead. * Added opacity-set functionality thanks to Lukas Hermann. * Added a tray icon. * Added an About and a Help dialog. * Added CMake build system support thanks to Russel Winder. * Replaced GTK3 deprecated functions with newer counterparts. 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.2/README.md000066400000000000000000000152001301315152200147250ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/bk138/gromit-mpx.svg?branch=master)](https://travis-ci.org/bk138/gromit-mpx) ## Gromit-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](mailto:simon@budig.de). 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. Similar tools for MS-Windows include *DemoHelper* (GPLv2 also), or proprietary tools like *ZoomIt* and *ScreenMarker*. For Compiz, there is also the *Annotate* plugin, and the much-flashier *Firepaint (paint fire on screen)* plugin. ### 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` and `F10` keys, so that no other application can use them and they are 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. F10: undo last stroke SHIFT-F10: redo last undone stroke You can specify the keys to grab via: ``` gromit-mpx --key --undo-key ``` Specifying an empty string or `none` for the keysym will prevent gromit from grabbing a key. You can specify the opacity simply via: ``` gromit-mpx -o ``` 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") gromit-mpx --undo will undo the last drawing stroke (or "-z") gromit-mpx --redo will redo the last undone drawing stroke (or "-y") 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. Undo/redo commands are cumulative. For example, sending two undo commands will undo the last two strokes. The maximum undo/redo depth is 4 strokes. ### Building it Gromit-MPX is small and lightweight. It needs GTK+3 to build. Simply type `./configure && make && make install`. If you checked out from git instead of using the tarball, an `autoreconf --install` is needed to setup the build system. You might also need to install `automake` and `gtk3-devel`. ### Configuration: Gromit-MPX is configurable via the file `gromit-mpx.cfg` in the directory defined by `$XDG_CONFIG_HOME` (usually `~/.config`). Here you can specify which Device/Button/Modifier combination invokes which tool. See the copy of `gromit-mpx.cfg` 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: 1. Buttons are more important than Modifiers 2. Low number Buttons are more important than higher ones 3. Modifiers: `SHIFT` > `CONTROL` > `ALT`/`META`. 4. 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. The same logic holds 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](mailto:dontmind@freeshell.org) gromit-mpx-1.2/TODO000066400000000000000000000001571301315152200141430ustar00rootroot00000000000000 * intro screen * runtime option to not show annotation on every virtual desktop * spot memleaks * code cleanupgromit-mpx-1.2/build-config.h_cmake_in000066400000000000000000000015751301315152200200210ustar00rootroot00000000000000#ifndef BUILD_CONFIG_h #define BUILD_CONFIG_H /* Name of package */ #define PACKAGE "gromit-mpx" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "Christian Beier " /* Define to the full name of this package. */ #define PACKAGE_NAME "gromit-mpx" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "gromit-mpx ${version}" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gromit-mpx" /* Define to the home page for this package. */ #define PACKAGE_URL "https://github.com/bk138/gromit-mpx" /* Define to the version of this package. */ #define PACKAGE_VERSION "${version}" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "${version}" #endif /* BUILD_CONFIG_H */ gromit-mpx-1.2/cmake_uninstall.cmake.in000066400000000000000000000020131301315152200202240ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) gromit-mpx-1.2/configure.ac000066400000000000000000000021201301315152200157310ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([gromit-mpx],[1.2],[Christian Beier ],[gromit-mpx],[https://github.com/bk138/gromit-mpx]) AM_INIT_AUTOMAKE([foreign subdir-objects -Wall]) AC_CONFIG_SRCDIR([src/gromit-mpx.c]) AC_CONFIG_HEADERS([build-config.h]) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O AX_CFLAGS_WARN_ALL AC_HEADER_STDC PKG_PROG_PKG_CONFIG([0.20]) # Checks for libraries. # check for math AC_SEARCH_LIBS([atan2], [m]) # check for gtk PKG_CHECK_MODULES([GTK3], [gtk+-3.0 >= 2.99.3]) # libappindicator for tray icon PKG_CHECK_MODULES([APPINDICATOR], appindicator3-0.1 >= 0.4.92) # check for XInput PKG_CHECK_MODULES([XINPUT2], [xi >= 1.3]) # check for X PKG_CHECK_MODULES([X11], [x11]) # export linker flags in the right order LIBS="$GTK3_LIBS $APPINDICATOR_LIBS $XINPUT2_LIBS $X11_LIBS $LIBS" # *************************************************************************** # finally # *************************************************************************** AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT gromit-mpx-1.2/data/000077500000000000000000000000001301315152200143615ustar00rootroot00000000000000gromit-mpx-1.2/data/gromit-mpx.cfg000066400000000000000000000010221301315152200171400ustar00rootroot00000000000000# 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.2/data/gromit-mpx.desktop000066400000000000000000000004751301315152200200650ustar00rootroot00000000000000[Desktop Entry] Exec=gromit-mpx Icon=gromit-mpx Name=Gromit-MPX Type=Application Comment=GRaphics Over MIscellaneous Things, a multi pointer annotation tool Comment[pl]=Program do rysowania bezpośrednio po ekranie Keywords=presentation;overlay;markup;pointer; Terminal=false StartupNotify=false Categories=Graphics; gromit-mpx-1.2/data/gromit-mpx.png000066400000000000000000000014051301315152200171720ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME U:IDATXý?hQ/ZjpWH$\@H%w"H"nWb},  h₈$#),"26oy<ޟy73ͼm+_G\h)5ۦY{o zڊ, l(ErG(!'P |Hm7j%%s)- .rk= mSH&upw[ `7K30i]w%M0AY`U)6TmI!(lv{ u~s ؓƒϊm=am9kxHQ]ІaknjJCjpR`}GLn3}<"(@E0Z4~1i\%=NŞ2Zps1vIjpMiH!M4 ! u8th@?7Ւ*z\x2NG@qc xaE"7i;4g;}r`@af*=5Kfa57c!q- T*,1IENDB`gromit-mpx-1.2/data/gromit-mpx.svg000066400000000000000000000140651301315152200172130ustar00rootroot00000000000000 image/svg+xml MPX gromit-mpx-1.2/data/gromit-mpx.xpm000066400000000000000000000025061301315152200172150ustar00rootroot00000000000000/* 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.2/gromit-mpx.1000066400000000000000000000105311301315152200156350ustar00rootroot00000000000000.\" Hey, vim: ft=nroff .TH GROMIT-MPX 1 "November 16, 2016" .\" 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 \-u , \-\-undo\-key will change the key used to undo/redo strokes. 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 \-U , \-\-undo\-keycode will change the key used to undo/redo strokes. 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. .TP .B \-z, \-\-undo will undo the last drawing stroke. .TP .B \-y, \-\-redo will redo the last undone drawing stroke. .SH BUGS When there is no compositing manager such as Compiz, xcompmgr or Mutter 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.2/src/000077500000000000000000000000001301315152200142375ustar00rootroot00000000000000gromit-mpx-1.2/src/Makefile.am000066400000000000000000000006221301315152200162730ustar00rootroot00000000000000## Process this file with automake to produce Makefile.in AM_CFLAGS = -Wall -Wextra -Wno-unused-parameter AM_CPPFLAGS = \ $(GTK3_CFLAGS) \ $(APPINDICATOR_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.2/src/callbacks.c000066400000000000000000000442451301315152200163330ustar00rootroot00000000000000/* * 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" #include "build-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, 1); data->default_eraser = paint_context_new (data, GROMIT_ERASER, data->red, 75, 0, 1); 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_widget_set_opacity(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 = 1; /* 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; snap_undo_state (data); gdk_event_get_axis ((GdkEvent *) ev, GDK_AXIS_PRESSURE, &pressure); data->maxwidth = (CLAMP (pressure + line_thickener, 0, 1) * (double) (slavedata->cur_context->width - slavedata->cur_context->minwidth) + slavedata->cur_context->minwidth); 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 = 1; /* 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(data->debug) g_printerr("DEBUG: Device '%s': motion to (x,y)=(%.2f : %.2f)\n", gdk_device_get_name(slave), ev->x, ev->y); 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) { data->maxwidth = (CLAMP (pressure + line_thickener, 0, 1) * (double) (slavedata->cur_context->width - slavedata->cur_context->minwidth) + slavedata->cur_context->minwidth); 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) { data->maxwidth = (CLAMP (pressure + line_thickener, 0, 1) * (double) (slavedata->cur_context->width - slavedata->cur_context->minwidth) + slavedata->cur_context->minwidth); 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"; GdkAtom action = gtk_selection_data_get_target(selection_data); if(action == 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 (action == GA_VISIBILITY) toggle_visibility (data); else if (action == GA_CLEAR) clear_screen (data); else if (action == GA_RELOAD) setup_input_devices(data); else if (action == GA_QUIT) gtk_main_quit (); else if (action == GA_UNDO) undo_drawing (data); else if (action == GA_REDO) redo_drawing (data); 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); } gboolean on_toggle_paint(GtkWidget *widget, GdkEventButton *ev, gpointer user_data) { GromitData *data = (GromitData *) user_data; GdkDevice *master = ev->device; GdkDevice *slave = gdk_event_get_source_device ((GdkEvent *) ev); if(data->debug) g_printerr("DEBUG: Device '%s': Button %i on_toggle_paint at (x,y)=(%.2f : %.2f)\n", gdk_device_get_name(slave), ev->button, ev->x, ev->y); toggle_grab(data, master); return TRUE; } void on_clear (GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; clear_screen(data); } void on_toggle_vis(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; toggle_visibility(data); } void on_thicker_lines(GtkMenuItem *menuitem, gpointer user_data) { line_thickener += 0.1; } void on_thinner_lines(GtkMenuItem *menuitem, gpointer user_data) { line_thickener -= 0.1; if (line_thickener < -1) line_thickener = -1; } void on_opacity_bigger(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; data->opacity += 0.1; if(data->opacity>1.0) data->opacity = 1.0; gtk_widget_set_opacity(data->win, data->opacity); } void on_opacity_lesser(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; data->opacity -= 0.1; if(data->opacity<0.0) data->opacity = 0.0; gtk_widget_set_opacity(data->win, data->opacity); } void on_undo(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; undo_drawing (data); } void on_redo(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; redo_drawing (data); } void on_help(GtkMenuItem *menuitem, gpointer user_data) { GromitData *data = (GromitData *) user_data; gchar helpString[4096]; snprintf(helpString, 4096, "The available commands are:\n\n\ toggle painting: %s\n\ clear screen: SHIFT-%s\n\ toggle visibility: CTRL-%s\n\ quit: ALT-%s\n\ undo last stroke: %s\n\ redo last undone stroke: SHIFT-%s", data->hot_keyval, data->hot_keyval, data->hot_keyval, data->hot_keyval, data->undo_keyval, data->undo_keyval); GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, NULL); gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), helpString); g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); gtk_widget_show_all(dialog); } void on_about(GtkMenuItem *menuitem, gpointer user_data) { const gchar *authors [] = { "Christian Beier ", "Simon Budig ", NULL }; gtk_show_about_dialog (NULL, "program-name", "Gromit-MPX", "logo-icon-name", "gromit-mpx", "title", "About Gromit-MPX", "comments", "Gromit-MPX (GRaphics Over MIscellaneous Things) is a small tool to make annotations on the screen. Gromit-MPX is a multi-pointer port of the original Gromit annotation tool by Simon Budig.", "version", VERSION, "website", "https://github.com/bk138/gromit-mpx", "authors", authors, "copyright", "Copyright 2000 Simon Budig, 2009-2016 Christian Beier", "license-type", GTK_LICENSE_GPL_2_0, NULL); } gromit-mpx-1.2/src/callbacks.h000066400000000000000000000072561301315152200163410ustar00rootroot00000000000000/* * 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); /* menu callbacks */ gboolean on_toggle_paint(GtkWidget *widget, GdkEventButton *ev, gpointer user_data); void on_clear (GtkMenuItem *menuitem, gpointer user_data); void on_toggle_vis(GtkMenuItem *menuitem, gpointer user_data); void on_thicker_lines(GtkMenuItem *menuitem, gpointer user_data); void on_thinner_lines(GtkMenuItem *menuitem, gpointer user_data); void on_opacity_bigger(GtkMenuItem *menuitem, gpointer user_data); void on_opacity_lesser(GtkMenuItem *menuitem, gpointer user_data); void on_undo(GtkMenuItem *menuitem, gpointer user_data); void on_redo(GtkMenuItem *menuitem, gpointer user_data); void on_help(GtkMenuItem *menuitem, gpointer user_data); void on_about(GtkMenuItem *menuitem, gpointer user_data); #endif gromit-mpx-1.2/src/config.c000066400000000000000000000303621301315152200156540ustar00rootroot00000000000000/* * 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; GdkRGBA *fg_color=NULL; guint width, arrowsize, minwidth; filename = g_strjoin (G_DIR_SEPARATOR_S, g_get_user_config_dir(), "gromit-mpx.cfg", NULL); file = open (filename, O_RDONLY); if (file < 0) { g_printerr ("Could not open %s: %s\n", filename, g_strerror (errno)); /* 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_scope_add_symbol (scanner, 2, "minsize", (gpointer) 4); 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; minwidth = 1; 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; minwidth = context_template->minwidth; 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) { GdkRGBA *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 (GdkRGBA)); if (gdk_rgba_parse (color, scanner->value.v_string)) { 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 if ((intptr_t) scanner->value.v_symbol == 4) { 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 Minsize (float)... " "aborting\n"); exit (1); } minwidth = 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, minwidth); 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.2/src/config.h000066400000000000000000000025421301315152200156600ustar00rootroot00000000000000/* * 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 #ifndef DEFAULT_UNDOKEY #define DEFAULT_UNDOKEY "F10" #endif #ifndef DEFAULT_OPACITY #define DEFAULT_OPACITY 0.75 #endif #endif gromit-mpx-1.2/src/erase_cursor.xpm000066400000000000000000000023371301315152200174660ustar00rootroot00000000000000/* 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.2/src/gromit-mpx.c000066400000000000000000001104101301315152200165030ustar00rootroot00000000000000/* * 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 "callbacks.h" #include "config.h" #include "input.h" #include "gromit-mpx.h" #include "build-config.h" #include "paint_cursor.xpm" #include "erase_cursor.xpm" GromitPaintContext *paint_context_new (GromitData *data, GromitPaintType type, GdkRGBA *paint_color, guint width, guint arrowsize, guint minwidth) { GromitPaintContext *context; context = g_malloc (sizeof (GromitPaintContext)); context->type = type; context->width = width; context->arrowsize = arrowsize; context->minwidth = minwidth; context->paint_color = paint_color; context->paint_ctx = cairo_create (data->backbuffer); gdk_cairo_set_source_rgba(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 ("minwidth: %3d, ", context->minwidth); g_printerr ("arrowsize: %.2f, ", context->arrowsize); g_printerr ("color: %s\n", gdk_rgba_to_string(context->paint_color)); } 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 snap_undo_state (GromitData *data) { if(data->debug) g_printerr ("DEBUG: Snapping undo buffer %d.\n", data->undo_head); copy_surface(data->undobuffer[data->undo_head], data->backbuffer); // Increment head position data->undo_head++; if(data->undo_head >= GROMIT_MAX_UNDO) data->undo_head -= GROMIT_MAX_UNDO; data->undo_depth++; // See if we ran out of undo levels with oldest undo overwritten if(data->undo_depth > GROMIT_MAX_UNDO) data->undo_depth = GROMIT_MAX_UNDO; // Invalidate any redo from this position data->redo_depth = 0; } void copy_surface (cairo_surface_t *dst, cairo_surface_t *src) { cairo_t *cr = cairo_create(dst); cairo_set_source_surface(cr, src, 0, 0); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_destroy(cr); } void swap_surfaces (cairo_surface_t *a, cairo_surface_t *b) { int width = cairo_image_surface_get_width(a); int height = cairo_image_surface_get_height(a); cairo_surface_t *temp = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); copy_surface(temp, a); copy_surface(a, b); copy_surface(b, temp); cairo_surface_destroy(temp); } void undo_drawing (GromitData *data) { /* Swap undobuffer[head-1]->backbuffer */ if(data->undo_depth <= 0) return; data->undo_depth--; data->redo_depth++; if(data->redo_depth > GROMIT_MAX_UNDO) data->redo_depth -= GROMIT_MAX_UNDO; data->undo_head--; if(data->undo_head < 0) data->undo_head += GROMIT_MAX_UNDO; swap_surfaces(data->backbuffer, data->undobuffer[data->undo_head]); GdkRectangle rect = {0, 0, data->width, data->height}; gdk_window_invalidate_rect(gtk_widget_get_window(data->win), &rect, 0); if(data->debug) g_printerr ("DEBUG: Undo drawing %d.\n", data->undo_head); } void redo_drawing (GromitData *data) { if(data->redo_depth <= 0) return; swap_surfaces(data->backbuffer, data->undobuffer[data->undo_head]); data->redo_depth--; data->undo_depth++; data->undo_head++; if(data->undo_head >= GROMIT_MAX_UNDO) data->undo_head -= GROMIT_MAX_UNDO; GdkRectangle rect = {0, 0, data->width, data->height}; gdk_window_invalidate_rect(gtk_widget_get_window(data->win), &rect, 0); if(data->debug) g_printerr("DEBUG: Redo drawing.\n"); } 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_rgba(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_rgba(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 */ void main_do_event (GdkEventAny *event, GromitData *data) { guint keycode = ((GdkEventKey *) event)->hardware_keycode; if ((event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) && event->window == data->root && (keycode == data->hot_keycode || keycode == data->undo_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 (GdkRGBA)); data->black = g_malloc (sizeof (GdkRGBA)); data->red = g_malloc (sizeof (GdkRGBA)); gdk_rgba_parse(data->white, "#FFFFFF"); gdk_rgba_parse(data->black, "#000000"); gdk_rgba_parse(data->red, "#FF0000"); /* 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); /* UNDO STATE */ data->undo_head = 0; data->undo_depth = 0; data->redo_depth = 0; int i; for (i = 0; i < GROMIT_MAX_UNDO; i++) { cairo_surface_destroy(data->undobuffer[i]); data->undobuffer[i] = 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); gtk_selection_add_target (data->win, GA_CONTROL, GA_UNDO, 8); gtk_selection_add_target (data->win, GA_CONTROL, GA_REDO, 9); /* * 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); } } /* FIND UNDOKEY KEYCODE */ if (data->undo_keyval) { GdkKeymap *keymap; GdkKeymapKey *keys; gint n_keys; guint keyval; if (strlen (data->undo_keyval) > 0 && strcasecmp (data->undo_keyval, "none") != 0) { keymap = gdk_keymap_get_for_display (data->display); keyval = gdk_keyval_from_name (data->undo_keyval); if (!keyval || !gdk_keymap_get_entries_for_keyval (keymap, keyval, &keys, &n_keys)) { g_printerr ("cannot find the key \"%s\"\n", data->undo_keyval); exit (1); } data->undo_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, 1); data->default_eraser = paint_context_new (data, GROMIT_ERASER, data->red, 75, 0, 1); gdk_event_handler_set ((GdkEventFunc) main_do_event, data, NULL); gtk_key_snooper_install (snoop_key_press, data); if (activate) acquire_grab (data, NULL); /* grab all */ /* TRAY ICON */ data->trayicon = app_indicator_new (PACKAGE_NAME, PACKAGE_NAME, APP_INDICATOR_CATEGORY_APPLICATION_STATUS); app_indicator_set_status (data->trayicon, APP_INDICATOR_STATUS_ACTIVE); /* create the menu */ GtkWidget *menu = gtk_menu_new (); /* Create the menu items */ GtkWidget* toggle_paint_item = gtk_menu_item_new_with_label ("Toggle Painting"); GtkWidget* clear_item = gtk_menu_item_new_with_label ("Clear Screen"); GtkWidget* toggle_vis_item = gtk_menu_item_new_with_label ("Toggle Visibility"); GtkWidget* thicker_lines_item = gtk_menu_item_new_with_label ("Thicker Lines"); GtkWidget* thinner_lines_item = gtk_menu_item_new_with_label ("Thinner Lines"); GtkWidget* opacity_bigger_item = gtk_menu_item_new_with_label ("Bigger Opacity"); GtkWidget* opacity_lesser_item = gtk_menu_item_new_with_label ("Lesser Opacity"); GtkWidget* undo_item = gtk_menu_item_new_with_label ("Undo"); GtkWidget* redo_item = gtk_menu_item_new_with_label ("Redo"); GtkWidget* sep_item = gtk_separator_menu_item_new(); GtkWidget* help_item = gtk_menu_item_new_with_mnemonic("_Help"); GtkWidget* about_item = gtk_menu_item_new_with_mnemonic("_About"); GtkWidget* quit_item = gtk_menu_item_new_with_mnemonic("_Quit"); /* 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); gtk_menu_shell_append (GTK_MENU_SHELL (menu), opacity_bigger_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), opacity_lesser_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), undo_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), redo_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), help_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), about_item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit_item); /* Attach the callback functions to the respective activate signal */ g_signal_connect(toggle_paint_item, "button-press-event", G_CALLBACK(on_toggle_paint), data); 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); g_signal_connect(G_OBJECT (opacity_bigger_item), "activate", G_CALLBACK (on_opacity_bigger), data); g_signal_connect(G_OBJECT (opacity_lesser_item), "activate", G_CALLBACK (on_opacity_lesser), data); g_signal_connect(G_OBJECT (undo_item), "activate", G_CALLBACK (on_undo), data); g_signal_connect(G_OBJECT (redo_item), "activate", G_CALLBACK (on_redo), data); g_signal_connect(G_OBJECT (help_item), "activate", G_CALLBACK (on_help), data); g_signal_connect(G_OBJECT (about_item), "activate", G_CALLBACK (on_about), NULL); g_signal_connect(G_OBJECT (quit_item), "activate", G_CALLBACK (gtk_main_quit), NULL); /* 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); gtk_widget_show (opacity_bigger_item); gtk_widget_show (opacity_lesser_item); gtk_widget_show (undo_item); gtk_widget_show (redo_item); gtk_widget_show (sep_item); gtk_widget_show (help_item); gtk_widget_show (about_item); gtk_widget_show (quit_item); app_indicator_set_menu (data->trayicon, GTK_MENU(menu)); } 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; data->undo_keyval = DEFAULT_UNDOKEY; data->undo_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 if (strcmp (arg, "-o") == 0 || strcmp (arg, "--opacity") == 0) { if (i+1 < argc && strtod (argv[i+1], NULL) >= 0.0 && strtod (argv[i+1], NULL) <= 1.0) { data->opacity = strtod (argv[i+1], NULL); g_printerr ("Opacity set to: %.2f\n", data->opacity); gtk_widget_set_opacity(data->win, data->opacity); i++; } else { g_printerr ("-o requires an opacity >= 0,0 && <=1,0 as argument\n"); wrong_arg = TRUE; } } else if (strcmp (arg, "-u") == 0 || strcmp (arg, "--undo-key") == 0) { if (i+1 < argc) { data->undo_keyval = argv[i+1]; data->undo_keycode = 0; i++; } else { g_printerr ("-u requires an Key-Name as argument\n"); wrong_arg = TRUE; } } else if (strcmp (arg, "-U") == 0 || strcmp (arg, "--undo-keycode") == 0) { if (i+1 < argc && atoi (argv[i+1]) > 0) { data->undo_keyval = NULL; data->undo_keycode = atoi (argv[i+1]); i++; } else { g_printerr ("-U 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 if (strcmp (arg, "-z") == 0 || strcmp (arg, "--undo") == 0) { action = GA_UNDO; } else if (strcmp (arg, "-y") == 0 || strcmp (arg, "--redo") == 0) { action = GA_REDO; } 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); data->opacity = DEFAULT_OPACITY; /* 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_widget_set_opacity(data->win, data->opacity); 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.2/src/gromit-mpx.h000066400000000000000000000123431301315152200165160ustar00rootroot00000000000000/* * 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_UNDO gdk_atom_intern ("Gromit/undo", FALSE) #define GA_REDO gdk_atom_intern ("Gromit/redo", FALSE) #define GA_DATA gdk_atom_intern ("Gromit/data", FALSE) #define GA_TOGGLEDATA gdk_atom_intern ("Gromit/toggledata", FALSE) #define GROMIT_MAX_UNDO 4 typedef enum { GROMIT_PEN, GROMIT_ERASER, GROMIT_RECOLOR } GromitPaintType; typedef struct { GromitPaintType type; guint width; gfloat arrowsize; guint minwidth; GdkRGBA *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; AppIndicator *trayicon; GdkCursor *paint_cursor; GdkCursor *erase_cursor; GdkDisplay *display; GdkScreen *screen; gboolean xinerama; gboolean composited; GdkWindow *root; gchar *hot_keyval; guint hot_keycode; gchar *undo_keyval; guint undo_keycode; gdouble opacity; GdkRGBA *white; GdkRGBA *black; GdkRGBA *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; cairo_surface_t *undobuffer[GROMIT_MAX_UNDO]; gint undo_head, undo_depth, redo_depth; } 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 copy_surface (cairo_surface_t *dst, cairo_surface_t *src); void swap_surfaces (cairo_surface_t *a, cairo_surface_t *b); void snap_undo_state (GromitData *data); void undo_drawing (GromitData *data); void redo_drawing (GromitData *data); 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, GdkRGBA *fg_color, guint width, guint arrowsize, guint minwidth); void paint_context_free (GromitPaintContext *context); #endif gromit-mpx-1.2/src/input.c000066400000000000000000000236021301315152200155450ustar00rootroot00000000000000 /* * Functions for setting up (parts of) the application */ #include #include #ifdef GDK_WINDOWING_X11 #include #include #endif #ifdef GDK_WINDOWING_WAYLAND #include #endif #include "input.h" void setup_input_devices (GromitData *data) { /* first, check platform */ gchar *backend; g_printerr("Supported backends: "); #ifdef GDK_WINDOWING_X11 g_printerr("x11 "); if (GDK_IS_X11_DISPLAY(data->display)) backend = "x11"; #endif #ifdef GDK_WINDOWING_WAYLAND g_printerr("wayland "); if (GDK_IS_WAYLAND_DISPLAY(data->display)) backend = "wayland"; #endif g_printerr("\nUsing backend: %s\n", backend); /* 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 || !data->undo_keycode) { g_printerr("ERROR: Grabbing hotkey from attached keyboard " "of '%s' failed, no hotkeys 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); if (GDK_IS_X11_DISPLAY(data->display)) { 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 hotkeys 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); XIGrabKeycode( GDK_DISPLAY_XDISPLAY(data->display), kbd_dev_id, data->undo_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; } } } // GDK_IS_X11_DISPLAY() 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)); } /* Key snooper */ gint snoop_key_press(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 toggle_grab(data, gdk_device_get_associated_device(dev)); return TRUE; } if (event->type == GDK_KEY_PRESS && event->hardware_keycode == data->undo_keycode) { if(data->debug) g_printerr("DEBUG: Received undokey press from device '%s'\n", gdk_device_get_name(dev)); if (data->hidden) return FALSE; if (event->state & GDK_SHIFT_MASK) redo_drawing (data); else undo_drawing (data); return TRUE; } return FALSE; } gromit-mpx-1.2/src/input.h000066400000000000000000000005521301315152200155510ustar00rootroot00000000000000 #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); gint snoop_key_press (GtkWidget *grab_widget, GdkEventKey *event, gpointer func_data); #endif gromit-mpx-1.2/src/paint_cursor.xpm000066400000000000000000000023371301315152200175020ustar00rootroot00000000000000/* 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", " . ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " + ", " ", " ", " ", " ", "......... ......... ", " ++++++++ +++++++++ ", " ", " ", " ", " ", " ", " . ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " .+ ", " + ", " "};