Add ability to bind arbitrary functions.

Before all the predated commands where kept in an array and their
indexes were used in bindings. This meant that users couldn't add their
own functions from the config file. Now key/mouse bindings have been
changed to to store the function ptr (wrapped in a cmd_t struct to also
store the mode) directly instead.

General cleanup done in this commit:
Defined `MODE_ALL` instead of using magic number.

For example, suppose one had bindings like:
{ 0,                   XK_q,             g_quit,                     None },
{ ShitMask,            XK_q,             {quit_err},                 None }
{ ControlMask,         XK_q,             {quit_err, .mode=MODE_IMAGE}, None }

The existing binding `q` has been left unchanged and is defined the same
way. However, the new hypothetical binding `Shift-q` can be used to call
the custom function quit_err in any mode (default). `Ctrl-q` on the
other hand will be called only on image mode.

Closes #50
This commit is contained in:
Arthur Williams 2021-09-18 12:27:12 -07:00 committed by N-R-K
parent 5c6947c1c6
commit 12efa0e3b4
6 changed files with 96 additions and 70 deletions

View file

@ -64,7 +64,7 @@ nsxiv: $(OBJS)
@echo "CC $@"
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
$(OBJS): Makefile nsxiv.h commands.lst config.h
$(OBJS): Makefile nsxiv.h config.h
options.o: version.h
window.o: icon/data.h

View file

@ -436,15 +436,3 @@ bool ct_reload_all(arg_t _)
tns.dirty = true;
return true;
}
#undef G_CMD
#define G_CMD(c) { -1, cg_##c },
#undef I_CMD
#define I_CMD(c) { MODE_IMAGE, ci_##c },
#undef T_CMD
#define T_CMD(c) { MODE_THUMB, ct_##c },
const cmd_t cmds[CMD_COUNT] = {
#include "commands.lst"
};

83
commands.h Normal file
View file

@ -0,0 +1,83 @@
#ifndef COMMANDS_H
#define COMMANDS_H
#include <stdbool.h>
/* global */
bool cg_change_gamma();
bool cg_first();
bool cg_mark_range();
bool cg_n_or_last();
bool cg_navigate_marked();
bool cg_prefix_external();
bool cg_quit();
bool cg_reload_image();
bool cg_remove_image();
bool cg_reverse_marks();
bool cg_scroll_screen();
bool cg_switch_mode();
bool cg_toggle_bar();
bool cg_toggle_fullscreen();
bool cg_toggle_image_mark();
bool cg_unmark_all();
bool cg_zoom();
/* image mode */
bool ci_alternate();
bool ci_cursor_navigate();
bool ci_drag();
bool ci_fit_to_win();
bool ci_flip();
bool ci_navigate();
bool ci_navigate_frame();
bool ci_rotate();
bool ci_scroll();
bool ci_scroll_to_edge();
bool ci_set_zoom();
bool ci_slideshow();
bool ci_toggle_alpha();
bool ci_toggle_animation();
bool ci_toggle_antialias();
/* thumbnails mode */
bool ct_move_sel();
bool ct_reload_all();
/* global */
#define g_change_gamma { cg_change_gamma, MODE_ALL }
#define g_first { cg_first, MODE_ALL }
#define g_mark_range { cg_mark_range, MODE_ALL }
#define g_n_or_last { cg_n_or_last, MODE_ALL }
#define g_navigate_marked { cg_navigate_marked, MODE_ALL }
#define g_prefix_external { cg_prefix_external, MODE_ALL }
#define g_quit { cg_quit, MODE_ALL }
#define g_reload_image { cg_reload_image, MODE_ALL }
#define g_remove_image { cg_remove_image, MODE_ALL }
#define g_reverse_marks { cg_reverse_marks, MODE_ALL }
#define g_scroll_screen { cg_scroll_screen, MODE_ALL }
#define g_switch_mode { cg_switch_mode, MODE_ALL }
#define g_toggle_bar { cg_toggle_bar, MODE_ALL }
#define g_toggle_fullscreen { cg_toggle_fullscreen, MODE_ALL }
#define g_toggle_image_mark { cg_toggle_image_mark, MODE_ALL }
#define g_unmark_all { cg_unmark_all, MODE_ALL }
#define g_zoom { cg_zoom, MODE_ALL }
/* image mode */
#define i_alternate { ci_alternate, MODE_IMAGE }
#define i_cursor_navigate { ci_cursor_navigate, MODE_IMAGE }
#define i_drag { ci_drag, MODE_IMAGE }
#define i_fit_to_win { ci_fit_to_win, MODE_IMAGE }
#define i_flip { ci_flip, MODE_IMAGE }
#define i_navigate { ci_navigate, MODE_IMAGE }
#define i_navigate_frame { ci_navigate_frame, MODE_IMAGE }
#define i_rotate { ci_rotate, MODE_IMAGE }
#define i_scroll { ci_scroll, MODE_IMAGE }
#define i_scroll_to_edge { ci_scroll_to_edge, MODE_IMAGE }
#define i_set_zoom { ci_set_zoom, MODE_IMAGE }
#define i_slideshow { ci_slideshow, MODE_IMAGE }
#define i_toggle_alpha { ci_toggle_alpha, MODE_IMAGE }
#define i_toggle_animation { ci_toggle_animation, MODE_IMAGE }
#define i_toggle_antialias { ci_toggle_antialias, MODE_IMAGE }
/* thumbnails mode */
#define t_move_sel { ct_move_sel, MODE_THUMB }
#define t_reload_all { ct_reload_all, MODE_THUMB }
#endif

