dockapps/000077500000000000000000000000001243437315700126735ustar00rootroot00000000000000dockapps/AUTHORS000066400000000000000000000006421243437315700137450ustar00rootroot00000000000000Michal Krause wrote wmcliphist Daniel Richard G. made icon set used from version 0.5 Michael Beattie wrote new exec actions handling (introduced in version 0.6) Vadim O. Ustiansky wrote patch allowing wmcliphist window of size 1px and second patch allowing to confirm actions by keyboard. Samuli Suominen created patches to make wmcliphist compatble with GTK+ 2.x and higher Alexey Vyskubov wrote foodock library dockapps/COPYING000066400000000000000000000431101243437315700137250ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 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 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) 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 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) year 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. dockapps/ChangeLog000066400000000000000000000066001243437315700144470ustar00rootroot0000000000000022/11/2014: v2.1 - Migrate to GTK3, removing foodock library in the process. - Add manpage from Debian. - Add -b command line option to select which clipboard to manage. - Now maintained by Window Maker Developers team . 21/03/2009: v2.0 - Gentoo patches by Samuli Suominen integrated (http://sources.gentoo.org/viewcvs.py/gentoo-x86/x11-plugins/wmcliphist/files/) 26/06/2005: v1.0 - confirmation dialogs supports Enter (Yes) and Esc (No) keys (Vadim O. Ustiansky) - wmcliphist now can run with almost invisible window (-s 0) which is usable on systems running windows manager without docking capabilities (Vadim O. Ustiansky) - some debug messages was removed, minor code tweaking and auto_take_up feature is now DISABLED by default due to problems with some GTK 2.x based applications 24/08/2003: v0.6 - exec actions can be performed automatically or on demand by middle mouse button click on menu item or by hot key for last captured item (Michael Beattie) - wmcliphist can automatically take up clipboard content allowing to paste it when application who copied it ended already 23/06/2003: v0.5 - brand new icon set made by Daniel Richard G. - icon size (60, 40, 30 or 16 pixels) selectable on command line - minor fixes and enhacements in Makefiles (suggested by Sebastian Ley) 04/06/2003: v0.4 - first version containing spec for building RPMs (Daniel Tschan ) - fixed locale and zombie bugs (Victor Cheburkin ) - wmcliphist now starts without .wmcliphistrc (Sebastian Ley ) - permissions of .wmcliphist.data are more secure now (Kresimir Kukulj ) - fixed buffer overrun bug in reading history (Simon 'corecode' Schubert ) - keyboard navigation in history menu is possible now - icons with antialiasing against dark, mid and light background are now compiled into wmcliphist and it can be choosen on command line (-i) - wmcliphist can optionaly ask before performing of exec action (suggested by Ivica Letunic ) - added hotkey which returns previously captured item back to clipboard. It can safe some keystrokes or mouse clicks in some situation, escpecially if you need clear destination before pasting to it and selecting of its content replaces your data in the clipboard 02/15/2002: v0.3 - code fully reorganized - new configuration file ~/.wmcliphistrc (clipboard history is now stored in ~/.wmcliphist.data) - added hotkey support (pop up menu at mouse cursor position) - added regular expression driven actions (ignore/submenu/exec) - new function Clipboard lock (new selection will not replace currently selected item in clipboard, but it will be stored in history) - new function Clipboard ignore (completely ignore new selections - they will not replace selected item and will not be stored in history) - new function to save history immediately - wmcliphist can autosave history in specified period - new icon 03/24/2001: v0.2 - hopefully fixed terrible memory leak - added items locking function (right click on item) and command line option for setting color of locked items - picked item will move to begining - removed dependency on getopt and wordexp 02/23/2001: v0.1 - initial release dockapps/INSTALL000066400000000000000000000000511243437315700137200ustar00rootroot00000000000000See README for installation instructions dockapps/Makefile000066400000000000000000000030611243437315700143330ustar00rootroot00000000000000srcCC ?= gcc INSTALL = install PREFIX = /usr/local BINDIR = $(PREFIX)/bin DATADIR = $(PREFIX)/share/wmcliphist MAN1DIR = $(PREFIX)/share/man/man1 INCLUDES = `pkg-config --cflags gtk+-3.0 x11` # for normal use CFLAGS += -Wall -ansi -pedantic $(INCLUDES) -DDATADIR=\"$(DATADIR)\" DEBUG = # for debuggind purposes # ISO doesn't support macros with variable number of arguments so -pedantic # must not be used #CFLAGS += -Wall -g -ansi $(INCLUDES) -DFNCALL_DEBUG #DEBUG = debug.o LIBS = `pkg-config --libs gtk+-3.0 x11` OBJECTS = wmcliphist.o clipboard.o gui.o rcconfig.o history.o hotkeys.o utils.o $(DEBUG) TARGET = wmcliphist ICONS = icon/ico_16x16.png icon/ico_30x30_black.png icon/ico_30x30_gray.png \ icon/ico_30x30_white.png icon/ico_40x40_black.png \ icon/ico_40x40_gray.png icon/ico_40x40_white.png \ icon/ico_60x60_black.png icon/ico_60x60_gray.png \ icon/ico_60x60_white.png all: $(TARGET) lclint: lclint $(INCLUDES) +posixlib *.c >lclint.log wmcliphist: $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@ wmcliphist.o: wmcliphist.c wmcliphist.h clipboard.o: clipboard.c wmcliphist.h rcconfig.o: rcconfig.c wmcliphist.h gui.o: gui.c wmcliphist.h history.o: history.c wmcliphist.h hotkeys.o: hotkeys.c wmcliphist.h utils.o: utils.c wmcliphist.h clean: rm -rf $(OBJECTS) $(TARGET) rm -rf core install: $(INSTALL) -d $(DESTDIR)$(DATADIR) $(INSTALL) -m 644 $(ICONS) $(DESTDIR)$(DATADIR) $(INSTALL) -d $(DESTDIR)$(BINDIR) $(INSTALL) $(TARGET) $(DESTDIR)$(BINDIR) $(INSTALL) -d $(DESTDIR)$(MAN1DIR) $(INSTALL) -m 644 wmcliphist.1 $(DESTDIR)$(MAN1DIR) dockapps/NEWS000066400000000000000000000003271243437315700133740ustar00rootroot0000000000000011/22/2014: v2.1 released 09/09/2004: v1.0 released 08/24/2003: v0.6 released 06/23/2003: v0.5 released 06/04/2003: v0.4 released 02/15/2002: v0.3 released 03/24/2001: v0.2 released 02/23/2001: v0.1 released dockapps/README000066400000000000000000000101671243437315700135600ustar00rootroot00000000000000Copying ------- 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. What is it? ----------- In short, it is clipboard history dockable application for Window Maker (and maybe AfterStep with some little modifications - not tested). wmcliphist keeps history of clipboard operations and allows you to put previously copied items back to clipboard for pasting to other applications. I wrote wmcliphist because there was no such application suitable for usage in Window Maker and I was confused to run number of KDE daemons for Klipper (which was the inspiration). Features -------- * selectable number of items to keep * detachable (tear off) menu with clipboard history * possibility to lock item (locked items will not be overriden by new clipboard operations). To lock item press right mouse button on it. * saves history to file on exit (and loads it on start, of course :), periodicaly and/or on request * can handle binary data * configurable hotkey support (pop up menu at mouse cursor position) * regular expression driven actions (ignore/submenu/exec) * possibility to lock clipboard (new selections will not replace the current one and it could not be stored in history too) Instalation ----------- wmcliphist requires gtk+ and glib (fully tested only with 1.2.8 and 1.2.10, but probably will work with any 1.2.x version) and foodock library for writing dockable applications based on gtk+ (included). Hopefuly you'll only need to run make all install to compile and install wmcliphist. Note that you have to be root to install program to /usr/local/bin (default). If it fails, check, that you have installed gtk+, gtk+-devel, glib and glib-devel packages, make and compiler (gcc). If it still fails, try to upgrade to up to date versions of libraries listed above (see www.gtk.org). wmcliphist was tested only on Linux (Red Hat Linux 7.2, kernel 2.4.9, gcc 2.96), but it should compile and run on other un*x systems too. After installing binary you can create your configuration file in ~/.wmcliphistrc (sample config file wmcliphistrc is included in distribution archive). Upgrading Please note, that upgrade from version 0.1 will delete your old history! If you are upgrading from version 0.2 to 0.3, move your ~/.wmcliphistrc to ~/.wmcliphist.data and create new ~/.wmcliphistrc with configuration (sample config file is included). Usage ----- wmcliphist accepts followinf options: -h show help -n set number of items to keep (default 10) -c color set color for locked items (default is red) -s choose wmcliphist icon size: 16 = tiny 16x16 px icon 30 = icon suitable for 32px dock/slit 40 = icon suitable for 48px dock/slit 60 = icon suitable for 64px dock/slit (default) -i choose wmcliphist icon antialiasing: 0 = for mid tones background (default) 1 = for dark background 2 = for light background Example: /usr/local/bin/wmcliphist -n 15 -c darkgreen Some of theese options and many others can be set in ~/.wmcliphistrc too. Left click on icon opens menu with history and right click opens application menu. Right click on history menu item will lock it. History menu can be opened at mouse cursor position with configurable hotkey too. ToDo ---- * Maybe some configuration GUI? Who knows... * Separated history queues Credits ------- Michal Krause Daniel Richard G. (icon set used from version 0.5) Michael Beattie (new exec action handling in 0.6) Vadim O. Ustiansky (some improvements in 0.7) Special thanx ------------- Alexey Vyskubov, foodock library Downloader for X, from which I took inspiration for clipboard monitoring. BTW, it's great peace of software, try it. Download -------- http://linux.nawebu.cz/wmcliphist/ Apology ------- I'd like to apologize to all English speaking people for mangling of their mother tongue :) dockapps/clipboard.c000066400000000000000000000106151243437315700150010ustar00rootroot00000000000000#include "wmcliphist.h" #include /* when true, clipboard will be automatically taken up by wmcliphist */ gint auto_take_up = 0; /* number of items to keep (may be overriden from command line) */ gint num_items_to_keep = 10; /* number if items kept */ gint num_items = 0; /* current number of locked items */ gint locked_count; /* list of clipboard history items */ GList *history_items = NULL; /* selected item */ HISTORY_ITEM *selected = NULL; /* * dumps history list to stderr * for debugging purposes only */ void dump_history_list_fn(char *header) { gint indent = 1, i; GList *node = history_items; HISTORY_ITEM *data; gchar *converted; fprintf(stderr, "%s\n", header); while (node) { data = (HISTORY_ITEM *)node->data; for (i = 0; i < indent; i++) putc('-', stderr); converted = from_utf8(data->content); fprintf(stderr, " %s\n", converted); g_free(converted); indent++; node = node->next; } fprintf(stderr, "==========\n"); } void my_get_selection_text(GtkClipboard *cb, const gchar *text, gpointer data) { /* previous clipboard content */ static gchar *old_content = ""; static gint has_old_content = 0; gchar *content; gchar *converted; begin_func("my_get_selection_text"); if (text == NULL) { return_void(); } if (g_utf8_collate(text, old_content) != 0 && !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_app_clip_ignore))) { /* new data in clipboard */ /* store new content for future comparation */ content = g_strdup(text); converted = from_utf8(content); /* fprintf(stderr, ">>> %s\n", converted); */ g_free(converted); if (has_old_content > 0) g_free(old_content); old_content = content; has_old_content = 1; /* process item */ process_item(content, 0, TRUE); } /* when clipboard is locked, set selection owener to myself */ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_app_clip_ignore)) || gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_app_clip_lock))) { if (gtk_selection_owner_set(dock_app, clipboard, GDK_CURRENT_TIME) == 0) selected = NULL; } return_void(); } /* * get clipboard content - partialy inspired by Downloader for X */ gboolean my_get_xselection(GtkWidget *window, GdkEvent *event) { GdkAtom atom; gint format; size_t length; gchar *content = NULL; /* previous clipboard content */ static size_t old_content_len = 0; static gchar *old_content = ""; begin_func("my_get_xselection"); gtk_clipboard_request_text(gtk_clipboard_get(clipboard), my_get_selection_text, NULL); return_val(TRUE); length = (size_t) gdk_selection_property_get(gtk_widget_get_window(window), (guchar **) &content, &atom, &format); if (length > 0) { if ((length != old_content_len || memcmp(content, old_content, length) != 0) && !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_app_clip_ignore))) { /* new data in clipboard */ /* store new content for future comparation */ if (old_content_len > 0) g_free(old_content); old_content = content; old_content_len = length; /* process item */ /* process_item(content, length, 0, TRUE); */ } else { /* no new data */ g_free(content); } /* when clipboard is locked, set selection owener to myself */ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_app_clip_ignore)) || gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_app_clip_lock))) { if (gtk_selection_owner_set(dock_app, clipboard, GDK_CURRENT_TIME) == 0) selected = NULL; } } return_val(TRUE); } /* * clipboard conversion - inspired by Downloader for X too :) */ gboolean time_conv_select() { begin_func("time_conv_select"); gtk_selection_convert(main_window, clipboard, GDK_TARGET_STRING, GDK_CURRENT_TIME); return_val(TRUE); } /* * handles request for selection from other apps */ gboolean selection_handle(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time_stamp, gpointer data) { static gchar *converted = NULL; begin_func("selection_handle"); if (converted != NULL) { g_free(converted); } if (selected) { converted = from_utf8(selected->content); gtk_selection_data_set(selection_data, GDK_SELECTION_TYPE_STRING, 8, (guchar *) converted, strlen(converted)); } else { gtk_selection_data_set(selection_data, GDK_SELECTION_TYPE_STRING, 8, (guchar *)"", 0); } return_val(TRUE); } dockapps/debug.c000066400000000000000000000031251243437315700141260ustar00rootroot00000000000000#include #include #include #include #include /* tabulators */ char tabs[1024]; #ifdef DBG_THREADS #include static pthread_key_t align_key; static pthread_once_t align_key_once = PTHREAD_ONCE_INIT; static void align_destroy(void *align) { free(align); } static void align_key_create() { pthread_key_create(&align_key, align_destroy); } void debug_init_threads() { int *new_align; memset(tabs, 9, 1024); if (!(new_align = malloc(sizeof(int)))) abort(); *new_align = 1; pthread_once(&align_key_once, align_key_create); pthread_setspecific(align_key, new_align); } #endif /* * no threads */ static int main_align = 1; void debug_init_nothreads() { memset(tabs, 9, 1024); } void fn_begin(char *format, ...) { va_list args; char msg_buf[1024]; char final_msg[2048]; int *align; #ifdef DBG_THREADS align = pthread_getspecific(align_key); #else align = &main_align; #endif va_start(args, format); vsprintf(msg_buf, format, args); va_end(args); strcat(msg_buf, " {\n"); sprintf(final_msg, "%d: %.*s%s", getpid(), *align, tabs, msg_buf); fprintf(stderr, "%s", final_msg); (*align)++; } void fn_end() { int *align; #ifdef DBG_THREADS align = pthread_getspecific(align_key); #else align = &main_align; #endif (*align)--; fprintf(stderr, "%d: %.*s}\n", getpid(), *align, tabs); } /* void fn2(int i) { _D(fn_begin("fn2(i = %d)", i)); return_void(); } int fn1() { _D(fn_begin("fn1")); fn2(1); return_val(0); } int main() { _D(fn_begin("main")); fn1(); fn2(2); return_val(0); } */ dockapps/debug.h000066400000000000000000000013151243437315700141320ustar00rootroot00000000000000#ifndef _DEBUG_H_ #define _DEBUG_H_ #ifdef DBG_THREADS #define debug_init() debug_init_threads() #else #define debug_init() debug_init_nothreads() #endif void debug_init_threads(); void debug_init_nothreads(); void fn_begin(char *format, ...); void fn_end(); #ifdef FNCALL_DEBUG /* define macros with debugging on */ #define begin_func(_format, _args...) fn_begin(_format , ##_args) #define return_val(_value) \ do { \ fn_end(); \ return _value; \ } while (0) #define return_void() \ do { \ fn_end(); \ return; \ } while (0) #else /* define macros with debugging off */ #define begin_func(_format) #define return_val(_value) return _value #define return_void() return #endif #endif dockapps/gui.c000066400000000000000000000247641243437315700136400ustar00rootroot00000000000000#include "wmcliphist.h" #include /* color of locked item */ gchar locked_color_str[32] = DEF_LOCKED_COLOR; GdkRGBA locked_color; /* Exec on middle click? */ int exec_middleclick = 1; /* main window widget */ GtkWidget *main_window; /* dock icon widget */ GtkWidget *dock_app; /* clipboard history menu */ GtkWidget *menu_hist; GtkWidget *menu_title; gint submenu_count = 0; /* application menu */ GtkWidget *menu_app; GtkWidget *menu_app_clip_lock; GtkWidget *menu_app_clip_ignore; GtkWidget *menu_app_exit; GtkWidget *menu_app_save; /* button */ GtkWidget *button; /* pixmap */ GtkWidget *pixmap; /* which clipboard to use */ gchar clipboard_str[32] = DEF_CLIPBOARD_STR; GdkAtom clipboard; /* ========================================================================== * clipboard history menu */ /* * history menu item button click function */ static gboolean menu_item_button_released(GtkWidget *widget, GdkEvent *event, gpointer user_data) { GdkEventButton *bevent = (GdkEventButton *)event; HISTORY_ITEM *data = user_data; begin_func("menu_item_button_released"); /* button 2 or 3 - exec or (un)lock item respectively */ if (bevent->button == 2) { if (exec_middleclick) { gtk_menu_popdown(GTK_MENU(menu_hist)); exec_item(data->content, NULL); } return_val(TRUE); } else if (bevent->button == 3) { if (data->locked == 0) { /* cannot lock all records */ if (locked_count == num_items_to_keep - 1) { show_message("There must remain at least one " "unlocked item\nwhen menu is full!", "Warning", "OK", NULL, NULL); return_val(TRUE); } gtk_widget_override_color( gtk_bin_get_child(GTK_BIN(data->menu_item)), GTK_STATE_FLAG_NORMAL, &locked_color); data->locked = 1; locked_count++; } else { gtk_widget_override_color( gtk_bin_get_child(GTK_BIN(data->menu_item)), GTK_STATE_FLAG_NORMAL, NULL); data->locked = 0; locked_count--; } } else { return_val(FALSE); } return_val(TRUE); } /* * history menu item left click or keypress function */ static gboolean menu_item_activated(GtkWidget *widget, gpointer user_data) { move_item_to_begin((HISTORY_ITEM *) user_data); return_val(TRUE); } /* * checks, if there is already such item in menu, * in which case it moves it to the begining */ HISTORY_ITEM * menu_item_exists(gchar *content, GtkWidget *submenu) { HISTORY_ITEM *hist_item; GList *list_node; begin_func("menu_item_exists"); list_node = g_list_last(history_items); while (list_node) { hist_item = (HISTORY_ITEM *)list_node->data; if (hist_item->menu == submenu && g_utf8_collate(hist_item->content, content) == 0) { gtk_menu_reorder_child(GTK_MENU(hist_item->menu), hist_item->menu_item, 1); history_items = g_list_remove_link(history_items, list_node); history_items = g_list_concat(list_node, history_items); return_val(hist_item); } list_node = g_list_previous(list_node); } return_val(NULL); } /* * add new item to menu */ HISTORY_ITEM * menu_item_add(gchar *content, gint locked, GtkWidget *target_menu) { GList *list_node; gint i; gchar *menu_item_name; gchar *fixed_menu_item_name; gsize length; HISTORY_ITEM *hist_item; begin_func("menu_item_add"); hist_item = menu_item_exists(content, target_menu); if (hist_item != NULL) { dump_history_list("reorder"); return_val(hist_item); } if (num_items == num_items_to_keep) { /* max item limit reached, destroy oldest one */ list_node = g_list_last(history_items); while (1) { hist_item = (HISTORY_ITEM*) list_node->data; if (hist_item->locked == 0) break; list_node = g_list_previous(list_node); g_assert((list_node != NULL)); } history_items = g_list_remove_link(history_items, list_node); gtk_container_remove(GTK_CONTAINER(hist_item->menu), hist_item->menu_item); gtk_widget_destroy(hist_item->menu_item); g_free(hist_item->content); g_free(hist_item); g_list_free_1(list_node); num_items--; dump_history_list("remove oldest"); } /* prepare menu item name */ menu_item_name = g_new0(char, MAX_ITEM_LENGTH * 2 + 1); memset(menu_item_name, 0, MAX_ITEM_LENGTH * 2 + 1); length = g_utf8_strlen(content, -1); if (length > (size_t) (MAX_ITEM_LENGTH)) { g_utf8_strncpy(menu_item_name, content, MAX_ITEM_LENGTH - 4); strcat(menu_item_name, "..."); } else { strcpy(menu_item_name, content); } /* do some menu item name cleanups */ fixed_menu_item_name = g_new0(char, strlen(menu_item_name) + 1); for (i = 0; i < g_utf8_strlen(menu_item_name, -1); i++) { gchar *uchar_ptr = g_utf8_offset_to_pointer(menu_item_name, i); gunichar uchar = g_utf8_get_char(uchar_ptr); if (g_unichar_isprint(uchar)) { gchar *decoded_char = g_ucs4_to_utf8(&uchar, 1, NULL, NULL, NULL); strcat(fixed_menu_item_name, decoded_char); g_free(decoded_char); } else { strcat(fixed_menu_item_name, "_"); } } g_free(menu_item_name); menu_item_name = fixed_menu_item_name; /* create menu item */ hist_item = g_new0(HISTORY_ITEM, 1); hist_item->menu_item = gtk_menu_item_new_with_label(menu_item_name); hist_item->content = g_strdup(content); hist_item->locked = locked; hist_item->menu = target_menu; if (locked == 1) { gtk_widget_override_color( gtk_bin_get_child(GTK_BIN(hist_item->menu_item)), GTK_STATE_FLAG_NORMAL, &locked_color); locked_count++; } /* add to menu */ gtk_menu_shell_insert(GTK_MENU_SHELL(hist_item->menu), hist_item->menu_item, 1); /* connect actions to signals */ g_signal_connect(G_OBJECT(hist_item->menu_item), "button-release-event", G_CALLBACK(menu_item_button_released), (gpointer)hist_item); g_signal_connect(G_OBJECT(hist_item->menu_item), "activate", G_CALLBACK(menu_item_activated), (gpointer)hist_item); gtk_widget_show(hist_item->menu_item); history_items = g_list_insert(history_items, hist_item, 0); num_items++; return_val(hist_item); } /* ========================================================================== * application menu */ /* * application main menu handler */ gboolean menu_app_item_click(GtkWidget *menuitem, gpointer data) { gint button; begin_func("menu_app_item_click"); switch (GPOINTER_TO_INT(data)) { /* save history menu */ case 0: if (history_save() != 0) { button = show_message("History was NOT saved.\n", "Warning", "OK", NULL, NULL); } return_val(TRUE); /* exit menu */ case 1: if (history_save() != 0) { button = show_message("History was NOT saved.\n" "Do you really want to exit?", "Error", "Yes", "No", NULL); if (button != 0) return_val(TRUE); } history_free(); rcconfig_free(); exit(0); return_val(TRUE); } return_val(FALSE); } /* ========================================================================== * dock button press */ /* * dock button click response */ gboolean button_press(GtkWidget *widget, GdkEvent *event, gpointer data) { begin_func("button_press"); if (event->type == GDK_BUTTON_PRESS) { GdkEventButton *bevent = (GdkEventButton *)event; switch (bevent->button) { case 1: /* popup history menu */ gtk_menu_popup(GTK_MENU(menu_hist), NULL, NULL, NULL, NULL, bevent->button, bevent->time); return_val(TRUE); case 3: /* popup application menu */ gtk_menu_popup(GTK_MENU(menu_app), NULL, NULL, NULL, NULL, bevent->button, bevent->time); return_val(TRUE); } } return_val(FALSE); } /* ========================================================================== * message dialogs */ static GMainLoop *loop; static gint button_pressed; static gboolean dialog_button_press(GtkWidget *button, gpointer data) { begin_func("dialog_button_press"); button_pressed = GPOINTER_TO_INT(data); g_main_quit(loop); return_val(TRUE); } static gboolean dialog_handle_key_press_event(GdkEventKey *event, gpointer data, guint key) { if(event->type != GDK_KEY_PRESS) return_val(FALSE); if(event->keyval != key) return_val(FALSE); button_pressed = GPOINTER_TO_INT(data); g_main_quit(loop); return_val(TRUE); } static gboolean dialog_key_press_yes(GtkWidget *button, GdkEventKey *event, gpointer data) { begin_func("dialog_key_press_yes"); return dialog_handle_key_press_event(event, data, GDK_KEY_Return); } static gboolean dialog_key_press_no(GtkWidget *button, GdkEventKey *event, gpointer data) { begin_func("dialog_key_press_no"); return dialog_handle_key_press_event(event, data, GDK_KEY_Escape); } /* * open dialog with specified message andbuttons * and return number of button pressed */ gint show_message(gchar *message, char *title, char *b0_text, char *b1_text, char *b2_text) { GtkWidget *dialog, *label, *button_0, *button_1, *button_2; begin_func("show_message"); /* create the main widgets */ dialog = gtk_dialog_new(); label = gtk_label_new(message); /* create buttons and set signals */ gtk_dialog_add_button(GTK_DIALOG(dialog), b0_text, 0); button_0 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 0); g_signal_connect(G_OBJECT(button_0), "clicked", G_CALLBACK(dialog_button_press), GINT_TO_POINTER(0)); if (!b2_text) { g_signal_connect(G_OBJECT(dialog), "key-press-event", G_CALLBACK(dialog_key_press_yes), GINT_TO_POINTER(0)); } if (b1_text != NULL) { gtk_dialog_add_button(GTK_DIALOG(dialog), b1_text, 1); button_1 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 1); g_signal_connect(G_OBJECT(button_1), "clicked", G_CALLBACK(dialog_button_press), GINT_TO_POINTER(1)); if (!b2_text) { g_signal_connect(G_OBJECT(dialog), "key-press-event", G_CALLBACK(dialog_key_press_no), GINT_TO_POINTER(1)); } } if (b2_text) { gtk_dialog_add_button(GTK_DIALOG(dialog), b2_text, 2); button_2 = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), 2); g_signal_connect(G_OBJECT(button_2), "clicked", G_CALLBACK(dialog_button_press), GINT_TO_POINTER(2)); } /* add the label, and show everything we've added to the dialog. */ gtk_misc_set_padding(>K_LABEL(label)->misc, 10, 10); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label); gtk_widget_show_all(dialog); /* set window title */ gtk_window_set_title(GTK_WINDOW(dialog), title); loop = g_main_new(FALSE); g_main_run(loop); g_main_destroy(loop); gtk_widget_destroy(dialog); return_val(button_pressed); } dockapps/history.c000066400000000000000000000162361243437315700145500ustar00rootroot00000000000000#include "wmcliphist.h" int autosave_period = 120; int confirm_exec = 0; int exec_immediately = 1; /* * process new history item */ void process_item(char *content, gint locked, gboolean exec) { GList *list_node; ACTION *action; gboolean processed = FALSE; HISTORY_ITEM *hist_item; begin_func("process_item"); list_node = g_list_first(action_list); while (list_node) { action = (ACTION *)list_node->data; /* check if some action is requested */ if (regexec(&action->expression, content, 0, NULL, 0) != 0) { list_node = g_list_next(list_node); continue; } /* match - execute requested action */ if (action->action == ACT_IGNORE) { processed = TRUE; break; } if (action->action == ACT_EXEC && exec_immediately == TRUE && exec == TRUE) { exec_item(content, action); } if (action->action == ACT_SUBMENU) { /* test if such item already exists in this menu */ processed = TRUE; /* add item to menu and item list */ hist_item = menu_item_add(content, locked, action->submenu); /* when auto_take_up is true, set selection owner to myself */ if (auto_take_up == 1) { selected = hist_item; if (gtk_selection_owner_set(dock_app, clipboard, GDK_CURRENT_TIME) == 0) { selected = NULL; } } dump_history_list("added item"); break; } list_node = g_list_next(list_node); } if (processed == FALSE) { hist_item = menu_item_add(content, locked, menu_hist); /* when auto_take_up is true, set selection owner to myself */ if (auto_take_up == 1) { selected = hist_item; if (gtk_selection_owner_set(dock_app, clipboard, GDK_CURRENT_TIME) == 0) { selected = NULL; } } } return_void(); } void move_item_to_begin(HISTORY_ITEM *item) { GList *list_node; begin_func("menu_item_activated"); if (!(list_node = g_list_find(history_items, item))) { g_assert((list_node != NULL)); } gtk_menu_popdown(GTK_MENU(menu_hist)); /* move previously stored item to beginning */ gtk_menu_reorder_child(GTK_MENU(item->menu), item->menu_item, 1); history_items = g_list_remove_link(history_items, list_node); history_items = g_list_concat(list_node, history_items); selected = item; if (gtk_selection_owner_set(dock_app, clipboard, GDK_CURRENT_TIME) == 0) selected = NULL; } /* * Exec's an action on item. */ void exec_item(char *content, ACTION *action) { int msg_result = 0, res; gchar *msg_buf; gchar *exec_buf; gchar *converted; converted = from_utf8(content); /* If we're not given an action to perform, find the first matching * exec action, and perform it */ if (!action) { GList *list_node; ACTION *a; list_node = g_list_first(action_list); while (list_node) { a = (ACTION *)list_node->data; /* check if some action is requested */ if ((regexec(&a->expression, converted, 0, NULL, 0) == 0) && (a->action == ACT_EXEC)) { action = a; break; } list_node = g_list_next(list_node); } } if (!action || action->action != ACT_EXEC) { g_free(converted); return; } exec_buf = g_new0(char, strlen(converted) + strlen(action->command) + 1); sprintf(exec_buf, action->command, converted); if (confirm_exec) { msg_buf = g_new0(char, strlen(exec_buf) + 256); sprintf(msg_buf, "Do you want to perform the " "following action?\n\n%s", exec_buf); msg_result = show_message(msg_buf, "wmcliphist", "Yes", "No", NULL); g_free(msg_buf); } /* create child and exec command */ if (msg_result == 0 && fork() == 0) { /* child */ res = system(exec_buf); if (res == -1) fprintf(stderr, "Cannot exec '%s'\n", exec_buf); else if (res == 127) fprintf(stderr, "/bin/sh not found\n"); g_free(exec_buf); g_free(converted); _exit(0); } else { /* parent */ g_free(exec_buf); g_free(converted); } } /* * loads history from file */ int history_load(gboolean dump_only) { gchar *buf; gint len; gint ver; FILE *f; gchar *fname; gint locked; int tmp_errno = 0; begin_func("history_load"); fname = rcconfig_get_name(".data"); if (!(f = fopen(fname, "r"))) { errno = E_OPEN; return_val(-1); } if (fread(&ver, sizeof(gint), 1, f) != 1) { fclose(f); return_val(0); } /* delete old history file */ if (ver == 0x0001) { fclose(f); if (remove(rcconfig_get_name(".data"))) { errno = E_REMOVE; return_val(-1); } return_val(0); } if (dump_only) { printf("\n"); } while (!feof(f)) { if (fread(&len, sizeof(gint), 1, f) != 1) break; if (num_items == num_items_to_keep && !dump_only) { tmp_errno = E_TOO_MUCH; break; } buf = g_new0(gchar, len + 1); if (fread(buf, len, 1, f) != 1) { g_free(buf); tmp_errno = E_INVALID; break; } buf[len] = '\0'; if (fread(&locked, sizeof(gint), 1, f) != 1) { g_free(buf); tmp_errno = E_INVALID; break; } if (dump_only) { printf("%s\n", buf); } else { process_item(buf, locked, FALSE); } g_free(buf); } fclose(f); if (dump_only) { printf("\n"); } else { dump_history_list("load_history()"); } errno = tmp_errno; if (errno == 0) return_val(0); else return_val(-1); } /* * store history to file */ int history_save() { char *fname; gint version = VERSION; FILE *f; HISTORY_ITEM *hist_item; GList *list_node; int tmp_errno = 0; begin_func("history_save"); fname = g_strdup(rcconfig_get_name(".data.tmp")); if (!(f = fopen(fname, "w"))) { perror("fopen"); g_free(fname); errno = E_OPEN; return_val(-1); } if ((chmod(fname, S_IRUSR|S_IWUSR)) != 0) { perror("chmod"); fclose(f); unlink(fname); g_free(fname); errno = E_OPEN; return_val(-1); } if (fwrite(&version, sizeof(gint), 1, f) != 1) { perror("fwrite version"); fclose(f); unlink(fname); g_free(fname); errno = E_WRITE; return_val(-1); } list_node = g_list_last(history_items); while (list_node) { int length; hist_item = (HISTORY_ITEM *)list_node->data; length = strlen(hist_item->content); if (fwrite(&length, sizeof(gint), 1, f) != 1) { tmp_errno = E_WRITE; break; } if (fwrite(hist_item->content, length, 1, f) != 1) { tmp_errno = E_WRITE; break; } if (fwrite(&hist_item->locked, sizeof(gint), 1, f) != 1) { tmp_errno = E_WRITE; break; } list_node = g_list_previous(list_node); } fclose(f); if (!list_node) { if (rename(fname, rcconfig_get_name(".data")) != 0) { perror("rename"); unlink(fname); g_free(fname); errno = E_RENAME; return_val(-1); } g_free(fname); return_val(0); } errno = tmp_errno; unlink(fname); g_free(fname); return_val(-1); } /* * free history data */ void history_free() { HISTORY_ITEM *hist_item; GList *list_node; begin_func("history_free"); list_node = g_list_last(history_items); while (list_node) { hist_item = (HISTORY_ITEM *)list_node->data; gtk_container_remove(GTK_CONTAINER(hist_item->menu), hist_item->menu_item); gtk_widget_destroy(hist_item->menu_item); g_free(hist_item->content); g_free(hist_item); list_node = g_list_previous(list_node); } g_list_free(history_items); return_void(); } /* * autosave timer function */ gboolean history_autosave() { begin_func("history_autosave"); history_save(); return_val(TRUE); } dockapps/hotkeys.c000066400000000000000000000134101243437315700145240ustar00rootroot00000000000000#include "wmcliphist.h" #include /* Exec on hotkey? */ int exec_hotkey = 1; /* hotkeys */ gchar menukey_str[32] = DEF_MENUKEY; guint menukey; guint menukey_mask; gchar prev_item_key_str[32] = DEF_PREV_ITEM_KEY; guint prev_item_key; guint prev_item_mask; gchar exec_item_key_str[32] = DEF_EXEC_ITEM_KEY; guint exec_item_key; guint exec_item_mask; /* * filter grabbed hotkeys */ GdkFilterReturn global_keys_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { XEvent *xevent = (XEvent *)gdk_xevent; begin_func("global_keys_filter"); if (xevent->type == KeyPress) { if (xevent->xkey.keycode == XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), menukey) && xevent->xkey.state & menukey_mask) { /* popup history menu */ gtk_menu_popup(GTK_MENU(menu_hist), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); return_val(GDK_FILTER_REMOVE); } else if (xevent->xkey.keycode == XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), prev_item_key) && xevent->xkey.state & prev_item_mask) { /* switch first two history items */ GList *second; if (history_items == NULL) { return_val(GDK_FILTER_REMOVE); } second = g_list_first(history_items)->next; if (second == NULL) { return_val(GDK_FILTER_REMOVE); } move_item_to_begin((HISTORY_ITEM *) second->data); return_val(GDK_FILTER_REMOVE); } else if (xevent->xkey.keycode == XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), exec_item_key) && xevent->xkey.state & exec_item_mask) { /* exec command on current item */ if (exec_hotkey) { HISTORY_ITEM *hist_item; hist_item = (HISTORY_ITEM *) g_list_first(history_items)->data; exec_item(hist_item->content, NULL); } return_val(GDK_FILTER_REMOVE); } } return_val(GDK_FILTER_CONTINUE); } /* * parse key string */ int hotkey_parse(char *hotkey, guint *key, guint *mask) { char c; char *tmp = g_new0(char, strlen(hotkey)); int i, idx = 0; begin_func("hotkey_parse"); *mask = 0; for (i = 0; i < strlen(hotkey); i++) { c = hotkey[i]; if (isalpha(c)) { tmp[idx++] = c; tmp[idx] = '\0'; } else if (c == '+' || c == '-') { idx = 0; if (strcasecmp(tmp, "control") == 0 || strcasecmp(tmp, "ctrl") == 0) *mask |= ControlMask; else if (strcasecmp(tmp, "alt") == 0) *mask |= Mod1Mask; else if (strcasecmp(tmp, "shift") == 0) *mask |= ShiftMask; else { fprintf(stderr, "Invalid key modifier: %s\n", tmp); g_free(tmp); return_val(-1); } } } if ((*key = gdk_keyval_from_name(tmp)) == GDK_KEY_VoidSymbol) { g_free(tmp); return_val(-1); } g_free(tmp); return_val(0); } #define grab_key(keysym, basemask) \ XGrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask, GDK_ROOT_WINDOW(), True, GrabModeAsync, \ GrabModeAsync); \ XGrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask | LockMask, GDK_ROOT_WINDOW(), True, \ GrabModeAsync, GrabModeAsync); \ XGrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask | Mod2Mask, GDK_ROOT_WINDOW(), True, \ GrabModeAsync, GrabModeAsync); \ XGrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask | Mod2Mask | LockMask, GDK_ROOT_WINDOW(), \ True, GrabModeAsync, GrabModeAsync); #define ungrab_key(keysym, basemask) \ XUngrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask, GDK_ROOT_WINDOW()); \ XUngrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask | LockMask, GDK_ROOT_WINDOW()); \ XUngrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask | Mod2Mask, GDK_ROOT_WINDOW()); \ XUngrabKey(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), keysym), \ basemask | Mod2Mask | LockMask, GDK_ROOT_WINDOW()); /* * initialize hotkeys */ void hotkeys_init() { char msg_str[128]; begin_func("hotkeys_init"); if (hotkey_parse(menukey_str, &menukey, &menukey_mask) != 0) { sprintf(msg_str, "Invalid menu hotkey '%s'.\nFalling back to " "default (" DEF_MENUKEY ")\n", menukey_str); show_message(msg_str, "Warning", "OK", NULL, NULL); strcpy(menukey_str, DEF_MENUKEY); hotkey_parse(menukey_str, &menukey, &menukey_mask); } if (hotkey_parse(prev_item_key_str, &prev_item_key, &prev_item_mask) != 0) { sprintf(msg_str, "Invalid previous item hotkey '%s'.\n" "Falling back to default (" DEF_PREV_ITEM_KEY ")\n", prev_item_key_str); show_message(msg_str, "Warning", "OK", NULL, NULL); hotkey_parse(DEF_PREV_ITEM_KEY, &prev_item_key, &prev_item_mask); } if (hotkey_parse(exec_item_key_str, &exec_item_key, &exec_item_mask) != 0) { sprintf(msg_str, "Invalid exec hotkey '%s'.\n" "Falling back to default (" DEF_EXEC_ITEM_KEY ")\n", exec_item_key_str); show_message(msg_str, "Warning", "OK", NULL, NULL); hotkey_parse(DEF_EXEC_ITEM_KEY, &exec_item_key, &exec_item_mask); } gdk_window_add_filter(gdk_get_default_root_window(), global_keys_filter, NULL); grab_key(menukey, menukey_mask); grab_key(prev_item_key, prev_item_mask); grab_key(exec_item_key, exec_item_mask); return_void(); } /* * disable hotkeys */ void hotkeys_done() { begin_func("hotkeys_done"); ungrab_key(menukey, menukey_mask); return_void(); } dockapps/icon/000077500000000000000000000000001243437315700136235ustar00rootroot00000000000000dockapps/icon/ico_16x16.png000066400000000000000000000004521243437315700157510ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME }IDAT8c`]{^\X9ˣ %%:c[o,f````\SLjM]Qmz,ۙ~8f ld`س,V2)dg`T🁁]Q?IÀƶ-x5W7] |R& #̄w.g" CIIENDB`dockapps/icon/ico_30x30_black.png000066400000000000000000000035151243437315700171000ustar00rootroot00000000000000PNG  IHDR;0bKGD pHYs  tIME -2=}KIDATH{PT?wy¢dy-_`|i|ŊզGA&&"6U5VBTԨ5j5(FQ,jײF"*87sf{9=?Bee%\xY%^fH$m|oQ <)^*8&&F 18^|k*gͬpBBFp$I3K=;:3M @d珡Tvgrs ưa:v2ѯxO/-n>EnPu).ӣkoELuM=UjXbB0vLt𔸞T*z`Ag`K+ M߰QI=t GS2z3 -$\C݇d]f(oʑ/ȿf qӘ‡w=a<<ܰ:CQq\W/f L0}kxsq=fRp|Wt[6G$LTJ>l~X Vތ%sppPP9p#n$|۹s={!$:#Hggpqqf׹p~ZGǶdPZZ2.hF8=8n|?93fѡlMYoRug`XXjk9~"  F|H VJս{1?~U @\ٺ $frweoV97vFQqɛ݃B^F֗ o GT`d{kQ]/?GuYvg|z%NN,]Ln=6'/#nT[̛Wo'Xɂey{rq}Z!I ㆈOQV_Ⱦd+)<-Ξ,<==Ēųۿ bgLc#^jq./*v3 :IENDB`dockapps/icon/ico_30x30_gray.png000066400000000000000000000035541243437315700167710ustar00rootroot00000000000000PNG  IHDR;0bKGD pHYs  tIME cIDATHiPʺ H#⁨xcψGA6щU5N1ZbDh: .ڊG9f9vF*ɷgޙgy?>^f..2j/ jjjHKKcEtdѣ( f"=='(L:U 1 ,B+*HMUbܸq}_$''￷/jjزeBia^zotQg%2buH^ l6FcC7م+WΓqJ޼0her G"Hڅ:??Ĩ02-MW\ G.رܺ',l(CDgx0}z˙7A>Sݛ8^\nnnXmT5$9Ҫvmj7ii8u̍WW ?'h4.*gp/_mv,-=.ڄj'33R,zލţh4 Mcu)zu&+[bkK㌈Q(w>C#,0+QI$VĎ`'&3_B⠪ZQ!3z~7xڄ]F_[ѝ92F6nϨH=|hbޜgI]|Upz6aZoJp%;\]c.ɻ[_Oo,+ =F쫷I;Fvn[N_үo@*Vա΁md]e Eh5V|}Z'KeM_`'?mL& gxw{ Vsq aRXpQ#rП N3se|4jfLM˘0>-52 { *"~ b玍H$(r>|/ZZwo$E*m:=G'hjiAy-ARf+Lawa}"&Fy;=8~lt7?БJCϹRٕ~RSSljߢވ7K?CՠTvm{44$鸝_޵!6pWr%{FQq9[˫2tH(Zƿ5 3G}EףR}':oO&DrMf臿ʝո8ܺ[?ZMT55m דZ:2_!X/$ (oܹFs;;9ᓉe>M\uV󠁉o{0w 󏣙hPXx*عs#/C멬,cFl% }ci1,YDNammꍬ:z|Fwc0((Akk+:]uulp̚W/q'qi"|l3?~(}ژ"H$\hֆFc%U{ag.Ξhn%(h8Æwt0;qQqtr9ZRajPmJ*FFKKњ5(nԉůʥqqֱSϷi?w>416P&S&ԄZŤ hh3{f DK\bg-9ٔ e z-Q#Cɻ^GfKB<0MMa4 8+\˾CױcR-tjD"E Z_/l%J>˖og``LGBo0Vf =}69@7rlsgyq@OQ= !_:ّV3R\RWpW)M/ٴq1"Gƚچ\{PJ1~ؾDBc܎_׃FVYXYIJ*p&#ɽ,4ݗVK*ز=Q^8u_B7ǻw'Fr-f‰}i] kkKml߲9Q{:3oP\RAObD΁$!HD\`?~sOxZ|N]k??JΈ3' g(qHb7rQa/umAH^Vo) XIENDB`dockapps/icon/ico_40x40_black.png000066400000000000000000000055631243437315700171070ustar00rootroot00000000000000PNG  IHDR((mbKGD pHYs  tIME  .2 IDATXyTTW[TQE1V LB@ >bFHҚnQlbl]!v:K_혧Ѩm&h F2H3@U "#{ι;}JL( BCCl6H?0vQTU Q]-Dee]#ZM6MBwAOÆŋ_׮u7kE||RTTTK \&/uuB:uJH/kE'  w /bƌ/߻݄$s-d(JEu1joom2o ]˥ Z5'nMRxqz?5e{%]LИh|ahWfZ ^W٦`L?RRґ$ T* ٹ,N8ャ@:wuyo@IT<~nn(ܿ vCRH?Gee%\r-;6dO A/jl.7_ "Sy_21} Fr: Kj%InZc3E^b<1)٠@#57C[[׵LJe -Zk/칿O/.דȱoBNdJ~A OI&m-'n`4<9D}}jZZ8Wo/:L:hni'0&P Ccѹ)Fn<<\inneҷpvVliFC_-444m68$Im-fdˮ3.)A)v̙pMfyPN}74{HNNBb>5&vtb!mgx$?j%Cxm^KtzB  Ȉ`ʾߍm4,{ I!I9464냋efσz_"h3[yi̼֬y ~ j *ΨTwA562srv bcܧpwwQxۿ"C E`_6l<̴qcOqwseLjfj:NNNѶn;zZ~;i >EQ '),pL Hu0*u5tv0xlL2 t芍9 w@''9 @WHJ'哖;775,aܯJqݎl_ȑ3UYƄ<4k>$qnc{̞0Ω7H UJ ۻR9VpFr{a#2ɘ)=IK͇۾[)_w?/ ´IENDB`dockapps/icon/ico_40x40_gray.png000066400000000000000000000056701243437315700167740ustar00rootroot00000000000000PNG  IHDR((mbKGD pHYs  tIME  _ EIDATXy\GǿtMs670d45h;FcfMtbL4f=2`tUcDP("j+twF"fvS[V}穧$4m4QXXF0#'3f˭9pKɠm\tId?XGSNzEb"9yXx}SW(--7n"BL*/^#H*8wVyV/_Etџ}W_{~H rKhhbصn3Wl` vZJo\ch7ŷ+НvaZD㡶G&X'Փk9~V*i v3IID"A.R_3sL.{O a1]=PP_ f`OT;HٔQRR7n{Rx@4>=ڍT4T`2u- \GP11x_2qH Ni͕՜-ø (Hx< Wo$ . /bee VZZҮ~;:@_ՀZy߂BXhFB+_],l?%K^ ]f3TWw&v:` ҴqHVַ9Qxa2)p6lJK F?z}W)-ENN6DF&]O9{8NNXf7 Fz$\J NJ19ehb"1K̚5KTUĵkB\j(,lEElx@"<\7pξ8k|P8tKTBggwcms&U@CfnSBGwc;D+X8AиB*=ߑqjZՀ .X[Z;9@7\U] Ns>*+ 1,{V/TUUPU'}#,vnVdrY5r]5S8ՕzHINk!0p!2-ݭ[:jLd`l="x/$G:03Q,;M΅>j`mK^WI+NNN"YŤH2?;3I>Gpl!S^L%eP,o/~Bѽ[ ,RJnbviz}#En2ds0{e 9|b<>yy`oK 'ΗE<1(-^nܸ͛wYfl8j'cs `N GFss7}JSs+ÂQ96X/l֢^!ؚ+ -ĕ=",O P(ŜYDpw6Cr|Uv_L_L_ϙ(1_dX/T6J+;:Dq ߎMB!]w9G%<7iN_"1!k_^4 ]N ;+er Qh}Sqpc՛hn"ΎD>h'HKK<N+TrAOA65>ܽ[͛w <5Gc6TZ6 lgƥ vRBr& _~]fuv#Ju N:::>|z:lmU45ur\]h3tԊ֕L& .3{d<{9WKtp&g3jM+`Kcc3-kk9˖D_?JyO1Ld>D"!?w'..N}=J* /W%a0E~03^̚ls^n֣;VC$`e%^.wIj&>7j=mL8lJˑwᏣJAbwDK`Aޔީ$$؇WQ[eTVVZe HH$X,+S_׈q@d,Ɍ:LK]`,XZPUJDamО,+W`6[eyo濈m!W/-gg`H/s@Or6 |زS&å+|u?c bٲt*m,VVV?ٓu c/MήzH>;Gn= "!PV%9” --m 5:;M6$wDWl3o%B^~i< KrL(Wo-~.إ#55g?T\1q-Dw| ?Ouٌȑg(qS.R|fHғѼcL1Z_uc4ɻY@|ݩo(lJj霭gޫo<8'/);g3Km]+YSK?P *ٕ2IENDB`dockapps/icon/ico_40x40_white.png000066400000000000000000000056711243437315700171530ustar00rootroot00000000000000PNG  IHDR((mbKGD pHYs  tIME  ' FIDATXyTWUPPkQlI "(H1CKmcq:Mv"D% ]QCI+"*KdG)QA$g&s==$ d2V+&L`ر~i_^ׯ7J!hŐ!C/JnڵbԩB";XMII#…֭1r_ZL1p 3Dmbڴi2Iikq OO5:4Jdc H}Bt:}Ws8D*E&sd_Z9}/L&r"6,`LX,`4ի)/İ@JW{Z f"H'F틟{Bz_?f3( ^\'|2%99 DLrO`̙{F䉾\=v J$E EXbȘ_QU+ |}ArWhΦR]=x.VB B+zDUcf͍ ՏLLXX0#97OKa\\Q˙JFC߃jtMPS5V0AqךnJmݛo{oJC/Nrv-Jg_\  {hћ47۞XFbZ׷b4ps >~ʐ,OK/F*`uCv|ʼnԸ}pRkذa+--^Lt:(/J^^6~~DG'%'sΜ9H22(gS)Di$%F $;QϵkhX5^}SC"  /ßr1 Di86$Ri7b.}R QڂL~ ΧGU pnt6}Zx4Nʕ;INNjpi܉V{w73 D0|h ju8JU:bKx$ʈ AN?RB@@*l/<{{?͡C=kD&sWwo& +y06AtOUr'UJ%͕?-7al7H={v'O~QρYdeG?#K&ٓCyE55:[ \H(t/X OrVOJREh^ɰ;{<">mV=$b⯣IAC- ~Л)6shmճ[YμEonu$Pቁ I8۳SgV=.NL6GNsy&J򐸎;T}KAoТl RZV#BVUtM_N%ԘH}[q9}ēG|J\ʌ,ض n(=6ޚCDxz@_w;{ظs4m,EoxbvJp;+0 Sk(v0|#.LD C YQpf8mB EK׶vw\B\BD =^SrP8Ůo?5jlބ݌U܁Ed#NĄh"fͪhX📱JpPJLp +~_` wqNNHMMD Q]rmxqW|Īw`We3hJ9}]k}RR&& 2{2yd΁qÃpi <ă&-է '?0ngdiHKK#- jh^vv`c\*>*0MIp'M5jf$vi>24z`2ՁNwg>0{U* ֬Y@mm-ű`:1:_ҍı]{{Wn޼IM\epuOOflA!j'T ɵ&l?u+jԜMjqpݧg騫k΍IZ9@qq۠TZsN:w)=I)s8Z4˸#g-,k׮i)+ UU`qU~.KKG}=.zWnp93붼d<.-Í. /j·{8s):gq?_5Ä{-OO)? քCġXZ5nIS*aQaj$<:ADD|_KNNׯ_l=VΊ5s S uZT<-1IPipFڂ?{}ܸp ՠR]~prCz0"ѣ{8sBJyĉsX7@.3kC2~2j<쭘ҿ3}ڻhCrN! Ol޼!df6ݳgbffhzzFD,g%h?}1>;#бcwLMXڵ/Ib9^DVf^>}[TG4UIvf_;ohG|8z4j{jkry;|2cllʜ9ߓ2T\TZO zm^p'qΜ9Vah?s ;:u\nGz΁!8Z5&2Ft$22##{JKݻ|/ F88P[[ÇexUU; Nrb /٩-B<;/OmMΞt6_{֢P(IOo }ʾ} \~ի1,^'M.5vqYϕ+穫S#Iqwb 펛%X۸`eE[;$OLZZv`3T%fm4SX'!2aBfٳٽ;&)!/fTUU o1FFz󫩩С߿h$ nNP+~v冴tFᎵ+0#4;?v%y%ﰶ'zؠlҒXUu˚5?4b،D"!$d|`ݺO9|x;%%Hԉ]cs]uâdlr_-d74fՏ?>}BlHLfyYY17bUU rctw[7]0mcX JU>{ܮZXm-L) !1|FzogӦp4J&g҄+d2Vioߙ;o%y(ﰳϾ篣V&^]D"#ou+.9o &؎Vw=FYm@»͠=Zl@V֐YX Fr;q]V+EӑI>t:-ׯ_ĉÜ;1( Օcxy6O8-TvoP̬^HġK+k("W%:^eUq5~IK`/q?~Gw`lXNnLK/쁥#VNyy%m]361b~d;3Xh㓖NJPXٶm}b6<&Ĉ!Jy{*LMqr5'5;?v0.xsgdbh((T<߯džMqws͜&i==±±~sf8!P8_ix7WiwGƯiYەb 2,ZV|Ils(V0mp>0\{W_?>2zЃ' '(}?NPo/W>^* tHuJ%xa4_})2A<ώ-+xnBHs\O{[Y@ @iiҚ3q8{U_mmJ*Z 6>!=sFWľD;Kf41 xy0!WRz=~vm痰t"oc~$MJ̥{7_>3ȨX>Ճ,ͧofsink4Zd2dww}QxyHX%65bb#YS1 t: F@}Q|\ژĔa\‚?͌ hT,GNȰW;TVI;6hҜeK^o.H$3?6%d2^ /6!-=_ ghHo :|0֘[lLPfLMtaQܣ媪icG;gf⠴sg KZ˱2dpPW6헞eD- sS29z, ˦ BV"{S$յ|eJ*002$z\"/F]jljގ|$svP\f-7ض4]Eac @ղR Cb'$(Kl"Ӆ%~o,l`;EG`S5ZΥ>>.$dg"/N;£c92`lZ}gaaކz Jͷe)=U_r$ >n,3}goWK\K3r)m"%ÿ}FZۧ 6/܊=_#EgS2veђN8QY03ɋޘ1bx>_ehlJ`$ %܂/Fbv\MϠ{F}jzN۵E oesT<5̙1v#J*EEe!ωckEdvG\;K5UT`fiMqwTp3GElj==J$x[amfµd RU\#~6mL8X05LKbæ| Hju\ƅ-'l`++y*xL<\q?\-'!~ֱ IENDB`dockapps/icon/ico_60x60_gray.png000066400000000000000000000124101243437315700167660ustar00rootroot00000000000000PNG  IHDR<<:rbKGD pHYs  tIME  gH1IDAThwTT?u``HE؍ Fc35DDc^zDco1"(E *mRfQ "{keu{gw/#G7nPRRR{ܜ@֮]+L [l)Z-ƍc`RHLLdÆ dffҥKg`Z0Fru!̙3X̜9 hʐH$b˖-Pd!F,v?,N/,/" ܹHNzĉ>8O|i7P,>,AAATVD E }}nRE U/|jÒ%K?;2rPr#c4c2CjV1Ѩm,t!/G%j%Ɗ!5 N*؄z3 nnnL-Z4C0J@ad̎̚5 BAE=j5o`!$gr;7[1j{S3vySܗVU%SRAS\ZF.SSc?zhDJcxv|.]QXu]3f kBp_ģ*-ݯ*.xy)!55Tjysߚ}! ;8ݣ4 }`e$ޭ45neH$疰[` Q A(0ˡu5RRrJ())!..ٳ!ق!A-$aic':7kC`͛7^k a#(B~1:Dj)[O\|d~i3) 9yҳTWKOW$rs]Pl߾@-ڛy쏿B|:=?/`IG=K~YyEm##E=)ݾ `krήSs##úN/g>`. }K7Қ30/ᢼlL\vrs,۫|zޘԋqc`iaj[hkptYig{cprva4oޞ7,!42넇oC0" AA(*'"b'8u* !HR<<|g)FPX3tƤ[\-cҥ;*+sf1gs]d"#n]k `8iiujVXNWؽL>|eY+W?IIL8|6*}쌞={hR)|]Ќ`_)YI3?"""pn?,!'~oOcbbƔ)siݺ#%%h4Yh4hUڻ89Jܹ?~˗qT:] 7;ci@6Q(L (:<1wsb޽TWWӮCpoH,8uj޽̝-)(89QUUɢEؽ{-nn,_ ?JS"9w.c9.ִ tbؠ|P{߲72YghpJO0A/x6Л^*,c)(`ըTjGGƚ5gO"׮]`ŊDFw̟YFM6}9wq9ٿQQ{t,Zr)1!n=pJwH?I[n"&&{+3VOTZl»@ wj*KZ[SSߪ.] ]bcc@GkS{]\\_~ht _i팋;v*03m"ՍVf~݊J*uʌ{ЃzF7Ғ9 SSSƈ5#ͼP*]sC.7~.si3tNNNdE}:-8}ZhUWk~=#Gv;u+6xgF/F荓s3m])޹;⻀>zvhJYF"DQY%yEZb'߯TTINԼK3^ǵk9~]˼]hʦx:$U@UMq)ra\.Gӫ1'?ooaHOOڍ;$]J_vrVՓzjZzh(B[̄ Ξ\4B7~? ;Ł3^TVjtaZyhڟ>5NC6q/ R6e|&o F=[굛>Dǐ<Ǣϲcnڒl|ݞȿ.g/@/)(V~ nv5scێ~<7WuLQ V~S=DXtt-FՑ1籵E1;|KbXBY_dbb"*++y!~c]Tc e8#Fǝxm?1iR ' w?G.ܚ l m{K\t!6ř3 jޣ`r,,'gϾh"лW>1bxߧ+,K͚=-j[[J)d$ԂALEv{iG"OӫGne|FFƻoEvM\ƵdeipwP8}^}'?Q   vfv BT_~zYί~G"Oi[9D73iq40x&3lPVfzJz < M| * $6wClvMn#6m |VfzN]'rH fLs|W7e0G%,[K@K/VwjN^#"J~'ϻ^DO9H$ؕ+7H$<-2»{μ֎|fjktA)fx6Z/vLH% ԠIr~}}Yv1>43w'.%LսJe~@dRn+w!J $.*rr XtT9lNyU iwx!`[8v&GrQ %Lk6H$^M()B. yu>j#jG;Rns LnnSNt l#eL ؠ~Sy1CXf\^^ss'nc2i"abbڞ@? \M3Ҩ&zҥTBO#++xr, m)wx!C{O5'dBbIye33G|pV3OPے[˻**XMKɤ y[b'O] ;;|vjGFufΦe납\= 7ٲ$muEzAN?!HT*[KHH~.\l7XGƂE? h alyl ?FG|ZFbz&3ثYlOgzNg~vВ,ٳRea4j_|mH{ȁp)|=`}ޟ賗9w#_W2)6&8r=ҼEp=)w҆oo6o{~:Ե3o*?ː=g9&u+[bjjM^-#3ZF"p4.Wfc0"/.`{%D\/\VVAjum(ns"JL[JHB~~1BB:xzَGxeMKje9eŅX(޾9*nfj8rH%mQZr媆 ױW+)ǏE@Դ۬pO?[L&Es> NoB Xv/GX  /qc7-O+ӓ$E_'{сSIENDB`dockapps/icon/ico_60x60_white.png000066400000000000000000000123651243437315700171550ustar00rootroot00000000000000PNG  IHDR<<:rbKGD pHYs  tIME  2BIDAThyXTe?3̰ Îl(igijb,=24-LJPPAq}Gf *X}]皙s<=|He߾}"""sJc(?,ÇΝcرtT lڴJfΜɴir ƍwB\;RRR+#<<k9d> ).x;ZjC@.kf:}C*,*OZ䀞j3N0sLr9TlܸCs)9\EFn!FsQL6MRn}mUURRJ +@R!ɨ?j(DJxv~n݆RTFFuӇ{2zh iaKqlģ&-ɳ J{xidԐBJ вn/>kjt}KGcPV*۸bjdDPmn~Ŀ>.jBJG Ae{u5h54`JիWPUUEii)qqq̚~v& m$ K{]X?,]YV#89xx-BADjO^xjN'~=li눭SﻖV\Z88'id< uJΝ;i׮Vn|~B|JjO [=)y8b:t耾nxt|y9dgי9n\y}'@Mn.ss;>x ~̱793ff[ß_8ӾnaS~OS]|<MaC<f狅 "J@w <j'g0wG-=9r$ rr2䓕|s}Ŭ\9CCc&OC۶)--!//L*Ə[[Zm={qYbc#hjxy7ꊩ5mC.7- `Q;Ą (++ç-B|O%|=SKkbcc10P]w}\t9s ==[[G*Yh*{э+(/KllgϞܹΝ; }s|2t7n(j^gxZAAA!΍_fӱsޭ`5(*RSGEʺuٷ/kγjB""> bPYӱ3gtWL=N8dv>ހn;ͨ}iyyyqy S|'9ZN%Uy9 ޭlH<_-IIq;v#Gv`_J'; "y;bnn9 3f_?1 ,;id4kUzM^ۉ% r:>T_Bb=0}TPX:5p'ee4cG@@ȘQ4GӋx>>>OYcG{L?.C0MmXCor!:3=I\3wz.Y4kkEK<zV!UJ""P(Nd;vP{"IK$]L_vSzjZhZ.eq uscC*8ss+Bc/yattTV'H6nX~Zrzy8rK27@NJo6y!V0rlV߰(^ɩSIt?q, N\&̛2큒c!ŋM6!ף=:3>x3 HG'.@E[NaԈ0v\R ?| Z! _{"XY78wZZrlm'N&v>6l:-7nf6K?V<== :ىC졁bt'ڪ8!Bㅶ*Nbk uFGPH$B"A,?Y*;GS'7SoTڪ8S 7WmNпعmOPc| /_NscCEr/Z{z_}{yk%]_P.mfps S^̺ J_~n%ʫEwH  T"a{c%1w6-˥):| q)|r4oNz6_p4??o~Uxr%%6:[\Y\gg䈾8:`)ݟ~B.3g*g P(Daa!]#⻬?#~^8?|,<ܝXx Wо3uJ%Lxm0|w_L_[ND'cg2_odL"ZWn÷뫴8tTϘQ8YoʹL:tőS4~:t]O2n˶p._ng_ѽt xa㏃ Z0ܷ7e4 k-[wkWfz]!~-wjbGIy;(9q%^N׭^dt"^59H$+7H$: zRCwy={*zt?9\\+fn{5Z7vEce aj3[J>l\k]wpv-/lGRi@?X |v)C*{4vJrr <tTZ6;9uʫjO͠[;(9v&GH! ZessS/B@H$^M{(ɷHOB& yuL%)ו JnnSNibDezL @g~3 !l\Z./DAfF .kQ\[80q"ahʊv'[OE<ILa$^w+k=vqgIh4gN ̴={vB*ǫQ }f>5|e:oD^DY{8 דbw gZnz+63ס]OÉ 8~ 1kJ&NB6k끑-a1mH$wWf} @م쌹WK%NKeet Oتt(npdL>$]L!]r #define RC_BUF_SIZE 256 /* automat state */ typedef enum { STATE_BEGINING, STATE_COMMENT, STATE_DIRECTIVE, STATE_VALUE, STATE_EXPRESSION_START, STATE_EXPRESSION, STATE_EXPRESSION_END, STATE_ACTION, STATE_COMMAND } STATE; GList *action_list = NULL; /* add character to buffer */ #define add_to_buff(buf, pos, chr) do { \ buf[pos++] = chr; \ buf[pos] = '\0'; \ if (pos + 1 == RC_BUF_SIZE) \ error = 7; \ } while (0) #define ismywhite(c) (c == '\t' || c == ' ') /* * returns config/data file name in user's home */ char * rcconfig_get_name(char *append) { static gchar fname[PATH_MAX]; const gchar *home; begin_func("rcconfig_get_name"); if (!(home = g_getenv("HOME"))) return_val(NULL); memset(fname, 0, PATH_MAX); snprintf(fname, PATH_MAX, "%s/.wmcliphist%s", home, append); return_val(fname); } /* * appends parsed action to action list */ int action_append(char *expr_buf, char *action_buf, char *cmd_buf) { ACTION *action; begin_func("action_append"); action = g_new0(ACTION, 1); if (regcomp(&action->expression, expr_buf, REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0) { g_free(action); return_val(-101); } if (strcmp(action_buf, "exec") == 0) action->action = ACT_EXEC; else if (strcmp(action_buf, "submenu") == 0) action->action = ACT_SUBMENU; else if (strcmp(action_buf, "ignore") == 0) action->action = ACT_IGNORE; else { g_free(action); return_val(-102); } action->command = g_strdup(cmd_buf); action_list = g_list_append(action_list, action); return_val(0); } /* * read and parse rcconfig */ int rcconfig_get(char *fname) { int f_rc; char tmp[1024], c; int byte_cnt; STATE state = STATE_BEGINING; char direc_buf[RC_BUF_SIZE], expr_buf[RC_BUF_SIZE], action_buf[RC_BUF_SIZE], cmd_buf[RC_BUF_SIZE]; int buf_index = 0; int error = 0, eof = 0; int i; int line = 0; int res; begin_func("rcconfig_get"); close(open(fname, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); if ((f_rc = open(fname, O_RDONLY)) < 0) { fprintf(stderr, ".wmcliphistrc not found\n"); return_val(1); } i = byte_cnt = 0; while (1) { if (i == byte_cnt) { byte_cnt = read(f_rc, tmp, 1024); if (byte_cnt == -1) { fprintf(stderr, "cannot read .wmcliphistrc\n"); break; } else if (byte_cnt < 1024) { tmp[byte_cnt++] = 0; eof = 1; } i = 0; } c = tmp[i++]; switch (state) { case STATE_BEGINING: line++; if (isalnum(c)) { state = STATE_DIRECTIVE; buf_index = 0; add_to_buff(direc_buf, buf_index, c); } else if (c == '#') state = STATE_COMMENT; else if (ismywhite(c)) line--; else if (c == '\n') state = STATE_BEGINING; else error = 1; break; case STATE_COMMENT: if (c == '\n' || c == '\0') state = STATE_BEGINING; break; case STATE_DIRECTIVE: if (ismywhite(c)) { if (strcmp(direc_buf, "action") == 0) { state = STATE_EXPRESSION_START; buf_index = 0; } else if (strcmp(direc_buf, "menukey") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "prev_item_key") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "exec_item_key") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "keep") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "lcolor") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "clipboard") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "autosave") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "confirm_exec") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "exec_immediately") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "exec_middleclick") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "exec_hotkey") == 0) { state = STATE_VALUE; buf_index = 0; } else if (strcmp(direc_buf, "auto_take_up") == 0) { state = STATE_VALUE; buf_index = 0; } else { error = 8; } } else if (isalpha(c) || c == '_') { add_to_buff(direc_buf, buf_index, c); } else { error = 1; } break; case STATE_VALUE: if (c == '\n' || ismywhite(c)) { if (strcmp(direc_buf, "menukey") == 0) { memset(menukey_str, 0, 32); strncpy(menukey_str, expr_buf, 31); } else if (strcmp(direc_buf, "prev_item_key") == 0) { memset(prev_item_key_str, 0, 32); strncpy(prev_item_key_str, expr_buf, 31); } else if (strcmp(direc_buf, "exec_item_key") == 0) { memset(exec_item_key_str, 0, 32); strncpy(exec_item_key_str, expr_buf, 31); } else if (strcmp(direc_buf, "keep") == 0) { num_items_to_keep = atoi(expr_buf); } else if (strcmp(direc_buf, "lcolor") == 0) { memset(locked_color_str, 0, 32); strncpy(locked_color_str, expr_buf, 31); } else if (strcmp(direc_buf, "clipboard") == 0) { memset(clipboard_str, 0, 32); strncpy(clipboard_str, expr_buf, 31); } else if (strcmp(direc_buf, "autosave") == 0) { autosave_period = atoi(expr_buf); } else if (strcmp(direc_buf, "confirm_exec") == 0) { if (strcasecmp(expr_buf, "yes") == 0) { confirm_exec = 1; } } else if (strcmp(direc_buf, "exec_immediately") == 0) { if (strcasecmp(expr_buf, "no") == 0) { exec_immediately= 0; } } else if (strcmp(direc_buf, "exec_middleclick") == 0) { if (strcasecmp(expr_buf, "no") == 0) { exec_middleclick = 0; } } else if (strcmp(direc_buf, "exec_hotkey") == 0) { if (strcasecmp(expr_buf, "no") == 0) { exec_hotkey = 0; } } else if (strcmp(direc_buf, "auto_take_up") == 0) { if (strcasecmp(expr_buf, "no") == 0) { auto_take_up = 0; } } else error = 1; } else if (isgraph(c)) add_to_buff(expr_buf, buf_index, c); else error = 2; if (error == 0) { if (c == '\n' || c == '\0') { buf_index = 0; state = STATE_BEGINING; } else if (ismywhite(c)) { buf_index = 0; state = STATE_COMMENT; } } break; case STATE_EXPRESSION_START: if (c == '"') state = STATE_EXPRESSION; else error = 1; break; case STATE_EXPRESSION: if (c == '"') state = STATE_EXPRESSION_END; else if (c == '\n') error = 1; else add_to_buff(expr_buf, buf_index, c); break; case STATE_EXPRESSION_END: if (c != ' ' && c != '\t') error = 1; if (strcmp(direc_buf, "action") == 0) { state = STATE_ACTION; buf_index = 0; } else error = 1; break; case STATE_ACTION: if (c == ' ' || c == '\t') { state = STATE_COMMAND; buf_index = 0; } else if (c == '\0' || c == '\n') { if (strcmp(action_buf, "ignore") == 0) { state = STATE_BEGINING; buf_index = 0; *cmd_buf = '\0'; res = action_append( expr_buf, action_buf, cmd_buf); if (res < 0) error = abs(res); } else error = 1; } else if (isalpha(c)) add_to_buff(action_buf, buf_index, c); else error = 1; break; case STATE_COMMAND: if (c == '\n' || c == '\0') { state = STATE_BEGINING; buf_index = 0; res = action_append( expr_buf, action_buf, cmd_buf); if (res < 0) error = abs(res); } else add_to_buff(cmd_buf, buf_index, c); break; } if (!error && (!eof || i < byte_cnt)) continue; switch (state) { case STATE_DIRECTIVE: if (error == 7) fprintf(stderr, "Directive is too long " "(line %d)\n", line); else if (error == 8) fprintf(stderr, "Unknown directive " "(line %d)\n", line); else fprintf(stderr, "Only letters are " "allowed in directive " "name (line %d)\n", line); break; case STATE_EXPRESSION_START: case STATE_EXPRESSION: if (error == 7) fprintf(stderr, "Expression is too long " "(line %d)\n", line); else fprintf(stderr, "Expression must be " "enclosed with quotes " "\" (line %d)\n", line); break; case STATE_EXPRESSION_END: fprintf(stderr, "One space/tab and " "action must follow " "each expression" " (line %d)\n", line); break; case STATE_ACTION: if (error == 1) fprintf(stderr, "Only letters are " "allowed in action " "name (line %d)\n", line); else if (error == 101) fprintf(stderr, "Invalid expression " "(line %d)\n", line); else if (error == 7) fprintf(stderr, "Action is too long " "(line %d)\n", line); else fprintf(stderr, "Invalid action " "(line %d)\n", line); break; case STATE_VALUE: if (error == 1) fprintf(stderr, "Invalid directive " "(line %d)\n", line); else if (error == 7) fprintf(stderr, "Value is too long " "(line %d)\n", line); else fprintf(stderr, "Invalid value " "(line %d)\n", line); break; case STATE_COMMAND: if (error == 101) fprintf(stderr, "Invalid expression " "(line %d)\n", line); else if (error == 7) fprintf(stderr, "Command is too long " "(line %d)\n", line); else fprintf(stderr, "Invalid action " "(line %d)\n", line); break; case STATE_COMMENT: if (!eof) fprintf(stderr, "Unknown error " "(line %d)\n", line); else error = 0; break; case STATE_BEGINING: /* everything is OK */ error = 0; break; } break; } close(f_rc); return_val(error); } /* * free rcconfig data */ void rcconfig_free() { GList *list_node; begin_func("rcconfig_free"); list_node = action_list; while (list_node) { ACTION *action = list_node->data; g_free(action->command); regfree(&action->expression); g_free(action); list_node = list_node->next; } g_list_free(action_list); return_void(); } dockapps/utils.c000066400000000000000000000010451243437315700141770ustar00rootroot00000000000000#include "wmcliphist.h" /* * converts text in UTF-8 to charset by actual locale */ gchar * from_utf8(gchar *string) { gsize bytes_read; gsize bytes_written; GError *error; gchar *converted; /* gchar *error_msg; */ /* gint error_code; */ converted = g_locale_from_utf8(string, -1, &bytes_read, &bytes_written, &error); /* error_code = (error == NULL) ? 0 : error->code; */ /* * fprintf(stderr, "from_utf8: %d b read, %d b written, error: %d\n", * bytes_read, bytes_written, error_code); */ return converted; } dockapps/wmcliphist.1000066400000000000000000000037131243437315700151440ustar00rootroot00000000000000.TH "WMCLIPHIST" "1" .SH "NAME" wmcliphist \(em provides a history to X11 selections .SH "SYNOPSIS" .PP \fBwmcliphist\fR [\fB-h\fP] [\fB-v\fP] [\fB-n \fInum\fR\fP] [\fB-c \fIcol\fR\fP] [\fB-i \fInum\fR\fP] [\fB-s \fIsize\fR\fP] [\fB-b \fIclipboard\fR\fP] .SH "DESCRIPTION" .PP This manual page documents briefly the program \fBwmcliphist\fR. .PP This manual page was written for the \fBDebian\fP distribution because the original program does not have a manual page. .PP \fBwmcliphist\fR is a dockable application which provides a history for the last few selections made in the X11 Window System. .PP Note, that most of \fBwmcliphist\fR's features are accessed by installing a configuration file .wmcliphistrc into your $HOME. Find a well documented example in /usr/share/doc/wmcliphist. .SH "OPTIONS" .IP "\fB-h\fP " 10 Show summary of options. .IP "\fB-v\fP " 10 Print version. .IP "\fB-n num\fP " 10 Set the number of items to keep in the history. Default is 10. .IP "\fB-c col\fP " 10 Set the color for locked items. Default is red. .IP "\fB-i num\fP " 10 Choose wmcliphist icon antialiasing: If you have a midtone background provide num=0, for dark backgrounds choose num=1 and for light backgrounds num=2. .IP "\fB-s size\fP " 10 Choose wmcliphist icon size, must be one of 16, 30, 40 or 60 (default). .IP "\fB-b clipboard\fP " 10 Choose clipboard to use, must be one of PRIMARY (select copies, middle click pastes, default), SECONDARY (not used), or CLIPBOARD (Ctrl+C copies, Ctrl+V pastes) .SH "AUTHOR" .PP This manual page was written by Sebastian Ley sebastian.ley@mmweg.rwth-aachen.de for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. dockapps/wmcliphist.c000066400000000000000000000260271243437315700152310ustar00rootroot00000000000000/* * (c) 2001 Michal Krause */ #include "wmcliphist.h" #define WMCLIPHIST_VERSION "2.1" /* * print some help */ void print_help() { begin_func("print_help"); fprintf(stderr, "Usage: wmcliphist [options]\n\n" "wmcliphist is small dock applet for Window Maker which " "keeps X clipboard history\n\n"); fprintf(stderr, "-h show this help\n" "-v print version\n" "-n set number of items to keep (default 10)\n" "-c color set color for locked items (default is red)\n" "-s choose wmcliphist icon size:\n" " 0 = no icon\n" " 16 = tiny 16x16 px icon\n" " 30 = icon suitable for 32px dock/slit\n" " 40 = icon suitable for 48px dock/slit\n" " 60 = icon suitable for 64px dock/slit (default)\n"); fprintf(stderr, "-i choose wmcliphist icon antialiasing:\n" " 0 = for mid tones background (default)\n" " 1 = for dark background\n" " 2 = for light background\n"); fprintf(stderr, "-d dumps clipboard history to stdout" " in pseudo XML format (no escaping etc.)\n"); fprintf(stderr, "-b choose clipboard to manage\n" " PRIMARY = select copies, middle click pastes (default)\n" " SECONDARY = not used\n" " CLIPBOARD = Ctrl+C copies, Ctrl+V pastes\n\n"); exit(1); return_void(); } static void wmcliphist_exit(gint code) { begin_func("wmcliphist_exit"); exit(code); return_void(); } /* gtk3 dockapp code based on wmpasman by Brad Jorsch * * http://sourceforge.net/projects/wmpasman */ GtkWidget *foo_create_main_icon_window(GtkWidget *mw, unsigned int s) { Display *d; GdkDisplay *display; GtkWidget *foobox; unsigned int dummy3; Window mainwin, iw, p, dummy1, *dummy2, w; XWMHints *wmHints; display = gdk_display_get_default(); foobox = gtk_window_new(GTK_WINDOW_POPUP); gtk_window_set_wmclass(GTK_WINDOW(mw), g_get_prgname(), "DockApp"); gtk_widget_set_size_request(foobox, s, s); gtk_widget_realize(mw); gtk_widget_realize(foobox); d = GDK_DISPLAY_XDISPLAY(display); mainwin = GDK_WINDOW_XID(gtk_widget_get_window(mw)); iw = GDK_WINDOW_XID(gtk_widget_get_window(foobox)); XQueryTree(d, mainwin, &dummy1, &p, &dummy2, &dummy3); if (dummy2) XFree(dummy2); w = XCreateSimpleWindow(d, p, 0, 0, 1, 1, 0, 0, 0); XReparentWindow(d, mainwin, w, 0, 0); gtk_widget_show(mw); gtk_widget_show(foobox); wmHints = XGetWMHints(d, mainwin); if (!wmHints) wmHints = XAllocWMHints(); wmHints->flags |= IconWindowHint; wmHints->icon_window = iw; XSetWMHints(d, mainwin, wmHints); XFree(wmHints); XReparentWindow(d, mainwin, p, 0, 0); XDestroyWindow(d, w); return foobox; } /* * main func */ int main(int argc, char **argv) { gint i = 1, res; gchar *arg; gchar *icon_file; GList *list_node; int icon_number = 0; int icon_size = 60; gboolean dump_only = FALSE; #ifdef FNCALL_DEBUG debug_init_nothreads(); #endif begin_func("main"); /* load configuration */ if ((res = rcconfig_get(rcconfig_get_name("rc"))) != 0) { fprintf(stderr, "~/.wmcliphistrc parse error (%d)\n", res); return_val(1); } /* parse command line */ while ((arg = argv[i])) { if (*arg == '-') { if (*(arg + 1) == 'h') print_help(); else if (*(arg + 1) == 'n') { i++; if (!argv[i]) { fprintf(stderr, "Missing value of -n\n"); print_help(); } num_items_to_keep = atol(argv[i]); } else if (*(arg + 1) == 'c') { i++; if (!argv[i]) { fprintf(stderr, "Missing value of -c\n"); print_help(); } memset(locked_color_str, 0, 32); strncpy(locked_color_str, argv[i], 31); } else if (*(arg + 1) == 'i') { i++; if (!argv[i]) { fprintf(stderr, "Missing value of -i\n"); print_help(); } icon_number = atoi(argv[i]); if (icon_number < 0 || icon_number > 2) { fprintf(stderr, "Invalid value of -i\n"); print_help(); } } else if (*(arg + 1) == 's') { i++; if (!argv[i]) { fprintf(stderr, "Missing value of -s\n"); print_help(); } icon_size = atoi(argv[i]); if (icon_size != 60 && icon_size != 40 && icon_size != 30 && icon_size != 16 && icon_size != 0) { fprintf(stderr, "Invalid value of -s\n"); print_help(); } if (icon_size == 0) { icon_size = 1; } } else if (*(arg + 1) == 'd') { dump_only = TRUE; } else if (*(arg + 1) == 'v') { printf("wmcliphist "WMCLIPHIST_VERSION"\n"); exit(1); } else if (*(arg + 1) == 'b') { i++; if (!argv[i]) { fprintf(stderr, "Missing value of -b\n"); print_help(); } memset(clipboard_str, 0, 32); strncpy(clipboard_str, argv[i], 31); } else { fprintf(stderr, "Invalid option -%c\n", *(arg + 1)); print_help(); } } else { fprintf(stderr, "Invalid option %s\n", arg); print_help(); } i++; } signal(SIGCHLD, SIG_IGN); /* initialize Gtk */ gtk_init(&argc, &argv); /* create main window */ main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); /* creat dock icon */ dock_app = foo_create_main_icon_window(main_window, icon_size); if (icon_size) { /* create icon_mask */ if (icon_size == 60) { /* 60x60 icon */ if (icon_number == 0) { icon_file = "ico_60x60_gray.png"; } else if (icon_number == 1) { icon_file = "ico_60x60_black.png"; } else { icon_file = "ico_60x60_white.png"; } } else if (icon_size == 40) { /* 40x40 icon */ /* create icon */ if (icon_number == 0) { icon_file = "ico_40x40_gray.png"; } else if (icon_number == 1) { icon_file = "ico_40x40_black.png"; } else { icon_file = "ico_40x40_white.png"; } } else if (icon_size == 30) { /* 30x30 icon */ /* create icon */ if (icon_number == 0) { icon_file = "ico_30x30_gray.png"; } else if (icon_number == 1) { icon_file = "ico_30x30_black.png"; } else { icon_file = "ico_30x30_white.png"; } } else { /* 16x16 icon */ /* create icon */ icon_file = "ico_16x16.png"; } icon_file = g_strconcat(DATADIR"/", icon_file, NULL); pixmap = gtk_image_new_from_file(icon_file); gtk_widget_show(pixmap); gtk_container_add(GTK_CONTAINER(dock_app), pixmap); } /* create clipboard history menu */ menu_hist = gtk_menu_new(); menu_title = gtk_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu_hist), menu_title); gtk_widget_show(menu_title); gtk_widget_show(menu_hist); /* create application menu */ menu_app = gtk_menu_new(); menu_app_clip_lock = gtk_check_menu_item_new_with_label("Clipboard lock"); gtk_menu_shell_append(GTK_MENU_SHELL(menu_app), menu_app_clip_lock); menu_app_clip_ignore = gtk_check_menu_item_new_with_label("Clipboard ignore"); gtk_menu_shell_append(GTK_MENU_SHELL(menu_app), menu_app_clip_ignore); menu_app_save = gtk_menu_item_new_with_label("Save history"); gtk_menu_shell_append(GTK_MENU_SHELL(menu_app), menu_app_save); g_signal_connect(G_OBJECT(menu_app_save), "activate", G_CALLBACK(menu_app_item_click), GINT_TO_POINTER(0)); menu_app_exit = gtk_menu_item_new_with_label("Exit"); gtk_menu_shell_append(GTK_MENU_SHELL(menu_app), menu_app_exit); g_signal_connect(G_OBJECT(menu_app_exit), "activate", G_CALLBACK(menu_app_item_click), GINT_TO_POINTER(1)); gtk_widget_show_all(menu_app); list_node = action_list; while (list_node) { ACTION *action = list_node->data; if (action->action == ACT_SUBMENU && strcmp(action->command, "-") != 0) { action->menu_item = gtk_menu_item_new_with_label( action->command); gtk_menu_shell_append(GTK_MENU_SHELL(menu_hist), action->menu_item); action->submenu = gtk_menu_new(); gtk_menu_item_set_submenu( GTK_MENU_ITEM(action->menu_item), action->submenu); menu_title = gtk_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(action->submenu), menu_title); gtk_widget_show(menu_title); gtk_widget_show(action->menu_item); gtk_widget_show(action->submenu); submenu_count++; } if (action->action == ACT_SUBMENU && strcmp(action->command, "-") == 0) { printf("'%s'\n", action->command); action->submenu = menu_hist; } list_node = list_node->next; } if (submenu_count) { GtkWidget *separator; separator = gtk_menu_item_new(); gtk_widget_show(separator); gtk_menu_shell_insert(GTK_MENU_SHELL(menu_hist), separator, 1); } /* prepare colors and styles */ if (gdk_rgba_parse(&locked_color, locked_color_str) == FALSE) { char msg_str[128]; sprintf(msg_str, "Invalid color string: '%s'.\n" "Falling back to default (red).", locked_color_str); show_message(msg_str, "Warning", "OK", NULL, NULL); strcpy(locked_color_str, DEF_LOCKED_COLOR); gdk_rgba_parse(&locked_color, locked_color_str); } /* set clipboard */ if (strcmp(clipboard_str, "PRIMARY") == 0) { clipboard = GDK_SELECTION_PRIMARY; } else if (strcmp(clipboard_str, "SECONDARY") == 0) { clipboard = GDK_SELECTION_SECONDARY; } else if (strcmp(clipboard_str, "CLIPBOARD") == 0) { clipboard = GDK_SELECTION_CLIPBOARD; } else { char msg_str[128]; sprintf(msg_str, "Invalid clipboard string: '%s'.\n" "Falling back to default (" DEF_CLIPBOARD_STR ").", clipboard_str); show_message(msg_str, "Warning", "OK", NULL, NULL); clipboard = DEF_CLIPBOARD; } /* load previously saved history */ if (history_load(dump_only) != 0) { if (errno == E_TOO_MUCH) { if (show_message("Number of items to keep (-n switch or " "keep directive in ~/.wmcliphistrc)\n" "is lower than actual number of items " "in history file.\nSome items from " "history will be lost. May I continue?", "Warning", "Yes", "No", NULL) == 1) { rcconfig_free(); exit(1); } } else if (errno != E_OPEN) { rcconfig_free(); fprintf(stderr, "cannot load history (%d)\n", errno); exit(1); } } if (dump_only) { rcconfig_free(); exit(1); } if (icon_size) { cairo_region_t *region; cairo_surface_t *surface; /* connect signal for menu popup */ gtk_widget_add_events(dock_app, GDK_BUTTON_PRESS_MASK); g_signal_connect(G_OBJECT(dock_app), "event", G_CALLBACK(button_press), G_OBJECT(menu_hist)); surface = cairo_image_surface_create_from_png(icon_file); region = gdk_cairo_region_create_from_surface(surface); gdk_window_shape_combine_region(gtk_widget_get_window(dock_app), region, 0, 0); } /* run clipboard monitor */ g_signal_connect(G_OBJECT(main_window), "selection_received", G_CALLBACK(my_get_xselection), NULL); g_timeout_add(250, time_conv_select, NULL); /* run autosave timer */ if (autosave_period > 0) g_timeout_add(autosave_period * 1000, history_autosave, NULL); /* setup everything for supplying selection to other apps */ gtk_selection_add_target(dock_app, clipboard, GDK_SELECTION_TYPE_STRING, 1); g_signal_connect(G_OBJECT(dock_app), "selection_get", G_CALLBACK(selection_handle), NULL); g_signal_connect(G_OBJECT(dock_app), "destroy", G_CALLBACK(wmcliphist_exit), NULL); hotkeys_init(); gtk_main(); return_val(0); } dockapps/wmcliphist.h000066400000000000000000000136131243437315700152330ustar00rootroot00000000000000#ifndef _WMCLIPHIST_H_ #define _WMCLIPHIST_H_ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #define VERSION 0x0003 #define DEF_LOCKED_COLOR "red" #define DEF_MENUKEY "Control+Alt+V" #define DEF_PREV_ITEM_KEY "Control+Alt+C" #define DEF_EXEC_ITEM_KEY "Control+Alt+E" #define DEF_CLIPBOARD_STR "PRIMARY" #define DEF_CLIPBOARD GDK_SELECTION_PRIMARY #define MAX_ITEM_LENGTH 40 /* ========================================================================== * CLIPBOARD FUNCTIONS */ /* history item */ typedef struct { GtkWidget *menu_item; gint locked; gchar *content; GtkWidget *menu; } HISTORY_ITEM; /* number of items to keep (may be overriden from command line) */ extern gint num_items_to_keep; /* when true, clipboard will be automatically taken up by wmcliphist */ extern gint auto_take_up; /* number of items kept */ extern gint num_items; /* list of clipboard history items */ extern GList *history_items; /* selected item */ extern HISTORY_ITEM *selected; /* current number of locked items */ extern gint locked_count; /* which clipboard to use */ extern gchar clipboard_str[32]; extern GdkAtom clipboard; #ifdef DEBUG #define dump_history_list(header) dump_history_list_fn(header) #else #define dump_history_list(header) #endif /* * get clipboard content - partialy inspired by Downloader for X */ gboolean my_get_xselection(GtkWidget *window, GdkEvent *event); /* * clipboard conversion - inspired by Downloader for X too :) */ gboolean time_conv_select(); /* * handles request for selection from other apps */ gint selection_handle(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time_stamp, gpointer data); /* ========================================================================== * RC CONFIG */ /* action record */ typedef struct { regex_t expression; enum { ACT_EXEC, ACT_SUBMENU, ACT_IGNORE } action; char *command; GtkWidget *menu_item; GtkWidget *submenu; } ACTION; extern GList *action_list; /* * returns config/data file name in user's home */ char * rcconfig_get_name(char *append); /* * read and parse rcconfig */ int rcconfig_get(char *fname); /* * free rcconfig data */ void rcconfig_free(); /* ========================================================================== * GUI */ /* error codes */ #define E_BASE 10000 #define E_OPEN (E_BASE | 1) #define E_INVALID (E_BASE | 2) #define E_REMOVE (E_BASE | 3) #define E_TOO_MUCH (E_BASE | 4) #define E_WRITE (E_BASE | 5) #define E_RENAME (E_BASE | 6) /* * process new history item */ void process_item(char *content, gint locked, gboolean exec); /* ========================================================================== * HISTORY FUNCTIONS */ /* * autosave period */ extern int autosave_period; /* * confirm actions? */ extern int confirm_exec; /* * Exec immediately when item is captured? */ extern int exec_immediately; /* * move supplied item to begin */ void move_item_to_begin(HISTORY_ITEM *item); /* * Execute an item. */ void exec_item(char *content, ACTION *action); /* * loads history from file */ int history_load(gboolean dump_only); /* * store history to file */ int history_save(); /* * free history data */ void history_free(); /* * autosave timer function */ gboolean history_autosave(); /* ========================================================================== * HOTKEYS */ /* hotkeys */ extern gchar menukey_str[32]; extern guint menukey; extern gchar prev_item_key_str[32]; extern gchar exec_item_key_str[32]; /* * Exec on hotkey? */ extern int exec_hotkey; /* * initialize hotkeys */ void hotkeys_init(); /* * disable hotkeys */ void hotkeys_done(); /* ========================================================================== * GUI */ /* color of locked item */ extern gchar locked_color_str[32]; extern GdkRGBA locked_color; extern gint submenu_count; /* * Exec on middle click? */ extern int exec_middleclick; /* main window widget */ extern GtkWidget *main_window; /* dock icon widget */ extern GtkWidget *dock_app; /* clipboard history menu */ extern GtkWidget *menu_hist; extern GtkWidget *menu_title; /* application menu */ extern GtkWidget *menu_app; extern GtkWidget *menu_app_clip_ignore; extern GtkWidget *menu_app_clip_lock; extern GtkWidget *menu_app_exit; extern GtkWidget *menu_app_save; /* button */ extern GtkWidget *button; /* pixmap */ extern GtkWidget *pixmap; /* * dock button click response */ gboolean button_press(GtkWidget *widget, GdkEvent *event, gpointer data); /* * checks, if there is already such item in menu, * in which case it moves it to the begining */ HISTORY_ITEM * menu_item_exists(gchar *content, GtkWidget *submenu); /* * add new item to menu */ HISTORY_ITEM * menu_item_add(gchar *content, gint locked, GtkWidget *target_menu); /* * application main menu handler */ gboolean menu_app_item_click(GtkWidget *menuitem, gpointer data); /* * open dialog with specified message andbuttons * and return number of button pressed */ gint show_message(gchar *message, char *title, char *b1_text, char *b2_text, char *b3_text); /* ========================================================================== * UTILITIES */ gchar * from_utf8(gchar *string); #endif dockapps/wmcliphistrc000066400000000000000000000071471243437315700153370ustar00rootroot00000000000000# Set hotkey for history menu popup. # you can use combination of modifiers (ctrl, alt, shift) and one # character (function keys etc. are not supported now). # Default: Ctrl+Alt+V menukey Ctrl+Alt+V # Set hotkey returning previously captured item back to clipboard. It's # useful when you replace your clipboard content with some other (e.g. # upon clearing of paste destination) and you want to switch back to it # quickly and easily. # Default: Ctrl+Alt+C prev_item_key Ctrl+Alt+C # Set hotkey to perform the first matching exec action on the current # clipboard item # Default: Ctrl+Alt+E exec_item_key Ctrl+Alt+E # Should wmcliphist automaticaly take up clipboard content? # Default: yes auto_take_up yes # Set number of items to keep. # Default: 10 keep 10 # Set color for locked items. Value is color in any X11-supported # format, eg. blue, green, #000080, #FF8000 # Default: red lcolor red # Set autosave period in seconds. # Default: 120 autosave 60 # Should wmcliphist ask you before performing action of exec type? # Default: no confirm_exec yes # Should wmcliphist exec commands immediately when matching item is captured? # Default: yes exec_immediately yes # Should wmcliphist exec commands on a middle click from the menu? # Default: yes exec_middleclick yes # Should wmcliphist exec commands from the exec hotkey? # Default: yes exec_hotkey yes # Which clipboard should wmcliphist manage? PRIMARY (select copies, middle click # pastes), SECONDARY (not used), or CLIPBOARD (Ctrl+C copies, Ctrl+V pastes) # Default: PRIMARY clipboard PRIMARY # You can define regular expressions driven actions executed when new # item is captured. Items can be silently ignored, inserted to submenus # or you can execute any command. # Action is defined like this: # # action "pattern" action_type command # # "pattern" is extended regular expression and it MUST by enclosed with # double quotes (") # action_type can be "ignore", "submenu" or "exec" (without quotes). # Actions of type "ignore" and "submenu" are terminating - no more # actions will be executed after them. Action of type "exec" is not # terminating and any matching actions will be executed too. For # example, you can let start browser automaticaly when URL is # captured and then drop this item with "ignore" statement or put it # into special submenu with "submenu" statement. # command is either submenu name for actions of type "submenu" or # command to be executed through /bin/sh for actions of type "exec". # Whole rest of line is taken as command so don't enclose it with # quotes. # If action type is "exec", you can include "%s" string in command # and it will be replaced with item content (don't use "%s" more # than once and any other occurrence of '%' character write as # "%%"!!!). # If action type is "submenu", command can be "-" (without quotes), # which means item will be placed in main menu, not in submenu. It's # usable if you want to use "exec" and then put item into main menu. # In other cases this construction doesn't make sense, because items # are placed into main menu by default. # show URLs in links browser started in new xterm window... action "^http://.*$" exec xterm -e links "%s" # ... and put it to submenu URL (action of type "ignore" can be used to # drop URLs) action "^http://.*$" submenu URL # put email addresses to submenu "Emails" action "^[^@]+@([^.]+\.)+[a-zA-Z]{2,}$" submenu Emails # ignore strings containing spaces or tabs only action "^[ \t]+$" ignore # ignore strings shorter than four characters (mostly selected by mistake) action "^.{1,3}$" ignore