
/* wmbackground.c
 * Copyright(c) 2012, by Cezary M. Kruk (c.kruk@bigfoot.com)
 * Copyright(c) 1999, by Aldrin Martoq A. (amartoq@cec.uchile.cl)
 *
 * This program is distributed under the GPL License, see "COPYING" file.
 *
 * This code is based and uses partly of the wmgeneral code found in the
 * wmmon.app by Martijn Pieterse (pieterse@xs4all.nl) and Antoine Nulle
 * (warp@xs4all.nl), which is based based on wmppp/wmifs, which is based on
 * pppstats and asclock.
 *
 */

#include "wmbackground.h"

#include "wmbackground.xpm"
#include "wmbackground-mask.xbm"

#define WMBACKGROUND_VERSION "1.0.1"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glob.h>

/* Global variables */
XImage *pixmap_copy;
unsigned long myfore1;
unsigned long myfore2;

char command1[1024];
char command2[1024];
char current[1024];
char *the_current;
char filename[1024];
char background[1024];

char home[1024];
char directory[1024];

int period = 0;
int default_period = 60;
int period_backup = 0;
int mode = 0;
int count = 0;
int backward = 0;

int main(int argc, char *argv[])
  {
	init_stuff(argc, argv);
	while(main_loop())
	  ;

	return 0;
  }

void add_backgrounds(char *filename)
  {	
	DIR *mydir;
	FILE *myfile;

	mydir = opendir(home);
	if (mydir == NULL)
	  {	if (errno != ENOENT)
		  {	perror("wmbackground (opendir)");  }

		printf("Creating `%s' directory.\n\n", home);
		if (mkdir(home, 0755) < 0)
		  {	fprintf(stderr, "Can't create the directory.\n");
			perror("wmbackground (mkdir)");
			exit(1);
		  }
	  }
	closedir(mydir);

	default_image();

	myfile = fopen(filename, "w");
	if (myfile == NULL)
	  {	perror("fopen");
		fprintf(stderr, "\nCan't write the profile file `%s'.\n\n", filename);
		exit(1);
	  }
	fclose(myfile);

	sprintf(current, "nice -n 19 montage \"%s.png\" -background gray -colors 256 -geometry 54x54 -size 54x54 -unsharp 0.125 +adjoin '%s.xpm.gz'", filename, filename);
	fflush(stdout);

	if (system(current) != 0)
	  {
		printf("\nThere's no montage program from ImageMagick package in the PATH.\n\n");
		exit(1);
	  }

	current[0] = 0;
	get_next_background(current);
  }

int exists(const char *fname)
{
    FILE *file;
    if ((file = fopen(fname, "r")))
    {
        fclose(file);
        return 1;
    }
    add_backgrounds(the_current);
    return 0;
}

int globbing( int argc, char *argv[] )
  {
	/* get the user's home */
	sprintf(home,"%s/.wmbackground",getenv("HOME"));

	static int lenght;
	static char *defExt = ".png";
	static int mylenght;

	mylenght = strlen(defExt);

	int no_dir;
	DIR *mydir;

	glob_t data;

	switch( glob("~/.wmbackground/*.png", GLOB_TILDE, NULL, &data ) )
	{
	case 0:
	    break;
	case GLOB_NOMATCH:
	    perror("wmbackground (opendir)");
	    break;
	default:
	    break;
	}

	no_dir = 0;

	mydir = opendir(home);
	if (mydir == NULL)
	  {
		no_dir = 1;
	  }
	closedir(mydir);

	int i, j;

	    for(i=0; i<data.gl_pathc; i++)
	    {
		j = i;

		the_current = data.gl_pathv[i];
		lenght = strlen(the_current);
		the_current[lenght - mylenght] = 0;

		sprintf(filename,"%s.xpm.gz",the_current);

		exists(filename);
	    }

	globfree( &data );
	return 0;
  }

