Add work in progress support for images on Wayland

This commit also adds MASSIVE speed improvements to image drawing, due
to code cleanup. There are still a *few* issues to resolve, one is
X11 related, and one is caused by alpha/blending.
This commit is contained in:
speedie 2023-06-08 19:40:30 +02:00
parent 9eb97d5da0
commit 5745b52bc9
21 changed files with 177 additions and 130 deletions

View file

@ -219,7 +219,6 @@ alt="typing" /> <img src="screenshots/bliss.png" alt="bliss" /></p>
</ul></li> </ul></li>
<li>imlib2 <li>imlib2
<ul> <ul>
<li>Only a dependency if X11 support is enabled.</li>
<li>Used for image support, can be disabled during compile time.</li> <li>Used for image support, can be disabled during compile time.</li>
</ul></li> </ul></li>
<li>libXinerama <li>libXinerama

View file

@ -39,7 +39,6 @@ can be themed to look identical to dmenu.
- libXrender - libXrender
- For X11 support, which is optional. - For X11 support, which is optional.
- imlib2 - imlib2
- Only a dependency if X11 support is enabled.
- Used for image support, can be disabled during compile time. - Used for image support, can be disabled during compile time.
- libXinerama - libXinerama
- For X11 support, which is optional. - For X11 support, which is optional.

View file

@ -713,7 +713,6 @@ These are the default keybinds. You can generate these yourself from a
| 0 | Shift | equal | setimgsize | +100 | | 0 | Shift | equal | setimgsize | +100 |
| 0 | Shift | minus | setimgsize | -100 | | 0 | Shift | minus | setimgsize | -100 |
| 0 | Shift | 0 | defaultimg | 0 | | 0 | Shift | 0 | defaultimg | 0 |
| 0 | 0 | r | rotateimg | 0 |
| 0 | 0 | o | setimgpos | +1 | | 0 | 0 | o | setimgpos | +1 |
| 0 | Ctrl | 1 | setimggaps | -1 | | 0 | Ctrl | 1 | setimggaps | -1 |
| 0 | Ctrl | 2 | setimggaps | +1 | | 0 | Ctrl | 2 | setimggaps | +1 |

View file

