Browse Source

Manages mutliple subtitles at the same time
and shows pause and shift messages

Olivier Marty 9 years ago
parent
commit
c5f568eb1b
4 changed files with 197 additions and 55 deletions
  1. 2 0
      README.md
  2. 47 9
      main.c
  3. 130 43
      printer.c
  4. 18 3
      printer.h

+ 2 - 0
README.md

@@ -9,6 +9,8 @@ This program uses X11 to show subtitles. If you are using Windows you probably d
 Currently, this program support only .srt subtitles. Please check also there is no empty line at the beginning of the file, or some unprintable characters before the first "1".
 You can see the specs of this format here : http://matroska.org/technical/specs/subtitles/srt.html
 
+To have transparency between subtitles, try to launch xcompmgr before subtitlesPrinter.
+
 ## Installation
 
 Run in a terminal

+ 47 - 9
main.c

@@ -40,6 +40,7 @@ void displayUsage(char *name)
   printf("  -m px\t\t: margin with the bottom of the screen\n");
   printf("  -p px\t\t: padding of the box\n");
   printf("  -g px\t\t: gap between two lines\n");
+  printf("  -k px\t\t: gap between two subtitles\n");
   printf("  -f fontname\t: name of the font to use\n");
   printf("  -i fontname\t: name of the italic font to use\n");
   printf("  -b fontname\t: name of the bold font to use\n");
@@ -47,9 +48,25 @@ void displayUsage(char *name)
   printf("  -h\t\t: display this help and exit\n");
 }
 
+// display a message and program its end (and free) (one at a time)
+void display(struct printerEnv *env, struct richText *rt, int time, t_events *events)
+{
+  static int id = -1;
+  t_event e;
+  printerHide(env, id);
+  id--;
+  e.type = T_HIDE;
+  e.hide.time = timeGetRelative();
+  e.hide.time.tv_sec += time;
+  e.hide.id = id;
+  e.hide.rt = rt;
+  printerShow(env, rt, id);
+  eventsPush(events, e);
+}
+
 int main(int argc, char **argv)
 {
-  int i, delay = 5, margin_bottom = 50, padding = 5, gap = 5;
+  int i, delay = 5, margin_bottom = 50, padding = 5, gap = 5, gap2 = 20;
   double factor = 1.0, shift = 0.;
   char *font = NULL, *font_i = NULL, *font_b = NULL, *font_bi = NULL;
   FILE *f = NULL;
@@ -57,7 +74,7 @@ int main(int argc, char **argv)
   
   // parse arguments
   int c;
-  while((c = getopt (argc, argv, "s:d:t:m:p:g:f:i:b:j:h")) != -1)
+  while((c = getopt (argc, argv, "s:d:t:m:p:g:k:f:i:b:j:h")) != -1)
     switch(c)
     {
       case 's':
@@ -79,6 +96,9 @@ int main(int argc, char **argv)
       case 'g':
         gap = atoi(optarg);
         break;
+      case 'k':
+        gap2 = atoi(optarg);
+        break;
       case 'f':
         font = malloc(strlen(optarg)+1);
         strcpy(font, optarg);
@@ -124,6 +144,7 @@ int main(int argc, char **argv)
   penv.margin_bottom = margin_bottom;
   penv.padding = padding;
   penv.gap = gap;
+  penv.gap2 = gap2;
   
   // show a counter before start the clock
   for(i = delay; i > 0; i--)
@@ -138,11 +159,13 @@ int main(int argc, char **argv)
     printerHide(&penv, 0);
     richTextFree(rt);
   }
+  printerRender(&penv);
   printf("0 !\n");
   timeInitialize();
   timeShift(-factor*shift);
   
   int id = 0;
+  struct richText *pausert = richTextParse("<i>paused...</i>\n");
   t_events events = eventsInit(8);
   t_event event;
   event.type = T_SHOW;
@@ -160,22 +183,34 @@ int main(int argc, char **argv)
               case ' ':
                 state = S_PAUSED;
                 printf("paused...\n");
+                printerShow(&penv, pausert, 0);
                 timePause(1);
                 break;
-              case 65361: // left (shift)
-                shift -= 0.05;
-                printf("shift : -0.05s (total : %.2f)\n", shift);
+              case 65363: // right shift
+                shift += 0.05;
+                printf("shift : +0.05s (total : %.2fs)\n", shift);
                 timeShift(-0.05);
+                {
+                  char *msg = malloc(64);
+                  sprintf(msg, "<i>shift %.2fs</i>\n", shift);
+                  display(&penv, richTextParse(msg), 1, &events);
+                }
                 break;
-              case 65363:
-                shift += 0.05;
-                printf("shift : +0.05s (total : %.2f)\n", shift);
-                timeShift(+0.05);
+              case 65361: // left shift
+                shift -= 0.05;
+                printf("shift : -0.05s (total : %.2fs)\n", shift);
+                timeShift(-0.05);
+                {
+                  char *msg = malloc(64);
+                  sprintf(msg, "<i>shift %.2fs</i>\n", shift);
+                  display(&penv, richTextParse(msg), 1, &events);
+                }
                 break;
             }
             break;
           case T_HIDE:
             printerHide(&penv, event.hide.id);
