Compare commits

...

142 Commits

Author SHA1 Message Date
wdlkmpx f3ff2c62eb update gmrun.1
forgot to update this for release 1.1w ...
2021-03-06 15:44:47 +08:00
wdlkmpx f3043727dc gmrun 1.1w 2021-03-06 15:22:44 +08:00
wdlkmpx e8dd889f24 merge data/zrelease into autogen.sh .. 2021-03-06 10:09:32 +08:00
wdlkmpx 802a4bda50 main.c (gtk3.4+): G_APPLICATION_NON_UNIQUE 2021-02-22 15:07:05 +08:00
wdlkmpx e390c1e063 main.c: main() gtk3.4+: hide cmd line args from GApplication
Handling cmd line args with GApplication is a nightmare
https://developer.gnome.org/gtkmm-tutorial/stable/sec-multi-item-containers.html.en#boxes-command-line-options
2021-02-22 15:00:58 +08:00
wdlkmpx 0573d99082 gmrunrc: EXT syntax-> EXT:ext,etc = handler '%s' 2021-02-22 08:21:46 +08:00
wdlkmpx ee2560d57f rename USE_XDG to USE_GLIB_XDG 2021-02-22 08:11:40 +08:00
PRESFIL 8e1c8718ae Fix xterm -e handling with multiword queryes
* `xterm`'s `-e` option is an option with a **variable number of parameters*.
  It does not perform word splitting on its own and takes all argv's words
  after it.  Therefore, the quotation marks in man and info prevent you from
  passing them switches and multiple arguments.

* Some commands (like `xdg`-gues) takes 1 argument and they can contain
  shell-symbols -> must be braced

* Some of them (like man & info) can take multiple arguments and (as it seems
  to me) cannot contain shell-symbloc -> must not be braced to split query to
  multiple words.
2021-02-22 20:47:37 +08:00
wdlkmpx c9e22f006a main.c: ext_check(): escape spaces only if USE_XDG = 1
otherwise unescape spaces

ref #5
2021-02-22 07:36:01 +08:00
wdlkmpx 78cac66790 restore system(3) call as the default option to run commands
Use libc's system(3) to run commands, this includes any shell command
   and special stuff that only a shell interpreter can understand
 Set to 0 if you want a more conservative approach where the file to run
   is validated and errors running files are reported (without closing the gmrun window)

SHELL_RUN = 1

ref #4
2021-02-18 17:51:38 +08:00
wdlkmpx 1e678b1038 gmrun 1.0w 2021-01-25 15:02:57 +08:00
wdlkmpx ceb6ae60b5 add Makefile.true 2021-01-25 14:15:02 +08:00
wdlkmpx a9c45a9f9d use GtkApplication for GTK3 2021-01-25 11:49:58 +08:00
wdlkmpx bfed4acda5 gtkcompletionline: tweaks / don't declare var inside for loop.. 2021-01-25 11:48:56 +08:00
wdlkmpx 077ac01700 history.c: use g_list_delete_link() 2021-01-22 16:27:41 +08:00
wdlkmpx 073e95a57a update README 2021-01-22 16:27:28 +08:00
wdlkmpx f59d31c5a4 configure.ac: default to GTK3, fall back to GTK2
the gtk3 port will be compiled if gtk3 is available

use --enable-gtk2 or --disable-gtk3 to compile the gtk2 port
2021-01-20 21:30:37 +08:00
wdlkmpx 26d4fb47c6 fix gcc9 warnings 2021-01-20 08:57:03 +08:00
wdlkmpx 7caa9ae8b4 configure.ac: disable deprecated gtk2 stuff 2021-01-20 08:57:00 +08:00
wdlkmpx 21dc2c4470 update README 2021-01-07 21:03:03 +08:00
wdlkmpx 8ca61a3951 update autogen.sh 2021-01-07 20:26:36 +08:00
wdlkmpx 6223b53709 move gmrunrc & zrelease to data/ dir 2021-01-07 20:16:41 +08:00
wdlkmpx 91173a2b49 remove .travis.yml 2021-01-07 20:12:45 +08:00
wdlkmpx 49dab051bf renamed: COPYING -> LICENSE 2021-01-07 20:11:52 +08:00
wdlkmpx 8e028445ca CTRl-g (search mode): cancel search and clear text entry 2020-12-29 17:34:52 +08:00
wdlkmpx b3dbc9ca9a CTRL-n: Fetch the next command from the history list 2020-12-29 17:33:28 +08:00
wdlkmpx 4fd7c52c48 CTRL-p: fetch the previous command from the history list 2020-12-29 17:33:28 +08:00
wdlkmpx d41ba7df77 search_off(): properly clear cl->hist_word .. 2020-12-29 16:34:18 +08:00
wdlkmpx e84930778a update gtkcompat 2020-12-29 11:11:05 +08:00
wdlkmpx 68282dd4c0 "!": history search mode that matches only the start of strings
The gtk entry must be emtpy before pressing "!"

It enters a special (history) search mode that only
matches the start of strings, a reverse search

hit CTRL-R or CTRL-S to extend search backwards or forwards
2020-10-14 09:09:39 +08:00
wdlkmpx 0bd21c2b90 gtkcompat.h 2020-10-11 2020-10-14 09:09:30 +08:00
wdlkmpx a46c04beca gtkcompletionline.c: (scandir) don't reverse GList
sorting happens in the GtkTreeView
2020-10-14 09:09:19 +08:00
wdlkmpx 4bc440cbb8 gtkcompletionline.c: (scandir) don't use alphasort
sorting happens in the GtkTreeView
2020-10-14 09:09:11 +08:00
wdlkmpx 8f95488c2c config_prefs.c: use free, strdup, calloc.. 2020-10-14 09:09:04 +08:00
wdlkmpx 177832c04a gtkcompletionline.c: restore bash-like search for CTRL-S/R
- CTRL-R enters search mode
- type text until you find something
- hit CTRL-R to nagivate through history items that mach the search text

CTRL-S: regular search
CTRL-R: reverse search

There's one advantage: you can use CTRL-S and CTRL-R any time
and you'll navigate through the results at will
2020-10-07 20:14:55 +08:00
wdlkmpx f529279ce5 completionline.c: CTRL-S/CTRL-R: search matches anywhere in strings
partially restores old behavior
2020-10-07 15:45:18 +08:00
wdlkmpx c5fb31c030 gtkcompletionline: get rid of cl->cmpl
complete_from_list()
   add param 'cword' with a string to strdup if completion window is not displayed

complete_line()
   rename GList *ls to FileList, and move it a few lines up
   use FileList instead of  cl->cmpl
   if num_items == 1 then pass FileList->data as the second param to complete_from_list()
2020-10-07 14:17:23 +08:00
wdlkmpx b00981c4b3 add gmrun.1 (manual) 2020-10-07 00:57:40 +08:00
wdlkmpx 771e5f5cfa main.c: gmrun [text] 2020-10-07 00:57:37 +08:00
wdlkmpx 03a98addb3 gtkcompletionline.c: set completion window transient for main window 2020-10-07 00:57:32 +08:00
wdlkmpx ed2760ac97 Relicense project to ISC
thanks to @mishoo

closes #2
2020-10-07 00:56:48 +08:00
wdlkmpx 833e0708e2 update README a bit 2020-10-07 00:56:03 +08:00
wdlkmpx 571d6f428c complete_from_list: fix memory leak 2020-10-05 17:36:47 +08:00
wdlkmpx a48ae4b973 complete_line: items > 1: always use 1st item from GtkTreeView 2020-10-05 17:03:22 +08:00
wdlkmpx 4930aa9240 gtkcompletionline.c: (scandir) use standard alphasort 2020-10-05 17:03:12 +08:00
wdlkmpx 90a73af854 gtkcompletionline.c: simplify my_alphasort() 2020-10-05 17:03:07 +08:00
wdlkmpx ea07442da2 generate_dir_list(): don't use GString 2020-10-05 17:01:18 +08:00
wdlkmpx 9f12390b20 src/history.c: fix memory leaks 2020-10-03 21:06:51 +08:00
wdlkmpx 3c4519a534 gtkcompletionline.c: remove unused GEN_COMP... 2020-10-03 21:06:49 +08:00
wdlkmpx 0f94a8cad3 gtkcompletionline.c: use only cl->cmpl to get filelist 2020-10-03 21:06:43 +08:00
wdlkmpx 30929fe68d gtkcompletionline: set/unset prefix in generate_execs_list/dirlist() 2020-10-03 21:06:41 +08:00
wdlkmpx 2c254aad92 gtkcompletionline.c: properly sort completion list 2020-10-03 21:05:30 +08:00
wdlkmpx 496a0782b4 gtkcompletionline.c: fix segfault with gtk3
the gtk_list_store is used after it's been destroyed

on_cursor_changed was being triggered inappropriately
block the signal in destroy_completion_window()
2020-10-02 12:29:44 +08:00
wdlkmpx 53de437b97 gtkcompletionline: remove unused cl->first_key 2020-10-02 12:28:19 +08:00
wdlkmpx 70a9bde3f6 get_words(): add empty string if glist is empty
move hack from tab_pressed()
2020-10-02 12:28:09 +08:00
wdlkmpx 669f9094cc gtkcompletionline.c: fix memory leak in complete_from_list() 2020-10-02 12:28:03 +08:00
wdlkmpx aecb75916c tab_pressed(): don't call complete_line() if completion window exists 2020-10-02 12:27:52 +08:00
wdlkmpx b026cd6e04 gtkcompletionline.c: improve logic to free glists 2020-10-02 12:27:49 +08:00
wdlkmpx d794934169 merge generate_completion_from_execs/dirlist() into complete_line() 2020-10-02 12:27:06 +08:00
wdlkmpx 3727eb6d26 gtkcompletionline.c: avoid triggering on_cursor_changed() twice
this also potentially fixes some memory leaks
2020-10-02 12:27:04 +08:00
wdlkmpx 60b7bca318 gtkcompletionline.c: fix complete_from_list / set_words / complete_line 2020-10-02 12:27:00 +08:00
wdlkmpx c8bd0dec3e gtkcompletionline.c: remove complete_common()
not really needed
2020-10-02 12:26:48 +08:00
wdlkmpx d46e89b2cf gtkcompletionline.c: add debug code 2020-10-02 12:26:35 +08:00
wdlkmpx acb6881379 complete_line(): optimize a bit / fix some memory leaks 2020-10-02 12:26:04 +08:00
wdlkmpx 9b51f89c54 main.c: use spaces 2020-09-29 16:22:07 +08:00
wdlkmpx fe821ecd98 gtkcompletionline.c: use spaces 2020-09-29 16:22:05 +08:00
wdlkmpx e866c24c39 gtkcompletionline.c: don't use gtk_tree_model_sort_new_with_model() 2020-09-29 16:22:03 +08:00
wdlkmpx da57c5dcb9 configure.ac: enable many gcc warnings 2020-09-29 16:22:00 +08:00
wdlkmpx 4361172862 *** gmrun is now a C application *** 2020-09-29 16:21:57 +08:00
wdlkmpx 30b75bd447 *** gtkcompletionline.c: use C code ***
based on a set of patches by mazes-80
but it became a different thing in the end

need to identify and fix potential memory leaks
(many of them are already fixed)
2020-09-29 16:21:52 +08:00
wdlkmpx 7218498da6 add data/zmtrace.sh 2020-09-29 16:20:02 +08:00
wdlkmpx d1b718c086 fix build with ancient glib 2020-09-14 23:51:13 +08:00
wdlkmpx 7622a99196 option to use glib XDG handling (disabled by default)
based on a set of patches by mazes-80

.# use GLib XDG handling? (freedesktop specification)
USE_XDG = 0

=======================================================================
 if not using XDG, you can specify URL and file Handlers...
