/* 
 *  @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: BeginSession.c /main/7 1995/07/14 11:31:26 drk $"
#endif
#endif
/***********************************************************************
  	@(#)BeginSession.c	1.8	Date:03/04/91
  	Author: TAT
	History:
            05/24/90 SJS add to sccs
            08/30/90 SJS cosmetic changes, exit on error
            10/03/90 SJS make keycode initialization changes
	Calls:

	Summary:
            Initializes the input synthesis libraries local copies of display 
        and application context pointers.  It also sets up local-globals for
        the screen and the root_window, and establishes pointers to functions 
        which need to be defined external to this library.  This remote function
        referencing is necessary since this library has been designed to know
        nothing internally about the widget set which it interacts with.

	    One further addition is to do all the key code lookup *1* time.
	This is a change from looking the key codes up every time a keyclick
	needs to be done.

        INPUTS:
            display_in     -  the display that is connected to
            app_context_in -  the Xt application context
            num_objects    -  number of unique objects defined
            generate_objects_func -a function which updates the object hierarchy
            get_object_type_name_func - a function which returns the object
                                        type name
            get_widget_class_name_func - a function which returns widget class
                                         name
            trace_msg_func - a function which prints out a trace message
            warning_msg_func - a function which prints out a warning message
            error_msg_func - a function which prints out an error message
        
        OUTPUTS:
            none

        RETURNS:
            nothing
************************************************************************/
#define DECLARE_XISLIB_GLOBALS_HERE

#include <AutoMessages.h>
#include "xislib.h"
#include <Xm/XmP.h>		/* for XmKeyBinding */

#define XK_MISCELLANY

#include <X11/keysymdef.h>


void AutoGetAdditionalModifier();


void  xisBeginSession(display_in,app_context_in,num_object_types,
                      generate_objects_func,
                      get_object_type_name_func, get_widget_class_name_func,
                      window_to_widget_func,
                      trace_msg_func, warning_msg_func, error_msg_func)
Display *display_in;
XtAppContext app_context_in;
int num_object_types;
void (*generate_objects_func) ( /* XisObjectRecord *root_obj, Root object */ );

char *(*get_object_type_name_func) ( /* int object_type
                                        Object type code (user defined) */ );

char *(*get_widget_class_name_func) ( /* Widget widget
                                         Widget to find lowest class name*/ );

Widget (*window_to_widget_func) ( /* Window window
                                     Window to find widget for */ );

void (*trace_msg_func)();      /* These three funcs have params like printf */
void (*warning_msg_func)();
void (*error_msg_func)();
{
    static char routine_name[] = "xisBeginSession():";
    int i;
    char msg_string[125];

    /* Validate incoming parameters */

    xisTraceMsg = trace_msg_func;
    xisWarningMsg = warning_msg_func;
    xisErrorMsg = error_msg_func;

    if (error_msg_func == 0) {
        fprintf(stderr, "%s called with NULL error_msg_func\n", routine_name);
        exit(-1);
    }
    if (display_in == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG115], routine_name);
        AutoError(msg_string);
        
    }
    if (app_context_in == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG104], routine_name);
        AutoError(msg_string);
        
    }
    if (generate_objects_func == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG108], routine_name);
        AutoError(msg_string);
        
    }
    if (get_object_type_name_func == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG106], routine_name);
        AutoError(msg_string);

    }
    if (get_widget_class_name_func == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG110], routine_name);
        AutoError(msg_string);

    }
    if (window_to_widget_func == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG111], routine_name);
        AutoError(msg_string);
    }
    if (trace_msg_func == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG112], routine_name);
        AutoError(msg_string);
    }
    if (warning_msg_func == 0) {
        sprintf (msg_string, _AutoMessages[WARNMSG113], routine_name);
        AutoError(msg_string);
    }
    xisAppContext = app_context_in;
    xisDisplay = display_in;

    xisScreen = XDefaultScreen(xisDisplay);
    xisRootWindow = XDefaultRootWindow(xisDisplay);

    xisNumObjectTypes = num_object_types;

    xisGenerateObjects = generate_objects_func;
    xisGetObjectTypeName = get_object_type_name_func;
    xisGetWidgetClassName = get_widget_class_name_func;
    xisWindowToWidget = window_to_widget_func;

    /* Initialize the Root Object */
    xisObjects[0].in_use = 1;
    xisObjects[0].id.window = xisRootWindow;
    xisObjects[0].id.widget = NULL;
    xisObjects[0].id.object_type = 0; /* corresponds to oUserDefined */
    xisObjects[0].id.instance = 0;
    xisObjects[0].x = 0;
    xisObjects[0].y = 0;
    xisObjects[0].width = DisplayWidth(xisDisplay,xisScreen);
    xisObjects[0].height = DisplayHeight(xisDisplay,xisScreen);
    xisObjects[0].parent = NULL;
    xisObjects[0].first_child = NULL;
    xisObjects[0].next_sibling = NULL;
    xisObjects[0].proc_InformExpectedActions = NULL;

    xisMaxObjectNum++;           /* "Alloc" the object */


} /* end xisBeginSession */