void init_stuff(int argc, char **argv)
  {
	/* get the user's home */
	sprintf(home,"%s/.wmbackground",getenv("HOME"));

	if (argc >= 2)
	  {	
	  	if (strcmp(argv[1], "-t") == 0)
		  {	period = atoi(argv[2]);  }
	  	if (strcmp(argv[1], "-h") == 0)
		  {	show_usage();  }
	  }

	openXwindow(argc, argv, wmbackground_xpm, wmbackground_mask_bits,
		wmbackground_mask_width, wmbackground_mask_height);

	/* We get this to put the marco after */
	pixmap_copy = XGetImage(display, wmgen.pixmap, 0, 0, 128, 64, ~0,
		ZPixmap);
	myfore1 = XGetPixel(pixmap_copy, 127, 0);
	myfore2 = XGetPixel(pixmap_copy, 126, 0);

	default_image();

	current[0] = 0;
	get_next_background(current);

  }

int main_loop()
  {	static XEvent	Event;

	waitpid(0, NULL, WNOHANG);

	globbing(0, 0);

	while (XPending(display) && (count <= period))
	  {	XNextEvent(display, &Event);
		switch (Event.type)
		  {	case Expose:
				RedrawWindowXY(0, 0);
				break;

			case DestroyNotify:
				XCloseDisplay(display);
				return 0;
				break;

			case ButtonRelease:
				switch(Event.xbutton.button)
				  {	case 1:
						myexecCommand(command1);
						break;

					case 2:
						myexecCommand(command2);
						break;

					case 3:
						if (backward == 0) {
							get_next_background(current);
						}
						else if (backward == 1) {
							get_prev_background(current);
						}
						break;
				  }

			case KeyPress:
				switch (Event.xkey.keycode) {
				case 22: /* Backspace */
					if (backward == 0) {
						count = 0;
						backward = 1;
					}
					else if (backward == 1) {
						count = 0;
						backward = 0;
					}
					break;
				case 36: /* Enter */
					if (mode == 0) {
						if (period == 0) {
							period_backup = 0;
							period = default_period;
						} else {
							period_backup = period;
							period = 0;
						}
						count = 0;
						mode = 1;
					}
					else if (mode == 1) {
						period = period_backup;
						period_backup = 0;
						count = 0;
						mode = 0;
					}
					break;
				}

			case EnterNotify:
				XSetInputFocus(display, PointerRoot, RevertToParent, CurrentTime);
				break;

			case LeaveNotify:
				XSetInputFocus(display, PointerRoot, RevertToParent, CurrentTime);
				break;
		  }
	  }

	usleep(1000000);

	if (period != 0)
	  {
	    count = count + 1;
	    if (count >= period)
	      {
		if (backward == 0) {
			get_next_background(current);
		}
		else if (backward == 1) {
			get_prev_background(current);
		}
		count = 0;
	      }
	  }

	return 1;
  }

void poner_marco()
  {	int i, j;
	unsigned long c;

	for (i=0; i<64; i++)
	  {	for (j = 0; j<64; j++)
		  {	c = XGetPixel(pixmap_copy, i+64, j);
			if (c == myfore1 || c == myfore2)
			  {	c = XGetPixel(pixmap_copy, i+64, j);
				XSetForeground(display, NormalGC, c);
				XDrawPoint(display, wmgen.pixmap, NormalGC, i, j);
			  }
		  }
	  }
  }

void default_image()
  {
	copyXPMArea(64, 0, 64, 64, 0, 0);
	RedrawWindowXY(0,0);
  }

void get_prev_background(char *current)
  {
	struct dirent **namelist;
	int m, n, i, mark;
	DIR *mydir;

	command1[0] = 0;
	command2[0] = 0;

	mydir = opendir(home);
	if (mydir == NULL)
	  {	if (errno != ENOENT)
		  {	perror("wmbackground (opendir)");  }
		default_image();
		return;
	  }
	closedir(mydir);

	n = scandir(home, &namelist, myselect, alphasort);
	m = n;

	if (n < 0)
	  {	perror("wmbackground (scandir)");
		default_image();
		return;
	  }

	if (n == 0)
	  {	default_image();
		globbing(0, 0);
		current[0] = 0;
		get_prev_background(current);
		return;
	  }

	if (current == NULL)
	  {	load_background(namelist[0]->d_name);
	  }
	else
	  {	mark = 0;
		n = n - 1;
		for (i=n; i>-1; i--)
		  {
			if (strcmp(namelist[i]->d_name, current) == 0)
			  {	mark = i - 1;  }
			if (mark == -1)
			  {	mark = m - 1;  }
		  }
		load_background(namelist[mark]->d_name);
	  }
	while (n--)
	  {	free(namelist[n]);  }
  }

