/*
 *  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 <string.h>

#include "generic/wwmlib.h"
#include "WindowMaker.h"
#include "menu.h"
#include "window.h"
#include "icon.h"
#include "appicon.h"
#include "application.h"
#include "appmenu.h"
#include "resource.h"
#include "properties.h"
#include "funcs.h"
#include "stacking.h"
#include "actions.h"
#ifdef DOCK
#include "dock.h"
#endif

/******** Global variables ********/

extern XContext wAppWinContext;
extern XContext wWinContext;
extern WPreferences wPreferences;

/******** Local variables ********/


/*
 * wApplication descriptors can be used both to track the list of
 * windows in a group for simple applications and to record information
 * for more complex applications with app defined menus and others.
 */



static WWindow*
makeMainWindow(WScreen *scr, Window window)
{
    WWindow *wwin;
    WResource *resource;
    XWindowAttributes attr;

    
    if (!XGetWindowAttributes(dpy, window, &attr)) {
	return NULL;
    }

    wwin = wmalloc(sizeof(WWindow));

    memset(wwin, 0, sizeof(WWindow));
    wwin->screen_ptr = scr;
    wwin->client_win = window;
    wwin->main_window = window;
    wwin->wm_hints = XGetWMHints(dpy, window);
    if (!MyXFetchName(dpy, window, &(wwin->title))) {
	wwin->title = NULL;
    }
    PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);

    if ((resource=wResourceGet(wwin->title, wwin->wm_instance,
			       wwin->wm_class))) {
	if ((resource->valid & WA_NOT_APPLICATION) &&
	    (resource->value & WA_NOT_APPLICATION)) {
	    if (wwin->title)
	      XFree(wwin->title);
	    if (wwin->wm_hints)
	      XFree(wwin->wm_hints);
	    if (wwin->wm_class)
	      XFree(wwin->wm_class);
	    if (wwin->wm_instance)
	      XFree(wwin->wm_instance);
	    wfree(wwin);
	    return NULL;
	}
	wwin->icon_file = resource->icon_file;
	wwin->icon_text = resource->icon_text;
    }
    XSelectInput(dpy, window, attr.your_event_mask | PropertyChangeMask
		 | StructureNotifyMask );
    return wwin;
}


WApplication*
wApplicationOf(Window window)
{
    WApplication *wapp;

    if (window == None) 
      return NULL;
    if (XFindContext(dpy, window, wAppWinContext, (XPointer*)&wapp)!=XCSUCCESS)
      return NULL;
    return wapp;
}


