From b967d39b8253eb4fda1a5507af6199ae76540d45 Mon Sep 17 00:00:00 2001 From: Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz> Date: Mon, 1 Feb 2021 23:48:01 +0100 Subject: [PATCH] Add module support by osdd_abstract -- names and module creators --- display.c | 163 ++++++++++++++++++++++++++++++++++++++++++++-- display.h | 7 +- osdd-set.c | 76 +++++++++++++++++++++- osdd-set.h | 37 ++++++++++- osdd.c | 186 +++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 405 insertions(+), 64 deletions(-) diff --git a/display.c b/display.c index ed8c57c..0912671 100644 --- a/display.c +++ b/display.c @@ -18,6 +18,7 @@ #include <X11/extensions/shape.h> #include <X11/extensions/render.h> #include <X11/Xft/Xft.h> +#include <getopt.h> #define DEBUG #include "display.h" @@ -25,8 +26,6 @@ #define SLIDERS_WITH_BRACKETS -static char *font_name = "times-64:bold"; -static double line_spacing = 0.2; @@ -124,7 +123,164 @@ stay_on_top(struct display_state *display) DBG("stay_on_top: WM does not support any known protocol\n"); } -struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y) +// **************************************************************************************** +static +void display_state_new_arg_help(FILE * f) +{ + fprintf(f,"Module DISPLAY help:\n\ +-f, --font=<f>\t\tFont to use for the OSD\n\ +-s, --line-spacing=<n>\tSet line spacing factor (decimal fraction, default=0.2)\n\ +\n"); +} + +struct osd_abstract display_state_new_arg(int argc, char ** argv,Display *dpy) +{ +static const char short_opts[] = "f:s:x:y:h:w:"; +static const struct option long_opts[] = { + { "font", required_argument, NULL, 'f' }, + { "line-spacing", required_argument, NULL, 's' }, + { "x", required_argument, NULL, 'x' }, + { "y", required_argument, NULL, 'y' }, + { "width", required_argument, NULL, 'h' }, + { "height", required_argument, NULL, 'w' }, + { NULL, 0, NULL, 0 }, +}; + fprintf(stderr,"NEW DISPLAY:\n"); + for(int i=0;i<argc;i++) fprintf(stderr,"\t%s\n",argv[i]); + char *font_name = "times-64:bold"; + double line_spacing = 0.2; + int opt; + int x=0,y=0; + int width = XDisplayWidth(dpy, XDefaultScreen(dpy)); + int height = XDisplayHeight(dpy, XDefaultScreen(dpy)); + optind = 0; + while (argv && argc>0 && (opt = getopt_long(argc+1, argv-1, short_opts, long_opts, NULL)) >= 0) + { + switch (opt) + { + case 'f': + font_name = optarg; + fprintf(stderr,"FONT SET\n"); + break; + case 's': + line_spacing = atof(optarg); + break; + case 'x': + x = atoi(optarg); + break; + case 'y': + y = atoi(optarg); + break; + case 'w': + width = atoi(optarg); + break; + case 'h': + height = atoi(optarg); + break; + default: + display_state_new_arg_help(stderr); + exit(0); + } + } + return display_state_new(dpy,width,height,x,y,font_name,line_spacing); +} + +struct osd_creator_abstract display_creator_new(void) +{ + struct osd_creator_abstract r; + memset(&r, 0, sizeof(r)); + r.name = "DISPLAY"; + r.help = display_state_new_arg_help; + r.new.add_one_osd = display_state_new_arg; + return r; +} + + +// **************************************************************************************** + + +static +void display_state_new_by_outputs_help(FILE * f) +{ + fprintf(f,"Module DISPLAY_BY_OUTPUTS help:\n\ +-f, --font=<f>\t\tFont to use for the OSD\n\ +-s, --line-spacing=<n>\tSet line spacing factor (decimal fraction, default=0.2)\n\ +-n, --name=<s> name with expansion %%d to display number (expanded by printf)\n\ +\n"); +} + +static +void display_state_new_by_outputs(struct osd_set *set, int argc, char ** argv,Display *dpy,int names_len, char ** names) +{ +static const char short_opts[] = "f:s:"; +static const struct option long_opts[] = { + { "font", required_argument, NULL, 'f' }, + { "line-spacing", required_argument, NULL, 's' }, + { "name", required_argument, NULL, 'n' }, + { NULL, 0, NULL, 0 }, +}; + fprintf(stderr,"NEW DISPLAY:\n"); + for(int i=0;i<argc;i++) fprintf(stderr,"\t%s\n",argv[i]); + char * expanding_name = "display%d"; + char *font_name = "times-64:bold"; + double line_spacing = 0.2; + int opt; + optind = 0; + while (argv && argc>0 && (opt = getopt_long(argc+1, argv-1, short_opts, long_opts, NULL)) >= 0) + { + switch (opt) + { + case 'f': + font_name = optarg; + fprintf(stderr,"FONT SET\n"); + break; + case 's': + line_spacing = atof(optarg); + break; + default: + display_state_new_by_outputs_help(stderr); + exit(0); + } + } + FILE * f = popen("xrandr | grep \\ connected","r"); + char line[1001]; + char ** new_names = xmalloc(sizeof(char *)*(names_len+1)); + for(int i=0;i<names_len;i++) new_names[i]=names[i]; + new_names[names_len] = xmalloc(sizeof(char)*(strlen(expanding_name)+100)); + int i=0; + while(fscanf(f," %1000[^\n]",line)==1) + { + int width,height,x,y; + char *l = line; + while(*l && !(*l==' ')) l++; + while(*l && !('0'<=*l&&*l<='9')) l++; + if(sscanf(l,"%dx%d+%d+%d",&width,&height,&x,&y)==4) + { + + DBG("ADD screen %dx%d on %d,%d\n",width,height,x,y); + sprintf(new_names[names_len],expanding_name,i,i,i,i,i,i); + osd_set_add(set,display_state_new(dpy,width,height,x,y,font_name,line_spacing),names_len+(bool)expanding_name[0],new_names); + i++; + } + } + free(new_names[names_len]); + free(new_names); +} + +struct osd_creator_abstract display_by_outputs_creator_new(void) +{ + struct osd_creator_abstract r; + memset(&r, 0, sizeof(r)); + r.name = "DISPLAY_BY_OUTPUTS"; + r.new.add_multiple_osd = display_state_new_by_outputs; + r.help = display_state_new_by_outputs_help; + r.t = OSD_CEATE_TYPE_ADD_MULTIPLE_OSD; + return r; +} + +// **************************************************************************************** + +struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y, char * font_name, double line_spacing) { struct display_state *display = xmalloc(sizeof(*display)); memset(display, 0, sizeof(*display)); @@ -202,7 +358,6 @@ struct display_line *display_add_line(struct display_state *display, struct osd_ } struct display_line *l = &display->lines[display->num_lines++]; - fprintf(stderr,"EZD %lld\n",(long long)display); l->line = line; return l; diff --git a/display.h b/display.h index 550f1c4..788ee28 100644 --- a/display.h +++ b/display.h @@ -26,7 +26,12 @@ struct display_line { int slider_units; }; -struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y); +struct osd_creator_abstract display_by_outputs_creator_new(void); +struct osd_creator_abstract display_creator_new(void); + + +struct osd_abstract display_state_new_arg(int argc, char ** argv,Display * dpy); +struct osd_abstract display_state_new(Display *dpy,int width,int height,int x,int y, char * font_name, double line_spacing); void display_free(struct display_state *display); void display_set_font(struct display_state *display, char *font_name, double line_spacing); struct display_line *display_add_line(struct display_state *display, struct osd_line * line); diff --git a/osdd-set.c b/osdd-set.c index 629228e..cdf45c9 100644 --- a/osdd-set.c +++ b/osdd-set.c @@ -6,10 +6,53 @@ */ #include <stdio.h> +#include <string.h> #include "osdd-set.h" #include "util.h" +int osd_set_trie_char_to_index(char in) +{ + if('0'<=in && in<='9') return in-'0'; + if(in == '_') return 10; + if('a'<=in && in<='z') return in-'a'+11; + return -1; +} + +struct osd_set_trie * osd_set_trie_new(void) +{ + struct osd_set_trie * r = xmalloc(sizeof(r[0])); + memset(r, 0, sizeof(r[0])); + return r; +} + +struct osd_set_trie * osd_set_trie_find(struct osd_set_trie * root, char * str, bool create) +{ + while(*str) + { + int i = osd_set_trie_char_to_index(*str); + if(i<0) + { + if(create) + { + die("osd_set_trie char %c not supported\n",*str); + } + else return 0; + } + if(!root->next[i]) + { + if(create) + root->next[i] = osd_set_trie_new(); + else return 0; + } + root = root->next[i]; + str++; + } + return root; +} + + +// *************************************************************************************************************** struct osd_line *osd_set_add_line(struct osd_set *set, enum osd_line_type type) { @@ -45,7 +88,7 @@ void osd_set_show(struct osd_set *set) { for(int i=0;i<set->len;i++) { - set->elements[i].show(set->elements[i].context,set->lines,set->num_lines); + if(set->is_active[i]) set->elements[i].show(set->elements[i].context,set->lines,set->num_lines); } } @@ -56,6 +99,16 @@ void osd_set_clear(struct osd_set *set) set->elements[i].clear(set->elements[i].context); } set->num_lines = 0; + memset(set->is_active,0,sizeof(bool)*set->max); +} + +void osd_set_active_outputs(struct osd_set *set, char * name, bool val) +{ + struct osd_set_trie *trie = osd_set_trie_find(&set->trie,name,0); + if(trie) + { + for(int i=0;i<trie->num_vals;i++) set->is_active[trie->vals[i]]=val; + } } bool osd_set_handle_event(struct osd_set *set, XEvent *ev) @@ -71,6 +124,7 @@ bool osd_set_handle_event(struct osd_set *set, XEvent *ev) struct osd_set osd_set_new(void) { struct osd_set set; + memset(&set, 0, sizeof(set)); set.len=0; set.num_lines=0; @@ -79,3 +133,23 @@ struct osd_set osd_set_new(void) return set; } +void osd_set_add(struct osd_set *set, struct osd_abstract abs, int names_len, char ** names) +{ + for(int i=0;i<names_len;i++) + { + printf("NAME |%s|\n",names[i]); + struct osd_set_trie *trie = osd_set_trie_find(&set->trie,names[i],1); + trie->vals = xrealloc(trie->vals,sizeof(trie->vals[0])*(trie->num_vals+1)); + trie->vals[trie->num_vals++] = set->len; + } + if(set->len>=set->max) + { + set->max *= 2; + if(set->max < 4) set->max=4; + set->elements = xrealloc(set->elements,sizeof(set->elements[0])*set->max); + set->is_active = xrealloc(set->is_active,sizeof(set->is_active[0])*set->max); + memset(set->is_active,0,sizeof(bool)*set->max); + } + set->elements[set->len++] = abs; +} + diff --git a/osdd-set.h b/osdd-set.h index 348ff1a..a8b691c 100644 --- a/osdd-set.h +++ b/osdd-set.h @@ -14,9 +14,20 @@ struct display_state; #define OSD_MAX_LINE_LEN 256 -#define OSD_MAX_SET_LEN 64 -#define OSD_ABSTRACT_NAME_LEN 64 +#define OSD_TRIE_LEN (26+10+1) + +struct osd_set_trie +{ + struct osd_set_trie *next[OSD_TRIE_LEN]; + int num_vals; + int *vals; +}; + +int osd_set_trie_char_to_index(char in); +struct osd_set_trie * osd_set_trie_new(void); +struct osd_set_trie * osd_set_trie_find(struct osd_set_trie * root, char * str, bool create); + enum osd_line_type { OSD_TYPE_TEXT, @@ -45,18 +56,38 @@ struct osd_abstract { }; struct osd_set { - struct osd_abstract elements[OSD_MAX_SET_LEN]; + struct osd_abstract * elements; + bool * is_active; int len; + int max; + struct osd_set_trie trie; struct osd_line *lines; int num_lines; int max_lines; }; +struct osd_creator_abstract { + enum type { + OSD_CEATE_ADD_ONE_OSD=0, + OSD_CEATE_TYPE_ADD_MULTIPLE_OSD, + } t; + char *name; + + void (*help)(FILE * out); + union { + struct osd_abstract (*add_one_osd)(int argc, char ** argv,Display *dpy); + void (*add_multiple_osd)(struct osd_set *set, int argc, char ** argv,Display *dpy,int names_len, char ** names); + } new; +}; + + struct osd_set osd_set_new(void); +void osd_set_add(struct osd_set *set, struct osd_abstract abs, int names_len, char ** names); struct osd_line *osd_set_add_line(struct osd_set *set, enum osd_line_type type); void osd_set_show(struct osd_set *set); void osd_set_clear(struct osd_set *set); bool osd_set_handle_event(struct osd_set *set, XEvent *ev); +void osd_set_active_outputs(struct osd_set *set, char * name, bool val); #endif diff --git a/osdd.c b/osdd.c index e9dc4af..ff4a795 100644 --- a/osdd.c +++ b/osdd.c @@ -22,27 +22,44 @@ static struct osd_set osd; +Display * dpy; #define FOREACHOSD for(int i=0;i<osd.len;i++) static timestamp_t now; /*** Options ***/ - static char *default_color = "green"; static char *default_outline_color = "black"; static int default_outline_width = 2; static int default_duration = 1000; static int default_min_duration = 250; static int default_log = 255; -static int debug_mode; +static int debug_mode = 1; static int test_mode; -static const char short_opts[] = "c:d:Df:m:o:O:s:"; enum long_opt { OPT_TEST = 256, }; + +static struct osd_creator_abstract * creator=NULL; +int num_creator=0; +int max_creator=0; + +static +void add_creator(struct osd_creator_abstract in) +{ + if(num_creator <= max_creator) + { + max_creator *= 2; + if(max_creator < 4) max_creator=4; + creator = xrealloc(creator,sizeof(creator[0])*max_creator); + } + creator[num_creator++]=in; +} + +static const char short_opts[] = "+c:d:Df:m:o:O:s:"; static const struct option long_opts[] = { { "color", required_argument, NULL, 'c' }, { "debug", no_argument, NULL, 'D' }, @@ -60,65 +77,121 @@ static const struct option long_opts[] = { static void NONRET usage(void) { - fprintf(stderr, "Usage: osdd <options>\n\n\ + fprintf(stderr, "Usage: osdd <options> <modules>\n\n\ Options:\n\ -c, --color=<c>\t\tDefault color (#rgb, #rrggbb or a name from rgb.txt)\n\ -D, --debug\t\tDebugging mode (do not detach from the terminal)\n\ -d, --duration=<ms>\tDefault message duration in milliseconds\n\ --f, --font=<f>\t\tFont to use for the OSD\n\ -m, --min-duration=<ms>\tDefault minimum message duration in milliseconds\n\ -o, --outline-color=<c>\tDefault outline color\n\ -O, --outline-width=<n>\tDefault outline width (default=2)\n\ --s, --line-spacing=<n>\tSet line spacing factor (decimal fraction, default=0.2)\n\ -L, --log=<n>\t\tSet default log options (bitmask, default=255)\n\ +\n\ +Modules:\n\ +Each module id specify by:\n\ +\tMODULE_NAME user_name1 user_name2 ... [ args ]\n\ +\n\ +MODULE_NAME is name from following list\n\ +user_name is name of module instance, that could by used by osdc --output=\n\ +\t\tonly small letters numbers and _ is allowed\n\ +optional arg is really in '[' ']'. Backet should be separate arguments\n\ +\n\ "); + for(int i=0;i<num_creator;i++) if(creator[i].help) creator[i].help(stderr); exit(1); } +static bool +is_small_ch(char in) +{ + return 'a'<=in && in<='z'; +} + static void parse_opts(int argc, char **argv) { int opt; + optind = 0; while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0) - switch (opt) - { - case 'c': + { + switch (opt) + { + case 'c': default_color = optarg; break; - case 'd': + case 'd': default_duration = atoi(optarg); break; - case 'D': + case 'D': debug_mode = 1; break; - case 'f': - //font_name = optarg; - break; - case 'l': - //line_spacing = atof(optarg); - break; - case 'm': + case 'm': default_min_duration = atoi(optarg); break; - case 'o': + case 'o': default_outline_color = optarg; break; - case 'O': + case 'O': default_outline_width = atoi(optarg); break; - case 'L': + case 'L': default_log = atoi(optarg); break; - case OPT_TEST: + case OPT_TEST: test_mode = 1; debug_mode = 1; break; - default: + default: + fprintf(stderr,"Option %c not exist\n\n",opt); usage(); - } + } + } + int ind = optind; + while(ind < argc) + { + for(int i=0;i<num_creator;i++) + { + if(!strcmp(creator[i].name,argv[ind])) + { + char ** name_argv = argv + ++ind; + int name_argc=0; + char ** creator_argv = 0; + int creator_argc=0; + for(;ind<argc && is_small_ch(argv[ind][0]);ind++) name_argc++; + if(ind<argc && !strcmp(argv[ind],"[")) + { + creator_argv = argv + ++ind; + int open_bracket = 1; + for(;ind<argc && open_bracket;ind++) + { + if(!strcmp(argv[ind],"[")) open_bracket++; + if(!strcmp(argv[ind],"]")) open_bracket--; + if(open_bracket) creator_argc++; + } + if(open_bracket) + { + fprintf(stderr,"Missing ']'\n\n"); + usage(); + } + } + char * default_str="default"; + if(name_argc == 0) + { + name_argc=1; + name_argv=&default_str; + } + if(creator[i].t == OSD_CEATE_ADD_ONE_OSD) + osd_set_add(&osd, creator[i].new.add_one_osd(creator_argc,creator_argv,dpy), name_argc, name_argv); + else + creator[i].new.add_multiple_osd(&osd,creator_argc,creator_argv,dpy, name_argc, name_argv); + goto parse_opt_next; + } + } + fprintf(stderr,"Module %s not exist\n\n",argv[ind]); + usage(); +parse_opt_next:; + } - if (optind < argc) - usage(); } /*** Displaying of messages ***/ @@ -142,6 +215,7 @@ display_msg(struct msg *msg) char *line = msg->text; int num_l=0; + bool is_output_set=0; while (*line) { // The parser is destructive, but it does not do any harm, since we display each message only once. @@ -190,6 +264,18 @@ display_msg(struct msg *msg) outline_color = val; else if (!strcmp(key, "outline-width")) outline_width = atoi(val); + else if (!strcmp(key, "output")) + { + is_output_set=1; + osd_set_active_outputs(&osd,val,1); + } + else if (!strcmp(key, "output-no")) + { + if(!is_output_set) + osd_set_active_outputs(&osd,"default",1); + is_output_set=1; + osd_set_active_outputs(&osd,val,0); + } if (l) { num_l++; @@ -202,6 +288,8 @@ display_msg(struct msg *msg) line = nl; } + if(!is_output_set) + osd_set_active_outputs(&osd,"default",1); if(!num_l) { struct osd_line *l = osd_set_add_line(&osd,OSD_TYPE_TEXT); @@ -364,11 +452,14 @@ do_test(void) int main(int argc, char **argv) { - parse_opts(argc, argv); + add_creator(display_creator_new()); + add_creator(display_by_outputs_creator_new()); + + setlocale(LC_CTYPE, ""); XInitThreads(); - Display *dpy = XOpenDisplay(NULL); + dpy = XOpenDisplay(NULL); if (!dpy) die("Cannot open display"); Window win = DefaultRootWindow(dpy); @@ -377,16 +468,6 @@ main(int argc, char **argv) if (!pty) die("Cannot intern OSD_QUEUE atom"); - if (!debug_mode) - { - pid_t pid = fork(); - if (pid < 0) - die("Cannot fork: %m"); - if (pid > 0) - return 0; - setsid(); - } - if (test_mode) { do_test(); @@ -400,23 +481,18 @@ main(int argc, char **argv) } osd = osd_set_new(); - { - FILE * f = popen("xrandr | grep \\ connected","r"); - char line[1001]; - while(fscanf(f," %1000[^\n]",line)==1) - { - int width,height,x,y; - char *l = line; - while(*l && !(*l==' ')) l++; - while(*l && !('0'<=*l&&*l<='9')) l++; - if(sscanf(l,"%dx%d+%d+%d",&width,&height,&x,&y)==4) - if(osd.len < OSD_MAX_SET_LEN) - { - DBG("ADD screen %dx%d on %d,%d\n",width,height,x,y); - osd.elements[osd.len++] = display_state_new(dpy,width,height,x,y); - } - } - } + parse_opts(argc, argv); + + if (!debug_mode) + { + pid_t pid = fork(); + if (pid < 0) + die("Cannot fork: %m"); + if (pid > 0) + return 0; + setsid(); + } + struct pollfd pfd = { .fd = ConnectionNumber(dpy), -- GitLab