/* PowerWindows Cx.c */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>
#include <graphics/modeid.h>
#include <libraries/commodities.h>
#include <utility/utility.h>

#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/commodities_lib.h>
#include <clib/alib_protos.h>

#pragma header

#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "PowerWindows.h"


enum {KEY_ICONFRONT=1,
		KEY_ICONBACK,
		KEY_DEICONIFYALL,
		KEY_WINDOWSIN,
		KEY_WINDOWSINALL,
		KEY_ICONIFY,
		KEY_PATCHSCR,
		KEY_UNPATCHSCR};

#define IDT_FRONT 1
#define IDT_BACK 2

#define WININ_SINGLE 1
#define WININ_ALL 2

static struct NewBroker MyNewBroker;
static struct Window *ActiveWin;
static struct Screen *ActiveScr;

static CxObj *MyBroker;

static void CreateHotKey(char *descr,LONG id)
{
	CxObj *obj;
	LONG Fehler;

	if (descr[0])
	{
		if (!(obj=HotKey(descr,BrokerMP,id)))
		{
			Ende("Cx-Hotkey-Object? Check Hotkey-Description!");
		}
		if ((Fehler=CxObjError(obj)))
		{
			if (Fehler==COERR_BADFILTER)
			{
				Ende("Bad Hotkey-Description!");
			}
			Ende("Cx-Hotkey-Object error!");
		}
		AttachCxObj(MyBroker,obj);
	}
}

void InitCx(void)
{
	if (!(BrokerMP=CreateMsgPort()))
	{
		Ende("Broker-MsgPort?");
	}
	CxMask=(1L << (BrokerMP->mp_SigBit));
	
	MyNewBroker.nb_Version=NB_VERSION;
	MyNewBroker.nb_Name="PowerWindows";
	MyNewBroker.nb_Title="PowerWindows "_FullProgVersionS_" ©1997 Georg Steger";
	MyNewBroker.nb_Descr="License to hack. Move Wins out of Screen";
	MyNewBroker.nb_Unique=NBU_UNIQUE|NBU_NOTIFY;
	MyNewBroker.nb_Flags=0;
	MyNewBroker.nb_Pri=0;
	MyNewBroker.nb_Port=BrokerMP;
	
	if (!(MyBroker=CxBroker(&MyNewBroker,0)))
	{
		Ende("Cx-Broker-Object?");
	}	
	CreateHotKey(MyConfig.IconFrontHotKey,KEY_ICONFRONT);
	CreateHotKey(MyConfig.IconBackHotKey,KEY_ICONBACK);
	CreateHotKey(MyConfig.DeIconifyAllHotKey,KEY_DEICONIFYALL);
	CreateHotKey(MyConfig.WindowsInHotKey,KEY_WINDOWSIN);
	CreateHotKey(MyConfig.WindowsInAllHotKey,KEY_WINDOWSINALL);
	CreateHotKey(MyConfig.IconifyHotKey,KEY_ICONIFY);
	CreateHotKey(MyConfig.PatchScrHotKey,KEY_PATCHSCR);
	CreateHotKey(MyConfig.UnPatchScrHotKey,KEY_UNPATCHSCR);
	ActivateCxObj(MyBroker,TRUE);
}

void EndCx(void)
{
	CxMsg *msg;
	
	if (MyBroker)
	{
		DeleteCxObjAll(MyBroker);MyBroker=0;
	}
	if (BrokerMP)
	{
		while ((msg=(CxMsg *)GetMsg(BrokerMP)))
		{
			ReplyMsg((struct Message *)msg);
		}
		DeleteMsgPort(BrokerMP);BrokerMP=0;
	}
}

/* GetActiveScreenEntry() --> wenn <>0 muss ScreenListSemaphore released werden, sonst nicht!! */

static struct ScreenEntry *GetActiveScreenEntry(void)
{
	struct ScreenEntry *se=0;
	ULONG ilock;
	
	ilock=LockIBase(0);
	ActiveWin=IntuitionBase->ActiveWindow;
	ActiveScr=IntuitionBase->ActiveScreen;
	UnlockIBase(ilock);
	
	if (ActiveScr)
	{
		ObtainSemaphoreShared(&ScreenListSemaphore);
		if (!(se=FindScreen(&ActiveScr->LayerInfo)))
		{
			ReleaseSemaphore(&ScreenListSemaphore);
		}
	}
	
	return se;
}

static void DoIconsDepth(WORD typ)
{
	struct ScreenEntry *se;
	struct Window *win;
	
	if (MyConfig.IconDepth!=ID_ALWAYSFRONT)
	{
		if ((se=GetActiveScreenEntry()))
		{					
			win=ActiveScr->FirstWindow;
			while (win)
			{
				if (win->WLayer->BackFill== &IconLayerHook)
				{
					switch(typ)
					{
						case IDT_FRONT:
							WindowToFront(win);
							break;
							
						case IDT_BACK:
							WindowToBack(win);
							break;
					}
				}
				win=win->NextWindow;
			}
			
			ReleaseSemaphore(&ScreenListSemaphore);
		}
	}
}

static void DoDeIconifyAll(void)
{
	struct ScreenEntry *se;
	struct Window *win;
	struct Gadget *gad;

	if ((se=GetActiveScreenEntry()))
	{

		win=ActiveScr->FirstWindow;
		while (win)
		{
			if (win->WLayer->BackFill== &IconLayerHook)
			{
				if ((gad=FindIconGadget(win)))
				{
					DoMethod((Object *)gad,CGM_DeIconify,win);
				}
			}
			win=win->NextWindow;
		}
	
		ReleaseSemaphore(&ScreenListSemaphore);
	}
}

