libxosd-xft/src/libxosd-xft/xosd-xft.c

878 lines
25 KiB
C

/*
Copyright 2021 Dakshinamurthy Karra (dakshinamurthy.karra@jaliansystems.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "intern.h"
char *osd_default_font = "saucecodepro nerd font:size=64";
char *osd_error;
#ifdef DEBUG
int _xosd_debug_fn_level = 0;
DEBUG_LEVEL _xosd_debug_level = Dnone;
#endif
/* load_defaults -- set sensible defaults for settings {{{ */
void load_defaults(osd_settings *settings)
{
FUNCTION_START();
settings->geometry = "0x0+0+0*top/center";
settings->monitor = -1;
#ifdef HAVE_LIBXRANDR
settings->use_xrandr = 1;
#endif
#ifdef HAVE_LIBXINERAMA
settings->use_xinerama = 1;
#endif
settings->fontname = osd_default_font;
settings->text_color = "#0000ee";
settings->text_alpha = 100;
settings->bg_color = "black";
settings->bg_alpha = 100;
settings->shadow_color = "lightgrey";
settings->shadow_alpha = 0;
settings->shadow_offset_x = 3;
settings->shadow_offset_y = 3;
settings->padding = "0";
settings->text_align = "center";
settings->maxlines = 1;
settings->lines = calloc(1, sizeof(char*));
FUNCTION_END();
}
/* }}} */
/* osd_create -- Create a new xosd_xft structure {{{ */
xosd_xft *
osd_create()
{
FUNCTION_START();
struct xosd_xft *osd = calloc(1, sizeof(struct xosd_xft));
if (osd == NULL)
{
osd_error = "Could not allocate memory...";
FUNCTION_END();
return NULL;
}
load_defaults(&osd->settings);
FUNCTION_END();
return osd;
}
/* }}} */
/* stay_on_top -- Tell window manager to put window topmost. {{{ */
static void
stay_on_top(Display *dpy, Window win)
{
FUNCTION_START();
Atom gnome, net_wm, type;
int format;
unsigned long nitems, bytesafter;
unsigned char *args = NULL;
Window root = DefaultRootWindow(dpy);
/*
* build atoms
*/
gnome = XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", False);
net_wm = XInternAtom(dpy, "_NET_SUPPORTED", False);
/*
* gnome-compliant
* tested with icewm + WindowMaker
*/
if (Success == XGetWindowProperty(dpy, root, gnome, 0, (65536 / sizeof(long)), False,
AnyPropertyType, &type, &format, &nitems, &bytesafter, &args) &&
nitems > 0)
{
/*
* FIXME: check capabilities
*/
XClientMessageEvent xev;
Atom gnome_layer = XInternAtom(dpy, "_WIN_LAYER", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.window = win;
xev.message_type = gnome_layer;
xev.format = 32;
xev.data.l[0] = 6 /* WIN_LAYER_ONTOP */;
XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask,
(XEvent *)&xev);
XFree(args);
}
/*
* netwm compliant.
* tested with kde
*/
else if (Success == XGetWindowProperty(dpy, root, net_wm, 0, (65536 / sizeof(long)), False,
AnyPropertyType, &type, &format, &nitems, &bytesafter, &args) &&
nitems > 0)
{
XEvent e;
Atom net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
Atom net_wm_top = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False);
memset(&e, 0, sizeof(e));
e.xclient.type = ClientMessage;
e.xclient.message_type = net_wm_state;
e.xclient.display = dpy;
e.xclient.window = win;
e.xclient.format = 32;
e.xclient.data.l[0] = 1 /* _NET_WM_STATE_ADD */;
e.xclient.data.l[1] = net_wm_top;
e.xclient.data.l[2] = 0l;
e.xclient.data.l[3] = 0l;
e.xclient.data.l[4] = 0l;
XSendEvent(dpy, DefaultRootWindow(dpy), False,
SubstructureRedirectMask, &e);
XFree(args);
}
/* XMapRaised(dpy, win); */
FUNCTION_END();
}
/* }}} */
/* osd_parse_geometry -- Parse (user-given) geometry string and create osd_geometry{{{ */
osd_geometry *
osd_parse_geometry(const char *geometry, const char *text_align, osd_geometry *geo)
{
FUNCTION_START();
/* Defaults */
geo->width = 100;
geo->width_per = 1;
geo->width_chars = 0;
geo->height = 0;
geo->height_per = 0;
geo->height_lines = 0;
geo->xoffset = 0;
geo->xneg = 0;
geo->yoffset = 0;
geo->yneg = 0;
geo->valign = XOSD_XFT_valign_none;
geo->halign = XOSD_XFT_halign_none;
if (geometry == NULL) {
FUNCTION_END();
return geo;
}
if (parse_geometry(geometry, &geo->width, &geo->height,
&geo->width_per, &geo->height_per,
&geo->width_chars, &geo->height_lines,
&geo->xoffset, &geo->yoffset,
&geo->xneg, &geo->yneg,
&geo->valign, &geo->halign) &&
parse_text_align(text_align, &geo->text_halign, &geo->text_valign)) {
FUNCTION_END();
return geo;
}
FUNCTION_END();
return NULL;
}
/* }}} */
/* init_padding -- Initialize padding values from settings {{{ */
void init_padding(xosd_xft *osd)
{
FUNCTION_START();
if (osd->settings.padding != NULL)
{
char *padding = strdup(osd->settings.padding);
char *s = strtok(padding, " ");
unsigned int l_padding[] = {-1, -1, -1, -1};
int i = 0;
do
{
l_padding[i++] = atoi(s);
if (i > 3)
break;
} while ((s = strtok(NULL, " ")) != NULL);
osd->w_pad_t = l_padding[0];
if (l_padding[1] == -1)
{
osd->w_pad_r = l_padding[0];
osd->w_pad_b = l_padding[0];
osd->w_pad_l = l_padding[0];
}
else if (l_padding[2] == -1)
{
osd->w_pad_r = l_padding[1];
osd->w_pad_b = l_padding[0];
osd->w_pad_l = l_padding[1];
}
else if (l_padding[3] == -1)
{
osd->w_pad_r = l_padding[1];
osd->w_pad_b = l_padding[2];
osd->w_pad_l = l_padding[1];
}
else
{
osd->w_pad_r = l_padding[1];
osd->w_pad_b = l_padding[2];
osd->w_pad_l = l_padding[3];
}
free(padding);
} else {
osd->w_pad_t = osd->w_pad_r = osd->w_pad_b = osd->w_pad_l = 0;
}
FUNCTION_END();
}
/* }}} */
/* min -- Find minimum of two numbers */
unsigned int
min(unsigned int x, unsigned int y)
{
return x < y ? x : y;
}
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
/* calc_geometry -- Calculate the geometry of OSD Window {{{ */
void calc_geometry(xosd_xft *osd, osd_geometry *geometry)
{
FUNCTION_START();
int xneg = geometry->xneg, yneg = geometry->yneg, xoffset = geometry->xoffset, yoffset = geometry->yoffset;
osd_valign valign = geometry->valign;
osd_halign halign = geometry->halign;
int xstart, ystart;
unsigned int width, height;
unsigned int line_height, char_width;
{
XGlyphInfo extents;
static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
XftTextExtentsUtf8(osd->display, osd->font, (const FcChar8 *) ascii_printable, strlen(ascii_printable), &extents);
char_width = DIVCEIL(extents.xOff, strlen(ascii_printable));
}
init_padding(osd);
line_height = osd->font->ascent + osd->font->descent;
/* char_width = osd->font->max_advance_width; */
DEBUG_MSG(Dvalue, "CalcGeometry { char_width: %u, width: %u }", char_width, geometry->width);
width = min(osd->screen_width,
geometry->width == 0 ? osd->screen_width :
(geometry->width_per ? osd->screen_width * geometry->width / 100 :
(geometry->width_chars ? geometry->width * char_width + osd->w_pad_l + osd->w_pad_r :
geometry->width)));
height = min(osd->screen_height,
geometry->height == 0 ? line_height + osd->w_pad_t + osd->w_pad_b :
(geometry->height_per ? osd->screen_height * geometry->height / 100 :
(geometry->height_lines ? geometry->height * line_height + osd->w_pad_t + osd->w_pad_b :
geometry->height)));
osd->t_width = width - osd->w_pad_l - osd->w_pad_r;
osd->t_height = height - osd->w_pad_t - osd->w_pad_b;
if(osd->settings.maxlines > osd->t_height / line_height) {
int maxlines = osd->t_height / line_height ;
fprintf(stderr, "Number of lines > displayable lines. Adjusting to %d", maxlines);
osd->settings.maxlines = maxlines ;
}
osd->w_width = width;
osd->w_height = height;
osd->line_height = line_height;
DEBUG_MSG(Dvalue, "CalcGeometry { width: %u, height: %u }", osd->w_width, osd->w_height);
if (xneg)
xoffset *= -1;
if (halign == XOSD_XFT_halign_none)
{
if (xneg)
{
xstart = osd->screen_xpos + osd->screen_width - width;
}
else
{
xstart = osd->screen_xpos;
}
}
else if (halign == XOSD_XFT_left)
{
xstart = osd->screen_xpos;
}
else if (halign == XOSD_XFT_right)
{
xstart = osd->screen_xpos + osd->screen_width - width;
}
else
{
xstart = osd->screen_xpos + (osd->screen_width - width) / 2;
}
if (yneg)
yoffset *= -1;
if (valign == XOSD_XFT_valign_none)
{
if (yneg)
{
ystart = osd->screen_ypos + osd->screen_height - height;
}
else
{
ystart = osd->screen_ypos;
}
}
else if (valign == XOSD_XFT_top)
{
ystart = osd->screen_ypos;
}
else if (valign == XOSD_XFT_bottom)
{
ystart = osd->screen_ypos + osd->screen_height - height;
}
else
{
ystart = osd->screen_ypos + (osd->screen_height - height) / 2;
}
osd->w_x = xstart + xoffset;
osd->w_y = ystart + yoffset;
osd->w_border_width = 0;
FUNCTION_END();
}
/* }}} */
/* event_loop -- X11 event loop {{{ */
static void *
event_loop(void *osdv)
{
xosd_xft *osd = osdv;
Atom xosd_xft_event = XInternAtom(osd->display, XOSD_XFT_event, False);
while (1) {
XEvent ev;
XNextEvent(osd->display, &ev);
if (ev.type == Expose) {
XftDrawRect(osd->draw, &osd->bg_color, 0, 0, osd->w_width, osd->w_height);
if (osd->settings.lines != NULL && osd->settings.nlines > 0) {
XRectangle clip;
int i;
clip.x = osd->w_pad_l;
clip.y = osd->w_pad_t;
clip.width = osd->w_width - osd->w_pad_r - osd->w_pad_l;
clip.height = osd->w_height - osd->w_pad_b - osd->w_pad_t;
XftDrawSetClipRectangles(osd->draw, 0, 0, &clip, 1);
for(i = 0; i < osd->settings.nlines; i++) {
char *message = osd->settings.lines[i];
XGlyphInfo extents;
XftTextExtentsUtf8(osd->display, osd->font, (XftChar8 *)message, strlen(message), &extents);
DEBUG_MSG(Dvalue, "Extents { width = %d, height = %d, x = %d, y = %d, xOff = %d, yOff = %d }", extents.width, extents.height, extents.x, extents.y, extents.xOff, extents.yOff);
DEBUG_MSG(Dvalue, "Geometry: { w_x = %d, w_y = %d, w_border_width = %d, w_width = %d, w_height = %d, t_width = %d, t_height = %d, w_pad_t = %d, w_pad_r = %d, w_pad_b = %d, w_pad_l = %d}", osd->w_x, osd->w_y, osd->w_border_width, osd->w_width, osd->w_height, osd->t_width, osd->t_height, osd->w_pad_t, osd->w_pad_r, osd->w_pad_b, osd->w_pad_l);
int x = osd->w_pad_l + extents.x;
int y = osd->w_pad_t + extents.y;
if(osd->geometry.text_halign == XOSD_XFT_right) {
x += osd->t_width - extents.width ;
} else if(osd->geometry.text_halign == XOSD_XFT_center) {
x += (osd->t_width - extents.width)/2 ;
}
if(osd->settings.maxlines <= 1) {
if(osd->geometry.text_valign == XOSD_XFT_bottom) {
y += osd->t_height - extents.height;
} else if(osd->geometry.text_valign == XOSD_XFT_middle) {
y += (osd->t_height - extents.height)/2 ;
}
} else {
y = osd->line_height * i + osd->w_pad_t + extents.y ;
}
if(osd->settings.shadow_offset_x && osd->settings.shadow_offset_y) {
XftDrawStringUtf8(osd->draw, &osd->shadow_color, osd->font, x + osd->settings.shadow_offset_x, y + osd->settings.shadow_offset_y, (const FcChar8 *)message, strlen(message));
}
XftDrawStringUtf8(osd->draw, &osd->text_color, osd->font, x, y, (const FcChar8 *)message, strlen(message));
}
XftDrawSetClip(osd->draw, NULL);
}
}
else if (ev.type == ClientMessage && ev.xclient.message_type == xosd_xft_event) {
if (ev.xclient.data.l[0] == XOSD_XFT_event_Exit) {
break;
} else if (ev.xclient.data.l[0] == XOSD_XFT_event_Show) {
XMapRaised(osd->display, osd->window);
} else if (ev.xclient.data.l[0] == XOSD_XFT_event_Hide) {
XUnmapWindow(osd->display, osd->window);
} else if (ev.xclient.data.l[0] == XOSD_XFT_event_Geometry) {
calc_geometry(osd, &osd->geometry);
XMoveResizeWindow(osd->display, osd->window, osd->w_x, osd->w_y, osd->w_width, osd->w_height);
} else if (ev.xclient.data.l[0] == XOSD_XFT_event_Foreground) {
XftColor xft_color ;
if(init_color(osd, osd->settings.text_color, osd->settings.text_alpha, &xft_color) != -1) {
XftColorFree(osd->display, osd->visual, osd->colormap, &osd->text_color);
osd->text_color = xft_color;
} else {
fprintf(stderr, "Error in setting text color %s: %s (ignoring)\n", osd->settings.text_color, osd_error);
}
} else if (ev.xclient.data.l[0] == XOSD_XFT_event_Background) {
XftColor xft_color ;
if(init_color(osd, osd->settings.bg_color, osd->settings.bg_alpha, &xft_color) != -1) {
XftColorFree(osd->display, osd->visual, osd->colormap, &osd->bg_color);
osd->bg_color = xft_color;
} else {
fprintf(stderr, "Error in setting background color %s: %s (ignoring)\n", osd->settings.bg_color, osd_error);
}
} else if (ev.xclient.data.l[0] == XOSD_XFT_event_Shadow) {
XftColor xft_color ;
if(init_color(osd, osd->settings.shadow_color, osd->settings.shadow_alpha, &xft_color) != -1) {
XftColorFree(osd->display, osd->visual, osd->colormap, &osd->shadow_color);
osd->shadow_color = xft_color;
} else {
fprintf(stderr, "Error in setting shadow color %s: %s (ignoring)\n", osd->settings.bg_color, osd_error);
}
}
}
}
return NULL;
}
/* }}} */
/* init_color -- Initialize a color with alpha channel {{{ */
int
init_color(xosd_xft* osd, const char* color, unsigned int alpha, XftColor* xft_color)
{
FUNCTION_START();
XRenderColor bgRender;
if (!XftColorAllocName(osd->display, osd->visual, osd->colormap, color, xft_color)) {
osd_error = "Could not allocate text color";
return -1;
}
if(alpha < 100) {
bgRender = xft_color->color;
bgRender.alpha = alpha / 100.0 * 0xFFFF;
XftColorFree(osd->display, osd->visual, osd->colormap, xft_color);
if (!XftColorAllocValue(osd->display, osd->visual, osd->colormap, &bgRender, xft_color)) {
osd_error ="Could not allocate background color";
return -1;
}
}
return 0;
}
/* }}} */
/* init_bg_color -- Initialize background color with alpha {{{ */
static int
init_bg_color(xosd_xft* osd, const char* color, unsigned int alpha)
{
XftColor bg_color;
if(init_color(osd, color, alpha, &bg_color) != -1) {
osd->bg_color = bg_color ;
return 0;
}
return -1;
}
/* }}} */
/* osd_init -- Initialize OSD Window {{{ */
static int
osd_init(xosd_xft *osd)
{
FUNCTION_START();
XVisualInfo vinfo;
XSetWindowAttributes winattr;
/* Initialization. */
osd->display = XOpenDisplay(NULL);
if (!osd->display) {
FUNCTION_END();
fail(-1, "Could not connect to display");
}
osd->event_display = XOpenDisplay(NULL);
if (!osd->event_display) {
FUNCTION_END();
fail(-1, "Could not connect to display");
}
osd->screen = DefaultScreen(osd->display);
if (XMatchVisualInfo(osd->display, osd->screen, 32, TrueColor, &vinfo))
{
osd->visual = vinfo.visual;
osd->colormap = XCreateColormap(osd->display, RootWindow(osd->display, osd->screen), osd->visual, AllocNone);
osd->depth = vinfo.depth;
}
else
{
osd->visual = DefaultVisual(osd->display, osd->screen);
osd->colormap = DefaultColormap(osd->display, osd->screen);
osd->depth = DefaultDepth(osd->display, osd->screen);
}
osd_init_monitor(osd->display, osd->screen, osd->settings.monitor,
osd->settings.use_xrandr, osd->settings.use_xinerama,
&osd->screen_width, &osd->screen_height,
&osd->screen_xpos, &osd->screen_ypos);
osd->font = XftFontOpenName(osd->display, osd->screen, osd->settings.fontname);
if (!osd->font) {
FUNCTION_END();
fail(-1, "Could not open font");
}
DEBUG_MSG(Dvalue, "XftFont { ascent = %d, descent = %d, height = %d, max_advance_width = %d }",
osd->font->ascent, osd->font->descent, osd->font->height, osd->font->max_advance_width);
calc_geometry(osd, &osd->geometry);
winattr.override_redirect = 1;
winattr.border_pixel = 0;
winattr.background_pixel = 0;
winattr.colormap = osd->colormap;
DEBUG_MSG(Dvalue,"CreateWindow { x: %d, y: %d, width: %u, height: %u }",
osd->w_x, osd->w_y, osd->w_width, osd->w_height );
osd->window = XCreateWindow(osd->display,
RootWindow(osd->display, osd->screen),
osd->w_x, osd->w_y,
osd->w_width, osd->w_height,
osd->w_border_width,
osd->depth,
CopyFromParent,
osd->visual,
CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &winattr);
{
Atom window_type = XInternAtom(osd->display, "_NET_WM_WINDOW_TYPE", False);
long value = XInternAtom(osd->display, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
XChangeProperty(osd->display, osd->window, window_type, XA_ATOM,
32, PropModeReplace, (unsigned char *) &value, 1 );
}
{
XClassHint class = { "xosd-xft", "xosd-xft" };
XSetClassHint(osd->display, osd->window, &class);
}
XStoreName(osd->display, osd->window, "XOSD_XFT");
XSelectInput(osd->display, osd->window, ExposureMask);
/* Xft. */
if (init_color(osd, osd->settings.text_color, osd->settings.text_alpha, &osd->text_color) == -1) {
FUNCTION_END();
return -1;
}
if (init_color(osd, osd->settings.shadow_color, osd->settings.shadow_alpha, &osd->shadow_color)) {
FUNCTION_END();
return -1;
}
if(init_bg_color(osd, osd->settings.bg_color, osd->settings.bg_alpha) == -1) {
FUNCTION_END();
return -1;
}
osd->draw = XftDrawCreate(osd->display, osd->window, osd->visual, osd->colormap);
stay_on_top(osd->display, osd->window);
pthread_create(&osd->event_thread, NULL, event_loop, osd);
FUNCTION_END();
return 0;
}
/* }}} */
/* send_expose_event -- send an expose event */
void send_expose_event(xosd_xft *osd)
{
FUNCTION_START();
XEvent exppp;
memset(&exppp, 0, sizeof(exppp));
exppp.type = Expose;
exppp.xexpose.window = osd->window;
XSendEvent(osd->event_display, osd->window, False, ExposureMask, &exppp);
XFlush(osd->event_display);
FUNCTION_END();
}
/* }}} */
/* osd_show -- Show the window {{{ */
int osd_show(xosd_xft *osd)
{
if(osd->display != NULL)
send_event(osd, XOSD_XFT_event_Show);
return 0;
}
/* }}} */
/* osd_hide -- Display a string {{{ */
int osd_hide(xosd_xft *osd)
{
if(osd->display != NULL)
send_event(osd, XOSD_XFT_event_Hide);
return 0;
}
/* }}} */
/* osd_display -- Display a string {{{ */
int osd_display(xosd_xft *osd, char *message, int len)
{
FUNCTION_START();
int i;
char *m = strndup(message, len);
m[len] = '\0';
if (osd->display == NULL)
{
if (osd_init(osd) != 0) {
FUNCTION_END();
fail(-1, osd_error);
}
}
if(osd->settings.nlines < osd->settings.maxlines) {
osd->settings.lines[osd->settings.nlines++] = m ;
} else {
for(i = 1; i < osd->settings.maxlines; i++) {
osd->settings.lines[i-1] = osd->settings.lines[i];
}
osd->settings.lines[osd->settings.nlines-1] = m ;
}
send_expose_event(osd);
FUNCTION_END();
osd_show(osd);
return 0;
}
/* }}} */
/* send_event -- send event to App {{{ */
void send_event(xosd_xft *osd, long event_type)
{
FUNCTION_START();
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.serial = 0;
event.xclient.send_event = True;
event.xclient.message_type = XInternAtom(osd->event_display, XOSD_XFT_event, False);
event.xclient.format = 32;
event.xclient.window = osd->window;
event.xclient.data.l[0] = event_type;
XSendEvent(osd->event_display, osd->window, False, NoEventMask, &event);
XFlush(osd->event_display);
FUNCTION_END();
}
/* }}} */
/* osd_destroy -- Free OSD resources {{{ */
int osd_destroy(xosd_xft *osd)
{
FUNCTION_START();
if(osd->display == NULL)
return 0;
send_event(osd, XOSD_XFT_event_Exit);
pthread_join(osd->event_thread, NULL);
XftColorFree(osd->display, osd->visual, osd->colormap, &osd->text_color);
XftDrawDestroy(osd->draw);
XDestroyWindow(osd->display, osd->window);
XCloseDisplay(osd->display);
XCloseDisplay(osd->event_display);
{
int i ;
for(i = 0; i < osd->settings.maxlines; i++)
free(osd->settings.lines[i]);
free(osd->settings.lines);
}
free(osd);
FUNCTION_END();
return 0;
}
/* }}} */
/* osd_set_geometry -- set geometry {{{ */
void osd_set_geometry(xosd_xft *osd, const osd_geometry *geometry)
{
FUNCTION_START();
osd->geometry = *geometry;
if(osd->display != NULL) {
send_event(osd, XOSD_XFT_event_Geometry);
send_expose_event(osd);
}
FUNCTION_END();
}
/* }}} */
/* osd_set_font -- set font {{{ */
void osd_set_font(xosd_xft *osd, const char *font)
{
FUNCTION_START();
osd->settings.fontname = font;
FUNCTION_END();
}
/* }}} */
/* osd_set_monitor -- set monitor {{{ */
void osd_set_monitor(xosd_xft *osd, int monitor)
{
FUNCTION_START();
osd->settings.monitor = monitor;
FUNCTION_END();
}
/* }}} */
/* osd_set_padding -- set padding {{{ */
void osd_set_padding(xosd_xft *osd, const char *padding)
{
FUNCTION_START();
osd->settings.padding = padding;
if(osd->display != NULL) {
init_padding(osd);
send_expose_event(osd);
}
FUNCTION_END();
}
/* }}} */
/* osd_set_textcolor -- set text color {{{ */
void osd_set_textcolor(xosd_xft *osd, const char *textcolor, unsigned int textalpha)
{
FUNCTION_START();
osd->settings.text_color = textcolor;
osd->settings.text_alpha = textalpha;
if(osd->display != NULL) {
send_event(osd, XOSD_XFT_event_Foreground);
send_expose_event(osd);
}
FUNCTION_END();
}
/* }}} */
/* osd_set_bgcolor -- set background color {{{ */
void osd_set_bgcolor(xosd_xft *osd, const char *bgcolor, unsigned int bgalpha)
{
FUNCTION_START();
osd->settings.bg_color = bgcolor;
osd->settings.bg_alpha = bgalpha;
if(osd->display != NULL) {
send_event(osd, XOSD_XFT_event_Background);
send_expose_event(osd);
}
FUNCTION_END();
}
/* }}} */
/* osd_set_shadowoffset -- set offset for the shadow (0 - None) {{{ */
void osd_set_shadowoffset(xosd_xft *osd, int offset_x, int offset_y)
{
FUNCTION_START();
osd->settings.shadow_offset_x = offset_x;
osd->settings.shadow_offset_y = offset_y;
FUNCTION_END();
}
/* }}} */
/* osd_set_shadowcolor -- set shadow color {{{ */
void osd_set_shadowcolor(xosd_xft *osd, const char *shadowcolor, unsigned int shadowalpha)
{
FUNCTION_START();
osd->settings.shadow_color = shadowcolor;
osd->settings.shadow_alpha = shadowalpha;
if(osd->display != NULL) {
send_event(osd, XOSD_XFT_event_Shadow);
send_expose_event(osd);
}
FUNCTION_END();
}
/* }}} */
/* osd_set_xinerama -- set xinerama {{{ */
void osd_set_xinerama(xosd_xft *osd, int xinerama)
{
FUNCTION_START();
osd->settings.use_xinerama = xinerama;
FUNCTION_END();
}
/* }}} */
/* osd_set_number_of_lines -- Set number of lines to display {{{ */
void osd_set_number_of_lines(xosd_xft *osd, int nlines)
{
FUNCTION_START();
if(osd->settings.lines) {
int i;
for(i = 0; i < osd->settings.maxlines; i++)
free(osd->settings.lines[i]);
free(osd->settings.lines);
}
osd->settings.maxlines = nlines;
osd->settings.lines = calloc(nlines, sizeof(char*));
FUNCTION_END();
}
/* }}} */
/* osd_set_xrandr -- set xrandr {{{ */
void osd_set_xrandr(xosd_xft *osd, int xrandr)
{
FUNCTION_START();
osd->settings.use_xrandr = xrandr;
FUNCTION_END();
}
/* osd_set_debug_level -- set the debug level {{{ */
#ifdef DEBUG
static int get_level(char *slevel) {
if(!strcmp(slevel,"none")) return Dnone;
if(!strcmp(slevel,"function")) return Dfunction;
if(!strcmp(slevel,"locking")) return Dlocking;
if(!strcmp(slevel,"select")) return Dselect;
if(!strcmp(slevel,"trace")) return Dtrace;
if(!strcmp(slevel,"value")) return Dvalue;
if(!strcmp(slevel,"update")) return Dupdate;
if(!strcmp(slevel,"all")) return Dall;
DEBUG_MSG(Dvalue, "Unknown debug level %s\n", slevel);
return 0;
}
void
osd_set_debug_level(char *debug_level) {
_xosd_debug_level = 0;
if(debug_level) {
debug_level = strdup(debug_level);
char *level = strtok(debug_level, ",");
do {
_xosd_debug_level |= get_level(level);
} while((level = strtok(NULL, ",")) != NULL);
free(debug_level);
}
}
#endif
/* }}} */
/* }}} */
/* {{{
vim: foldmethod=marker tabstop=2 shiftwidth=2 expandtab
}}} */