2020-09-14 23:51:12 +08:00
wdlkmpx 84df0cdecc ext_check/url_check: don't include handler in history entry 2020-09-14 23:51:10 +08:00
wdlkmpx 41c75d7610 main.cc: fix calls to config_get_int() 2020-09-14 23:51:08 +08:00
wdlkmpx 3762bfc1d4 completionline.cc: make CTRL-R work as intended.. 2020-09-13 23:58:41 +08:00
wdlkmpx ef6ffe8d80 completionline: remove handling of ctrl-e/g (what's this?) 2020-09-13 23:51:16 +08:00
wdlkmpx 2869dc0e23 history.c: improvements
- _history_write_to_file(): just write everything
- new HistoryFile.list_end: references the last item
- new HistoryFile.has_changed: flag to determine if the history has changed..
- do not allow duplicate entries
- option to save only if the history has changed
2020-09-13 23:51:04 +08:00
wdlkmpx b95c55899b main.cc: (history) show search text next to "Search:" label 2020-09-13 23:50:54 +08:00
wdlkmpx 7c73eb62ea completionline.cc: fix Pango-CRITICAL **: pango_layout_get_cursor_pos ...
GTK3: Pango-CRITICAL **: pango_layout_get_cursor_pos: assertion 'index >= 0 && index <= layout->length' failed
-- for some reason there's an error when the object is destroyed
-- The GtkCompletionLine 'cancel' signal makes gmrun destroy the object and exit
-- The current fix is to set an empty text

Something must be causing the issue, a proper fix is yet to be found.
2020-09-13 00:16:55 +08:00
wdlkmpx 5bec03672d src/main.cc: get rid of 'struct gigi'
create two global variables
- wlabel
- wlabel_search

instead of using g->w1, g->w2
2020-09-13 00:16:50 +08:00
wdlkmpx 1a72b7c36c completion: (search) cl->hist_word is now a char array 2020-09-13 00:16:48 +08:00
wdlkmpx 05511520d9 *** handle configuration and history with C code ***
This is a major change that may lead to a complete C application.

Deleted files:
- prefs.cc
- prefs.h
- history.cc
- history.h

New files:
- config_prefs.c
- config_prefs.h
- history.c
- history.h

gmrun was mostly broken, I'm not sure when the app became so broken
but it's better now.

The code is more readable and more stable.

Various bugs were fixed, it would take many lines to explain the changes,
they were just so dramatic
2020-09-13 00:16:42 +08:00
wdlkmpx 1836e4a58f completion: TabTimeout: fix "Source ID was not found when attempting to remove it" 2020-09-09 00:03:14 +08:00
wdlkmpx 83cb7b7d85 new configuration option: Geometry
remove 'Left', 'Top', 'Width'

*# Set window geometry
*# - Wx      width                400x
*# - WxH     width x height       400x70         (height = 0 = ignore)
*# - WxH+x+y width x height +x +y 400x0+200+100
*#
*# If +x+y is not specified (or not allowed), the gmrun window is displayed centered
Geometry = 450x
2020-09-08 23:51:02 +08:00
wdlkmpx 92f184ac7e main.cc: gmrun_activate() / parse_command_line()
make main() as simple as possible
2020-09-08 21:44:37 +08:00
wdlkmpx b227610e0c main.cc: gmrun_exit() 2020-09-08 21:27:06 +08:00
wdlkmpx 42860f123a add gmrun.desktop / gmrun.png 2020-09-08 14:40:04 +08:00
wdlkmpx 4615a8701c gtk_completion_line_init: 'self' instead of 'object' 2020-09-07 23:20:31 +08:00
wdlkmpx ceff6dd2bd gtkcompletionline.cc: use G_DEFINE_TYPE_EXTENDED() 2020-09-07 21:47:47 +08:00
wdlkmpx f191713307 update gtkcompat.h
now a single-header lib (MIT)
2020-09-07 18:50:27 +08:00
wdlkmpx da1ec0d8fd remove src/main.h 2020-09-07 17:37:52 +08:00
wdlkmpx 997eb7480e window icon: use 'system-run' or 'gtk-execute' 2020-09-07 17:07:54 +08:00
wdlkmpx 67096ce9ae set_info_text_color: optimize a bit 2020-09-07 15:56:19 +08:00
wdlkmpx 3d3c2785ed run_the_command: use g_shell_parse_argv() and g_spawn_async() 2020-09-07 15:48:07 +08:00
wdlkmpx 37667213b0 use G_OBJECT with g_signal_* 2020-09-07 12:14:20 +08:00
wdlkmpx abb39e6d61 main.cc: gtk_widget_show_all (dialog) 2020-09-07 11:51:11 +08:00
wdlkmpx a93e3b8b08 main.cc: main_vbox 2020-09-07 11:51:10 +08:00
wdlkmpx 9097eba9f3 gtk_completion_line_class_init(): cosmetic changes 2020-09-07 11:51:10 +08:00
wdlkmpx 216c71d7fd completion: use gtk_tree_model_iter_n_children() to get row count 2020-09-07 11:51:10 +08:00
wdlkmpx 81d1a925f2 completion: attemp to silence Gtk-WARNING **: Allocating size to Window ...
Gtk-WARNING **: Allocating size to XXX without calling
  gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?

Not a proper fix
Bug appeared in gtk 3.20
Probably fixed in gtk 3.22.xx .. I get this this warning with gtk 3.22.11

the hack should be applied to (gtk >= 3.20 && gtk < 3.24)
2020-09-07 11:51:09 +08:00
wdlkmpx d73f7460c4 completion: use gtk_tree_selection_select_iter() 2020-09-06 20:07:34 +08:00
wdlkmpx 0dab60df9b completion: don't create extra column
...that stores the current index in the GtkTreeView model

it was a hack, but it was not needed anyway

gtk2 does not have this function:
	gtk_tree_model_iter_previous()

but it's possible to do the same
with gtk_tree_path_prev() + a few more lines
2020-09-06 19:18:00 +08:00
wdlkmpx cd78cd0f0d gtkcompletionline.cc: avoid on_key_press callback when key is released 2020-09-06 17:51:18 +08:00
wdlkmpx 703cf54b76 main.cc: (search) fix "Source ID was not found when attempting to remove it" 2020-08-24 20:28:25 +08:00
wdlkmpx fe7fdf4f54 src: (gtkcompat) use gtk_widget_set_margin_start/end 2020-08-24 19:27:31 +08:00
wdlkmpx 2dd933b6a2 src: (gtkcompat) use gtk_widget_set_halign/valign 2020-08-24 19:27:28 +08:00
wdlkmpx 2b250ecbd7 src: use gtk_box_new() 2020-08-24 19:27:26 +08:00
wdlkmpx a2009d7d76 gtkcompletionline.cc: hack for glibc < 2.10 (dirent) 2020-08-24 19:27:24 +08:00
wdlkmpx c4813e68e4 update autogen.sh 2020-08-24 19:27:20 +08:00
wdlkmpx 54c03a2099 support gtk >= 2.14 2020-08-24 19:27:15 +08:00
wdlkmpx e6328e50a8 main.cc: properly free GError and GOptionContext... 2020-08-24 19:27:09 +08:00
wdlkmpx 1345447fb1 reimplement `--geometry WxH+X+Y` (cli param) [without libpopt]
example: gmrun --geometry 600x40+100+100
2020-07-17 14:50:30 +08:00
wdlkmpx 8340de3671 gmrunrc: remove unused options
-CenteredByWidth
-CenteredByHeight
-UseActiveMonitor
2020-07-17 13:42:10 +08:00
Samuel Bauer d6a5099595 gtkcompletionline.cc: don't use `goto` in generate_dir_list()
mazes-80
2020-07-17 13:42:09 +08:00
wdlkmpx 1ce4041550 fix setting dialog border, name and title..
my bad
2020-07-16 20:13:06 +08:00
Samuel Bauer df93a29b66 renamed main window 2020-07-16 19:30:33 +08:00
wdlkmpx c64e88d053 update README a bit 2020-07-16 18:51:05 +08:00
wdlkmpx 35f715d5c9 remove gmrun.glade 2020-07-16 18:40:36 +08:00
wdlkmpx 97e81a047e update ChangeLog & AUTHORS 2020-07-16 18:40:10 +08:00
wdlkmpx 108bd70d17 Silence "GtkDialog mapped without a transient parent. This is discouraged." 2020-01-18 19:53:04 +08:00
Samuel Bauer 617d1847df Cosmetic changes
From 7b3cd60dee790d8fd8faa187d8b743acad71ff09
2020-01-18 19:36:08 +08:00
Samuel Bauer 7037e1079a removed compilation warnings
From 3ec51c4b83369fae6700fc3418a431627966c72e
2020-01-16 08:21:56 +08:00
Samuel Bauer 49443fe20b removed quote_string: use glib regex
From 7eb9d24a5d9124ca959778dda3f7ff4a0f87a6d4
2020-01-16 07:59:36 +08:00
wdlkmpx de54e6311c indentation style: use tabs
so that it's easier to port patches from

https://gitlab.com/mazes_80/gmrun/commits/master
2020-01-16 07:47:38 +08:00
Samuel Bauer f3a560cc31 parse_tilda(): use only glib
cf8a73470a
2020-01-16 03:31:24 +08:00
mazes_80 bbc29eca32 GtkCList to GtkTreeview
d85a0c6733
2020-01-16 03:08:04 +08:00
wdlkmpx 869a63a7a0 gtk2/3: support "navigating" history with mouse wheel
based on gmrun-0.9.2-mousewheel.patch [fedora]
2020-01-16 00:45:34 +08:00
wdlkmpx 6063a4d2ba gmrunrc: better defaults
gmrun-gmrunrc.patch [fedora]
2020-01-15 23:03:46 +08:00
wdlkmpx 5572744a9a update readme 2020-01-15 22:38:42 +08:00
wdlkmpx 876b146465 gtk2/3: set_info_text_color() [unify GtkStyle functions]
this is compatible with gtk2 and gtk3.. the same code
2020-01-15 21:06:40 +08:00
wdlkmpx 827d926d23 gtk2/3: remove titlebar from dialog (is this a good idea?)
To me it looks better with a titlebar

use gtk_widget_get_window() for gdk_window_set_decorations()
2020-01-15 18:41:08 +08:00
wdlkmpx aa4a37ddcc WIP gtk3 support [--enable-gtk3]
work in progress..

deleted functions:

- gtk_style_ref() = gtk1.2 - not needed in gtk2/3
- gdk_window_set_decorations() - bug with gtk3 - not required
- gtk_window_set_policy() - gtk2 - not required

Problem:

Need to replace GtkCList with GtkTreeView #help_wanted

http://scentric.net/tutorial/ch-treeview.html
https://stackoverflow.com/questions/18908756/use-what-instead-of-deprecated-gtk-clist
https://lists.gnu.org/archive/html/bug-gnubg/2016-06/msg00010.html
2020-01-15 04:13:23 +08:00
wdlkmpx f9094b6a61 gtkcompletionline.cc: comment out gtk_window_set_policy()
this is not compatible with gtk3

code to replace it with cairo or something:
https://stackoverflow.com/questions/40645031/how-do-i-make-a-gtk3-image-in-a-window-shrinkable
2020-01-15 03:36:35 +08:00
wdlkmpx f5106c4526 Replace gtk_widget_set_usize() with gtk_widget_set_size_request() 2020-01-15 03:36:35 +08:00
wdlkmpx 39f5b171cb Replace GTK_CHECK_CAST with G_TYPE_CHECK_INSTANCE_CAST 2020-01-15 03:36:34 +08:00
wdlkmpx d338978275 replace gtk_timeout_add() with g_timeout_add() [not sure what I'm doing] 2020-01-15 03:36:34 +08:00
wdlkmpx 6bce26ac00 gtkcompletionline.cc: use gtk-widget-get-allocation
https://developer.gnome.org/gtk2/stable/GtkWidget.html#gtk-widget-get-allocation

gtk >= 2.18
2020-01-15 00:06:29 +08:00
wdlkmpx 2ad08091e7 minimum gtk version = 2.24.0 2020-01-14 23:33:39 +08:00
wdlkmpx 1571627ad9 Replace GDK_<keyname> with GDK_KEY_<keyname>
gtk >= 2.22
2020-01-14 23:33:38 +08:00
wdlkmpx a7d13fdfa6 gtk_signal_* -> g_signal_* / GTK_OBJECT -> GTK_WIDGET
GTK_TYPE_* -> G_TYPE_*
GTK_SIGNAL_FUNC() -> GCALLBACK()

https://developer.gnome.org/gtk2/stable/gtk2-Signals.html

gtk_signal is deprecated in gtk2 and completely removed in gtk3
2020-01-14 23:33:38 +08:00
wdlkmpx edd815e3fd update README.markdown (a bit) 2020-01-14 23:33:38 +08:00
44 changed files with 4052 additions and 3295 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ compile
config.guess
config.h*
config.log
config.rpath
config.status
config.sub
autom4te.cache

View File

@ -1,6 +0,0 @@
language: c++
install: sudo apt-get install libgtk2.0-dev
before_script: ./autogen.sh
script:
- ./configure
- make

18
AUTHORS
View File

@ -1 +1,17 @@
Mihai Bazon <mishoo@infoiasi.ro>
Initial author: Mihai Bazon <mishoo@infoiasi.ro>
Icon: Andrea Soragna - https://icon-icons.com/icon/gtk-execute/36132
CVS:
----
andreas99
Henning Schild
Makoto Nokata
mishoo
Paweł Błaszczyk
PRESFIL
R. Tyler Croy
Samuel Bauer
sonofkojak
wdlkmpx

340
COPYING
View File

@ -1,340 +0,0 @@
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.

330
ChangeLog
View File

@ -1,23 +1,323 @@
2003-11-16 AV <andreas99@users.sourceforge.net>
* configure.in: added support for libpopt
==========
gmrun 1.1w
==========
* src/gtkcompletionline.cc: added UTF-8 support for input and output
PRESFIL (1):
Fix xterm -e handling with multiword queryes
* src/main.cc: added UTF-8 support for input and output and
added an option to place gmrun (-geometry)
wdlkmpx (7):
restore system(3) call as the default option to run commands
main.c: ext_check(): escape spaces only if USE_XDG = 1
rename USE_XDG to USE_GLIB_XDG
gmrunrc: EXT syntax-> EXT:ext,etc = handler '%s'
main.c: main() gtk3.4+: hide cmd line args from GApplication
main.c (gtk3.4+): G_APPLICATION_NON_UNIQUE
merge data/zrelease into autogen.sh ..
2002-06-05 EJ <sonofkojak@users.sourceforge.net>
* src/history.cc (append): Previously, an item was not placed in
the history when it was the last item. Now, if we find an entry,
we move it to the end of the list.
==========
gmrun 1.0w
==========
2002-06-05 EJ <sonofkojak@users.sourceforge.net>
Highlights:
- GTK 3 support (default / use --enable-gtk2 to compile the gtk2 port)
- should work with GTK 2.12+ (or even older GTK versions)
- fixed broken CTRL-R / CTRL-S
- gmrun is now a C application
- added desktop file and icon
- added manual
- changed license to ISC (approved by @mishoo)
- support Glib XDG handling (set USE_XDG = 1 in gmrunrc)
- keep support for custom extension and url handlers
(the app is a bit more complex than it should because of this)
- restored --geometry param (it's a bit different)
- gmrunrc: Geometry = (read comments)
(this probably doesn't work with wayland and other protocols)
* acinclude.m4: Added stlport detection code. When using an old
version of g++/stdc++ you can get this code to compile only with
the stlport. gcc-2.9[56] don't have a definition for
char_traits.
changes since 0.9.5w
Samuel Bauer (6):
parse_tilda(): use only glib
removed quote_string: use glib regex
removed compilation warnings
Cosmetic changes
renamed main window
gtkcompletionline.cc: don't use `goto` in generate_dir_list()
mazes_80 (1):
GtkCList to GtkTreeview
wdlkmpx (124):
update README.markdown (a bit)
gtk_signal_* -> g_signal_* / GTK_OBJECT -> GTK_WIDGET
Replace GDK_<keyname> with GDK_KEY_<keyname>
minimum gtk version = 2.24.0
gtkcompletionline.cc: use gtk-widget-get-allocation
replace gtk_timeout_add() with g_timeout_add() [not sure what I'm doing]
Replace GTK_CHECK_CAST with G_TYPE_CHECK_INSTANCE_CAST
Replace gtk_widget_set_usize() with gtk_widget_set_size_request()
gtkcompletionline.cc: comment out gtk_window_set_policy()
WIP gtk3 support [--enable-gtk3]
gtk2/3: remove titlebar from dialog (is this a good idea?)
gtk2/3: set_info_text_color() [unify GtkStyle functions]
update readme
gmrunrc: better defaults
gtk2/3: support "navigating" history with mouse wheel
indentation style: use tabs
Silence "GtkDialog mapped without a transient parent. This is discouraged."
update ChangeLog & AUTHORS
remove gmrun.glade
update README a bit
fix setting dialog border, name and title..
gmrunrc: remove unused options
reimplement `--geometry WxH+X+Y` (cli param) [without libpopt]
main.cc: properly free GError and GOptionContext...
support gtk >= 2.14
update autogen.sh
gtkcompletionline.cc: hack for glibc < 2.10 (dirent)
src: use gtk_box_new()
src: (gtkcompat) use gtk_widget_set_halign/valign
src: (gtkcompat) use gtk_widget_set_margin_start/end
main.cc: (search) fix "Source ID was not found when attempting to remove it"
gtkcompletionline.cc: avoid on_key_press callback when key is released
completion: don't create extra column
completion: use gtk_tree_selection_select_iter()
completion: attemp to silence Gtk-WARNING **: Allocating size to Window ...
completion: use gtk_tree_model_iter_n_children() to get row count
gtk_completion_line_class_init(): cosmetic changes
main.cc: main_vbox
main.cc: gtk_widget_show_all (dialog)
use G_OBJECT with g_signal_*
run_the_command: use g_shell_parse_argv() and g_spawn_async()
set_info_text_color: optimize a bit
window icon: use 'system-run' or 'gtk-execute'
remove src/main.h
update gtkcompat.h
gtkcompletionline.cc: use G_DEFINE_TYPE_EXTENDED()
gtk_completion_line_init: 'self' instead of 'object'
add gmrun.desktop / gmrun.png
main.cc: gmrun_exit()
main.cc: gmrun_activate() / parse_command_line()
new configuration option: Geometry
completion: TabTimeout: fix "Source ID was not found when attempting to remove it"
*** handle configuration and history with C code ***
completion: (search) cl->hist_word is now a char array
src/main.cc: get rid of 'struct gigi'
completionline.cc: fix Pango-CRITICAL **: pango_layout_get_cursor_pos ...
main.cc: (history) show search text next to "Search:" label
history.c: improvements
completionline: remove handling of ctrl-e/g (what's this?)
completionline.cc: make CTRL-R work as intended..
main.cc: fix calls to config_get_int()
ext_check/url_check: don't include handler in history entry
option to use glib XDG handling (disabled by default)
fix build with ancient glib
add data/zmtrace.sh
*** gtkcompletionline.c: use C code ***
*** gmrun is now a C application ***
configure.ac: enable many gcc warnings
gtkcompletionline.c: don't use gtk_tree_model_sort_new_with_model()
gtkcompletionline.c: use spaces
main.c: use spaces
complete_line(): optimize a bit / fix some memory leaks
gtkcompletionline.c: add debug code
gtkcompletionline.c: remove complete_common()
gtkcompletionline.c: fix complete_from_list / set_words / complete_line
gtkcompletionline.c: avoid triggering on_cursor_changed() twice
merge generate_completion_from_execs/dirlist() into complete_line()
gtkcompletionline.c: improve logic to free glists
tab_pressed(): don't call complete_line() if completion window exists
gtkcompletionline.c: fix memory leak in complete_from_list()
get_words(): add empty string if glist is empty
gtkcompletionline: remove unused cl->first_key
gtkcompletionline.c: fix segfault with gtk3
gtkcompletionline.c: properly sort completion list
gtkcompletionline: set/unset prefix in generate_execs_list/dirlist()
gtkcompletionline.c: use only cl->cmpl to get filelist
gtkcompletionline.c: remove unused GEN_COMP...
src/history.c: fix memory leaks
generate_dir_list(): don't use GString
gtkcompletionline.c: simplify my_alphasort()
gtkcompletionline.c: (scandir) use standard alphasort
complete_line: items > 1: always use 1st item from GtkTreeView
complete_from_list: fix memory leak
update README a bit
Relicense project to ISC
gtkcompletionline.c: set completion window transient for main window
main.c: gmrun [text]
add gmrun.1 (manual)
gtkcompletionline: get rid of cl->cmpl
completionline.c: CTRL-S/CTRL-R: search matches anywhere in strings
gtkcompletionline.c: restore bash-like search for CTRL-S/R
config_prefs.c: use free, strdup, calloc..
gtkcompletionline.c: (scandir) don't use alphasort
gtkcompletionline.c: (scandir) don't reverse GList
gtkcompat.h 2020-10-11
"!": history search mode that matches only the start of strings
update gtkcompat
search_off(): properly clear cl->hist_word ..
CTRL-p: fetch the previous command from the history list
CTRL-n: Fetch the next command from the history list
CTRl-g (search mode): cancel search and clear text entry
renamed: COPYING -> LICENSE
remove .travis.yml
move gmrunrc & zrelease to data/ dir
update autogen.sh
update README
configure.ac: disable deprecated gtk2 stuff
fix gcc9 warnings
configure.ac: default to GTK3, fall back to GTK2
update README
history.c: use g_list_delete_link()
gtkcompletionline: tweaks / don't declare var inside for loop..
use GtkApplication for GTK3
add Makefile.true
============
gmrun 0.9.5w
============ changes since 0.9.4w:
Henning Schild (2):
gtk: replace deprecated gtk_type_new and _unique
gtk: do not select any text to keep clipboard clean
unknown (1):
Handle more than 256 characters in the history
wdlkmpx (3):
add .travis.yml
configure.ac: no need to check for glib
gmrun 0.9.5w
============
gmrun 0.9.4w
============ changes since 0.9.2:
Makoto Nokata (2):
Rewritten feature which places gmrun window on monitor
Updated default gmrun config
Paweł Błaszczyk (2):
Fix for "undefined reference to symbol 'XQueryPointer'"
Use GtkDialog instead of GtkWindow.
R. Tyler Ballance (1):
Correct a few compiler errors due to missing imports under gcc4
R. Tyler Croy (7):
Remove generated config.h.in
Add simplistic git ignore file
Fix bug with running quoted commands in the terminal
Correct improper function prototype for my_alphasort.
Rename the readme for extra special GitHub consideration
Center the window on the screen with the mouse pointer
Add a README symlink for kicks
wdlkmpx (15):
clean up/update build system
always use libc's system() function to run commands
configure.ac: remove unneded AM_PROG_AR
bump version to 0.9.3
use gtk_window_set_position()
remove commented out code
remove libpopt dep / --geometry param
remove gmrun.spec.in...
configure.ac: update AM_INIT_AUTOMAKE
update .gitignore
remove unused screen_contains_pointer()
add 'make-release' script
configure.ac: remove unused XQueryPointer stuff
simplify / use @sysconfdir@ for gmrunrc
bump version to 0.9.4w
===========
gmrun 0.9.2
===========
andreas99 (3):
- merged gtk-2 branch to main branch
- UTF-8 support - libpopt support
changes for 0.9.2
mishoo (73):
Initial revision
These files are generated.
little bug fixed in gtkcompletionline.cc (the prev. version works with an older compiler)
Removed useless files
jump to new version
removed unconditional debug output.
added drop-down list (nice)
switch to new version (added drop-down list functionality)
*** empty log message ***
some nice changes - fixed bug, completion window is displayed even if we're not completing the last word. Also, cursor now marks two words for completion, even if there's no space between.
some bugs fixes, support for CTRL-ENTER starts command in terminal.
new version
Added support for configuration file
fix compilation prob.
configure -- switch to new version gtkcompletionline -- much smoother completion.. select completed-text.. etc, really better.. prefs -- added support for $(Variable) expansion main -- added 3 config options: Top, Left (opper-left corner)
End, Escape -- clear the selection
-- swithced to new version -- more intuitive tab completion (hit tab only once, and the list is shown) -- fixed bug in prefs (made it recursive, so can replace more than one variable on a line) -- ... and other nice things :) hopefully
fixed bug in gtkcompletionline.cc -- crashed when no completion found..
case-insensitive std::string-like class
*** empty log message ***
default configuration file
added support for default configuration file
switched to new version
revert to normal version (0.5.3-2 not good for building rpms..)
[main.cc] set widget names [history.cc] history size moved to config file (not hard coded) [gmrunrc] set history size in default config file
changed gdk_window_set_position to gtk_widget_set_uposition -- got rid of flicker.. :)
updated
*** empty log message ***
trying to add CTRL-R feature from bash...
updated code to support backward / forward searching through history using CTRL-R / CTRL-S as in bash / Emacs.
fixed bug in CTRL-R/S searching. added code for backspace in history search mode.
switched to new version (0.5.4)
search phrase gets nice selected :)
various bug fixes
bug fixing / improvement..
*** empty log message ***
rpm spec file
hmm...
added "!" to complete from history with the last command beginning with the entered text
cosmetic...
updated
new version
- bug fixes - nice window, no titlebar
fixed bug
added URL-handling ability (check the config file)
modified for URL-s also, added some small comments to make content clearer for user.
changed version
README -- improved documentation. configure -- hmm... this should be removed from CVS, but... later.
removed. moved to gmrun.spec.in -- to be generated by configure.
generates gmrun.spec when configure is run
support for creating gmrun.spec
fixed bug
programs are now executed with exec*p
fixed bug
another bug fix... :)
changes related to generation of gmrun.spec
fixed some bugs; new features:
updated for new configuration parameters
updated for the new release
fixed bug
fixed bugs, new configuration parameter: ShowLast (1 / 0) to determine if gmrun should display the last history item as selected by default. (maybe some users don't like that...)
added nice frame around the completion window
*** empty log message ***
included some patches from Michal Politowski (thanks!);
bug fixes: - file names containing white-space now (hopefully) behave correctly - others, I don't remember
they're kind of old, but..
these are automatically generated, duh..
preparing for a new version
finally, I write news :)
new bugfix version
bugfixes: END/HOME (C-E/C-A) behavior is now much better, some code cleanup (mainly reindentation :)), removed some warnings, etc. Major bug fixed is that previously (with 0.8) you could not edit a .doc file with soffice if you had .doc extension handler set as AbiWord :)
0.8.1 news
bug fixed (the "e"/"E" character doesn't clear selection)
sonofkojak (1):
Added support for STLPort.

View File

@ -1,5 +0,0 @@
-*- text -*-
Michal Politowski - provided patches for some.. well.. not bugs, but say
incorrect behavior. Thanks! Also thanks to David B
Harris who sent me these patches.

182
INSTALL
View File

@ -1,182 +0,0 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright 2020 Mihai Bazon
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided that
the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALLWARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,30 +1,6 @@
## Process this file with automake to produce Makefile.in
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
SUBDIRS = data src
myrcdir = @sysconfdir@
myrc_DATA = gmrunrc
EXTRA_DIST = gmrunrc
install-data-local:
@$(NORMAL_INSTALL)
if test -d $(srcdir)/pixmaps; then \
$(SHELL) $(top_srcdir)/install-sh -d $(DESTDIR)$(pkgdatadir)/pixmaps; \
for pixmap in $(srcdir)/pixmaps/*; do \
if test -f $$pixmap; then \
$(INSTALL_DATA) $$pixmap $(DESTDIR)$(pkgdatadir)/pixmaps; \
fi \
done \
fi
dist-hook:
if test -d pixmaps; then \
mkdir $(distdir)/pixmaps; \
for pixmap in pixmaps/*; do \
if test -f $$pixmap; then \
cp -p $$pixmap $(distdir)/pixmaps; \
fi \
done \
fi

55
NEWS
View File

@ -1,55 +0,0 @@
-*- text -*-
0.9.2 (Son, Nov 16 2003)
- UTF-8 support (only tested with german). Please report problems with
other languages to <andreas99@users.sf.net>
- New little feature: you could place gmrun with the -geometry parameter
0.8.1 (Sat, Aug 17 2002)
- bug fix release:
- major bug fixed: you could not edit a .doc file with soffice if
you had an extension handler for .doc set as "AbiWord %s" :)
Analogue for other extensions.
- smoother key handling (mainly the END/C-E, HOME/C-A keys now work
correctly and also clear the selection).
- others: elimined most compiler warnings (I just noticed them..:),
some code cleanup (mainly reindentation).
0.8.0 (Fri, Aug 16 2002, it's been a long time)
- New feature: extension handlers. This allows us to type directly the
file, and gmrun will select your preferred application handler based of
the configuration in ~/.gmrunrc or $prefis/share/gmrun/gmrunrc
- New feature: TAB simulation. You can set a timeout for this in the
config file, and gmrun will automatically issue a TAB press after that
milliseconds after the last keypress.. I've tried to handle this the
smart way, but it could still be buggy so by default is disabled
(TabTimeout variable in config file, set it to some non-zero value to
enable).
- New "feature": you can select the old way of running commands using the
"system" libc function. This has the great advantage that allows you to
combine commands using shell operators. To enable it specify
"--enable-system" at configure time.
- Bug fix: white-space characters inside file names now (hopefully) behave
correcly. They are backslash-ed :) like in bash.
- Bug fix: '!' character now enters search mode even if all the field is
selected. Thanks to Michal Politowski for noticing this and also for
fixing it :) actually I never regarded it as a bug, but it was.. :)
- Another patch from Michal Politowski lets two configuration files to
work together. More specifically, if $prefix/share/gmrun/gmrunrc exists
it will be loaded, and then it will try $HOME/.gmrunrc, but the latter
does not override completely the settings from the global file. So you
can provide clean defaults in the global file, and each user will
customize it's own file by editing only those properties that he doesn't
like.. which is kind of normal, after all :)

1
README
View File

@ -1 +0,0 @@
README.markdown

View File

@ -1,47 +0,0 @@
since gmrun version 0.2.5 there is possible to use a configuration file for
some features gmrun has... for now only Terminal and Width are available but
maybe more will be added in the future ;-]~
The configuration file should be located in your home directory, named as
GMRUNRC compilation directive (".gmrunrc" by default).
The syntax is plain simple. Look at the example below:
--
TermExec = xterm -bg black -fg white -geometry 100x60 -e
Width = 300
Top = 100
Left = 50
--
* 'TermExec' is the command used for terminal spawning when the magic
Ctrl-Enter is pressed upon a gmrun command. NOTE that -e should be THE
VERY LAST argument as the program just gets this configuration line and
appends to it the gmrun input text. ie, try: 'man bash<Ctrl-Enter>'
* 'Width' is simply the desired width of the gmrun window in pixels (by
default it is 500 which may be a little big for low-resolution X desktops).
* 'Top' and 'Left' represent ofc the distance from the top-left corner of your
screen where the gmrun window will appear
-----------------------------------
NEWS:
as gmrun v 0.5.3 appeared... mishoo thought it would be useful to be
able to to things like these below in your configuration file:
##################### set terminal
TermOptions = -bg black -cr green -fg white -C -fn 9x15 -sl 8912
TermGeometry = -geometry 100x40
MyTerm = rxvt
Terminal = ${MyTerm} ${TermOptions} ${TermGeometry}
TermExec = ${Terminal} -e
#####################################################
if you understand it and need it, use it =]~ it's pretty simple duh.. and
quite useless though ;-]~
//altblue

View File

@ -1,15 +0,0 @@
* Terminal spawning:
- just activate your command by pressing not only ENTER but CTRL-ENTER
(i.e.: man perl<CTRL-ENTER>)
* Completion:
- hit TAB key to get a list of possible completions
(isn't that obvious, duh!?! =]~ )
* Window too large?
- read README.gmrunrc
* Want to run eterm/kterm/rxvt/gnome-terminal/footerm instead xterm?
- read README.gmrunrc
//altblue

View File

@ -1,32 +0,0 @@
for those who use icewm as their window manager gmrun comes as a very light and good
replacement for the nifty but desktop space consuming 'address bar' that
comes with this window manager.
what should you do:
edit your icewm preferences (~/.icewm/preferences) and modify some
params there as below:
TaskBarDoubleHeight=0
ShowAddressBar=0 # in fact this is the only option you need to
# modify.. but this was my only reason to use a
# double-height taskbar :))
RunCommand="gmrun" # heh, this too :) .. it's pretty obvious why :P~
this can suffice but still there is more you can do to make your life easier:
1. put up a keyboard shortcut for gmrun:
edit ~/.icewm/keys and put there a line like this one below:
key "Alt+Ctrl+r" gmrun
2. customize the gmrun window management:
edit ~/.icewm/winoptions and put there stuff like this:
gmrun.ignoreTaskBar: 1
gmrun.layer: OnTop
gmrun.fResize: 0
gmrun.fClose: 0
gmrun.fMinimize: 0
gmrun.fMaximize: 0
gmrun.fHide: 0
gmrun.fRollup: 0
gmrun.dTitleBar: 0
gmrun.dBorder: 0
//altblue

View File

@ -1,208 +0,0 @@
gmrun 0.9.4w http://students.infoiasi.ro/~mishoo/site/gmrun.epl
------------ ---------------------------------------------------
Short GtkEntry for file autocompletion + main.cc that does the
needed stuff for running programs. This is intended as a
replacement to grun or gnome-run, which (sorry) sucks. The idea
comes from the KDE Window Manager (ALT-F2 in KDE). Though, GNOME
is better :)
Copyright (c) 2000-2003 Mihai Bazon
Author: Mihai Bazon <mishoo@infoiasi.ro>.
send postcards to:
Mihai Bazon,
str. Republicii, nr. 350, sc. E, ap. 9, cod 6500 VASLUI - VASLUI
Romania
This program falls under the GNU General Public License version 2 or above.
Features
---------
* Tilda completion (~/ <==> $HOME/)
* Completion works for separate words (e.g. you can type em<TAB> which
turns to emacs, type a SPACE, and write the file you want to open using
completion).
* I added history capability (limited to 20 entries, change history.cc for
more, #define HIST_MAX_SIZE). History is maintained in the file "
~/.gmrun_history ".
CHANGED (since 0.5.3, I think..) -- new config file parameter: History.
* CTRL-Enter runs the command in a terminal. CTRL-Enter without any
command starts a new terminal.
* New configuration file: ~/.gmrunrc or /usr/local/share/gmrun/gmrunrc.
Check one of them, configuration is very simple. From that file you
can change window position and width, history size, terminal, URL
handlers, etc.
* You can use CTRL-R / CTRL-S to search through history, much like in bash
or Emacs. Also, pressing "!" as the first character enters some special
search mode, finding those history entries that begin with the entered
text.
* URL handlers (added in 0.6.0). Nice feature, allowing you to enter
lines like "http://www.google.com" to start your favorite browser on
www.google.com. The URL-s are configurable from the configuration
file, in a simple manner (I hope..).
* Extension handlers (added in 0.8.0). Basically you can run, for
instance, a ".txt" file, assuming that you have configured a handler for
it in the configuration file. The default handler for ".txt" files is,
of course, Emacs. But you can easily change that, you... you VIM user!
* UTF-8 support (added in 0.9.2)
Requirements
-------------
* A good C++ compiler (that is, g++ 3.0 or later). It did originally
compile with g++ 2.95, but not anymore ;-] -- though that's easy to fix.
* GTK-2. gmrun upto and including 0.8.1 were for GTK-1.x series, version
0.9.0 requires GTK-2.
For code critics
-----------------
This program is written in 2 hours. The code might seem a little weird,
but it works, and that's what I'm interested in. Code completion is
written in C++, although GTK+ is written in standard C. Should you think
this is a problem, feel free to rewrite the code in C (it could be at
least 4 times bigger).
It uses some static data (I know, I'm a too lasy programmer to think about
something better); this means that if you're having *two or more*
GtkCompletionLine-s in a program, you're looking for trouble. The static
data will be *shared* between them, and completion might not work
correctly. However, I don't know for sure, and I'm not going to test
this.
Having all that said, you should know that I'm not actually a bad
programmer ;-] The problem being too simple for huge code complications, I
preferred the easy way of doing different kind of things. It works quite
fine, so "don't expect tons of C code for completion" (quoted from some
sources in mini-commander applet of GNOME).
Compilation, installation
--------------------------
Use the configure script:
$ ./configure
$ make
$ make install
After this the executable goes usually in /usr/local/bin, make sure this is
in your path. Put this in your .sawmillrc:
(require 'sawmill-defaults)
(bind-keys global-keymap "S-C-M-RET" '(system "gmrun &"))
Note that if you're using sawfish you have other ways to customize your
keyboard, through the control panel.
For another window managers you gonna have to find a way to bind this
program to a key combination; otherwise it wouldn't be much help... (I
coded it exactly to get rid of the mouse-time-wasting-walking).
E.g. for IceWM (my favorite, at this time) you edit ~/.icewm/preferences
and add a line like:
KeySysRun="Alt+Ctrl+Shift+Enter"
Tips and tricks (hope that doesn't sound MS-ish...)
----------------------------------------------------
1. Everything that doesn't start with "/" or "~" gets completed from $PATH
environment var. More exactly, all files from $PATH directories are
subjects to completion (even if they are NOT executables; this is a
bug, but I'm afraid I'm not willing to fix it).
Pressing TAB once when no text is entered opens the completion window,
which will contain ALL files under $PATH.
2. For instance you use TAB to complete from "nets" to "netscape-navigator".
A small window appears, allowing you to select from:
- netscape
- netscape-communicator
- netscape-navigator
- netstat
That is because all these executables have the same prefix, "nets". You
type TAB twice to get to the third element ("netscape-navigator"). Now,
if you want to add a parameter such as "-url http://blah.blah.org" you
can press SPACE (the list disappears, and a SPACE is inserted after the
netscape-navigator).
3. If you accidentally pressed TAB more than you wanted (in that small
window, described above) you can use UP / DOWN arrows to select the right
completion.
4. - ESC closes the completion window, leaving the selected text in the entry.
- HOME / END - the same, but clears the selection.
- SPACE - the same, but clears the selection and appends one space.
- Pressing ENTER (anytime) runs the command that is written in the entry.
- Pressing CTRL+Enter (anytime) runs the command in a terminal (check your
configuration file). But if the entry is empty (no text is present, or
only whitespaces) then a fresh terminal will be started.
5. Suppose you use CTRL-R to search backwards through history. If,
accidentally, you skipped the line that you're interested in, you can use
CTRL-S to search forward. This is more awesome than in bash :) It
basically acts like a filter on history, for which you use CTRL-R instead
of UP arrow, and CTRL-S instead of DOWN arrow.
The same if you search something with "!": only lines that BEGIN with the
entered text are matching, but you can reverse the search order using
CTRL-R / CTRL-S. Very flexible approach.
Bugs
-----
* It gets pretty slow... Maybe I should consider writting it in ANSI-C,
but.... maybe not.
* Writting this README took me more time than writting the program.
* As I mentioned before, the code is written in C++, although GTK+ is a
C library. This is not actually a bug; I like C++ because programs
become clearer and easier to maintain, not to mention the source file
size is smaller. So, if anyone cares to port this to standard C, feel
free to do it, but I fear the code should be rewritten (almost) from
scratch.
* Documentation is inexistent (except this file) (however, it would be
quite useless).
Should you have any problems mail me a detailed description; please put
the text "ignore_me" in the subject line, for easy message filtering. :)
(just kidding... I would gladely help if I can).
* Actually I worked more than 2 hours. Anyway, the completion code took
about 2-3 h to design and implement.
Disclaimer
-----------
* The Short Way:
NO WARRANTIES OF ANY KIND. USE IT AT YOUR OWN RISK.
* The Right Way:
Please read the GNU General Public License. This program falls under
its terms.
(: END OF TERMS AND CONDITIONS :)

90
README.md Normal file
View File

@ -0,0 +1,90 @@
GMRUN
-----
A run utiliy featuring a slim design and bash style auto-completion.
Features
---------
* Tilda completion (~/ <==> $HOME/)
* Completion works for separate words (e.g. you can type em<TAB> which
turns to emacs, type a SPACE, and write the file you want to open using
completion).
* Configuration file: ~/.gmrunrc or /etc/gmrunrc.
Check one of them, configuration is very simple. From that file you
can change window position and width, history size, terminal, URL
handlers, etc.
* CTRL-Enter runs the command in a terminal.
* CTRL-Enter without any command starts a new terminal.
* History is maintained in the file "~/.gmrun_history".
* CTRL-R to search backwards through history.
* CTRL-S to search forward through history.
* "!" enters a special search mode, matching only the start of strings.
-- Esc to cancel search (only once).
-- CTRL-G to cancel search and clear the text entry
* URL handlers allowing you to enter lines like "http://www.google.com"
to start your favorite browser on www.google.com.
The URL-s are configurable from the configuration file.
* Extension handlers. Basically you can run, for instance,
a ".txt" file, assuming that you have configured a handler for it
in the configuration file.
Requirements
-------------
* GTK 2/3
Compilation, installation
--------------------------
Use the configure script (run ./autogen.sh if ./configure is missing):
./configure --prefix=/usr --sysconfdir=/etc
make
make install
By default it will use the GTK3 ui if it's available.
Pass `--enable-gtk2` to `./configure` to build the gtk2 ui
Optionally you can configure your window manager to call gmrun
with WinKey + R or something.
Tips and tricks
---------------
1. Everything that doesn't start with "/" or "~" gets completed from $PATH
environment var. More exactly, all files from $PATH directories are
subjects to completion.
Pressing TAB once when no text is entered opens the completion window,
which will contain ALL files under $PATH.
2. For instance you use TAB to complete from "nets" to "netscape-navigator".
A small window appears, allowing you to select from:
- netscape
- netscape-navigator
- netstat
That is because all these executables have the same prefix, "nets".
You can use UP / DOWN arrows to select the right completion.
You can use CTRL-P / CTRL-N or TAB to select the right completion.
3. - ESC closes the completion window, leaving the selected text in the entry.
- HOME / END - the same, but clears the selection.
- SPACE - the same, but clears the selection and appends one space.
- Pressing ENTER (anytime) runs the command that is written in the entry.
- Pressing CTRL+Enter (anytime) runs the command in a terminal (check your
configuration file). But if the entry is empty (no text is present, or
only whitespaces) then a fresh terminal will be started.

View File

@ -1,14 +1,61 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
#Get all required m4 macros required for configure
libtoolize -ci
aclocal
if test "$1" == "release" || test "$1" == "--release" ; then
pkg="$(grep -m1 AC_INIT configure.ac | cut -f 2 -d '[' | cut -f 1 -d ']')"
ver="$(grep -m1 AC_INIT configure.ac | cut -f 3 -d '[' | cut -f 1 -d ']')"
ver=$(echo $ver)
dir=${pkg}-${ver}
rm -rf ../$dir
mkdir -p ../$dir
cp -rf $PWD/* ../$dir
( cd ../$dir ; ./autogen.sh )
cd ..
tar -Jcf ${dir}.tar.xz $dir
exit
fi
#generate configure
autoconf
#===========================================================================
#Generate config.h.in
autoheader
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
cd $srcdir
#Generate Makefile.in's
automake -ac
test -z "$AUTOMAKE" && AUTOMAKE=automake
test -z "$ACLOCAL" && ACLOCAL=aclocal
test -z "$AUTOCONF" && AUTOCONF=autoconf
test -z "$AUTOHEADER" && AUTOHEADER=autoheader
test -z "$LIBTOOLIZE" && LIBTOOLIZE=$(which libtoolize glibtoolize 2>/dev/null | head -1)
test -z "$LIBTOOLIZE" && LIBTOOLIZE=libtoolize #paranoid precaution
if test "$1" == "verbose" || test "$1" == "--verbose" ; then
set -x
verbose='--verbose'
verbose2='--debug'
fi
# Get all required m4 macros required for configure
$LIBTOOLIZE ${verbose} --copy --force || exit 1
$ACLOCAL ${verbose} -I m4 || exit 1
# Generate config.h.in
$AUTOHEADER ${verbose} --force || exit 1
# Generate Makefile.in's
touch config.rpath
$AUTOMAKE ${verbose} --add-missing --copy --force || exit 1
if grep "IT_PROG_INTLTOOL" configure.ac >/dev/null ; then
intltoolize ${verbose2} -c --automake --force || exit 1
# po/Makefile.in.in has these lines:
# mostlyclean:
# rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp
# prevent $(GETTEXT_PACKAGE).pot from being deleted by `make clean`
sed 's/pox \$(GETTEXT_PACKAGE).pot/pox/' po/Makefile.in.in > po/Makefile.in.inx
mv -f po/Makefile.in.inx po/Makefile.in.in
fi
# generate configure
$AUTOCONF ${verbose} --force || exit 1
rm -rf autom4te.cache

View File

@ -1,26 +1,21 @@
# Process this file with autoconf to produce a configure script.
AC_INIT([gmrun], [0.9.5w])
AC_INIT([gmrun], [1.1w])
AM_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE([-Wall foreign])
AC_CONFIG_MACRO_DIR([m4])
AM_MAINTAINER_MODE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
m4_ifdef([AM_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
LT_INIT
AC_ISC_POSIX
AC_PROG_CC
AM_PROG_CC_STDC
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_PROG_CXX
AC_ARG_ENABLE(debug,
[ --enable-debug=[no/yes] Debugging information == no <--> optimization == yes],[],
enable_debug=no)
if [ ! test "x$enable_debug" != "xyes"]; then
CFLAGS="-g3 -O0 -DDEBUG"
CXXFLAGS="-g3 -O0 -DDEBUG"
if [ ! test "x$enable_debug" != xyes]; then
CFLAGS="-g -DDEBUG"
fi
AC_ARG_ENABLE(mtrace,
@ -29,18 +24,60 @@ AC_ARG_ENABLE(mtrace,
if [ ! test "x$enable_mtrace" != "xyes"]; then
CFLAGS="$CFLAGS -DMTRACE"
CXXFLAGS="$CXXFLAGS -DMTRACE"
fi
PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.10)
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
#========================================================================
PREFIX=${prefix}
AC_SUBST(PREFIX)
GTK3_CHECK="gtk+-3.0 >= 3.4.0"
GTK2_CHECK="gtk+-2.0 >= 2.12.0"
AC_ARG_ENABLE(gtk3,
AS_HELP_STRING([--disable-gtk3],[build with GTK3 (Autodetect)]),[],
[enable_gtk3=check])
AC_ARG_ENABLE(gtk2,
AS_HELP_STRING([--enable-gtk2],[build with GTK2 (Autodetect)]),[],
[enable_gtk2=check])
AS_IF([test "x$enable_gtk3" = xyes],
[enable_gtk2=no])
AS_IF([test "x$enable_gtk2" = xyes],
[enable_gtk3=no])
AS_IF([test "x$enable_gtk3" = xcheck],
[PKG_CHECK_MODULES([GTK],[$GTK3_CHECK],
[enable_gtk3=yes],[enable_gtk3=no])])
AS_IF([test "x$enable_gtk3" = xyes],
[
gtk_modules="$GTK3_CHECK"
gtk_version="gtk+-3.0"
errmsg="GTK3 is not installed, use --enable-gtk2 to build with GTK2"
],
[
gtk_modules="$GTK2_CHECK"
gtk_version="gtk+-2.0"
errmsg="GTK2 is not installed, use --enable-gtk3 to build with GTK3"
CPPFLAGS="$CPPFLAGS -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES -DGTK_DISABLE_DEPRECATED -DGTK_DISABLE_SINGLE_INCLUDES"
])
PKG_CHECK_MODULES([GTK], [$gtk_modules], [], [AC_ERROR([$errmsg])])
AC_SUBST([GTK_CFLAGS])
AC_SUBST([GTK_LIBS])
#========================================================================
case "$CC" in
gcc*) CPPFLAGS="$CPPFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers" ;;
*) ;;
esac
AC_OUTPUT([
Makefile
data/Makefile
src/Makefile
])
echo
echo "GTK Version: $(pkg-config --modversion $gtk_version)"
echo

14
data/Makefile.am Normal file
View File

@ -0,0 +1,14 @@
## Process this file with automake to produce Makefile.in
appdir = $(datadir)/applications
app_DATA = gmrun.desktop
icondir = $(datadir)/pixmaps
icon_DATA = gmrun.png
manualdir = $(mandir)/man1
manual_DATA = gmrun.1
myrcdir = @sysconfdir@
myrc_DATA = gmrunrc
EXTRA_DIST = gmrunrc

72
data/gmrun.1 Normal file
View File

@ -0,0 +1,72 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH gmrun 1.1w "2021"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
gmrun \- Featureful CLI-like GTK+ application launcher
.SH SYNOPSIS
.B gmrun \fR\fI[TEXT]\fR
.br
.SH DESCRIPTION
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
\fBgmrun\fP is a GTK program that allows a user to use a CLI-like interface to launch applications.
.SH OPTIONS
If gmrun is invoked with a command-line parameter, that will be the initial content of the dialog box.
.PP
gmrun can be customized using a configuration file, ~/.gmrunrc . The system-wide configuration file is /etc/gmrunrc .
.PP
The format of the configuration file is simple; "variable = value".
.TP
.B Example:
variable1 = foobar
.br
.TP
.B Terminal
The command to run when Ctrl+Enter is pressed with no command entered; used to start a new terminal.
.TP
.B TermExec
The command to run when Ctrl+Enter is pressed with a command entered. The entered command is supplied as an argument to TermExec.
.TP
.B Geometry
see /etc/gmrunrc for more info
.TP
.B History
Number of entered commands which should be kept in gmrun's history(~/.gmrun_history). Using the Up and Down arrow keys within the gmrun window will cycle through the history. You can search backwards through the history with Ctrl+R, and forward with Ctrl+S. Hit "!" to enter a special search that matches only the start of strings. To cancel a search, hit the \fIESC\fP key. Otherwise, after you have found the history item you wish to run, hit Enter. Also: CTRL-P = Up / CTRL-N = Down.
.TP
.B ShowLast
Whether to show the last command as initial text, or an empty textarea (1 or 0).
.TP
.B Selected
Whether the initial text should be selected or not (1 or 0).
.SH URL/File HANDLING
.TP
.B USE_GLIB_XDG = 1
For automatic URL and File handling using the freedesktop specification.
.TP
See /etc/gmrunrc for custom URL and extension handlers (USE_GLIB_XDG = 0)
.TP
The included configuration files have a few examples which you can work with. You should also note that the protocol part of URL_protocol can be *anything*. You can set up "URL_foobarbazcustom", and so long as you enter in "foobarbazcustom:<whatever>", it will use the given program.
.SH SEE ALSO
.BR /etc/gmrunrc.
.br
.SH AUTHOR
Originally written by
.B Mihai Bazon
, the latest version is available from
\fIhttps://github.com/wdlkmpx/gmrun/\fP
.PP
This manual page was originally written by David B Harris <david@eelf.ddts.net>

9
data/gmrun.desktop Normal file
View File

@ -0,0 +1,9 @@
[Desktop Entry]
Name=gmrun
Icon=gmrun.png
Comment=execute a command
Exec=gmrun
Terminal=false
Type=Application
Categories=TerminalEmulator
GenericName=gmrun

BIN
data/gmrun.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

62
data/gmrunrc Normal file
View File

@ -0,0 +1,62 @@
# gmrun configuration file
# Set terminal
Terminal = xterm
TermExec = ${Terminal} -e
AlwaysInTerm = ssh telnet ftp lynx mc vi vim pine centericq perldoc man
# Set window geometry
# - Wx width 400x
# - WxH width x height 400x70 (height = 0 = ignore)
# - WxH+x+y width x height +x +y 400x0+200+100
#
# If +x+y is not specified (or not allowed), the gmrun window is displayed centered
Geometry = 450x
# History size
History = 256
# Shows last history line selected when invoked
ShowLast = 0
# Show files starting with '.'
# Default is 0 (off), set it to 1 if you want "hidden" files to show up
# in the completion window
ShowDotFiles = 0
# Timeout (in milliseconds) after which gmrun will simulate a TAB press
# Set this to NULL if don't like this feature.
TabTimeout = 0
# Use libc's system(3) to run commands, this includes any shell command
# and special stuff that only a shell interpreter can understand
# Set to 0 if you want a more conservative approach where the file to run
# is validated and errors running files are reported (without closing the gmrun window)
SHELL_RUN = 1
# use GLib XDG handling? (freedesktop specification)
USE_GLIB_XDG = 0
#=======================================================================
# USE_GLIB_XDG = 0, you can specify URL and extension Handlers...
#=======================================================================
# URL handlers
# If the entered text is "http://www.google.com" then:
# - %u gets replaced with the whole URL ("http://www.google.com")
# - %s gets replaced with "//www.google.com".
# useful for URL's like "man:printf" --> %s becomes printf
URL_http = xdg-open '%u'
URL_mailto = xdg-email '%u'
URL_file = xdg-open '%s'
URL_man = ${TermExec} man %s
URL_info = ${TermExec} info %s
URL_search = xdg-open 'http://www.google.com/search?q=%s'
# extension handlers
# Customize your own extension handler.
# syntax-> EXT:ext,etc = handler '%s'
EXT:doc,rtf,txt,cc,cpp,h,java,html,htm,epl,tex,latex,js,css,xml,xsl,am,ps,pdf = xdg-open '%s'
EXT:mkv,mp4,avi,asf,wmv = xdg-open '%s'
EXT:mp3,flac,ogg,aac,wav = xdg-open '%s'

39
data/zmtrace.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <https://unlicense.org>
# ./data/zmtrace.sh
if ! test -f autogen.sh ; then
exit
fi
if ! test -f configure ; then
./autogen.sh;
fi
export MALLOC_TRACE=$(pwd)/mtrace.txt
if ! test -f src/gmrun ; then
./configure --prefix=/usr --enable-mtrace;
make;
fi
./src/gmrun;
mtrace=
for i in $(echo $PATH | tr ':' ' ')
do
if test -x $i/mtrace ; then
mtrace=$i/mtrace;
break;
fi
done
if test "x${mtrace}" != "x" ; then
mtrace src/gmrun mtrace.txt > mtrace-out.txt;
printf "see mtrace-out.txt\n";
else
printf "mtrace is missing\n";
printf "see mtrace.txt\n"
fi

View File

@ -1,27 +0,0 @@
<?xml version="1.0"?>
<GTK-Interface>
<project>
<name>Gmrun</name>
<program_name>gmrun</program_name>
<directory></directory>
<source_directory>src</source_directory>
<pixmaps_directory>pixmaps</pixmaps_directory>
<language>C</language>
<gnome_support>False</gnome_support>
<gettext_support>False</gettext_support>
<use_widget_names>False</use_widget_names>
<output_main_file>False</output_main_file>
<output_support_files>False</output_support_files>
<output_build_files>True</output_build_files>
<backup_source_files>False</backup_source_files>
<main_source_file>interface.c</main_source_file>
<main_header_file>interface.h</main_header_file>
<handler_source_file>callbacks.c</handler_source_file>
<handler_header_file>callbacks.h</handler_header_file>
<support_source_file>support.c</support_source_file>
<support_header_file>support.h</support_header_file>
<translatable_strings_file></translatable_strings_file>
</project>
</GTK-Interface>

54
gmrunrc
View File

@ -1,54 +0,0 @@
# gmrun configuration file
# gmrun is (C) Mihai Bazon, <mishoo@infoiasi.ro>
# GPL v2.0 applies
# Set terminal
Terminal = gnome-terminal --start-factory-server --use-factory
TermExec = ${Terminal} -e
AlwaysInTerm = ssh telnet ftp lynx mc vi vim pine centericq perldoc man
# Set window geometry (except height)
Width = 400
Top = 100
Left = 200
# Place window centered by the size of screen
CenteredByWidth = 0
CenteredByHeight = 0
# Place window on active monitor
UseActiveMonitor = 0
# History size
History = 256
# Shows last history line selected when invoked
ShowLast = 0
# Show files starting with '.'
# Default is 0 (off), set it to 1 if you want "hidden" files to show up
# in the completion window
ShowDotFiles = 0
# Timeout (in milliseconds) after which gmrun will simulate a TAB press
# Set this to NULL if don't like this feature.
TabTimeout = 0
# URL handlers
# If the entered text is "http://www.google.com" then:
# - %u gets replaced with the whole URL ("http://www.google.com")
# - %s gets replaced with "//www.google.com". This is useful for URL-s
# like "man:printf" --> %s will get replaced with "printf"
URL_http = mozilla -remote "openURL(%u, new-window)"
URL_mailto = mozilla -remote "mailto(%s)"
URL_man = ${TermExec} 'man %s'
URL_info = ${TermExec} 'info %s'
URL_pd = ${TermExec} 'perldoc %s'
URL_file = nautilus %s
URL_readme = ${TermExec} 'less /usr/doc/%s/README'
URL_info = ${TermExec} 'info %s'
URL_sh = sh -c '%s'
# extension handlers
EXT:doc,rtf = AbiWord %s
EXT:txt,cc,cpp,h,java,html,htm,epl,tex,latex,js,css,xml,xsl,am = emacs %s
EXT:ps = gv %s
EXT:pdf = xpdf %s

View File

@ -4,11 +4,10 @@ AM_CPPFLAGS = @GTK_CFLAGS@
bin_PROGRAMS = gmrun
gmrun_SOURCES = \
gtkcompletionline.cc gtkcompletionline.h \
history.cc history.h \
main.cc main.h \
prefs.cc prefs.h ci_string.h
gmrun_SOURCES = config_prefs.c \
history.c \
gtkcompletionline.c \
main.c
# gmrun_LDFLAGS = -s

24
src/Makefile.true Normal file
View File

@ -0,0 +1,24 @@
PROGRAM = gmrun
OBJS = config_prefs.o gtkcompletionline.o history.o main.o
BIN_PATH = /usr/local/bin
CC = gcc
CFLAGS = `pkg-config gtk+-2.0 --cflags` -Wall -O2
LIBS = `pkg-config gtk+-2.0 --libs`
all: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(PROGRAM) $(LIBS)
strip:
strip $(PROGRAM)
clean:
rm -f *.o *~ $(PROGRAM)
install:
mkdir -p $(DESTDIR)$(BIN_PATH)
install $(PROGRAM) $(DESTDIR)$(BIN_PATH)
uninstall:
rm -i $(DESTDIR)$(BIN_PATH)/$(PROGRAM)

View File

@ -1,41 +0,0 @@
// $Id: ci_string.h,v 1.2 2001/05/16 14:39:31 mishoo Exp $
// This is a very nice class, probably because it's not coded by me ;=]~
// Provide a case-insensitive std::string-like class.
#ifndef __CI_STRING_H__
#define __CI_STRING_H__
#include <string.h>
#include <ctype.h>
struct ci_char_traits : public std::char_traits<char>
{
static bool eq( char c1, char c2 ) {
return ::tolower(c1) == ::tolower(c2);
}
static bool ne( char c1, char c2 ) {
return ::tolower(c1) != ::tolower(c2);
}
static bool lt( char c1, char c2 ) {
return ::tolower(c1) < ::tolower(c2);
}
static int compare( const char* s1,
const char* s2,
size_t n ) {
return strncasecmp( s1, s2, n );
}
static const char*
find( const char* s, int n, char a ) {
while ( n-- > 0 && ::tolower(*s) != ::tolower(a) ) ++s;
return s;
}
};
typedef std::basic_string<char, ci_char_traits> ci_string;
#endif // __CI_STRING_H__

356
src/config_prefs.c Normal file
View File

@ -0,0 +1,356 @@
/*
* This is free and unencumbered software released into the public domain.
*
* For more information, please refer to <https://unlicense.org>
*/
/*
* Read config file formatted like this:
*
* key1 = value1
* key2=value2
*
* It's possible to open several files with the same config
* The keys will be updated with thew new values.
* 'key' is not case sensitive
*/
#include "config_prefs.h"
#define APP_CONFIG_FILE "gmrunrc"
// ============================================================
// PRIVATE
// ============================================================
static GList * PrefsGList = NULL;
static GList * ExtensionGList = NULL;
struct _pref_item
{
char * key;
char * value;
};
typedef struct _pref_item pref_item;
static void pref_item_free (pref_item * item)
{
if (item) {
if (item->key) free (item->key);
if (item->value) free (item->value);
free (item);
}
}
static void pref_item_free_cb (gpointer data)
{
pref_item_free ((pref_item *) data);
}
static GList * config_find_key (GList * list, const char * key)
{
GList *i;
pref_item * item;
if (!key || !*key) { /* ignore empty keys (strings) */
return (NULL);
}
for (i = list; i; i = i->next)
{
item = (pref_item *) (i->data);
if (strcasecmp (key, item->key) == 0) {
return (i);
}
}
return (NULL); /* key not found */
}
static void config_replace_key (GList ** list, pref_item * item)
{
GList * found = config_find_key (*list, item->key);
if (found) {
/* only update found item */
pref_item * found_item = (pref_item *) (found->data);
if (strcmp (found_item->value, item->value) == 0) {
pref_item_free (item);
return; /* values are equal, nothing to update */
}
free (found_item->value);
found_item->value = strdup (item->value);
pref_item_free (item);
} else {
/* append item */
*list = g_list_append (*list, (gpointer) item);
}
}
/** get value, it's always a string **/
static char * config_get_item_value (GList * list, const char * key)
{
GList * ret;
pref_item * item;
ret = config_find_key (list, key);
if (ret) {
item = (pref_item *) (ret->data);
return (item->value);
}
return (NULL); /* key not found */
}
static void config_load_from_file (const char * filename, GList ** out_list)
{
FILE *fp;
char buf[1024];
char * stripped;
char ** keyvalue;
pref_item * item;
fp = fopen (filename, "r");
if (!fp) {
return;
}
/* Read file line by line */
while (fgets (buf, sizeof (buf), fp))
{
stripped = buf;
while (*stripped && *stripped <= 0x20) { // 32 = space
stripped++;
}
if (strlen (stripped) < 3 || *stripped == '#') {
continue;
}
if (!strchr (stripped, '=')) {
continue;
}
item = (pref_item *) calloc (1, sizeof (pref_item));
keyvalue = g_strsplit (stripped, "=", 2);
item->key = g_strstrip (keyvalue[0]);
item->value = g_strstrip (keyvalue[1]);
if (!*item->key || !*item->value) {
g_strfreev (keyvalue);
free (item);
continue;
}
/// fprintf (stderr, "### %s = %s\n", key, value);
/* Insert or replace item */
config_replace_key (out_list, item);
}
fclose (fp);
return;
}
static void create_extension_handler_list (void)
{
GList * i;
pref_item * item, * item_out;
char ** str_vector;
for (i = PrefsGList; i; i = i->next)
{
item = (pref_item *) (i->data);
if (strncasecmp (item->key, "EXT:", 4) == 0)
{
int w;
str_vector = g_strsplit (item->key + 4, ",", 0);
for (w = 0; str_vector[w]; w++)
{
item_out = (pref_item *) calloc (1, sizeof (pref_item));
item_out->key = strdup (str_vector[w]);
item_out->value = strdup (item->value);
config_replace_key (&ExtensionGList, item_out);
}
g_strfreev (str_vector);
}
}
}
static char * replace_variable (char * txt) /* config_get_string_expanded() */
{
// pre${variable}post : ${Terminal} -e ...
char * pre = NULL, * post = NULL;
char * variable = NULL;
char * variable_value = NULL;
char * new_text = NULL;
char * p, * p2;
if (strlen (txt) < 5) { // at least ${xx}
return (NULL);
}
p = strstr (txt, "${");
if (!p) {
return (NULL); // syntax error
}
if (!strchr (p + 3, '}')) {
return (NULL); // syntax error
}
if (txt[0] != '$' && txt[1] != '$') {
pre = strdup (txt);
p2 = strchr (pre, '$');
if (p2) p2 = 0;
}
variable = strdup (p + 2); // variable start
p2 = strchr (variable, '}'); // variable end
*p2 = 0; // `Terminal`
post = p2 + 1; // ` -e ...`
variable_value = config_get_item_value (PrefsGList, variable); // xterm
if (variable_value) {
if (pre) {
// pre xterm -e ...
new_text = g_strconcat (pre, variable_value, post, NULL);
} else {
// xterm -e ...
new_text = g_strconcat (variable_value, post, NULL);
}
}
if (pre) free (pre);
if (variable) free (variable);
return (new_text);
}
// ============================================================
// PUBLIC
// ============================================================
void config_init ()
{
if (PrefsGList) {
return;
}
char config_file[512];
char * HOME;
snprintf (config_file, sizeof (config_file), "/etc/%s", APP_CONFIG_FILE);
config_load_from_file (config_file, &PrefsGList);
HOME = getenv ("HOME");
if (HOME) {
snprintf (config_file, sizeof (config_file), "%s/.%s", HOME, APP_CONFIG_FILE);
config_load_from_file (config_file, &PrefsGList);
}
create_extension_handler_list ();
}
void config_destroy ()
{
if (PrefsGList) {
g_list_free_full (PrefsGList, pref_item_free_cb);
g_list_free_full (ExtensionGList, pref_item_free_cb);
PrefsGList = NULL;
ExtensionGList = NULL;
}
}
void config_reload ()
{
config_destroy ();
config_init ();
}
void config_print ()
{
GList * i;
pref_item * item;
for (i = PrefsGList; i; i = i->next)
{
item = (pref_item *) (i->data);
printf ("%s = %s\n", item->key, item->value);
}
for (i = ExtensionGList; i; i = i->next)
{
item = (pref_item *) (i->data);
printf ("%s = %s\n", item->key, item->value);
}
}
gboolean config_get_int (const char * key, int * out_int)
{
char * value;
value = config_get_item_value (PrefsGList, key);
if (value) {
*out_int = (int) strtoll (value, NULL, 0);
return TRUE;
} else {
*out_int = -1;
return FALSE;
}
}
// returns a string that must be freed with g_free
gboolean config_get_string_expanded (const char * key, char ** out_str)
{
char * value1, * value2, * value = NULL;
value1 = config_get_item_value (PrefsGList, key);
if (value1 && strstr (value1, "${")) {
value2 = replace_variable (value1);
value = value2;
// expand variable up to 2 times
if (value2 && strstr (value2, "${")) {
value = replace_variable (value2);
free (value2);
}
} else {
value = strdup (value1);
}
if (value) {
*out_str = value;
return TRUE;
} else {
*out_str = NULL;
return FALSE;
}
}
gboolean config_get_string (const char * key, char ** out_str)
{
char * value;
value = config_get_item_value (PrefsGList, key);
if (value) {
*out_str = value;
return TRUE;
} else {
*out_str = NULL;
return FALSE;
}
}
char * config_get_handler_for_extension (const char * extension)
{
char * handler;
if (extension && *extension == '.') {
extension++; // .html -> html
}
handler = config_get_item_value (ExtensionGList, extension);
return (handler);
}

41
src/config_prefs.h Normal file
View File

@ -0,0 +1,41 @@
/*
* This is free and unencumbered software released into the public domain.
*
* For more information, please refer to <https://unlicense.org>
*/
#ifndef __CONFIG_PREFS_H
#define __CONFIG_PREFS_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "gtkcompat.h" // glib-compat.h
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void config_init ();
void config_destroy ();
void config_reload ();
void config_print ();
gboolean config_get_int (const char * key, int * out_int);
/// changes string pointer (must not be freed)
gboolean config_get_string (const char * key, char ** out_str);
/// allocates a string that must be freed with g_free
gboolean config_get_string_expanded (const char * key, char ** out_str);
/// returns a constant string (must not be freed)
char * config_get_handler_for_extension (const char * extension);
#ifdef __cplusplus
}
#endif
#endif