void get_next_background(char *current)
  {
	struct dirent **namelist;
	int n, i, mark;
	DIR *mydir;

	command1[0] = 0;
	command2[0] = 0;

	mydir = opendir(home);
	if (mydir == NULL)
	  {	if (errno != ENOENT)
		  {	perror("wmbackground (opendir)");  }
		default_image();
		return;
	  }
	closedir(mydir);

	n = scandir(home, &namelist, myselect, alphasort);

	if (n < 0)
	  {	perror("wmbackground (scandir)");
		default_image();
		return;
	  }

	if (n == 0)
	  {	default_image();
		globbing(0, 0);
		current[0] = 0;
		get_next_background(current);
		return;
	  }

	if (current == NULL)
	  {	load_background(namelist[0]->d_name);
	  }
	else
	  {	mark = 0 ;
		for (i=0; i<n; i++)
		  {	
		  if (strcmp(namelist[i]->d_name, current) == 0)
			  {	mark = i + 1;  }
		  }
		mark = (mark == n ? 0 : mark);
		load_background(namelist[mark]->d_name);
	  }
	while (n--)
	  {	free(namelist[n]);  }
  }

int myselect(const struct dirent *d)
  {	const char *name = d->d_name;
	static int lenght;
	static char *defExt = ".xpm.gz";
	static int mylenght;

	lenght = strlen(name);
	mylenght = strlen(defExt);

	if (lenght < (mylenght + 1) || name[0] == '.' || 
		strcmp(&(name[lenght - mylenght]), defExt) != 0 )
	  {	return 0;  }

	return 1;
  }

void load_background(char *name)
  {	Pixmap mypixmap;
	int status;
	static int lenght;
	static char *defExt = ".xpm.gz";
	static int mylenght;
	FILE *myfile;
	XpmAttributes xpmAttributes;
	char command[1024];

	mylenght = strlen(defExt);

	sprintf(current, "%s/%s", home, name);

	lenght = strlen(current);
	current[lenght - mylenght] = 0;

	sprintf(background,"%s.png",current);
	sprintf(command,"wmsetbg %s",background);

	myfile = fopen(current, "r");
	if (myfile != NULL)
	  {	if (fgets(command1, 1024, myfile) != NULL)
		  {	int l = strlen(command1);
			if (command1[l-1] == '\n')
			  {	command1[l-1] = 0;  }

			if (fgets(command2, 1024, myfile) != NULL)
			  {	l = strlen(command2);

				if (command2[l-1] == '\n')
				  {	command2[l-1] = 0;  }
			  }
		  }
		fclose(myfile);
	  }
	
	current[lenght - mylenght] = '.';

	xpmAttributes.valuemask = XpmCloseness;
	xpmAttributes.closeness = 65536;

	status = XpmReadFileToPixmap(display, wmgen.pixmap, current, &mypixmap,
		0, &xpmAttributes);
	strcpy(current, name);
	if (status != XpmSuccess)
	  {	fprintf(stderr, "wmbackground (XpmError): %s\n",
			XpmGetErrorString(status));
		default_image();
		return;
	  }
	XCopyArea(display, mypixmap, wmgen.pixmap, NormalGC, 0, 0, 54, 54, 5,
		5);

	XFreePixmap(display, mypixmap);
	XpmFreeAttributes(&xpmAttributes);

	poner_marco();
	RedrawWindowXY(0, 0);
	myexecCommand(command);
  }

void myexecCommand(char *command)
  {
	if (command[0] != 0)
	  {	execCommand(command);  }
  }

void show_usage()
  {
	printf("wmbackground %s: Copyright (C) 2012 by Cezary M. Kruk (c.kruk@bigfoot.com)", WMBACKGROUND_VERSION);

	printf("\n\nCOMMAND:\n  wmbackground : starts wmbackground using ~/.wmbackground directory\n\nOPTIONS:\n  -t <n>       : changes a background every n seconds\n  -h           : this help\n\nSHORTCUTS:\n  Backspace    : switches the order of the backgrounds back and forth\n  Enter        : switches the manual and the slide show modes on the fly\n");

	exit(0);
  }

