/*
Copyright 1990-2003 Sun Microsystems, Inc. All Rights Reserved.

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 OPEN GROUP OR SUN MICROSYSTEMS, INC. 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 EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/

#pragma ident   "@(#)PaletteAux.c 1.12 03/03/11"

#include <stdio.h>
#include <locale.h>
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <Xm/DrawingA.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/Separator.h>
#include <Xm/MwmUtil.h>

#include "xaux_locale.h"
#include "hzinput.h"
#include "CmnFunction.h"
#include "PaletteAux.h"
#include "UtilityConfig.h"
#include "KeyboardConfig.h"
#include "xpm.h"
#include "pixmap.h"

#define DEFAULT_IME_NAME "No IME"

#define MOVEAREA_WIDTH  	12
#define IMEAREA_WIDTH   	50
#define CHARTYPEAREA_WIDTH   	22
#define PUNCTTYPEAREA_WIDTH   	22
#define KEYBOARDAREA_WIDTH   	22
#define OPTIONSAREA_WIDTH   	22
#define PALETTE_HEIGHT  	26

PaletteAuxData 	gPAData;

Display  	*gDisplay;
char 		gLocaleID;

int button_width[FIXBTN_NUM] = {
	MOVEAREA_WIDTH,
	IMEAREA_WIDTH,
	CHARTYPEAREA_WIDTH,
	PUNCTTYPEAREA_WIDTH,
	KEYBOARDAREA_WIDTH,
	OPTIONSAREA_WIDTH
};
	
char** arrCharTypePmpStr[] =
{
	halfwidth_xpm,
	fullwidth_xpm,
};

char** arrPunctTypePmpStr[] =
{
	en_punct_xpm,
	ch_punct_xpm,
};

char** arrKeyboardPmpStr[] =
{
	keyboard_xpm,
};

char** arrOptionsPmpStr[] =
{
	options_xpm,
};

/*  Auxiliary Window User Input Method Information  */
extern IMEListRec	AllIMEList, SelectedIMEList;
extern AuxCommonData	gCommonData;

extern int 		gUtilitiesNum;
extern Utility_Item 	*gUtilitiesItem[];

extern int		gVKB_Name_Num;
extern char 		*gVKB_Name_List[];

int  PaletteAux_InitAttributes();
void PaletteAux_InitPixmaps();
void PaletteAux_FreePixmaps();
void PaletteAux_DestroyProc(Widget, XtPointer, XtPointer);
void PaletteAux_LeaveWindowProc(Widget, XtPointer,XEvent*, Boolean*);
void PaletteAux_ExposeProc(Widget, XtPointer, XEvent*, Boolean*);
void PaletteAux_ButtonPressProc(Widget, XtPointer,XEvent*, Boolean*);
void PaletteAux_ButtonReleaseProc(Widget, XtPointer,XEvent*, Boolean*);
void PaletteAux_PointerMotionProc(Widget, XtPointer,XEvent*, Boolean*);
void PaletteAux_FixButtonPressFunc(FixButton*, XButtonEvent*);
void PaletteAux_FixButtonReleaseFunc(FixButton*, XButtonEvent*);
void PaletteAux_DrawAllButtons();
void PaletteAux_DrawFixButton(FixButton*, Boolean);
void PaletteAux_DrawMoveArea(XRectangle*);
void PaletteAux_ChangeIME(int, int);
void PaletteAux_ChangePunct(int);
void PaletteAux_ChangeQjBj(int);
void PaletteAux_CalcSize();
void MenuUnMapCallback(Widget, XtPointer, XtPointer);
void IMEMenuValueChangedCallback(Widget, XtPointer, XtPointer);
void PaletteAux_CreateVKeyboardMenu();
void KeyboardMenu_cb(Widget widget, XtPointer pClientData, XtPointer pCallData);
void PaletteAux_CreateUtilitiesMenu();
void UtilitiesMenu_cb(Widget widget, XtPointer pClientData, XtPointer pCallData);
void PaletteAux_UpdateStatus();
FixButton *PaletteAux_GetFixButtonByPoint(XPoint);

int main(int argc, char **argv)
{
	XtAppContext 	app;
	Widget 		shell, drawarea, label;

	int nArg;
	Arg arrArg[16];

	XtSetLanguageProc((XtAppContext)0, (XtLanguageProc)0, (XtPointer)0);

	nArg = 0;
	XtSetArg(arrArg[nArg], XmNx, 10); nArg++;
	XtSetArg(arrArg[nArg], XmNy, 600); nArg++;
	XtSetArg(arrArg[nArg], XmNmwmDecorations, 0); nArg++;
	XtSetArg(arrArg[nArg], XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_RESIZE); nArg++;
	XtSetArg(arrArg[nArg], XmNinput, FALSE); nArg++;
	XtSetArg(arrArg[nArg], XmNdefaultPosition, FALSE); nArg++;
	shell = XtAppInitialize(&app, "PaletteAux", NULL, 0, &argc, argv, NULL, arrArg, nArg);
	XtAddCallback(shell, XmNdestroyCallback, PaletteAux_DestroyProc, NULL);
	gPAData.wdtShell = shell;

	/* get default font informations */
	nArg = 0;
	XtSetArg(arrArg[nArg], XmNmappedWhenManaged, FALSE); nArg++;
	label = XtCreateManagedWidget("Label", xmLabelWidgetClass, shell, arrArg, nArg);
	XtVaGetValues(label, XmNfontList, &(gPAData.fontList), NULL);

	nArg = 0;
	drawarea = XtCreateManagedWidget("PaletteArea", xmDrawingAreaWidgetClass, shell, arrArg, nArg);
	gPAData.wdtPaletteArea = drawarea;

	XtAddEventHandler(drawarea, ExposureMask, FALSE, PaletteAux_ExposeProc, NULL);
	XtAddEventHandler(drawarea, LeaveWindowMask, FALSE, PaletteAux_LeaveWindowProc, NULL);
	XtAddEventHandler(drawarea, ButtonPressMask, FALSE, PaletteAux_ButtonPressProc, NULL);
	XtAddEventHandler(drawarea, ButtonReleaseMask, FALSE, PaletteAux_ButtonReleaseProc, NULL);
	XtAddEventHandler(drawarea, PointerMotionMask, FALSE, PaletteAux_PointerMotionProc, NULL);

	XtSetMappedWhenManaged(shell, FALSE);
	XtRealizeWidget(shell);

	/* Make dtsession do not save the geometry information */
	XSetCommand(XtDisplay(shell), XtWindow(shell), NULL, 0);

	/* Initialize the Palette informations */
	if (PaletteAux_InitAttributes() == -1)
		return(-1);

	/* Register aux class */
	if (xaux_ext_register_classes(shell) == -1) {
		return(-1);
	}

	XtAppMainLoop(app);
}

