//-*-c++-*-
// -------------------------------------------
// RCS data:
// $Date: 2003/07/04 10:12:01 $
// $Revision: 1.3 $
// $Source: /cvsroot/miwm/miwm/miwm/wspace.cc,v $
// $Id: wspace.cc,v 1.3 2003/07/04 10:12:01 sgbeal Exp $
// $RCSfile: wspace.cc,v $
// -------------------------------------------
// Copyright by Ben Paul Wise.
// -------------------------------------------
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
// -------------------------------------------
// this defines the functions for workspace-related
// manipulations
// -------------------------------------------

#include "miwm.h"
#include "ws.h"
#include "miwm_framework.h"
#include "EStringList.h"

// -------------------------------------------

void
WindowManager::setupWS() {

        numWorkSpaces = 0;
        allWorkSpaces = (WorkSpace**) malloc (maxNumWorkSpaces * sizeof (WorkSpace));
        previewWSP = 0;
        previewedWorkSpace = NULL; // and likely to stay that way
  
        std::string spacenames = miwm::config().getString( "workspace_names", "One Two Three Four Five Six" );
        EStringList list = EStringList::tokenize( spacenames );
        std::string wsname;
        while( true )
        {
                wsname = list.shift();
                if( wsname.empty() ) break;
                addWorkSpace( wsname.c_str() );
        }
  return;
}


void
WindowManager::addWorkSpace(const char* wsName) {

  if (numWorkSpaces < maxNumWorkSpaces) {
  WorkSpace* ws = new WorkSpace(wsName);
  allWorkSpaces[numWorkSpaces] = ws;
  numWorkSpaces = numWorkSpaces + 1;
  if (1 == numWorkSpaces)
    workSpace = ws;
  }
  else {
    cout << "Maximum number of workspaces ("<<maxNumWorkSpaces<<") reached." << endl;
    cout << "Therefore, workspace " << wsName<<" will not be added"<<endl;
    cout << flush;
  }
  return;
}

// -------------------------------------------

// I defocus everything right before moving it off screen, for two reasons.
// First: if I did not, things that were in focus but are now
// offscreen get redrawn (with defocused border) when I set focus in
// the new workspace.
// Second: it prevents things like offscreen-xterms from accidentally
// getting keyboard input, doing deletes in the wrong directory, etc.

void 
WindowManager::changeWorkSpace(WorkSpace* ws1, WorkSpace* ws2) {
  Node* cND = NULL;
  Client* c = NULL;
  assert (NULL != ws1);
  assert (NULL != ws2);
  if (ws1 == ws2)
    return;

  for (cND = allClients->first; cND != NULL; cND = allClients->nextNode(cND)) {
    c = ((Client*) cND->data);

    // if this client is NULL, we are in deep doo doo
    assert (NULL != c);


    if (c->workSpace == ws1)  {
      // I marked the following 'if' as suspicious,
      // but now I don't recall why
      if (False == c->hidden)
	if (c->sticky == 0)  {
	  if (c == current) {
	    setactive(current , 0 , 0L); 
	    current = NULL;
	  }
	  innerSendClienttoWS(c, 0); // hide it
	}
	else { // c->sticky == 1
	  c->workSpace = ws2;
	}
    }

    if (c->workSpace == ws2)  {
      if (c->sticky == 0)  {
 	if (False == c->hidden)
	  innerSendClienttoWS(c, 1);  // actually show it
      }
      else  { 
	// do nothing: it is sticky and already in this WS
      }
    }

  }
  workSpace = ws2;
  focusOn(NULL); // arrive defocused
  return;
}

void 
WindowManager::sendClientToWorkSpace(Client* client, WorkSpace* ws2) {
  assert (NULL != ws2);
  if (NULL != client) { // client did not die during the operation
    if ((ws2 != workSpace) || (ws2 != client->workSpace)) {
      client->sticky = 0;
      client->workSpace = ws2;
  
      // is this one in focus?
      if (client == current) {
	setactive(current, 0, 0L); // copied from disp.cc
	current = NULL;
      }

      innerSendClienttoWS(client, 0); // make it invisible
    }
    assert (client->workSpace == ws2);

    if (1 == followClientToWS) {
      changeWorkSpace(workSpace, client->workSpace);
      followClientToWS = 0;
    }
  }
  else { // client died during the operation. CYA
    XUnmapWindow(dpy, popup);
    mode =   wmReady;
  }

  return;
}

void
WindowManager::innerSendClienttoWS(Client* client, int visibleP) {

  if (visibleP == 0)  {// slide it away
    //  set normalX, normalY just prior to pushing it off the screen.
    client->normalX = client->size.x;
    client->normalY = client->size.y;
    client->normalW = client->size.width;
    client->normalH = client->size.height;

    XMoveWindow(dpy, client->parent,
		client->size.x + offWorkSpace, 
		client->size.y + offWorkSpace);
    // note that I do not do any configure notification.
    // if the client pops up an emergency dialog box, I want it to show.
  }
  else {  // slide it back
    XMoveWindow(dpy, client->parent,
		client->normalX, 
		client->normalY);
    //         XMapWindow(dpy, client->parent);
  }
  return;
}

// -------------------------------------------

WorkSpace::WorkSpace(const char* n) {
  label = string(n);
}


WorkSpace::~WorkSpace() {
//   XtFree(label);
}

void 
WindowManager::rotateWSClients() {
  Client *c1 = current;
  Client *c2 = NULL;
  Node* cND = NULL;
  int i = 0;
  int numClients = allClients->length() ;
  

  if (0 == numClients)
    return;

  if (c1 == NULL) {
    cND = allClients->first;
    c1 = ((Client*) cND->data);
  }

  cND = allClients->inList(c1);

  while ((c2 == NULL) && ( i < numClients + 2)) {
    cND = allClients->nextNode(cND);
    if (cND == NULL)
      cND = allClients->first;
    i = i + 1;

    c1 = ((Client*) cND->data);

    // if this client is NULL, we are in deep doo doo
    assert (NULL != c1);


    if ((False == c1->hidden) && (workSpace == c1->workSpace))
      c2 = c1;
  }

  if (c2 != NULL) {
    raiseClient(c2);
    focusOn(c2);
  }

  return;
}
// -------------------------------------------
// end of wspace.cc
// -------------------------------------------

