Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardgv/5651456 to your computer and use it in GitHub Desktop.
Save richardgv/5651456 to your computer and use it in GitHub Desktop.
richardgv/skippy-xd #7: Quick and dirty implementation of customizable tooltip positioning
diff --git a/skippy-xd.rc-default b/skippy-xd.rc-default
index adcba44..3836848 100644
--- a/skippy-xd.rc-default
+++ b/skippy-xd.rc-default
@@ -54,6 +54,10 @@ opacity = 255
[tooltip]
show = true
+followsMouse = true
+offsetX = 20
+offsetY = 20
+align = left
border = #ffffff
background = #404040
opacity = 128
diff --git a/src/clientwin.c b/src/clientwin.c
index 7fc3038..8172da9 100644
--- a/src/clientwin.c
+++ b/src/clientwin.c
@@ -389,11 +389,10 @@ clientwin_handle(ClientWin *cw, XEvent *ev)
{
int win_title_len = 0;
FcChar8 *win_title = wm_get_window_title(cw->mainwin->ps, cw->client.window, &win_title_len);
- if(win_title)
- {
+ if (win_title) {
tooltip_map(cw->mainwin->tooltip,
- ev->xcrossing.x_root + 20, ev->xcrossing.y_root + 20,
- win_title, win_title_len);
+ ev->xcrossing.x_root, ev->xcrossing.y_root,
+ win_title, win_title_len);
free(win_title);
}
}
diff --git a/src/skippy.c b/src/skippy.c
index c077e70..e6e2b3c 100644
--- a/src/skippy.c
+++ b/src/skippy.c
@@ -54,6 +54,26 @@ parse_cliop(session_t *ps, const char *str, enum cliop *dest) {
return false;
}
+/**
+ * @brief Parse a string representation of enum align.
+ */
+static bool
+parse_align(session_t *ps, const char *str, enum align *dest) {
+ static const char * const STRS_ALIGN[] = {
+ [ ALIGN_LEFT ] = "left",
+ [ ALIGN_MID ] = "mid",
+ [ ALIGN_RIGHT ] = "right",
+ };
+ for (int i = 0; i < sizeof(STRS_ALIGN) / sizeof(STRS_ALIGN[0]); ++i)
+ if (!strcmp(STRS_ALIGN[i], str)) {
+ *dest = i;
+ return true;
+ }
+
+ printfef("(\"%s\"): Unrecognized operation.", str);
+ return false;
+}
+
static dlist *
update_clients(MainWin *mw, dlist *clients, Bool *touched)
{
@@ -296,7 +316,6 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
last_rendered = time_in_millis();
while(! die) {
int i, j, now, timeout;
- int move_x = -1, move_y = -1;
struct pollfd r_fd;
XFlush(ps->dpy);
@@ -325,10 +344,10 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
#endif
const Window wid = ev_window(ps, &ev);
- if (ev.type == MotionNotify)
- {
- move_x = ev.xmotion.x_root;
- move_y = ev.xmotion.y_root;
+ if (MotionNotify == ev.type) {
+ if (mw->tooltip && ps->o.tooltip_followsMouse)
+ tooltip_move(mw->tooltip,
+ ev.xmotion.x_root, ev.xmotion.y_root);
}
else if (ev.type == DestroyNotify || ev.type == UnmapNotify) {
dlist *iter = (wid ? dlist_find(clients, clientwin_cmp_func, (void *) wid): NULL);
@@ -400,9 +419,6 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
break;
}
}
-
- if(mw->tooltip && move_x != -1)
- tooltip_move(mw->tooltip, move_x + 20, move_y + 20);
}
/* Unmap the main window and clean up */
@@ -770,6 +786,11 @@ int main(int argc, char *argv[]) {
config_get_int_wrap(config, "highlight", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256);
config_get_int_wrap(config, "highlight", "opacity", &ps->o.highlight_opacity, 0, 256);
config_get_bool_wrap(config, "tooltip", "show", &ps->o.tooltip_show);
+ config_get_bool_wrap(config, "tooltip", "followsMouse", &ps->o.tooltip_followsMouse);
+ config_get_int_wrap(config, "tooltip", "offsetX", &ps->o.tooltip_offsetX, INT_MIN, INT_MAX);
+ config_get_int_wrap(config, "tooltip", "offsetY", &ps->o.tooltip_offsetY, INT_MIN, INT_MAX);
+ if (!parse_align(ps, config_get(config, "tooltip", "align", "left"), &ps->o.tooltip_align))
+ return RET_BADARG;
config_get_int_wrap(config, "tooltip", "tintOpacity", &ps->o.highlight_tintOpacity, 0, 256);
config_get_int_wrap(config, "tooltip", "opacity", &ps->o.tooltip_opacity, 0, 256);
diff --git a/src/skippy.h b/src/skippy.h
index 94982c5..1dc00cd 100644
--- a/src/skippy.h
+++ b/src/skippy.h
@@ -43,6 +43,7 @@
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/shape.h>
#ifdef CFG_XINERAMA
# include <X11/extensions/Xinerama.h>
@@ -88,6 +89,12 @@ enum cliop {
CLIENTOP_DESTROY,
};
+enum align {
+ ALIGN_LEFT,
+ ALIGN_MID,
+ ALIGN_RIGHT,
+};
+
/// @brief Option structure.
typedef struct {
char *config_path;
@@ -115,6 +122,10 @@ typedef struct {
int highlight_opacity;
bool tooltip_show;
+ bool tooltip_followsMouse;
+ int tooltip_offsetX;
+ int tooltip_offsetY;
+ enum align tooltip_align;
char *tooltip_border;
char *tooltip_background;
int tooltip_opacity;
@@ -147,6 +158,10 @@ typedef struct {
.highlight_tintOpacity = 64, \
.highlight_opacity = 255, \
.tooltip_show = true, \
+ .tooltip_followsMouse = true, \
+ .tooltip_offsetX = 20, \
+ .tooltip_offsetY = 20, \
+ .tooltip_align = ALIGN_LEFT, \
.tooltip_border = NULL, \
.tooltip_background = NULL, \
.tooltip_opacity = 128, \
diff --git a/src/tooltip.c b/src/tooltip.c
index 8f0cbb8..b4490d2 100644
--- a/src/tooltip.c
+++ b/src/tooltip.c
@@ -151,12 +151,20 @@ tooltip_create(MainWin *mw) {
tt->font_height = tt->font->ascent + tt->font->descent;
+ // Set tooltip window input region to empty to prevent disgusting
+ // racing situations
+ {
+ XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0);
+ XFixesSetWindowShapeRegion(ps->dpy, tt->window, ShapeInput, 0, 0, region);
+ XFixesDestroyRegion(ps->dpy, region);
+ }
+
return tt;
}
void
-tooltip_map(Tooltip *tt, int x, int y, const FcChar8 *text, int len)
-{
+tooltip_map(Tooltip *tt, int mouse_x, int mouse_y,
+ const FcChar8 *text, int len) {
session_t * const ps = tt->mainwin->ps;
XUnmapWindow(ps->dpy, tt->window);
@@ -166,7 +174,7 @@ tooltip_map(Tooltip *tt, int x, int y, const FcChar8 *text, int len)
tt->width = tt->extents.width + 8;
tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0);
XResizeWindow(ps->dpy, tt->window, tt->width, tt->height);
- tooltip_move(tt, x, y);
+ tooltip_move(tt, mouse_x, mouse_y);
if(tt->text)
free(tt->text);
@@ -181,15 +189,24 @@ tooltip_map(Tooltip *tt, int x, int y, const FcChar8 *text, int len)
}
void
-tooltip_move(Tooltip *tt, int x, int y)
-{
- if(x + tt->extents.width + 9 > tt->mainwin->x + tt->mainwin->width)
- x = tt->mainwin->x + tt->mainwin->width - tt->extents.width - 9;
- x = MAX(0, x);
-
- if(y + tt->extents.height + 8 > tt->mainwin->y + tt->mainwin->height)
- y = tt->mainwin->height + tt->mainwin->y - tt->extents.height - 8;
- y = MAX(0, y);
+tooltip_move(Tooltip *tt, int mouse_x, int mouse_y) {
+ session_t *ps = tt->mainwin->ps;
+ int x = ps->o.tooltip_offsetX, y = ps->o.tooltip_offsetY;
+ if (ps->o.tooltip_followsMouse) {
+ x += mouse_x;
+ y += mouse_y;
+ }
+ switch (ps->o.tooltip_align) {
+ case ALIGN_LEFT: break;
+ case ALIGN_MID:
+ x -= tt->width / 2;
+ break;
+ case ALIGN_RIGHT:
+ x -= tt->width;
+ break;
+ }
+ x = MIN(MAX(0, x), tt->mainwin->x + tt->mainwin->width - tt->width);
+ y = MIN(MAX(0, y), tt->mainwin->y + tt->mainwin->height - tt->height);
XMoveWindow(tt->mainwin->ps->dpy, tt->window, x, y);
}
@@ -207,11 +224,10 @@ tooltip_unmap(Tooltip *tt)
void
tooltip_handle(Tooltip *tt, XEvent *ev)
{
- if(! tt->text)
+ if (!tt->text)
return;
- if(ev->type == Expose && ev->xexpose.count == 0)
- {
+ if (ev->type == Expose && ev->xexpose.count == 0) {
XftDrawRect(tt->draw, &tt->border, 0, 0, tt->width, 1);
XftDrawRect(tt->draw, &tt->border, 0, 1, 1, tt->height - 2);
XftDrawRect(tt->draw, &tt->border, 0, tt->height - 1, tt->width, 1);
diff --git a/src/tooltip.h b/src/tooltip.h
index b2bd045..2d1e5e1 100644
--- a/src/tooltip.h
+++ b/src/tooltip.h
@@ -39,9 +39,10 @@ typedef struct _Tooltip Tooltip;
Tooltip *tooltip_create(MainWin *mw);
void tooltip_destroy(Tooltip *);
-void tooltip_map(Tooltip *, int, int, const FcChar8 *, int);
+void tooltip_map(Tooltip *tt, int mouse_x, int mouse_y,
+ const FcChar8 *text, int len);
void tooltip_unmap(Tooltip *);
void tooltip_handle(Tooltip *, XEvent *);
-void tooltip_move(Tooltip *, int, int);
+void tooltip_move(Tooltip *tt, int mouse_x, int mouse_y);
#endif /* SKIPPY_TOOLTIP_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment