/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: ProcesEvents.c /main/7 1995/07/14 11:30:48 drk $"
#endif
#endif
/***********************************************************************
  	@(#)ProcesEvents.c	1.10.1.1	Date:1/22/91
  	Author: TAT
	History:
            05/29/90 SJS add to sccs
            06/21/90 SJS do not set focus to unmapped widgets
            07/11/90 SJS test return of XmProcessTraversal() for what its worth
            08/22/90 SJS set our internal concept of focus to the "real"
                         widget when keyboard focus mode is NATURAL
            10/10/90 SJS do SetExpected for Focus In/Out. Try to follow
			 Motif focus.
	Calls:

	Summary:
            Processes all events generated by Xm, Xt, and X-server until the
        next quiescent condition.  Then it returns control back to the calling
        routine.

        INPUTS:
            done_func           - external function which determines if the 
                                  processing is done yet based on external 
                                  environment conditions which are known to it
                                  (i.e., callbacks, etc.).

            max_wait_time       - Maximum number of milliseconds to wait overall
                                  before giving up on sync_func.

        OUTPUTS:
            none

        RETURNS:
            void
************************************************************************/

#include "xislib.h"
#include <Xm/XmP.h>         /* Warning: Potentially non-portable */
#include <AutoMessages.h>

static XtIntervalId interval_timer_id=0;

static void timer_expire_callback(client_data,timer_id) 
XtPointer client_data;
XtIntervalId *timer_id;
{
    if (*timer_id != interval_timer_id) {
        AutoMessage(_AutoMessages[WARNMSG77]);
    }
    interval_timer_id = 0;
}