@ -440,13 +440,6 @@ spmenu = {
function = "defaultimg"; function = "defaultimg";
argument = "0"; argument = "0";
}, },
// r: Rotate image
{ mode = 0;
modifier = "None";
key = "r";
function = "rotateimg";
argument = "0";
},
// o: Toggle image position // o: Toggle image position
{ mode = 0; { mode = 0;
modifier = "None"; modifier = "None";

View file

@ -36,7 +36,6 @@ static Key keys[] = {
{ 0, Shift, XK_equal, setimgsize, {.i = +100 } }, { 0, Shift, XK_equal, setimgsize, {.i = +100 } },
{ 0, Shift, XK_minus, setimgsize, {.i = -100 } }, { 0, Shift, XK_minus, setimgsize, {.i = -100 } },
{ 0, Shift, XK_0, defaultimg, {0} }, { 0, Shift, XK_0, defaultimg, {0} },
{ 0, 0, XK_r, rotateimg, {0} },
{ 0, 0, XK_o, setimgpos, {.i = +1 } }, { 0, 0, XK_o, setimgpos, {.i = +1 } },
{ 0, Ctrl, XK_1, setimggaps, {.i = -1 } }, { 0, Ctrl, XK_1, setimggaps, {.i = -1 } },
{ 0, Ctrl, XK_2, setimggaps, {.i = +1 } }, { 0, Ctrl, XK_2, setimggaps, {.i = +1 } },
@ -113,7 +112,6 @@ static WlKey wl_keys[] = {
{ 0, WL_Shift, XKB_KEY_equal, setimgsize, {.i = +100 } }, { 0, WL_Shift, XKB_KEY_equal, setimgsize, {.i = +100 } },
{ 0, WL_Shift, XKB_KEY_minus, setimgsize, {.i = -100 } }, { 0, WL_Shift, XKB_KEY_minus, setimgsize, {.i = -100 } },
{ 0, WL_Shift, XKB_KEY_0, defaultimg, {0} }, { 0, WL_Shift, XKB_KEY_0, defaultimg, {0} },
{ 0, WL_None, XKB_KEY_r, rotateimg, {0} },
{ 0, WL_None, XKB_KEY_o, setimgpos, {.i = +1 } }, { 0, WL_None, XKB_KEY_o, setimgpos, {.i = +1 } },
{ 0, WL_Ctrl, XKB_KEY_1, setimggaps, {.i = -1 } }, { 0, WL_Ctrl, XKB_KEY_1, setimggaps, {.i = -1 } },
{ 0, WL_Ctrl, XKB_KEY_2, setimggaps, {.i = +1 } }, { 0, WL_Ctrl, XKB_KEY_2, setimggaps, {.i = +1 } },

View file

@ -415,17 +415,6 @@ void setimggaps(Arg *arg) {
#endif #endif
} }
void rotateimg(Arg *arg) {
#if USEIMAGE
if (!image || hideimage) return;
rotation += arg->i ? arg->i : 1;
drawmenu();
#endif
}
void toggleimg(Arg *arg) { void toggleimg(Arg *arg) {
#if USEIMAGE #if USEIMAGE

View file

@ -35,7 +35,6 @@ static void setimgsize(Arg *arg);
static void toggleimg(Arg *arg); static void toggleimg(Arg *arg);
static void togglefullimg(Arg *arg); static void togglefullimg(Arg *arg);
static void defaultimg(Arg *arg); static void defaultimg(Arg *arg);
static void rotateimg(Arg *arg);
static void flipimg(Arg *arg); static void flipimg(Arg *arg);
static void setimgpos(Arg *arg); static void setimgpos(Arg *arg);
static void setimggaps(Arg *arg); static void setimggaps(Arg *arg);

View file

@ -378,7 +378,6 @@ static FuncList fl[] = {
{ "toggleimg", toggleimg }, { "toggleimg", toggleimg },
{ "togglefullimg", togglefullimg }, { "togglefullimg", togglefullimg },
{ "defaultimg", defaultimg }, { "defaultimg", defaultimg },
{ "rotateimg", rotateimg },
{ "flipimg", flipimg }, { "flipimg", flipimg },
{ "setimgpos", setimgpos }, { "setimgpos", setimgpos },
{ "setimgpos", setimgpos }, { "setimgpos", setimgpos },

View file

@ -286,7 +286,7 @@ int drawitem(int x, int y, int w) {
// draw image first // draw image first
#if USEIMAGE #if USEIMAGE
if (!hideimage && longestedge != 0 && !protocol) { // TODO: wayland image support if (!hideimage && longestedge != 0) {
rx = ox; rx = ox;
rx += MAX((imagegaps * 2) + imagewidth + menumarginh, indentitems ? x : 0); rx += MAX((imagegaps * 2) + imagewidth + menumarginh, indentitems ? x : 0);
} else } else
@ -520,10 +520,12 @@ void drawmenu(void) {
wl_surface_attach(state.surface, state.buffer, 0, 0); wl_surface_attach(state.surface, state.buffer, 0, 0);
wl_surface_damage(state.surface, 0, 0, state.width, state.height); wl_surface_damage(state.surface, 0, 0, state.width, state.height);
wl_surface_commit(state.surface); wl_surface_commit(state.surface);
drawimage();
} else { } else {
drawmenu_layer(); drawmenu_layer();
} }
#else #elif USEX
drawmenu_layer(); drawmenu_layer();
#endif #endif
} }
@ -627,6 +629,7 @@ void drawmenu_layer(void) {
} }
#if USEX #if USEX
drawimage();
drw_map(drw, win, 0, 0, mw, mh); drw_map(drw, win, 0, 0, mw, mh);
#endif #endif
} }

View file