467
src/gtkcompat.h Normal file
View File

@ -0,0 +1,467 @@
/*
* This is free and unencumbered software released into the public domain.
*
* For more information, please refer to <https://unlicense.org>
*/
/** 2020-12-29 **/
/*
* gtkcompat.h, GTK2+ compatibility layer
*
* This lib makes it easier to support older GTK versions
* while still avoiding deprecated functions as much as possible.
*
* The older the GTK version, the more compatible functions are "defined"
* so it's not wise to use the compiled binary in newer distros or something.
*
* Apps should support gtk2 >= 2.14 / gtk3 >= 3.14
*
*/
/*
special defines:
gtkcompat_widget_set_halign_left (w)
gtkcompat_widget_set_halign_center (w)
gtkcompat_widget_set_halign_right (w)
*/
/*
GTKCOMPAT_DRAW_SIGNAL (gtk3="draw", gtk2="expose_event")
---------------------
g_signal_connect (w, GTKCOMPAT_DRAW_SIGNAL, G_CALLBACK (w_draw_cb), NULL);
gboolean w_draw_cb (GtkWidget *w, gpointer compat, gpointer user_data)
{
#if GTK_CHECK_VERSION (3, 0, 0)
cairo_t * cr = (cairo_t *) compat;
#else // gtk2
//GdkEventExpose * event = (GdkEventExpose *) compat;
cairo_t * cr = gdk_cairo_create (gtk_widget_get_window (w));
#endif
#if GTK_MAJOR_VERSION == 2
cairo_destroy (cr);
#endif
}
*/
#ifndef __GTKCOMPAT_H
#define __GTKCOMPAT_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#if GTK_MAJOR_VERSION == 3
#include <gdk/gdkkeysyms-compat.h>
#endif
/* ================================================== */
/* GLIB */
/* ================================================== */
#ifndef __GLIB_COMPAT_H
#define __GLIB_COMPAT_H
#include <glib.h>
// GLIB < 2.58
#if ! GLIB_CHECK_VERSION (2, 58, 0)
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
#endif
// GLIB < 2.32
#if ! GLIB_CHECK_VERSION (2, 32, 0)
#define G_SOURCE_REMOVE FALSE
#define G_SOURCE_CONTINUE TRUE
#define GRecMutex GStaticRecMutex
#define g_rec_mutex_init(x) g_static_rec_mutex_init(x)
#define g_rec_mutex_lock(x) g_static_rec_mutex_lock(x)
#define g_rec_mutex_trylock(x) g_static_rec_mutex_trylock(x)
#define g_rec_mutex_unlock(x) g_static_rec_mutex_unlock(x)
#define g_rec_mutex_clear(x) g_static_rec_mutex_free(x)
#define g_thread_new(name,func,data) g_thread_create(func,data,TRUE,NULL)
#define g_thread_try_new(name,func,data,error) g_thread_create(func,data,TRUE,error)
#define g_hash_table_add(ht,key) g_hash_table_replace(ht,key,key)
#define g_hash_table_contains(ht,key) g_hash_table_lookup_extended(ht,key,NULL,NULL)
#endif
// GMutex vs GStaticMutex
#if GLIB_CHECK_VERSION (2, 32, 0)
// since version 2.32.0 GMutex can be statically allocated
// don't use WGMutex to replace GMutex * ... issues, errors.
# define WGMutex GMutex
# define Wg_mutex_init g_mutex_init
# define Wg_mutex_lock g_mutex_lock
# define Wg_mutex_trylock g_mutex_trylock
# define Wg_mutex_unlock g_mutex_unlock
# define Wg_mutex_clear g_mutex_clear
#else
# define WGMutex GStaticMutex
# define Wg_mutex_init g_static_mutex_init
# define Wg_mutex_lock g_static_mutex_lock
# define Wg_mutex_trylock g_static_mutex_trylock
# define Wg_mutex_unlock g_static_mutex_unlock
# define Wg_mutex_clear g_static_mutex_free
// sed -i 's%g_mutex_%Wg_mutex_%g' $(grep "g_mutex_" *.c *.h | cut -f 1 -d ":" | grep -v -E 'gtkcompat|glib-compat' | sort -u)
#endif
// GLIB < 2.30
#if ! GLIB_CHECK_VERSION (2, 30, 0)
#define g_format_size g_format_size_for_display
#endif
// GLIB < 2.28
#if ! GLIB_CHECK_VERSION (2, 28, 0)
#define g_list_free_full(list,free_func) {\
g_list_foreach (list, (GFunc) free_func, NULL);\
g_list_free (list);\
}
#endif
// GLIB < 2.22
#if ! GLIB_CHECK_VERSION (2, 22, 0)
#define g_mapped_file_unref(x) g_mapped_file_free(x)
#endif
// GLIB < 2.20
#if ! GLIB_CHECK_VERSION (2, 20, 0)
#define g_app_info_get_commandline(app) g_app_info_get_executable(app)
#endif
/* glib 2.18+ tested */
#endif /* __GLIB_COMPAT_H */
/* ================================================== */
/* GTK 3 */
/* ================================================== */
// GTK >= 3.0 -- applies to GTK3, GTK4...
#if GTK_CHECK_VERSION (3, 0, 0)
#define GTKCOMPAT_DRAW_SIGNAL "draw"
#define gtkcompat_widget_set_halign_left(w) gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_START)
#define gtkcompat_widget_set_halign_center(w) gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_CENTER)
#define gtkcompat_widget_set_halign_right(w) gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_END)
/* some compatible deprecated GTK2 functions... */
#define gtk_hbox_new(homogenous,spacing) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,spacing)
#define gtk_vbox_new(homogenous,spacing) gtk_box_new(GTK_ORIENTATION_VERTICAL,spacing)
#define gtk_hscale_new(adjustment) gtk_scale_new(GTK_ORIENTATION_HORIZONTAL,adjustment)
#define gtk_vscale_new(adjustment) gtk_scale_new(GTK_ORIENTATION_VERTICAL,adjustment)
#define gtk_hscale_new_with_range(min,max,step) gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,min,max,step)
#define gtk_vscale_new_with_range(min,max,step) gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL,min,max,step)
#define gtk_hseparator_new() gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)
#define gtk_vseparator_new() gtk_separator_new(GTK_ORIENTATION_VERTICAL)
#define gtk_hscrollbar_new(adj) gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL,adj)
#define gtk_vscrollbar_new(adj) gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL,adj)
#define gtk_hpaned_new() gtk_paned_new(GTK_ORIENTATION_HORIZONTAL)
#define gtk_vpaned_new() gtk_paned_new(GTK_ORIENTATION_VERTICAL)
#endif
// GTK < 3.12
#if ! GTK_CHECK_VERSION (3, 12, 0)
#define gtk_widget_set_margin_start(widget,margin) gtk_widget_set_margin_left(widget,margin)
#define gtk_widget_set_margin_end(widget,margin) gtk_widget_set_margin_right(widget,margin)
#endif
// GTK < 3.4
#if ! GTK_CHECK_VERSION (3, 4, 0)
#define gtk_application_window_new(app) gtk_window_new(GTK_WINDOW_TOPLEVEL)
#endif
/* ================================================== */
/* GTK 2 */
/* ================================================== */
// define some GTK3+ functions
#if GTK_MAJOR_VERSION <= 2
#define GTKCOMPAT_DRAW_SIGNAL "expose_event"
#define gtk_box_new(ori,spacing) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hbox_new(FALSE,spacing) \
: gtk_vbox_new(FALSE,spacing))
#define gtk_button_box_new(ori) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hbutton_box_new() \
: gtk_vbutton_box_new())
#define gtk_scale_new(ori,adjustment) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hscale_new(adjustment) \
: gtk_vscale_new(adjustment))
#define gtk_scale_new_with_range(ori,min,max,step) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hscale_new_with_range(min,max,step) \
: gtk_vscale_new_with_range(min,max,step))
#define gtk_separator_new(ori) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hseparator_new() \
: gtk_vseparator_new())
#define gtk_scrollbar_new(ori,adjustment) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hscrollbar_new(adjustment) \
: gtk_vscrollbar_new(adjustment))
#define gtk_paned_new(ori) \
((ori == GTK_ORIENTATION_HORIZONTAL) ? gtk_hpaned_new() \
: gtk_vpaned_new())
#define gtk_widget_get_allocated_height(widget) (GTK_WIDGET(widget)->allocation.height )
#define gtk_widget_get_allocated_width(widget) (GTK_WIDGET(widget)->allocation.width )
#define gtk_combo_box_text_remove_all(cmb) { \
GtkTreeModel * model = gtk_combo_box_get_model (GTK_COMBO_BOX (cmb)); \
gtk_list_store_clear (GTK_LIST_STORE (model)); \
}
#define gtk_tree_model_iter_previous(model,iter) ({ \
GtkTreePath * path = gtk_tree_model_get_path (model, iter); \
gboolean valid = gtk_tree_path_prev (path); \
if (valid) gtk_tree_model_get_iter (model, iter, path); \
gtk_tree_path_free (path); \
valid; \
})
#define gtk_widget_override_font(w,f) gtk_widget_modify_font(w,f)
#define gtkcompat_widget_set_halign_left(w) gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5)
#define gtkcompat_widget_set_halign_center(w) gtk_misc_set_alignment(GTK_MISC(w), 0.5, 0.5)
#define gtkcompat_widget_set_halign_right(w) gtk_misc_set_alignment(GTK_MISC(w), 1.0, 0.5)
/* GtkApplication */
#define GtkApplication void
#define g_application_quit(app) gtk_main_quit()
#undef G_APPLICATION
#define G_APPLICATION(app) ((void *) (app))
#endif
// GTK < 2.24
#if ! GTK_CHECK_VERSION (2, 24, 0)
typedef struct _GtkComboBox GtkComboBoxText;
typedef struct _GtkComboBoxClass GtkComboBoxTextClass;
typedef struct _GtkComboBoxPrivate GtkComboBoxTextPrivate;
#define GTK_TYPE_COMBO_BOX_TEXT (gtk_combo_box_get_type ())
#define GTK_COMBO_BOX_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxText))
#define GTK_COMBO_BOX_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COMBO_BOX, GtkComboBoxTextClass))
#define GTK_IS_COMBO_BOX_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COMBO_BOX))
#define GTK_IS_COMBO_BOX_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COMBO_BOX))
#define GTK_COMBO_BOX_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxTextClass))
#define gtk_combo_box_text_new() gtk_combo_box_new_text()
#define gtk_combo_box_text_new_with_entry() gtk_combo_box_entry_new_text()
#define gtk_combo_box_text_append_text(combo,text) gtk_combo_box_append_text(combo,text)
#define gtk_combo_box_text_insert_text(combo,pos,text) gtk_combo_box_insert_text(combo,pos,text)
#define gtk_combo_box_text_prepend_text(combo,text) gtk_combo_box_prepend_text(combo,text)
#define gtk_combo_box_text_remove(combo,pos) gtk_combo_box_remove_text(combo,pos)
#define gtk_combo_box_text_get_active_text(combo) (gtk_combo_box_get_active_text(combo))
#define gtk_combo_box_get_has_entry(combo) (0)
#define gtk_combo_box_set_entry_text_column(combo,cl)
#define gtk_combo_box_get_entry_text_column(combo) (0)
#define gtk_range_get_round_digits(range) (GTK_RANGE(range)->round_digits)
//#define gdk_window_get_visual(w) (gdk_drawable_get_visual(GDK_DRAWABLE(w)))
#define gdk_window_get_screen(w) (gdk_drawable_get_screen(GDK_DRAWABLE(w)))
#define gdk_window_get_display(w) (gdk_drawable_get_display(GDK_DRAWABLE(w)))
#endif
// GTK < 2.22
#if ! GTK_CHECK_VERSION (2, 22, 0)
#define gtk_window_has_group(w) (GTK_WINDOW(w)->group != NULL)
#define gtk_window_group_get_current_grab(wg) \
((GTK_WINDOW_GROUP(wg)->grabs) ? GTK_WIDGET(GTK_WINDOW_GROUP(wg)->grabs->data) : NULL)
#define gtk_font_selection_dialog_get_font_selection(fsd)(GTK_FONT_SELECTION_DIALOG(fsd)->fontsel)
#define gtk_notebook_get_tab_hborder(n) (GTK_NOTEBOOK(n)->tab_hborder)
#define gtk_notebook_get_tab_vborder(n) (GTK_NOTEBOOK(n)->tab_vborder)
#define gtk_button_get_event_window(button) (GTK_BUTTON(button)->event_window)
#define gdk_visual_get_visual_type(visual) (GDK_VISUAL(visual)->type)
#define gdk_visual_get_depth(visual) (GDK_VISUAL(visual)->depth)
#define gdk_visual_get_byte_order(visual) (GDK_VISUAL(visual)->byte_order)
#define gdk_visual_get_colormap_size(visual) (GDK_VISUAL(visual)->colormap_size)
#define gdk_visual_get_bits_per_rgb(visual) (GDK_VISUAL(visual)->bits_per_rgb)
#endif
// GTK < 2.20
#if ! GTK_CHECK_VERSION (2, 20, 0)
#define gtk_widget_get_mapped(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_MAPPED) != 0)
#define gtk_widget_get_realized(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_REALIZED) != 0)
#define gtk_window_get_window_type(window) (GTK_WINDOW(window)->type)
#define gtk_widget_get_requisition(w,r) (*(r) = GTK_WIDGET(w)->requisition)
#define gtk_widget_set_mapped(w,yes) { \
if (yes) GTK_WIDGET_SET_FLAGS(w,GTK_MAPPED); \
else GTK_WIDGET_UNSET_FLAGS(w,GTK_MAPPED); \
}
#define gtk_widget_set_realized(w,yes) { \
if (yes) GTK_WIDGET_SET_FLAGS(w,GTK_REALIZED); \
else GTK_WIDGET_UNSET_FLAGS(w,GTK_REALIZED); \
}
#define gtk_range_get_slider_size_fixed(range) (GTK_RANGE(range)->slider_size_fixed)
#define gtk_range_get_min_slider_size(range) (GTK_RANGE(range)->min_slider_size)
#define gtk_entry_get_text_window(entry) (GTK_ENTRY(entry)->text_area)
#endif
// GTK < 2.18
#if ! GTK_CHECK_VERSION (2, 18, 0)
#define gtk_widget_get_state(wid) (GTK_WIDGET (wid)->state)
#define gtk_widget_is_toplevel(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_TOPLEVEL) != 0)
#define gtk_widget_get_has_window(wid) !((GTK_WIDGET_FLAGS (wid) & GTK_NO_WINDOW) != 0)
#define gtk_widget_get_visible(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_VISIBLE) != 0)
#define gtk_widget_is_drawable(wid) (GTK_WIDGET_VISIBLE (wid) && GTK_WIDGET_MAPPED (wid))
#define gtk_widget_get_sensitive(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_SENSITIVE) != 0)
#define gtk_widget_get_can_focus(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_CAN_FOCUS) != 0)
#define gtk_widget_has_focus(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_HAS_FOCUS) != 0)
#define gtk_widget_get_can_default(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_CAN_DEFAULT) != 0)
#define gtk_widget_get_receives_default(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_RECEIVES_DEFAULT) != 0)
#define gtk_widget_has_default(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_HAS_DEFAULT) != 0)
#define gtk_widget_has_grab(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_HAS_GRAB) != 0)
#define gtk_widget_get_app_paintable(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_APP_PAINTABLE) != 0)
#define gtk_widget_get_double_buffered(wid) ((GTK_WIDGET_FLAGS (wid) & GTK_DOUBLE_BUFFERED) != 0)
#define gtk_widget_set_allocation(w,alloc) (GTK_WIDGET(w)->allocation = *(alloc))
#define gtk_widget_get_allocation(w,alloc) (*(alloc) = GTK_WIDGET(w)->allocation)
#define gtk_widget_set_can_default(w,yes) { \
if (yes) GTK_WIDGET_SET_FLAGS(w,GTK_CAN_DEFAULT); \
else GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_DEFAULT); \
}
#define gtk_widget_set_can_focus(w,yes) { \
if (yes) GTK_WIDGET_SET_FLAGS(w,GTK_CAN_FOCUS); \
else GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS); \
}
#define gtk_widget_set_has_window(w,yes) { \
if (yes) GTK_WIDGET_UNSET_FLAGS(w,GTK_NO_WINDOW); \
else GTK_WIDGET_SET_FLAGS(w,GTK_NO_WINDOW); \
}
#define gtk_widget_set_visible(w,yes) { \
if (yes) gtk_widget_show(w); \
else gtk_widget_hide(w); \
}
#define gtk_range_get_flippable(range) (GTK_RANGE(range)->flippable)
#define gdk_window_is_destroyed(w) (GDK_WINDOW_DESTROYED (GDK_WINDOW(w)))
#endif
// GTK < 2.16
#if ! GTK_CHECK_VERSION (2, 16, 0)
#define gtk_status_icon_set_tooltip_text(icon,text) gtk_status_icon_set_tooltip(icon,text)
#define gtk_menu_item_get_label(i) (gtk_label_get_label (GTK_LABEL (GTK_BIN (i)->child)))
#define gtk_menu_item_set_label(i,label) gtk_label_set_label(GTK_LABEL(GTK_BIN(i)->child), (label) ? label : "")
#define gtk_menu_item_get_use_underline(i) (gtk_label_get_use_underline (GTK_LABEL (GTK_BIN (i)->child)))
#endif
// GTK < 2.14
#if ! GTK_CHECK_VERSION (2, 14, 0)
#define gtk_dialog_get_action_area(dialog) (GTK_DIALOG(dialog)->action_area)
#define gtk_dialog_get_content_area(dialog) (GTK_DIALOG(dialog)->vbox)
#define gtk_widget_get_window(widget) (GTK_WIDGET(widget)->window)
#define gtk_window_get_default_widget(window) (GTK_WINDOW(window)->default_widget)
#define gtk_menu_item_get_accel_path(i) (GTK_MENU_ITEM(i)->accel_path)
#define gtk_menu_get_accel_path(menu) (GTK_MENU(menu)->accel_path)
#define gtk_message_dialog_get_image(m) (GTK_MESSAGE_DIALOG(m)->image)
#define gtk_entry_get_overwrite_mode(e) (GTK_ENTRY(e)->overwrite_mode)
#endif
/* ================================================== */
/* GDK KEYS */
/* ================================================== */
#ifndef GDK_KEY_a
# define GDK_KEY_Control_R GDK_Control_R
# define GDK_KEY_Control_L GDK_Control_L
# define GDK_KEY_Shift_R GDK_Shift_R
# define GDK_KEY_Shift_L GDK_Shift_L
# define GDK_KEY_Alt_R GDK_Alt_R
# define GDK_KEY_Alt_L GDK_Alt_L
# define GDK_KEY_Tab GDK_Tab
# define GDK_KEY_Up GDK_Up
# define GDK_KEY_space GDK_space
# define GDK_KEY_Down GDK_Down
# define GDK_KEY_Return GDK_Return
# define GDK_KEY_exclam GDK_exclam
# define GDK_KEY_BackSpace GDK_BackSpace
# define GDK_KEY_Home GDK_Home
# define GDK_KEY_End GDK_End
# define GDK_KEY_Escape GDK_Escape
# define GDK_KEY_a GDK_a
# define GDK_KEY_A GDK_A
# define GDK_KEY_b GDK_b
# define GDK_KEY_B GDK_B
# define GDK_KEY_c GDK_c
# define GDK_KEY_C GDK_C
# define GDK_KEY_d GDK_d
# define GDK_KEY_D GDK_D
# define GDK_KEY_e GDK_e
# define GDK_KEY_E GDK_E
# define GDK_KEY_f GDK_F
# define GDK_KEY_g GDK_g
# define GDK_KEY_G GDK_G
# define GDK_KEY_h GDK_h
# define GDK_KEY_H GDK_H
# define GDK_KEY_i GDK_i
# define GDK_KEY_I GDK_I
# define GDK_KEY_j GDK_j
# define GDK_KEY_J GDK_J
# define GDK_KEY_k GDK_k
# define GDK_KEY_K GDK_K
# define GDK_KEY_l GDK_l
# define GDK_KEY_L GDK_L
# define GDK_KEY_m GDK_m
# define GDK_KEY_M GDK_M
# define GDK_KEY_n GDK_n
# define GDK_KEY_N GDK_N
# define GDK_KEY_o GDK_o
# define GDK_KEY_O GDK_O
# define GDK_KEY_p GDK_p
# define GDK_KEY_P GDK_P
# define GDK_KEY_q GDK_q
# define GDK_KEY_Q GDK_Q
# define GDK_KEY_r GDK_r
# define GDK_KEY_R GDK_R
# define GDK_KEY_s GDK_s
# define GDK_KEY_S GDK_S
# define GDK_KEY_t GDK_t
# define GDK_KEY_T GDK_T
# define GDK_KEY_u GDK_u
# define GDK_KEY_U GDK_U
# define GDK_KEY_v GDK_v
# define GDK_KEY_V GDK_V
# define GDK_KEY_w GDK_w
# define GDK_KEY_W GDK_W
# define GDK_KEY_x GDK_x
# define GDK_KEY_X GDK_X
# define GDK_KEY_y GDK_y
# define GDK_KEY_Y GDK_Y
# define GDK_KEY_z GDK_z
# define GDK_KEY_Z GDK_Z
# define GDK_KEY_exclam GDK_exclam
# define GDK_KEY_F1 GDK_F1
# define GDK_KEY_F2 GDK_F2
# define GDK_KEY_F3 GDK_F3
# define GDK_KEY_F4 GDK_F4
# define GDK_KEY_F5 GDK_F5
# define GDK_KEY_F6 GDK_F6
# define GDK_KEY_F7 GDK_F7
# define GDK_KEY_F8 GDK_F8
# define GDK_KEY_F9 GDK_F9
# define GDK_KEY_F10 GDK_F10
# define GDK_KEY_F11 GDK_F11
# define GDK_KEY_F12 GDK_F12
#endif
// PANGO
#ifndef PANGO_WEIGHT_MEDIUM
#define PANGO_WEIGHT_MEDIUM 500
#endif
#ifdef __cplusplus
}
#endif
#endif /* __GTKCOMPAT_H */

