/* -*-c-*- */
/* This module, and the entire FvwmSaveDesktop program, and the concept for
 * interfacing this module to the Window Manager, are all original work
 * by Robert Nation and Mr. Per Persson <pp@solace.mh.se>
 *
 * Copyright 1994, Robert Nation and Mr. Per Persson.
 *  No guarantees or warantees or anything
 * are provided or implied in any way whatsoever. Use this program at your
 * own risk. Permission to use this program for any purpose is given,
 * as long as the copyright is kept intact. */

/* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "libs/ftime.h"
#include <unistd.h>
#include <ctype.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>

#include "libs/Module.h"

#include "FvwmSave.h"

static ModuleArgs *module;
int fd[2];

struct list *list_root = NULL;

Display *dpy;                   /* which display are we talking to */
int ScreenWidth, ScreenHeight;
int screen;

long Vx, Vy;

/*
 *
 *  Procedure:
 *      main - start of module
 *
 */
int main(int argc, char **argv)
{
  char *display_name = NULL;

  module = ParseModuleArgs(argc,argv,0); /* don't accept an alias */
  if (module == NULL)
  {
    fprintf(stderr,"FvwmSave Version %s should only be executed by fvwm!\n",
            VERSION);
    exit(1);
  }

  /* Open the X display */
  if (!(dpy = XOpenDisplay(display_name)))
    {
      fprintf(stderr,"%s: can't open display %s", module->name,
	      XDisplayName(display_name));
      exit (1);
    }
  screen= DefaultScreen(dpy);
  ScreenHeight = DisplayHeight(dpy,screen);
  ScreenWidth = DisplayWidth(dpy,screen);

  /* We should exit if our fvwm pipes die */
  signal (SIGPIPE, DeadPipe);

  fd[0] = module->to_fvwm;
  fd[1] = module->from_fvwm;

  /* Create a list of all windows */
  /* Request a list of all windows,
   * wait for ConfigureWindow packets */
  SendInfo(fd,"Send_WindowList",0);

  /* tell fvwm we're running */
  SendFinishedStartupNotification(fd);

  Loop(fd);
  return 0;
}


/*
 *
 *  Procedure:
 *      Loop - wait for data to process
 *
 */
void Loop(int *fd)
{
    while(1) {
	FvwmPacket* packet = ReadFvwmPacket(fd[1]);
	if ( packet == NULL )
	    exit(0);
	else
	    process_message( packet->type, packet->body );
    }
}


/*
 *
 *  Procedure:
 *      Process message - examines packet types, and takes appropriate action
 *
 */
void process_message(unsigned long type,unsigned long *body)
{
  switch(type)
    {
    case M_CONFIGURE_WINDOW:
      if(!find_window(body[0]))
	add_window(body[0],body);
      break;
    case M_NEW_PAGE:
      list_new_page(body);
      break;
    case M_END_WINDOWLIST:
      do_save();
      break;
    default:
      break;
    }
}





/*
 *
 *  Procedure:
 *      find_window - find a window in the current window list
 *
 */
struct list *find_window(unsigned long id)
{
  struct list *l;

  if(list_root == NULL)
    return NULL;

  for(l = list_root; l!= NULL; l= l->next)
    {
      if(l->id == id)
	return l;
    }
  return NULL;
}



/*
 *
 *  Procedure:
 *      add_window - add a new window in the current window list
 *
 */
void add_window(unsigned long new_win, unsigned long *body)
{
  struct list *t;
  struct ConfigWinPacket *cfgpacket = (void *)body;

  if(new_win == 0)
    return;

  t = (struct list *)safemalloc(sizeof(struct list));
  t->id = new_win;
  t->next = list_root;
  t->frame_height = cfgpacket->frame_height;
  t->frame_width = cfgpacket->frame_width;
  t->base_width = cfgpacket->hints_base_width;
  t->base_height = cfgpacket->hints_base_height;
  t->width_inc  = cfgpacket->hints_width_inc;
  t->height_inc  = cfgpacket->hints_height_inc;
  t->frame_x  = cfgpacket->frame_x;
  t->frame_y  = cfgpacket->frame_y;
  t->title_height  = cfgpacket->title_height;
  t->boundary_width  = cfgpacket->border_width;
  memcpy(&(t->flags), &(cfgpacket->flags), sizeof(t->flags));
  t->gravity = cfgpacket->hints_win_gravity;
  list_root = t;
}



/*
 *
 *  Procedure:
 *      list_new_page - capture new-page info
 *
 */
