 /*
  * Khoros: $Id: wmprotocol.c,v 1.3 1992/03/20 22:50:18 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: wmprotocol.c,v 1.3 1992/03/20 22:50:18 dkhoros Exp $";
#endif

 /*
  * $Log: wmprotocol.c,v $
 * Revision 1.3  1992/03/20  22:50:18  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "xvutils.h"	


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    	    file name: wmprotocol.c			<<<<
   >>>>								<<<<
   >>>>		  Install the appropriate action for the 	<<<<
   >>>>		desired window manager protocol.		<<<<
   >>>>								<<<<
   >>>>								<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


/*
 *  structure used by the xvf_protocol_delete()
 */
typedef struct _protocol
{
	Atom	atom;
	Widget  widget;
	void	(*routine)();
	caddr_t clientData;

	struct  _protocol *next, *prev;
} xvf_protocol;


static void protocol_handler();
static void add_protocol_handler();
static xvf_protocol *protocol_list = NULL;
static XtTranslations wm_translations;

static char translations[] = "<Message>WM_PROTOCOLS: protocol()";
static XtActionsRec actions[] = {
	{ "protocol", protocol_handler }
};


/************************************************************
*
*  Routine Name: static init_protocol_handler
*
*      Purpose:  Adds the specified entry from the protocol
*		 list and frees memory.
*
*        Input:
*
*       Output:
*
*   Written By:   Mark Young
*
*************************************************************/


static void init_protocol_handler()
{
	static int init = FALSE;

	if (init == FALSE)
	{
	   XtAppAddActions(xvf_app_context, actions, XtNumber(actions));
	   wm_translations = XtParseTranslationTable(translations);
	   init = TRUE;
	}
}



/************************************************************
*
*  Routine Name: static protocol_handler
*
*      Purpose:  Adds the specified entry from the protocol
*		 list and frees memory.
*
*        Input:
*
*       Output:
*
*   Written By:   Mark Young
*
*************************************************************/


static void protocol_handler(w, event, params, num_params)

Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
	Atom	     atom;
	caddr_t	     data;
	void	     (*routine)();
	xvf_protocol *entry;


	if (event->type == ClientMessage)
	   atom = event->xclient.data.l[0];
	else
	   atom = (Atom) -1;

	entry = protocol_list;
	while (entry != NULL)
	{
	   if (entry->widget == w && (entry->atom == atom || atom == (Atom) -1))
	      break;

	   entry = entry->next;
	}

	if (entry == NULL)
	   return;

	if (entry->routine != NULL)
	{
	   routine = entry->routine;
	   data	   = entry->clientData;
	   (void) routine(w, data);
	}
}



/************************************************************
*
*  Routine Name: static add_protocol_entry
*
*      Purpose:  Adds the specified entry from the protocol
*		 list and frees memory.
*
*        Input:
*
*       Output:
*
*   Written By:   Mark Young
*
*************************************************************/


static xvf_protocol *add_protocol_entry(atom, widget, routine, clientData)

Atom	atom;
Widget	widget;
void	(*routine)();
caddr_t clientData;
{
	xvf_protocol *entry;
	EventMask    mask = StructureNotifyMask;

	/*
	 *  create a new entry in which to record the protocol information.
	 *  This is where a widget records it's atom and callback information.
	 */
	if (!(entry = (xvf_protocol *) calloc(1, sizeof(xvf_protocol))))
	{
	   return(NULL);
	}
	entry->next   = protocol_list;
	entry->prev   = NULL;

	if (protocol_list != NULL)
	   protocol_list->prev = entry;

	protocol_list	  = entry;
	entry->atom	  = atom;
	entry->routine	  = routine;
	entry->clientData = clientData;
	entry->widget	  = widget;
	return(entry);
}



/************************************************************
*
*  Routine Name: static remove_protocol_entry
*
*      Purpose:  Removes the specified entry from the protocol
*		 list and frees memory.
*
*        Input:  entry  -  the entry to be removed from the
*			   list.
*
*       Output:
*
*   Written By:   Mark Young
*
*************************************************************/


static remove_protocol_entry(entry)

xvf_protocol  *entry;
{
	EventMask    mask = StructureNotifyMask;


	if (entry->next == NULL && entry->prev == NULL)
	{
	   protocol_list =  NULL;
	}
	else if (entry->prev == NULL)
	{
	   entry->next->prev = NULL;
	   protocol_list = entry->next;
	}
	else if (entry->next == NULL)
	{
	   entry->prev->next = NULL;
	}
	else
	{
	   entry->prev->next = entry->next;
	   entry->next->prev = entry->prev;
	}
	free(entry);
}



/************************************************************
*
*  Routine Name: xvf_add_protocol_delete
*
*      Purpose:  
*
*        Input:
*
*       Output:
*
*   Written By:   Mark Young
*
*    Called By:  application programmer
*
*************************************************************/


xvf_add_protocol_handler(widget, protocol, routine, clientData)

Widget	widget;
char	*protocol;
void	(*routine)();
caddr_t	clientData;
{
	Atom	     atom;
	xvf_protocol *entry;

	(void) init_protocol_handler();
	XtOverrideTranslations(widget, wm_translations);
	atom = XInternAtom(XtDisplay(widget), protocol, False);
	entry = add_protocol_entry(atom, widget, routine, clientData);
	if (entry == NULL)
	    return;

	/*
	 *  yuck poo.  kludge city 
	 *
	 *  If the widget isn't realized then we add an event handler that
	 *  will set the XSetWMProtocols() at some later date.
	 */
	if (XtIsRealized(widget) == False)
	{
	   XtAddEventHandler(widget, StructureNotifyMask, False,
			add_protocol_handler, (caddr_t) entry);
	}
	else
	   (void) XSetWMProtocols(XtDisplay(widget), XtWindow(widget), &atom,1);
}

static void  add_protocol_handler(widget, clientData, event)

Widget  widget;
caddr_t clientData;
XEvent  *event;
{
	xvf_protocol *entry = (xvf_protocol *) clientData;


	if (entry != NULL)
	{
	   (void) XSetWMProtocols(XtDisplay(widget), XtWindow(widget),
			&entry->atom, 1);
	}
	XtRemoveEventHandler(widget, StructureNotifyMask, False,
			add_protocol_handler, (caddr_t) entry);
}



/************************************************************
*
*  Routine Name: xvf_remove_protocol_handler
*
*      Purpose:  
*
*        Input:
*
*       Output:
*
*   Written By:   Mark Young
*
*    Called By:  application programmer
*
*************************************************************/


xvf_remove_protocol_handler(widget, protocol, routine, clientData)

Widget	widget;
char	*protocol;
void	(*routine)();
caddr_t	clientData;
{
	Atom	     atom;
	xvf_protocol *entry;


	if (protocol != NULL)
	   atom = XInternAtom(XtDisplay(widget), protocol, False);
	else
	   atom = AnyPropertyType;

	entry = protocol_list;
	while (entry != NULL)
	{
	   if (entry->clientData == clientData && entry->routine == routine &&
	       entry->widget == widget && entry->atom == atom)
	   {
	      break;
	   }
	   entry = entry->next;
	}

	if (entry != NULL)
	   remove_protocol_entry(entry);
}