@ -12,11 +12,11 @@ void setimagesize(int width, int height) {
oih = imageheight; oih = imageheight;
oiw = imagewidth; oiw = imagewidth;
drawimage();
imageheight = height; imageheight = height;
imagewidth = width; imagewidth = width;
drawimage();
needredraw = 0; needredraw = 0;
if (!image) { if (!image) {
@ -46,11 +46,6 @@ void flipimage(void) {
} }
} }
void rotateimage(void) {
rotation %= 4;
imlib_image_orientate(rotation);
}
void cleanupimage(void) { void cleanupimage(void) {
if (image) { // free image using imlib2 if (image) { // free image using imlib2
imlib_free_image(); imlib_free_image();
@ -77,8 +72,6 @@ void drawimage(void) {
} else if ((!sel || !sel->image) && image) { // free image } else if ((!sel || !sel->image) && image) { // free image
cleanupimage(); cleanupimage();
} if (image && longestedge && width && height) { // render the image } if (image && longestedge && width && height) { // render the image
// rotate and flip, will return if we don't need to
rotateimage();
flipimage(); flipimage();
int leftmargin = imagegaps; // gaps between image and menu int leftmargin = imagegaps; // gaps between image and menu
@ -97,9 +90,9 @@ void drawimage(void) {
wta += menumarginv; wta += menumarginv;
if (mh != bh + height + leftmargin * 2 - wtr && !fullscreen) { // menu height cannot be smaller than image height if (mh != bh + height + leftmargin * 2 - wtr && !fullscreen) { // menu height cannot be smaller than image height
resizetoimageheight(height); resizetoimageheight(width, height);
} else if (mh != bh + height + leftmargin * 2 - wtr && fullscreen) { } else if (mh != bh + height + leftmargin * 2 - wtr && fullscreen) {
resizetoimageheight(height-bh); resizetoimageheight(width-bh, height-bh);
} }
// we're covering all the area // we're covering all the area
@ -107,20 +100,23 @@ void drawimage(void) {
xta = wta = wtr = leftmargin = 0; xta = wta = wtr = leftmargin = 0;
} }
// render image drw_set_img(drw, imlib_image_get_data(), width, height);
// render image on X11
if (!imageposition && image) { // top mode = 0 if (!imageposition && image) { // top mode = 0
if (height > width) if (height > width)
width = height; width = height;
imlib_render_image_on_drawable(leftmargin+(imagewidth-width)/2+xta, wta+leftmargin);
drw_img(drw, leftmargin+(imagewidth-width)/2+xta, wta+leftmargin);
} else if (imageposition == 1 && image) { // bottom mode = 1 } else if (imageposition == 1 && image) { // bottom mode = 1
if (height > width) if (height > width)
width = height; width = height;
imlib_render_image_on_drawable(leftmargin+(imagewidth-width)/2+xta, mh-height-leftmargin); drw_img(drw, leftmargin+(imagewidth-width)/2+xta, mh-height-leftmargin);
} else if (imageposition == 2 && image) { // center mode = 2 } else if (imageposition == 2 && image) { // center mode = 2
imlib_render_image_on_drawable(leftmargin+(imagewidth-width)/2+xta, (mh-wta-height)/2+wta); drw_img(drw, leftmargin+(imagewidth-width)/2+xta, (mh-wta-height)/2+wta);
} else if (image) { // top center } else if (image) { // top center
int minh = MIN(height, mh-bh-leftmargin*2); int minh = MIN(height, mh-bh-leftmargin*2);
imlib_render_image_on_drawable(leftmargin+(imagewidth-width)/2+xta, (minh-height)/2+wta+leftmargin); drw_img(drw, leftmargin+(imagewidth-width)/2+xta, (minh-height)/2+wta+leftmargin);
} }
} }
@ -131,18 +127,12 @@ void drawimage(void) {
} }
} }
#if USEX
void setimageopts(void) { void setimageopts(void) {
imlib_set_cache_size(8192 * 1024); imlib_set_cache_size(8192 * 1024);
imlib_context_set_blend(1); imlib_context_set_blend(1);
imlib_context_set_dither(1); imlib_context_set_dither(1);
imlib_set_color_usage(128); imlib_set_color_usage(128);
imlib_context_set_display(dpy);
imlib_context_set_visual(visual);
imlib_context_set_colormap(cmap);
imlib_context_set_drawable(win);
} }
#endif
void createifnexist(const char *dir) { void createifnexist(const char *dir) {
// exists, so return // exists, so return
@ -337,8 +327,25 @@ void jumptoindex(unsigned int index) {
} }
} }
void resizetoimageheight(int imageheight) { void resizetoimageheight(int imagewidth, int imageheight) {
//int ih = imageheight;
int ih = imlib_image_get_height();
#if USEX #if USEX
if (!protocol) {
resizetoimageheight_x11(ih);
} else {
#if USEWAYLAND
resizetoimageheight_wl(ih);
#endif
}
#elif USEWAYLAND
resizetoimageheight_wl(ih);
#endif
}
#if USEX
void resizetoimageheight_x11(int imageheight) {
int omh = mh, olines = lines; int omh = mh, olines = lines;
lines = reallines; lines = reallines;
int wtr = 0; int wtr = 0;
@ -447,9 +454,69 @@ void resizetoimageheight(int imageheight) {
jumptoindex(i); jumptoindex(i);
} }
drawmenu(); drawmenu_layer();
#endif
} }
#endif
#if USEWAYLAND
void resizetoimageheight_wl(int imageheight) {
int omh = mh, olines = lines;
lines = reallines;
int wtr = 0;
if (lines * bh < imageheight + imagegaps * 2) {
lines = (imageheight + imagegaps * 2) / bh;
}
if (hideprompt && hideinput && hidemode && hidematchcount) {
wtr = bh;
}
mh = MAX((lines + 1) * bh + 2 * menumarginv, ((lines + 1) * bh) - wtr + 2 * menumarginv);
if (mh - bh < imageheight + imagegaps * 2) {
mh = (imageheight + imagegaps * 2 + bh) - wtr + 2 * menumarginv;
}
if (omh == mh) {
return;
}
if (olines != lines) {
struct item *item;
unsigned int i = 1;
// walk through all matches
for (item = matches; item && item != sel; item = item->right)
++i;
jumptoindex(i);
}
state.width = mw;
state.height = mh;
state.buffer = create_buffer(&state);
if (drw == NULL) {
die("spmenu: drw == NULL");
}
if (state.buffer == NULL) {
die("state.buffer == null");
}
set_layer_size(&state, state.width, state.height);
drw_create_surface_wl(drw, state.data, state.width, state.height);
drawmenu();
wl_surface_set_buffer_scale(state.surface, 1);
wl_surface_attach(state.surface, state.buffer, 0, 0);
wl_surface_damage(state.surface, 0, 0, state.width, state.height);
wl_surface_commit(state.surface);
}
#endif
void store_image_vars(void) { void store_image_vars(void) {
longestedge = MAX(imagewidth, imageheight); longestedge = MAX(imagewidth, imageheight);

View file

@ -7,16 +7,19 @@
#include <openssl/md5.h> #include <openssl/md5.h>
static void setimagesize(int width, int height); static void setimagesize(int width, int height);
#if USEX
static void setimageopts(void); static void setimageopts(void);
#endif
static void cleanupimage(void); static void cleanupimage(void);
static void drawimage(void); static void drawimage(void);
static void rotateimage(void);
static void flipimage(void); static void flipimage(void);
static void loadimage(const char *file, int *width, int *height); static void loadimage(const char *file, int *width, int *height);
static void loadimagecache(const char *file, int *width, int *height); static void loadimagecache(const char *file, int *width, int *height);
static void resizetoimageheight(int imageheight); static void resizetoimageheight(int imagewidth, int imageheight);
#if USEWAYLAND
static void resizetoimageheight_wl(int imageheight);
#endif
#if USEX
static void resizetoimageheight_x11(int imageheight);
#endif
static void store_image_vars(void); static void store_image_vars(void);
static Imlib_Image image = NULL; static Imlib_Image image = NULL;

View file

@ -415,6 +415,28 @@ void drw_cur_free(Drw *drw, Cur *cursor) {
#endif #endif
} }
void drw_set_img(Drw *drw, void *data, int w, int h) {
if (!w || !h || !drw) {
return;
}
drw->img_data = data;
drw->img_surface = cairo_image_surface_create_for_data(drw->img_data, CAIRO_FORMAT_ARGB32, w, h, w * 4);
}
void drw_img(Drw *drw, int x, int y) {
if (!drw) {
return;
}
cairo_set_operator(drw->d, CAIRO_OPERATOR_OVER);
cairo_set_source_surface(drw->d, drw->img_surface, x, y);
cairo_paint(drw->d);
cairo_set_source_surface(drw->d, drw->surface, drw->w, drw->h);
}
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n, Bool markup) { unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n, Bool markup) {
unsigned int tmp = 0; unsigned int tmp = 0;
if (drw && drw->font && text && n) if (drw && drw->font && text && n)

View file

@ -24,18 +24,25 @@ typedef struct {
Window root; Window root;
Visual *visual; Visual *visual;
unsigned int depth; unsigned int depth;
void *img_data;
void *data; void *data;
Colormap cmap; Colormap cmap;
Drawable drawable; Drawable drawable;
GC gc; GC gc;
Fnt *font; Fnt *font;
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_surface_t *img_surface;
cairo_t *d; cairo_t *d;
cairo_t *img_d;
} Drw; } Drw;
/* Cairo color convertion */ /* Cairo color convertion */
void cairo_set_source_hex(cairo_t* cr, const char *col, int alpha); void cairo_set_source_hex(cairo_t* cr, const char *col, int alpha);
/* Cairo image drawing */
void drw_img(Drw *drw, int x, int y);
void drw_set_img(Drw *drw, void *data, int w, int h);
/* Drawable abstraction */ /* Drawable abstraction */
Drw *drw_create_x11(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap, int protocol); Drw *drw_create_x11(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap, int protocol);
Drw *drw_create_wl(int protocol); Drw *drw_create_wl(int protocol);