int  PaletteAux_InitAttributes()
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	FixButton* 	pFixButton = NULL;
	XmString   	xmString;
	Dimension  	nWidth, nHeight;
	int 		nButtonID;

	gPAData.pIME_Name = NULL;
	gPAData.bPixmapsInited = False;

	gPAData.pFixButton = (FixButton *)calloc(FIXBTN_NUM, sizeof(FixButton));
	if (gPAData.pFixButton == NULL)
		return(-1);

	xmString = XmStringCreateLocalized("I");
	XmStringExtent(gPAData.fontList, xmString, &nWidth, &nHeight);
	XmStringFree(xmString);
	DEBUG_printf("nWidth:%d, nHeight:%d\n", nWidth, nHeight);

	gPAData.nHeight = nHeight + 8;

	for (nButtonID = FIXBTN_MOVEAREA; nButtonID < FIXBTN_NUM; nButtonID ++) {
		pFixButton = (gPAData.pFixButton + nButtonID);
		pFixButton->nButtonID = nButtonID;
		pFixButton->nButtonType = 0;
		pFixButton->bEnabled = TRUE;
		pFixButton->bPushed = FALSE;
		pFixButton->bShow = TRUE;
		pFixButton->bSelected = FALSE;
		pFixButton->wdtMenu = 0;
	}

	PaletteAux_CalcSize();

	CommonData_Init(pDisplay);
	IMEList_Init();

	gDisplay = pDisplay;
	gLocaleID = gCommonData.locale_id;

	/* Create Virtual Keyboard Menu List */
	VKB_Name_List_Init();

	/* Create Utilities Menu List */
	Utilities_Init();
	PaletteAux_CreateUtilitiesMenu();

	return(0);
}

/* Initialize some variables: GC, Bitmap */
void PaletteAux_InitPixmaps()
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	int nScreenNo = DefaultScreen(pDisplay);
	Window RootWin = RootWindow(pDisplay, nScreenNo);
	XpmAttributes Attr;
	XpmColorSymbol Symbols[4];
	XGCValues Gcv;
	Pixmap MaskPixmap;
	Pixel foreground, background;
	int i;

	if (gPAData.bPixmapsInited == True) return;

	gPAData.bPixmapsInited = True;

	XtVaGetValues(gPAData.wdtPaletteArea, XmNforeground, &foreground, XmNbackground, &background, NULL);

	Symbols[0].name  = "foreground";
	Symbols[0].value = NULL;
	Symbols[0].pixel = foreground;
	Symbols[1].name  = "background";
	Symbols[1].value = NULL;
	Symbols[1].pixel = background;

	Attr.colorsymbols = Symbols;
	Attr.numsymbols = 2;
	Attr.colormap  = DefaultColormap(pDisplay, nScreenNo);
	Attr.depth     = DefaultDepth(pDisplay, nScreenNo);
	Attr.visual    = DefaultVisual(pDisplay, nScreenNo);
	Attr.valuemask = XpmColormap | XpmDepth | XpmColorSymbols | XpmVisual;
	
	Gcv.foreground = foreground;
	Gcv.background = background;

	for (i = 0 ; i < CHAR_TYPE_NUM ; i++) {
		XpmCreatePixmapFromData(pDisplay, RootWin, arrCharTypePmpStr[i],
				&gPAData.arrCharTypePmp[i], &MaskPixmap, &Attr);
		gPAData.arrCharTypeGC[i] = XCreateGC(pDisplay, RootWin, GCBackground|GCForeground, &Gcv);
	}

	for (i = 0 ; i < PUNCT_TYPE_NUM ; i++) {
		XpmCreatePixmapFromData(pDisplay, RootWin, arrPunctTypePmpStr[i],
				&gPAData.arrPunctTypePmp[i], &MaskPixmap, &Attr);
		gPAData.arrPunctTypeGC[i] = XCreateGC(pDisplay, RootWin, GCBackground|GCForeground, &Gcv);
	}

	for (i = 0 ; i < KEYBOARD_PMP_NUM ; i++) {
		XpmCreatePixmapFromData(pDisplay, RootWin, arrKeyboardPmpStr[i],
				&gPAData.arrKeyboardPmp[i], &MaskPixmap, &Attr);
		gPAData.arrKeyboardGC[i] = XCreateGC(pDisplay, RootWin, GCBackground|GCForeground, &Gcv);
	}

	for (i = 0 ; i < OPTIONS_PMP_NUM ; i++) {
		XpmCreatePixmapFromData(pDisplay, RootWin, arrOptionsPmpStr[i],
				&gPAData.arrOptionsPmp[i], &MaskPixmap, &Attr);
		gPAData.arrOptionsGC[i] = XCreateGC(pDisplay, RootWin, GCBackground|GCForeground, &Gcv);
	}
}

