summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/feh.pre124
-rw-r--r--src/events.c177
-rw-r--r--src/events.h2
-rw-r--r--src/feh.h1
-rw-r--r--src/help.raw24
-rw-r--r--src/keyevents.c2
-rw-r--r--src/main.c1
-rw-r--r--src/options.c59
-rw-r--r--src/options.h30
-rw-r--r--src/structs.h2
10 files changed, 242 insertions, 180 deletions
diff --git a/man/feh.pre b/man/feh.pre
index 5635fe8..b40510e 100644
--- a/man/feh.pre
+++ b/man/feh.pre
@@ -517,66 +517,6 @@ mode.
.El
.
.
-.Sh BUTTON OPTIONS
-.
-.Bl -tag -width indent
-.
-.It Cm -0 , --reload-button Ar int
-.
-Set button to reload the image
-.Pq default: 0 .
-.
-.It Cm -1 , --pan-button Ar int
-.
-Set button to pan the image
-.Pq hold button down and move mouse to move the image .
-When the mouse is not moved, advances to the next image in slideshow mode.
-.Pq default: 1 , usually the left button .
-.
-.It Cm -2 , --zoom-button Ar int
-.
-Set button to enable zoom mode
-.Pq default: 2 , usually the middle button .
-.
-.It Cm -3 , --menu-button Ar int
-.
-Set button to activate the menu.
-.Pq default: 3 , usually the right button .
-.
-.It Cm --menu-ctrl-mask
-.
-Require CTRL+Button for menu activation.
-.
-.It Cm -4 , --prev-button Ar int
-.
-Set button to switch to the previous image in slideshow mode
-.Pq default: 4 , usually Aq mousewheel up .
-.
-.It Cm -5 , --next-button Ar int
-.
-Set button to switch to the next image in slideshow mode
-.Pq default: 5 , usually Aq mousewheel down .
-.
-.It Cm -8 , --rotate-button Ar int
-.
-Use CTRL+Button to rotate the current image
-.Pq default : 2 .
-.
-.It Cm --no-rotate-ctrl-mask
-.
-Don't require CTRL+Button for rotation - just use the button.
-.
-.It Cm -9 , --blur-button Ar int
-.
-Use CTRL+Button for blurring
-.Pq default : 1 .
-.
-.It Cm --no-blur-ctrl-mask
-.
-Don't require CTRL+Button for blurring - just use the button.
-.El
-.
-.
.Sh MONTAGE MODE OPTIONS
.
These additional options can be used for index, montage and
@@ -1167,6 +1107,70 @@ Select highlighted menu item
.El
.
.
+.Sh BUTTONS CONFIG SYNTAX
+.
+This works like the keys config file: the entries are of the form
+.Qq Ar action Op Ar binding .
+.
+.Pp
+.
+Each
+.Ar binding
+is a button name. It may optionally start with modifiers for things like
+Control, in which case
+.Ar binding
+looks like
+.Ar mod Ns No - Ns Ar button
+.Pq for example "C-1" for Ctrl + Left button .
+.
+.Pp
+.
+For the available modifiers, see
+.Sx KEYS CONFIGURATION SYNTAX .
+.
+.
+.Ss BUTTONS
+.
+In an image window, the following buttons may be used
+.Pq The strings in Bo square brackets Bc are the config action names :
+.
+.Bl -tag -width indent
+.
+.It Bq reload
+.
+Reload current image
+.
+.It 1 Ao left mouse button Ac Bq pan
+.
+pan the current image
+.
+.It 2 Ao middle mouse button Ac Bq zoom
+.
+Zoom the current image
+.
+.It 3 Ao right mouse button Ac Bq menu
+.
+Toggle menu
+.
+.It 4 Ao mousewheel down Ac Bq prev
+.
+Show previous image
+.
+.It 5 Ao mousewheel up Ac Bq next
+.
+Show next image
+.
+.It Ctrl+1 Bq blur
+.
+Blur current image
+.
+.It Ctrl+2 Bq rotate
+.
+Rotate current image
+.
+.El
+.
+.
.Sh MOUSE ACTIONS
.
When viewing an image, by default mouse button 1 pans
diff --git a/src/events.c b/src/events.c
index 2b8abdd..0d5e07d 100644
--- a/src/events.c
+++ b/src/events.c
@@ -32,6 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "events.h"
#include "thumbnail.h"
+fehbb buttons;
+
feh_event_handler *ev_handler[LASTEvent];
static void feh_event_handle_ButtonPress(XEvent * ev);
@@ -41,6 +43,129 @@ static void feh_event_handle_LeaveNotify(XEvent * ev);
static void feh_event_handle_MotionNotify(XEvent * ev);
static void feh_event_handle_ClientMessage(XEvent * ev);
+static void feh_set_bb(fehbutton *bb, int modifier, char button)
+{
+ bb->modifier = modifier;
+ bb->button = button;
+}
+
+static void feh_set_parse_bb_partial(fehbutton *button, char *binding)
+{
+ char *cur = binding;
+ int mod = 0;
+
+ if (!*binding) {
+ button->button = 0;
+ return;
+ }
+
+ while (cur[1] == '-') {
+ switch (cur[0]) {
+ case 'C':
+ mod |= ControlMask;
+ break;
+ case 'S':
+ mod |= ShiftMask;
+ break;
+ case '1':
+ mod |= Mod1Mask;
+ break;
+ case '4':
+ mod |= Mod4Mask;
+ break;
+ default:
+ weprintf("buttons: invalid modifier %c in \"%s\"", cur[0], binding);
+ break;
+ }
+ cur += 2;
+ }
+
+ button->button = atoi(cur);
+ button->modifier = mod;
+}
+
+void init_buttonbindings(void)
+{
+ char *home = NULL;
+ char *confhome = NULL;
+ char *confpath = NULL;
+ char line[128];
+ char action[32], button[8];
+ struct __fehbutton *cur_bb = NULL;
+ FILE *conf = NULL;
+ int read = 0;
+
+ memset(&buttons, 0, sizeof(buttons));
+
+ feh_set_bb(&buttons.reload, 0, 0);
+ feh_set_bb(&buttons.pan, 0, 1);
+ feh_set_bb(&buttons.zoom, 0, 2);
+ feh_set_bb(&buttons.menu, 0, 3);
+ feh_set_bb(&buttons.prev, 0, 4);
+ feh_set_bb(&buttons.next, 0, 5);
+ feh_set_bb(&buttons.blur, 4, 1);
+ feh_set_bb(&buttons.rotate, 4, 2);
+
+ home = getenv("HOME");
+ if (!home)
+ eprintf("No HOME in environment");
+
+ confhome = getenv("XDG_CONFIG_HOME");
+
+ if (confhome)
+ confpath = estrjoin("/", confhome, "feh/buttons", NULL);
+ else
+ confpath = estrjoin("/", home, ".config/feh/buttons", NULL);
+
+ conf = fopen(confpath, "r");
+
+ free(confpath);
+
+ if (!conf && ((conf = fopen("/etc/feh/buttons", "r")) == NULL))
+ return;
+
+ while (fgets(line, sizeof(line), conf)) {
+ *action = '\0';
+ *button = '\0';
+
+ read = sscanf(line, "%31s %7s\n", (char *) &action, (char *) &button);
+
+ if ((read == EOF) || (read == 0) || (line[0] == '#'))
+ continue;
+
+ if (!strcmp(action, "reload"))
+ cur_bb = &buttons.reload;
+ else if (!strcmp(action, "pan"))
+ cur_bb = &buttons.pan;
+ else if (!strcmp(action, "zoom"))
+ cur_bb = &buttons.zoom;
+ else if (!strcmp(action, "menu"))
+ cur_bb = &buttons.menu;
+ else if (!strcmp(action, "prev"))
+ cur_bb = &buttons.prev;
+ else if (!strcmp(action, "next"))
+ cur_bb = &buttons.next;
+ else if (!strcmp(action, "blur"))
+ cur_bb = &buttons.blur;
+ else if (!strcmp(action, "rotate"))
+ cur_bb = &buttons.rotate;
+ else
+ weprintf("buttons: Invalid action: %s", action);
+
+ if (cur_bb)
+ feh_set_parse_bb_partial(cur_bb, button);
+ }
+ fclose(conf);
+}
+
+static short feh_is_bb(fehbutton *bb, int button, int mod)
+{
+ if ((bb->modifier == mod) && (bb->button == button))
+ return 1;
+ return 0;
+}
+
+
void feh_event_init(void)
{
int i;
@@ -62,6 +187,7 @@ void feh_event_init(void)
static void feh_event_handle_ButtonPress(XEvent * ev)
{
winwidget winwid = NULL;
+ int state, button;
/* get the heck out if it's a mouse-click on the
cover, we'll hide the menus on release */
@@ -74,31 +200,34 @@ static void feh_event_handle_ButtonPress(XEvent * ev)
return;
}
- if (!opt.no_menus && EV_IS_MENU_BUTTON(ev)) {
+ state = ev->xbutton.state & (ControlMask | ShiftMask | Mod1Mask | Mod4Mask);
+ button = ev->xbutton.button;
+
+ if (!opt.no_menus && feh_is_bb(&buttons.menu, button, state)) {
D(("Menu Button Press event\n"));
winwidget_show_menu(winwid);
- } else if ((ev->xbutton.button == opt.rotate_button)
- && (winwid->type != WIN_TYPE_THUMBNAIL)
- && ((opt.no_rotate_ctrl_mask)
- || (ev->xbutton.state & ControlMask))) {
+
+ } else if (feh_is_bb(&buttons.rotate, button, state)
+ && (winwid->type != WIN_TYPE_THUMBNAIL)) {
opt.mode = MODE_ROTATE;
winwid->mode = MODE_ROTATE;
D(("rotate starting at %d, %d\n", ev->xbutton.x, ev->xbutton.y));
- } else if ((ev->xbutton.button == opt.blur_button)
- && (winwid->type != WIN_TYPE_THUMBNAIL)
- && ((opt.no_blur_ctrl_mask)
- || (ev->xbutton.state & ControlMask))) {
+
+ } else if (feh_is_bb(&buttons.blur, button, state)
+ && (winwid->type != WIN_TYPE_THUMBNAIL)) {
opt.mode = MODE_BLUR;
winwid->mode = MODE_BLUR;
D(("blur starting at %d, %d\n", ev->xbutton.x, ev->xbutton.y));
- } else if (ev->xbutton.button == opt.pan_button) {
+
+ } else if (feh_is_bb(&buttons.pan, button, state)) {
D(("Next button, but could be pan mode\n"));
opt.mode = MODE_NEXT;
winwid->mode = MODE_NEXT;
D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y));
winwid->click_offset_x = ev->xbutton.x - winwid->im_x;
winwid->click_offset_y = ev->xbutton.y - winwid->im_y;
- } else if (ev->xbutton.button == opt.zoom_button) {
+
+ } else if (feh_is_bb(&buttons.zoom, button, state)) {
D(("Zoom Button Press event\n"));
opt.mode = MODE_ZOOM;
winwid->mode = MODE_ZOOM;
@@ -112,17 +241,21 @@ static void feh_event_handle_ButtonPress(XEvent * ev)
- winwid->im_x) / winwid->old_zoom;
winwid->im_click_offset_y = (winwid->click_offset_y
- winwid->im_y) / winwid->old_zoom;
- } else if (ev->xbutton.button == opt.reload_button) {
+
+ } else if (feh_is_bb(&buttons.reload, button, state)) {
D(("Reload Button Press event\n"));
feh_reload_image(winwid, 0, 1);
- } else if (ev->xbutton.button == opt.prev_button) {
+
+ } else if (feh_is_bb(&buttons.prev, button, state)) {
D(("Prev Button Press event\n"));
if (winwid->type == WIN_TYPE_SLIDESHOW)
slideshow_change_image(winwid, SLIDE_PREV, 1);
- } else if (ev->xbutton.button == opt.next_button) {
+
+ } else if (feh_is_bb(&buttons.next, button, state)) {
D(("Next Button Press event\n"));
if (winwid->type == WIN_TYPE_SLIDESHOW)
slideshow_change_image(winwid, SLIDE_NEXT, 1);
+
} else {
D(("Received other ButtonPress event\n"));
}
@@ -132,6 +265,8 @@ static void feh_event_handle_ButtonPress(XEvent * ev)
static void feh_event_handle_ButtonRelease(XEvent * ev)
{
winwidget winwid = NULL;
+ int state = ev->xbutton.state & (ControlMask | ShiftMask | Mod1Mask | Mod4Mask);
+ int button = ev->xbutton.button;
if (menu_root) {
/* if menus are open, close them, and execute action if needed */
@@ -156,7 +291,7 @@ static void feh_event_handle_ButtonRelease(XEvent * ev)
return;
}
- if (ev->xbutton.button == opt.pan_button) {
+ if (feh_is_bb(&buttons.pan, button, state)) {
if (opt.mode == MODE_PAN) {
D(("Disabling pan mode\n"));
opt.mode = MODE_NORMAL;
@@ -186,13 +321,14 @@ static void feh_event_handle_ButtonRelease(XEvent * ev)
opt.mode = MODE_NORMAL;
winwid->mode = MODE_NORMAL;
}
- } else if ((ev->xbutton.button == opt.rotate_button)
- || (ev->xbutton.button == opt.zoom_button)) {
+
+ } else if (feh_is_bb(&buttons.rotate, button, state)
+ || feh_is_bb(&buttons.zoom, button, state)) {
D(("Disabling mode\n"));
opt.mode = MODE_NORMAL;
winwid->mode = MODE_NORMAL;
- if ((ev->xbutton.button == opt.zoom_button)
+ if ((feh_is_bb(&buttons.zoom, button, state))
&& (ev->xbutton.x == winwid->click_offset_x)
&& (ev->xbutton.y == winwid->click_offset_y)) {
winwid->zoom = 1.0;
@@ -201,9 +337,8 @@ static void feh_event_handle_ButtonRelease(XEvent * ev)
winwidget_sanitise_offsets(winwid);
winwidget_render_image(winwid, 0, 0);
- } else if ((ev->xbutton.button == opt.blur_button)
- && ((opt.no_blur_ctrl_mask)
- || (ev->xbutton.state & ControlMask))) {
+
+ } else if (feh_is_bb(&buttons.blur, button, state)) {
D(("Disabling Blur mode\n"));
opt.mode = MODE_NORMAL;
winwid->mode = MODE_NORMAL;
diff --git a/src/events.h b/src/events.h
index 22abaf7..195f268 100644
--- a/src/events.h
+++ b/src/events.h
@@ -32,6 +32,4 @@ extern feh_event_handler *ev_handler[];
void feh_event_init(void);
-#define EV_IS_MENU_BUTTON(ev) ((((ev)->xbutton.button == opt.menu_button) || (opt.menu_button == 0)) && (((!opt.menu_ctrl_mask) && (!((ev)->xbutton.state & ControlMask))) || (((ev)->xbutton.state & ControlMask) && (opt.menu_ctrl_mask))))
-
#endif
diff --git a/src/feh.h b/src/feh.h
index d4a1ff7..550b6f5 100644
--- a/src/feh.h
+++ b/src/feh.h
@@ -134,6 +134,7 @@ void slideshow_change_image(winwidget winwid, int change, int render);
void slideshow_pause_toggle(winwidget w);
char *slideshow_create_name(feh_file * file);
void init_keyevents(void);
+void init_buttonbindings(void);
void feh_event_handle_keypress(XEvent * ev);
void feh_action_run(feh_file * file, char *action);
char *feh_printf(char *str, feh_file * file);
diff --git a/src/help.raw b/src/help.raw
index e8c848e..48c8a70 100644
--- a/src/help.raw
+++ b/src/help.raw
@@ -80,30 +80,6 @@ OPTIONS
-B, --image-bg STYLE Set background for transparent images and the like.
Accepted values: white, black, default
-N, --no-menus Don't load or show any menus.
- -0, --reload-button B Use button B to reload the image (defaults to 0)
- -1, --pan-button B Use button B pan the image (hold button down, move
- the mouse to move the image around. Advances to the
- next image when the mouse is not moved (defaults to
- 1, usually the left button).
- -2, --zoom-button B Use button B to zoom the current image in any
- mode (defaults to 2, usually the middle button).
- -3, --menu-button B Click button B to activate the menu in any
- mode. Set to 0 for any button. This option
- is disabled if the -N or --no-menus option is set
- (defaults to 3, usually the right button).
- --menu-ctrl-mask Require CTRL+Button for menu activation
- -4, --prev-button B Use button B to switch to the previous image
- (defaults to 4, which usually is <mousewheel up>).
- -5, --next-button B Use button B to switch to the next image
- (defaults to 5, which usually is <mousewheel down>).
- -8, --rotate-button B Use CTRL+Button B to rotate the current image in
- any mode (default=2).
- --no-rotate-ctrl-mask Don't require CTRL+Button for rotation in
- any mode -- just use the button (default=off).
- -9, --blur-button B Use CTRL+Button B to blur the current image in
- any mode (default=1).
- --no-blur-ctrl-mask Don't require CTRL+Button for blurring in
- any mode -- just use the button (default=off).
--no-xinerama Disable Xinerama support
--no-screen-clip Do not limit window size to screen size
-Y, --hide-pointer Hide the pointer
diff --git a/src/keyevents.c b/src/keyevents.c
index 942a88b..827ab24 100644
--- a/src/keyevents.c
+++ b/src/keyevents.c
@@ -154,7 +154,7 @@ void init_keyevents(void) {
home = getenv("HOME");
if (!home)
- eprintf("No HOME in environment\n");
+ eprintf("No HOME in environment");
confhome = getenv("XDG_CONFIG_HOME");
diff --git a/src/main.c b/src/main.c
index 12dec52..5891056 100644
--- a/src/main.c
+++ b/src/main.c
@@ -47,6 +47,7 @@ int main(int argc, char **argv)
if (opt.display) {
init_x_and_imlib();
init_keyevents();
+ init_buttonbindings();
}
feh_event_init();
diff --git a/src/options.c b/src/options.c
index def17f0..316f62d 100644
--- a/src/options.c
+++ b/src/options.c
@@ -61,19 +61,6 @@ void init_parse_options(int argc, char **argv)
opt.menu_bg = estrdup(PREFIX "/share/feh/images/menubg_default.png");
opt.menu_style = estrdup(PREFIX "/share/feh/fonts/menu.style");
- opt.reload_button = 0;
- opt.pan_button = 1;
- opt.zoom_button = 2;
- opt.menu_button = 3;
- opt.menu_ctrl_mask = 0;
- opt.prev_button = 4;
- opt.next_button = 5;
-
- opt.rotate_button = 2;
- opt.no_rotate_ctrl_mask = 0;
- opt.blur_button = 1;
- opt.no_blur_ctrl_mask = 0;
-
opt.start_list_at = NULL;
opt.jump_on_resort = 1;
@@ -315,7 +302,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)
{
static char stropts[] =
"a:A:b:B:cC:dD:e:E:f:Fg:GhH:iIj:J:kK:lL:mM:nNo:O:pPqrR:sS:tT:uUvVwW:xXy:YzZ"
- "0:1:2:4:5:8:9:.@:^:~:):|:+:";
+ ".@:^:~:):|:+:";
/* (*name, has_arg, *flag, val) See: struct option in getopts.h */
static struct option lopts[] = {
@@ -352,9 +339,6 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)
{"cache-thumbnails", 0, 0, 'P'},
{"cycle-once" , 0, 0, 224},
{"no-xinerama" , 0, 0, 225},
- {"no-rotate-ctrl-mask", 0, 0, 226},
- {"no-blur-ctrl-mask", 0, 0, 227},
- {"menu-ctrl-mask", 0, 0, 228},
{"draw-tinted" , 0, 0, 229},
{"output" , 1, 0, 'o'},
@@ -381,14 +365,6 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)
{"fontpath" , 1, 0, 'C'},
{"menu-bg" , 1, 0, ')'},
{"image-bg" , 1, 0, 'B'},
- {"reload-button" , 1, 0, '0'},
- {"pan-button" , 1, 0, '1'},
- {"zoom-button" , 1, 0, '2'},
- {"menu-button" , 1, 0, '3'},
- {"prev-button" , 1, 0, '4'},
- {"next-button" , 1, 0, '5'},
- {"rotate-button" , 1, 0, '8'},
- {"blur-button" , 1, 0, '9'},
{"start-at" , 1, 0, '|'},
{"debug" , 0, 0, '+'},
{"output-dir" , 1, 0, 'j'},
@@ -631,30 +607,6 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)
else
opt.filelistfile = estrdup(optarg);
break;
- case '0':
- opt.reload_button = atoi(optarg);
- break;
- case '1':
- opt.pan_button = atoi(optarg);
- break;
- case '2':
- opt.zoom_button = atoi(optarg);
- break;
- case '3':
- opt.menu_button = atoi(optarg);
- break;
- case '4':
- opt.prev_button = atoi(optarg);
- break;
- case '5':
- opt.next_button = atoi(optarg);
- break;
- case '8':
- opt.rotate_button = atoi(optarg);
- break;
- case '9':
- opt.blur_button = atoi(optarg);
- break;
case '|':
opt.start_list_at = estrdup(optarg);
break;
@@ -746,15 +698,6 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)
case 225:
opt.xinerama = 0;
break;
- case 226:
- opt.no_rotate_ctrl_mask = 1;
- break;
- case 227:
- opt.no_blur_ctrl_mask = 1;
- break;
- case 228:
- opt.menu_ctrl_mask = 1;
- break;
case 229:
opt.text_bg = TEXT_BG_TINTED;
break;
diff --git a/src/options.h b/src/options.h
index ae3a707..f1fe3c4 100644
--- a/src/options.h
+++ b/src/options.h
@@ -92,20 +92,6 @@ struct __fehoptions {
gib_style *menu_style_l;
- unsigned char pan_button;
- unsigned char zoom_button;
- unsigned char menu_button;
- unsigned char menu_ctrl_mask;
- unsigned char prev_button;
- unsigned char next_button;
-
- unsigned char rotate_button;
- unsigned char blur_button;
- unsigned char reload_button;
- unsigned char no_rotate_ctrl_mask;
- unsigned char no_blur_ctrl_mask;
- unsigned char no_pan_ctrl_mask;
-
int force_aliasing;
int thumb_w;
int thumb_h;
@@ -199,6 +185,22 @@ struct __fehkb {
struct __fehkey reload_plus;
};
+struct __fehbutton {
+ int modifier;
+ char button;
+};
+
+struct __fehbb {
+ struct __fehbutton pan;
+ struct __fehbutton zoom;
+ struct __fehbutton reload;
+ struct __fehbutton prev;
+ struct __fehbutton next;
+ struct __fehbutton menu;
+ struct __fehbutton blur;
+ struct __fehbutton rotate;
+};
+
void init_parse_options(int argc, char **argv);
char *feh_string_normalize(char *str);
diff --git a/src/structs.h b/src/structs.h
index 3942bc0..e1acf2d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -36,5 +36,7 @@ typedef _winwidget *winwidget;
typedef struct __fehoptions fehoptions;
typedef struct __fehkey fehkey;
typedef struct __fehkb fehkb;
+typedef struct __fehbutton fehbutton;
+typedef struct __fehbb fehbb;
#endif