Logo Search packages:      
Sourcecode: habak version File versions  Download package

habak.c

#include "defaults.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
#include <Imlib2.h>
#include "types.h"
#include "proto.h"

habak_l *current_list_item=NULL, *first_list_item=NULL;
habak_t *current_habak;
char *fp=NULL, *fn=NULL, *fn1=NULL, *multxt=NULL, *multxt10;
struct stat file_info;
double xco,yco;
DATA32 *raw_data;

int i, multy;
Imlib_Image workspace;
habak_t template_habak;

#ifdef DEBUG_HABAK
#define d(string) fprintf(stderr,"%s\n",string);
#else
#define d(string)
#endif

habak_l *new_habak(void) {
      d("making a shiny new habak...");
if (first_list_item==NULL) {
/* pierwsze wywołanie */
      first_list_item=current_list_item=malloc(sizeof(habak_l));
      current_list_item->next=NULL;
      d("done.");
      return current_list_item;
}
      d("making another habak...");
      current_list_item->next=malloc(sizeof(habak_l));
      current_list_item=current_list_item->next;
      current_list_item->next=NULL;
      d("done.");
      return current_list_item;
}

habak_l *next_habak(void) {
if (current_list_item==NULL) {return new_habak();}
if (current_list_item->next) {
current_list_item=current_list_item->next;
return current_list_item;
}
current_list_item=first_list_item;
return NULL;
}

int flush_habak(void) {
new_habak();
d("made a new habak from flush_habak");
current_list_item->data.type=template_habak.type;
current_list_item->data.x=template_habak.x;
current_list_item->data.y=template_habak.y;
current_list_item->data.invx=template_habak.invx;
current_list_item->data.invy=template_habak.invy;
current_list_item->data.width=template_habak.width;
current_list_item->data.height=template_habak.height;
current_list_item->data.orig_width=template_habak.orig_width;
current_list_item->data.orig_height=template_habak.orig_height;
current_list_item->data.red=template_habak.red;
current_list_item->data.green=template_habak.green;
current_list_item->data.blue=template_habak.blue;
current_list_item->data.alpha=template_habak.alpha;
current_list_item->data.image=template_habak.image;
current_list_item->data.font=template_habak.font;
current_list_item->data.text=template_habak.text;
current_list_item->data.scale_art=template_habak.scale_art;
current_list_item->data.center=template_habak.center;

current_list_item->data.file=malloc(strlen(template_habak.file)+1);
strcpy(current_list_item->data.file,template_habak.file);

current_list_item->data.fontpath=malloc(strlen(template_habak.fontpath)+1);
strcpy(current_list_item->data.fontpath,template_habak.fontpath);

current_list_item->data.internal_t=malloc(strlen(template_habak.internal_t)+1);
strcpy(current_list_item->data.internal_t,template_habak.internal_t);

current_list_item->data.fontsize=malloc(strlen(template_habak.fontsize)+1);
strcpy(current_list_item->data.fontsize,template_habak.fontsize);

return 0;
}

