/* placement.c - window and icon placement on screen
 * 
 *  WindowMaker window manager
 * 
 *  Copyright (c) 1997 Alfredo K. Kojima
 * 
 *  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.
 */

#include "wconfig.h"

#include <X11/Xlib.h>
#include <stdlib.h>
#include <stdio.h>

#include "generic/wwmlib.h"
#include "WindowMaker.h"
#include "wcore.h"
#include "icon.h"
#include "actions.h"
#include "funcs.h"
#include "application.h"
#include "appicon.h"
#include "dock.h"

extern WPreferences wPreferences;


/*
 * interactive window placement is in moveres.c
 */

extern void
InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret);


void
PlaceIcon(WScreen *scr, int *x_ret, int *y_ret)
{
    int x1, y1, x2, y2;
    int icon_x, icon_y;
    int left_margin, right_margin;
    WCoreWindow *wcore;

    if (scr->dock) {
	if (scr->dock->on_right_side) {
	    left_margin = 0;
	    right_margin = scr->scr_width-ICON_WIDTH;
	} else {
	    left_margin = ICON_WIDTH;
	    right_margin = scr->scr_width;
	}
    } else {
	left_margin = 0;
	right_margin = scr->scr_width;
    }
    x1 = left_margin;
    y2 = scr->scr_height;
    y1 = y2-ICON_HEIGHT*2;    
    x2 = left_margin+ICON_WIDTH;

    while (1) {
	wcore = scr->stacking_list[0];
	
	while (wcore) {

	    if (x2>=right_margin+ICON_WIDTH) {
		x1 = left_margin;
		x2 = left_margin+ICON_WIDTH*2;
		y1 -= ICON_HEIGHT;
		y2 -= ICON_HEIGHT;
		if (y2<ICON_HEIGHT) {
		    /* what's this guy doing!? */
		    *x_ret = 0;
		    *y_ret = 0;
		    return;
		}
		break;
	    }
	    
	    /* if it is an application icon */
	    if (wcore->descriptor.parent_type == WCLASS_APPICON) {
		icon_x = ((WAppIcon*)wcore->descriptor.parent)->x_pos;
		icon_y = ((WAppIcon*)wcore->descriptor.parent)->y_pos;
	    } else if (wcore->descriptor.parent_type == WCLASS_MINIWINDOW) {
		icon_x = ((WIcon*)wcore->descriptor.parent)->owner->icon_x;
		icon_y = ((WIcon*)wcore->descriptor.parent)->owner->icon_y;
	    } else {
		wcore = wcore->stacking->under;
		continue;
	    }
	    wcore = wcore->stacking->under;
	    
	    /* test if place is taken */
	    if (icon_y>y1 && icon_y<y2) {
		if (icon_x<x2 && icon_x>=x1) { 
		    x2 = icon_x+ICON_WIDTH*2;
		    x1 = icon_x+ICON_WIDTH;
		    /* this place can't be used */
		    wcore = scr->stacking_list[0];
		    break;
		}
	    }
	}
	if (!wcore) {
	    /* found spot */
	    break;
	}
    }
    *x_ret = x1;
    *y_ret = y2-ICON_HEIGHT;
}


static int
smartPlaceWindow(WWindow *wwin, int *x_ret, int *y_ret)
{
    WScreen *scr = wwin->screen_ptr;
    int height,width;
    int test_x = 1,test_y = 1;
    int loc_ok = False, tw,tx,ty,th;
    WWindow *test_window;

     /* this was based on fvwm2's smart placement */

    height = wwin->client.height+wwin->top_width+wwin->bottom_width;
    width  = wwin->client.width;
    while (((test_y + height) < (scr->scr_height)) && (!loc_ok)) {
	
	test_x = 1;
	
	while (((test_x + width) < (scr->scr_width)) && (!loc_ok)) {
	    
	    loc_ok = True;
	    test_window = scr->focused_window;
	    
	    while ((test_window != (WWindow *) 0) && (loc_ok == True)) {
		
		tw = test_window->client.width;
		th = test_window->client.height+test_window->top_width+test_window->bottom_width;
		tx = test_window->frame_x;
		ty = test_window->frame_y;
		
		if((tx<(test_x+width))&&((tx + tw) > test_x)&&
		   (ty<(test_y+height))&&((ty + th)>test_y)&&
		   (test_window->flags.mapped==1)) {
		    
		    loc_ok = False;
		}
		test_window = test_window->next;
	    }
	    
	    test_window = scr->focused_window;
	    
	    while ((test_window != (WWindow *) 0) && (loc_ok == True))  {
		
		tw = test_window->client.width;
		th = test_window->client.height+test_window->top_width+test_window->bottom_width;
		tx = test_window->frame_x;
		ty = test_window->frame_y;
		
		if((tx<(test_x+width))&&((tx + tw) > test_x)&&
		   (ty<(test_y+height))&&((ty + th)>test_y)&&
		   (test_window->flags.mapped==1)) {
		    
		    loc_ok = False;
		}
		test_window = test_window->prev;
	    }
	    if (loc_ok == True) {
		*x_ret = test_x;
		*y_ret = test_y;
		break;
	    }
	    test_x += PLACETEST_HSTEP;
	}
	test_y += PLACETEST_VSTEP;
    }
    return loc_ok;
}

void
PlaceWindow(WWindow *wwin, int *x_ret, int *y_ret)
{
    WScreen *scr = wwin->screen_ptr;
    int h = scr->title_font.height+8;

    switch (wPreferences.window_placement) {
     case WPM_MANUAL:
	InteractivePlaceWindow(wwin, x_ret, y_ret);
	break;

     case WPM_SMART:
	if (smartPlaceWindow(wwin, x_ret, y_ret))
	  break;
	/* there isn't a break here, because if we fail, it should fall
	   through to cascade placement, as people who want tiling want
	   automagicness aren't going to want to place their window */

     case WPM_CASCADE:
	scr->cascade_index++;
	*x_ret = h*scr->cascade_index + ICON_WIDTH;
	*y_ret = h*scr->cascade_index + ICON_WIDTH;
	if ((*x_ret > scr->scr_width/2)||(*y_ret > scr->scr_height/2))
	  scr->cascade_index = 0;
	break;

     case WPM_RANDOM:
	*x_ret = rand()%(scr->scr_width-wwin->client.width);
	*y_ret = rand()%(scr->scr_height-wwin->client.height);
	break;

#ifdef DEBUG	
     default:
	puts("Invalid window placement!!!");
	*x_ret = 0;
	*y_ret = 0;
#endif
    }
}