void xisProcessEvents(done_func,max_wait_time)
int (*done_func)();
int max_wait_time;
{
    static char routine_name[] = "xisProcessEvents";
    int done=0;
    int called_dispatch = 0;
    Window focus_window;
    int revert_to;
    XisObjectRecord *new_object;

    xisUseSessionInfo(routine_name);
    called_dispatch = xisSynchronize();

    if (done_func != NULL) {
        if ((*done_func)() == 0) {
            interval_timer_id = 0;
            interval_timer_id = XtAppAddTimeOut(xisAppContext,max_wait_time,
                                                timer_expire_callback, 
						(XtPointer) 0);
            while (!done) {
                if ((XtAppPending(xisAppContext)&XtIMTimer) > 0) 
                    XtAppProcessEvent(xisAppContext,XtIMTimer);

                if (interval_timer_id == 0) {
                    done = 1;
                }
                else {
                    called_dispatch = xisSynchronize();
                    done = (*done_func)();
		}
	    }
            if (interval_timer_id != 0)
                XtRemoveTimeOut(interval_timer_id);
        } /* End if ((*done_func)() == 0) */
    } /* End if (done_func != NULL) */

    if (called_dispatch) {
        xisProcessObjects();
    }

    /* Make sure that the correct window has the keyboard focus */
    XGetInputFocus(xisDisplay,&focus_window,&revert_to);

    if (xisKeyboardFocusMode == KEYBOARD_FOCUS_CONTROLLED &&
        focus_window != xisState.focus_window) {

        (*xisTraceMsg)("WARNING..Window manager changed focus window; changing back\n");
        if (!xisState.focus_window || 
             xisState.focus_window == xisRootWindow ||
            !xisWindowExists(xisState.focus_window) ||
            !xisIsMapped(xisState.focus_window)   ) {

            if (!xisDummyFocusWindow) {
                xisCreateSimple();
                called_dispatch = xisSynchronize();
	    }
            xisState.focus_window = xisDummyFocusWindow;
            xisState.focus_widget = NULL;
            xisState.focus_revert_to = RevertToNone;
	}
        else {
            /* In this case, the window manager moved focus out. We need
               to do an Xis event for this FocusOut and for the FocusIn
               we are about to cause
            */
            new_object = xisGetObjectFromWidget(xisState.focus_widget);
            if (new_object->proc_InformExpectedActions != NULL) {
                xisInform.current_obj = new_object;
                xisInform.is_valid = 1;
                xisInform.action_obj = new_object;
                xisInform.modifier_key_status = 0;
                xisInform.button_num = 0;
                xisInform.key_code = 0;
                xisInform.edge_code = 0;
                xisInform.num_clicks = 0;
                xisInform.event_code = EventFocusOut;
                (*new_object->proc_InformExpectedActions)(EventFocusOut);
                xisInform.event_code = EventFocusIn;
                (*new_object->proc_InformExpectedActions)(EventFocusIn);
            }
        }

        if (xisState.focus_widget == NULL) {
            XSetInputFocus(xisDisplay,xisState.focus_window,
                           RevertToNone,CurrentTime);
	}
        else {
            XSetInputFocus(xisDisplay,
                           XtWindow(xisGetShellWidget(xisState.focus_widget)),
                           RevertToNone,CurrentTime);

            if(!XmProcessTraversal(xisState.focus_widget,XmTRAVERSE_CURRENT)) {
                XisObjectRecord *new_focus; /* Lord knows where it ends up */

                XGetInputFocus(xisDisplay,&xisState.focus_window,
                               &xisState.focus_revert_to);
                new_focus = xisFindObjectFromWindow(xisState.focus_window);
                xisState.focus_widget = new_focus->id.widget;
                xisState.focus_object_type = new_focus->id.object_type;
                xisState.focus_instance = new_focus->id.instance;

            }
            else {
                XGetInputFocus(xisDisplay,&xisState.focus_window,
                               &xisState.focus_revert_to);
            }
        }
    } /* End if(KEYBOARD_FOCUS_CONTROLLED) */
    else { /* KEYBOARD_FOCUS_NATURAL */
        /* Do our best to find out where it went. THIS IS THE CODE THAT
           SHOULD BE CHANGED IF MOTIF EVER GIVES US A REAL FOCUS QUERY
           FUNCTION
        */

        Widget new_widget;
        XisObjectRecord *tmp_object;
        XisObjectRecord *tmp2_object;

        new_widget = xisGetFocusWidget();
        if(new_widget != NULL) {
            if(new_widget != xisState.focus_widget) {/* New widget with focus */
                new_object = xisGetObjectFromWidget(new_widget);
                tmp_object = new_object;
if(focus_window != xisState.focus_window) { /* Focus move in hierarchy, too */
                while(tmp_object != NULL) {
                    if (tmp_object->proc_InformExpectedActions != NULL) {
                        xisInform.current_obj = tmp_object;
                        xisInform.is_valid = 1;
                        xisInform.action_obj = new_object;
                        xisInform.modifier_key_status = 0;
                        xisInform.button_num = 0;
                        xisInform.key_code = 0;
                        xisInform.edge_code = 0;
                        xisInform.num_clicks = 0;
                        xisInform.event_code = EventFocusIn;
                        (*tmp_object->proc_InformExpectedActions)(EventFocusIn);
                    }
                    tmp_object = tmp_object->parent;
                }
                tmp_object = xisGetObjectFromWidget(xisState.focus_widget);
                tmp2_object = tmp_object;
                while(tmp2_object != NULL ) {
                    if (tmp2_object->proc_InformExpectedActions != NULL) {
                        xisInform.current_obj = tmp2_object;
                        xisInform.is_valid = 1;
                        xisInform.action_obj = tmp_object;
                        xisInform.modifier_key_status = 0;
                        xisInform.button_num = 0;
                        xisInform.key_code = 0;
                        xisInform.edge_code = 0;
                        xisInform.num_clicks = 0;
                        xisInform.event_code = EventFocusOut;
                        (*tmp2_object->proc_InformExpectedActions)
                                                                (EventFocusOut);
                    }
                    tmp2_object = tmp2_object->parent;
                }
}
                if((new_object != NULL)&&(focus_window != xisDummyFocusWindow)){
                    xisState.focus_window = focus_window;
                    xisState.focus_widget = new_widget;
                    xisState.focus_object_type = new_object->id.object_type;
                    xisState.focus_instance = new_object->id.instance;
                }
            }
        } /* End if(new_widget != xisState.focus_widget) */
    } /* End else KEYBOARD_FOCUS_NATURAL */

} /* End xisProcessEvents() */
