//////////////////////////////////////////////
// NovaWM - Nova Window Manager for X11     //
//////////////////////////////////////////////
// By: Tim Walters                          //
//////////////////////////////////////////////
// Copyright (C) 2001-2002 Tim Walters      //
//////////////////////////////////////////////

////////////////////////////////////////////////////////////////
//This code is released under the terms of the GNU GPL. Refer //
//to the license file included with this source code.         //
////////////////////////////////////////////////////////////////

#include "novawm.h"

void
NovaWM::CreateBar ()
{
  XSetWindowAttributes attributes;

  if (cfg.disableBar == true)
    return;

  attributes.override_redirect = true;
  attributes.background_pixel = mainPixel;
  attributes.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask;

  bar_x = (XDisplayWidth (display, screen) / 2) - 187;

  NovaBar = XCreateWindow (display, root, bar_x, 0, 374, NOVABAR_HEIGHT,	//18,
			   0, DefaultDepth (display, screen),
			   CopyFromParent, DefaultVisual (display,
							  screen),
			   CWBackPixel | CWEventMask |
			   CWOverrideRedirect, &attributes);

  nbClock = XCreateWindow (display, NovaBar, 318, 3, 52, 12, 0,
			   DefaultDepth (display, screen),
			   CopyFromParent, DefaultVisual (display,
							  screen),
			   CWBackPixel, &attributes);

  nbButton = XCreateWindow (display, NovaBar, 3, 3, 13, 12,
			    0, DefaultDepth (display, screen),
			    CopyFromParent, DefaultVisual (display,
							   screen),
			    CWBackPixel | CWEventMask |
			    CWOverrideRedirect, &attributes);

  nbCurWin = XCreateWindow (display, NovaBar, 18, 3, 280, 13,
			    0, DefaultDepth (display, screen),
			    CopyFromParent, DefaultVisual (display,
							   screen),
			    CWBackPixel | CWEventMask |
			    CWOverrideRedirect, &attributes);

  nbListButton = XCreateWindow (display, NovaBar, 298, 3, 12, 13,
				0, DefaultDepth (display, screen),
				CopyFromParent, DefaultVisual (display,
							       screen),
				CWBackPixel | CWEventMask |
				CWOverrideRedirect, &attributes);

  XMapWindow (display, NovaBar);
  XMapWindow (display, nbClock);
  XMapWindow (display, nbButton);
  XMapWindow (display, nbCurWin);
  XMapWindow (display, nbListButton);

  nSeconds = 0;
}

void
NovaWM::UpdateClock ()
{
  if (cfg.disableBar == true)
    return;

  XSetFont (display, novawm_gc, nbFont->fid);

  XClearWindow (display, nbClock);

  char *curTime = GetTime (cfg.clockFormat);

  XDrawString (display, nbClock, novawm_gc, 4, 10, curTime, strlen (curTime));

  free (curTime);

  XSetFont (display, novawm_gc, novawmFont->fid);

  //Draw Clock Border
  XSetForeground (display, novawm_gc, WhitePixel (display, screen));

  XDrawLine (display, nbClock, novawm_gc, 1, 11, 50, 11);
  XDrawLine (display, nbClock, novawm_gc, 50, 0, 50, 12);

  XSetForeground (display, novawm_gc, BlackPixel (display, screen));

  XDrawLine (display, nbClock, novawm_gc, 0, 0, 50, 0);
  XDrawLine (display, nbClock, novawm_gc, 0, 0, 0, 12);

  XSetForeground (display, novawm_gc, WhitePixel (display, screen));

}

void
NovaWM::DrawBar ()
{
  char *cwTitle;
  int dummy;
  XCharStruct chStrct;

  UpdateClock ();

  events.DrawUp (NovaBar);

  XClearWindow (display, nbCurWin);

  events.DrawUp (nbCurWin);
  if (events.downWindow != nbListButton)
    events.DrawUp (nbListButton);

  if (winmgr.focusWindow)
    cwTitle = winmgr.focusWindow->title;
  else
    cwTitle = "---";

  XSetFont (display, novawm_gc, nbFont->fid);

  XTextExtents (nbFont, cwTitle, strlen (cwTitle), &dummy, &dummy,
		&dummy, &chStrct);

  XDrawString (display, nbCurWin, novawm_gc, 140 - (chStrct.width / 2),
	       10, cwTitle, strlen (cwTitle));

  XSetForeground (display, novawm_gc, WhitePixel (display, screen));

  XSetFont (display, novawm_gc, novawmFont->fid);

  XClearWindow (display, nbButton);
  XDrawString (display, nbButton, novawm_gc, 3, 13, "*", 1);

  DrawArrow (nbListButton);
}