void PaletteAux_FreePixmaps()
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	int i;

	if (gPAData.bPixmapsInited == False) return;

	for (i = 0 ; i < CHAR_TYPE_NUM ; i++) {
		XFreeGC(pDisplay, gPAData.arrCharTypeGC[i]);
		XFreePixmap(pDisplay, gPAData.arrCharTypePmp[i]);
	}

	for (i = 0 ; i < PUNCT_TYPE_NUM ; i++) {
		XFreeGC(pDisplay, gPAData.arrPunctTypeGC[i]);
		XFreePixmap(pDisplay, gPAData.arrPunctTypePmp[i]);
	}

	for (i = 0 ; i < KEYBOARD_PMP_NUM ; i++) {
		XFreeGC(pDisplay, gPAData.arrKeyboardGC[i]);
		XFreePixmap(pDisplay, gPAData.arrKeyboardPmp[i]);
	}

	for (i = 0 ; i < OPTIONS_PMP_NUM ; i++) {
		XFreeGC(pDisplay, gPAData.arrOptionsGC[i]);
		XFreePixmap(pDisplay, gPAData.arrOptionsPmp[i]);
	}
}

/*   
======= Note: 
pSelectFixButton: record the Button that pointer(Mouse) is on.
pPressFixButton:  record the Button that pointer(Mouse) is pressed.
wdtSelectMenu:    record the current opened menu.
=======
*/
void PaletteAux_DestroyProc(Widget widget, XtPointer pClientData, XtPointer pCallData)
{
	free((char *)gPAData.pFixButton);

	VKB_Name_List_Done();
	Utilities_Done();
	IMEList_Free();
	CommonData_Free();

	PaletteAux_FreePixmaps();
}

void PaletteAux_LeaveWindowProc(Widget widget, XtPointer pClientData,
				XEvent* pEvent, Boolean* pbFlag)
{
	/* unselect the button that the pointer is on */
	if (gPAData.pSelectFixButton) {
		gPAData.pSelectFixButton->bSelected = FALSE;
		PaletteAux_DrawFixButton(gPAData.pSelectFixButton, FALSE);
		gPAData.pSelectFixButton = NULL;
	}
}

void PaletteAux_ExposeProc(Widget widget, XtPointer pClientData, XEvent *pEvent, Boolean *pbFlag)
{
	PaletteAux_UpdateStatus();
}

void PaletteAux_ButtonPressProc(Widget widget, XtPointer pClientData,
				XEvent* pEvent, Boolean* pbFlag)
{
	Display* pDisplay = XtDisplay(widget);
	FixButton* pFixButton;
	XPoint ptButton;

	SetPoint(&ptButton, pEvent->xbutton.x, pEvent->xbutton.y);

	if (pEvent->xbutton.button == 1) {
		if (pEvent->xbutton.send_event) {
		} else {
			XGrabPointer(pDisplay, XtWindow(gPAData.wdtPaletteArea), FALSE, 
				ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
				GrabModeAsync, GrabModeAsync, None, None, CurrentTime);

			pFixButton = PaletteAux_GetFixButtonByPoint(ptButton);
			if (pFixButton != NULL) {
				if (gPAData.pSelectFixButton) {
					gPAData.pSelectFixButton->bSelected = FALSE;
					gPAData.pSelectFixButton = NULL;
				}
				gPAData.pPressFixButton = pFixButton;
				gPAData.pPressFixButton->bPushed = TRUE;
				PaletteAux_DrawFixButton(gPAData.pPressFixButton, FALSE);

				if ( pFixButton->nButtonID == FIXBTN_MOVEAREA) {
					SetMovingBoxFrame(pEvent, &gPAData.rcPalette);
				} else { 
					PaletteAux_FixButtonPressFunc(gPAData.pPressFixButton, &pEvent->xbutton);
				}
			}
		}
	} else {
		/* unselect the button that pointer is on */
		if (gPAData.pSelectFixButton) {
			gPAData.pSelectFixButton->bSelected = FALSE;
			PaletteAux_DrawFixButton(gPAData.pSelectFixButton, FALSE);
			gPAData.pSelectFixButton = NULL;
		}
	}

}