1133
src/gtkcompletionline.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +1,84 @@
/*****************************************************************************
* $Id: gtkcompletionline.h,v 1.12 2003/11/16 10:43:32 andreas99 Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/
/*
* Copyright 2020 Mihai Bazon
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided that
* the above copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef __GTKCOMPLETIONLINE_H__
#define __GTKCOMPLETIONLINE_H__
#include <gtk/gtkentry.h>
#include <string>
#include "gtkcompat.h"
#include "history.h"
extern "C++" {
#ifdef __cplusplus
extern "C"
{
#endif
#define GTK_COMPLETION_LINE(obj) \
GTK_CHECK_CAST(obj, gtk_completion_line_get_type(), GtkCompletionLine)
#define GTK_COMPLETION_LINE_CLASS(klass) \
GTK_CHECK_CLASS_CAST(klass, gtk_completion_line_get_type(), GtkCompletionLineClass)
#define IS_GTK_COMPLETION_LINE(obj) \
GTK_CHECK_TYPE(obj, gtk_completion_line_get_type())
#define GTK_COMPLETION_LINE(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_completion_line_get_type(), GtkCompletionLine)
#define GTK_COMPLETION_LINE_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_completion_line_get_type(), GtkCompletionLineClass)
#define IS_GTK_COMPLETION_LINE(obj) GTK_CHECK_TYPE(obj, gtk_completion_line_get_type())
typedef struct _GtkCompletionLine GtkCompletionLine;
typedef struct _GtkCompletionLineClass GtkCompletionLineClass;
typedef struct _GtkCompletionLine GtkCompletionLine;
typedef struct _GtkCompletionLineClass GtkCompletionLineClass;
enum GCL_SEARCH_MODE
{
GCL_SEARCH_OFF = 0,
GCL_SEARCH_REW = 1,
GCL_SEARCH_FWD = 2,
GCL_SEARCH_BEG = 3
};
#define MAX_HISTWORD_CHARS 1024
struct _GtkCompletionLine
{
GtkEntry parent;
GtkWidget *win_compl;
GtkWidget *list_compl;
int list_compl_items_where;
int list_compl_nr_rows;
int pos_in_text;
struct _GtkCompletionLine
{
GtkEntry parent;
GtkWidget * win_compl;
GtkListStore * list_compl;
GtkTreeModel * sort_list_compl;
GtkWidget * tree_compl;
GtkTreeIter list_compl_it;
int pos_in_text; /* Cursor position in main "line" */
HistoryFile * hist;
gboolean hist_search_mode;
gboolean hist_search_match_start;
char hist_word[MAX_HISTWORD_CHARS]; /* history search: word that is being typed */
int hist_word_count; /* history search: word that is being typed */
GList *cmpl;
GList *where;
int tabtimeout;
int show_dot_files;
};
HistoryFile *hist;
GCL_SEARCH_MODE hist_search_mode;
std::string *hist_word;
int first_key;
int tabtimeout;
int show_dot_files;
};
struct _GtkCompletionLineClass
{
GtkEntryClass parent_class;
/* add your CLASS members here */
void (* unique) (GtkCompletionLine *cl);
void (* notunique) (GtkCompletionLine *cl);
void (* incomplete) (GtkCompletionLine *cl);
void (* runwithterm) (GtkCompletionLine *cl);
void (* search_mode) (GtkCompletionLine *cl);
void (* search_letter) (GtkCompletionLine *cl);
void (* search_not_found) (GtkCompletionLine *cl);
void (* ext_handler) (GtkCompletionLine *cl);
void (* cancel) (GtkCompletionLine *cl);
};
struct _GtkCompletionLineClass
{
GtkEntryClass parent_class;
/* add your CLASS members here */
void (* unique)(GtkCompletionLine *cl);
void (* notunique)(GtkCompletionLine *cl);
void (* incomplete)(GtkCompletionLine *cl);
void (* runwithterm)(GtkCompletionLine *cl);
void (* search_mode)(GtkCompletionLine *cl);
void (* search_letter)(GtkCompletionLine *cl);
void (* search_not_found)(GtkCompletionLine *cl);
void (* ext_handler)(GtkCompletionLine *cl);
void (* cancel)(GtkCompletionLine *cl);
};
GType gtk_completion_line_get_type (void);
GtkWidget * gtk_completion_line_new ();
void gtk_completion_line_last_history_item (GtkCompletionLine*);
GType gtk_completion_line_get_type(void);
GtkWidget *gtk_completion_line_new();
void gtk_completion_line_last_history_item(GtkCompletionLine*);
#ifdef __cplusplus
}
#endif
#endif /* __GTKCOMPLETIONLINE_H__ */
// Local Variables: ***
// mode: c++ ***
// c-basic-offset: 2 ***
// End: ***