WApplication*
wApplicationCreate(WScreen *scr, Window main_window)
{
    WApplication *wapp;
    WWindow *leader;

    if (main_window==None || main_window==scr->root_win) {
#ifdef DEBUG0
	wWarning("trying to create application for %x",(unsigned)main_window);
#endif
	return NULL;
    }

    {
	Window root;
	int foo;
	unsigned int bar;
	/* check if the window is valid */
	if (!XGetGeometry(dpy, main_window, &root, &foo, &foo, &bar, &bar,
			  &bar, &bar)) {
	    return NULL;
	}
    }
    
    wapp = wApplicationOf(main_window);
    if (wapp) {
	wapp->refcount++;
	return wapp;
    }
    
    wapp = wmalloc(sizeof(WApplication));

    wapp->refcount = 1;
    wapp->last_focused = NULL;
      
    wapp->main_window = main_window;
    wapp->main_window_desc = makeMainWindow(scr, main_window);
    if (!wapp->main_window_desc) {
	wfree(wapp);
	return NULL;
    }
    
    leader = wWindowFor(main_window);
    if (leader) {
	leader->main_window = main_window;
    }
    wapp->menu = wAppMenuGet(scr, main_window);

    /* application descriptor */
    XSaveContext(dpy, main_window, wAppWinContext, (XPointer)wapp);

    if (!wapp->main_window_desc->window_flags.not_application) {
#ifdef DOCK
	if (scr->dock) {
	    wDockTrackWindowLaunch(scr->dock, main_window);
	    if ((wapp->app_icon = wDockFindIconFor(scr->dock, main_window))) {
		wapp->app_icon->running = 1;
		wapp->app_icon->icon->force_paint = 1;
		wapp->app_icon->icon->owner = wapp->main_window_desc;
		wIconUpdate(wapp->app_icon->icon);
		wAppIconPaint(wapp->app_icon);
	    } else {
		wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
	    }
	} else
#endif
	wapp->app_icon = wAppIconCreate(wapp->main_window_desc);
    } else {
	wapp->app_icon = NULL;
    }
    
    if (wapp->app_icon)
      wapp->app_icon->main_window = main_window;
    
    if (wapp->app_icon && !wapp->app_icon->docked) {
	WIcon *icon = wapp->app_icon->icon;
#ifdef AUTOARRANGE_ICON
	WWindow *wwin = scr->focused_window;
	int x, y;
	x = 0;
	y = scr->scr_height - ICON_HEIGHT;
	
	wArrangeIcons(scr);
	
	while(wwin){
	    if (wwin->icon && wwin->flags.miniaturized) {
		x = wwin->icon_x + ICON_WIDTH;
#ifdef ANIMATIONS
		if (wPreferences.animations 
		    && (wwin->icon_x != x || wwin->icon_y != y)) {
		    SlideWindow(wwin->icon->core->window, wwin->icon_x, 
				wwin->icon_y, x, y, ARRANGE_ICONS_ANIMATION_STEPS,
				ARRANGE_ICONS_ANIMATION_DELAY);
		} else {
		    XMoveWindow(dpy, wwin->icon->core->window, x, y);
		}
#else
		XMoveWindow(dpy, wwin->icon->core->window, x, y);
#endif /* ANIMATIONS */
		wwin->icon_x = x;
		wwin->icon_y = y;
		wwin->flags.icon_moved = 0;
		wwin = wwin->prev;
	    } else {
		wwin = wwin->prev;
	    }
	    if (x > scr->scr_width-ICON_WIDTH) {
		x = 0;
		y -= ICON_HEIGHT;
	    }
	}

#endif /* AUTOARRANGE_ICON */
	PlaceIcon(scr, &wapp->app_icon->x_pos, &wapp->app_icon->y_pos);
	XMoveWindow(dpy, icon->core->window, wapp->app_icon->x_pos, 
		    wapp->app_icon->y_pos);
	XMapWindow(dpy, icon->core->window);
    }

#ifdef DEBUG
    printf("Created application for %x\n", (unsigned)main_window);
#endif
    return wapp;
}


void
wApplicationDestroy(WApplication *wapp)
{
    Window main_window;
    WWindow *wwin;
    WScreen *scr;

    if (!wapp)
      return;

    wapp->refcount--;
    if (wapp->refcount>0)
      return;

    scr = wapp->main_window_desc->screen_ptr;
    main_window = wapp->main_window;
    XDeleteContext(dpy, wapp->main_window, wAppWinContext);
    wAppMenuDestroy(wapp->menu);
    if (wapp->app_icon) {
	if (wapp->app_icon->docked) {
	    wapp->app_icon->running = 0;
	    wapp->app_icon->main_window = None;
	    wapp->app_icon->pid = 0;
	    wapp->app_icon->icon->owner = NULL;
	    wapp->app_icon->icon->client_pixmap = 0;
	    wapp->app_icon->icon->client_window = None;
	    wapp->app_icon->icon->force_paint = True;
	    wIconUpdate(wapp->app_icon->icon);
	    wAppIconPaint(wapp->app_icon);
	} else {
	    wAppIconDestroy(wapp->app_icon);
	}
    }
    wwin = wWindowFor(wapp->main_window_desc->client_win);

    wWindowDestroy(wapp->main_window_desc);
    if (wwin) {
    	/* undelete client window context that was deleted in
     	 * wWindowDestroy */
    	XSaveContext(dpy, wwin->client_win, wWinContext, 
		    (XPointer)&wwin->client_descriptor);
    }
    wfree(wapp);
#ifdef DEBUG
    printf("Destroyed application for %x\n", (unsigned)main_window);
#endif
    
}