void PaletteAux_ButtonReleaseProc(Widget widget, XtPointer pClientData,
				XEvent* pEvent, Boolean* pbFlag)
{
	Display* pDisplay = XtDisplay(widget);
	FixButton* pFixButton;
	XPoint ptButton;
	int bMoveArea = FALSE;
	Dimension nXPos, nYPos;
	
	SetPoint(&ptButton, pEvent->xbutton.x, pEvent->xbutton.y);

	if (pEvent->xbutton.button == 1) {
		XUngrabPointer(pDisplay, CurrentTime);

		if (gPAData.pPressFixButton) {
			if (gPAData.pPressFixButton->nButtonID == FIXBTN_MOVEAREA) {
				/* move the palette */
				MoveWidgetToPoint(gPAData.wdtShell, pEvent, &gPAData.rcPalette);

				/* notify LE that the Palette has change position. */
				XtVaGetValues(gPAData.wdtShell, XmNx, &nXPos, XmNy, &nYPos, NULL);
				DEBUG_printf("After move: nXPos:%d, nYPos:%d\n", nXPos, nYPos);
				gPAData.x = nXPos;
				gPAData.y = nYPos;
				PaletteAux_Change_LE_Position_Request(nXPos, nYPos);

				bMoveArea = TRUE;
			} else {
				/* unselect the button that the pointer is on */
				gPAData.pPressFixButton->bPushed = FALSE;
				PaletteAux_DrawFixButton(gPAData.pPressFixButton, FALSE);

				if (PointInRectangle(&(gPAData.pPressFixButton->rcDraw), &ptButton)) {
					PaletteAux_FixButtonReleaseFunc(gPAData.pPressFixButton, &pEvent->xbutton);
				}
			}
			gPAData.pPressFixButton = NULL;
		}
	}

	/* if is moving, need not set pSelectFixButton */
	if (bMoveArea == TRUE) return;

	/* activate the button that the pointer is on */
	pFixButton = PaletteAux_GetFixButtonByPoint(ptButton);
	if (pFixButton != NULL) {
		gPAData.pSelectFixButton = pFixButton;
		gPAData.pSelectFixButton->bSelected = TRUE;
		PaletteAux_DrawFixButton(gPAData.pSelectFixButton, FALSE);
	}
}

void PaletteAux_PointerMotionProc(Widget widget, XtPointer pClientData,
                                 XEvent* pEvent, Boolean* pbFlag)
{
	FixButton* pFixButton = gPAData.pFixButton;
	XPoint ptButton;

	SetPoint(&ptButton, pEvent->xmotion.x, pEvent->xmotion.y);

	if (Button1MotionMask & pEvent->xmotion.state) {
		if (gPAData.pPressFixButton) {
			if ( gPAData.pPressFixButton->nButtonID == FIXBTN_MOVEAREA) {
				DrawMovingBoxFrameAtPoint(pEvent, &gPAData.rcPalette);
			} else { 
				if (PointInRectangle(&gPAData.pPressFixButton->rcDraw, &ptButton) !=
					gPAData.pPressFixButton->bPushed) {
					gPAData.pPressFixButton->bPushed = !gPAData.pPressFixButton->bPushed;
					PaletteAux_DrawFixButton(gPAData.pPressFixButton, FALSE);
				}
			}
		}
	} else if (!(pEvent->xmotion.state & BUTTON_ALL_STATE)) {
		Boolean bFixSelect = FALSE;

		pFixButton = PaletteAux_GetFixButtonByPoint(ptButton);
		if (pFixButton != NULL) {
			if (gPAData.pSelectFixButton != pFixButton) {
				/* unselect the old button that the pointer is on */
				if (gPAData.pSelectFixButton) {
					gPAData.pSelectFixButton->bSelected = FALSE;
					PaletteAux_DrawFixButton(gPAData.pSelectFixButton, FALSE);
				}

				/* activate the button that the pointer is on */
				gPAData.pSelectFixButton = pFixButton;
				gPAData.pSelectFixButton->bSelected = TRUE;
				PaletteAux_DrawFixButton(gPAData.pSelectFixButton, TRUE);
			}
			bFixSelect = TRUE;
		}

		/* unselect the button that the pointer is on */
		if (!bFixSelect && gPAData.pSelectFixButton) {
			gPAData.pSelectFixButton->bSelected = FALSE;
			PaletteAux_DrawFixButton(gPAData.pSelectFixButton, FALSE);
			gPAData.pSelectFixButton = NULL;
		}

		if (gPAData.pSelectFixButton) {
/*
			DEBUG_printf("selectbutton's menu:0x%x, wdtSelectMenu:0x%x\n", gPAData.pSelectFixButton->wdtMenu, gPAData.wdtSelectMenu);
*/
			if(gPAData.pSelectFixButton->wdtMenu != gPAData.wdtSelectMenu) {
/*
				if (gPAData.wdtSelectMenu)
					XtVaSetValues(gPAData.wdtSelectMenu, XmNmenuPost, "<Btn3Down>", XmNwhichButton, 3, NULL);
				if (gPAData.pSelectFixButton->wdtMenu)
					XtVaSetValues(gPAData.pSelectFixButton->wdtMenu, XmNmenuPost, "<Btn1Down>", XmNwhichButton, 1, NULL);
*/
				gPAData.wdtSelectMenu = gPAData.pSelectFixButton->wdtMenu;
			}
		}
		
	}
}

void PaletteAux_FixButtonPressFunc(FixButton* pFixButton, XButtonEvent* pEvent)
{
	/* need not process the action of BUTTON_MOVEAREA */
	if (pFixButton->nButtonID == FIXBTN_KEYBOARD)
		PaletteAux_CreateVKeyboardMenu();

	switch(pFixButton->nButtonID) {
		case FIXBTN_IMENAME:
		case FIXBTN_KEYBOARD:
		case FIXBTN_OPTIONS:
			OpenMenuAtBox(gPAData.wdtShell, pFixButton->wdtMenu, pEvent, &pFixButton->rcDraw);
			break;
	}
}

void PaletteAux_FixButtonReleaseFunc(FixButton* pFixButton, XButtonEvent* pEvent)
{
	/* need not process the action of BUTTON_MOVEAREA */
	switch(pFixButton->nButtonID) {
		case FIXBTN_CHARTYPE:
			/* update the qjbj logo on the control bar */
			pFixButton->nButtonType = 1 - pFixButton->nButtonType;
			PaletteAux_DrawFixButton(pFixButton, FALSE);

			/* send qjbj status change info to LE */
			gPAData.qjbj = pFixButton->nButtonType;
			PaletteAux_Switch_LE_QjBj_Request(gPAData.qjbj);
			break;

		case FIXBTN_PUNCTTYPE:
			/* update the punct logo on the control bar */
			pFixButton->nButtonType = 1 - pFixButton->nButtonType;
			PaletteAux_DrawFixButton(pFixButton, FALSE);

			/* send punct status change info to LE */
			gPAData.punct = pFixButton->nButtonType;
			PaletteAux_Switch_LE_Punct_Request(gPAData.punct);
			break;
	}
}