void print_help(int rc) {
printf("Habak Utility - option summary:\n\
Invocation model:\n\
habak [-mX -mY -m... -hx ... [ -mX -mY -m... -hx ...]]\n\n\
Every set of modifiers (\"-mX\" options) should be finalized with a Habak\n\
invocation (\"-hX\" option).\n\n\
AVAILABLE MODIFIERS:\n\
-mC -- Habak will be centered on the screen.\n\
Overrides and can be overriden by \"-mp\".\n\
Active by default.\n\
\n\
-mS -- Habak will be proportionally stretched to fill the screen.\n\
Implies \"-mC\".\n\
Inactive by default.\n\
\n\
-ms -- Habak will be non-proportionally stretched to fill the screen.\n\
Overrides and can be overriden by \"-mp\".\n\
Inactive by default.\n\
\n\
-mp X,Y -- Habak's top left corner will be placed at screen coordinates\n\
denoted by [X,Y]. Negative integers \"flip\" the coordinates of the screen.\n\
Overrides and can be overriden by \"-mC\", \"-mS\" or \"-ms\"\n\
Inactive by default\n\
\n\
-mc R,G,B,A -- Color modifier, can influence some Habaks. The color is\n\
specified via comma-separated quad of integers, each one ranging from 0 to\n\
255 and denoting the intensity of four channels: red, green, blue, alpha\n\
(\"alpha\" means \"transparency\").\n\
Active by default, set to a color best described as \"five day old snow\n\
in urban areas, somewhat transparent\"\n\
\n\
-mf (font.ttf|font_dir) -- Font modifier, selects the font used by \"-ht\"\n\
You can either give it a .ttf file, or give it a whole directory (a font\n\
file will be then selected randomly from within that directory - provided\n\
that there are any *.ttf files in there)\n\
Active by default, pointing at $HOME/.fonts/\n\
\n\
-mh height -- Font height modifier. Sets font heights, measured in pixels.\n\
Active by default, set to 30.\n\
\n\
AVAILABLE HABAKS:\n\
-hi [(image_file|image_dir)] -- Image Habak. Selects an image to use. If you\n\
name a directory Habak will randomly select an image file from this\n\
directory. If you omit the image_file/image_dir Habak will re-use the one\n\
given with previous \"-hi\" option or fall back to the default (searching\n\
for an image within the abyss of $HOME)\n\
\n\
-hI [(Int|int)] -- Internal Habak. Interlaces the whole screen, applying\n\
a modification of the color set with \"-mc\" to every second scanline. The\n\
arguments Int/int switch between even/odd lines. Called without an argument\n\
this Habak will use the argument supplied with a previous \"-hI\" invocation\n\
or fall back to the default \"int\".\n\
\n\
-ht [text_string] -- Text Habak. Prints a string using antialiased TTF fonts\n\
somewhere on the screen. Can be called multiple times to print multiple\n\
lines. The string will be interpreted as an UTF-8 stream.\n\
Called without an argument this Habak will re-use the text supplied\n\
last time, or fall back to the default \"Habak vX.Y.Z\" string.\n");

exit(rc);
}

void error(char *e) {
printf("ERROR: %s\n",e);
exit(-1);
}

