From 6ac2afb24039c965286237071b6b4c972a71fcf4 Mon Sep 17 00:00:00 2001 From: speedie Date: Fri, 31 Mar 2023 12:42:15 +0200 Subject: [PATCH] add plenty of comments to spmenu --- TODO | 1 + libs/arg.c | 4 +- libs/arg.h | 8 +- libs/argv.c | 10 ++- libs/client.c | 23 ++++-- libs/colors.h | 5 +- libs/define.c | 2 +- libs/draw.c | 2 + libs/event.c | 4 +- libs/history.c | 92 ++++++++++++++++++++++ libs/history.h | 3 + libs/img-c.c | 49 +++++++----- libs/stream.c | 4 +- libs/xrdb.c | 25 +++--- spmenu.c | 209 ++++++++++++++++++------------------------------- 15 files changed, 252 insertions(+), 189 deletions(-) create mode 100644 libs/history.c create mode 100644 libs/history.h diff --git a/TODO b/TODO index be0edae..95a8961 100644 --- a/TODO +++ b/TODO @@ -7,3 +7,4 @@ - Use cairo for text drawing over Xft - MAYBE wayland support, but only if it doesn't require writing any extra code which as of now seems unlikely - Write documentation about profiles +- FIFO, used to dynamically refresh diff --git a/libs/arg.c b/libs/arg.c index a3482ec..b39bf58 100644 --- a/libs/arg.c +++ b/libs/arg.c @@ -509,6 +509,6 @@ setcolumns(const Arg *arg) void setprofile(const Arg *arg) { - int ax = system("command -v spmenu_profile > /dev/null && spmenu_profile --spmenu-set-profile > /dev/null"); - exit(ax); + // this just runs an external shell script to set the profile + exit(system("command -v spmenu_profile > /dev/null && spmenu_profile --spmenu-set-profile > /dev/null")); } diff --git a/libs/arg.h b/libs/arg.h index 28f7ab3..e7572a7 100644 --- a/libs/arg.h +++ b/libs/arg.h @@ -1,8 +1,8 @@ typedef union { - int i; - unsigned int ui; - float f; - const void *v; + int i; // integer + unsigned int ui; // unsigned int + float f; // float + const void *v; // void } Arg; // declare keybind functions diff --git a/libs/argv.c b/libs/argv.c index 606973a..770edcb 100644 --- a/libs/argv.c +++ b/libs/argv.c @@ -6,7 +6,8 @@ readargs(int argc, char *argv[]) int cxrdb = 0; - // check if we should load the xrdb/config, because it needs to be loaded before arguments are checked (internal -> xresources -> arguments) + // check if we should load the xrdb/config, because it needs to be loaded before arguments are checked + // priority: internal -> xresources -> arguments for (j = 1; j < argc; j++) { if (!strcmp(argv[j], "-xrdb") || (!strcmp(argv[j], "--xrdb"))) { xresources = 1; @@ -23,16 +24,19 @@ readargs(int argc, char *argv[]) } } + // TODO: improve this function significantly + // init/read xrdb if (xresources) { XrmInitialize(); + // also load config/profile if .Xresources if (loadconfig) { cxrdb = system("command -v spmenu_profile > /dev/null && spmenu_profile --spmenu-load-default-profile > /dev/null"); } - // avoid an annoying warning gcc will spit out when you don't care about the result - if (!cxrdb || cxrdb || xresources) load_xresources(); + if (!cxrdb||cxrdb) // load .Xresources, cxrdb is only here to avoid an annoying gcc warning + load_xresources(); } // no arguments diff --git a/libs/client.c b/libs/client.c index 2e4f71b..37291e8 100644 --- a/libs/client.c +++ b/libs/client.c @@ -1,8 +1,11 @@ void prepare_window_size(void) { + // set horizontal and vertical padding sp = menupaddingh; vp = (menuposition == 1) ? menupaddingv : - menupaddingv; + + return; } void @@ -13,7 +16,12 @@ create_window(int x, int y, int w, int h) swa.override_redirect = managed ? False : True; swa.background_pixel = 0; swa.colormap = cmap; - swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonPressMask | PointerMotionMask; + swa.event_mask = + ExposureMask | // mapping the drawing + KeyPressMask | // keypresses + VisibilityChangeMask | // whether or not client is visible + ButtonPressMask | // see buttonpress in libs/mouse.c for usage + PointerMotionMask; // we need pointer for selecting entries using the mouse // create client win = XCreateWindow(dpy, parentwin, x, y, w, h, borderwidth, @@ -29,17 +37,17 @@ set_window(void) { XClassHint ch = { class, class }; + // set border and class XSetWindowBorder(dpy, win, scheme[SchemeBorder][ColBg].pixel); XSetClassHint(dpy, win, &ch); - return; } void set_prop(void) { - XChangeProperty(dpy, win, types, XA_ATOM, 32, PropModeReplace, (unsigned char *) &dock, 1); - + // TODO: add toggle for this + XChangeProperty(dpy, win, types, XA_ATOM, 32, PropModeReplace, (unsigned char *) &dock, 1); // set dock property return; } @@ -58,17 +66,18 @@ resizeclient(void) lines = MIN(itemCount, MAX(lines, 0)); reallines = lines; + // resize client to image height #if USEIMAGE - if (image) - resizetoimageheight(imageheight); + if (image) resizetoimageheight(imageheight); #endif mh = (lines + 1) * bh; - // why have an empty line? + // why have an empty line? when there's nothing to draw there anyway? if (hideprompt && hideinput && hidemode && hidematchcount) mh += bh; + // no window/invalid window or menu height we had before is the same as the current window height if (!win || omh == mh) return; XResizeWindow(dpy, win, mw, mh); diff --git a/libs/colors.h b/libs/colors.h index 5b42094..171cae4 100644 --- a/libs/colors.h +++ b/libs/colors.h @@ -1,4 +1,4 @@ -// color scheme arrays +// alpha array static unsigned int alphas[][3] = { // fg bg border [SchemeLArrow] = { fgalpha, bgalpha, borderalpha }, @@ -18,6 +18,7 @@ static unsigned int alphas[][3] = { [SchemeBorder] = { fgalpha, bgalpha, borderalpha }, }; +// colorscheme array static char *colors[SchemeLast][2] = { // fg bg [SchemeLArrow] = { col_larrowfg, col_larrowbg }, @@ -37,7 +38,7 @@ static char *colors[SchemeLast][2] = { [SchemeBorder] = { NULL, col_bordercolor }, }; -// sgr colors +// sgr color array // to enable 256 color support, append to this. static char *textcolors[] = { col_sgrcolor0, diff --git a/libs/define.c b/libs/define.c index da6035d..8dc13a8 100644 --- a/libs/define.c +++ b/libs/define.c @@ -14,7 +14,7 @@ // item #define MAXITEMLENGTH 1024 -// user friendly names for all the modifiers +// user friendly names for all the modifiers we're using, but there are many more #define CONTROL ControlMask #define SHIFT ShiftMask #define ALT Mod1Mask diff --git a/libs/draw.c b/libs/draw.c index 979c799..e9911b0 100644 --- a/libs/draw.c +++ b/libs/draw.c @@ -389,6 +389,8 @@ drawmenu(void) if (!hideinput) x = drawinput(x, y, w); if (!hidemode) modeWidth = pango_mode ? TEXTWM(modetext) : TEXTW(modetext); + // draw the items, this function also calls drawrarrow() and drawlarrow() + // TODO: Allow hiding items, without setting columns to 0 drawitem(x, y, w); if (!hidematchcount) drawnumber(x, y, w, numberWidth, modeWidth); diff --git a/libs/event.c b/libs/event.c index b802f2b..a0140fb 100644 --- a/libs/event.c +++ b/libs/event.c @@ -36,10 +36,10 @@ eventloop(void) if (ev.xfocus.window != win) grabfocus(); break; - case KeyPress: + case KeyPress: // read key array and call functions keypress(&ev); break; - case SelectionNotify: + case SelectionNotify: // paste selection if (ev.xselection.property == utf8) pastesel(); break; diff --git a/libs/history.c b/libs/history.c new file mode 100644 index 0000000..04a6089 --- /dev/null +++ b/libs/history.c @@ -0,0 +1,92 @@ +void +loadhistory(void) +{ + FILE *fp = NULL; + static size_t cap = 0; + size_t llen; + char *line; + + // no history file, give up like i do with all things in life + if (!histfile) { + return; + } + + // open history file, return if it failed + fp = fopen(histfile, "r"); + if (!fp) { + fprintf(stderr, "spmenu: failed to open history file\n"); + return; + } + + for (;;) { + line = NULL; + llen = 0; + + if (-1 == getline(&line, &llen, fp)) { + if (ferror(fp)) { + die("spmenu: failed to read history"); + } + + free(line); + break; + } + + if (cap == histsz) { + cap += 64 * sizeof(char*); + history = realloc(history, cap); + if (!history) { + die("spmenu: failed to realloc memory"); + } + } + strtok(line, "\n"); + history[histsz] = line; + histsz++; + } + + histpos = histsz; + + if (fclose(fp)) { + die("spmenu: failed to close file %s", histfile); + } +} + +void +navigatehistfile(int dir) +{ + static char def[BUFSIZ]; + char *p = NULL; + size_t len = 0; + + if (!history || histpos + 1 == 0) + return; + + if (histsz == histpos) { + strncpy(def, text, sizeof(def)); + } + + switch (dir) { + case 1: + if (histpos < histsz - 1) { + p = history[++histpos]; + } else if (histpos == histsz - 1) { + p = def; + histpos++; + } + break; + case -1: + if (histpos > 0) { + p = history[--histpos]; + } + break; + } + + if (p == NULL) { + return; + } + + len = MIN(strlen(p), BUFSIZ - 1); + strcpy(text, p); + text[len] = '\0'; + cursor = len; + match(); +} diff --git a/libs/history.h b/libs/history.h new file mode 100644 index 0000000..f39232f --- /dev/null +++ b/libs/history.h @@ -0,0 +1,3 @@ +static char *histfile; +static char **history; +static size_t histsz, histpos; diff --git a/libs/img-c.c b/libs/img-c.c index 70989f7..9a21035 100644 --- a/libs/img-c.c +++ b/libs/img-c.c @@ -1,6 +1,7 @@ void setimagesize(int width, int height) { + // don't even bother if we don't have image support #if !USEIMAGE return; #endif @@ -11,6 +12,7 @@ setimagesize(int width, int height) // this makes sure we cannot scale the image up or down too much if ((!image && height < imageheight) || (!image && width < imagewidth) || width > mw || hideimage) return; + // original width/height oih = imageheight; oiw = imagewidth; @@ -33,6 +35,7 @@ setimagesize(int width, int height) void flipimage(void) { + // flip image switch (flip) { case 1: // horizontal imlib_image_flip_horizontal(); @@ -59,7 +62,7 @@ rotateimage(void) void cleanupimage(void) { - if (image) { + if (image) { // free image using imlib2 imlib_free_image(); image = NULL; } @@ -73,29 +76,30 @@ drawimage(void) if (!lines || !columns || hideimage) return; - // to prevent the image from being drawn multiple times + // to prevent the image from being drawn multiple times wasting resources if (!needredraw) { needredraw = 1; return; } + // load image cache if (sel && sel->image && strcmp(sel->image, limg ? limg : "")) { if (longestedge) loadimagecache(sel->image, &width, &height); - } else if ((!sel || !sel->image) && image) { - imlib_free_image(); - image = NULL; - } if (image && longestedge) { - + } else if ((!sel || !sel->image) && image) { // free image + cleanupimage(); + } if (image && longestedge) { // render the image + // rotate and flip, will return if we don't need to rotateimage(); flipimage(); int leftmargin = imagegaps; - if(mh != bh + height + imagegaps * 2) { + if (mh != bh + height + imagegaps * 2) { // menu height cannot be smaller than image height resizetoimageheight(height); } + // render image if (!imageposition) { // top mode = 0 if (height > width) width = height; @@ -110,9 +114,9 @@ drawimage(void) int minh = MIN(height, mh-bh-imagegaps*2); imlib_render_image_on_drawable(leftmargin+(imagewidth-width)/2, (minh-height)/2+bh+imagegaps); } + } - - } if (sel) { + if (sel) { limg = sel->image; } else { limg = NULL; @@ -135,13 +139,16 @@ setimageopts(void) void createifnexist(const char *dir) { - if(access(dir, F_OK) == 0) + // exists, so return + if (access(dir, F_OK) == 0) return; - if(errno == EACCES) + // fatal: permission denied + if (errno == EACCES) fprintf(stderr, "spmenu: no access to create directory: %s\n", dir); - if(mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) + // mkdir() failure + if (mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) fprintf(stderr, "spmenu: failed to create directory: %s\n", dir); } @@ -181,21 +188,22 @@ loadimage(const char *file, int *width, int *height) void scaleimage(int *width, int *height) { - int nwidth, nheight; + int new_width, new_height; float aspect = 1.0f; + // depending on what size, we determine aspect ratio if (imagewidth > *width) aspect = (float)(*width)/imagewidth; else aspect = (float)imagewidth/(*width); - nwidth = *width * aspect; - nheight = *height * aspect; + new_width = *width * aspect; + new_height = *height * aspect; - if(nwidth == *width && nheight == *height) + if (new_width == *width && new_height == *height) return; - image = imlib_create_cropped_scaled_image(0,0,*width,*height,nwidth,nheight); + image = imlib_create_cropped_scaled_image(0,0,*width,*height,new_width,new_height); imlib_free_image(); @@ -204,8 +212,8 @@ scaleimage(int *width, int *height) imlib_context_set_image(image); - *width = nwidth; - *height = nheight; + *width = new_width; + *height = new_height; return; } @@ -343,6 +351,7 @@ resizetoimageheight(int imageheight) struct item *item; unsigned int i = 1; + // walk through all matches for (item = matches; item && item != sel; item = item->right) ++i; diff --git a/libs/stream.c b/libs/stream.c index 446c4f7..7783f87 100644 --- a/libs/stream.c +++ b/libs/stream.c @@ -91,13 +91,13 @@ readstdin(void) // spmenu:about if (!strncmp("about", items[i].ex, strlen("about"))) { int i = system("printf \"spmenu $([ -f '/usr/share/spmenu/version' ] && cat /usr/share/spmenu/version || printf unknown)\\nBased on dmenu 5.2 from https://tools.suckless.org/dmenu\\nCompiled $([ -f '/usr/share/spmenu/compile-date' ] && cat /usr/share/spmenu/compile-date || printf Unknown)\\nCFLAGS: $([ -f '/usr/share/spmenu/cflags' ] && cat /usr/share/spmenu/cflags || printf unknown)\\nCC: $([ -f '/usr/share/spmenu/cc' ] && cat /usr/share/spmenu/cc || printf unknown)\\nDistro: $([ -f '/usr/share/spmenu/pkg_arch' ] && echo Arch || echo Installed manually)\\n\" | spmenu --columns 1 --lines 10 --hide-cursor --no-allow-typing --hide-mode --hide-match-count --hide-prompt --hide-powerline --hide-input --no-indent --no-color-items > /dev/null"); - if (i||!i) exit(0); + if (i||!i) exit(i); } // spmenu:test if (!strncmp("test", items[i].ex, strlen("test"))) { int i = system("command -v spmenu_test > /dev/null && spmenu_test"); - if (i||!i) exit(0); + if (i||!i) exit(i); } } } diff --git a/libs/xrdb.c b/libs/xrdb.c index 405dd29..c790603 100644 --- a/libs/xrdb.c +++ b/libs/xrdb.c @@ -13,19 +13,18 @@ resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) snprintf(fullname, sizeof(fullname), "%s.%s", "spmenu", name); fullname[sizeof(fullname) - 1] = '\0'; XrmGetResource(db, fullname, "*", &type, &ret); - if (!(ret.addr == NULL || strncmp("String", type, 64))) - { - switch (rtype) { - case STRING: - strcpy(sdst, ret.addr); - break; - case INTEGER: - *idst = strtoul(ret.addr, NULL, 10); - break; - case FLOAT: - *fdst = strtof(ret.addr, NULL); - break; - } + if (!(ret.addr == NULL || strncmp("String", type, 64))) { + switch (rtype) { // type + case STRING: + strcpy(sdst, ret.addr); + break; + case INTEGER: + *idst = strtoul(ret.addr, NULL, 10); + break; + case FLOAT: + *fdst = strtof(ret.addr, NULL); + break; + } } } diff --git a/spmenu.c b/spmenu.c index 68a1c8b..9ba493a 100644 --- a/spmenu.c +++ b/spmenu.c @@ -99,6 +99,7 @@ #include "libs/key.h" #include "libs/mouse.h" #include "libs/sort.h" +#include "libs/history.h" // misc #include "libs/key_struct.c" @@ -182,11 +183,6 @@ static Drw *drw; static Clr *scheme[SchemeLast]; static Clr textclrs[256]; -// history -static char *histfile; -static char **history; -static size_t histsz, histpos; - // declare functions static void calcoffsets(void); static void recalculatenumbers(void); @@ -235,6 +231,7 @@ static char *(*fstrstr)(const char *, const char *) = cistrstr; #include "libs/client.c" #include "libs/match.h" #include "libs/match.c" +#include "libs/history.c" #include "libs/arg.c" #include "libs/stream.c" @@ -258,11 +255,16 @@ recalculatenumbers(void) struct item *item; if (matchend) { numer++; + + // walk through items that match and add to numer for (item = matchend; item && item->left; item = item->left) numer++; } + + // walk through all items, matching or not and add to denom for (item = items; item && item->text; item++) denom++; + snprintf(numbers, NUMBERSBUFSIZE, "%d/%d", numer, denom); } @@ -273,7 +275,7 @@ calcoffsets(void) if (lines > 0) n = lines * columns * bh; - else { + else { // no lines, therefore the size of items must be decreased to fit the menu elements int numberWidth = 0; int modeWidth = 0; int larrowWidth = 0; @@ -287,10 +289,12 @@ calcoffsets(void) n = mw - (promptw + inputw + larrowWidth + rarrowWidth + modeWidth + numberWidth); } - // calculate which items will begin the next page and previous page + // calculate which items will begin the next page for (i = 0, next = curr; next; next = next->right) if ((i += (lines > 0) ? bh : MIN(TEXTWM(next->text), n)) > n) break; + + // calculate which items will begin the previous page for (i = 0, prev = curr; prev && prev->left; prev = prev->left) if ((i += (lines > 0) ? bh : MIN(TEXTWM(prev->left->text), n)) > n) break; @@ -300,8 +304,10 @@ int max_textw(void) { int len = 0; + for (struct item *item = items; item && item->text; item++) len = MAX(TEXTW(item->text), len); + return len; } @@ -311,17 +317,20 @@ cleanup(void) size_t i; #if USEIMAGE - cleanupimage(); + cleanupimage(); // function frees images #endif - XUngrabKey(dpy, AnyKey, AnyModifier, root); + XUngrabKey(dpy, AnyKey, AnyModifier, root); // ungrab keys + // free color scheme for (i = 0; i < SchemeLast; i++) free(scheme[i]); + // free high priority items for (i = 0; i < hplength; ++i) free(hpitems[i]); + // free drawing and close the display drw_free(drw); XSync(dpy, False); XCloseDisplay(dpy); @@ -337,11 +346,12 @@ cistrstr(const char *h, const char *n) for (; *h; ++h) { for (i = 0; n[i] && tolower((unsigned char)n[i]) == - tolower((unsigned char)h[i]); ++i) - ; + tolower((unsigned char)h[i]); ++i); + if (n[i] == '\0') return (char *)h; } + return NULL; } @@ -356,20 +366,23 @@ grabfocus(void) XGetInputFocus(dpy, &focuswin, &revertwin); if (focuswin == win) return; + + // if it's a client, we can't just steal all the input for ourselves if (managed) { - XTextProperty prop; - char *windowtitle = prompt != NULL ? prompt : "spmenu"; - Xutf8TextListToTextProperty(dpy, &windowtitle, 1, XUTF8StringStyle, &prop); - XSetWMName(dpy, win, &prop); - XSetTextProperty(dpy, win, &prop, XInternAtom(dpy, "_NET_WM_NAME", False)); - XFree(prop.value); - } else { - XSetInputFocus(dpy, win, RevertToParent, CurrentTime); - } + XTextProperty prop; + char *windowtitle = prompt != NULL ? prompt : "spmenu"; + Xutf8TextListToTextProperty(dpy, &windowtitle, 1, XUTF8StringStyle, &prop); + XSetWMName(dpy, win, &prop); + XSetTextProperty(dpy, win, &prop, XInternAtom(dpy, "_NET_WM_NAME", False)); + XFree(prop.value); + } else { // spmenu is not managed, and is very greedy + XSetInputFocus(dpy, win, RevertToParent, CurrentTime); + } nanosleep(&ts, NULL); } - die("cannot grab focus"); + + die("spmenu: cannot grab focus"); // not possible to grab focus, abort immediately } void @@ -377,10 +390,15 @@ insert(const char *str, ssize_t n) { if (strlen(text) + n > sizeof text - 1) return; + // move existing text out of the way, insert new text, and update cursor memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); + + // update cursor if (n > 0) memcpy(&text[cursor], str, n); + + // add to cursor position and continue matching cursor += n; match(); } @@ -392,95 +410,8 @@ nextrune(int inc) // return location of next utf8 rune in the given direction (+1 or -1) for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc) - ; - return n; -} - -void -loadhistory(void) -{ - FILE *fp = NULL; - static size_t cap = 0; - size_t llen; - char *line; - - if (!histfile) { - return; - } - - fp = fopen(histfile, "r"); - if (!fp) { - return; - } - - for (;;) { - line = NULL; - llen = 0; - if (-1 == getline(&line, &llen, fp)) { - if (ferror(fp)) { - die("failed to read history"); - } - free(line); - break; - } - - if (cap == histsz) { - cap += 64 * sizeof(char*); - history = realloc(history, cap); - if (!history) { - die("failed to realloc memory"); - } - } - strtok(line, "\n"); - history[histsz] = line; - histsz++; - } - histpos = histsz; - - if (fclose(fp)) { - die("failed to close file %s", histfile); - } -} - -void -navigatehistfile(int dir) -{ - static char def[BUFSIZ]; - char *p = NULL; - size_t len = 0; - - if (!history || histpos + 1 == 0) - return; - - if (histsz == histpos) { - strncpy(def, text, sizeof(def)); - } - - switch (dir) { - case 1: - if (histpos < histsz - 1) { - p = history[++histpos]; - } else if (histpos == histsz - 1) { - p = def; - histpos++; - } - break; - case -1: - if (histpos > 0) { - p = history[--histpos]; - } - break; - } - - if (p == NULL) { - return; - } - - len = MIN(strlen(p), BUFSIZ - 1); - strcpy(text, p); - text[len] = '\0'; - cursor = len; - match(); + ; + return n; } void @@ -495,9 +426,11 @@ pastesel(void) if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False, utf8, &da, &di, &dl, &dl, (unsigned char **)&p) == Success && p) { - insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); + insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); // insert selection XFree(p); } + + // draw the menu drawmenu(); } @@ -509,7 +442,7 @@ xinitvisual() int nitems; int i; - // properties + // visual properties XVisualInfo tpl = { .screen = screen, .depth = 32, @@ -520,6 +453,8 @@ xinitvisual() infos = XGetVisualInfo(dpy, masks, &tpl, &nitems); visual = NULL; + + // create colormap for(i = 0; i < nitems; i ++) { fmt = XRenderFindVisualFormat(dpy, infos[i].visual); if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { @@ -542,7 +477,7 @@ xinitvisual() } void -setup(void) +setupdisplay(void) { int x, y, i; #if USEXINERAMA @@ -563,7 +498,7 @@ setup(void) init_appearance(); // init colorschemes by reading arrays - // properties + // set properties indicating what spmenu handles clip = XInternAtom(dpy, "CLIPBOARD", False); utf8 = XInternAtom(dpy, "UTF8_STRING", False); types = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); @@ -581,6 +516,7 @@ setup(void) mh = (lines + 1) * bh; // lines + 1 * bh is the menu height + // set prompt width based on prompt size promptw = (prompt && *prompt) ? pango_prompt ? TEXTWM(prompt) : TEXTW(prompt) - lrpad / 4 : 0; // prompt width @@ -628,11 +564,11 @@ setup(void) break; // calculate x/y position - if (menuposition == 2) { + if (menuposition == 2) { // centered mw = MIN(MAX(max_textw() + promptw, minwidth), info[i].width); x = info[i].x_org + ((info[i].width - mw) / 2); y = info[i].y_org + ((info[i].height - mh) / 2); - } else { + } else { // top or bottom x = info[i].x_org + dmx; y = info[i].y_org + (menuposition ? 0 : info[i].height - mh - dmy); mw = (dmw>0 ? dmw : info[i].width); @@ -643,14 +579,14 @@ setup(void) #endif { if (!XGetWindowAttributes(dpy, parentwin, &wa)) - die("could not get embedding window attributes: 0x%lx", - parentwin); + die("spmenu: could not get embedding window attributes: 0x%lx", + parentwin); // die because unable to get attributes for the parent window - if (menuposition == 2) { + if (menuposition == 2) { // centered mw = MIN(MAX(max_textw() + promptw, minwidth), wa.width); x = (wa.width - mw) / 2; y = (wa.height - mh) / 2; - } else { + } else { // top or bottom x = 0; y = 0; mw = wa.width; @@ -660,9 +596,9 @@ setup(void) // might be faster in some instances, most of the time unnecessary if (!accuratewidth) inputw = MIN(inputw, mw/3); - match(); + match(); // match entries - // create menu window + // create menu window and set properties for it create_window(x + sp, y + vp - (menuposition == 2 ? 0 : borderwidth * 2), mw - 2 * sp - borderwidth * 2, mh); set_window(); set_prop(); @@ -679,6 +615,8 @@ setup(void) XNClientWindow, win, XNFocusWindow, win, NULL); XMapRaised(dpy, win); + + // embed spmenu inside parent window if (embed) { XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { @@ -699,12 +637,13 @@ main(int argc, char *argv[]) { XWindowAttributes wa; - readargs(argc, argv); + readargs(argc, argv); // start by reading arguments #if USEIMAGE longestedge = MAX(imagewidth, imageheight); #endif + // set default mode, must be done before the event loop or keybindings will not work if (mode) { curMode = 1; allowkeys = 1; @@ -718,36 +657,40 @@ main(int argc, char *argv[]) } if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) - fputs("warning: no locale support\n", stderr); + fputs("warning: no locale support\n", stderr); // invalid locale, so notify the user about it - if (!(dpy = XOpenDisplay(NULL))) - die("spmenu: cannot open display"); + if (!(dpy = XOpenDisplay(NULL))) + die("spmenu: cannot open display"); // failed to open display + // set screen and root window screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); + // parent window is the root window (ie. window manager) because we're not embedding if (!embed || !(parentwin = strtol(embed, NULL, 0))) parentwin = root; if (!XGetWindowAttributes(dpy, parentwin, &wa)) die("spmenu: could not get embedding window attributes: 0x%lx", parentwin); - xinitvisual(); - drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap); + xinitvisual(); // init visual and create drawable after + drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap); // wrapper function creating a drawable // load fonts if (!drw_font_create(drw, fonts, LENGTH(fonts))) die("no fonts could be loaded."); + // resize window lrpad = drw->font->h + textpadding; - prepare_window_size(); + prepare_window_size(); // this function sets padding size + // openbsd specifics, i use gnu/linux so i have no idea why this is here #ifdef __OpenBSD__ if (pledge("stdio rpath", NULL) == -1) die("pledge"); #endif - loadhistory(); + loadhistory(); // read history entries // fast (-f) means we grab keyboard before reading standard input if (fast && !isatty(0)) { @@ -767,8 +710,8 @@ main(int argc, char *argv[]) } #endif - setup(); - eventloop(); + setupdisplay(); // set up display and create window + eventloop(); // function is a loop which checks X11 events and calls other functions accordingly - return 1; + return 1; // should be unreachable }