365
src/history.c Normal file
View File

@ -0,0 +1,365 @@
/*
* This is free and unencumbered software released into the public domain.
*
* For more information, please refer to <https://unlicense.org>
*/
/*
* - Generic implementation of HistoryFile
* - Loads history from file. Saves history to file.
* - Keeps track of the last entry, making it a bit more efficient
* - Only adding entries is supported ...
* - Supports maximum number of entries,
* The first entry is removed if the new entry exceeds the max count.
* - Does not allow duplicate strings
* This is not a good idea if the list is too long
* - If entry exists it's moved to the end of the list..
*
*/
#include "history.h"
// ============================================================
// PRIVATE
// ============================================================
struct _Whistory
{
long int index;
unsigned int count;
unsigned int max;
char * filename;
int has_changed;
int save_if_changed;
GList * list;
GList * list_end;
GList * current;
};
static void _history_clear (HistoryFile * history)
{
// keep history->filename (destroyed in _history_free())
if (history->list)
{
//g_list_free_full (history->list, free);
GList * i;
for (i = history->list; i; i = i->next) {
free (i->data);
}
g_list_free (history->list);
history->list = NULL;
history->has_changed = 1;
}
history->index = 0;
history->count = 0;
}
static void _history_free (HistoryFile * history)
{
_history_clear (history);
if (history->filename) {
free (history->filename);
history->filename = NULL;
}
free (history);
}
/// load entries from file and initialize private variables
static void _history_load_from_file (HistoryFile * history, const char * filename)
{
FILE *fp;
char buf[1024];
char * p, * item;
size_t len;
unsigned int count = 0;
unsigned int max = history->max;
GList * out_list = NULL;
fp = fopen (filename, "r");
if (!fp) {
return;
}
/* Read file line by line */
while (fgets (buf, sizeof (buf), fp))
{
p = buf;
while (*p && *p <= 0x20) { // 32 = space [ignore spaces]
p++;
}
if (!*p) {
continue;
}
item = strdup (p);
len = strlen (buf);
item[len-1] = 0;
if (max > 0 && count >= max) {
free (item);
break;
}
count++;
out_list = g_list_prepend (out_list, (gpointer) item);
}
if (out_list) {
history->list_end = out_list;
history->list = out_list;
if (out_list->next) {
history->list = g_list_reverse (out_list);
}
history->index = 1;
}
history->count = count;
history->current = history->list; // current = 1st item
fclose (fp);
return;
}
void _history_write_to_file (HistoryFile * history, const char * filename)
{
FILE *fp;
fp = fopen (filename, "w");
if (!fp) {
return;
}
GList * i;
for (i = history->list; i; i = i->next)
{
fprintf (fp, "%s\n", (char *) (i->data));
}
fclose (fp);
return;
}
// ============================================================
// PUBLIC
// ============================================================
HistoryFile * history_new (char * filename, unsigned int maxcount)
{
HistoryFile * history = calloc (1, sizeof (HistoryFile));
history->max = maxcount;
if (filename && *filename) {
history->filename = strdup (filename);
_history_load_from_file (history, filename);
}
return (history);
}
void history_save (HistoryFile * history, int save_if_changed)
{
if (history && history->filename) {
if (save_if_changed) {
if (history->has_changed) {
_history_write_to_file (history, history->filename);
} // else printf ("not saving!!\n");
} else {
_history_write_to_file (history, history->filename);
}
} else {
fprintf (stderr, "history_save(): history or filename is NULL\n");
}
}
void history_destroy (HistoryFile * history)
{
if (history) {
_history_free (history);
}
}
void history_reload (HistoryFile * history)
{
if (history) {
_history_clear (history);
if (history->filename) {
_history_load_from_file (history, history->filename);
}
history->has_changed = 0;
}
}
void history_print (HistoryFile * history)
{
if (history) {
unsigned int count = 0;
GList * i;
for (i = history->list; i; i = i->next) {
count++;
printf ("[%d] %s\n", count, (char *) (i->data));
}
printf ("-- list internal count: [%d]\n", history->count);
if (history->list_end) {
printf ("** list : %s\n", (char *) (history->list->data));
printf ("** list_end : %s\n", (char *) (history->list_end->data));
}
if (history->current) {
printf ("** list current : %s\n", (char *) (history->current->data));
}
}
}
// some apps might want to handle prev/next in a special way
void history_unset_current (HistoryFile * history)
{
if (history) {
history->current = NULL;
history->index = -1;
}
}
const char * history_get_current (HistoryFile * history)
{
if (history) return ((char*) (history->current->data));
else return (NULL);
}
int history_get_current_index (HistoryFile * history)
{
if (history) return (history->index);
else return (-1);
}
const char * history_next (HistoryFile * history)
{
if (history->current && history->current->next) {
history->current = history->current->next;
history->index++;
return ((char *) (history->current->data));
}
return (NULL);
}
const char * history_prev (HistoryFile * history)
{
if (history->current && history->current->prev) {
history->current = history->current->prev;
history->index--;
return ((char *) (history->current->data));
}
return (NULL);
}
const char * history_first (HistoryFile * history)
{
if (history->list) {
history->current = history->list;
history->index = 1;
return ((char *) (history->current->data));
}
return (NULL);
}
const char * history_last (HistoryFile * history)
{
if (history->list) {
history->current = history->list_end; // g_list_last (history->list);
return ((char *) (history->current->data));
history->index = history->count;
}
return (NULL);
}
void history_append (HistoryFile * history, const char * text)
{
if (!text || !*text) {
return;
}
GList * i, * templist;
char * ientry;
// if new entry = last entry, then abort
if (history->list_end) {
ientry = (char *) (history->list_end->data);
if (strcmp (text, ientry) == 0) {
return;
}
}
// do not allow duplicate entries, remove existing entry
for (i = history->list; i; i = i->next)
{
char * ientry = (char *) (i->data);
if (strcmp (text, ientry) == 0)
{
// entry already exists.. remove
free (i->data);
templist = g_list_delete_link (history->list, i);
if (!templist->prev) { // no previous entry.. new start
history->list = templist;
}
if (!templist->next) { // no next... only 1 entry
history->list_end = templist;
}
history->count--;
break;
}
// TODO: handle 'current'
}
// if new entry exceeds the max count, first entry will be removed
unsigned int remove_first = 0;
if (history->max > 0
&& history->count > 1
&& history->count >= history->max) {
remove_first = 1;
}
if (history->count < history->max) {
history->count++;
}
// add new item
char * new_item = strdup (text);
GList * position = history->list_end ? history->list_end : history->list;
position = g_list_append (position, (gpointer) new_item);
history->has_changed = 1;
if (!history->list) {
history->list = position; // first
history->current = history->list; // set current to first
history->index = 1;
}
if (history->list_end) {
history->list_end = history->list_end->next;
} else {
history->list_end = history->list; // first element has just been added
}
if (remove_first && history->list->next) {
// problem when removing the first entry - current may become invalid
if (history->current == history->list) {
history->current = history->list->next;
}
free (history->list->data);
history->list = g_list_delete_link (history->list, history->list);
}
}
void history_reverse (HistoryFile * history)
{
if (history && history->list) {
GList * prev_first = history->list;
history->list = g_list_reverse (history->list);
history->list_end = prev_first;
if (history->current == prev_first) {
history->current = history->list;
}
}
}