+            printerRender(&penv);
             free(event.hide.rt->raw);
             richTextFree(event.hide.rt);
             printf("\n");
@@ -238,6 +273,8 @@ int main(int argc, char **argv)
             {
               state = S_RUNNING;
               printf("end\n");
+              printerHide(&penv, 0);
+              printerRender(&penv);
               timePause(0);
             }
             break;
@@ -295,6 +332,7 @@ int main(int argc, char **argv)
     }
   }
   
+  richTextFree(pausert);
   printerCloseWindow(penv);
   fclose(f);
 }

+ 130 - 43
printer.c

@@ -83,10 +83,7 @@ struct printerEnv printerOpenWindow(char *font, char *font_i, char *font_b,
   //env.color_background = a*256*256*256 + r*256*256 + g*256 + b;
   
   // create the window
-  env.width = 1;
-  env.height = 1;
-  env.w = XCreateWindow(env.d, RootWindow(env.d, env.s), 0, 0, env.width,
-    env.height, 0, vinfo.depth, InputOutput, vinfo.visual,
+  env.w = XCreateWindow(env.d, RootWindow(env.d, env.s), 0, 0, 1, 1, 0, vinfo.depth, InputOutput, vinfo.visual,
     CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &attr);
   
   // setting fonts
@@ -123,8 +120,12 @@ struct printerEnv printerOpenWindow(char *font, char *font_i, char *font_b,
   XGetInputFocus(env.d, &env.w_focused, &revert);
   
   // event to be listened
-  XSelectInput(env.d, env.w_focused, KeyPressMask|FocusChangeMask);
+  XSelectInput(env.d, env.w_focused, KeyPressMask | FocusChangeMask | ExposureMask);
   
+  // empty message set
+  env.maxsize = 0;
+  env.size = 0;
+  env.texts = NULL;
   return env;
 }
 
@@ -161,7 +162,7 @@ int drawTextRaw(struct printerEnv env, char *text, int size, enum t_type font,
 }
 
 int drawTextLines(struct printerEnv env, char *text, int size, enum t_type font,
-    int *x, int *y, int *maxw, int draw)
+    int initx, int *x, int *y, int *maxw, int draw)
 {
   char *nl = memchr(text, '\n', size);
   if(nl == NULL)
@@ -175,62 +176,143 @@ int drawTextLines(struct printerEnv env, char *text, int size, enum t_type font,
     drawTextRaw(env, text, nl-text, font, x, y, draw);
     if(*x > *maxw)
       *maxw = *x;
-    *x = env.padding;
+    *x = initx; // TODO center
     *y += env.maxascent + env.maxdescent + env.gap;
-    drawTextLines(env, nl+1, text-nl-1+size, font, x, y, maxw, draw);
+    drawTextLines(env, nl+1, text-nl-1+size, font, initx, x, y, maxw, draw);
   }
 }
 
 // update x and y
 int drawText(struct printerEnv env, struct richText *rt,
-    int *x, int *y, int *maxw, int draw)
+    int initx, int *x, int *y, int *maxw, int draw)
 {
   if(rt->left != NULL && rt->right != NULL)
   {
-    drawText(env, rt->left, x, y, maxw, draw);
-    drawText(env, rt->right, x, y, maxw, draw);
+    drawText(env, rt->left, initx, x, y, maxw, draw);
+    drawText(env, rt->right, initx, x, y, maxw, draw);
   }
   else
-    drawTextLines(env, rt->pos, rt->size, rt->type, x, y, maxw, draw);
+    drawTextLines(env, rt->pos, rt->size, rt->type, initx, x, y, maxw, draw);
 }
 
