#ifndef CODE_XDISPLAY_CXX
#define CODE_XDISPLAY_CXX

/*-----------------------------------------------------------------------
 * Xclasses code file
 * ($Id: Xdisplay.cxx,v 1.4 1999/06/06 20:35:02 schmitzj Exp $)
 * 
 * Copyright (C) 1998 Jürgen Schmitz
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *-----------------------------------------------------------------------
 */

#include <locale.h>
#include "types.h"
#include <Xclasses/Xclasses_class.h>
#include <Xclasses/Xdisplay.h>
#include "include/Xdisplay_p.h"
#include "../include/XCprogram_p.h"
#include "../include/defaults.h"

// #define XTEST

static Display	*G_display=NULL;
static int		g_anzahl=0;
static char		*dspname=NULL;
XIM		 xim=0;
XIMStyle best_style=0;

#ifdef XTEST
static int afterfunc(Display *d)
{
	XSync(d,0); usleep(750);
	return 0;
}
#endif

// #define USEERRORHANDLER
#ifdef USEERRORHANDLER
static int error_handler(Display *d, XErrorEvent *eevent)
{
	char msg[200],buf[100];
	XGetErrorText(d,eevent->error_code,msg,sizeof(msg));
//	XGetErrorDatabaseText(d,"","XRequest","---",msg,sizeof(msg));
	fprintf(stderr,"X Error of failed request: %s\n",msg);

	sprintf(buf,"XRequest.%d",eevent->request_code);
	XGetErrorDatabaseText(d,"",buf,"---",msg,sizeof(msg));
	fprintf(stderr,"  Major opcode of failed request: %d (%s)\n",eevent->request_code,msg);
	fprintf(stderr,"  Resource id in failed request: 0x%x\n",eevent->resourceid);
	fprintf(stderr,"  Serial number of failed request: %d\n",eevent->serial);
//	fprintf(stderr,"  Current serial number in output stream: %d\n",eevent->
	
	return 1;
}
#endif

Xdisplay::Xdisplay() : Xclasses()
{
	while (!(p=new pXdisplay))
	{
		outOfMemory("Xdisplay");
	}
	p->o=this;
	g_anzahl++;
	Name("Xdisplay");
}
Xdisplay::Xdisplay(char *dsp) : Xclasses()
{
	while (!(p=new pXdisplay))
	{
		outOfMemory("Xdisplay");
	}
	p->o=this;
	if (!Init(dsp)) exit(1);
	g_anzahl++;
	Name("Xdisplay");
}
Xdisplay::Xdisplay(int &argc,char *argv[]) : Xclasses()
{
	while (!(p=new pXdisplay))
	{
		outOfMemory("Xdisplay");
	}
	p->o=this;
	if (!Init(argc,argv)) exit(1);
	g_anzahl++;
	Name("Xdisplay");
};
Xdisplay::~Xdisplay()
{
	Close();
	g_anzahl--;
	if (p) delete p;
}
pXdisplay::pXdisplay()
{
	extradisplay=0;
}
pXdisplay::~pXdisplay()
{
}

XIMStyle pXdisplay::ChooseBetterStyle(XIMStyle style1,XIMStyle style2)
{
	XIMStyle s,t;
	XIMStyle preedit=XIMPreeditArea | XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
	XIMStyle status=XIMStatusArea | XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone;

	if (style1==0) return style2;
	if (style2==0) return style1;
	if ((style1 & (preedit | status))==(style2 & (preedit | status))) return style1;

	s=style1 & preedit;
	t=style2 & preedit;

	if (s!=t)
	{
		if (s|t|XIMPreeditCallbacks)
			return (s==XIMPreeditCallbacks)?style1:style2;
		else if (s|t|XIMPreeditPosition)
			return (s==XIMPreeditPosition)?style1:style2;
		else if (s|t|XIMPreeditArea)
			return (s==XIMPreeditArea)?style1:style2;
		else if (s|t|XIMPreeditNothing)
			return (s==XIMPreeditNothing)?style1:style2;
	}
	else
	{
		s=style1 & status;
		t=style2 & status;

		if (s|t|XIMStatusCallbacks)
			return (s==XIMStatusCallbacks)?style1:style2;
		else if (s|t|XIMStatusArea)
			return (s==XIMStatusArea)?style1:style2;
		else if (s|t|XIMStatusNothing)
			return (s==XIMStatusNothing)?style1:style2;
	}
	return 0;
}

int Xdisplay::Init(char *dsp)
{
	if (!G_display)
	{
		setlocale(LC_ALL,"POSIX");
		dspname=dsp;
	    if (G_display=XOpenDisplay(dsp))
    	{
#ifdef XTEST
        	XSynchronize(G_display,1);
			XSetAfterFunction(G_display,afterfunc);
#endif

#ifdef USEERRORHANDLER
			XSetErrorHandler(error_handler);
#endif

			if (defaults.intlkey && XSupportsLocale())
			{
				if (XSetLocaleModifiers("")==NULL) return 1;

				if (!(xim=XOpenIM(G_display,NULL,NULL,NULL))) return 1;

				XIMStyle app_supported_styles=XIMPreeditNone | XIMPreeditNothing | XIMPreeditArea | XIMStatusNone | XIMStatusNothing | XIMStatusArea;
//				XIMStyle app_supported_styles=XIMPreeditNothing | XIMStatusNothing;
				XIMStyles *im_supported_styles;
				XIMStyle style;

				XGetIMValues(xim,XNQueryInputStyle,&im_supported_styles,NULL);
				for(int i=0;i<im_supported_styles->count_styles;i++)
				{
					style=im_supported_styles->supported_styles[i];
					if ((style & app_supported_styles)==style)
						best_style=p->ChooseBetterStyle(style,best_style);
				}
				XFree(im_supported_styles);
//				best_style=XIMPreeditNothing | XIMStatusNothing;
			}
			start_x_session(this);
	        return 1;
    	}
    	G_display=NULL;
	    return 0;
	}
	return 1;
}
int Xdisplay::Init(int &argc,char *argv[])
{
	int c=0;
	char *sl,*dsp=NULL;

	if (!thisProgram)
	{
		class XCprogram *dummy=new XCprogram(argv[0],XCP_Done);
		dummy=dummy;
	}
	prgname=thisProgram->name->Name();
	sl=prgname;

	while (*sl)
	{
		if (*sl=='/')
		{
			prgname=sl+1;
		}
		sl++;
	}

	for (int i=1;i<argc;i++)
	{
		if (!strcasecmp(argv[i],"-display"))
		{
			c=i+1;
			if (c<argc)
			{
				dsp=argv[c];
				remarg(argc,argv,i);
				argc--;
			}
			remarg(argc,argv,i);
			argc--;
			i=argc;
		}
	}
	argvparser(argc,argv);
	return Init(dsp);
}
void Xdisplay::Close(void)
{
    if (G_display && g_anzahl==1)
    {
		end_x_session(this);
		if (xim) XCloseIM(xim);
		xim=0;
        XCloseDisplay(G_display);
    	G_display=NULL;
    }
}
Display *Xdisplay::display(void)
{
	return (p->extradisplay?p->e_display:G_display);
};
int Xdisplay::screen(void)
{
	return DefaultScreen(display());
};
Window Xdisplay::rootwindow(void)
{
	return DefaultRootWindow(display());
}
char *Xdisplay::DisplayName(void)
{
	if (G_display)
		return DisplayString(G_display);
	else
		return XDisplayName(dspname);
}

Display *g_display(void)
{
	return G_display;
}
#endif