static void WindowsIN(WORD typ)
{
	struct Window *win;
	struct Rectangle oscan;
	struct ScreenEntry *se;

	ULONG id;
	WORD	x1,y1;

	if ((se=GetActiveScreenEntry()))
	{
	
		win=ActiveWin;
	
		if (win)
		{
			switch(typ)
			{
				case WININ_SINGLE:
					if (!FindIconWindow(win))
					{
						if (((win->LeftEdge+win->Width)<=se->se_NormalWidth) &&
						    ((win->TopEdge+win->Height)<=se->se_NormalHeight))
						{
							if (!(win->Flags&WFLG_BACKDROP))
							{
								x1=(se->se_NormalWidth - win->Width)/2;
								y1=(se->se_NormalHeight - win->Height)/2;
			
								id=GetVPModeID(ViewPortAddress(ActiveWin));
								if (id != INVALID_ID)
								{
									if (QueryOverscan(id,&oscan,OSCAN_TEXT))
									{
										x1= (oscan.MaxX-oscan.MinX+1-win->Width)/2  - ActiveScr->LeftEdge;
										y1= (oscan.MaxY-oscan.MinY+1-win->Height)/2 - ActiveScr->TopEdge;
									}
								}
								if (x1<0) x1=0;
								if (y1<0) y1=0;
								
								MoveWindow(win,x1-win->LeftEdge,y1-win->TopEdge);
								WindowToFront(win);
								ActivateWindow(win);
							} // if (!(win->Flags&WFLG_BACKDROP))
						} else {
							x1=(win->LeftEdge+win->Width)<=se->se_NormalWidth ? win->LeftEdge : se->se_NormalWidth - win->Width;
							y1=(win->TopEdge+win->Height)<=se->se_NormalHeight ? win->TopEdge : se->se_NormalHeight - win->Height;
							if (x1<0) x1=0;
							if (y1<0) y1=0;

							MoveWindow(win,x1-win->LeftEdge,y1-win->TopEdge);
						}
					}	/* if (!FindIconWindow(win)) */
					break;
				
				case WININ_ALL:
					win=ActiveScr->FirstWindow;
					while (win)
					{
						if (!FindIconWindow(win))
						{
							x1=((win->LeftEdge+win->Width)<=se->se_NormalWidth) ? win->LeftEdge : se->se_NormalWidth - win->Width;
							y1=((win->TopEdge+win->Height)<=se->se_NormalHeight) ? win->TopEdge : se->se_NormalHeight - win->Height;
							if (x1<0) x1=0;
							if (y1<0) y1=0;
		
							if ((x1 != win->LeftEdge) || (y1 != win->TopEdge))
							{
								MoveWindow(win,x1-win->LeftEdge,y1-win->TopEdge);
							}
						}
						win=win->NextWindow;
					}
					break;
	
			}
		}
		ReleaseSemaphore(&ScreenListSemaphore);
	} /* if se=GetActiveScreenEntry */
}

static void IconifyMe(void)
{
	struct Gadget *gad;
	struct Window *win;
	ULONG	ilock;
	
	ilock=LockIBase(0);
	win=IntuitionBase->ActiveWindow;
	UnlockIBase(ilock);
	
	if (win)
	{
		if ((gad=FindIconifyGadget(win)))
		{
			DoMethod((Object *)gad,CGM_Iconify);
		}
	}
	
}

static void DoScreenPatch(BOOL activate)
{
	struct ScreenEntry *se=GetActiveScreenEntry();

	if (activate)
	{
		if (se)
		{
			ReleaseSemaphore(&ScreenListSemaphore);
		} else {
			After_OpenScreen(ActiveScr);
			ScanWindows(ActiveScr);
		}

	} else {
		if (se)
		{
			ReleaseSemaphore(&ScreenListSemaphore);
			NEW_CloseScreen(ActiveScr);
		}
	}
}

void HandleHotKey(LONG key)
{
	switch (key)
	{
		case KEY_ICONFRONT:
			DoIconsDepth(IDT_FRONT);
			break;

		case KEY_ICONBACK:
			DoIconsDepth(IDT_BACK);
			break;

		case KEY_DEICONIFYALL:
			DoDeIconifyAll();
			break;

		case KEY_WINDOWSIN:
			WindowsIN(WININ_SINGLE);
			break;

		case KEY_WINDOWSINALL:
			WindowsIN(WININ_ALL);
			break;

		case KEY_ICONIFY:
			IconifyMe();
			break;
		
		case KEY_PATCHSCR:
			DoScreenPatch(TRUE);
			break;

		case KEY_UNPATCHSCR:
			DoScreenPatch(FALSE);
			break;
		
	}
}

void HandleCx(void)
{
	LONG msgid;
	ULONG msgtype;
	CxMsg *msg;

	while ((msg=(CxMsg *)GetMsg(BrokerMP)))
	{
		msgid=CxMsgID(msg);
		msgtype=CxMsgType(msg);

		switch (msgtype)
		{
			case CXM_COMMAND:
				switch (msgid)
				{
					case CXCMD_DISABLE:
						ActivateCxObj(MyBroker,FALSE);
						CxInactive=TRUE;
						break;

					case CXCMD_ENABLE:
						ActivateCxObj(MyBroker,TRUE);
						CxInactive=FALSE;
						break;

					case CXCMD_UNIQUE:
						break;

					case CXCMD_KILL:
						QuitMe=TRUE;
						break;
				}
				break;

			case CXM_IEVENT:
				HandleHotKey(msgid);
				break;
		}
		ReplyMsg((struct Message *)msg);
	}
}

						
