diff --git a/display.c b/display.c
index ed8c57c3029d1f4d341ff9d49823e000064e8e96..0912671828e8d1184b840e3d3ac7af7baa27d840 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 550f1c49b797c02a7d5f151774ed04f54f096f0e..788ee280ea9337ef30fa63a8fe7aaca21cd82527 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 629228eb4711fdfc2d2793f7d65063a7ff30d5af..cdf45c9dcc89ac09b44b837a8c5654a938a1c55a 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 348ff1a0b42f67c85fb592f00b63148d7056aded..a8b691c5659c4e1821ab07d431195aa44aadcc2e 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 e9dc4afee1dd991f387a09ec65af0757ebfcf358..ff4a795a6bef4d32ddcadc04d843b65488680aaa 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),