FixButton *PaletteAux_GetFixButtonByPoint(XPoint ptButton)
{
	FixButton* pFixButton = gPAData.pFixButton;
	int i;

	for (i = 0 ; i < FIXBTN_NUM ; i++, pFixButton++) {
		if (PointInRectangle(&(pFixButton->rcDraw), &ptButton) &&
		    pFixButton->bEnabled && pFixButton->bShow) {
			return(pFixButton);
		}
	}

	return(NULL);
}

void PaletteAux_CalcSize()
{
	FixButton* pFixButton = NULL;
	int nXPos = 2;
	int nYPos = 2;
	int nButtonID, nWidth, nHeight;
	Dimension nStrWidth, nStrHeight;
	char *pIME_Name;
	XmString xmString;

	pIME_Name = gPAData.pIME_Name;
	if (pIME_Name == NULL) pIME_Name = DEFAULT_IME_NAME;

	xmString = XmStringCreateLocalized(pIME_Name);
	XmStringExtent(gPAData.fontList, xmString, &nStrWidth, &nStrHeight);
	XmStringFree(xmString);

	button_width[FIXBTN_IMENAME] = (int)nStrWidth + 6;

	nHeight = gPAData.nHeight - 4;
	for (nButtonID = FIXBTN_MOVEAREA; nButtonID < FIXBTN_NUM; nButtonID ++) {
		pFixButton = (gPAData.pFixButton + nButtonID);
		if (pFixButton->bShow == FALSE) continue;

		SetRectangle(&pFixButton->rcDraw, nXPos, nYPos, button_width[nButtonID], nHeight);
		nXPos += button_width[nButtonID];
	}

	nWidth = nXPos + 2;
	nHeight += 4;
	SetRectangle(&gPAData.rcPalette, 0, 0, nWidth, nHeight);
	XtVaSetValues(gPAData.wdtShell, XmNwidth, nWidth, XmNheight, nHeight, NULL);
	XtVaSetValues(gPAData.wdtPaletteArea, XmNwidth, nWidth, XmNheight, nHeight, NULL);
}

void PaletteAux_DrawAllButtons()
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	int nScreenNo = DefaultScreen(pDisplay);
	GC defGC = DefaultGC(pDisplay, nScreenNo);
	Window window = XtWindow(gPAData.wdtPaletteArea);
	XRectangle rcFrame;
	Pixel backPixel;
	int nXPos, nYPos, nWidth, nHeight;
	int nButtonID;
	
	XClearWindow(pDisplay, window);

	nXPos = gPAData.rcPalette.x;
	nYPos = gPAData.rcPalette.y;
	nWidth = gPAData.rcPalette.width;
	nHeight = gPAData.rcPalette.height;
	XtVaGetValues(gPAData.wdtPaletteArea, XmNbackground, &backPixel, NULL);
	XSetForeground(pDisplay, defGC, backPixel);
	XFillRectangle(pDisplay, window, defGC, nXPos, nYPos, nWidth, nHeight);

	XSetForeground(pDisplay, defGC, BlackPixel(pDisplay, nScreenNo));
	XDrawRectangle(pDisplay, window, defGC, nXPos, nYPos, nWidth -1, nHeight-1);

	SetRectangle(&rcFrame, 1, 1, nWidth-2, nHeight-2);
	DrawButtonFrame(gPAData.wdtPaletteArea, &rcFrame, FALSE, 1);
	
	for (nButtonID = FIXBTN_MOVEAREA; nButtonID < FIXBTN_NUM; nButtonID ++) {
		PaletteAux_DrawFixButton(gPAData.pFixButton+nButtonID, TRUE);
	}
}