//Draw a arrow pointing down
void
NovaWM::DrawArrow (Window xWindow)
{

  XDrawLine (display, xWindow, novawm_gc, 3, 3, 9, 3);
  XDrawLine (display, xWindow, novawm_gc, 3, 3, 5, 10);
  XDrawLine (display, xWindow, novawm_gc, 8, 3, 5, 10);
  XDrawLine (display, xWindow, novawm_gc, 4, 3, 5, 10);
  XDrawLine (display, xWindow, novawm_gc, 5, 3, 5, 10);
  XDrawLine (display, xWindow, novawm_gc, 6, 3, 5, 10);
  XDrawLine (display, xWindow, novawm_gc, 7, 3, 5, 10);

}

//Draw a arrow pointing up
void
NovaWM::DrawUpArrow (Window xWindow)
{

  XDrawLine (display, xWindow, novawm_gc, 3, 10, 9, 10);
  XDrawLine (display, xWindow, novawm_gc, 3, 10, 5, 3);
  XDrawLine (display, xWindow, novawm_gc, 8, 10, 5, 3);
  XDrawLine (display, xWindow, novawm_gc, 4, 10, 5, 3);
  XDrawLine (display, xWindow, novawm_gc, 5, 10, 5, 3);
  XDrawLine (display, xWindow, novawm_gc, 6, 10, 5, 3);
  XDrawLine (display, xWindow, novawm_gc, 7, 10, 5, 3);

}

//Scrollbar concept: The bar size is the percentage viewable,
//each unit is one.
void
NovaWM::CreateWinList ()
{
  int width = 292;
  int height = 320;

  XSetWindowAttributes attributes;

  attributes.background_pixel = mainPixel;
  attributes.event_mask =
    ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask;

  nbWinList =
    XCreateWindow (display, root, bar_x + 17, 20, width, height,
		   0, DefaultDepth (display, screen),
		   CopyFromParent, DefaultVisual (display,
						  screen),
		   CWBackPixel | CWEventMask, &attributes);

  nbWLstScrllBar =
    XCreateWindow (display, nbWinList, width - 24, 5, 16,
		   height - 12, 0, DefaultDepth (display, screen),
		   CopyFromParent, DefaultVisual (display,
						  screen),
		   CWBackPixel | CWEventMask, &attributes);

  nbWLstScrllUp =
    XCreateWindow (display, nbWLstScrllBar, 2, 2, 12,
		   14, 0, DefaultDepth (display, screen),
		   CopyFromParent, DefaultVisual (display,
						  screen),
		   CWBackPixel | CWEventMask, &attributes);

  nbWLstScrllDwn =
    XCreateWindow (display, nbWLstScrllBar, 2, height - 28, 12,
		   14, 0, DefaultDepth (display, screen),
		   CopyFromParent, DefaultVisual (display,
						  screen),
		   CWBackPixel | CWEventMask, &attributes);

  attributes.background_pixel = BlackPixel (display, screen);

  nbWLstItemWin =
    XCreateWindow (display, nbWinList, 5, 4, width - 30,
		   height - 10, 0, DefaultDepth (display, screen),
		   CopyFromParent, DefaultVisual (display,
						  screen),
		   CWBackPixel | CWEventMask, &attributes);

  XMapWindow (display, nbWinList);
  XMapWindow (display, nbWLstItemWin);
  XMapWindow (display, nbWLstScrllBar);
  XMapWindow (display, nbWLstScrllDwn);
  XMapWindow (display, nbWLstScrllUp);

  topItem = 0;

  DrawWinList ();
}

void
NovaWM::List_Scroll (int units)
{
  if ((topItem + units < 0) || (topItem + units >= lstItems))
    return;

  topItem += units;

#ifdef DEBUG
  printf ("DEBUG: List_Scroll(%d)\n", units);
#endif

  DrawWinList ();
}