int main(int argc, char *argv[]) {
srand(time(NULL)+time(NULL)*1000);

initXconnection();

template_habak.type=DEFAULT_TYPE;
template_habak.file=getenv("HOME");
template_habak.x=DEFAULT_X;
template_habak.y=DEFAULT_Y;
template_habak.invx=DEFAULT_INVX;
template_habak.invy=DEFAULT_INVY;
template_habak.scale_art=DEFAULT_SCALE_ART;
template_habak.center=DEFAULT_CENTER;
template_habak.width=scr->width;
template_habak.height=scr->height;
template_habak.orig_width=scr->width;
template_habak.orig_height=scr->height;
template_habak.red=DEFAULT_RED;
template_habak.green=DEFAULT_GREEN;
template_habak.blue=DEFAULT_BLUE;
template_habak.alpha=DEFAULT_ALPHA;
template_habak.image=NULL;
template_habak.font=NULL;
template_habak.fontpath=malloc(strlen(getenv("HOME"))+strlen("/.fonts")+1);
strcpy(template_habak.fontpath,getenv("HOME"));
strcat(template_habak.fontpath,"/.fonts");
template_habak.fontsize=DEFAULT_FONTSIZE;
template_habak.internal_t=DEFAULT_INTERNAL_TYPE;
template_habak.text=DEFAULT_TEXT;

/* parse options */

if (argc==1) {print_help(0);}

for (i=1;i<argc;i++) {
      if (!strcmp(argv[i],"-mC")) {
            d("parse center");
            template_habak.center=MOD_CENTER;
      }
      else if (!strcmp(argv[i],"-mS")) {
            d("parse scale");
            template_habak.scale_art=MOD_SCALE;
      }
      else if (!strcmp(argv[i],"-ms")) {
            d("parse uglyscale");
            template_habak.scale_art=MOD_SCALE_NOPROP;
      }
      else if (!strcmp(argv[i],"-mf")) {
            d("parse font");
            if (argc!=i+1) {
            if (stat(argv[i+1],&file_info)) {
            printf("Couldn't access \"%s\"\n",argv[i+1]);
            exit(-1);
            }
            template_habak.fontpath=argv[++i];
            #ifdef DEBUG_HABAK
            printf("FONT: %s\n",template_habak.fontpath);
            #endif
            } else { error("-mf requires an argument!"); }
      }
      else if (!strcmp(argv[i],"-mh")) {
            d("parse font height");
            if (argc!=i+1) {
            i++;
            if (strtol(argv[i],NULL,10)==0) {
                  printf("Font size %s is invalid!\n",argv[i]);
                  exit(-1);
            }
            template_habak.fontsize=argv[i];
            #ifdef DEBUG_HABAK
            printf("FONT HEIGHT: %s\n",template_habak.fontsize);
            #endif
            } else { error("-mh requires an argument!"); }
      }
      else if (!strcmp(argv[i],"-mc")) {
            d("parse color");
            if (argc!=i+1) {
            fn=argv[i+1];
            template_habak.red=strtol(fn,NULL,10);
            fn=strchr(fn,',');
            if (fn==NULL) {printf("Wrong argument to -mc: %s\n",argv[i+1]); exit(-1); }
            template_habak.green=strtol(fn+1,NULL,10);
            fn=strchr(fn+1,',');
            if (fn==NULL) {printf("Wrong argument to -mc: %s\n",argv[i+1]); exit(-1); }
            template_habak.blue=strtol(fn+1,NULL,10);
            fn=strchr(fn+1,',');
            printf("Got color: %s\n",fn+1);
            if (fn==NULL) {printf("Wrong argument to -mc: %s\n",argv[i+1]); exit(-1); }
            template_habak.alpha=strtol(fn+1,NULL,10);
            i++;
            } else { error("-mc requires an argument!"); }
      }
      else if (!strcmp(argv[i],"-mp")) {
            d("parse position");
            d("\tmalloc fn1");
            if (argc!=i+1) {
            fn=argv[i+1];
            d("Splitting string...");
            if (fn[0]=='-') {template_habak.invx=1;} 
            else {template_habak.invx=0;}
            template_habak.x=strtol(fn,NULL,10);
            fn=strchr(fn,',');
            if (fn==NULL) {printf("Wrong argument to -mp: %s\n",argv[i+1]); exit(-1); }
            fn++;
            if (fn[0]=='-') {template_habak.invy=1;}
            else {template_habak.invy=0;}
            template_habak.y=strtol(fn,NULL,10);
#ifdef DEBUG_HABAK
            printf("X: %i\n",template_habak.x);
            printf("Y: %i\n",template_habak.y);
#endif
            template_habak.scale_art=0;
            template_habak.center=0;
            i++;
            } else { error("-mp requires an argument!"); }
      }
      else if (!strcmp(argv[i],"-hi")) {
            d("parse image");
            template_habak.type=IMAGE_HABAK;
            if ((argc!=i+1) && (argv[i+1][0]!='-')) {
            if (stat(argv[i+1],&file_info)) {
            printf("Couldn't access \"%s\"\n",argv[i+1]);
            exit(-1);
            }
            template_habak.file=argv[++i];
            }
            d("flushing image...");
            flush_habak();
            d("done.");
      }
      else if (!strcmp(argv[i],"-ht")) {
            d("parse text");
            template_habak.type=TEXT_HABAK;
#ifdef DEBUG_HABAK
            printf("Arg count: %i\n",argc);
            printf("Parsing arg: %i\n",i);
#endif
            if ((i+1!=argc) && (argv[i+1][0]!='-')) {
            template_habak.text=argv[++i];
            }
      d("flushing text...");
      flush_habak();
      d("done.");
      }
      else if (!strcmp(argv[i],"-hI")) {
            d("parse internal");
            template_habak.type=INTERNAL_HABAK;
            if ((i+1!=argc) && (argv[i+1][0]!='-')) {
            template_habak.internal_t=argv[++i];
            }
            d("flushing internal...");
            flush_habak();
            d("done.");
      }
      else if ((!strcmp(argv[i],"-h"))|| (!strcmp(argv[i],"--help"))) {
            print_help(0);
      }
      else {
            /* 
             * An unexpected argument. If it exists in the filesystem treat it
             * like an Image Habak
             */
            if (!stat(argv[i],&file_info)) {
            d("parse image");
            template_habak.type=IMAGE_HABAK;
            template_habak.file=argv[i];
            d("flushing image...");
            flush_habak();
            d("done.");
            }
            else {
            printf("Unexpected argument \"%s\"\n",argv[i]);
            exit(-1);
            }
      }
}

/* Dobra, czas na postprocessing */
current_list_item=first_list_item;

do {
      d("postprocess...");
/*
 * To upierdliwa robota, mamy teraz jednokierunkową listę zawierającą spis
 * struktur 'habak' do końcowego przetworzenia. Trzeba po kolei przejrzeć
 * każdą strukturę i zaktualizować niektóre pola.
 */
switch (current_list_item->data.type) {
      /* 
       * Polecę według typów, bo to od typu habaka zależy "sposób traktowania"
       */
      case IMAGE_HABAK:
      d("postprocess image");
#ifdef DEBUG_HABAK
      printf("Will need %i bytes.\n",strlen(current_list_item->data.file)+1);
#endif
      fn1=malloc(strlen(current_list_item->data.file)+1);
      d("\tmalloced fn1");
      strcpy(fn1,current_list_item->data.file);
      d("copied image path");
      /* Mam już kopię nazwy pliku w tymczasowej zmiennej fn1 */
      if (stat(fn1,&file_info)==-1) {
      printf("Couldn't access \"%s\"\n",fn1);
      exit(-1);
      }
      if (S_ISDIR(file_info.st_mode)) {
      d("The so-called 'Image' is a directory... going in.");
      fn=randomly_select_image(fn1);
      if (fn==NULL) {
            fprintf(stderr,"The randomizer wasn't able to find any images in %s\n",fn1);
            exit(-1);
      }
      d("Selected a random image");
      } else {fn=fn1;}
      d("Ready to load");
      if (!(current_list_item->data.image=imlib_load_image_immediately(fn))) {
      /* Błąd przy ładowaniu pliku */
      d("Error loading");
            fprintf(stderr,"File '%s' is not an image\n",fn);
            return 0;
      } else {
      d("File loaded correctly");
      imlib_context_set_image(current_list_item->data.image);
      current_list_item->data.width=current_list_item->data.orig_width=imlib_image_get_width();
      current_list_item->data.height=current_list_item->data.orig_height=imlib_image_get_height();
      }
      free(fn1);
      /* No i w tym momencie można założyć, że mamy załadowany poprawnie
       * plik. Co dalej? Hmm, warto sprawdzić, czy ma być skalowany.
       */
      if (current_list_item->data.scale_art) {
            if (current_list_item->data.scale_art==MOD_SCALE) {
            /* ładne skalowanie */
            xco=((double)scr->width/(double)current_list_item->data.orig_width);
            yco=((double)scr->height/(double)current_list_item->data.orig_height);
            if (xco > yco) {xco=yco;}
            if (xco < yco) {yco=xco;}
            current_list_item->data.width=current_list_item->data.orig_width*xco;
            current_list_item->data.height=current_list_item->data.orig_height*yco;
            current_list_item->data.x = (scr->width-current_list_item->data.width)/2;
            current_list_item->data.y = (scr->height-current_list_item->data.height)/2;
            } else {
            /* brzydkie skalowanie 
             * W sumie to mogłem je robić wcześniej, ale dorzucam je tutaj,
             * żeby inne post-procesowane modyfikatory nie czuły się urażone */
            current_list_item->data.width=scr->width;
            current_list_item->data.height=scr->height;
            current_list_item->data.x = 0;
            current_list_item->data.y = 0;
            }
      } else if (current_list_item->data.center) {
            /* Centrowanie */
            current_list_item->data.x = (scr->width-current_list_item->data.orig_width)/2;
            current_list_item->data.y = (scr->height-current_list_item->data.orig_height)/2;
      } else {
            /* No tutaj nie zostało już nic innego, jak pikselowato-dokładne
             * pozycjonowanie. W sumie to trzeba tylko odbić współrzędne
             * jeśli user podał ujemne koordynaty */
            if (current_list_item->data.invx)
            {current_list_item->data.x+=scr->width-current_list_item->data.width;}
            if (current_list_item->data.invy)
            {current_list_item->data.y+=scr->height-current_list_item->data.height;}
      }
      break;
      case TEXT_HABAK: 
      d("postprocess text");
      /* OK, postprocessing tekstu. Dosyć złożona sprawa :/ */
      if (stat(current_list_item->data.fontpath, &file_info)==-1) {
            /* brak pliku? */
            fprintf(stderr,"File '%s' not found\n",current_list_item->data.fontpath);
            exit(-1);
      } else {
            if (S_ISDIR(file_info.st_mode)) {
            d("The so-called 'Font' is a directory... going in.");
            fn=randomly_select_font(current_list_item->data.fontpath);
            if (fn==NULL) {
                  fprintf(stderr,"The randomizer wasn't able to find any fonts in %s\n",
                        current_list_item->data.fontpath);
                  exit(-1);
            }
            d("Selected a random font");
            current_list_item->data.fontpath=realloc(current_list_item->data.fontpath,strlen(fn)+1);
            strcpy(current_list_item->data.fontpath,fn);
            free(fn);
            }
      }
            
            fn=malloc(strlen(current_list_item->data.fontpath)+strlen(current_list_item->data.fontsize)+2);
            strcpy(fn,current_list_item->data.fontpath);
            fp=rindex(fn,'/');
            fp[0]='\0';
            /* Dobra, fp to teraz katalog z fontem */
            imlib_add_path_to_font_path(fn);
#ifdef DEBUG_HABAK
            printf("FONT PATH: %s\n",fn);
#endif
            fp[0]='/';
#ifdef DEBUG_HABAK
            printf("FONT: %s\n",fn);
#endif
            strcat(fn,"/");
            strcat(fn,current_list_item->data.fontsize);
#ifdef DEBUG_HABAK
            printf("FINAL FONT: %s\n",fn);
#endif
            /* OK, w tym oto momencie powinienem mieć już śliczną linię
             * gotową do załadowania */
      if (!(current_list_item->data.font=imlib_load_font(fn))) {
            fprintf(stderr, "Couldn't load font.\n");
            return 0;
      }
      free(fn);
      imlib_context_set_font(current_list_item->data.font);
      /* Panie i panowie, font załadowany :) */
      /* TODO: poprawka na wielolinijkowy tekst */
      imlib_get_text_advance(current_list_item->data.text,&current_list_item->data.width,&current_list_item->data.height);
      current_list_item->data.orig_width=current_list_item->data.width;
      current_list_item->data.orig_height=current_list_item->data.height;
      
      /* Tekstu się nie skaluje, ale można go pozycjonować lub
       * centrować...
       */
      if (current_list_item->data.center) {
            /* Centrowanie */
            current_list_item->data.x = (scr->width-current_list_item->data.orig_width)/2;
            current_list_item->data.y = (scr->height-current_list_item->data.orig_height)/2;
      } else {
            /* No tutaj nie zostało już nic innego, jak pikselowato-dokładne
             * pozycjonowanie. W sumie to trzeba tylko odbić współrzędne
             * jeśli user podał ujemne koordynaty */
            if (current_list_item->data.invx)
            {current_list_item->data.x+=scr->width-current_list_item->data.width;}
            if (current_list_item->data.invy)
            {current_list_item->data.y+=scr->height-current_list_item->data.height;}
      }
      /* TODO: Tutaj można walnąć jakąś sprytną wstawkę która zmieni
       pozycję (X,Y) następnego habaka na liście */
      break;
      
      case INTERNAL_HABAK:
      d("postprocess internal");
//    imlib_context_set_operation(IMLIB_OP_RESHADE);
      if (strncmp(current_list_item->data.internal_t,INTERNAL_HABAK_INTERLACE,3)==0) {
            /* INTERLACE typu 1 */
      current_list_item->data.x=0;
      current_list_item->data.y=0;
      current_list_item->data.image=imlib_create_image(scr->width,scr->height);
      current_list_item->data.width=current_list_item->data.orig_width=scr->width;
      current_list_item->data.height=current_list_item->data.orig_height=scr->height;
      imlib_context_set_image(current_list_item->data.image);
      imlib_image_set_has_alpha(1);
      imlib_context_set_color(current_list_item->data.red,current_list_item->data.green,current_list_item->data.blue,current_list_item->data.alpha);
      for (i=0;i<scr->height;i+=2) {
            imlib_image_draw_line(0,i,current_list_item->data.width,i,0);
      }
      /* OK, mamy gotowy obraz. Ponieważ jest to teraz tak naprawdę _obraz_, to
       * można zmienić jego typ na "IMAGE_HABAK"
       */
      current_list_item->data.type=IMAGE_HABAK;
      break;
      }
      if (strncmp(current_list_item->data.internal_t,INTERNAL_HABAK_INTERLACE_REVERSED,3)==0) {
      current_list_item->data.x=0;
      current_list_item->data.y=0;
      current_list_item->data.image=imlib_create_image(scr->width,scr->height);
      current_list_item->data.width=current_list_item->data.orig_width=scr->width;
      current_list_item->data.height=current_list_item->data.orig_height=scr->height;
      imlib_context_set_image(current_list_item->data.image);
      imlib_image_set_has_alpha(1);
      imlib_context_set_color(current_list_item->data.red,current_list_item->data.green,current_list_item->data.blue,current_list_item->data.alpha);
      for (i=1;i<scr->height;i+=2) {imlib_image_draw_line(0,i,current_list_item->data.width,i,0);}
      /* OK, mamy gotowy obraz. Ponieważ jest to teraz tak naprawdę _obraz_, to
       * można zmienić jego typ na "IMAGE_HABAK"
       */
      current_list_item->data.type=IMAGE_HABAK;
      }}
      
} while (next_habak());

/* OK, I guess everything is fine now. So fire up the Imlib machine... */
      d("create black image");
      workspace=imlib_create_image(scr->width,scr->height);
      imlib_context_set_image(workspace);
      imlib_context_set_anti_alias(1);
      imlib_context_set_dither(1);
      imlib_context_set_blend(1);

/* Should be down hill from here. I like this part, makes for a nice,
 * clean finish. Just the way I like them :) */
do {
      d("begin drawing");
switch (current_list_item->data.type) {   
      case TEXT_HABAK:
      d("draw text");
      imlib_context_set_color(current_list_item->data.red,current_list_item->data.green,current_list_item->data.blue,current_list_item->data.alpha);
      imlib_context_set_font(current_list_item->data.font);
      multxt=current_list_item->data.text;
      multy=current_list_item->data.y;
      while (multxt10=strchr(multxt,10)) {
            *multxt10=0;
            imlib_text_draw(current_list_item->data.x,multy,multxt);
            *multxt10=10;
            multxt=multxt10+1;
            /* TODO: poprawka - to nie jest rzeczywista wysokość tekstu */
            multy+=strtol(current_list_item->data.fontsize,NULL,10);
      }
      imlib_text_draw(current_list_item->data.x,multy,multxt);
      break;
//    case INTERNAL_HABAK:
//    break;
      case IMAGE_HABAK:
      d("draw image");
      imlib_blend_image_onto_image(current_list_item->data.image, 0, 0,0,current_list_item->data.orig_width,current_list_item->data.orig_height,current_list_item->data.x,current_list_item->data.y,current_list_item->data.width,current_list_item->data.height);
      break;
}

} while (next_habak());

      d("display everything");
dumpToScreen();
set_pixmap_property(p);


return 0;
}


Generated by  Doxygen 1.6.0   Back to index