static void 
CvtVirtualToActualKeysym( dpy, virtKeysym, actualKeysymRtn, modifiersRtn )
     Display *dpy ;
     KeySym virtKeysym ;
     KeySym *actualKeysymRtn ;
     Modifiers *modifiersRtn ;
{
  int num_keys;
  XmKeyBinding keys;

  /* Initialize the return parameters. */
  *actualKeysymRtn = NoSymbol;
  *modifiersRtn = 0;

  /* Arbitrarily return the first keysym in the list. */
  num_keys = XmeVirtualToActualKeysyms(dpy, virtKeysym, &keys);
  if (num_keys > 0)
    {
      *actualKeysymRtn = keys[0].keysym;
      *modifiersRtn = keys[0].modifiers;
    }
  XtFree((char*) keys);
}



void xisInitKeyCodes(sh_widget)
Widget sh_widget ;
{

    KeySym   tmp_key, tmp_key2 ;
    int i,j ;
    int x,y ;
    Boolean collision ;
    Modifiers	new_modifier;
    char msg_string[125];

    /* Initialize all keycodes declared */

    for(i=0; i< _MaxKey; i++) {
        tmp_key = XStringToKeysym(xisKeySymName[i].key_name) ;

        /* if it is an osf key then translate it again */
        if ( strncmp(xisKeySymName[i].key_name,"osf",3) == 0 )
            CvtVirtualToActualKeysym(xisDisplay,tmp_key,&tmp_key2,
				     &xisKeySymName[i].modifier) ;
        else /* just copy it over */
           tmp_key2 = tmp_key ;

        xisKeySymName[i].code = XKeysymToKeycode(xisDisplay,tmp_key2) ;
	/*
	 * The following two lines added for automation.
	 */
	AutoGetAdditionalModifier(xisDisplay, tmp_key2, &new_modifier);
	xisKeySymName[i].modifier |= new_modifier;

        (*xisTraceMsg)(" keycode number %2d: %s -> %d -> %d/%d --> %d \n",
               i,xisKeySymName[i].key_name,tmp_key,tmp_key2,
                      xisKeySymName[i].modifier,xisKeySymName[i].code) ;
  
       
        /* a key is undefined */
        if (( i != 0 ) && ( i != (_MaxKey-1) ))  {
           if (( tmp_key == NoSymbol ) || ( tmp_key2 == NoSymbol )) {
	     sprintf (msg_string,_AutoMessages[WARNMSG114],
		      xisKeySymName[i].key_name) ;
             AutoMessage (msg_string);

	   }   
         }
      }
    
         /* look for duplicate key bindings */

        collision = False ;
        for(i=1;i<(_MaxKey-1);i++) {
           for(j=i;j<(_MaxKey-1);j++) {
              if ( i != j ) {
                 x = (int)xisKeySymName[i].code ;
                 y = (int)xisKeySymName[j].code ;
                 if ( x == y ) {
                    collision = True ;
		  }
	       }
	    }
	 }

} /* end xisInitKeyCodes */


/*
 *	The following routine has been added to get the group modifier when
 *	needed. If the key modmap is arranged in more than two columns
 *	(i.e. when the no. of keysyms_per_keycode is greater than two), to
 *	send the key event corresponding to any keysym in the third or
 *	fourth column of the modmap, it is necessary to add the group modifier
 *	to the current modifier switch in order for the server to interpret
 *	the event correctly. This group modifier is available through the
 *	variable 'mode_switch' in the display, which gets initialized when
 *	the internal modmap for X is getting initialized. (InitModMap() in
 *	XKeyBind.c).
 */
void AutoGetAdditionalModifier(dpy, ks, new_mod)
Display		*dpy;
KeySym		ks;
Modifiers	*new_mod;
{
    register int i, j, n;
    Boolean	done = False;
    KeySym	ksym, *ks_list;
    XModifierKeymap *mod_keymap;
    int		min_keycode_rtn, max_keycode_rtn ;
    int		keysyms_per_keycode_rtn ;
    int		keycode_count ;
    unsigned int  mode_switch;

    *new_mod = 0;

/*
 * Fix for CR 5663 -- Use function interface to retrieve
 * publicly accessible Display info.
 */
    XDisplayKeycodes( dpy, &min_keycode_rtn, &max_keycode_rtn ) ;
    keycode_count = max_keycode_rtn - min_keycode_rtn + 1 ;
    if (!( ks_list =
	   XGetKeyboardMapping( dpy, min_keycode_rtn, keycode_count,
				&keysyms_per_keycode_rtn ) ) )
		return; 

/*
 * Fix for CR 5663 -- Since X11R5 made the display mode_switch
 * variable opaque, we will have to regenerate it here, using
 * the same algorithm as in XKeyBind.c.
 */

    mod_keymap = XGetModifierMapping( dpy );
    /* Find any Mod<n> modifier acting as the Group modifier */
    mode_switch = 0;
    n = 8 * mod_keymap->max_keypermod;
    for (i = 3*mod_keymap->max_keypermod; i < n; i++) {
        for (j = 0; j < keysyms_per_keycode_rtn; j++) {
            ksym = XKeycodeToKeysym(dpy, mod_keymap->modifiermap[i], j);
            if (ksym == XK_Mode_switch)
                mode_switch |= 1 << (i / mod_keymap->max_keypermod);
        }
    }

    for (i = min_keycode_rtn; i <= max_keycode_rtn && !done; i++) {

	for (j = 0; j < keysyms_per_keycode_rtn; j++) {
	    	if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == ks) {
			if (j > 1)
				*new_mod = mode_switch;
			done = True;
			break;
		}
	}

    }

    XFree( ks_list ) ;
    XFreeModifiermap ( mod_keymap );
    return;

}