void PaletteAux_DrawFixButton(FixButton* pFixButton, Boolean bExpose)
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	Window window = XtWindow(gPAData.wdtPaletteArea);
	int nScreenNo = DefaultScreen(pDisplay);
	GC defGC = DefaultGC(pDisplay, nScreenNo);
	XmFontList fontList = gPAData.fontList;
	XmString xmString;
	Pixmap pixmap = 0;
	Pixel  backPixel, forePixel;
	GC gc = 0;
	Window root;
	int nXPos, nYPos, nXEndPos, nYEndPos, nWidth, nHeight;
	unsigned int srcx, srcy, destx, desty, pix_w, pix_h;
	int x_return, y_return;
	int nXMargin, nYMargin;
	char *pIME_Name;
 	int nCursor = CURSOR_NONE;

	if (pFixButton->bShow == FALSE) return;

	if (!bExpose) {
		XtVaGetValues(gPAData.wdtPaletteArea, XmNbackground, &backPixel, NULL);
		XSetForeground(pDisplay, defGC, backPixel);
		XFillRectangle(pDisplay, window, defGC,
				pFixButton->rcDraw.x, pFixButton->rcDraw.y,
				pFixButton->rcDraw.width, pFixButton->rcDraw.height);
	}

	switch(pFixButton->nButtonID) {
	case FIXBTN_MOVEAREA:
		nCursor = CURSOR_MOVE;
		PaletteAux_DrawMoveArea(&pFixButton->rcDraw);
		break;

	case FIXBTN_IMENAME:
		pIME_Name = gPAData.pIME_Name;
		if (pIME_Name == NULL) pIME_Name = DEFAULT_IME_NAME;

		xmString = XmStringCreateLocalized(pIME_Name);

		nXPos = pFixButton->rcDraw.x;
		nYPos = pFixButton->rcDraw.y + 2,
		nWidth = pFixButton->rcDraw.width;

		XtVaGetValues(gPAData.wdtPaletteArea, XmNforeground, &forePixel, NULL);
		XSetForeground(pDisplay, defGC,  forePixel);
		XmStringDraw(pDisplay, window, fontList, xmString, defGC, 
				nXPos, nYPos, nWidth,
				XmALIGNMENT_CENTER, XmSTRING_DIRECTION_L_TO_R, NULL);

		XmStringFree(xmString);
		break;
	
	case FIXBTN_CHARTYPE:
	case FIXBTN_PUNCTTYPE:
	case FIXBTN_KEYBOARD:
	case FIXBTN_OPTIONS:

		PaletteAux_InitPixmaps();

		if (pFixButton->nButtonID == FIXBTN_CHARTYPE) {
			pixmap = gPAData.arrCharTypePmp[pFixButton->nButtonType];
			gc = gPAData.arrCharTypeGC[pFixButton->nButtonType];
		} else if (pFixButton->nButtonID == FIXBTN_PUNCTTYPE) {
			pixmap = gPAData.arrPunctTypePmp[pFixButton->nButtonType];
			gc = gPAData.arrPunctTypeGC[pFixButton->nButtonType];
		} else if (pFixButton->nButtonID == FIXBTN_KEYBOARD) {
			pixmap = gPAData.arrKeyboardPmp[pFixButton->nButtonType];
			gc = gPAData.arrKeyboardGC[pFixButton->nButtonType];
		} else if (pFixButton->nButtonID == FIXBTN_OPTIONS) {
			pixmap = gPAData.arrOptionsPmp[pFixButton->nButtonType];
			gc = gPAData.arrOptionsGC[pFixButton->nButtonType];
		}

		XGetGeometry (pDisplay, pixmap, &root, &x_return, &y_return, &pix_w, &pix_h, &srcx, &srcx);

		nWidth = pFixButton->rcDraw.width;
		nHeight = pFixButton->rcDraw.height;

		nXMargin = (pFixButton->rcDraw.width - 4 - (int)pix_w ) / 2;
		if (nXMargin < 0) nXMargin = 0;

		nYMargin = (pFixButton->rcDraw.height - 4 - (int)pix_h ) / 2;
		if (nYMargin < 0) nYMargin = 0;

		nXPos = pFixButton->rcDraw.x + nXMargin + 2;
		nYPos = pFixButton->rcDraw.y + nYMargin + 2;

		nWidth = (nWidth > pix_w ? pix_w : nWidth);
		nHeight = (nHeight > pix_h ? pix_h : nHeight);

		XSetClipOrigin(pDisplay, gc, nXPos, nYPos);
		XCopyArea(pDisplay, pixmap, window, gc,
			0, 0, nWidth, nHeight, nXPos, nYPos);

		break;
	}

	if (pFixButton->nButtonID != FIXBTN_MOVEAREA) {
		if (pFixButton->bSelected || pFixButton->bPushed)
			DrawButtonFrame(gPAData.wdtPaletteArea, &pFixButton->rcDraw, pFixButton->bPushed, 1);
	}

	SetCursorShape(pDisplay, window, nCursor);

	if (!bExpose)
		XFlush(pDisplay);

}

void PaletteAux_DrawMoveArea(XRectangle* pRect)
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	Window window = XtWindow(gPAData.wdtPaletteArea);
	int nScreenNo = DefaultScreen(pDisplay);
	GC defGC = DefaultGC(pDisplay, nScreenNo);
	XPoint arrPt[3];
	int nXPos, nYPos, nXPosEnd, nYPosEnd;
	int nDeltaWidth = 4;
	int nXadd = 2;
  	
	nXPos = pRect->x + 2;
	nYPos = pRect->y;
	nYPosEnd = pRect->y + pRect->height - 1;
  
	/* Draw Highlight Lines */
	XSetForeground(pDisplay, defGC, WhitePixel(pDisplay, nScreenNo));

  	arrPt[0].x = nXPos; 		arrPt[0].y = nYPosEnd;
	arrPt[1].x = nXPos; 		arrPt[1].y = nYPos;
	arrPt[2].x = nXPos+nXadd; 	arrPt[2].y = nYPos;
	XDrawLines(pDisplay, window, defGC, arrPt, 3, CoordModeOrigin);

	arrPt[0].x = nXPos + nDeltaWidth;
  	arrPt[1].x = nXPos + nDeltaWidth;
	arrPt[2].x = nXPos + nXadd + nDeltaWidth;
	XDrawLines(pDisplay, window, defGC, arrPt, 3, CoordModeOrigin);

	XSetForeground(pDisplay, defGC,  BlackPixel(pDisplay, nScreenNo));

	arrPt[0].x = nXPos+nXadd; 	arrPt[0].y = nYPos;
	arrPt[1].x = nXPos+nXadd; 	arrPt[1].y = nYPosEnd;
  	arrPt[2].x = nXPos; 		arrPt[2].y = nYPosEnd;
	XDrawLines(pDisplay, window, defGC, arrPt, 3, CoordModeOrigin);

	arrPt[0].x = nXPos+nXadd+ nDeltaWidth;
	arrPt[1].x = nXPos+nXadd+ nDeltaWidth;
	arrPt[2].x = nXPos+ nDeltaWidth;
	XDrawLines(pDisplay, window, defGC, arrPt, 3, CoordModeOrigin);
}