-// TODO show and hide : show mutliple rt, with id
-void printerShow(struct printerEnv *env, struct richText *rt, int id)
+void printerRender(struct printerEnv *env)
 {
-  int x, y;
-  // remap the window
-  XMapWindow(env->d, env->w);
-  //  width and height
-  x = env->padding;
-  env->width = x;
-  env->height = env->padding;
-  drawText(*env, rt, &x, &env->height, &env->width, 0);
-  env->width += env->padding;
-  env->height += env->padding;
-  
-  XClearWindow(env->d, env->w);
-  
-  XMoveResizeWindow(env->d, env->w, (env->root_width - env->width)/2,
-    env->root_height - env->margin_bottom - env->height, env->width,
-    env->height);
-  
-  // frame
-  XSetForeground(env->d, env->gc, env->color_background);
-  XFillRectangle(env->d, env->w, env->gc, 0, 0, env->width, env->height);
-  XSetForeground(env->d, env->gc, env->color_text);
-  
-  // text
-  x = env->padding; // TODO avant c'était centré
-  y = env->padding + env->maxascent;
-  drawText(*env, rt, &x, &y, &x, 1);
+  if(env->size == 0)
+  {
+    XClearWindow(env->d, env->w);
+    XUnmapWindow(env->d, env->w);
+  }
+  else
+  {
+    int i;
+    int w = 0, h = 0;
+    // remap the window
+    XMapWindow(env->d, env->w);
+    XClearWindow(env->d, env->w);
+    
+    // resize the window
+    for(i = 0; i < env->size; i++)
+    {
+      if(env->texts[i].width > w)
+        w = env->texts[i].width;
+      if(-env->texts[i].posy > h)
+        h = -env->texts[i].posy;
+    }
+    w += 2*env->padding;
+    h += 2*env->padding;
+    XMoveResizeWindow(env->d, env->w, (env->root_width - w)/2,
+      env->root_height - env->margin_bottom - h, w, h);
+    
+    // draw texts
+    for(i = 0; i < env->size; i++)
+    {
+      int x = (w-env->texts[i].width)/2;
+      int y = h+env->texts[i].posy - env->padding;
+      // frame
+      XSetForeground(env->d, env->gc, env->color_background);
+      XFillRectangle(env->d, env->w, env->gc, x - env->padding, y - env->padding,
+        env->texts[i].width + 2*env->padding,
+        env->texts[i].height + 2*env->padding);
+      XSetForeground(env->d, env->gc, env->color_text);
+      // text
+      y += env->maxascent;
+      drawText(*env, env->texts[i].t, x, &x, &y, &x, 1);
+    }
+  }
   XFlush(env->d);
 }
 
 void printerHide(struct printerEnv *env, int id)
 {
-  XClearWindow(env->d, env->w);
-  XUnmapWindow(env->d, env->w);
-  XFlush(env->d);
+  int i;
+  for(i = 0; i < env->size; i++)
+    if(env->texts[i].id == id)
+      break;
+  if(i < env->size)
+  {
+    // delete it
+    memmove(env->texts + i, env->texts + (i + 1),
+      sizeof(struct message[env->size-i-1]));
+    env->size--;
+  }
+}
+
+int getPos(struct printerEnv *env, int h)
+{
+  int pos = -h, i;
+  // change pos until it works
+  while(1)
+  {
+    // is it ok betwen pos and pos+h ?
+    int i, gap = env->gap2 + 2 * env->padding;
+    for(i = 0; i < env->size; i++)
+    {
+      int pos2 = env->texts[i].posy;
+      int h2 = env->texts[i].height;
+      if(h2 + pos2 <= pos - gap)
+        continue;
+      if(pos2 >= pos + h + gap)
+        continue;
+      pos = pos2 - h - gap;
+      break;
+    }
+    if(i == env->size)
+      return pos;
+  }
+}
+
+void printerShow(struct printerEnv *env, struct richText *rt, int id)
+{
+  int w = 0, h = 0, x = 0;
+  // hide previous message with this id
+  printerHide(env, id);
+  if(env->maxsize == 0) // first call
+  {
+    env->maxsize = 2;
+    env->texts = malloc(sizeof(struct message[env->maxsize]));
+  }
+  else if(env->size == env->maxsize) // too small
+  {
+    env->maxsize *= 2;
+    env->texts = realloc(env->texts, sizeof(struct message[env->maxsize]));
+  }
+  if(env->texts == NULL)
+  {
+    perror("[re|m]alloc()");
+    exit(1);
+  }
+  env->texts[env->size].t = rt;
+  env->texts[env->size].id = id;
+  
+  // compute w and h
+  drawText(*env, rt, 0, &x, &h, &w, 0);
+  
+  // 0 is the bottom
+  env->texts[env->size].posy = getPos(env, h);
+  env->texts[env->size].height = h;
+  env->texts[env->size].width = w;
+  env->size++;
+  printerRender(env);
 }
 
 t_event manageEvent(struct printerEnv *env)
