//-*-c++-*-
// ----------------------------------------------
// RCS data:
// $Date: 2003/07/04 09:48:55 $
// $Revision: 1.3 $
// $Source: /cvsroot/miwm/miwm/miwm/ops.cc,v $
// $Id: ops.cc,v 1.3 2003/07/04 09:48:55 sgbeal Exp $
// $RCSfile: ops.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.
// ----------------------------------------------
// simple window management operations
// ----------------------------------------------

#include "miwm.h"
#include "miwm_framework.h"
// ----------------------------------------------

void
toggleRaiseOnFocus() {
  if (1 == theWM->raiseOnFocusP)
    theWM->raiseOnFocusP = 0;
  else
    theWM->raiseOnFocusP = 1;
  miwm::config().set( "raise_client_on_focus", theWM->raiseOnFocusP );
  return;
}

void
toggleTopLeft() {
  if (1 == theWM->protectTopLeft)
    theWM->protectTopLeft = 0;
  else
    theWM->protectTopLeft = 1;
  return;
}

void
toggleClientPreview() {
  if (1 == theWM->previewCP)
    theWM->previewCP = 0;
  else
    theWM->previewCP = 1;
  miwm::config().set( "preview_client_before_unhide", theWM->previewCP );
  return;
}


void toggleTiling() {
  if (1 == theWM->tileP)
    theWM->tileP = 0;
  else
    theWM->tileP = 1;
  return;
}


void togglePixmaps() {

#ifdef USE_PIXMAPS

  XSetWindowAttributes attr;

  switch (theWM->usePixmapsP) {
  case 1:
    theWM->usePixmapsP = 0;
    attr.background_pixmap = None;
    XChangeWindowAttributes(dpy, popup,  CWBackPixmap  , &attr);
    XSetWindowBackground(dpy, popup, theWM->inactiveBorderColor.pixel);
    break;

  case 0:
    theWM->usePixmapsP = 1;
    attr.background_pixmap = theWM->popupBgd;
    XChangeWindowAttributes(dpy, popup,  CWBackPixmap  , &attr);
    break;
  default:
    break;
  }
  miwm::config().set( "enable_pixmaps", theWM->usePixmapsP );
#endif
  return;
}

void rotateClients() {
  theWM->rotateWSClients();
  return;
}

void terminateWM() {
  Terminate(0);
  return;
}

void contractWS() {
  WorkSpace *home = theWM->allWorkSpaces[0];
  Node* cND;
  Client* c;
  int i;

  // cycle through workspaces, unhiding things
  for (i = 0; i<theWM->numWorkSpaces; i++) {
    theWM->changeWorkSpace(theWM->workSpace, theWM->allWorkSpaces[i]);
    for (cND = theWM->allClients->first;
	 cND != NULL;
	 cND = theWM->allClients->nextNode(cND)) {
      c = ((Client*) cND->data);


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


      if (hidden(c))
	unhidec(c,1);
    }
  }

  // cycle through workspaces, sending each client home
  for (i = 0; i<theWM->numWorkSpaces; i++) {
    theWM->changeWorkSpace(theWM->workSpace, theWM->allWorkSpaces[i]);
    for (cND = theWM->allClients->first;
	 cND != NULL;
	 cND = theWM->allClients->nextNode(cND)) {
      c = ((Client*) cND->data);

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


      theWM->sendClientToWorkSpace(c, home);
    }
  }

  // finally, WM goes home
  theWM->changeWorkSpace(theWM->workSpace, home);

  // try to clean up the resulting mess !
  retileWS();
  return;
}

void stepWSup() {
  stepWS(+1);
  return;
}

void stepWS(int step) {
  assert ((+1 == step) || (-1 == step));
  int i = 0;
  int j = -1;
  WorkSpace* ws1 = theWM->workSpace;
  WorkSpace* ws2 = NULL;
  for (i=0; ((-1 == j) && (i<theWM->numWorkSpaces)); i++) 
    if (theWM->allWorkSpaces[i] == ws1) {
      j = i;
    }
  // ensure it is positive, 
  step = step + theWM->numWorkSpaces;
  j = (j+step) % theWM->numWorkSpaces;
  ws2 = theWM->allWorkSpaces[j];

  
  theWM->changeWorkSpace(ws1, ws2);
  return;
}
void retileWS() {
  Node* cND;
  NodeList* remaining = new NodeList();
  Client* c;
  Client* bigC;
  int largestArea = 0;
  int area = 0;
  int oldTiling = theWM->tileP;
  theWM->tileP = 1;
  theWM->auto_x = 1;
  theWM->auto_y = 1;
  if (current != NULL) {
    setactive(current, 0, 0L);
    current = NULL;
  }

  // find every non-sticky client in the current workspace,
  // and shift their coordinates out of the way
  // it is a good idea to put sticky things on the bottom or right edges)
  for (cND = theWM->allClients->first;
       cND != NULL;
       cND = theWM->allClients->nextNode(cND)) {
    c = ((Client*) cND->data);

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


    if ((c->sticky == 0) 
	&& (c->workSpace == theWM->workSpace) 
	&& (False == c->hidden) 
	&& (1 == c->isMapped) 
	)  
      {
	remaining->append((void*)c);
	c->size.x = c->size.x + theWM->offWorkSpace;
      }
  }

  // re-place them in largest-first order.
  while (remaining->length() > 0) {
    largestArea = 0;
    bigC = NULL;
    for (cND = remaining->first;
	 cND != NULL;
	 cND = remaining->nextNode(cND)) {
      c = ((Client*) cND->data);
      area = c->size.width * c->size.height;
      if (area > largestArea) {
	largestArea = area;
	bigC = c;
      }
    }
    theWM->autoPlaceCoords(bigC);
    XMoveWindow(dpy, bigC->parent, bigC->size.x, bigC->size.y);

    sendConfigureNotify(bigC);
    // ensure the last are on top of the first-placed large ones
    if (1 == bigC->isMapped)
      theWM->raiseClient(bigC); 
    cND = remaining->inList((void*) bigC);
    assert (NULL != cND);
    remaining->remove(cND);
  }

  delete remaining;
  remaining = NULL;
  theWM->auto_x = 5;
  theWM->auto_y = 5;
  theWM->tileP = oldTiling;
  return;
}

void restartWM() {
  char* sh = ((char*) getenv("SHELL"));
  if (sh == 0)
    sh = "/bin/bash"; 
  int rslt = fork();
  switch (rslt) {
  case 0:  // child
    
    close(ConnectionNumber(dpy));
    execl(sh, sh, "-c", "miwm", 0);
    break;

  case -1: // error
    XBell(dpy, 70);
    fprintf(stderr, "miwm: restart failed (errno %d)\n", errno);
    exit(1);
    break;

  default: // parent
    Terminate(0);
    break;
  }

  return;
}

void idCurrent() {
  if (NULL != current) {
    cout << "Current client is " << current->clientID <<endl;
    cout << "Hidden: " << current->hidden << endl;
    cout << "isMapped: " << current->isMapped << endl;
  }
  else { // client died during the operation. CYA
    cout << "Current client is NULL"<<endl;
  }
  return;
}

void terminateCurrent() {
  if (NULL != current)
    closeClient(current);
  else { // client died during the operation. CYA
    cout << "Current client is NULL"<<endl;
  }
  return;
}


void toggleSticky() {
  if (NULL != current)
    current->sticky = 1- current->sticky;
  else { // client died during the operation. CYA
    cout << "Current client is NULL"<<endl;
  }
  return;
}



// ----------------------------------------------
// end of ops.cc
// ----------------------------------------------