View file

@ -1,36 +0,0 @@
G_CMD(quit)
G_CMD(switch_mode)
G_CMD(toggle_fullscreen)
G_CMD(toggle_bar)
G_CMD(prefix_external)
G_CMD(reload_image)
G_CMD(remove_image)
G_CMD(first)
G_CMD(n_or_last)
G_CMD(scroll_screen)
G_CMD(zoom)
G_CMD(toggle_image_mark)
G_CMD(reverse_marks)
G_CMD(mark_range)
G_CMD(unmark_all)
G_CMD(navigate_marked)
G_CMD(change_gamma)
I_CMD(navigate)
I_CMD(cursor_navigate)
I_CMD(alternate)
I_CMD(navigate_frame)
I_CMD(toggle_animation)
I_CMD(scroll)
I_CMD(scroll_to_edge)
I_CMD(drag)
I_CMD(set_zoom)
I_CMD(fit_to_win)
I_CMD(rotate)
I_CMD(flip)
I_CMD(toggle_antialias)
I_CMD(toggle_alpha)
I_CMD(slideshow)
T_CMD(move_sel)
T_CMD(reload_all)

15
main.c
View file

@ -17,6 +17,7 @@
*/
#include "nsxiv.h"
#include "commands.h"
#define _MAPPINGS_CONFIG
#include "config.h"
@ -613,10 +614,10 @@ void on_keypress(XKeyEvent *kev)
} else for (i = 0; i < ARRLEN(keys); i++) {
if (keys[i].ksym == ksym &&
MODMASK(keys[i].mask | sh) == MODMASK(kev->state) &&
keys[i].cmd >= 0 && keys[i].cmd < CMD_COUNT &&
(cmds[keys[i].cmd].mode < 0 || cmds[keys[i].cmd].mode == mode))
keys[i].cmd.func &&
(keys[i].cmd.mode == MODE_ALL || keys[i].cmd.mode == mode))
{
if (cmds[keys[i].cmd].func(keys[i].arg))
if (keys[i].cmd.func(keys[i].arg))
dirty = true;
}
}
@ -638,10 +639,10 @@ void on_buttonpress(XButtonEvent *bev)
for (i = 0; i < ARRLEN(buttons); i++) {
if (buttons[i].button == bev->button &&
MODMASK(buttons[i].mask) == MODMASK(bev->state) &&
buttons[i].cmd >= 0 && buttons[i].cmd < CMD_COUNT &&
(cmds[buttons[i].cmd].mode < 0 || cmds[buttons[i].cmd].mode == mode))
buttons[i].cmd.func &&
(buttons[i].cmd.mode == MODE_ALL || buttons[i].cmd.mode == mode))
{
if (cmds[buttons[i].cmd].func(buttons[i].arg))
if (buttons[i].cmd.func(buttons[i].arg))
dirty = true;
}
}
@ -778,7 +779,7 @@ void run(void)
break;
case ClientMessage:
if ((Atom) ev.xclient.data.l[0] == atoms[ATOM_WM_DELETE_WINDOW])
cmds[g_quit].func(0);
cg_quit();
break;
case DestroyNotify:
exit(EXIT_FAILURE);

18
nsxiv.h
View file

@ -60,6 +60,7 @@ typedef enum {
} byteorder_t;
typedef enum {
MODE_ALL,
MODE_IMAGE,
MODE_THUMB
} appmode_t;
@ -162,36 +163,25 @@ bool arl_handle(arl_t*);
typedef int arg_t;
typedef bool (*cmd_f)(arg_t);
#define G_CMD(c) g_##c,
#define I_CMD(c) i_##c,
#define T_CMD(c) t_##c,
typedef enum {
#include "commands.lst"
CMD_COUNT
} cmd_id_t;
typedef struct {
int mode;
cmd_f func;
appmode_t mode;
} cmd_t;
typedef struct {
unsigned int mask;
KeySym ksym;
cmd_id_t cmd;
cmd_t cmd;
arg_t arg;
} keymap_t;
typedef struct {
unsigned int mask;
unsigned int button;
cmd_id_t cmd;
cmd_t cmd;
arg_t arg;
} button_t;
extern const cmd_t cmds[CMD_COUNT];
/* image.c */