/* 
 *  WindowMaker window manager
 * 
 *  Copyright (c) 1997 Shige Abe and 
 *		       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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "generic/wwmlib.h"
#include "WindowMaker.h"
#include "window.h"
#include "actions.h"
#include "client.h"
#include "funcs.h"
#include "stacking.h"


/********* Global Variables *******/
extern WPreferences wPreferences;
extern Time LastTimestamp;

/*
 * TODO:
 * 
 * - disable entry of the current selected window
 *
 */


/*
 * FocusWindow
 *
 *  - Needs to check if already in the right workspace before
 *    calling wChangeWorkspace?
 *
 *  Order:
 *    Switch to correct workspace
 *    Unshade if shaded
 *    If iconified then deiconify else focus/raise.
 */
static void
focusWindow(WMenu *menu, WMenuEntry *entry)
{
    WWindow *wwin;
    WScreen *scr;
    int x, y, move=0;

    wwin = (WWindow*)entry->clientdata;
    scr = wwin->screen_ptr;
    
    wChangeWorkspace(menu->frame->screen_ptr, wwin->workspace);
    RefreshWorkspaceMenu(menu->frame->screen_ptr);

    if (wwin->flags.shaded) {
	wUnshadeWindow(wwin);
    }
    if (wwin->flags.hidden) {
	wUnhideApplication(wApplicationOf(wwin->main_window));
    } else if (wwin->flags.miniaturized) {
	wDeiconifyWindow(wwin);
    } else {
	wSetFocusTo(menu->frame->screen_ptr, wwin);
	wRaiseFrame(wwin->frame);
    }

    x = wwin->frame_x;
    y = wwin->frame_y;
    
    /* bring window back to visible area */
    if (x-4 <= -(int)wwin->frame->width) {
	move = 1;
	x = 20 - wwin->frame->width;
    }
    if (y-4 <= -(int)wwin->frame->height) {
	move = 1;
	y = 20 - wwin->frame->height;
    }
    if (x >= scr->scr_width-5) {
	move = 1;
	x = scr->scr_width - 20;
    }
    if (y >= scr->scr_height-5) {
	move = 1;
	y = scr->scr_height - 20;
    }
    if (move) {
	wWindowConfigure(wwin, x, y, wwin->frame->width, wwin->frame->height);
    }
}
 
/*
 *
 * Open switch menu 
 *
 */
void 
OpenSwitchMenu(WScreen *scr, int x, int y)
{
    WMenu *switchmenu = scr->switch_menu;
    WWindow *wwin;
    char title[MAX_MENU_TEXT_LENGTH+6];

    if (switchmenu) {
	if (switchmenu->flags.mapped) {
	    if (!switchmenu->flags.buttoned) {
		wMenuUnmap(switchmenu);
	    } else {
		wRaiseFrame(switchmenu->frame);
		wMenuMapAt(switchmenu->brother, x-switchmenu->frame->width/2, 
			   y-switchmenu->titlebar->height/2);
	    }
	} else {
	    wMenuMapAt(switchmenu, x-switchmenu->frame->width/2,
		       y-switchmenu->titlebar->height/2);
	}
	return;
    }
    switchmenu = wMenuCreate(scr,_("Windows"),True);
    wwin = scr->focused_window;
    while (wwin) {
	WMenuEntry *entry;
	char *t;

	if (wwin->flags.internal_window 
	    || wwin->window_flags.skip_window_list) {
	    wwin = wwin->prev;
	    continue;
	}
	sprintf(title, "%s", wwin->title);
	t = ShrinkString(&scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
	entry = wMenuAddCallback(switchmenu, t, focusWindow, wwin);
	free(t);
	if (!wwin->window_flags.focusable)
	  wMenuSetEnabled(switchmenu, entry->order, False);

	entry->rtext = wmalloc(16);
	if (entry->rtext) {
	    if (wwin->window_flags.omnipresent)
	      sprintf(entry->rtext, "[*]");
	    else
	      sprintf(entry->rtext, "[%i]", wwin->workspace+1);
	}

        wwin = wwin->prev;
    }
    scr->switch_menu = switchmenu;
    if (switchmenu) {
	if (!switchmenu->flags.realized)
	  wMenuRealize(switchmenu);
	wMenuMapAt(switchmenu, x-switchmenu->frame->width/2,
		   y-switchmenu->titlebar->height/2);
    }
}

/*
 *
 * Update switch menu
 *
 *
 */
void 
UpdateSwitchMenu(WScreen *scr, WWindow *wwin, int action)
{
    WMenu *switchmenu = scr->switch_menu;
    WMenuEntry *entry;
    char title[MAX_MENU_TEXT_LENGTH+6];
    int i;

    if (!wwin->screen_ptr->switch_menu)
      return;
    /*
     *  This menu is updated under the following conditions:
     *
     *    1.  When a window is created.
     *    2.  When a window is destroyed.
     *
     *    3.  When a window changes it's title.
     */
    if (action == ACTION_ADD) {
	char *t;
	if (wwin->flags.internal_window 
	    || wwin->window_flags.skip_window_list)
	  return;
	    
	if (wwin->title)
	  sprintf(title, "%s", wwin->title);
	else
	  sprintf(title, "%s", DEF_WINDOW_TITLE);
	t = ShrinkString(&scr->menu_entry_font, title, MAX_WINDOWLIST_WIDTH);
	entry = wMenuAddCallback(switchmenu, t, focusWindow, wwin);
	free(t);
	if (!wwin->window_flags.focusable)
	  wMenuSetEnabled(switchmenu, entry->order, False);
	
	entry->rtext = wmalloc(16);
	if (entry->rtext) {
	    if (wwin->window_flags.omnipresent)
	      sprintf(entry->rtext, "[*]");
	    else
	      sprintf(entry->rtext, "[%i]", wwin->workspace+1);
	}

	wMenuRealize(switchmenu);
    } else {
	char *t;
	for (i=0; i<switchmenu->entry_no; i++) {
	    entry = switchmenu->entries[i];
	    /* this is the entry that was changed */
	    if (entry->clientdata == wwin) {
		switch (action) {
		 case ACTION_REMOVE:
		    wMenuRemoveItem(switchmenu, i);
		    wMenuRealize(switchmenu);
		    break;
		    
		 case ACTION_CHANGE:
		    if (entry->text)
		      free(entry->text);
		    
		    if (wwin->title)
		      sprintf(title, "%s", wwin->title);
		    else
		      sprintf(title, "%s", DEF_WINDOW_TITLE);

		    t = ShrinkString(&scr->menu_entry_font, title, 
				     MAX_WINDOWLIST_WIDTH);
		    entry->text = t;
		    
		    /* fall through to update workspace number */
		 case ACTION_CHANGE_WORKSPACE:
		    if (entry->rtext) {
			if (wwin->window_flags.omnipresent)
			  sprintf(entry->rtext, "[*]");
			else
			  sprintf(entry->rtext, "[%i]", wwin->workspace+1);
		    }
		    wMenuRealize(switchmenu);
		    break;
		    
		}
		break;
	    }
	}
    }
    wMenuPaint(switchmenu);
}