void PaletteAux_UpdateStatus()
{
	Display* pDisplay = XtDisplay(gPAData.wdtShell);
	int nScreenNo = DefaultScreen(pDisplay);
	Window window = XtWindow(gPAData.wdtShell);
	int ime_id, need_notify_le;

	DEBUG_printf("PaletteAux_UpdateStatus:  x:0x%x, y: 0x%x, on:%d, engine_id:%d, qjbj:%d, punct:%d\n",
		gPAData.x, gPAData.y, gPAData.on, 
		gPAData.engine_id, gPAData.qjbj, gPAData.punct);
	if (gPAData.on == False) {
		XtUnmapWidget(gPAData.wdtShell);
		return;
	}
	
	if (gPAData.x == 0)
		gPAData.x = 10;
	if (gPAData.y == 0)
		gPAData.y = DisplayHeight(pDisplay, nScreenNo) - 50;

	XtVaSetValues(gPAData.wdtShell, XmNx, gPAData.x, XmNy, gPAData.y, NULL);
	XtMapWidget(gPAData.wdtShell);
	xaux_ext_skip_taskbar_hint(pDisplay, window, True);
	XRaiseWindow(pDisplay, window);
	XFlush(pDisplay);

	PaletteAux_ChangeQjBj(gPAData.qjbj);
	PaletteAux_ChangePunct(gPAData.punct);

	if (SelectedIMEList.nIME_Num <= 0) {
		PaletteAux_CalcSize();
		PaletteAux_DrawAllButtons();
		return;
	}

	need_notify_le = False;
	ime_id = get_ime_id_by_engine_id(&SelectedIMEList, gPAData.engine_id);
	if (ime_id == -1 || ime_id >= SelectedIMEList.nIME_Num) {
		ime_id = 0;
		need_notify_le = True;
	}

	/* Change auxiliary window input method display information */
	PaletteAux_ChangeIME(ime_id, need_notify_le);
}

void PaletteAux_ChangeIME(int nIME_id_new, int bNeedNotifyLE)
{
	int nEngineID, nIME_Num;
	char *pIME_Name;

	DEBUG_printf("PaletteAux_ChangeIME: change to ime:%d\n", nIME_id_new);
	nIME_Num = SelectedIMEList.nIME_Num;

	if (nIME_Num <= 0) return;
	if (nIME_id_new < 0) return;
	if (nIME_id_new >= nIME_Num) return;

	if (bNeedNotifyLE == True) {
		nEngineID = SelectedIMEList.arrIME_Base[nIME_id_new]->engine_id;
		gPAData.engine_id = nEngineID;

		PaletteAux_Switch_LE_Engine_Request(nEngineID);
		return;
	}

	pIME_Name = (char *)SelectedIMEList.arrIME_Base[nIME_id_new]->cname;

	gPAData.pIME_Name = pIME_Name;
	PaletteAux_CalcSize();
	PaletteAux_DrawAllButtons();
}

void PaletteAux_ChangePunct(int nPunct)
{
	FixButton* pFixButton;

	pFixButton = gPAData.pFixButton+FIXBTN_PUNCTTYPE;
	pFixButton->nButtonType = (nPunct ? 1 : 0);

	PaletteAux_DrawFixButton(pFixButton, FALSE);
}

void PaletteAux_ChangeQjBj(int nQjBj)
{
	FixButton* pFixButton;

	pFixButton = gPAData.pFixButton+FIXBTN_CHARTYPE;
	pFixButton->nButtonType = nQjBj ? 1 : 0;

	PaletteAux_DrawFixButton(pFixButton, FALSE);
}

Widget PaletteAux_CreatePopupMenu(char **ppArrMenuName, int nMenuNum, XtCallbackProc callback)
{
	Widget wdtMenu, wdtButton;
	char menu_name[256];
	int i;

	wdtMenu = (Widget) XmCreatePopupMenu(gPAData.wdtPaletteArea, "MenuList", NULL, 0);
	XtAddCallback(wdtMenu, XmNunmapCallback, MenuUnMapCallback, NULL);

	for(i = 0; i<nMenuNum; i++) {
		if (ppArrMenuName[i]) {
			sprintf(menu_name, " %s ", ppArrMenuName[i]);
			wdtButton = (Widget)XtVaCreateManagedWidget(menu_name, 
				xmPushButtonWidgetClass, wdtMenu, 
				NULL);
			XtAddCallback(wdtButton, XmNactivateCallback, callback, (XtPointer)i);
		} else {
			wdtButton = XtVaCreateManagedWidget("separator", 
				xmSeparatorWidgetClass, wdtMenu,
				NULL);
		}
	}

	XtVaSetValues(wdtMenu, XmNmenuPost, "<Btn1Down>", XmNwhichButton, 1, NULL);
	return(wdtMenu);
}

