/*
 * Copyright (c) 1999-2003 Alfredo K. Kojima, Alban Hertroys
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 * $Id: damain.c,v 1.16 2005/04/20 18:05:04 dalroi Exp $
 */

#include "dockapp.h"
#include "daargs.h"
#include "dautil.h"

#define MIN(a, b)	(a < b ? a : b)

struct DAContext *_daContext;

DARect		DANoRect = {0, 0, 0, 0};
Display		*DADisplay = NULL;
Window		DALeader = None;
Window		DAIcon = None;
Window		DAWindow = None;
int		DADepth = 0;
Visual		*DAVisual = NULL;
unsigned long	DAExpectedVersion = 0;
GC		DAGC = NULL, DAClearGC = NULL;
DARect		DAPreferredIconSizes = {-1, -1, 0, 0};
Atom		WM_DELETE_WINDOW;


void
DAOpenDisplay(char *display, int argc, char **argv)
{
    /* Open Connection to X Server */
    DADisplay = XOpenDisplay(display);
    if (!DADisplay) {
	printf("%s: could not open display %s!\n", _daContext->programName,
		XDisplayName(display));
	exit(EXIT_FAILURE);
    }

    DADepth	= DefaultDepth(DADisplay, DefaultScreen(DADisplay));
    DAVisual	= DefaultVisual(DADisplay, DefaultScreen(DADisplay));
    DAGC	= DefaultGC(DADisplay, DefaultScreen(DADisplay));
}


void
DAProposeIconSize(unsigned width, unsigned height)
{
    XIconSize		*iconSizes;
    int			nrSizes = 0;

    _daContext->width	= width;
    _daContext->height	= height;

    /* Get the nearest allowed icon size if the WM specifies such */
    iconSizes = XAllocIconSize();
    if (XGetIconSizes(DADisplay, DefaultRootWindow(DADisplay), 
		&iconSizes, &nrSizes)) {
	int i;
	int da = -1;
	int min_w = -1, min_h = -1;
	int max_w = 0, max_h = 0;

	for (i = 0; i < nrSizes; i++)  {
	    int w1, h1, w, h;

	    if ((max_w < iconSizes[i].max_width) || 
		    (max_h < iconSizes[i].max_height)) {
		max_w = iconSizes[i].max_width;
		max_h = iconSizes[i].max_height;
	    }
	    
	    if ((min_w > iconSizes[i].min_width) || 
		    (min_h > iconSizes[i].min_height) || 
		    (min_w == -1)) {
		min_w = iconSizes[i].min_width;
		min_h = iconSizes[i].min_height;
	    }
	    
	    if ((width  > iconSizes[i].max_width) ||
		(width  < iconSizes[i].min_width) ||
		(height > iconSizes[i].max_height) ||
		(height < iconSizes[i].min_height))
		continue;
	    
	    w1 = (iconSizes[i].max_width  - width ) % iconSizes[i].width_inc;
	    h1 = (iconSizes[i].max_height - height) % iconSizes[i].height_inc;
	    w = MIN(w1, iconSizes[i].width_inc  - w1);
	    h = MIN(h1, iconSizes[i].height_inc - h1);

    	    if ((w * h < da) || (da == -1)) {
		_daContext->width  = width  + w;
		_daContext->height = height + h;
		da = w * h;
	    }
	}

	DAPreferredIconSizes.x = min_w;
	DAPreferredIconSizes.y = min_h;
	DAPreferredIconSizes.width  = max_w;
	DAPreferredIconSizes.height = max_h;

	if (da == -1) {	/* requested size is out of bounds */
	    DAWarning("Requested icon-size (%d x %d) is out of the range "
		    "allowed by the window manager\n",
		    _daContext->width, _daContext->height);
	}
    }
    XFree(iconSizes);
}


void
DACreateIcon(char *name, unsigned width, unsigned height, int argc, char **argv)
{
    XClassHint		*classHint;
    XWMHints		*wmHints;
    XGCValues		gcv;
    unsigned long	valueMask;
    char		*resourceValue;

    _daContext->width  = width;
    _daContext->height = height;

    /* Create Windows */
    DALeader = XCreateSimpleWindow(DADisplay, DefaultRootWindow(DADisplay),
	    0, 0, width, height, 0, 0, 0);

    if (! _daContext->windowed) {
	DAIcon = XCreateSimpleWindow(DADisplay, DefaultRootWindow(DADisplay),
		0, 0, width, height, 0, 0, 0);
	DAWindow = DAIcon;
    } else {
	DAIcon = None;
	DAWindow = DALeader;
    }

    /* Set ClassHint */
    if (!(classHint = XAllocClassHint()))
	printf("%s: can't allocate memory for class hints!\n",
		_daContext->programName), exit(1);
    classHint->res_class = RES_CLASSNAME;
    classHint->res_name = name;

    XSetClassHint(DADisplay, DALeader, classHint);
    XFree(classHint);

    /* Set WMHints */
    if (!(wmHints = XAllocWMHints()))
	printf("%s: can't allocate memory for wm hints!\n",
		_daContext->programName), exit(1);

    wmHints->flags = WindowGroupHint;
    wmHints->window_group = DALeader;

    if (!_daContext->windowed) {
    	wmHints->flags |= IconWindowHint|StateHint;
	wmHints->icon_window = DAIcon;
    	wmHints->initial_state = WithdrawnState;
    }

    XSetWMHints(DADisplay, DALeader, wmHints);
    XFree(wmHints);

    /* Set WMProtocols */
    WM_DELETE_WINDOW = XInternAtom(DADisplay, "WM_DELETE_WINDOW", True);
    XSetWMProtocols(DADisplay, DALeader, &WM_DELETE_WINDOW, 1);
    
    /* Set Command to start the app so it can be docked properly */
    XSetCommand(DADisplay, DALeader, argv, argc);

    gcv.graphics_exposures = False;
    valueMask = GCGraphicsExposures;

    /* continue setting the foreground GC */
    resourceValue = XGetDefault(DADisplay, RES_CLASSNAME, "foreground");
    if (resourceValue) {
	gcv.foreground = DAGetColor(resourceValue);
	valueMask |= GCForeground;
    }

    XChangeGC(DADisplay, DAGC, valueMask, &gcv);

    /* set background GC values before setting value for foreground */
    resourceValue = XGetDefault(DADisplay, RES_CLASSNAME, "background");
    if (resourceValue) {
	gcv.foreground = DAGetColor(resourceValue);
    }

    DAClearGC = XCreateGC(DADisplay, DAWindow,
	    GCGraphicsExposures|GCForeground, &gcv);

    XFlush(DADisplay);
}


void
DAShow(void)
{
    DAShowWindow(DALeader);
}


void
DAShowWindow(Window window)

{
    XMapRaised(DADisplay, window);
    if ((window == DALeader) && !_daContext->windowed) {
	XMapSubwindows(DADisplay, DAIcon);
    } else {
	XMapSubwindows(DADisplay, window);
    }

    XFlush(DADisplay);
}


/* Deprecated */
void
DAInitialize(char *display, char *name, unsigned width, unsigned height,
	int argc, char **argv)
{
    DAOpenDisplay(display, argc, argv);
    DACreateIcon(name, width, height, argc, argv);
}


syntax highlighted by Code2HTML, v. 0.9.1