/*
 *  Window Maker window manager
 * 
 *  Copyright (c) 1997-2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
 *  USA.
 */

#include "wconfig.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <string.h>
#include <stdlib.h>

#include "WindowMaker.h"
#include "window.h"
#include "GNUstep.h"


/* atoms */
extern Atom _XA_WM_STATE;
extern Atom _XA_WM_CHANGE_STATE;
extern Atom _XA_WM_PROTOCOLS;
extern Atom _XA_WM_CLIENT_LEADER;
extern Atom _XA_WM_TAKE_FOCUS;
extern Atom _XA_WM_DELETE_WINDOW;
extern Atom _XA_WM_SAVE_YOURSELF;
#ifdef XSMP_ENABLED
extern Atom _XA_WM_WINDOW_ROLE;
extern Atom _XA_SM_CLIENT_ID;
#endif


extern Atom _XA_GNUSTEP_WM_ATTR;
extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;

extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
extern Atom _XA_WINDOWMAKER_MENU;
extern Atom _XA_WINDOWMAKER_WM_PROTOCOLS;
extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
extern Atom _XA_WINDOWMAKER_ICON_TILE;
extern Atom _XA_WINDOWMAKER_ICON_SIZE;

int
PropGetNormalHints(Window window, XSizeHints *size_hints, int *pre_iccm)
{
    long supplied_hints;

    if (!XGetWMNormalHints(dpy, window, size_hints, &supplied_hints)) {
	return False;
    }    
    if (supplied_hints==(USPosition|USSize|PPosition|PSize|PMinSize|PMaxSize
	|PResizeInc|PAspect)) {
	*pre_iccm = 1;
    } else {
	*pre_iccm = 0;
    }
    return True;
}


int
PropGetWMClass(Window window, char **wm_class, char **wm_instance)
{
    XClassHint	*class_hint;

    class_hint = XAllocClassHint();
    if (XGetClassHint(dpy,window,class_hint) == 0) {
	*wm_class = NULL;
	*wm_instance = NULL;
	XFree(class_hint);
	return False;
    }
    *wm_instance = class_hint->res_name;
    *wm_class = class_hint->res_class;

    XFree(class_hint);    
    return True;
}


void
PropGetProtocols(Window window, WProtocols *prots)
{
    Atom *protocols;
    int count, i;
    
    memset(prots, 0, sizeof(WProtocols));
    if (!XGetWMProtocols(dpy, window, &protocols, &count)) {
	return;
    }
    for (i=0; i<count; i++) {
	if (protocols[i]==_XA_WM_TAKE_FOCUS)
	  prots->TAKE_FOCUS=1;
	else if (protocols[i]==_XA_WM_DELETE_WINDOW)
	  prots->DELETE_WINDOW=1;
	else if (protocols[i]==_XA_WM_SAVE_YOURSELF)
	  prots->SAVE_YOURSELF=1;
	else if (protocols[i]==_XA_GNUSTEP_WM_MINIATURIZE_WINDOW)
	  prots->MINIATURIZE_WINDOW=1;
    }
    XFree(protocols);
}


unsigned char*
PropGetCheckProperty(Window window, Atom hint, Atom type, int format,
		     int count, int *retCount)
{
    Atom type_ret;
    int fmt_ret;
    unsigned long nitems_ret;
    unsigned long bytes_after_ret;
    unsigned char *data;
    int tmp;

    if (count <= 0)
	tmp = 0xffffff;
    else
	tmp = count;

    if (XGetWindowProperty(dpy, window, hint, 0, tmp, False, type,
			   &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
			   (unsigned char **)&data)!=Success || !data)
	return NULL;

    if ((type!=AnyPropertyType && type!=type_ret)
	|| (count > 0 && nitems_ret != count)
	|| (format != 0 && format != fmt_ret)) {
	XFree(data);
	return NULL;
    }

    if (retCount)
	*retCount = nitems_ret;

    return data;
}


int
PropGetGNUstepWMAttr(Window window, GNUstepWMAttributes **attr)
{
    unsigned long *data;

    data = (unsigned long*)PropGetCheckProperty(window, _XA_GNUSTEP_WM_ATTR,
						_XA_GNUSTEP_WM_ATTR, 32, 9,
						NULL);
    
    if (!data)
	return False;
    
    *attr = malloc(sizeof(GNUstepWMAttributes));
    if (!*attr) {
	XFree(data);
	return False;
    }
    (*attr)->flags = data[0];
    (*attr)->window_style = data[1];
    (*attr)->window_level = data[2];
    (*attr)->reserved = data[3];
    (*attr)->miniaturize_pixmap = data[4];
    (*attr)->close_pixmap = data[5];
    (*attr)->miniaturize_mask = data[6];
    (*attr)->close_mask = data[7];
    (*attr)->extra_flags = data[8];

    XFree(data);

    return True;
}



