diff --git a/README.html b/README.html index bb2debf..27b4abb 100644 --- a/README.html +++ b/README.html @@ -314,8 +314,6 @@ it’s not like you will be unable to use spmenu in its current state. -

Bugs

-

None discovered yet! :)

Scripts

There’s a page dedicated to user scripts over on the diff --git a/README.md b/README.md index 6acbc89..b09b8ff 100644 --- a/README.md +++ b/README.md @@ -138,10 +138,6 @@ code which as of now seems unlikely, or if someone makes a patch. - You can just use XWayland anyway if you happen to use Wayland, so it's not like you will be unable to use spmenu in its current state. -### Bugs - -None discovered yet! :) - ## Scripts There's a page dedicated to user scripts diff --git a/libs/client.c b/libs/x11/client.c similarity index 100% rename from libs/client.c rename to libs/x11/client.c diff --git a/libs/client.h b/libs/x11/client.h similarity index 100% rename from libs/client.h rename to libs/x11/client.h diff --git a/libs/x11/init.c b/libs/x11/init.c new file mode 100644 index 0000000..8771b71 --- /dev/null +++ b/libs/x11/init.c @@ -0,0 +1,164 @@ +void setupdisplay(void) { + int x, y, i; +#if USEXINERAMA + int j, di; +#endif + unsigned int du; + unsigned int tmp, minstrlen = 0, curstrlen = 0; + int numwidthchecks = 100; + struct item *item; + XIM xim; + Window w, dw, *dws; + XWindowAttributes wa; +#if USEXINERAMA + XineramaScreenInfo *info; + Window pw; + int a, n, area = 0; +#endif + + // 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); + dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + + // resize client + bh = MAX(drw->font->h, drw->font->h + 2 + lineheight); + lines = MAX(lines, 0); + reallines = lines; + + // resize client to image height if deemed necessary +#if USEIMAGE + if (image) resizetoimageheight(imageheight); +#endif + + mh = (lines + 1) * bh + 2 * menumarginv; // 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 + + // get accurate width + if (accuratewidth) { + for (item = items; !lines && item && item->text; ++item) { + curstrlen = strlen(item->text); + if (numwidthchecks || minstrlen < curstrlen) { + numwidthchecks = MAX(numwidthchecks - 1, 0); + minstrlen = MAX(minstrlen, curstrlen); + if ((tmp = MIN(TEXTW(item->text), mw/3) > inputw)) { + inputw = tmp; + if (tmp == mw/3) + break; + } + } + } + } + + // init xinerama screens +#if USEXINERAMA + i = 0; + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { + XGetInputFocus(dpy, &w, &di); + if (mon >= 0 && mon < n) + i = mon; + else if (w != root && w != PointerRoot && w != None) { + // find top-level window containing current input focus + do { + if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) + XFree(dws); + } while (w != root && w != pw); + // find xinerama screen with which the window intersects most + if (XGetWindowAttributes(dpy, pw, &wa)) + for (j = 0; j < n; j++) + if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { + area = a; + i = j; + } + } + // no focused window is on screen, so use pointer location instead + if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + for (i = 0; i < n; i++) + if (INTERSECT(x, y, 1, 1, info[i])) + break; + + // calculate x/y position + 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 { // top or bottom + x = info[i].x_org + xpos; + y = info[i].y_org + (menuposition ? 0 : info[i].height - mh - ypos); + mw = (menuwidth>0 ? menuwidth : info[i].width); + } + + XFree(info); + } else +#endif + { + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("spmenu: could not get embedding window attributes: 0x%lx", + parentwin); // die because unable to get attributes for the parent window + + if (menuposition == 2) { // centered + mw = MIN(MAX(max_textw() + promptw, minwidth), wa.width); + x = (wa.width - mw) / 2; + y = (wa.height - mh) / 2; + } else { // top or bottom + x = 0; + y = menuposition ? 0 : wa.width - mh - ypos; + mw = wa.width; + } + } + + // might be faster in some instances, most of the time unnecessary + if (!accuratewidth) inputw = MIN(inputw, mw/3); + + match(); // match entries + + // create menu window and set properties for it + create_window(x + sp, y + vp - (menuposition == 1 ? 0 : menuposition == 2 ? borderwidth : borderwidth * 2), mw - 2 * sp - borderwidth * 2, mh); + set_window(); + set_prop(); + +#if USEIMAGE + setimageopts(); +#endif + + // input methods + if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im=local"); + if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im="); + if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) + die("XOpenIM failed: could not open input device"); + } + } + + xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, win, XNFocusWindow, win, NULL); + + XMapRaised(dpy, win); + + XSync(dpy, False); + XGetWindowAttributes(dpy, win, &wa); + + if (wa.map_state == IsViewable) // must be viewable, otherwise we get a BadMatch error + XSetInputFocus(dpy, win, RevertToParent, CurrentTime); + + // embed spmenu inside parent window + if (embed) { + XReparentWindow(dpy, win, parentwin, x, y); + XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); + if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { + for (i = 0; i < du && dws[i] != win; ++i) + XSelectInput(dpy, dws[i], FocusChangeMask); + XFree(dws); + } + grabfocus(); + } + + // resize and draw + drw_resize(drw, mw - 2 * sp - borderwidth * 2, mh); + drawmenu(); +} diff --git a/libs/x11/init.h b/libs/x11/init.h new file mode 100644 index 0000000..b9f2d77 --- /dev/null +++ b/libs/x11/init.h @@ -0,0 +1 @@ +static void setupdisplay(void); diff --git a/libs/key.c b/libs/x11/key.c similarity index 100% rename from libs/key.c rename to libs/x11/key.c diff --git a/libs/key.h b/libs/x11/key.h similarity index 100% rename from libs/key.h rename to libs/x11/key.h diff --git a/libs/mouse.c b/libs/x11/mouse.c similarity index 100% rename from libs/mouse.c rename to libs/x11/mouse.c diff --git a/libs/mouse.h b/libs/x11/mouse.h similarity index 100% rename from libs/mouse.h rename to libs/x11/mouse.h diff --git a/libs/xrdb.c b/libs/x11/xrdb.c similarity index 100% rename from libs/xrdb.c rename to libs/x11/xrdb.c diff --git a/libs/xrdb.h b/libs/x11/xrdb.h similarity index 100% rename from libs/xrdb.h rename to libs/x11/xrdb.h diff --git a/libs/xresources.h b/libs/x11/xresources.h similarity index 100% rename from libs/xresources.h rename to libs/x11/xresources.h diff --git a/spmenu.c b/spmenu.c index d71f49a..09b242a 100644 --- a/spmenu.c +++ b/spmenu.c @@ -1,9 +1,9 @@ /* spmenu - fancy dynamic menu * * If you're looking for functions used to draw text, see 'libs/draw.c' - * If you're looking for wrapper functions used inside the draw functions, see 'libs/sl/draw.c' + * If you're looking for wrapper functions used inside the draw functions, see 'libs/libdrw/drw.c' * If you're looking for functions used to draw images, see 'libs/img.c' - * If you're looking for the .Xresources array, see 'libs/xresources.h' + * If you're looking for the .Xresources array, see 'libs/x11/xresources.h' * * You don't need to edit spmenu.c if you aren't making big changes to the software. * @@ -118,13 +118,14 @@ static int allowkeys = 1; // whether or not to interpret a keypress as an insert // various headers #include "libs/libdrw/drw.h" #include "libs/sl/main.h" +#include "libs/x11/init.h" #include "libs/draw.h" #include "libs/stream.h" #include "libs/schemes.h" #include "libs/arg.h" -#include "libs/xrdb.h" -#include "libs/key.h" -#include "libs/mouse.h" +#include "libs/x11/xrdb.h" +#include "libs/x11/key.h" +#include "libs/x11/mouse.h" #include "libs/sort.h" #include "libs/history.h" @@ -237,7 +238,6 @@ static void grabfocus(void); static void pastesel(void); static void appenditem(struct item *item, struct item **list, struct item **last); static void xinitvisual(void); -static void setupdisplay(void); static int max_textw(void); static size_t nextrune(int inc); @@ -252,7 +252,7 @@ static int listchanged = 0; #include "mouse.h" // xresources/color arrays -#include "libs/xresources.h" +#include "libs/x11/xresources.h" #include "libs/colors.h" static char *fonts[] = { font }; @@ -273,16 +273,16 @@ static char *(*fstrstr)(const char *, const char *) = cistrstr; #include "libs/img.c" #include "libs/rtl.h" #include "libs/rtl.c" -#include "libs/key.c" -#include "libs/mouse.c" +#include "libs/x11/key.c" +#include "libs/x11/mouse.c" #include "libs/sort.c" #include "libs/draw.c" #include "libs/schemes.c" #include "libs/argv.h" #include "libs/argv.c" -#include "libs/xrdb.c" -#include "libs/client.h" -#include "libs/client.c" +#include "libs/x11/xrdb.c" +#include "libs/x11/client.h" +#include "libs/x11/client.c" #include "libs/match.h" #include "libs/match.c" #include "libs/history.c" @@ -290,6 +290,7 @@ static char *(*fstrstr)(const char *, const char *) = cistrstr; #include "libs/stream.c" #include "libs/event.h" #include "libs/event.c" +#include "libs/x11/init.c" int is_selected(size_t index) { for (int i = 0; i < sel_size; i++) { @@ -554,173 +555,6 @@ void xinitvisual(void) { } } -void setupdisplay(void) { - int x, y, i; -#if USEXINERAMA - int j, di; -#endif - unsigned int du; - unsigned int tmp, minstrlen = 0, curstrlen = 0; - int numwidthchecks = 100; - struct item *item; - XIM xim; - Window w, dw, *dws; - XWindowAttributes wa; -#if USEXINERAMA - XineramaScreenInfo *info; - Window pw; - int a, n, area = 0; -#endif - - init_appearance(); // init colorschemes by reading arrays - - // 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); - dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); - - // resize client - bh = MAX(drw->font->h, drw->font->h + 2 + lineheight); - lines = MAX(lines, 0); - reallines = lines; - - // resize client to image height if deemed necessary -#if USEIMAGE - if (image) resizetoimageheight(imageheight); -#endif - - mh = (lines + 1) * bh + 2 * menumarginv; // 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 - - // get accurate width - if (accuratewidth) { - for (item = items; !lines && item && item->text; ++item) { - curstrlen = strlen(item->text); - if (numwidthchecks || minstrlen < curstrlen) { - numwidthchecks = MAX(numwidthchecks - 1, 0); - minstrlen = MAX(minstrlen, curstrlen); - if ((tmp = MIN(TEXTW(item->text), mw/3) > inputw)) { - inputw = tmp; - if (tmp == mw/3) - break; - } - } - } - } - - // init xinerama screens -#if USEXINERAMA - i = 0; - if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { - XGetInputFocus(dpy, &w, &di); - if (mon >= 0 && mon < n) - i = mon; - else if (w != root && w != PointerRoot && w != None) { - // find top-level window containing current input focus - do { - if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) - XFree(dws); - } while (w != root && w != pw); - // find xinerama screen with which the window intersects most - if (XGetWindowAttributes(dpy, pw, &wa)) - for (j = 0; j < n; j++) - if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { - area = a; - i = j; - } - } - // no focused window is on screen, so use pointer location instead - if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) - for (i = 0; i < n; i++) - if (INTERSECT(x, y, 1, 1, info[i])) - break; - - // calculate x/y position - 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 { // top or bottom - x = info[i].x_org + xpos; - y = info[i].y_org + (menuposition ? 0 : info[i].height - mh - ypos); - mw = (menuwidth>0 ? menuwidth : info[i].width); - } - - XFree(info); - } else -#endif - { - if (!XGetWindowAttributes(dpy, parentwin, &wa)) - die("spmenu: could not get embedding window attributes: 0x%lx", - parentwin); // die because unable to get attributes for the parent window - - if (menuposition == 2) { // centered - mw = MIN(MAX(max_textw() + promptw, minwidth), wa.width); - x = (wa.width - mw) / 2; - y = (wa.height - mh) / 2; - } else { // top or bottom - x = 0; - y = menuposition ? 0 : wa.width - mh - ypos; - mw = wa.width; - } - } - - // might be faster in some instances, most of the time unnecessary - if (!accuratewidth) inputw = MIN(inputw, mw/3); - - match(); // match entries - - // create menu window and set properties for it - create_window(x + sp, y + vp - (menuposition == 1 ? 0 : menuposition == 2 ? borderwidth : borderwidth * 2), mw - 2 * sp - borderwidth * 2, mh); - set_window(); - set_prop(); - -#if USEIMAGE - setimageopts(); -#endif - - // input methods - if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im=local"); - if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im="); - if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) - die("XOpenIM failed: could not open input device"); - } - } - - xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, win, XNFocusWindow, win, NULL); - - XMapRaised(dpy, win); - - XSync(dpy, False); - XGetWindowAttributes(dpy, win, &wa); - - if (wa.map_state == IsViewable) // must be viewable, otherwise we get a BadMatch error - XSetInputFocus(dpy, win, RevertToParent, CurrentTime); - - // embed spmenu inside parent window - if (embed) { - XReparentWindow(dpy, win, parentwin, x, y); - XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); - if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { - for (i = 0; i < du && dws[i] != win; ++i) - XSelectInput(dpy, dws[i], FocusChangeMask); - XFree(dws); - } - grabfocus(); - } - - // resize and draw - drw_resize(drw, mw - 2 * sp - borderwidth * 2, mh); - drawmenu(); -} - int main(int argc, char *argv[]) { XWindowAttributes wa; @@ -804,6 +638,7 @@ int main(int argc, char *argv[]) { } #endif + init_appearance(); // init colorschemes by reading arrays setupdisplay(); // set up display and create window eventloop(); // function is a loop which checks X11 events and calls other functions accordingly