View File

@ -1,166 +0,0 @@
/*****************************************************************************
* $Id: history.cc,v 1.10 2002/08/17 13:19:31 mishoo Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/
#include <glib.h>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
#include "history.h"
#include "prefs.h"
HistoryFile::HistoryFile()
{
m_file_entries = 0;
m_filename = g_get_home_dir();
m_filename += "/.gmrun_history";
m_current = 0;
m_default_set = false;
read_the_file();
}
HistoryFile::~HistoryFile()
{}
void
HistoryFile::read_the_file()
{
const char *filename = m_filename.c_str();
ifstream f(filename);
if (!f) return;
string line_text;
while (!f.eof()) {
string line_str;
getline(f,line_text);
line_str = line_text;
history.push_back(line_str);
}
m_file_entries = history.size();
m_current = m_file_entries;
}
void
HistoryFile::sync_the_file()
{
const char *filename = m_filename.c_str();
int HIST_MAX_SIZE;
if (!configuration.get_int("History", HIST_MAX_SIZE))
HIST_MAX_SIZE = 20;
ofstream f(filename, ios::out);
int start = 0;
if (history.size() > (size_t)HIST_MAX_SIZE)
start = history.size() - HIST_MAX_SIZE;
for (size_t i = start; i < history.size(); i++)
if (history[i].length() != 0)
f << history[i] << endl;
f.flush();
}
void
HistoryFile::append(const char *entry)
{
std::string ent = std::string(entry);
if (!history.empty()) {
StrArray::reverse_iterator i;
#ifdef DEBUG
for_each(history.begin(), history.end(), DumpString(cerr));
#endif
i = find(history.rbegin(), history.rend(), ent);
if (i != history.rend()) {
#ifdef DEBUG
cerr << "erasing "<< ent << endl;
#endif
history.erase(remove(history.begin(), history.end(), ent));
}
}
history.push_back(ent);
}
void
HistoryFile::set_default(const char *defstr)
{
if (!m_default_set) {
m_default = defstr;
m_default_set = true;
}
}
const char *
HistoryFile::operator [] (size_t index)
{
if (index < 0 || index >= history.size()) {
return m_default.c_str();
}
return history[index].c_str();
}
const char *
HistoryFile::prev()
{
const char *ret = (*this)[--m_current];
if (m_current < 0) m_current = history.size();
return ret;
}
const char *
HistoryFile::next()
{
const char *ret = (*this)[++m_current];
if (m_current >= history.size()) m_current = -1;
return ret;
}
const char *
HistoryFile::prev_to_first()
{
if (m_current > 0) {
return (*this)[--m_current];
} else {
return NULL;
}
}
const char *
HistoryFile::next_to_last()
{
if (m_current < history.size()) {
return (*this)[++m_current];
} else {
return NULL;
}
}
void
HistoryFile::clear_default()
{
m_default_set = false;
}
void
HistoryFile::reset_position()
{
m_current = m_file_entries;
}

View File

@ -1,71 +1,86 @@
/*****************************************************************************
* $Id: history.h,v 1.11 2002/08/17 13:19:31 mishoo Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
/*
* This is free and unencumbered software released into the public domain.
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/
* For more information, please refer to <https://unlicense.org>
*/
/*
* Generic implementation of HistoryFile
*/
#ifndef __HISTORY_H__
#define __HISTORY_H__
#ifndef __HISTORY_H
#define __HISTORY_H
#include <vector>
#include <string>
using namespace std;
class HistoryFile
#ifdef __cplusplus
extern "C"
{
protected:
int m_file_entries;
string m_filename;
string m_default;
bool m_default_set;
int m_current;
#endif
typedef vector<string> StrArray;
StrArray history;
#include "gtkcompat.h"
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
public:
HistoryFile();
~HistoryFile();
typedef struct _Whistory HistoryFile;
void append(const char *entry);
void set_default(const char *defstr);
void clear_default();
void reset_position();
const char * operator [] (size_t index);
const char * prev();
const char * next();
const char * prev_to_first();
const char * next_to_last();
void sync_the_file();
inline const char* last_item() {
return history.empty() ? 0 : history.back().c_str();
}
inline const char* first_item() {
return history.empty() ? 0 : history.front().c_str();
}
protected:
void read_the_file();
private:
struct DumpString {
DumpString(std::ostream& o) : _out(o) {}
void operator()(std::string& str) { _out << str << endl; }
private:
std::ostream& _out;
};
enum
{
HISTORY_SAVE_ALWAYS,
HISTORY_SAVE_IF_CHANGED,
};
#endif // __HISTORY_H__
/// create a new HistoryFile
/// the history is initialized using filename and the filename is stored
/// maxcount > 0 sets a maximun item count
HistoryFile * history_new (char * filename, unsigned int maxcount);
/// save history to file, 0 = force save / 1 = save only if history has changed
void history_save (HistoryFile * history, int save_if_changed);
/// history is destroyed, you must variable to NULL
void history_destroy (HistoryFile * history);
/// clear history and reload from file
void history_reload (HistoryFile * history);
/// print history, good for debugging
void history_print (HistoryFile * history);
/// some apps might want to handle prev/next in a special way
void history_unset_current (HistoryFile * history);
/// returns string with the current history item
const char * history_get_current (HistoryFile * history);
/// returns current index: valid index > 0
/// assume unser current item if index <= 0
int history_get_current_index (HistoryFile * history);
/// moves position to the next entry and returns text
/// if there is no next entry, the position is not moved and returns NULL
const char * history_next (HistoryFile * history);
/// moves position to the previous entry and returns text
/// if there is no next entry, the position is not moved and returns NULL
const char * history_prev (HistoryFile * history);
/// moves position to the first entry en returns text
/// if there are no entries, it returns NULL
const char * history_first (HistoryFile * history);
/// moves position to the last entry en returns text
/// if there are no entries, it returns NULL
const char * history_last (HistoryFile * history);
/// add entry to history, if entry already exists, it's moved to the end of the list
void history_append (HistoryFile * history, const char * text);
void history_reverse (HistoryFile * history);
#ifdef __cplusplus
}
#endif
#endif

780
src/main.c Normal file
View File