void
PropSetWMakerProtocols(Window root)
{
    Atom protocols[3];
    int count=0;
    
    protocols[count++] = _XA_WINDOWMAKER_MENU;
    protocols[count++] = _XA_WINDOWMAKER_WM_FUNCTION;
    protocols[count++] = _XA_WINDOWMAKER_NOTICEBOARD;

    XChangeProperty(dpy, root, _XA_WINDOWMAKER_WM_PROTOCOLS, XA_ATOM,
		    32, PropModeReplace,  (unsigned char *)protocols, count);
}


void
PropSetIconTileHint(WScreen *scr, RImage *image)
{
    static Atom imageAtom = 0;
    unsigned char *tmp;
    int x, y;
    
    if (scr->info_window == None)
	return;
    
    if (!imageAtom) {
	/*
	 * WIDTH, HEIGHT (16 bits, MSB First)
	 * array of R,G,B,A bytes
	 */
	imageAtom = XInternAtom(dpy, "_RGBA_IMAGE", False);
    }
    
    tmp = malloc(image->width * image->height * 4 + 4);
    if (!tmp) {
	wwarning("could not allocate memory to set _WINDOWMAKER_ICON_TILE hint");
	return;
    }
    
    tmp[0] = image->width>>8;
    tmp[1] = image->width&0xff;
    tmp[2] = image->height>>8;
    tmp[3] = image->height&0xff;
    
    if (image->format == RRGBAFormat) {
	memcpy(&tmp[4], image->data, image->width*image->height*4);
    } else {
	char *ptr = tmp+4;
	char *src = image->data;
	
	for (y = 0; y < image->height; y++) {
	    for (x = 0; x < image->width; x++) {
		*ptr++ = *src++;
		*ptr++ = *src++;
		*ptr++ = *src++;
		*ptr++ = 255;
	    }
	}
    }
    
    XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_ICON_TILE,
		    imageAtom, 8, PropModeReplace, tmp, 
		    image->width * image->height * 4 + 4);
    wfree(tmp);
    
}


Window
PropGetClientLeader(Window window)
{
    Window *win;
    Window leader;

    win = (Window*)PropGetCheckProperty(window, _XA_WM_CLIENT_LEADER,
					XA_WINDOW, 32, 1, NULL);

    if (!win)
	return None;

    leader = (Window)*win;
    XFree(win);

    return leader;
}


#ifdef XSMP_ENABLED
char*
PropGetClientID(Window window)
{
    XTextProperty txprop;
    
    txprop.value = NULL;

    if (XGetTextProperty(dpy, window, &txprop, _XA_SM_CLIENT_ID)!=Success) {
	return NULL;
    }
    
    if (txprop.encoding == XA_STRING &&	txprop.format == 8 
	&& txprop.nitems > 0) {

	return (char*)txprop.value;
    } else {

	if (txprop.value)
	    XFree(txprop.value);

	return NULL;
    }
}


char*
PropGetWindowRole(Window window)
{
    XTextProperty txprop;
    
    txprop.value = NULL;

    if (XGetTextProperty(dpy, window, &txprop, _XA_WM_WINDOW_ROLE)!=Success) {
	return NULL;
    }

    if (txprop.encoding == XA_STRING &&	txprop.format == 8 
	&& txprop.nitems > 0) {

	return (char*)txprop.value;
    } else {

	if (txprop.value)
	    XFree(txprop.value);

	return NULL;
    }
}
#endif /* XSMP_ENABLED */


void
PropWriteGNUstepWMAttr(Window window, GNUstepWMAttributes *attr)
{
    unsigned long data[9];
        
    data[0] = attr->flags;
    data[1] = attr->window_style;
    data[2] = attr->window_level;
    data[3] = 0;		       /* reserved */
    /* The X protocol says XIDs are 32bit */
    data[4] = attr->miniaturize_pixmap;
    data[5] = attr->close_pixmap;
    data[6] = attr->miniaturize_mask;
    data[7] = attr->close_mask;
    data[8] = attr->extra_flags;
    XChangeProperty(dpy, window, _XA_GNUSTEP_WM_ATTR, _XA_GNUSTEP_WM_ATTR, 
		    32, PropModeReplace,  (unsigned char *)data, 9);
}


int
PropGetWindowState(Window window)
{
    long *data;
    long state;

    data = (long*)PropGetCheckProperty(window, _XA_WM_STATE, _XA_WM_STATE,
				       32, 1, NULL);

    if (!data)
	return -1;

    state = *data;
    XFree(data);

    return state;
}


void
PropCleanUp(Window root)
{
    XDeleteProperty(dpy, root, _XA_WINDOWMAKER_WM_PROTOCOLS);

    XDeleteProperty(dpy, root, _XA_WINDOWMAKER_NOTICEBOARD);

    XDeleteProperty(dpy, root, XA_WM_ICON_SIZE);

#ifdef KWM_HINTS
    XDeleteProperty(dpy, root, XInternAtom(dpy, "KWM_RUNNING", False));
#endif
}