void MenuUnMapCallback(Widget widget, XtPointer pClientData, XtPointer pCallData)
{
	FixButton* pFixButton;
	XPoint ptButton;
	int nXPos, nYPos;
	Boolean bInClient;

	/* close the current opened menu */
	if (gPAData.wdtSelectMenu) {
/*
 		XtVaSetValues(gPAData.wdtSelectMenu, XmNmenuPost, "<Btn3Down>", XmNwhichButton, 3, NULL);
*/
 		gPAData.wdtSelectMenu = 0;
 	}
 		
	/* redraw the pressed button, and make the button unactivate. */
  	if (gPAData.pPressFixButton) {
    		gPAData.pPressFixButton->bPushed = FALSE;
    		PaletteAux_DrawFixButton(gPAData.pPressFixButton, FALSE);
    		gPAData.pPressFixButton = NULL;
  	} 

	/* check pointer is in the palette, if yes, activate the select button */
  	if (bInClient = GetClientPointer(gPAData.wdtPaletteArea, &nXPos, &nYPos)) {
		SetPoint(&ptButton, nXPos, nYPos);  
		pFixButton = PaletteAux_GetFixButtonByPoint(ptButton);
		if (pFixButton != NULL) {
      			gPAData.pSelectFixButton = pFixButton;
      			gPAData.pSelectFixButton->bSelected = TRUE;
      			PaletteAux_DrawFixButton(gPAData.pSelectFixButton, FALSE);
  		}
	}
	
	/* if the activated button has menu, open the menu */
	if (gPAData.pSelectFixButton && gPAData.pSelectFixButton->wdtMenu) {
/*
 		XtVaSetValues(gPAData.pSelectFixButton->wdtMenu, XmNmenuPost, "<Btn1Down>", XmNwhichButton, 1, NULL);
*/
 		gPAData.wdtSelectMenu = gPAData.pSelectFixButton->wdtMenu;
	}
}

void PaletteAux_CreateIMEListMenu()
{
	FixButton* pFixButton;
	char *pArrMenuName[MAX_ENGINE_NUM];
	int i, nIME_Num, nMenuNum = 0;

	nIME_Num = SelectedIMEList.nIME_Num;
	if (nIME_Num <= 0) return;

	for(i = 0; i < nIME_Num; i ++) {
		if (SelectedIMEList.arrIME_Base[i]->status == ENGINE_NOT_INSTALLED) continue;
		pArrMenuName[nMenuNum] = (char *)SelectedIMEList.arrIME_Base[i]->cname;
		nMenuNum ++;
	}

	pFixButton = (gPAData.pFixButton + FIXBTN_IMENAME);

	if (pFixButton->wdtMenu) XtDestroyWidget(pFixButton->wdtMenu);

	pFixButton->wdtMenu = PaletteAux_CreatePopupMenu(pArrMenuName, nMenuNum, IMEMenuValueChangedCallback);
}

void IMEMenuValueChangedCallback(Widget widget, XtPointer pClientData, XtPointer pCallData)
{
	int nIME_id_new = (int)pClientData;
	PaletteAux_ChangeIME(nIME_id_new, True);
}

void PaletteAux_CreateVKeyboardMenu()
{
	FixButton* pFixButton;
	int i;

	DEBUG_printf("PaletteAux_CreateVKeyboardMenu() \n");
	if (gVKB_Name_Num <= 0) return;

	pFixButton = (gPAData.pFixButton + FIXBTN_KEYBOARD);

	if (pFixButton->wdtMenu) XtDestroyWidget(pFixButton->wdtMenu);

	VKB_Name_List_Create(gPAData.engine_id);
	pFixButton->wdtMenu = (Widget)PaletteAux_CreatePopupMenu(gVKB_Name_List, 
					gVKB_Name_Num, KeyboardMenu_cb);
}

void KeyboardMenu_cb(Widget widget, XtPointer pClientData, XtPointer pCallData)
{
	int nKeyboardID = (int)pClientData;

	DEBUG_printf("KeyboardMenu_cb: nKeyboardID:%d\n", nKeyboardID);

	if (nKeyboardID < 0 || nKeyboardID >= gVKB_Name_Num) return;

	/* if nKeyboardID is gVKB_Name_Num - 1, mean need close the keyboard */
	if (nKeyboardID == gVKB_Name_Num - 1)
		nKeyboardID = -1;
	PaletteAux_Show_KeyboardAux_Request(nKeyboardID);
}

void PaletteAux_CreateUtilitiesMenu()
{
	FixButton* pFixButton;
	char **pArrMenuName;
	int i;

	if (gUtilitiesNum <= 0) return;

	pArrMenuName = (char **)calloc(gUtilitiesNum, sizeof(char *));

	for (i=0; i<gUtilitiesNum; i++) {
		pArrMenuName[i] = (char *)strdup(gUtilitiesItem[i]->label_str);
	}

	pFixButton = (gPAData.pFixButton + FIXBTN_OPTIONS);
	pFixButton->wdtMenu = (Widget)PaletteAux_CreatePopupMenu(pArrMenuName, gUtilitiesNum, UtilitiesMenu_cb);

	for (i=0; i<gUtilitiesNum; i++) {
		if (pArrMenuName[i]) free((char *)pArrMenuName[i]);
	}
	free((char *)pArrMenuName);
}

void UtilitiesMenu_cb(Widget widget, XtPointer pClientData, XtPointer pCallData)
{
	int nUtilitiesID = (int)pClientData;
	char *command_str;

	if (nUtilitiesID < 0 || nUtilitiesID >= gUtilitiesNum) return;

	if (nUtilitiesID >= NORMAL_UTILITIES_NUM) {
		command_str = (char *)gUtilitiesItem[nUtilitiesID]->command_str;
		if (command_str && *command_str) {
			DEBUG_printf("PaletteAux_StartAction_Request: command:%s\n", command_str);
			PaletteAux_StartAction_Request(command_str);
		}
	} else {
		switch (nUtilitiesID) {
			case UTILITY_IME_SELECTION:
				PaletteAux_Show_SelectAux_Request();
				break;
			case UTILITY_IME_OPTION:
				PaletteAux_Show_OptionAux_Request();
				break;
			case UTILITY_IME_LOOKUP:
				PaletteAux_Show_LookupAux_Request();
				break;
		}
	}
}