@ -0,0 +1,780 @@
/*
* Copyright 2020 Mihai Bazon
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided that
* the above copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include <X11/Xlib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#ifdef MTRACE
#include <mcheck.h>
#endif
#include <unistd.h>
#include <errno.h>
#include "gtkcompletionline.h"
#include "config_prefs.h"
#define CMD_LENGTH 1024
enum
{
W_TEXT_STYLE_NORMAL,
W_TEXT_STYLE_NOTFOUND,
W_TEXT_STYLE_NOTUNIQUE,
W_TEXT_STYLE_UNIQUE,
};
GtkApplication * gmrun_app;
char * gmrun_text = NULL;
static void gmrun_exit (void);
GtkAllocation window_geom = { -1, -1, -1, -1 };
/* widgets that are used in several functions */
GtkWidget * compline;
GtkWidget * wlabel;
GtkWidget * wlabel_search;
/* preferences */
int USE_GLIB_XDG = 0;
int SHELL_RUN = 1;
/// BEGIN: TIMEOUT MANAGEMENT
static gboolean search_off_timeout ();
static guint g_search_off_timeout_id = 0;
static void remove_search_off_timeout (void)
{
if (g_search_off_timeout_id) {
g_source_remove(g_search_off_timeout_id);
g_search_off_timeout_id = 0;
}
}
static void add_search_off_timeout (guint32 timeout, GSourceFunc func)
{
remove_search_off_timeout();
if (!func)
func = (GSourceFunc) search_off_timeout;
g_search_off_timeout_id = g_timeout_add (timeout, func, NULL);
}
/// END: TIMEOUT MANAGEMENT
// https://unix.stackexchange.com/questions/457584/gtk3-change-text-color-in-a-label-raspberry-pi
static void set_info_text_color (GtkWidget *w, const char *text, int spec)
{
char *markup = NULL;
static const char * colors[] = {
"black", /* W_TEXT_STYLE_NORMAL */
"red", /* W_TEXT_STYLE_NOTFOUND */
"blue", /* W_TEXT_STYLE_NOTUNIQUE */
"green", /* W_TEXT_STYLE_UNIQUE */
};
markup = g_markup_printf_escaped ("<span foreground=\"%s\">%s</span>",
colors[spec], text);
if (markup) {
gtk_label_set_markup (GTK_LABEL (w), markup);
g_free(markup);
}
}
static void run_the_command (char * cmd)
{
#if DEBUG
fprintf (stderr, "command: %s\n", cmd);
#endif
if (SHELL_RUN)
{
// need to add extra &
if (strlen (cmd) < (CMD_LENGTH-10)) {
strcat (cmd, " &"); /* safe to use in this case */
}
int ret = system (cmd);
if (ret != -1) {
gmrun_exit ();
} else {
char errmsg[256];
snprintf (errmsg, sizeof(errmsg)-1, "ERROR: %s", strerror (errno));
set_info_text_color (wlabel, errmsg, W_TEXT_STYLE_NOTFOUND);
add_search_off_timeout (3000, NULL);
}
}
else // glib - more conservative approach and robust error reporting
{
GError * error = NULL;
gboolean success;
int argc;
char ** argv;
success = g_shell_parse_argv (cmd, &argc, &argv, &error);
if (!success) {
set_info_text_color (wlabel, error->message, W_TEXT_STYLE_NOTFOUND);
g_error_free (error);
add_search_off_timeout (3000, NULL);
return;
}
success = g_spawn_async (NULL, argv, NULL,
G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
if (argv) {
g_strfreev (argv);
}
if (success) {
gmrun_exit ();
} else {
set_info_text_color (wlabel, error->message, W_TEXT_STYLE_NOTFOUND);
g_error_free (error);
add_search_off_timeout (3000, NULL);
}
}
}
static void
on_ext_handler (GtkCompletionLine *cl, const char * filename)
{
if (USE_GLIB_XDG) // GLib XDG handling (freedesktop specification)
{
gchar * content_type, * mime_type, * msg;
const gchar * handler;
GAppInfo * app_info;
if (filename) {
content_type = g_content_type_guess (filename, NULL, 0, NULL);
if (content_type) {
mime_type = g_content_type_get_mime_type (content_type);
g_free (content_type);
app_info = g_app_info_get_default_for_type (mime_type, FALSE);
g_free (mime_type);
if (app_info) {
handler = g_app_info_get_commandline (app_info);
msg = g_strconcat("Handler: ", handler, NULL);
gtk_label_set_text (GTK_LABEL (wlabel_search), msg);
gtk_widget_show (wlabel_search);
g_object_unref(app_info);
g_free(msg);
return;
}
}
}
search_off_timeout();
}
else // custom EXT handlers
{
const char * ext = strrchr (filename, '.');
if (!ext) {
search_off_timeout ();
return;
}
const char * handler = config_get_handler_for_extension (ext);
if (handler) {
char * tmp = g_strconcat ("Handler: ", handler, NULL);
gtk_label_set_text (GTK_LABEL (wlabel_search), tmp);
gtk_widget_show (wlabel_search);
g_free (tmp);
}
}
}
static void on_compline_runwithterm (GtkCompletionLine *cl)
{
char cmd[CMD_LENGTH];
char * term;
char * entry_text = g_strdup (gtk_entry_get_text (GTK_ENTRY(cl)));
g_strstrip (entry_text);
if (*entry_text) {
if (config_get_string_expanded ("TermExec", &term)) {
snprintf (cmd, sizeof (cmd), "%s %s", term, entry_text);
g_free (term);
} else {
snprintf (cmd, sizeof (cmd), "xterm -e %s", entry_text);
}
} else {
if (config_get_string ("Terminal", &term)) {
strncpy (cmd, term, sizeof (cmd) - 1);
} else {
strncpy (cmd, "xterm", sizeof (cmd) - 1);
}
}
history_append (cl->hist, cmd);
run_the_command (cmd);
g_free (entry_text);
}
static gboolean search_off_timeout ()
{
set_info_text_color (wlabel, "Run program:", W_TEXT_STYLE_NORMAL);
gtk_widget_hide (wlabel_search);
g_search_off_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
on_compline_unique (GtkCompletionLine *cl)
{
set_info_text_color (wlabel, "unique", W_TEXT_STYLE_UNIQUE);
add_search_off_timeout (1000, NULL);
}
static void
on_compline_notunique (GtkCompletionLine *cl)
{
set_info_text_color (wlabel, "not unique", W_TEXT_STYLE_NOTUNIQUE);
add_search_off_timeout (1000, NULL);
}
static void
on_compline_incomplete (GtkCompletionLine *cl)
{
set_info_text_color (wlabel, "not found", W_TEXT_STYLE_NOTFOUND);
add_search_off_timeout (1000, NULL);
}
static void
on_search_mode (GtkCompletionLine *cl)
{
if (cl->hist_search_mode == TRUE) {
gtk_widget_show (wlabel_search);
gtk_label_set_text (GTK_LABEL (wlabel), "Search:");
gtk_label_set_text (GTK_LABEL (wlabel_search), cl->hist_word);
} else {
gtk_widget_hide (wlabel_search);
gtk_label_set_text (GTK_LABEL (wlabel), "Search OFF");
add_search_off_timeout (1000, NULL);
}
}
static void
on_search_letter(GtkCompletionLine *cl, GtkWidget *label)
{
gtk_label_set_text (GTK_LABEL(label), cl->hist_word);
}
static gboolean search_fail_timeout (gpointer user_data)
{
set_info_text_color (wlabel, "Search:", W_TEXT_STYLE_NOTUNIQUE);
g_search_off_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
on_search_not_found(GtkCompletionLine *cl)
{
set_info_text_color (wlabel, "Not Found!", W_TEXT_STYLE_NOTFOUND);
add_search_off_timeout (1000, (GSourceFunc) search_fail_timeout);
}
// =============================================================
static void xdg_app_run_command (GAppInfo *app, const gchar *args)
{
// get
char * cmd, * exe;
GRegex * regex;
regex = g_regex_new (".%[fFuUdDnNickvm]", G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL);
exe = g_regex_replace_literal (regex, // Remove xdg desktop files fields from app
g_app_info_get_commandline (app),
-1, 0, "", G_REGEX_MATCH_NOTEMPTY, NULL);
cmd = g_strconcat (exe, " ", args, NULL);
run_the_command (cmd); /* Launch the command */
g_regex_unref (regex);
g_free (exe);
g_free (cmd);
}
/* Handler for URLs */
static gboolean url_check (GtkCompletionLine *cl, char * entry_text)
{
if (USE_GLIB_XDG) // GLib XDG handling (freedesktop specification)
{
char * delim;
const char * url, * protocol;
GAppInfo * app;
delim = strchr (entry_text, ':');
if (!delim || !*(delim+1)) {
return FALSE;
}
protocol = entry_text;
url = delim + 1;
*delim = 0;
if (url[0] == '/' && url[1] == '/')
{
app = g_app_info_get_default_for_uri_scheme (protocol);
if (app) { // found known uri handler for protocol
*delim = ':';
xdg_app_run_command (app, entry_text);
history_append (cl->hist, entry_text);
g_object_unref (app);
} else {
char *tmp = g_strconcat ("No URL handler for [", protocol, "]", NULL);
set_info_text_color (wlabel, tmp, W_TEXT_STYLE_NOTFOUND);
add_search_off_timeout (1000, NULL);
g_free (tmp);
}
return TRUE;
}
*delim = ':';
return FALSE;
}
else //-------- custom URL handlers
{
// <url_type> <delim> <url>
// http : //www.fsf.org
// <f u l l u r l>
// config: URL_<url_type>
// handler %s (format 1) = run handler with <url>
// handler %u (format 2) = run handler with <full url>
char * cmd;
char * tmp, * delim, * p;
char * url, * url_type, * full_url, * chosen_url;
char * url_handler;
char * config_key;
cmd = tmp = delim = p = url_handler = config_key = NULL;
delim = strchr (entry_text, ':');
if (!delim || !*(delim+1)) {
return FALSE;
}
tmp = g_strdup (entry_text);
delim = strchr (tmp, ':');
*delim = 0;
url_type = tmp; // http
url = delim + 1; // //www.fsf.org
full_url = entry_text;
config_key = g_strconcat ("URL_", url_type, NULL);
if (config_get_string_expanded (config_key, &url_handler))
{
chosen_url = url;
p = strchr (url_handler, '%');
if (p) { // handler %s
p++;
if (*p == 'u') { // handler %u
*p = 's'; // convert %u to %s (for printf)
chosen_url = full_url;
}
cmd = g_strdup_printf (url_handler, chosen_url);
} else {
cmd = g_strconcat (url_handler, " ", url, NULL);
}
g_free (url_handler);
}
if (cmd) {
history_append (cl->hist, entry_text);
run_the_command (cmd);
g_free (cmd);
} else {
g_free (tmp);
tmp = g_strconcat ("No URL handler for [", config_key, "]", NULL);
set_info_text_color (wlabel, tmp, W_TEXT_STYLE_NOTFOUND);
add_search_off_timeout (1000, NULL);
}
g_free (config_key);
g_free (tmp);
return TRUE;
}
}
static char * escape_spaces (char * entry_text)
{ // run file with glib: replace " " with "\ "
GRegex * regex;
char * quoted;
if (!strstr (entry_text, "\\ ")) {
regex = g_regex_new (" ", G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL);
quoted = g_regex_replace_literal (regex, entry_text, -1, 0, "\\ ", G_REGEX_MATCH_NOTEMPTY, NULL);
g_regex_unref (regex);
} else {
quoted = strdup (entry_text); // already scaped, just duplicate text
}
return (quoted);
}
/* Handler for extensions */
static gboolean ext_check (GtkCompletionLine *cl, char * entry_text)
{
if (USE_GLIB_XDG) // GLib XDG handling (freedesktop specification)
{
char *quoted, *content_type, *mime_type;
GAppInfo *app_info;
gboolean sure;
quoted = escape_spaces (entry_text);
/* File is executable: launch it (fail silently if file isn't really executable) */
if (g_file_test (quoted, G_FILE_TEST_IS_EXECUTABLE)) {
run_the_command (quoted);
history_append (cl->hist, entry_text);
g_free (quoted);
return TRUE;
}
/* Check mime type through extension */
if (quoted[0] == '/' && strchr (quoted, '.')) {
content_type = g_content_type_guess (quoted, NULL, 0, &sure);
if (content_type) {
mime_type = g_content_type_get_mime_type (content_type);
g_free (content_type);
app_info = g_app_info_get_default_for_type (mime_type, FALSE);
g_free (mime_type);
if (app_info) { // found mime
xdg_app_run_command (app_info, quoted);
history_append (cl->hist, entry_text);
g_free (quoted);
g_object_unref(app_info);
return TRUE;
}
}
}
g_free (quoted);
return FALSE;
}
else //-------- custom EXTension handlers
{
// example: file.html | xdg-open '%s' -> xdg-open 'file.html'
char * cmd, * quoted;
char * ext = strrchr (entry_text, '.');
char * handler_format = NULL;
if (ext) {
handler_format = config_get_handler_for_extension (ext);
}
if (handler_format) {
quoted = g_strcompress (entry_text); /* unescape chars */
if (strstr (handler_format, "%s")) {
cmd = g_strdup_printf (handler_format, quoted);
}
else { // xdg-open
cmd = g_strconcat (handler_format, " '", quoted, "'", NULL);
}
history_append (cl->hist, entry_text);
run_the_command (cmd);
g_free (cmd);
g_free (quoted);
return TRUE;
}
return FALSE;
}
}
// =============================================================
static void on_compline_activated (GtkCompletionLine *cl)
{
char * entry_text = g_strdup (gtk_entry_get_text (GTK_ENTRY(cl)));
g_strstrip (entry_text);
if (url_check (cl, entry_text) == TRUE
|| ext_check (cl, entry_text) == TRUE) {
g_free (entry_text);
return;
}
char cmd[CMD_LENGTH];
char * AlwaysInTerm = NULL;
char ** term_progs = NULL;
char * selected_term_prog = NULL;
if (config_get_string ("AlwaysInTerm", &AlwaysInTerm))
{
term_progs = g_strsplit (AlwaysInTerm, " ", 0);
int i;
for (i = 0; term_progs[i]; i++) {
if (strcmp (term_progs[i], entry_text) == 0) {
selected_term_prog = g_strdup (term_progs[i]);
break;
}
}
g_strfreev (term_progs);
}
if (selected_term_prog) {
char * TermExec;
config_get_string_expanded ("TermExec", &TermExec);
snprintf (cmd, sizeof (cmd), "%s %s", TermExec, selected_term_prog);
g_free (selected_term_prog);
g_free (TermExec);
} else {
strncpy (cmd, entry_text, sizeof (cmd) - 1);
}
g_free (entry_text);
history_append (cl->hist, cmd);
run_the_command (cmd);
}
// =============================================================
static void gmrun_activate(void)
{
GtkWidget *dialog, * main_vbox;
GtkWidget *label_search;
GtkWidget * window = gtk_application_window_new (gmrun_app);
dialog = gtk_dialog_new();
gtk_window_set_transient_for( (GtkWindow*)dialog, (GtkWindow*)window );
gtk_widget_realize(dialog);
main_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
// this removes the title bar..
GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET(dialog));
gdk_window_set_decorations (gwin, GDK_DECOR_BORDER);
gtk_widget_set_name (GTK_WIDGET (dialog), "gmrun");
gtk_window_set_title (GTK_WINDOW(window), "A simple launcher with completion");
gtk_container_set_border_width(GTK_CONTAINER(dialog), 4);
g_signal_connect(G_OBJECT(dialog), "destroy",
G_CALLBACK(gmrun_exit), NULL);
GtkWidget *hhbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (main_vbox), hhbox, FALSE, FALSE, 0);
GtkWidget *label = gtk_label_new("Run program:");
gtk_box_pack_start (GTK_BOX(hhbox), label, FALSE, FALSE, 10);
gtkcompat_widget_set_halign_left (GTK_WIDGET (label));
wlabel = label;
label_search = gtk_label_new("");
gtk_box_pack_start (GTK_BOX (hhbox), label_search, FALSE, TRUE, 0);
wlabel_search = label_search;
compline = gtk_completion_line_new();
gtk_widget_set_name (compline, "gmrun_compline");
gtk_box_pack_start (GTK_BOX (main_vbox), compline, TRUE, TRUE, 0);
if (!config_get_int ("SHELL_RUN", &SHELL_RUN)) {
SHELL_RUN = 1;
}
// don't show files starting with "." by default
if (!config_get_int ("ShowDotFiles", &(GTK_COMPLETION_LINE(compline)->show_dot_files))) {
GTK_COMPLETION_LINE(compline)->show_dot_files = 0;
}
int tmp;
if (!config_get_int ("TabTimeout", &tmp)) {
((GtkCompletionLine*)compline)->tabtimeout = tmp;
}
if (!config_get_int ("USE_GLIB_XDG", &USE_GLIB_XDG)) {
USE_GLIB_XDG = 0;
}
g_signal_connect(G_OBJECT(compline), "cancel",
G_CALLBACK(gmrun_exit), NULL);
g_signal_connect(G_OBJECT(compline), "activate",
G_CALLBACK (on_compline_activated), NULL);
g_signal_connect(G_OBJECT(compline), "runwithterm",
G_CALLBACK (on_compline_runwithterm), NULL);
g_signal_connect(G_OBJECT(compline), "unique",
G_CALLBACK (on_compline_unique), NULL);
g_signal_connect(G_OBJECT(compline), "notunique",
G_CALLBACK (on_compline_notunique), NULL);
g_signal_connect(G_OBJECT(compline), "incomplete",
G_CALLBACK (on_compline_incomplete), NULL);
g_signal_connect(G_OBJECT(compline), "search_mode",
G_CALLBACK (on_search_mode), NULL);
g_signal_connect(G_OBJECT(compline), "search_not_found",
G_CALLBACK (on_search_not_found), NULL);
g_signal_connect(G_OBJECT(compline), "search_letter",
G_CALLBACK(on_search_letter), label_search);
g_signal_connect(G_OBJECT(compline), "ext_handler",
G_CALLBACK (on_ext_handler), NULL);
int shows_last_history_item;
if (!config_get_int ("ShowLast", &shows_last_history_item)) {
shows_last_history_item = 0;
}
if (gmrun_text) {
gtk_entry_set_text (GTK_ENTRY(compline), gmrun_text);
} else if (shows_last_history_item) {
gtk_completion_line_last_history_item (GTK_COMPLETION_LINE(compline));
}
// geometry: window position
if (window_geom.x > -1 || window_geom.y > -1) {
gtk_window_move (GTK_WINDOW (dialog), window_geom.x, window_geom.y);
} else {
/* default: centered */
gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ALWAYS);
}
// geometry: window size
if (window_geom.height > -1 || window_geom.width > -1) {
gtk_window_set_default_size (GTK_WINDOW (dialog), window_geom.width,
window_geom.height);
} else {
/* default width = 450 */
gtk_window_set_default_size (GTK_WINDOW (dialog), 450, -1);
}
// window icon
GError * error = NULL;
GtkIconTheme * theme = gtk_icon_theme_get_default ();
GdkPixbuf * icon = gtk_icon_theme_load_icon (theme, "gmrun", 48, GTK_ICON_LOOKUP_USE_BUILTIN, &error);
if (error) {
g_object_set (dialog, "icon-name", "gtk-execute", NULL);
g_error_free (error);
} else {
gtk_window_set_icon (GTK_WINDOW (dialog), icon);
g_object_unref (icon);
}
gtk_widget_show_all (dialog);
gtk_window_set_focus(GTK_WINDOW(dialog), compline);
}
// =============================================================
static void parse_command_line (int argc, char ** argv)
{
// --geometry / parse commandline options
static char *geometry_str = NULL;
GError *error = NULL;
GOptionContext *context = NULL;
static GOptionEntry entries[] =
{
{ "geometry", 'g', 0, G_OPTION_ARG_STRING, &geometry_str, "This option specifies the initial size and location of the window.", NULL, },
{ NULL },
};
context = g_option_context_new (NULL);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_add_group (context, gtk_get_option_group (TRUE));
if (!g_option_context_parse (context, &argc, &argv, &error))
{
g_print ("option parsing failed: %s\n", error->message);
if (context) g_option_context_free (context);
if (error) g_error_free (error);
if (geometry_str) g_free (geometry_str);
exit (1);
}
if (context) g_option_context_free (context);
if (error) g_error_free (error);
if (argc >= 2) {
gmrun_text = argv[1];
}
// --
if (!geometry_str)
{
// --geometry was not specified, see config file
char * geomstr;
if (config_get_string ("Geometry", &geomstr)) {
geometry_str = g_strdup (geomstr);
}
}
if (geometry_str)
{
// --geometry WxH+X+Y
// width x height + posX + posY
int width, height, posX, posY;
char *Wstr, *Hstr, *Xstr, *Ystr;
Wstr = Hstr = Xstr = Ystr = NULL;
Xstr = strchr (geometry_str, '+');
if (Xstr) { // +posX+posY
*Xstr = 0;
Xstr++; // posX+posY
Ystr = strchr (Xstr, '+');
if (Ystr) { // +posY
*Ystr = 0;
Ystr++; // posY
}
}
if (Xstr && Ystr && *Xstr && *Ystr) {
posX = strtoll (Xstr, NULL, 0);
posY = strtoll (Ystr, NULL, 0);
///fprintf (stderr, "x: %" G_GINT64_FORMAT "\ny: %" G_GINT64_FORMAT "\n", posX, posY);
window_geom.x = posX;
window_geom.y = posY;
}
Hstr = strchr (geometry_str, 'x');
if (Hstr) { // WxH
*Hstr = 0;
Hstr++; // H
Wstr = geometry_str;
width = strtoll (Wstr, NULL, 0);
height = strtoll (Hstr, NULL, 0);
///fprintf (stderr, "w: %" G_GINT64_FORMAT "\nh: %" G_GINT64_FORMAT "\n", width, height);
window_geom.width = width;
window_geom.height = height;
}
g_free (geometry_str);
}
}
// =============================================================
// MAIN
void gmrun_exit(void)
{
gtk_widget_destroy (compline);
config_destroy ();
g_application_quit (G_APPLICATION (gmrun_app));
}
int main(int argc, char **argv)
{
#ifdef MTRACE
mtrace();
#endif
int status = 0;
config_init ();
parse_command_line (argc, argv);
#if GTK_CHECK_VERSION(3, 4, 0)
// Handling cmd line args with GApplication is a nightmare
// follow this: https://developer.gnome.org/gtkmm-tutorial/stable/sec-multi-item-containers.html.en#boxes-command-line-options
argc = 1; /* hide args from GApplication */
gmrun_app = gtk_application_new ("org.gtk.gmrun", G_APPLICATION_NON_UNIQUE);
g_signal_connect (gmrun_app, "activate", gmrun_activate, NULL);
status = g_application_run (G_APPLICATION (gmrun_app), argc, argv);
g_object_unref (gmrun_app);
#else
gtk_init (&argc, &argv);
gmrun_activate ();
gtk_main ();
#endif
#ifdef MTRACE
muntrace();
#endif
return (status);
}

