e219301540223496e70a4d006887e322551bfdb2
[herbe.git] / herbe.c
1 #include <X11/Xlib.h>
2 #include <X11/Xft/Xft.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <signal.h>
6 #include <unistd.h>
7 #include <string.h>
8
9 #include "config.h"
10
11 Display *display;
12 Window window;
13
14 int get_max_len(char *body, XftFont *font, int max_text_width)
15 {
16 int body_len = strlen(body);
17 XGlyphInfo info;
18 XftTextExtentsUtf8(display, font, (FcChar8 *)body, body_len, &info);
19
20 if (info.width < max_text_width)
21 return body_len;
22
23 int eol = max_text_width / font->max_advance_width;
24 info.width = 0;
25
26 while (info.width < max_text_width)
27 {
28 eol++;
29 XftTextExtentsUtf8(display, font, (FcChar8 *)body, eol, &info);
30 }
31
32 eol--;
33
34 int temp = eol;
35
36 while (body[eol] != ' ' && eol)
37 --eol;
38
39 if (eol == 0)
40 return temp;
41 else
42 return ++eol;
43 }
44
45 void expire()
46 {
47 XEvent event;
48 event.type = ButtonPress;
49 XSendEvent(display, window, 0, 0, &event);
50 XFlush(display);
51 }
52
53 int main(int argc, char *argv[])
54 {
55 if (argc == 1)
56 {
57 fprintf(stderr, "Usage: herbe body\n");
58 exit(EXIT_FAILURE);
59 }
60
61 signal(SIGALRM, expire);
62 alarm(duration);
63
64 display = XOpenDisplay(0);
65
66 if (display == 0)
67 {
68 fprintf(stderr, "Cannot open display\n");
69 exit(EXIT_FAILURE);
70 }
71
72 int screen = DefaultScreen(display);
73 Visual *visual = DefaultVisual(display, screen);
74 Colormap colormap = DefaultColormap(display, screen);
75
76 int screen_width = DisplayWidth(display, screen);
77 int screen_height = DisplayHeight(display, screen);
78
79 XftColor color;
80
81 XSetWindowAttributes attributes;
82 attributes.override_redirect = True;
83 XftColorAllocName(display, visual, colormap, background_color, &color);
84 attributes.background_pixel = color.pixel;
85 XftColorAllocName(display, visual, colormap, border_color, &color);
86 attributes.border_pixel = color.pixel;
87
88 XftFont *font = XftFontOpenName(display, screen, font_pattern);
89
90 int num_of_lines = 0;
91 int max_text_width = width - 2 * padding;
92 // TODO replace hard-coded size 100
93 char words[100][max_text_width / font->max_advance_width + 2];
94
95 for (int i = 1; i < argc; i++)
96 {
97 char *body = argv[i];
98
99 for (unsigned int eol = get_max_len(body, font, max_text_width); eol <= strlen(body) && eol; body += eol, num_of_lines++, eol = get_max_len(body, font, max_text_width))
100 {
101 strncpy(words[num_of_lines], body, eol);
102 words[num_of_lines][eol] = '\0';
103 }
104 }
105
106 unsigned int x = pos_x;
107 unsigned int y = pos_y;
108 unsigned int text_height = font->ascent - font->descent;
109 unsigned int height = (num_of_lines - 1) * line_spacing + num_of_lines * text_height + 2 * padding;
110
111 if (corner == TOP_RIGHT || corner == BOTTOM_RIGHT)
112 x = screen_width - width - border_size * 2 - pos_x;
113
114 if (corner == BOTTOM_LEFT || corner == BOTTOM_RIGHT)
115 y = screen_height - height - border_size * 2 - pos_y;
116
117 window = XCreateWindow(display, RootWindow(display, screen), x, y, width, height, border_size, DefaultDepth(display, screen), CopyFromParent, visual,
118 CWOverrideRedirect | CWBackPixel | CWBorderPixel, &attributes);
119
120 XftDraw *draw = XftDrawCreate(display, window, visual, colormap);
121 XftColorAllocName(display, visual, colormap, font_color, &color);
122
123 XSelectInput(display, window, ExposureMask | ButtonPress);
124
125 XMapWindow(display, window);
126
127 while (1)
128 {
129 XEvent event;
130 XNextEvent(display, &event);
131
132 if (event.type == Expose)
133 {
134 XClearWindow(display, window);
135 for (int i = 0; i < num_of_lines; i++)
136 XftDrawStringUtf8(draw, &color, font, padding, line_spacing * i + text_height * (i + 1) + padding, (FcChar8 *)words[i], strlen(words[i]));
137 }
138 if (event.type == ButtonPress)
139 break;
140 }
141
142 XftDrawDestroy(draw);
143 XftColorFree(display, visual, colormap, &color);
144 XftFontClose(display, font);
145 XCloseDisplay(display);
146
147 return EXIT_SUCCESS;
148 }