sxalert.c (4871B)
1 /* Simple X Alert v0.1 2 * Simple notification program for X 3 * GNU GPL v3.0+ 4 * 5 * sxalert.c - main program 6 */ 7 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <unistd.h> 11 #include <string.h> 12 #include <stdbool.h> 13 #include <getopt.h> 14 #include <time.h> 15 #include <poll.h> 16 #include <X11/Xft/Xft.h> 17 18 #include "config.h" 19 20 #define VERSION "v0.1" 21 22 static void 23 die(const char *msg, int code) 24 { 25 fprintf(stderr, "%s\n", msg); 26 exit(code); 27 } 28 29 static void 30 help(char *bin) 31 { 32 printf("sxalert %s - Alert utility for X\n\n", VERSION); 33 printf(" -t text hex color (eg FFFFFF)\n"); 34 printf(" -g background hex color\n"); 35 printf(" -r border hex color\n"); 36 printf(" -b border width in pixels\n"); 37 printf(" -d duration in milliseconds\n"); 38 printf(" -v print version & exit\n\n"); 39 printf(" -h print help panel & exit\n\n"); 40 printf("Usage: %s [arguments] \"text\" \"text\" \"text\"\n", bin); 41 exit(0); 42 } 43 44 static int 45 hex2int(char *str) 46 { 47 int num; 48 sscanf(str, "%x", &num); 49 return num; 50 } 51 52 static char * 53 convert_text_color_code(void) /* adds a '#' before the color hex, as XftColorAllocName requires it */ 54 { 55 char* text_color_pnd = (char*)malloc(8); 56 strncpy(text_color_pnd+1, text_color, 6); 57 text_color_pnd[0] = '#'; 58 text_color_pnd[7] = '\0'; 59 return text_color_pnd; 60 } 61 62 int 63 get_max(int arr[], int len) 64 { 65 int max = -1; 66 for (int i=0; i<len; i++) { 67 if (arr[i] > max) 68 max = arr[i]; 69 } 70 71 return max; 72 } 73 74 static int 75 get_width(Display *dpy, XftFont *font, char **lines, int length) 76 { 77 XGlyphInfo ext; 78 int width = 0; 79 if (length > 0) { 80 int width_lines[length]; 81 int j = 0; 82 for (int i = 0; i < length; i++) { 83 XftTextExtentsUtf8(dpy, font, (XftChar8*)lines[i], strlen(lines[i]), &ext); 84 width_lines[i] = ext.xOff; 85 j++; 86 } 87 88 int text_width = get_max(width_lines, length); 89 width = (text_x_padding * 2) + text_width; 90 } 91 92 if (width < min_width) 93 return min_width; 94 else if (width > max_width) 95 return max_width; 96 else 97 return width; 98 } 99 100 static void 101 write_text(Display *dpy, Window w, XftDraw *draw, XftColor color, XftFont *font, int text_height, char **lines, int length) 102 { 103 while (1) { 104 struct pollfd pfd = { 105 .fd = ConnectionNumber(dpy), 106 .events = POLLIN, 107 }; 108 int pending = XPending(dpy) > 0 || poll(&pfd, 1, duration) > 0; 109 110 if (!pending) 111 break; 112 113 XEvent ev; 114 XSelectInput(dpy, w, ExposureMask | ButtonPressMask); 115 XNextEvent(dpy, &ev); 116 117 if (ev.type == Expose) { 118 int spacing = text_height * 2; 119 for (int i = 0; i < length; i++) { 120 if (length != 0) 121 XftDrawStringUtf8(draw, &color, font, text_x_padding, spacing, (XftChar8 *)lines[i], strlen(lines[i])); 122 spacing += text_height * 2; 123 } 124 } else if (ev.type == ButtonPress) { 125 return; 126 } 127 } 128 } 129 130 static void 131 draw(int border, int duration, char **lines, int length) 132 { 133 char text_color_pnd[8]; 134 strncpy(text_color_pnd, convert_text_color_code(), 8); 135 136 Display *dpy = XOpenDisplay(NULL); 137 if (!dpy) 138 die("Cannot open X11 display\n", EXIT_FAILURE); 139 int scr = DefaultScreen(dpy); 140 Visual *visual = DefaultVisual(dpy, scr); 141 Colormap cmap = DefaultColormap(dpy, scr); 142 143 XftColor color; 144 XGlyphInfo extents; 145 XftFont *font = XftFontOpenName(dpy, scr, fontname); 146 if (!font) 147 die("Cannot load font\n", EXIT_FAILURE); 148 if (!XftColorAllocName(dpy, visual, cmap, text_color_pnd, &color)) 149 die("Cannot allocate Xft color\n", EXIT_FAILURE); 150 151 int width = get_width(dpy, font, lines, length); 152 int height = length * (text_height * 2) + text_height; 153 154 int count_screens = ScreenCount(dpy); 155 Screen *screen = ScreenOfDisplay(dpy, 0); 156 int x = screen->width - width - x_offset; 157 158 Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), x, y_offset, width, height, border, hex2int(border_color), hex2int(bg_color)); 159 XSetWindowAttributes attributes; 160 attributes.override_redirect = True; 161 XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attributes); 162 XSelectInput(dpy, win, ExposureMask | KeyPressMask); 163 XMapWindow(dpy, win); 164 165 XftDraw *draw = XftDrawCreate(dpy, win, visual, cmap); 166 167 write_text(dpy, win, draw, color, font, text_height, lines, length); 168 169 XftColorFree(dpy, visual, cmap, &color); 170 XftDrawDestroy(draw); 171 XDestroyWindow(dpy, win); 172 XCloseDisplay(dpy); 173 } 174 175 int 176 main(int argc, char **argv) 177 { 178 int c, s = 3; 179 char text[BUFFER]; 180 extern char *optarg; 181 182 while ((c = getopt(argc, argv, "d:b:t:g:r:vh")) != -1 ) { 183 switch (c) { 184 case 'v': 185 die(VERSION, EXIT_SUCCESS); 186 case 'h': 187 help(argv[0]); 188 case 'd': 189 duration=atoi(optarg); 190 break; 191 case 'b': 192 border_width=atoi(optarg); 193 break; 194 case 't': 195 strncpy(text_color, optarg, 7); 196 break; 197 case 'g': 198 strncpy(bg_color, optarg, 7); 199 break; 200 case 'r': 201 strncpy(border_color, optarg, 7); 202 break; 203 } 204 } 205 206 int lines_len=argc-optind; 207 char **lines = argv + optind; /* get lines to print */ 208 draw(border_width, duration, lines, lines_len); 209 210 return 0; 211 }