Created
May 26, 2013 02:05
-
-
Save richardgv/5651456 to your computer and use it in GitHub Desktop.
richardgv/skippy-xd #7: Quick and dirty implementation of customizable tooltip positioning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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