void list_new_page(unsigned long *body)
{
  Vx = (long)body[0];
  Vy = (long)body[1];
}
/*
 *
 *  Procedure:
 *      SIGPIPE handler - SIGPIPE means fvwm is dying
 *
 */
RETSIGTYPE DeadPipe(int nonsense)
{
  exit(0);
  SIGNAL_RETURN;
}


/*
 *
 *  Procedure:
 *      writes a command line argument to file "out"
 *      checks for qoutes and stuff
 *
 */
void write_string(FILE *out, char *line)
{
  int len,space = 0, qoute = 0,i;

  len = strlen(line);

  for(i=0;i<len;i++)
    {
      if(isspace((unsigned char)(line[i])))
	space = 1;
      if(line[i]=='\"')
	qoute = 1;
    }
  if(space == 1)
    fprintf(out,"\"");
  if(qoute == 0)
    fprintf(out,"%s",line);
  else
    {
      for(i=0;i<len;i++)
	{
	  if(line[i]=='\"')
	    fprintf(out,"\\\"");
	  else
	    fprintf(out,"%c",line[i]);
	}
    }
  if(space == 1)
    fprintf(out,"\"");
  fprintf(out," ");

}



/*
 *
 *  Procedure:
 *      checks to see if we are supposed to take some action now,
 *      finds time for next action to be performed.
 *
 */
void do_save(void)
{
  struct list *t;
  char tname[200],loc[30];
  FILE *out;
  char **command_list;
  int dwidth,dheight,xtermline = 0;
  int x1,x2,y1,y2,i,command_count;
  long tVx, tVy;

  sprintf(tname, "%s/new.xinitrc", getenv( "HOME" ) );
  out = fopen( tname, "w+" );
  for (t = list_root; t != NULL; t = t->next)
  {
    tname[0]=0;

    x1 = t->frame_x;
    x2 = ScreenWidth - x1 - t->frame_width - 2;
    if(x2 < 0)
      x2 = 0;
    y1 = t->frame_y;
    y2 = ScreenHeight - y1 -  t->frame_height - 2;
    if(y2 < 0)
      y2 = 0;
    dheight = t->frame_height - t->title_height - 2*t->boundary_width;
    dwidth = t->frame_width - 2*t->boundary_width;
    dwidth -= t->base_width ;
    dheight -= t->base_height ;
    dwidth /= t->width_inc;
    dheight /= t->height_inc;

    if (IS_STICKY_ACROSS_PAGES(t))
    {
      tVx = 0;
      tVy = 0;
    }
    else
    {
      tVx = Vx;
      tVy = Vy;
    }
    sprintf(tname,"%dx%d",dwidth,dheight);
    if ((t->gravity == EastGravity) ||
	(t->gravity == NorthEastGravity) ||
	(t->gravity == SouthEastGravity))
      sprintf(loc,"-%d",x2);
    else
      sprintf(loc,"+%d",x1+(int)tVx);
    strcat(tname, loc);

    if((t->gravity == SouthGravity)||
       (t->gravity == SouthEastGravity)||
       (t->gravity == SouthWestGravity))
      sprintf(loc,"-%d",y2);
    else
      sprintf(loc,"+%d",y1+(int)tVy);
    strcat(tname, loc);

    if ( XGetCommand( dpy, t->id, &command_list, &command_count ) )
    {
      for (i=0; i < command_count; i++)
      {
	if ( strncmp( "-geo", command_list[i], 4) == 0)
	{
	  i++;
	  continue;
	}
	if ( strncmp( "-ic", command_list[i], 3) == 0)
	  continue;
	if ( strncmp( "-display", command_list[i], 8) == 0)
	{
	  i++;
	  continue;
	}
	write_string(out,command_list[i]);
	if(strstr(command_list[i], "xterm"))
	{
	  fprintf( out, "-geometry %s ", tname );
	  if (IS_ICONIFIED(t))
	    fprintf(out, "-ic ");
	  xtermline = 1;
	}
      }
      if ( command_count > 0 )
      {
	if ( xtermline == 0 )
	{
	  if (IS_ICONIFIED(t))
	    fprintf(out, "-ic ");
	  fprintf( out, "-geometry %s &\n", tname );
	}
	else
	{
	  fprintf( out, "&\n");
	}
      }
      XFreeStringList( command_list );
      xtermline = 0;
    }
  }
  fprintf(out, "fvwm\n");
  fclose( out );
  exit(0);
}