View File

@ -1,526 +0,0 @@
/*****************************************************************************
* $Id: main.cc,v 1.26 2003/11/16 10:55:07 andreas99 Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/
#include <X11/Xlib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
#ifdef MTRACE
#include <mcheck.h>
#endif
#include <unistd.h>
#include <errno.h>
#include "gtkcompletionline.h"
#include "prefs.h"
// defined in gtkcompletionline.cc
int get_words(GtkCompletionLine *object, vector<string>& words);
string quote_string(const string& str);
struct gigi
{
GtkWidget *w1;
GtkWidget *w2;
};
/// BEGIN: TIMEOUT MANAGEMENT
static gint search_off_timeout(struct gigi *g);
static guint g_search_off_timeout_id = 0;
static void remove_search_off_timeout()
{
if (g_search_off_timeout_id) {
gtk_timeout_remove(g_search_off_timeout_id);
g_search_off_timeout_id = 0;
}
}
static void add_search_off_timeout(guint32 timeout, struct gigi *g, GtkFunction func = 0)
{
remove_search_off_timeout();
if (!func)
func = GtkFunction(search_off_timeout);
g_search_off_timeout_id = gtk_timeout_add(timeout, func, g);
}
/// END: TIMEOUT MANAGEMENT
GtkStyle* style_normal(GtkWidget *w)
{
static GtkStyle *style;
if (!style) {
style = gtk_style_copy(gtk_widget_get_style(w));
style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0x0000, 0x0000, 0x0000};
gtk_style_ref(style);
}
return style;
}
GtkStyle* style_notfound(GtkWidget *w)
{
static GtkStyle *style;
if (!style) {
style = gtk_style_copy(gtk_widget_get_style(w));
style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0xFFFF, 0x0000, 0x0000};
gtk_style_ref(style);
}
return style;
}
GtkStyle* style_notunique(GtkWidget *w)
{
static GtkStyle *style;
if (!style) {
style = gtk_style_copy(gtk_widget_get_style(w));
style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0x0000, 0x0000, 0xFFFF};
gtk_style_ref(style);
}
return style;
}
GtkStyle* style_unique(GtkWidget *w)
{
static GtkStyle *style;
if (!style) {
style = gtk_style_copy(gtk_widget_get_style(w));
style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0x0000, 0xFFFF, 0x0000};
gtk_style_ref(style);
}
return style;
}
static void
run_the_command(const std::string& command, struct gigi* g)
{
string cmd(command);
cmd += '&';
int ret = system(cmd.c_str());
#ifdef DEBUG
cerr << "System exit code: " << ret << endl;
#endif
if (ret != -1)
gtk_main_quit();
else {
string error("ERROR: ");
error += strerror(errno);
#ifdef DEBUG
cerr << error << endl;
#endif
gtk_label_set_text(GTK_LABEL(g->w1), error.c_str());
gtk_widget_set_style(g->w1, style_notfound(g->w1));
add_search_off_timeout(2000, g);
}
}
static void
on_ext_handler(GtkCompletionLine *cl, const char* ext, struct gigi* g)
{
string cmd;
if (ext && configuration.get_ext_handler(ext, cmd)) {
string str("Handler: ");
size_t pos = cmd.find_first_of(" \t");
if (pos == string::npos)
str += cmd;
else
str += cmd.substr(0, pos);
gtk_label_set_text(GTK_LABEL(g->w2), str.c_str());
gtk_widget_show(g->w2);
// gtk_timeout_add(1000, GtkFunction(search_off_timeout), g);
} else {
search_off_timeout(g);
}
}
static void
on_compline_runwithterm(GtkCompletionLine *cl, struct gigi* g)
{
string command(g_locale_from_utf8 (gtk_entry_get_text(GTK_ENTRY(cl)),
-1,
NULL,
NULL,
NULL));
string tmp;
string term;
string::size_type i;
i = command.find_first_not_of(" \t");
if (i != string::npos) {
if (!configuration.get_string("TermExec", term)) {
term = "xterm -e";
}
tmp = term;
tmp += " ";
tmp += command;
} else {
if (!configuration.get_string("Terminal", term)) {
tmp = "xterm";
} else {
tmp = term;
}
}
#ifdef DEBUG
cerr << tmp << endl;
#endif
cl->hist->append(command.c_str());
cl->hist->sync_the_file();
run_the_command(tmp.c_str(), g);
}
static gint
search_off_timeout(struct gigi *g)
{
gtk_label_set_text(GTK_LABEL(g->w1), "Run program:");
gtk_widget_set_style(g->w1, style_normal(g->w1));
gtk_widget_hide(g->w2);
return FALSE;
}
static void
on_compline_unique(GtkCompletionLine *cl, struct gigi *g)
{
gtk_label_set_text(GTK_LABEL(g->w1), "unique");
gtk_widget_set_style(g->w1, style_unique(g->w1));
add_search_off_timeout(1000, g);
}
static void
on_compline_notunique(GtkCompletionLine *cl, struct gigi *g)
{
gtk_label_set_text(GTK_LABEL(g->w1), "not unique");
gtk_widget_set_style(g->w1, style_notunique(g->w1));
add_search_off_timeout(1000, g);
}
static void
on_compline_incomplete(GtkCompletionLine *cl, struct gigi *g)
{
gtk_label_set_text(GTK_LABEL(g->w1), "not found");
gtk_widget_set_style(g->w1, style_notfound(g->w1));
add_search_off_timeout(1000, g);
}
static void
on_search_mode(GtkCompletionLine *cl, struct gigi *g)
{
if (cl->hist_search_mode != GCL_SEARCH_OFF) {
gtk_widget_show(g->w2);
gtk_label_set_text(GTK_LABEL(g->w1), "Search:");
gtk_label_set_text(GTK_LABEL(g->w2), cl->hist_word->c_str());
} else {
gtk_widget_hide(g->w2);
gtk_label_set_text(GTK_LABEL(g->w1), "Search OFF");
add_search_off_timeout(1000, g);
}
}
static void
on_search_letter(GtkCompletionLine *cl, GtkWidget *label)
{
gtk_label_set_text(GTK_LABEL(label), cl->hist_word->c_str());
}
static gint
search_fail_timeout(struct gigi *g)
{
gtk_label_set_text(GTK_LABEL(g->w1), "Search:");
gtk_widget_set_style(g->w2, style_notunique(g->w2));
return FALSE;
}
static void
on_search_not_found(GtkCompletionLine *cl, struct gigi *g)
{
gtk_label_set_text(GTK_LABEL(g->w1), "Not Found!");
gtk_widget_set_style(g->w2, style_notfound(g->w2));
add_search_off_timeout(1000, g, GtkFunction(search_fail_timeout));
}
static bool
url_check(GtkCompletionLine *cl, struct gigi *g)
{
string text(g_locale_from_utf8 (gtk_entry_get_text(GTK_ENTRY(cl)),
-1,
NULL,
NULL,
NULL));
string::size_type i;
string::size_type sp;
sp = text.find_first_not_of(" \t");
if (sp == string::npos) return true;
text = text.substr(sp);
sp = text.find_first_of(" \t");
i = text.find(":");
if (i != string::npos && i < sp) {
// URL entered...
string url(text.substr(i + 1));
string url_type(text.substr(0, i));
string url_handler;
if (configuration.get_string(string("URL_") + url_type, url_handler)) {
string::size_type j = 0;
do {
j = url_handler.find("%s", j);
if (j != string::npos) {
url_handler.replace(j, 2, url);
}
} while (j != string::npos);
j = 0;
do {
j = url_handler.find("%u", j);
if (j != string::npos) {
url_handler.replace(j, 2, text);
}
} while (j != string::npos);
cl->hist->append(text.c_str());
cl->hist->sync_the_file();
run_the_command(url_handler.c_str(), g);
return true;
} else {
gtk_label_set_text(GTK_LABEL(g->w1),
(string("No URL handler for [") +
url_type + "]").c_str());
gtk_widget_set_style(g->w1, style_notfound(g->w1));
add_search_off_timeout(1000, g);
return true;
}
}
return false;
}
static bool
ext_check(GtkCompletionLine *cl, struct gigi *g)
{
vector<string> words;
get_words(cl, words);
vector<string>::const_iterator
i = words.begin(),
i_end = words.end();
while (i != i_end) {
const string& w = quote_string(*i++);
if (w[0] == '/') {
// absolute path, check for extension
size_t pos = w.rfind('.');
if (pos != string::npos) {
// we have extension
string ext = w.substr(pos + 1);
string ext_handler;
if (configuration.get_ext_handler(ext, ext_handler)) {
// we have the handler
pos = ext_handler.find("%s");
if (pos != string::npos)
ext_handler.replace(pos, 2, w);
cl->hist->append(w.c_str());
cl->hist->sync_the_file();
run_the_command(ext_handler.c_str(), g);
return true;
}
}
}
// FIXME: for now we check only one entry
break;
}
return false;
}
static void
on_compline_activated(GtkCompletionLine *cl, struct gigi *g)
{
if (url_check(cl, g))
return;
if (ext_check(cl, g))
return;
string command = g_locale_from_utf8 (gtk_entry_get_text(GTK_ENTRY(cl)),
-1,
NULL,
NULL,
NULL);
string::size_type i;
i = command.find_first_not_of(" \t");
if (i != string::npos) {
string::size_type j = command.find_first_of(" \t", i);
string progname = command.substr(i, j - i);
list<string> term_progs;
if (configuration.get_string_list("AlwaysInTerm", term_progs)) {
#ifdef DEBUG
cerr << "---" << std::endl;
std::copy(term_progs.begin(), term_progs.end(),
std::ostream_iterator<string>(cerr, "\n"));
cerr << "---" << std::endl;
#endif
list<string>::const_iterator w =
std::find(term_progs.begin(), term_progs.end(), progname);
if (w != term_progs.end()) {
on_compline_runwithterm(cl, g);
return;
}
}
cl->hist->append(command.c_str());
cl->hist->sync_the_file();
run_the_command(command, g);
}
}
int main(int argc, char **argv)
{
GtkWidget *dialog;
GtkWidget *compline;
GtkWidget *label_search;
struct gigi g;
#ifdef MTRACE
mtrace();
#endif
gtk_init(&argc, &argv);
dialog = gtk_dialog_new();
gtk_widget_realize(dialog);
gdk_window_set_decorations(dialog->window, GDK_DECOR_BORDER);
gtk_widget_set_name(dialog, "Msh_Run_Window");
gtk_window_set_title(GTK_WINDOW(dialog), "Execute program feat. completion");
gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
// gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(dialog), 4);
gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
GtkWidget *hhbox = gtk_hbox_new(FALSE, 2);
gtk_widget_show(hhbox);
gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hhbox, FALSE, FALSE, 0);
GtkWidget *label = gtk_label_new("Run program:");
gtk_widget_show(label);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 1.0);
gtk_misc_set_padding(GTK_MISC(label), 10, 0);
gtk_box_pack_start(GTK_BOX(hhbox), label, FALSE, FALSE, 0);
label_search = gtk_label_new("");
gtk_widget_show(label_search);
gtk_misc_set_alignment(GTK_MISC(label_search), 1.0, 0.5);
gtk_misc_set_padding(GTK_MISC(label_search), 10, 0);
gtk_box_pack_start(GTK_BOX(hhbox), label_search, TRUE, TRUE, 0);
compline = gtk_completion_line_new();
gtk_widget_set_name(compline, "Msh_Run_Compline");
int prefs_width;
if (!configuration.get_int("Width", prefs_width))
prefs_width = 500;
// don't show files starting with "." by default
if (!configuration.get_int("ShowDotFiles", GTK_COMPLETION_LINE(compline)->show_dot_files))
GTK_COMPLETION_LINE(compline)->show_dot_files = 0;
{
int tmp;
if (configuration.get_int("TabTimeout", tmp))
((GtkCompletionLine*)compline)->tabtimeout = tmp;
}
g.w1 = label;
g.w2 = label_search;
gtk_widget_set_usize(compline, prefs_width, -2);
gtk_signal_connect(GTK_OBJECT(compline), "cancel",
GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
gtk_signal_connect(GTK_OBJECT(compline), "activate",
GTK_SIGNAL_FUNC(on_compline_activated), &g);
gtk_signal_connect(GTK_OBJECT(compline), "runwithterm",
GTK_SIGNAL_FUNC(on_compline_runwithterm), &g);
gtk_signal_connect(GTK_OBJECT(compline), "unique",
GTK_SIGNAL_FUNC(on_compline_unique), &g);
gtk_signal_connect(GTK_OBJECT(compline), "notunique",
GTK_SIGNAL_FUNC(on_compline_notunique), &g);
gtk_signal_connect(GTK_OBJECT(compline), "incomplete",
GTK_SIGNAL_FUNC(on_compline_incomplete), &g);
gtk_signal_connect(GTK_OBJECT(compline), "search_mode",
GTK_SIGNAL_FUNC(on_search_mode), &g);
gtk_signal_connect(GTK_OBJECT(compline), "search_not_found",
GTK_SIGNAL_FUNC(on_search_not_found), &g);
gtk_signal_connect(GTK_OBJECT(compline), "search_letter",
GTK_SIGNAL_FUNC(on_search_letter), label_search);
gtk_signal_connect(GTK_OBJECT(compline), "ext_handler",
GTK_SIGNAL_FUNC(on_ext_handler), &g);
gtk_widget_show(compline);
int shows_last_history_item;
if (!configuration.get_int("ShowLast", shows_last_history_item)) {
shows_last_history_item = 0;
}
if (shows_last_history_item) {
gtk_completion_line_last_history_item(GTK_COMPLETION_LINE(compline));
}
gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), compline, TRUE, TRUE, 0);
int prefs_top = 80;
int prefs_left = 100;
int prefs_centred_by_width = 0;
int prefs_centred_by_height = 0;
int prefs_use_active_monitor = 0;
configuration.get_int("Top", prefs_top);
configuration.get_int("Left", prefs_left);
configuration.get_int("CenteredByWidth", prefs_centred_by_width);
configuration.get_int("CenteredByHeight", prefs_centred_by_height);
configuration.get_int("UseActiveMonitor", prefs_use_active_monitor);
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ALWAYS);
gtk_widget_show(dialog);
gtk_window_set_focus(GTK_WINDOW(dialog), compline);
gtk_main();
}
// Local Variables: ***
// mode: c++ ***
// c-basic-offset: 2 ***
// End: ***

View File

@ -1,13 +0,0 @@
/*****************************************************************************
* $Id: main.h,v 1.2 2001/05/16 14:39:31 mishoo Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/

View File

@ -1,178 +0,0 @@
/*****************************************************************************
* $Id: prefs.cc,v 1.9 2002/08/16 10:48:22 mishoo Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <list>
#define GMRUNRC "gmrunrc"
using std::ifstream;
using std::getline;
using std::string;
using std::list;
#include "prefs.h"
#include "config.h"
Prefs configuration;
Prefs::Prefs()
{
string file_name = "/etc/";
file_name += GMRUNRC;
init(file_name);
file_name = getenv("HOME");
if (!file_name.empty()) {
string::iterator i = file_name.end() - 1;
if (*i == '/') file_name.erase(i);
file_name += "/.";
file_name += GMRUNRC;
init(file_name);
}
}
Prefs::~Prefs()
{}
bool Prefs::get_string(const string& key, string& val) const
{
CONFIG::const_iterator i;
i = vals_.find(ci_string(key.c_str()));
if (i != vals_.end()) {
val = process(i->second);
return true;
} else {
return false;
}
}
bool Prefs::get_ext_handler(const std::string& ext, std::string& val) const
{
CONFIG::const_iterator i;
i = exts_.find(ci_string(ext.c_str()));
if (i != exts_.end()) {
val = process(i->second);
return true;
} else {
return false;
}
}
bool Prefs::get_int(const std::string& key, int& val) const
{
string sval;
if (get_string(key, sval)) {
int ret;
if (sscanf(sval.c_str(), "%d", &ret) == 1) {
val = ret;
return true;
} else {
return false;
}
} else {
return false;
}
}
bool Prefs::init(const string& file_name)
{
ifstream f(file_name.c_str());
if (!f.good() || f.eof()) return false;
while (f.good() && !f.eof()) {
string line;
char key[0x100];
char val[0x100];
getline(f, line);
if (f.eof()) break;
string::size_type i = line.find_first_not_of(" \t");
if (i == string::npos) continue;
if (line[i] == '#') continue;
sscanf(line.c_str(), "%255[a-zA-Z_0-9:,;] = %255[^\n]", key, val);
if (strncmp(key, "EXT:", 4) == 0) {
string k(key + 4);
size_t i = 0;
while (i != string::npos) {
string ext;
size_t j = k.find(',', i);
if (j != string::npos) {
ext = k.substr(i, j - i);
i = j + 1;
} else {
ext = k.substr(i);
i = string::npos;
}
if (ext.length() > 0) {
#ifdef DEBUG
std::cerr << "Extension: " << ext << " - " << val << std::endl;
#endif
exts_[ext.c_str()] = val;
}
}
} else {
vals_[key] = val;
}
#ifdef DEBUG
std::cerr << "Key: " << key << ", val: " << vals_[key] << std::endl;
#endif
}
return true;
}
string Prefs::process(const std::string& cmd) const
{
string::size_type i = cmd.find("${");
string::size_type j = cmd.find("}", i);
if (i == string::npos || j == string::npos) {
return cmd;
}
string val;
if (!get_string(cmd.substr(i + 2, j - i - 2), val)) return cmd;
string ret(cmd);
ret.replace(i, j - i + 1, val);
return process(ret);
}
bool Prefs::get_string_list(const string& key, list<string>& val) const
{
string sval;
if (get_string(key, sval)) {
const char *q, *p = sval.c_str();
for (q = sval.c_str(); *q; ++q) {
if (::isspace(*q)) {
string s(p, q - p);
val.push_back(s);
while (*q && ::isspace(*q)) ++q;
p = q;
}
}
if (p != q) {
string s(p, q - p);
val.push_back(s);
}
return (val.size() > 0);
}
return false;
}

View File

@ -1,45 +0,0 @@
/*****************************************************************************
* $Id: prefs.h,v 1.6 2002/08/16 10:30:18 mishoo Exp $
* Copyright (C) 2000, Mishoo
* Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
*
* Distributed under the terms of the GNU General Public License. You are
* free to use/modify/distribute this program as long as you comply to the
* terms of the GNU General Public License, version 2 or above, at your
* option, and provided that this copyright notice remains intact.
*****************************************************************************/
#ifndef __PREFS_H__
#define __PREFS_H__
#include "ci_string.h"
#include <map>
#include <list>
class Prefs
{
public:
typedef std::map<ci_string, std::string> CONFIG;
typedef std::pair<ci_string, std::string> PAIR;
private:
CONFIG vals_;
CONFIG exts_;
bool init(const std::string& file_name);
string process(const std::string& cmd) const;
public:
Prefs();
~Prefs();
bool get_string(const std::string& key, std::string& val) const;
bool get_int(const std::string& key, int& val) const;
bool get_string_list(const std::string& ket, std::list<string>& val) const;
bool get_ext_handler(const std::string& ext, std::string& val) const;
};
extern Prefs configuration;
#endif /* __PREFS_H__ */

View File

@ -1,24 +0,0 @@
#!/bin/sh
pkg=gmrun
ver=$(grep AC_INIT configure.ac | cut -f 3 -d '[' | cut -f 1 -d ']')
dir=${pkg}-${ver}
mkdir -p ../$dir
cp -rf $PWD/* ../$dir
(
cd ../$dir
./autogen.sh
rm -rf autom4te.cache
#rm -rf m4
rm -f make-release
)
cd ..
tar -Jcf ${dir}.tar.xz $dir
### END ###