2 #include <X11/Xft/Xft.h>
11 #include <semaphore.h>
17 #define EXIT_DISMISS 2
21 int exit_code
= EXIT_DISMISS
;
23 static void die(const char *format
, ...)
27 vfprintf(stderr
, format
, ap
);
28 fprintf(stderr
, "\n");
33 char *read_stdin_walloc(void)
37 FILE *memstream
= open_memstream(&buff
, &size
);
40 die("open_memstream failed");
42 char *temp
= malloc(4096);
47 while ((len
= fread(temp
, 1, 4096, stdin
)) > 0)
48 fwrite(temp
, 1, len
, memstream
);
56 char *invert_color(const char *color
)
59 static char inverted
[8];
61 strcpy(inverted
, color
);
62 for (int i
= 1; i
< 7; i
++)
65 inverted
[i
] = (c
< 'a') ?
66 "0123456789ABCDEF"[15 - (c
- '0' - (c
> '9' ? 7 : 0))] :
67 "0123456789abcdef"[15 - (c
- 'a')];
74 int get_max_len(char *string
, XftFont
*font
, int max_text_width
)
76 int eol
= strlen(string
);
78 XftTextExtentsUtf8(display
, font
, (FcChar8
*)string
, eol
, &info
);
80 if (info
.width
> max_text_width
)
82 eol
= max_text_width
/ font
->max_advance_width
;
85 while (info
.width
< max_text_width
)
88 XftTextExtentsUtf8(display
, font
, (FcChar8
*)string
, eol
, &info
);
94 for (int i
= 0; i
< eol
; i
++)
95 if (string
[i
] == '\n')
101 if (info
.width
<= max_text_width
)
106 while (string
[eol
] != ' ' && eol
)
118 event
.type
= ButtonPress
;
119 event
.xbutton
.button
= (sig
== SIGUSR2
) ? (ACTION_BUTTON
) : (DISMISS_BUTTON
);
120 XSendEvent(display
, window
, 0, 0, &event
);
124 int main(int argc
, char *argv
[])
126 int nargc
= 0, rstatus
;
130 char *body
= NULL
, *bptr
;
131 const char *pattern
= "#[a-fA-F0-9]{6}";
133 if (!isatty(STDIN_FILENO
))
135 body
= read_stdin_walloc();
140 if (*bptr
== '\n' && *(bptr
+ 1)) nargc
++;
147 nargv
= malloc((argc
+ nargc
) * sizeof(char *));
149 die("malloc failed");
151 memcpy(nargv
, argv
, argc
* sizeof(char *));
159 if (c
== nargc
+ argc
) break;
160 if (*bptr
== '\n' && *(bptr
+ 1))
174 sem_unlink("/herbe");
175 die("usage: %s [body]", argv
[0]);
178 struct sigaction act_expire
, act_ignore
;
180 if ((rstatus
= regcomp(®ex
, pattern
, REG_EXTENDED
)))
181 die("%s: regex compilation failed", argv
[0]);
183 if (!(rstatus
= regexec(®ex
, argv
[1], 1, &match
, 0)))
185 background_color
= argv
[1];
186 font_color
= invert_color(argv
[1]);
187 border_color
= font_color
;
190 act_expire
.sa_handler
= expire
;
191 act_expire
.sa_flags
= SA_RESTART
;
192 sigemptyset(&act_expire
.sa_mask
);
194 act_ignore
.sa_handler
= SIG_IGN
;
195 act_ignore
.sa_flags
= 0;
196 sigemptyset(&act_ignore
.sa_mask
);
198 sigaction(SIGALRM
, &act_expire
, 0);
199 sigaction(SIGTERM
, &act_expire
, 0);
200 sigaction(SIGINT
, &act_expire
, 0);
202 sigaction(SIGUSR1
, &act_ignore
, 0);
203 sigaction(SIGUSR2
, &act_ignore
, 0);
205 if (!(display
= XOpenDisplay(0)))
206 die("Cannot open display");
208 int screen
= DefaultScreen(display
);
209 Visual
*visual
= DefaultVisual(display
, screen
);
210 Colormap colormap
= DefaultColormap(display
, screen
);
212 int screen_width
= DisplayWidth(display
, screen
);
213 int screen_height
= DisplayHeight(display
, screen
);
215 XSetWindowAttributes attributes
;
216 attributes
.override_redirect
= True
;
218 XftColorAllocName(display
, visual
, colormap
, background_color
, &color
);
219 attributes
.background_pixel
= color
.pixel
;
220 XftColorAllocName(display
, visual
, colormap
, border_color
, &color
);
221 attributes
.border_pixel
= color
.pixel
;
223 int num_of_lines
= 0;
224 int max_text_width
= width
- 2 * padding
;
226 char **lines
= malloc(lines_size
* sizeof(char *));
228 die("malloc failed");
230 XftFont
*font
= XftFontOpenName(display
, screen
, font_pattern
);
232 for (int i
= 1; i
< argc
; i
++)
234 for (unsigned int eol
= get_max_len(argv
[i
], font
, max_text_width
); eol
; argv
[i
] += eol
, num_of_lines
++, eol
= get_max_len(argv
[i
], font
, max_text_width
))
236 if (lines_size
<= num_of_lines
)
238 lines
= realloc(lines
, (lines_size
+= 5) * sizeof(char *));
240 die("realloc failed");
243 lines
[num_of_lines
] = malloc((eol
+ 1) * sizeof(char));
244 if (!lines
[num_of_lines
])
245 die("malloc failed");
247 strncpy(lines
[num_of_lines
], argv
[i
], eol
);
248 lines
[num_of_lines
][eol
] = '\0';
252 unsigned int x
= pos_x
;
253 unsigned int y
= pos_y
;
254 unsigned int text_height
= font
->ascent
- font
->descent
;
255 unsigned int height
= (num_of_lines
- 1) * line_spacing
+ num_of_lines
* text_height
+ 2 * padding
;
257 if (corner
== TOP_RIGHT
|| corner
== BOTTOM_RIGHT
)
258 x
= screen_width
- width
- border_size
* 2 - pos_x
;
260 if (corner
== BOTTOM_LEFT
|| corner
== BOTTOM_RIGHT
)
261 y
= screen_height
- height
- border_size
* 2 - pos_y
;
263 window
= XCreateWindow(display
, RootWindow(display
, screen
), x
, y
, width
, height
, border_size
, DefaultDepth(display
, screen
),
264 CopyFromParent
, visual
, CWOverrideRedirect
| CWBackPixel
| CWBorderPixel
, &attributes
);
266 XftDraw
*draw
= XftDrawCreate(display
, window
, visual
, colormap
);
267 XftColorAllocName(display
, visual
, colormap
, font_color
, &color
);
269 XSelectInput(display
, window
, ExposureMask
| ButtonPress
);
270 XMapWindow(display
, window
);
272 sem_t
*mutex
= sem_open("/herbe", O_CREAT
, 0644, 1);
275 sigaction(SIGUSR1
, &act_expire
, 0);
276 sigaction(SIGUSR2
, &act_expire
, 0);
284 XNextEvent(display
, &event
);
286 if (event
.type
== Expose
)
288 XClearWindow(display
, window
);
289 for (int i
= 0; i
< num_of_lines
; i
++)
290 XftDrawStringUtf8(draw
, &color
, font
, padding
, line_spacing
* i
+ text_height
* (i
+ 1) + padding
,
291 (FcChar8
*)lines
[i
], strlen(lines
[i
]));
293 else if (event
.type
== ButtonPress
)
295 if (event
.xbutton
.button
== DISMISS_BUTTON
)
297 else if (event
.xbutton
.button
== ACTION_BUTTON
)
299 exit_code
= EXIT_ACTION
;
308 for (int i
= 0; i
< num_of_lines
; i
++)
317 XftDrawDestroy(draw
);
318 XftColorFree(display
, visual
, colormap
, &color
);
319 XftFontClose(display
, font
);
320 XCloseDisplay(display
);