@@ -243,6 +325,11 @@ t_event manageEvent(struct printerEnv *env)
   XNextEvent(env->d, &event);
   switch(event.type)
   {
+    case Expose:
+      if(event.xexpose.count == 0) // last expose event
+        printerRender(env);
+      break;
+    
     case FocusOut:
       XGetInputFocus(env->d, &env->w_focused, &r);
       if(env->w_focused == PointerRoot)

+ 18 - 3
printer.h

@@ -23,6 +23,15 @@
 #include "events.h"
 #include <X11/Xlib.h>
 
+struct message
+{
+  struct richText *t;
+  int id;
+  int posy;
+  int height;
+  int width;
+};
+
 struct printerEnv
 {
   Display *d;
@@ -36,21 +45,27 @@ struct printerEnv
   XFontStruct *fontinfo_b;  // bold
   XFontStruct *fontinfo_bi; // both
   int maxascent, maxdescent;
-  int width, height;
-  int padding, gap;
+  int padding, gap, gap2;
   int root_width, root_height;
   int margin_bottom;
   unsigned long color_background, color_text;
+  
+  struct message *texts;
+  int size;
+  int maxsize;
 };
 
 struct printerEnv printerOpenWindow(char *font, char *font_i, char *font_b,
   char *font_bi);
 void printerCloseWindow(struct printerEnv env);
 
-// the id are not implemented now
+// rt is not copied
 void printerShow(struct printerEnv *env, struct richText *rt, int id);
 void printerHide(struct printerEnv *env, int id);
 
+// automatically called in printerShow
+void printerRender(struct printerEnv *env);
+
 // read next event
 t_event manageEvent(struct printerEnv *env);