multiline working

This commit is contained in:
Sascha Kruse 2011-09-12 23:01:16 +02:00
parent ca07ca090e
commit f64fcc63cd
4 changed files with 168 additions and 117 deletions

51
README
View File

@ -1,25 +1,21 @@
DNOTIFY(1) DNOTIFY(1)
NAME NAME
dunst - dmenu-ish universal notification system dunst - dmenu-ish universal notification system
SYNOPSIS SYNOPSIS
dunst [-b] [-ne l/r] [-fn font] [-nb color] [-nf color] [-to secs] [-key key] [-mod modifier] dunst [-geometry geom] [-fn font] [-nb color] [-nf color] [-to secs] [-key key] [-mod modifier] [-mon n]
[-mon n]
DESCRIPTION DESCRIPTION
dunst is a lightweight notification-daemon for the libnotify. It can also be used as a standalone dunst is a lightweight notification-daemon for the libnotify. It can also be used as a standalone notification system. Dnotify displays messages received via dbus or as commandline argu
notification system. Dnotify displays messages received via dbus or as commandline argument in a ment in a fashion similar to dmenu and additionally prints them to stdout. Notifications can be closed via mouseclick.
fashion similar to dmenu and additionally prints them to stdout. Notifications can be closed via
mouseclick.
OPTIONS OPTIONS
-h/--help -h/--help
display help message. display help message.
-b dunst appears at the bottom of the screen.
-ne l/r
Don't expand popup across the screen and put it in the [l]eft or [r]ight edge
-fn/ font -fn/ font
defines the font or font set used. defines the font or font set used.
@ -36,22 +32,37 @@ OPTIONS
display each message for secs seconds. display each message for secs seconds.
-key key -key key
close window by pressing key [a,b,space,Return etc.] (should be used in combination with close window by pressing key [a,b,space,Return etc.] (should be used in combination with -mod).
-mod).
-mod modifier -mod modifier
defines the modifier for the key. Available modifiers are: ctrl,shift,mod1 (usually the defines the modifier for the key. Available modifiers are: ctrl,shift,mod1 (usually the alt-key),mod2,mod3,mod4 (usually windows key). This option can be used multiple times to
alt-key),mod2,mod3,mod4 (usually windows key). This option can be used multiple times to
combine modifiers. combine modifiers.
-mon n show the notification on monitor n. -mon n
-mon [[<width>]x<height>][+/-<X>+/-<y>]
The geometry of the message window. The height is measured in lines everything else in pixels. If the width is omitted but the height is given ("-geometry x2"), the message window
expands over the whole screen (dmenu-like). If width is 0, the window expands to the longest message displayed. A positive x is measured from the left, a negative from the right
side of the screen. Y is measured from the top and down respectevly. see also EXAMPLES show the notification on monitor n.
EXAMPLES
dunst -geometry x2 Displays a maximum of two lines across the top of the screen.
dunst -geometry x3+0-0
Displays a maximum of three the lines across the bottom of the screen.
dunst -geometry 0x3-30+20
Displays a maximum of three lines 30 pixels away from the right border and 20 pixels away from the top with adaptive size.
dunst -geometry 100x3-30+20
Displays a maximum of three lines 30 pixels away from the right border and 20 pixels away from the top with a width of 100 pixels.
AUTHOR AUTHOR
written by Sascha Kruse <knopwob@googlemail.com> written by Sascha Kruse <knopwob@googlemail.com>
COPYRIGHT COPYRIGHT
Parts of the code are taken from dmenu (especially draw.c and draw.h). Read LICENCE.dmenu and Parts of the code are taken from dmenu (especially draw.c and draw.h). Read LICENCE.dmenu and look at http://tools.suckless.org/dmenu.
look at http://tools.suckless.org/dmenu.
Some snippets in dunst_dbus.c are taken from twmn. See http://github.com/sboli/twmn. Some snippets in dunst_dbus.c are taken from twmn. See http://github.com/sboli/twmn.
@ -59,3 +70,7 @@ COPYRIGHT
SEE also SEE also
dwm(1), dmenu(1), twmn(1), notify-send(1) dwm(1), dmenu(1), twmn(1), notify-send(1)
DNOTIFY(1)

