Add some more comments

This commit is contained in:
speedie 2023-07-16 02:57:38 +02:00
parent 8e33d4c667
commit 7b7c1a56f4
4 changed files with 104 additions and 65 deletions

View file

@ -4,14 +4,17 @@ void moveleft(Arg *arg) {
int i, offscreen = 0; int i, offscreen = 0;
int argu = arg->i ? arg->i : 1; int argu = arg->i ? arg->i : 1;
// If we cannot move left because !lines, moving left should move to the next item. Calling moveup() does this.
if (!lines) { if (!lines) {
moveup(arg); moveup(arg);
return; return;
} }
if (columns > 1) { if (columns > 1) {
if (!sel) if (!sel) {
return; return;
}
tmpsel = sel; tmpsel = sel;
for (i = 0; i < lines; i++) { for (i = 0; i < lines; i++) {
if (!tmpsel->left || tmpsel->left->right != tmpsel) { if (!tmpsel->left || tmpsel->left->right != tmpsel) {
@ -40,7 +43,7 @@ void moveright(Arg *arg) {
int i, offscreen = 0; int i, offscreen = 0;
int argu = arg->i ? arg->i : 1; int argu = arg->i ? arg->i : 1;
if (!lines) { if (!lines) { // If we cannot move right because !lines, moving right should move to the previous item. Calling down() does this.
movedown(arg); movedown(arg);
return; return;
} }
@ -75,7 +78,7 @@ void movedown(Arg *arg) {
for (int j = 0; j < argu; j++) { for (int j = 0; j < argu; j++) {
if (sel && sel->right && (sel = sel->right) == next) { if (sel && sel->right && (sel = sel->right) == next) {
curr = next; curr = next; // Current item is now the next item
} }
} }
@ -88,7 +91,7 @@ void moveup(Arg *arg) {
for (int j = 0; j < argu; j++) { for (int j = 0; j < argu; j++) {
if (sel && sel->left && (sel = sel->left)->right == curr) { if (sel && sel->left && (sel = sel->left)->right == curr) {
curr = prev; curr = prev; // Current item is now the previous item
} }
} }

View file

@ -9,8 +9,8 @@ int draw_icon(struct item *item, int x, int y, int w, int h) {
int slen = 0, i; int slen = 0, i;
unsigned int digest_len = EVP_MD_size(EVP_md5()); unsigned int digest_len = EVP_MD_size(EVP_md5());
unsigned char *digest = (unsigned char *)OPENSSL_malloc(digest_len); unsigned char *digest = (unsigned char *)OPENSSL_malloc(digest_len);
char *xdg_cache, *home = NULL, *dsize, *buf = NULL; char *xdg_cache, *home = NULL, *cachesize, *buf = NULL;
struct passwd *pw = NULL; struct passwd *user_id = NULL;
if (hideimage) { if (hideimage) {
return x; return x;
@ -19,15 +19,17 @@ int draw_icon(struct item *item, int x, int y, int w, int h) {
if (item->image) { if (item->image) {
if (generatecache) { if (generatecache) {
if(!(xdg_cache = getenv("XDG_CACHE_HOME"))) { if(!(xdg_cache = getenv("XDG_CACHE_HOME"))) {
if(!(home = getenv("HOME")) && (pw = getpwuid(getuid()))) if(!(home = getenv("HOME")) && (user_id = getpwuid(getuid()))) {
home = pw->pw_dir; home = user_id->pw_dir;
if(!home) { }
if(!home) { // no home directory.. somehow
fprintf(stderr, "spmenu: could not find home directory"); fprintf(stderr, "spmenu: could not find home directory");
return x; return x;
} }
} }
dsize = "icon"; cachesize = "icon";
slen = snprintf(NULL, 0, "file://%s", item->image)+1; slen = snprintf(NULL, 0, "file://%s", item->image)+1;
@ -46,34 +48,34 @@ int draw_icon(struct item *item, int x, int y, int w, int h) {
free(buf); free(buf);
char md5[digest_len*2+1]; char md5sum[digest_len*2+1];
for (i = 0; i < digest_len; ++i) for (i = 0; i < digest_len; ++i)
sprintf(&md5[i*2], "%02x", (unsigned int)digest[i]); sprintf(&md5sum[i*2], "%02x", (unsigned int)digest[i]);
if (!cachedir || !strcmp(cachedir, "default")) { if (!cachedir || !strcmp(cachedir, "default")) { // "default" here is from the config file
if (xdg_cache || !strcmp(cachedir, "xdg")) if (xdg_cache || !strcmp(cachedir, "xdg"))
slen = snprintf(NULL, 0, "%s/thumbnails/%s/%s.png", xdg_cache, dsize, md5)+1; slen = snprintf(NULL, 0, "%s/thumbnails/%s/%s.png", xdg_cache, cachesize, md5sum)+1;
else else
slen = snprintf(NULL, 0, "%s/.cache/thumbnails/%s/%s.png", home, dsize, md5)+1; slen = snprintf(NULL, 0, "%s/.cache/thumbnails/%s/%s.png", home, cachesize, md5sum)+1;
} else { } else {
slen = snprintf(NULL, 0, "%s/%s/%s.png", cachedir, dsize, md5)+1; slen = snprintf(NULL, 0, "%s/%s/%s.png", cachedir, cachesize, md5sum)+1;
} }
if(!(buf = malloc(slen))) { if(!(buf = malloc(slen))) {
return x; return x;
} }
if (!cachedir || !strcmp(cachedir, "default")) { if (!cachedir || !strcmp(cachedir, "default")) { // "default" here is from the config file
if (xdg_cache) if (xdg_cache)
sprintf(buf, "%s/thumbnails/%s/%s.png", xdg_cache, dsize, md5); sprintf(buf, "%s/thumbnails/%s/%s.png", xdg_cache, cachesize, md5sum);
else else
sprintf(buf, "%s/.cache/thumbnails/%s/%s.png", home, dsize, md5); sprintf(buf, "%s/.cache/thumbnails/%s/%s.png", home, cachesize, md5sum);
} else { } else {
sprintf(buf, "%s/%s/%s.png", cachedir, dsize, md5); sprintf(buf, "%s/%s/%s.png", cachedir, cachesize, md5sum);
} }
image = imlib_load_image(buf); image = imlib_load_image(buf); // attempt to load image from path
if (image) { if (image) {
imlib_context_set_image(image); imlib_context_set_image(image);
@ -83,10 +85,15 @@ int draw_icon(struct item *item, int x, int y, int w, int h) {
} }
} }
/* If passed w or h has changed, cache is invalid and has to be regenerated. This prevents flickering.
* It could change if sp.bh has changed in some way, such as font size being changed after cache has
* been generated.
*/
if (ich != h || icw != w) { if (ich != h || icw != w) {
image = NULL; image = NULL;
} }
// load regular image, because an image was not loaded from cache
if (!image || !generatecache) { if (!image || !generatecache) {
image = imlib_load_image(item->image); image = imlib_load_image(item->image);
@ -107,19 +114,21 @@ int draw_icon(struct item *item, int x, int y, int w, int h) {
imlib_free_image(); imlib_free_image();
imlib_context_set_image(image); imlib_context_set_image(image);
// get new width/height
icw = imlib_image_get_width(); icw = imlib_image_get_width();
ich = imlib_image_get_height(); ich = imlib_image_get_height();
} }
imlib_image_set_format("png"); imlib_image_set_format("png");
// create directory and write cache file
if (buf && generatecache && image) { if (buf && generatecache && image) {
createifnexist_rec(buf); createifnexist_rec(buf);
imlib_save_image(buf); imlib_save_image(buf);
free(buf); free(buf);
} }
// Draw the image // draw the image
draw_set_img(draw, imlib_image_get_data(), w, h); draw_set_img(draw, imlib_image_get_data(), w, h);
draw_img(draw, x, y); draw_img(draw, x, y);

View file

@ -190,8 +190,8 @@ void loadimagecache(const char *file, int *width, int *height) {
int slen = 0, i; int slen = 0, i;
unsigned int digest_len = EVP_MD_size(EVP_md5()); unsigned int digest_len = EVP_MD_size(EVP_md5());
unsigned char *digest = (unsigned char *)OPENSSL_malloc(digest_len); unsigned char *digest = (unsigned char *)OPENSSL_malloc(digest_len);
char *xdg_cache, *home = NULL, *dsize, *buf = NULL; char *xdg_cache, *home = NULL, *cachesize, *buf = NULL;
struct passwd *pw = NULL; struct passwd *user_id = NULL;
// just load and don't store or try cache // just load and don't store or try cache
if (img.longestedge > maxcache) { if (img.longestedge > maxcache) {
@ -204,18 +204,20 @@ void loadimagecache(const char *file, int *width, int *height) {
if (generatecache) { if (generatecache) {
// try find image from cache first // try find image from cache first
if(!(xdg_cache = getenv("XDG_CACHE_HOME"))) { if(!(xdg_cache = getenv("XDG_CACHE_HOME"))) {
if(!(home = getenv("HOME")) && (pw = getpwuid(getuid()))) if(!(home = getenv("HOME")) && (user_id = getpwuid(getuid()))) {
home = pw->pw_dir; home = user_id->pw_dir;
if(!home) { }
if(!home) { // no home directory could be grabbed.. somehow
fprintf(stderr, "spmenu: could not find home directory"); fprintf(stderr, "spmenu: could not find home directory");
return; return;
} }
} }
// which cache do we try? // which cache do we try?
dsize = "normal"; cachesize = "normal";
if (img.longestedge > 128) if (img.longestedge > 128)
dsize = "large"; cachesize = "large";
slen = snprintf(NULL, 0, "file://%s", file)+1; slen = snprintf(NULL, 0, "file://%s", file)+1;
@ -243,11 +245,11 @@ void loadimagecache(const char *file, int *width, int *height) {
// path for cached thumbnail // path for cached thumbnail
if (!cachedir || !strcmp(cachedir, "default")) { if (!cachedir || !strcmp(cachedir, "default")) {
if (xdg_cache || !strcmp(cachedir, "xdg")) if (xdg_cache || !strcmp(cachedir, "xdg"))
slen = snprintf(NULL, 0, "%s/thumbnails/%s/%s.png", xdg_cache, dsize, md5)+1; slen = snprintf(NULL, 0, "%s/thumbnails/%s/%s.png", xdg_cache, cachesize, md5)+1;
else else
slen = snprintf(NULL, 0, "%s/.cache/thumbnails/%s/%s.png", home, dsize, md5)+1; slen = snprintf(NULL, 0, "%s/.cache/thumbnails/%s/%s.png", home, cachesize, md5)+1;
} else { } else {
slen = snprintf(NULL, 0, "%s/%s/%s.png", cachedir, dsize, md5)+1; slen = snprintf(NULL, 0, "%s/%s/%s.png", cachedir, cachesize, md5)+1;
} }
if(!(buf = malloc(slen))) { if(!(buf = malloc(slen))) {
@ -256,11 +258,11 @@ void loadimagecache(const char *file, int *width, int *height) {
if (!cachedir || !strcmp(cachedir, "default")) { if (!cachedir || !strcmp(cachedir, "default")) {
if (xdg_cache) if (xdg_cache)
sprintf(buf, "%s/thumbnails/%s/%s.png", xdg_cache, dsize, md5); sprintf(buf, "%s/thumbnails/%s/%s.png", xdg_cache, cachesize, md5);
else else
sprintf(buf, "%s/.cache/thumbnails/%s/%s.png", home, dsize, md5); sprintf(buf, "%s/.cache/thumbnails/%s/%s.png", home, cachesize, md5);
} else { } else {
sprintf(buf, "%s/%s/%s.png", cachedir, dsize, md5); sprintf(buf, "%s/%s/%s.png", cachedir, cachesize, md5);
} }
loadimage(buf, width, height); loadimage(buf, width, height);
@ -298,7 +300,7 @@ void jumptoindex(unsigned int index) {
calcoffsets(); calcoffsets();
for (i = 1; i < index; ++i) { for (i = 1; i < index; ++i) { // move to item index
if(sel && sel->right && (sel = sel->right) == next) { if(sel && sel->right && (sel = sel->right) == next) {
curr = next; curr = next;
calcoffsets(); calcoffsets();

View file

@ -95,7 +95,7 @@
// include macros and other defines // include macros and other defines
#include "libs/define.c" #include "libs/define.c"
enum { enum { // click enum
ClickWindow, ClickWindow,
ClickPrompt, ClickPrompt,
ClickInput, ClickInput,
@ -159,7 +159,7 @@ struct mo {
struct img { struct img {
int setlines; // actual lines int setlines; // actual lines
int flip; // %= int flip; // %=
int longestedge; // MAX(imagewidth, imagheight) int longestedge; // MAX(imagewidth, imageheight)
int imagewidth; // current image width int imagewidth; // current image width
int imageheight; // current image height int imageheight; // current image height
int imagegaps; // current image gaps int imagegaps; // current image gaps
@ -206,12 +206,12 @@ static struct item *prev, *curr, *next, *sel;
#include "libs/stream.h" #include "libs/stream.h"
#include "libs/schemes.h" #include "libs/schemes.h"
#include "libs/arg.h" #include "libs/arg.h"
#include "libs/x11/inc.h" // include x11 #include "libs/x11/inc.h"
#include "libs/wl/inc.h" // include wayland #include "libs/wl/inc.h"
#include "libs/sort.h" #include "libs/sort.h"
#include "libs/history.h" #include "libs/history.h"
static Draw_t *draw; static Draw_t *draw; // Draw_t type, see libs/draw/draw.c
// high priority // high priority
static int hplength = 0; static int hplength = 0;
@ -243,13 +243,15 @@ static void handle(void);
static void appenditem(struct item *item, struct item **list, struct item **last); static void appenditem(struct item *item, struct item **list, struct item **last);
static int max_textw(void); static int max_textw(void);
static size_t nextrune(int inc); static size_t nextrune(int inc);
// matching
static char * cistrstr(const char *s, const char *sub); static char * cistrstr(const char *s, const char *sub);
static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp; static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
static char *(*fstrstr)(const char *, const char *) = cistrstr; static char *(*fstrstr)(const char *, const char *) = cistrstr;
#if USEX #if USEX
static void pastesel(void); static void pastesel(void); // TODO: wayland clipboard
static void grabfocus(void); static void grabfocus(void); // focus doesn't need to be grabbed on wayland
#endif #endif
static char **list; static char **list;
@ -298,7 +300,7 @@ static char *fonts[] = { font };
int is_selected(size_t index) { int is_selected(size_t index) {
for (int i = 0; i < sel_size; i++) { for (int i = 0; i < sel_size; i++) {
if (sel_index[i] == index) { if (sel_index[i] == index) {
return 1; return 1; // selected item index is size_t index
} }
} }
@ -319,6 +321,7 @@ void appenditem(struct item *item, struct item **list, struct item **last) {
void recalculatenumbers(void) { void recalculatenumbers(void) {
unsigned int numer = 0, denom = 0, selected = 0; unsigned int numer = 0, denom = 0, selected = 0;
struct item *item; struct item *item;
if (matchend) { if (matchend) {
numer++; numer++;
@ -328,8 +331,9 @@ void recalculatenumbers(void) {
} }
// walk through all items, matching or not and add to denom // walk through all items, matching or not and add to denom
for (item = items; item && item->text; item++) for (item = items; item && item->text; item++) {
denom++; denom++;
}
for (int i = 0; i < sel_size; i++) { for (int i = 0; i < sel_size; i++) {
if (sel_index[i] == -1) { if (sel_index[i] == -1) {
@ -347,37 +351,38 @@ void recalculatenumbers(void) {
} }
void calcoffsets(void) { void calcoffsets(void) {
int i, n; int i, offset;
if (lines > 0) if (lines > 0) {
n = lines * columns * sp.bh; offset = lines * columns * sp.bh;
else { // no lines, therefore the size of items must be decreased to fit the menu elements } else { // no lines, therefore the size of items must be decreased to fit the menu elements
int numberw = 0; int numberw = 0;
int modeWidth = 0; int modew = 0;
int larroww = 0; int larroww = 0;
int rarrowWidth = 0; int rarroww = 0;
int capsw = 0; int capsw = 0;
if (!hidematchcount) numberw = pango_numbers ? TEXTWM(tx.numbers) : TEXTW(tx.numbers); if (!hidematchcount) numberw = pango_numbers ? TEXTWM(tx.numbers) : TEXTW(tx.numbers);
if (!hidemode) modeWidth = pango_mode ? TEXTWM(tx.modetext) : TEXTW(tx.modetext); if (!hidemode) modew = pango_mode ? TEXTWM(tx.modetext) : TEXTW(tx.modetext);
if (!hidelarrow) larroww = pango_leftarrow ? TEXTWM(leftarrow) : TEXTW(leftarrow); if (!hidelarrow) larroww = pango_leftarrow ? TEXTWM(leftarrow) : TEXTW(leftarrow);
if (!hiderarrow) rarrowWidth = pango_rightarrow ? TEXTWM(rightarrow) : TEXTW(rightarrow); if (!hiderarrow) rarroww = pango_rightarrow ? TEXTWM(rightarrow) : TEXTW(rightarrow);
if (!hidecaps) capsw = pango_caps ? TEXTWM(tx.capstext) : TEXTW(tx.capstext); if (!hidecaps) capsw = pango_caps ? TEXTWM(tx.capstext) : TEXTW(tx.capstext);
if (!strcmp(tx.capstext, "")) if (!strcmp(tx.capstext, "")) {
capsw = 0; capsw = 0;
}
n = sp.mw - (sp.promptw + sp.inputw + larroww + rarrowWidth + modeWidth + numberw + capsw + menumarginh); offset = sp.mw - (sp.promptw + sp.inputw + larroww + rarroww + modew + numberw + capsw + menumarginh);
} }
// calculate which items will begin the next page // calculate which items will begin the next page
for (i = 0, next = curr; next; next = next->right) for (i = 0, next = curr; next; next = next->right)
if ((i += (lines > 0) ? sp.bh : MIN(TEXTWM(next->text) + (powerlineitems ? !lines ? 2 * sp.plw : 0 : 0), n)) > n) if ((i += (lines > 0) ? sp.bh : MIN(TEXTWM(next->text) + (powerlineitems ? !lines ? 2 * sp.plw : 0 : 0), offset)) > offset)
break; break;
// calculate which items will begin the previous page // calculate which items will begin the previous page
for (i = 0, prev = curr; prev && prev->left; prev = prev->left) for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
if ((i += (lines > 0) ? sp.bh : MIN(TEXTWM(prev->left->text) + (powerlineitems ? !lines ? 2 * sp.plw : 0 : 0), n)) > n) if ((i += (lines > 0) ? sp.bh : MIN(TEXTWM(prev->left->text) + (powerlineitems ? !lines ? 2 * sp.plw : 0 : 0), offset)) > offset)
break; break;
} }
@ -413,6 +418,7 @@ void cleanup(void) {
free(sel_index); free(sel_index);
} }
// This function handles case insensitive matching
char * cistrstr(const char *h, const char *n) { char * cistrstr(const char *h, const char *n) {
size_t i; size_t i;
@ -438,17 +444,25 @@ void grabfocus(void) {
void insert(const char *str, ssize_t n) { void insert(const char *str, ssize_t n) {
if (strlen(tx.text) + n > sizeof tx.text - 1) if (strlen(tx.text) + n > sizeof tx.text - 1)
return; return; // length of text should not exceed size
static char l[BUFSIZ] = ""; static char l[BUFSIZ] = "";
if (requirematch) memcpy(l, tx.text, BUFSIZ);
if (requirematch) {
memcpy(l, tx.text, BUFSIZ);
}
// move existing text out of the way, insert new text, and update cursor // move existing text out of the way, insert new text, and update cursor
memmove(&tx.text[sp.cursor + n], &tx.text[sp.cursor], sizeof tx.text - sp.cursor - MAX(n, 0)); memmove(
&tx.text[sp.cursor + n],
&tx.text[sp.cursor],
sizeof tx.text - sp.cursor - MAX(n, 0)
);
// update cursor // update cursor
if (n > 0 && str && n) if (n > 0 && str && n) {
memcpy(&tx.text[sp.cursor], str, n); memcpy(&tx.text[sp.cursor], str, n);
}
// add to cursor position and continue matching // add to cursor position and continue matching
sp.cursor += n; sp.cursor += n;
@ -460,6 +474,7 @@ void insert(const char *str, ssize_t n) {
match(); match();
} }
// output on insertion
if (incremental) { if (incremental) {
puts(tx.text); puts(tx.text);
fflush(stdout); fflush(stdout);
@ -467,12 +482,13 @@ void insert(const char *str, ssize_t n) {
} }
size_t nextrune(int inc) { size_t nextrune(int inc) {
ssize_t n; ssize_t rune;
// return location of next utf8 rune in the given direction (+1 or -1) // return location of next utf8 rune in the given direction (+1 or -1)
for (n = sp.cursor + inc; n + inc >= 0 && (tx.text[n] & 0xc0) == 0x80; n += inc) for (rune = sp.cursor + inc; rune + inc >= 0 && (tx.text[rune] & 0xc0) == 0x80; rune += inc)
; ;
return n;
return rune;
} }
#if USEX #if USEX
@ -497,6 +513,10 @@ void resizeclient(void) {
#endif #endif
} }
/* Width reserved for input when !lines is a fixed size of the menu width / 3
* This is reasonable, but in rare cases may cause input text to overlap
* items.
*/
void get_width(void) { void get_width(void) {
sp.inputw = sp.mw / 3; sp.inputw = sp.mw / 3;
} }
@ -507,12 +527,14 @@ void get_mh(void) {
sp.mh = (lines + 1) * sp.bh; sp.mh = (lines + 1) * sp.bh;
sp.mh += 2 * menumarginv; sp.mh += 2 * menumarginv;
// subtract 1 line if there's nothing to draw on the top line
if ((hideprompt && hideinput && hidemode && hidematchcount && hidecaps) && lines) { if ((hideprompt && hideinput && hidemode && hidematchcount && hidecaps) && lines) {
sp.mh -= sp.bh; sp.mh -= sp.bh;
} }
epad = 2 * menupaddingv; epad = 2 * menupaddingv;
// the spmenu window should not exceed the screen resolution height
if (mo.output_height && !xpos && !ypos) { if (mo.output_height && !xpos && !ypos) {
sp.mh = MIN(sp.mh, mo.output_height - epad); sp.mh = MIN(sp.mh, mo.output_height - epad);
@ -540,6 +562,7 @@ void set_mode(void) {
sp_strncpy(tx.modetext, normtext, sizeof(tx.modetext)); sp_strncpy(tx.modetext, normtext, sizeof(tx.modetext));
} }
// normal mode disabled
if (sp.forceinsertmode) { if (sp.forceinsertmode) {
sp.mode = 1; sp.mode = 1;
sp.allowkeys = 1; sp.allowkeys = 1;
@ -608,7 +631,9 @@ void handle(void) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
readargs(argc, argv); // start by reading arguments readargs(argc, argv); // start by reading arguments
// pledge limits what programs can do, so here we specify what spmenu should be allowed to do /* pledge limits what programs can do, so here we specify what spmenu should be allowed to do
* TODO: test this on a openbsd operating system
*/
#ifdef __OpenBSD__ #ifdef __OpenBSD__
if (pledge("stdio rpath wpath cpath", NULL) == -1) if (pledge("stdio rpath wpath cpath", NULL) == -1)
die("pledge"); die("pledge");