void
NovaWM::DrawWinList ()
{

  XClearWindow (display, nbWLstItemWin);

  events.DrawUp (nbWLstScrllUp);
  events.DrawUp (nbWLstScrllDwn);
  events.DrawUp (nbWinList);
  events.DrawDown (nbWLstScrllBar);
  events.DrawDown (nbWLstItemWin);
  DrawArrow (nbWLstScrllDwn);
  DrawUpArrow (nbWLstScrllUp);

  lstItems = 0;
  selItem = -1;

//      for (Novawm_Window * cWindow = winmgr.topWindow;
//           cWindow; cWindow = cWindow->next)

  for (list < Novawm_Window * >::const_iterator i =
       winmgr.novawm_window_List.begin ();
       i != winmgr.novawm_window_List.end (); ++i)
    {
      if ((*i)->isTransient == false)
	{
	  XDrawString (display, nbWLstItemWin, novawm_gc, 5,
		       ((lstItems - topItem) * 15) + 14,
		       (*i)->title, strlen ((*i)->title));
	  lstItems++;
	}
    }
}

void
NovaWM::HighlightListItem (int cY)
{
//      DrawWinList ();

  if ((selItem >= 0) && (selItem <= lstItems))
    {

      //First erase previous inverted selection
      XSetFunction (display, novawm_gc, GXinvert);

      XFillRectangle (display, nbWLstItemWin, novawm_gc, 0,
		      selItem * 15, 282, 19);

      XSetFunction (display, novawm_gc, GXcopy);

    }

  int selection = (cY - 4) / 15;

  if (selection >= lstItems)
    {
      //selItem = -1;
      return;
    }

  selItem = selection;

  XSetForeground (display, novawm_gc, WhitePixel (display, screen));

  XSetFunction (display, novawm_gc, GXinvert);

  XFillRectangle (display, nbWLstItemWin, novawm_gc, 0, selItem * 15,
		  282, 19);

  XSetFunction (display, novawm_gc, GXcopy);

}

void
NovaWM::CreateNovaMenu ()
{
}

void
NovaWM::DestroyWinList ()
{
  lstItems = 0;
  selItem = -1;

  XDestroyWindow (display, nbWLstScrllUp);
  XDestroyWindow (display, nbWLstScrllDwn);
  XDestroyWindow (display, nbWLstScrllBar);
  XDestroyWindow (display, nbWLstItemWin);
  XDestroyWindow (display, nbWinList);
}

void
NovaWM::DestroyBar ()
{
  if (cfg.disableBar == true)
    return;

  XDestroyWindow (display, nbClock);
  XDestroyWindow (display, nbListButton);
  XDestroyWindow (display, nbCurWin);
  XDestroyWindow (display, nbButton);
  XDestroyWindow (display, NovaBar);

  XFreeFont (display, nbFont);
}

void
NovaWM::novaMenu_Click (int item)
{
  if ((item > cfg.itemExec.size () + 3) || (item < 0))
    return;

  if (item == cfg.itemExec.size () + 1)
    {
      Restart ();
      return;
    }
  if (item == cfg.itemExec.size () + 2)
    {
      Shutdown ();
      return;
    }

  Run ((char *) cfg.itemExec[item].c_str ());

}

//Check if the time has changed to see if it needs to be updated
void
NovaWM::CheckClock ()
{
  time_t tmp = time (NULL);
  struct tm *ptm = 0;

  double SecDiff = difftime (tmp, oldTime);

  //Time to update the clock
  if (SecDiff >= nSeconds)
    {
      UpdateClock ();

      oldTime = tmp;

      ptm = localtime (&tmp);
      nSeconds = 60 - ptm->tm_sec;
    }

}

char *
NovaWM::GetTime (int format)
{
  char *pTime;
  char *s = (char *) malloc (10);
  struct tm *ptm = 0;
  time_t tmp = time (NULL);
  ptm = localtime (&tmp);

  if (format == 1)
    {
      if (!strftime (s, 10, "%l:%M %p", ptm))
	return "Error";
      pTime = s;
    }
  else
    {
      if (!strftime (s, 10, "%H:%M", ptm))
	return "Error";
      pTime = s;
    }
  return pTime;
}


syntax highlighted by Code2HTML, v. 0.9.1