View file

@ -145,6 +145,7 @@ static int set_exclusive_zone(struct state *state, unsigned int val);
static int set_keyboard(struct state *state, int interactivity); static int set_keyboard(struct state *state, int interactivity);
static int add_layer_listener(struct state *state); static int add_layer_listener(struct state *state);
static int set_visible_layer(struct state *state); static int set_visible_layer(struct state *state);
struct wl_buffer *create_buffer(struct state *state);
/* Set to 0 if the connection was successful /* Set to 0 if the connection was successful
* You can use this for say, X11 compatibility mode. * You can use this for say, X11 compatibility mode.

View file

@ -93,7 +93,7 @@ void resizeclient_x11(void) {
// resize client to image height // resize client to image height
#if USEIMAGE #if USEIMAGE
if (image) resizetoimageheight(imageheight); if (image) resizetoimageheight(imagewidth, imageheight);
#endif #endif
mh = (lines + 1) * bh + 2 * menumarginv; mh = (lines + 1) * bh + 2 * menumarginv;

View file

@ -1,7 +1,6 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
void eventloop_x11(void) { void eventloop_x11(void) {
XEvent ev; XEvent ev;
int noimg = 0;
while (!XNextEvent(dpy, &ev)) { while (!XNextEvent(dpy, &ev)) {
if (XFilterEvent(&ev, None)) if (XFilterEvent(&ev, None))
@ -15,7 +14,6 @@ void eventloop_x11(void) {
exit(1); exit(1);
case ButtonPress: case ButtonPress:
buttonpress_x11(&ev); buttonpress_x11(&ev);
noimg = 0;
break; break;
case MotionNotify: // currently does nothing case MotionNotify: // currently does nothing
break; break;
@ -35,7 +33,6 @@ void eventloop_x11(void) {
} }
keypress_x11(&ev); keypress_x11(&ev);
noimg = 1;
break; break;
case SelectionNotify: // paste selection case SelectionNotify: // paste selection
if (ev.xselection.property == utf8) if (ev.xselection.property == utf8)
@ -48,7 +45,6 @@ void eventloop_x11(void) {
case KeyRelease: case KeyRelease:
getcapsstate(); getcapsstate();
drawmenu(); drawmenu();
noimg = 0;
break; break;
} }
@ -67,13 +63,5 @@ void eventloop_x11(void) {
drawmenu(); drawmenu();
} }
} }
// redraw image on X11 event
if (!noimg)
#if USEIMAGE
drawimage();
#else
;
#endif
} }
} }

View file

@ -10,7 +10,7 @@ void setupdisplay_x11(void) {
// resize client to image height if deemed necessary // resize client to image height if deemed necessary
#if USEIMAGE #if USEIMAGE
if (image) resizetoimageheight(imageheight); if (image) resizetoimageheight(imagewidth, imageheight);
#endif #endif
// set prompt width based on prompt size // set prompt width based on prompt size

View file

@ -57,7 +57,7 @@ if get_option('wayland')
run_command('scripts/make/generate-headers.sh', check : false) run_command('scripts/make/generate-headers.sh', check : false)
endif endif
if get_option('imlib2') and get_option('openssl') and get_option('x11') if get_option('imlib2') and get_option('openssl')
project_dependencies += [ dependency('imlib2') ] project_dependencies += [ dependency('imlib2') ]
project_dependencies += [ dependency('openssl') ] project_dependencies += [ dependency('openssl') ]
build_args += [ '-DIMAGE' ] build_args += [ '-DIMAGE' ]

View file

@ -1001,17 +1001,6 @@ T{
T}@T{ T}@T{
0 0
T}@T{ T}@T{
r
T}@T{
rotateimg
T}@T{
0
T}
T{
0
T}@T{
0
T}@T{
o o
T}@T{ T}@T{
setimgpos setimgpos

View file

@ -153,7 +153,6 @@ struct item {
// image globals // image globals
#if USEIMAGE #if USEIMAGE
static int flip = 0; static int flip = 0;
static int rotation = 0;
static int needredraw = 1; static int needredraw = 1;
static int longestedge = 0; static int longestedge = 0;
static int imagew = 0; static int imagew = 0;
@ -495,7 +494,7 @@ void handle(void) {
} }
loadhistory(); // read history entries loadhistory(); // read history entries
#if USEX #if USEIMAGE
store_image_vars(); store_image_vars();
#endif #endif

View file

@ -1186,284 +1186,277 @@ a <code>keybinds.h</code> using
<tr class="odd"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">r</td>
<td style="text-align: left;">rotateimg</td>
<td style="text-align: left;">0</td>
</tr>
<tr class="even">
<td style="text-align: left;">0</td>
<td style="text-align: left;">0</td>
<td style="text-align: left;">o</td> <td style="text-align: left;">o</td>
<td style="text-align: left;">setimgpos</td> <td style="text-align: left;">setimgpos</td>
<td style="text-align: left;">+1</td> <td style="text-align: left;">+1</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">1</td> <td style="text-align: left;">1</td>
<td style="text-align: left;">setimggaps</td> <td style="text-align: left;">setimggaps</td>
<td style="text-align: left;">-1</td> <td style="text-align: left;">-1</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">2</td> <td style="text-align: left;">2</td>
<td style="text-align: left;">setimggaps</td> <td style="text-align: left;">setimggaps</td>
<td style="text-align: left;">+1</td> <td style="text-align: left;">+1</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">1</td> <td style="text-align: left;">1</td>
<td style="text-align: left;">setimggaps</td> <td style="text-align: left;">setimggaps</td>
<td style="text-align: left;">-10</td> <td style="text-align: left;">-10</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">2</td> <td style="text-align: left;">2</td>
<td style="text-align: left;">setimggaps</td> <td style="text-align: left;">setimggaps</td>
<td style="text-align: left;">+10</td> <td style="text-align: left;">+10</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Shift</td> <td style="text-align: left;">Shift</td>
<td style="text-align: left;">1</td> <td style="text-align: left;">1</td>
<td style="text-align: left;">setimggaps</td> <td style="text-align: left;">setimggaps</td>
<td style="text-align: left;">-100</td> <td style="text-align: left;">-100</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Shift</td> <td style="text-align: left;">Shift</td>
<td style="text-align: left;">2</td> <td style="text-align: left;">2</td>
<td style="text-align: left;">setimggaps</td> <td style="text-align: left;">setimggaps</td>
<td style="text-align: left;">+100</td> <td style="text-align: left;">+100</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">t</td> <td style="text-align: left;">t</td>
<td style="text-align: left;">toggleimg</td> <td style="text-align: left;">toggleimg</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">f</td> <td style="text-align: left;">f</td>
<td style="text-align: left;">togglefullimg</td> <td style="text-align: left;">togglefullimg</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">p</td> <td style="text-align: left;">p</td>
<td style="text-align: left;">paste</td> <td style="text-align: left;">paste</td>
<td style="text-align: left;">2</td> <td style="text-align: left;">2</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">h</td> <td style="text-align: left;">h</td>
<td style="text-align: left;">flipimg</td> <td style="text-align: left;">flipimg</td>
<td style="text-align: left;">1</td> <td style="text-align: left;">1</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">v</td> <td style="text-align: left;">v</td>
<td style="text-align: left;">flipimg</td> <td style="text-align: left;">flipimg</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">k</td> <td style="text-align: left;">k</td>
<td style="text-align: left;">moveup</td> <td style="text-align: left;">moveup</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">j</td> <td style="text-align: left;">j</td>
<td style="text-align: left;">movedown</td> <td style="text-align: left;">movedown</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">h</td> <td style="text-align: left;">h</td>
<td style="text-align: left;">moveleft</td> <td style="text-align: left;">moveleft</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">l</td> <td style="text-align: left;">l</td>
<td style="text-align: left;">moveright</td> <td style="text-align: left;">moveright</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">u</td> <td style="text-align: left;">u</td>
<td style="text-align: left;">moveup</td> <td style="text-align: left;">moveup</td>
<td style="text-align: left;">5</td> <td style="text-align: left;">5</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">d</td> <td style="text-align: left;">d</td>
<td style="text-align: left;">movedown</td> <td style="text-align: left;">movedown</td>
<td style="text-align: left;">5</td> <td style="text-align: left;">5</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">k</td> <td style="text-align: left;">k</td>
<td style="text-align: left;">setlines</td> <td style="text-align: left;">setlines</td>
<td style="text-align: left;">+1</td> <td style="text-align: left;">+1</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">j</td> <td style="text-align: left;">j</td>
<td style="text-align: left;">setlines</td> <td style="text-align: left;">setlines</td>
<td style="text-align: left;">-1</td> <td style="text-align: left;">-1</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl+Alt+Shift</td> <td style="text-align: left;">Ctrl+Alt+Shift</td>
<td style="text-align: left;">k</td> <td style="text-align: left;">k</td>
<td style="text-align: left;">setlines</td> <td style="text-align: left;">setlines</td>
<td style="text-align: left;">+5</td> <td style="text-align: left;">+5</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl+Alt+Shift</td> <td style="text-align: left;">Ctrl+Alt+Shift</td>
<td style="text-align: left;">j</td> <td style="text-align: left;">j</td>
<td style="text-align: left;">setlines</td> <td style="text-align: left;">setlines</td>
<td style="text-align: left;">-5</td> <td style="text-align: left;">-5</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">h</td> <td style="text-align: left;">h</td>
<td style="text-align: left;">setcolumns</td> <td style="text-align: left;">setcolumns</td>
<td style="text-align: left;">+1</td> <td style="text-align: left;">+1</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl</td> <td style="text-align: left;">Ctrl</td>
<td style="text-align: left;">l</td> <td style="text-align: left;">l</td>
<td style="text-align: left;">setcolumns</td> <td style="text-align: left;">setcolumns</td>
<td style="text-align: left;">-1</td> <td style="text-align: left;">-1</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl+Alt+Shift</td> <td style="text-align: left;">Ctrl+Alt+Shift</td>
<td style="text-align: left;">h</td> <td style="text-align: left;">h</td>
<td style="text-align: left;">setcolumns</td> <td style="text-align: left;">setcolumns</td>
<td style="text-align: left;">+5</td> <td style="text-align: left;">+5</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl+Alt+Shift</td> <td style="text-align: left;">Ctrl+Alt+Shift</td>
<td style="text-align: left;">l</td> <td style="text-align: left;">l</td>
<td style="text-align: left;">setcolumns</td> <td style="text-align: left;">setcolumns</td>
<td style="text-align: left;">-5</td> <td style="text-align: left;">-5</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">u</td> <td style="text-align: left;">u</td>
<td style="text-align: left;">togglehighlight</td> <td style="text-align: left;">togglehighlight</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Ctrl+Shift</td> <td style="text-align: left;">Ctrl+Shift</td>
<td style="text-align: left;">h</td> <td style="text-align: left;">h</td>
<td style="text-align: left;">viewhist</td> <td style="text-align: left;">viewhist</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">d</td> <td style="text-align: left;">d</td>
<td style="text-align: left;">clear</td> <td style="text-align: left;">clear</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Shift</td> <td style="text-align: left;">Shift</td>
<td style="text-align: left;">d</td> <td style="text-align: left;">d</td>
<td style="text-align: left;">clearins</td> <td style="text-align: left;">clearins</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Escape</td> <td style="text-align: left;">Escape</td>
<td style="text-align: left;">quit</td> <td style="text-align: left;">quit</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Home</td> <td style="text-align: left;">Home</td>
<td style="text-align: left;">movestart</td> <td style="text-align: left;">movestart</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">End</td> <td style="text-align: left;">End</td>
<td style="text-align: left;">moveend</td> <td style="text-align: left;">moveend</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">g</td> <td style="text-align: left;">g</td>
<td style="text-align: left;">movestart</td> <td style="text-align: left;">movestart</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Shift</td> <td style="text-align: left;">Shift</td>
<td style="text-align: left;">g</td> <td style="text-align: left;">g</td>
<td style="text-align: left;">moveend</td> <td style="text-align: left;">moveend</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Next</td> <td style="text-align: left;">Next</td>
<td style="text-align: left;">movenext</td> <td style="text-align: left;">movenext</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Prior</td> <td style="text-align: left;">Prior</td>
<td style="text-align: left;">moveprev</td> <td style="text-align: left;">moveprev</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Alt</td> <td style="text-align: left;">Alt</td>
<td style="text-align: left;">p</td> <td style="text-align: left;">p</td>
<td style="text-align: left;">navhistory</td> <td style="text-align: left;">navhistory</td>
<td style="text-align: left;">-1</td> <td style="text-align: left;">-1</td>
</tr> </tr>
<tr class="even"> <tr class="odd">
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Alt</td> <td style="text-align: left;">Alt</td>
<td style="text-align: left;">n</td> <td style="text-align: left;">n</td>
<td style="text-align: left;">navhistory</td> <td style="text-align: left;">navhistory</td>
<td style="text-align: left;">+1</td> <td style="text-align: left;">+1</td>
</tr> </tr>
<tr class="odd"> <tr class="even">
<td style="text-align: left;">1</td> <td style="text-align: left;">1</td>
<td style="text-align: left;">0</td> <td style="text-align: left;">0</td>
<td style="text-align: left;">Escape</td> <td style="text-align: left;">Escape</td>