wmusic: Drop "-1.0" from playerctl pkg-config check.
[dockapps.git] / wmtunlo / docklib.c
blob7d58faeb994ba85ac2a8ae9defcc50bebf056a31
1 /*--------------------------------*/
2 /* a simple dockapp library */
3 /* made from scratch */
4 /*--------------------------------*/
6 /*
7 functions were written by following People:
9 --- linked list
10 Kresten Krab Thorup
11 Alfredo K. Kojima
13 --- built-in Dock module for WindowMaker
14 Alfredo K. Kojima
16 --- wmgeneral (taken from wmppp)
17 Martijn Pieterse (pieterse@xs4all.nl)
19 --- prefs routines
20 Tomasz M±ka
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
32 #include <X11/Xlib.h>
33 #include <X11/xpm.h>
34 #include <X11/extensions/shape.h>
36 #include "docklib.h"
38 /* Return a cons cell produced from (head . tail) */
40 INLINE LinkedList*
41 list_cons(void* head, LinkedList* tail)
43 LinkedList* cell;
45 cell = (LinkedList*)malloc(sizeof(LinkedList));
46 cell->head = head;
47 cell->tail = tail;
48 return cell;
51 /* Return the length of a list, list_length(NULL) returns zero */
53 INLINE int
54 list_length(LinkedList* list)
56 int i = 0;
57 while(list)
59 i += 1;
60 list = list->tail;
62 return i;
65 /* Return the Nth element of LIST, where N count from zero. If N
66 larger than the list length, NULL is returned */
68 INLINE void*
69 list_nth(int index, LinkedList* list)
71 while(index-- != 0)
73 if(list->tail)
74 list = list->tail;
75 else
76 return 0;
78 return list->head;
81 /* Remove the element at the head by replacing it by its successor */
83 INLINE void
84 list_remove_head(LinkedList** list)
86 if (!*list) return;
87 if ((*list)->tail)
89 LinkedList* tail = (*list)->tail; /* fetch next */
90 *(*list) = *tail; /* copy next to list head */
91 free(tail); /* free next */
93 else /* only one element in list */
95 free(*list);
96 (*list) = 0;
100 INLINE LinkedList *
101 list_remove_elem(LinkedList* list, void* elem)
103 LinkedList *tmp;
105 if (list) {
106 if (list->head == elem) {
107 tmp = list->tail;
108 free(list);
109 return tmp;
111 list->tail = list_remove_elem(list->tail, elem);
112 return list;
114 return NULL;
118 /* Return element that has ELEM as car */
120 INLINE LinkedList*
121 list_find(LinkedList* list, void* elem)
123 while(list)
125 if (list->head == elem)
126 return list;
127 list = list->tail;
129 return NULL;
132 /* Free list (backwards recursive) */
134 INLINE void
135 list_free(LinkedList* list)
137 if(list)
139 list_free(list->tail);
140 free(list);
144 /* Map FUNCTION over all elements in LIST */
146 INLINE void
147 list_mapcar(LinkedList* list, void(*function)(void*))
149 while(list)
151 (*function)(list->head);
152 list = list->tail;
158 *----------------------------------------------------------------------
159 * parse_command--
160 * Divides a command line into a argv/argc pair.
161 *----------------------------------------------------------------------
163 #define PRC_ALPHA 0
164 #define PRC_BLANK 1
165 #define PRC_ESCAPE 2
166 #define PRC_DQUOTE 3
167 #define PRC_EOS 4
168 #define PRC_SQUOTE 5
170 typedef struct {
171 short nstate;
172 short output;
173 } DFA;
176 static DFA mtable[9][6] = {
177 {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
178 {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
179 {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
180 {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
181 {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
182 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
183 {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
184 {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
185 {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
188 char*
189 next_token(char *word, char **next)
191 char *ptr;
192 char *ret, *t;
193 int state, ctype;
195 t = ret = malloc(strlen(word)+1);
196 ptr = word;
198 state = 0;
199 *t = 0;
200 while (1) {
201 if (*ptr==0)
202 ctype = PRC_EOS;
203 else if (*ptr=='\\')
204 ctype = PRC_ESCAPE;
205 else if (*ptr=='"')
206 ctype = PRC_DQUOTE;
207 else if (*ptr=='\'')
208 ctype = PRC_SQUOTE;
209 else if (*ptr==' ' || *ptr=='\t')
210 ctype = PRC_BLANK;
211 else
212 ctype = PRC_ALPHA;
214 if (mtable[state][ctype].output) {
215 *t = *ptr; t++;
216 *t = 0;
218 state = mtable[state][ctype].nstate;
219 ptr++;
220 if (mtable[state][0].output<0) {
221 break;
225 if (*ret==0)
226 t = NULL;
227 else
228 t = strdup(ret);
230 free(ret);
232 if (ctype==PRC_EOS)
233 *next = NULL;
234 else
235 *next = ptr;
237 return t;
241 extern void
242 parse_command(char *command, char ***argv, int *argc)
244 LinkedList *list = NULL;
245 char *token, *line;
246 int count, i;
248 line = command;
249 do {
250 token = next_token(line, &line);
251 if (token) {
252 list = list_cons(token, list);
254 } while (token!=NULL && line!=NULL);
256 count = list_length(list);
257 *argv = malloc(sizeof(char*)*count);
258 i = count;
259 while (list!=NULL) {
260 (*argv)[--i] = list->head;
261 list_remove_head(&list);
263 *argc = count;
266 extern pid_t
267 execCommand(char *command)
269 pid_t pid;
270 char **argv;
271 int argc;
273 parse_command(command, &argv, &argc);
275 if (argv==NULL) {
276 return 0;
279 if ((pid=fork())==0) {
280 char **args;
281 int i;
283 args = malloc(sizeof(char*)*(argc+1));
284 if (!args)
285 exit(10);
286 for (i=0; i<argc; i++) {
287 args[i] = argv[i];
289 args[argc] = NULL;
290 execvp(argv[0], args);
291 exit(10);
293 return pid;
298 /*****************/
299 /* X11 Variables */
300 /*****************/
302 Window Root;
303 int screen;
304 int x_fd;
305 int d_depth;
306 XSizeHints mysizehints;
307 XWMHints mywmhints;
308 Pixel back_pix, fore_pix;
309 char *Geometry = "";
310 Window iconwin, win;
311 GC NormalGC;
312 XpmIcon wmgen;
313 Pixmap pixmask;
315 /*****************/
316 /* Mouse Regions */
317 /*****************/
319 typedef struct {
320 int enable;
321 int top;
322 int bottom;
323 int left;
324 int right;
325 } MOUSE_REGION;
327 #define MAX_MOUSE_REGION (8)
328 MOUSE_REGION mouse_region[MAX_MOUSE_REGION];
330 /***********************/
331 /* Function Prototypes */
332 /***********************/
334 static void GetXPM(XpmIcon *, char **);
335 static Pixel GetColor(char *);
336 void RedrawWindow(void);
337 void AddMouseRegion(int, int, int, int, int);
338 int CheckMouseRegion(int, int);
340 /*******************************************************************************\
341 |* read_rc_file *|
342 \*******************************************************************************/
344 void parse_rcfile(const char *filename, rckeys *keys) {
346 char *p;
347 char temp[128];
348 char *tokens = " :\t\n";
349 FILE *fp;
350 int i,key;
352 fp = fopen(filename, "r");
353 if (fp) {
354 while (fgets(temp, 128, fp)) {
355 key = 0;
356 while (key >= 0 && keys[key].label) {
357 if ((p = strstr(temp, keys[key].label))) {
358 p += strlen(keys[key].label);
359 p += strspn(p, tokens);
360 if ((i = strcspn(p, "#\n"))) p[i] = 0;
361 free(*keys[key].var);
362 *keys[key].var = strdup(p);
363 key = -1;
364 } else key++;
367 fclose(fp);
372 /*******************************************************************************\
373 |* GetXPM *|
374 \*******************************************************************************/
376 static void GetXPM(XpmIcon *wmgen, char *pixmap_bytes[]) {
378 XWindowAttributes attributes;
379 int err;
381 /* For the colormap */
382 XGetWindowAttributes(display, Root, &attributes);
384 wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
386 err = XpmCreatePixmapFromData(display, Root, pixmap_bytes, &(wmgen->pixmap),
387 &(wmgen->mask), &(wmgen->attributes));
389 if (err != XpmSuccess) {
390 fprintf(stderr, "Not enough free colorcells.\n");
391 exit(1);
395 /*******************************************************************************\
396 |* GetColor *|
397 \*******************************************************************************/
399 static Pixel GetColor(char *name) {
401 XColor color;
402 XWindowAttributes attributes;
404 XGetWindowAttributes(display, Root, &attributes);
406 color.pixel = 0;
407 if (!XParseColor(display, attributes.colormap, name, &color)) {
408 fprintf(stderr, "wm.app: can't parse %s.\n", name);
409 } else if (!XAllocColor(display, attributes.colormap, &color)) {
410 fprintf(stderr, "wm.app: can't allocate %s.\n", name);
412 return color.pixel;
415 /*******************************************************************************\
416 |* flush_expose *|
417 \*******************************************************************************/
419 static int flush_expose(Window w) {
421 XEvent dummy;
422 int i=0;
424 while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
425 i++;
427 return i;
430 /*******************************************************************************\
431 |* RedrawWindow *|
432 \*******************************************************************************/
434 void RedrawWindow(void) {
436 flush_expose(iconwin);
437 XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
438 0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
439 flush_expose(win);
440 XCopyArea(display, wmgen.pixmap, win, NormalGC,
441 0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
444 /*******************************************************************************\
445 |* RedrawWindowXY *|
446 \*******************************************************************************/
448 void RedrawWindowXY(int x, int y) {
450 flush_expose(iconwin);
451 XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
452 x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
453 flush_expose(win);
454 XCopyArea(display, wmgen.pixmap, win, NormalGC,
455 x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
458 /*******************************************************************************\
459 |* AddMouseRegion *|
460 \*******************************************************************************/
462 void AddMouseRegion(int index, int left, int top, int right, int bottom) {
464 if (index < MAX_MOUSE_REGION) {
465 mouse_region[index].enable = 1;
466 mouse_region[index].top = top;
467 mouse_region[index].left = left;
468 mouse_region[index].bottom = bottom;
469 mouse_region[index].right = right;
473 /*******************************************************************************\
474 |* CheckMouseRegion *|
475 \*******************************************************************************/
477 int CheckMouseRegion(int x, int y) {
479 int i;
480 int found;
482 found = 0;
484 for (i=0; i<MAX_MOUSE_REGION && !found; i++) {
485 if (mouse_region[i].enable &&
486 x <= mouse_region[i].right &&
487 x >= mouse_region[i].left &&
488 y <= mouse_region[i].bottom &&
489 y >= mouse_region[i].top)
490 found = 1;
492 if (!found) return -1;
493 return (i-1);
496 /*******************************************************************************\
497 |* copyXPMArea *|
498 \*******************************************************************************/
500 void copyXPMArea(int x, int y, int sx, int sy, int dx, int dy) {
502 XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
506 /*******************************************************************************\
507 |* copyXBMArea *|
508 \*******************************************************************************/
510 void copyXBMArea(int x, int y, int sx, int sy, int dx, int dy) {
512 XCopyArea(display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
516 /*******************************************************************************\
517 |* setMaskXY *|
518 \*******************************************************************************/
520 void setMaskXY(int x, int y) {
522 XShapeCombineMask(display, win, ShapeBounding, x, y, pixmask, ShapeSet);
523 XShapeCombineMask(display, iconwin, ShapeBounding, x, y, pixmask, ShapeSet);
526 /*******************************************************************************\
527 |* openXwindow *|
528 \*******************************************************************************/
529 void openXwindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height) {
531 unsigned int borderwidth = 1;
532 XClassHint classHint;
533 char *display_name = NULL;
534 char *wname = argv[0];
535 XTextProperty name;
537 XGCValues gcv;
538 unsigned long gcm;
541 int dummy=0;
542 int i;
544 for (i=1; argv[i]; i++) {
545 if (!strcmp(argv[i], "-display"))
546 display_name = argv[i+1];
549 if (!(display = XOpenDisplay(display_name))) {
550 fprintf(stderr, "%s: can't open display %s\n",
551 wname, XDisplayName(display_name));
552 exit(1);
554 screen = DefaultScreen(display);
555 Root = RootWindow(display, screen);
556 d_depth = DefaultDepth(display, screen);
557 x_fd = XConnectionNumber(display);
559 /* Convert XPM to XImage */
560 GetXPM(&wmgen, pixmap_bytes);
562 /* Create a window to hold the stuff */
563 mysizehints.flags = USSize | USPosition;
564 mysizehints.x = 0;
565 mysizehints.y = 0;
567 back_pix = GetColor("white");
568 fore_pix = GetColor("black");
570 XWMGeometry(display, screen, Geometry, NULL, borderwidth, &mysizehints,
571 &mysizehints.x, &mysizehints.y,&mysizehints.width,&mysizehints.height, &dummy);
573 mysizehints.width = 64;
574 mysizehints.height = 64;
576 win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y,
577 mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
579 iconwin = XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y,
580 mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
582 /* Activate hints */
583 XSetWMNormalHints(display, win, &mysizehints);
584 classHint.res_name = wname;
585 classHint.res_class = wname;
586 XSetClassHint(display, win, &classHint);
588 XSelectInput(display, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
589 XSelectInput(display, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
591 if (XStringListToTextProperty(&wname, 1, &name) == 0) {
592 fprintf(stderr, "%s: can't allocate window name\n", wname);
593 exit(1);
596 XSetWMName(display, win, &name);
598 /* Create GC for drawing */
600 gcm = GCForeground | GCBackground | GCGraphicsExposures;
601 gcv.foreground = fore_pix;
602 gcv.background = back_pix;
603 gcv.graphics_exposures = 0;
604 NormalGC = XCreateGC(display, Root, gcm, &gcv);
606 /* ONLYSHAPE ON */
608 pixmask = XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width, pixmask_height);
610 XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
611 XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
613 /* ONLYSHAPE OFF */
615 mywmhints.initial_state = WithdrawnState;
616 mywmhints.icon_window = iconwin;
617 mywmhints.icon_x = mysizehints.x;
618 mywmhints.icon_y = mysizehints.y;
619 mywmhints.window_group = win;
620 mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
622 XSetWMHints(display, win, &mywmhints);
624 XSetCommand(display, win, argv, argc);
625 XMapWindow(display, win);
630 FILE *prefs_filehandle;
631 char* p_strcpy (char *dest, const char *src, int maxlength);
632 char* p_strcat (char *dest, const char *src, int maxlength);
634 /*---------------------------------------------------------------------------*/
636 char* p_getdir_config (char *cdirectory)
638 static char cfgdir[MAX_PATH];
639 struct stat cfg;
641 p_strcpy (cfgdir, getenv ("HOME"), MAX_PATH);
642 p_strcat (cfgdir, slash, MAX_PATH);
643 p_strcat (cfgdir, cdirectory, MAX_PATH);
645 if(stat(cfgdir, &cfg) < 0)
646 mkdir(cfgdir, S_IRUSR | S_IWUSR | S_IXUSR);
648 return cfgdir;
651 /*---------------------------------------------------------------------------*/
653 char* p_getfilename_config (char *config_dir, char *config_filename)
655 static char filename[MAX_PATH];
657 p_strcpy (filename, p_getdir_config(config_dir), MAX_PATH);
658 p_strcat (filename, slash, MAX_PATH);
659 p_strcat (filename, config_filename, MAX_PATH);
661 return filename;
664 /*---------------------------------------------------------------------------*/
666 void* p_prefs_openfile (char *filename, int openmode)
668 prefs_filehandle = NULL;
670 if (openmode == P_READ)
671 prefs_filehandle = fopen (filename, "rb");
672 else if (openmode == P_WRITE)
673 prefs_filehandle = fopen (filename, "wb");
675 return prefs_filehandle;
679 void p_prefs_closefile (void)
681 fclose (prefs_filehandle);
684 /*---------------------------------------------------------------------------*/
686 void p_prefs_put_int (char *tagname, int value)
688 fprintf (prefs_filehandle, "%s=%d\n", tagname, value);
692 void p_prefs_put_float (char *tagname, float value)
694 fprintf (prefs_filehandle, "%s=%f\n", tagname, value);
698 void p_prefs_put_string (char *tagname, char *value)
700 fprintf (prefs_filehandle, "%s=%s\n", tagname, value);
704 void p_prefs_put_lf (void)
706 fprintf (prefs_filehandle, "\n");
710 void p_prefs_put_comment (char *comment)
712 char text[MAX_LINE_LEN];
714 p_strcpy (text, "# ", MAX_LINE_LEN);
715 p_strcat (text, comment, MAX_LINE_LEN);
716 fprintf (prefs_filehandle, text);
719 /*---------------------------------------------------------------------------*/
721 char* p_prefs_get_line_with_tag (char *tagname)
723 static char prfline[MAX_LINE_LEN];
724 int i;
725 char c;
727 fseek (prefs_filehandle, 0, SEEK_SET);
729 while (!feof (prefs_filehandle)) {
730 i = 0;
732 while (((c = fgetc (prefs_filehandle)) != crlf_char) && c!= EOF && i < MAX_LINE_LEN)
733 prfline[i++] = c;
735 prfline[i] = null_char;
737 if (prfline[0] != '#')
738 if (!strncmp (tagname, prfline, strlen (tagname))) break;
741 return prfline;
745 char* p_prefs_get_value_field (char *tagname)
747 static char valuestr[MAX_VALUE_LEN];
748 char *valpos, c;
749 int i;
751 i = 0;
753 if ((valpos = strchr (p_prefs_get_line_with_tag (tagname), '='))) {
754 while((c = valpos[i+1]) != null_char && i < MAX_VALUE_LEN) valuestr[i++] = c;
757 valuestr[i] = null_char;
758 return valuestr;
762 int p_prefs_get_int (char *tagname)
764 return (atoi (p_prefs_get_value_field (tagname)));
768 float p_prefs_get_float (char *tagname)
770 return (atof (p_prefs_get_value_field (tagname)));
774 char* p_prefs_get_string (char *tagname)
776 return (p_prefs_get_value_field (tagname));
779 /*---------------------------------------------------------------------------*/
780 /* following functions based on samba sources. */
781 /* safe_strcpy and safe_strcat routines written by Andrew Tridgell */
782 /*---------------------------------------------------------------------------*/
784 char* p_strcpy (char *dest, const char *src, int maxlength)
786 int len;
788 if (!dest) {
789 printf ("ERROR: NULL dest in safe_strcpy\n");
790 return NULL;
793 if (!src) {
794 *dest = 0;
795 return dest;
798 len = strlen(src);
800 if (len > maxlength) {
801 printf ("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
802 (int)(len-maxlength), src);
803 len = maxlength;
806 memcpy(dest, src, len);
807 dest[len] = 0;
808 return dest;
811 /*---------------------------------------------------------------------------*/
813 char* p_strcat (char *dest, const char *src, int maxlength)
815 int src_len, dest_len;
817 if (!dest) {
818 printf ("ERROR: NULL dest in safe_strcat\n");
819 return NULL;
822 if (!src) {
823 return dest;
826 src_len = strlen(src);
827 dest_len = strlen(dest);
829 if (src_len + dest_len > maxlength) {
830 printf ("ERROR: string overflow by %d in safe_strcat [%.50s]\n",
831 (int)(src_len + dest_len - maxlength), src);
832 src_len = maxlength - dest_len;
835 memcpy(&dest[dest_len], src, src_len);
836 dest[dest_len + src_len] = 0;
837 return dest;
840 /*---------------------------------------------------------------------------*/