33
dunst.1
View File

@ -3,9 +3,8 @@
dunst \- dmenu\-ish universal notification system dunst \- dmenu\-ish universal notification system
.SH SYNOPSIS .SH SYNOPSIS
.B dunst .B dunst
.RB [ \-b ] .RB [ \-geometry
.RB [ \-ne .IR geom ]
.IR l/r ]
.RB [ \-fn .RB [ \-fn
.IR font ] .IR font ]
.RB [ \-nb .RB [ \-nb
@ -14,11 +13,11 @@ dunst \- dmenu\-ish universal notification system
.IR color ] .IR color ]
.RB [ \-to .RB [ \-to
.IR secs ] .IR secs ]
.RB [ \- key .RB [ \-key
.IR key ] .IR key ]
.RB [ \- mod .RB [ \-mod
.IR modifier ] .IR modifier ]
.RB [ \- mon .RB [ \-mon
.IR n ] .IR n ]
.P .P
.SH DESCRIPTION .SH DESCRIPTION
@ -29,12 +28,6 @@ is a lightweight notification\-daemon for the libnotify. It can also be used as
.B \-h/\-\-help .B \-h/\-\-help
display help message. display help message.
.TP .TP
.B \-b
dunst appears at the bottom of the screen.
.TP
.BI \-ne " l/r"
Don't expand popup across the screen and put it in the [l]eft or [r]ight edge
.TP
.BI \-fn/ " font" .BI \-fn/ " font"
defines the font or font set used. defines the font or font set used.
.TP .TP
@ -57,7 +50,23 @@ close window by pressing key [a,b,space,Return etc.] (should be used in combinat
defines the modifier for the key. Available modifiers are: ctrl,shift,mod1 (usually the alt-key),mod2,mod3,mod4 (usually windows key). This option can be used multiple times to combine modifiers. defines the modifier for the key. Available modifiers are: ctrl,shift,mod1 (usually the alt-key),mod2,mod3,mod4 (usually windows key). This option can be used multiple times to combine modifiers.
.TP .TP
.BI \-mon " n" .BI \-mon " n"
.TP
.BI \-mon " [[<width>]x<height>][+/-<X>+/-<y>]"
The geometry of the message window. The height is measured in lines everything else in pixels. If the width is omitted but the height is given ("-geometry x2"), the message window expands over the whole screen (dmenu-like). If width is 0, the window expands to the longest message displayed. A positive x is measured from the left, a negative from the right side of the screen. Y is measured from the top and down respectevly. see also EXAMPLES
show the notification on monitor n. show the notification on monitor n.
.SH EXAMPLES
.BI "dunst " \-geometry " x2"
Displays a maximum of two lines across the top of the screen.
.TP
.BI "dunst " \-geometry " x3+0-0"
Displays a maximum of three the lines across the bottom of the screen.
.TP
.BI "dunst " \-geometry " 0x3-30+20"
Displays a maximum of three lines 30 pixels away from the right border and 20 pixels away from the top with adaptive size.
.TP
.BI "dunst " \-geometry " 100x3-30+20"
Displays a maximum of three lines 30 pixels away from the right border and 20 pixels away from the top with a width of 100 pixels.
.SH AUTHOR .SH AUTHOR
written by Sascha Kruse <knopwob@googlemail.com> written by Sascha Kruse <knopwob@googlemail.com>
.SH COPYRIGHT .SH COPYRIGHT

200
dunst.c
View File

@ -17,6 +17,7 @@
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b))
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define FONT_HEIGHT_BORDER 2
/* structs */ /* structs */
typedef struct _msg_queue_t { typedef struct _msg_queue_t {
@ -28,8 +29,9 @@ typedef struct _msg_queue_t {
typedef struct _dimension_t { typedef struct _dimension_t {
int x; int x;
int y; int y;
int h; unsigned int h;
int w; unsigned int w;
int mask;
} dimension_t; } dimension_t;
typedef struct _screen_info { typedef struct _screen_info {
@ -38,14 +40,11 @@ typedef struct _screen_info {
} screen_info; } screen_info;
/* global variables */ /* global variables */
static int expand = True;
static int right = False;
static const char *font = NULL; static const char *font = NULL;
static const char *normbgcolor = "#cccccc"; static const char *normbgcolor = "#cccccc";
static const char *normfgcolor = "#000000"; static const char *normfgcolor = "#000000";
static unsigned long normcol[ColLast]; static unsigned long normcol[ColLast];
static Atom utf8; static Atom utf8;
static Bool topbar = True;
static DC *dc; static DC *dc;
static Window win; static Window win;
static double global_timeout = 10; static double global_timeout = 10;
@ -56,7 +55,8 @@ static int visible = False;
static KeySym key = NoSymbol; static KeySym key = NoSymbol;
static KeySym mask = 0; static KeySym mask = 0;
static screen_info scr; static screen_info scr;
static int message_h; static dimension_t geometry;
static int font_h;
/* list functions */ /* list functions */
msg_queue_t *append(msg_queue_t *queue, char *msg); msg_queue_t *append(msg_queue_t *queue, char *msg);
@ -65,9 +65,9 @@ int list_len(msg_queue_t *list);
/* misc funtions */ /* misc funtions */
void drawmsg(const char *msg); void delete_msg(void);
void drawmsg(void);
void handleXEvents(void); void handleXEvents(void);
void next_win(void);
void run(void); void run(void);
void setup(void); void setup(void);
void show_win(void); void show_win(void);
@ -80,10 +80,10 @@ append(msg_queue_t *queue, char *msg) {
msg_queue_t *new = malloc(sizeof(msg_queue_t)); msg_queue_t *new = malloc(sizeof(msg_queue_t));
msg_queue_t *last; msg_queue_t *last;
new->msg = msg; new->msg = msg;
new->start = 0;
printf("%s\n", new->msg); printf("%s\n", new->msg);
new->next = NULL; new->next = NULL;
if(queue == NULL) { if(queue == NULL) {
new->start = now;
return new; return new;
} }
for(last = queue; last->next; last = last->next); for(last = queue; last->next; last = last->next);
@ -102,7 +102,6 @@ pop(msg_queue_t *queue) {
return NULL; return NULL;
} }
new_head = queue->next; new_head = queue->next;
new_head->start = now;
free(queue); free(queue);
return new_head; return new_head;
} }
@ -120,63 +119,7 @@ int list_len(msg_queue_t *list) {
} }
void void
drawmsg(const char *msg) { delete_msg(void) {
int width, x, y;
dc->x = 0;
dc->y = 0;
dc->h = 0;
y = topbar ? 0 : scr.dim.h - message_h;
if(expand) {
width = scr.dim.w;
} else {
width = textw(dc, msg);
}
if(right) {
x = scr.dim.x + (scr.dim.w - width);
} else {
x = scr.dim.x;
}
resizedc(dc, width, message_h);
XResizeWindow(dc->dpy, win, width, message_h);
drawrect(dc, 0, 0, width, message_h, True, BG(dc, normcol));
drawtext(dc, msg, normcol);
XMoveWindow(dc->dpy, win, x, y);
mapdc(dc, win, width, message_h);
}
void
handleXEvents(void) {
XEvent ev;
while(XPending(dc->dpy) > 0) {
XNextEvent(dc->dpy, &ev);
switch(ev.type) {
case Expose:
if(ev.xexpose.count == 0)
mapdc(dc, win, scr.dim.w, message_h);
break;
case SelectionNotify:
if(ev.xselection.property == utf8)
break;
case VisibilityNotify:
if(ev.xvisibility.state != VisibilityUnobscured)
XRaiseWindow(dc->dpy, win);
break;
case ButtonPress:
if(ev.xbutton.window == win) {
next_win();
}
break;
case KeyPress:
if(XLookupKeysym(&ev.xkey, 0) == key) {
next_win();
}
}
}
}
void
next_win(void) {
if(msgqueue == NULL) { if(msgqueue == NULL) {
return; return;
} }
@ -192,7 +135,98 @@ next_win(void) {
XFlush(dc->dpy); XFlush(dc->dpy);
visible = False; visible = False;
} else { } else {
drawmsg(msgqueue->msg); drawmsg();
}
}
void
drawmsg(void) {
int width, x, y, height, i;
int len = list_len(msgqueue);
msg_queue_t *cur_msg = msgqueue;
dc->x = 0;
dc->y = 0;
dc->h = 0;
/* a height of 0 doesn't make sense, so we define it as 1 */
if(geometry.h == 0) {
geometry.h = 1;
}
height = MIN(geometry.h, len);
if(geometry.mask & WidthValue) {
if(geometry.w == 0) {
width = 0;
for(i = 0; i < height; i++){
width = MAX(width, textw(dc, cur_msg->msg));
cur_msg = cur_msg->next;
}
} else {
width = geometry.w;
}
} else {
width = scr.dim.w;
}
cur_msg = msgqueue;
if(geometry.mask & XNegative) {
x = (scr.dim.x + (scr.dim.w - width)) + geometry.x;
} else {
x = scr.dim.x + geometry.x;
}
if(geometry.mask & YNegative) {
y = (scr.dim.h + geometry.y) - height*font_h;
} else {
y = 0 + geometry.y;
}
resizedc(dc, width, height*font_h);
XResizeWindow(dc->dpy, win, width, height*font_h);
drawrect(dc, 0, 0, width, height*font_h, True, BG(dc, normcol));
for(i = 0; i < height; i++) {
if(cur_msg->start == 0)
cur_msg->start = now;
drawtext(dc, cur_msg->msg, normcol);
dc->y += font_h;
cur_msg = cur_msg->next;
}
XMoveWindow(dc->dpy, win, x, y);
mapdc(dc, win, width, height*font_h);
}
void
handleXEvents(void) {
XEvent ev;
while(XPending(dc->dpy) > 0) {
XNextEvent(dc->dpy, &ev);
switch(ev.type) {
case Expose:
if(ev.xexpose.count == 0)
mapdc(dc, win, scr.dim.w, font_h);
break;
case SelectionNotify:
if(ev.xselection.property == utf8)
break;
case VisibilityNotify:
if(ev.xvisibility.state != VisibilityUnobscured)
XRaiseWindow(dc->dpy, win);
break;
case ButtonPress:
if(ev.xbutton.window == win) {
delete_msg();
}
break;
case KeyPress:
if(XLookupKeysym(&ev.xkey, 0) == key) {
delete_msg();
}
}
} }
} }
@ -208,7 +242,7 @@ run(void) {
if(msgqueue != NULL) { if(msgqueue != NULL) {
show_win(); show_win();
if(difftime(now, msgqueue->start) > global_timeout) { if(difftime(now, msgqueue->start) > global_timeout) {
next_win(); delete_msg();
} }
handleXEvents(); handleXEvents();
} else if (!listen_to_dbus) { } else if (!listen_to_dbus) {
@ -237,7 +271,7 @@ setup(void) {
utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False);
/* menu geometry */ /* menu geometry */
message_h = dc->font.height + 2; font_h = dc->font.height + FONT_HEIGHT_BORDER;
#ifdef XINERAMA #ifdef XINERAMA
if((info = XineramaQueryScreens(dc->dpy, &n))) { if((info = XineramaQueryScreens(dc->dpy, &n))) {
if(scr.scr >= n) { if(scr.scr >= n) {
@ -262,7 +296,7 @@ setup(void) {
wa.override_redirect = True; wa.override_redirect = True;
wa.background_pixmap = ParentRelative; wa.background_pixmap = ParentRelative;
wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonPressMask; wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonPressMask;
win = XCreateWindow(dc->dpy, root, scr.dim.x, scr.dim.y, scr.dim.w, message_h, 0, win = XCreateWindow(dc->dpy, root, scr.dim.x, scr.dim.y, scr.dim.w, font_h, 0,
DefaultDepth(dc->dpy, DefaultScreen(dc->dpy)), CopyFromParent, DefaultDepth(dc->dpy, DefaultScreen(dc->dpy)), CopyFromParent,
DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)), DefaultVisual(dc->dpy, DefaultScreen(dc->dpy)),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
@ -288,11 +322,10 @@ show_win(void) {
XGrabButton(dc->dpy, AnyButton, AnyModifier, win, False, XGrabButton(dc->dpy, AnyButton, AnyModifier, win, False,
BUTTONMASK, GrabModeAsync, GrabModeSync, None, None); BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
XFlush(dc->dpy); XFlush(dc->dpy);
drawmsg(msgqueue->msg); drawmsg();
visible = True; visible = True;
} }
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
@ -302,8 +335,9 @@ main(int argc, char *argv[]) {
for(i = 1; i < argc; i++) { for(i = 1; i < argc; i++) {
/* switches */ /* switches */
if(!strcmp(argv[i], "-b")) if(!strcmp(argv[i], "-b")) {
topbar = False; geometry.mask |= YNegative;
}
else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
usage(EXIT_SUCCESS); usage(EXIT_SUCCESS);
@ -312,17 +346,6 @@ main(int argc, char *argv[]) {
printf("Option needs an argument\n"); printf("Option needs an argument\n");
usage(1); usage(1);
} }
else if(!strcmp(argv[i], "-ne")) {
expand = False;
if(!strcmp(argv[i+1], "l")) {
right = False;
} else if (!strcmp(argv[i+1], "r")) {
right = True;
} else {
usage(EXIT_FAILURE);
}
i++;
}
else if(!strcmp(argv[i], "-fn")) else if(!strcmp(argv[i], "-fn"))
font = argv[++i]; font = argv[++i];
else if(!strcmp(argv[i], "-nb") || !strcmp(argv[i], "-bg")) else if(!strcmp(argv[i], "-nb") || !strcmp(argv[i], "-bg"))
@ -346,6 +369,9 @@ main(int argc, char *argv[]) {
} }
i++; i++;
} }
else if(!strcmp(argv[i], "-geometry")) {
geometry.mask = XParseGeometry(argv[++i], &geometry.x, &geometry.y, &geometry.w, &geometry.h);
}
else if(!strcmp(argv[i], "-mod")) { else if(!strcmp(argv[i], "-mod")) {
if(!strcmp(argv[i+1], "ctrl")) { if(!strcmp(argv[i+1], "ctrl")) {
mask |= ControlMask; mask |= ControlMask;
@ -389,6 +415,6 @@ main(int argc, char *argv[]) {
void void
usage(int exit_status) { usage(int exit_status) {
fputs("usage: dunst [-h/--help] [-b] [-ne l/r] [-fn font]\n[-nb/-bg color] [-nf/-fg color] [-to secs] [-key key] [-mod modifier] [-mon n] [-msg msg]\n", stderr); fputs("usage: dunst [-h/--help] [-geometry geom] [-fn font]\n[-nb/-bg color] [-nf/-fg color] [-to secs] [-key key] [-mod modifier] [-mon n] [-msg msg]\n", stderr);
exit(exit_status); exit(exit_status);
} }

View File

@ -200,6 +200,7 @@ notify(DBusMessage *dmsg) {
} }
msgqueue = append(msgqueue, msg); msgqueue = append(msgqueue, msg);
drawmsg();
reply = dbus_message_new_method_return(dmsg); reply = dbus_message_new_method_return(dmsg);