Logo Search packages:      
Sourcecode: ldtp version File versions

ldtp-record.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * Linux Desktop Testing Project http://ldtp.freedesktop.org
 *
 * Author:
 *    Shankar Ganesh <shagan.glare@gmail.com>
 *    Harishankaran <sp2hari@gmail.com>
 *    Theyagarajan <theyaga@gmail.com>
 *
 * Copyright 2004 - 2006 Novell, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "ldtp.h"
#include "remap.h"
#include "ldtp-gui.h"
#include "ldtp-error.h"
#include "ldtp-utils.h"
#include "ldtp-record.h"
#include "ldtp-logger.h"
#include "ldtp-gui-cb.h"
#include "ldtp-command.h"

/*
The following variables are to be used for any callbacks

static AccessibleEventListener *specific_listener;
static AccessibleEventListener *bounds_listener;
static AccessibleEventListener *detail1_listener;
static AccessibleEventListener *test_listener;
static AccessibleEventListener *caret_listener;
static AccessibleEventListener *mousemove_listener = NULL;
static AccessibleEventListener *text_selection_listener;
static AccessibleEventListener *active_descendant_changed_listener;
static AccessibleEventListener *children_changed_listener;
static AccessibleEventListener *description_changed_listener;
static AccessibleEventListener *parent_changed_listener;
static AccessibleEventListener *table_summary_listener;
static AccessibleEventListener *table_header_listener;
static AccessibleEventListener *table_caption_listener;
static AccessibleEventListener *table_row_description_listener;
static AccessibleEventListener *table_column_description_listener;
static AccessibleDeviceListener *mouse_device_listener;
*/

static void
caculate_time_elapsed (LDTPRecord *rec)
{
      long time_elapsed = (long) g_timer_elapsed (rec->timer, NULL);
      if (time_elapsed == 0)
            return;
      fprintf (rec->fp,
             "<SLEEP>%ld</SLEEP>\n",
             time_elapsed);
      g_timer_start (rec->timer);
}

static void
init_record_file (LDTPClientContext* cctxt, LDTPErrorCode*err)
{
      /*
       * This function creates a tmp file where XML content of the  events is dumped by the server.
       * Called once when the record is started
       */
      char *tmpl = NULL;
      gint ofile;
      tmpl = g_strdup_printf ("ldtp-record-%s-XXXXXX", g_get_user_name ());
      ofile = g_file_open_tmp ((const gchar*)tmpl, &cctxt->rec->filename, NULL);
      close (ofile);
      g_free (tmpl);
      cctxt->rec->fp = fopen (cctxt->rec->filename, "w");
      if (!cctxt->rec->fp) {
            g_print ("Unable to open tmp file.\n Quitting\n");
            *err =  (LDTP_ERROR_OPENING_RECORD_FILE);
            return;
      }
      /*
       * Writes the <?xml?> tag and starts the <RECORD> tag
       */
      fprintf (cctxt->rec->fp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RECORD>\n");
      *err =  (LDTP_ERROR_SUCCESS);
}

static char*
get_property_from_hash_table (LDTPClientContext* cctxt, char *object_name, char *property)
{
      /*
       *  This function gets the object name when Accessible_getName() and get_relation_name() fails to get the name
       *  Calls remap() function (if cctxt->appmap is null) and hence must be used sparingly.
       */
      char *object_property = NULL;
      LDTPErrorCode err;
      //GHashTable *ht = NULL;
      GHashTable *cur_window = NULL;
      GHashTable *cur_component = NULL;
      //LDTPGuiHandle *accessible = NULL;

      if (!cctxt->req->context) {
            err =  (LDTP_ERROR_ARGUMENT_NULL);
            g_print ("%s\n", ldtp_error_get_message (err));
            log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (err), cctxt->log_fp);
            return NULL;
      }

      if (!cctxt->app_map) {
            update_cur_window_appmap_handle (cctxt, &err);
            if (err != LDTP_ERROR_SUCCESS) {
                  g_print ("Could not update appmap\n");
                  return NULL;
            }
      }

      cur_window = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, TRUE);
      if (!cur_window) {
            update_cur_window_appmap_handle (cctxt, &err);
      }

      if (!cctxt->app_map) {
            g_print ("Could not update appmap\n");
            return NULL;
      }
      cur_window = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, TRUE);
      if (!cur_window) {
            if (cctxt->req->context)
                  g_print ("Unable to find window name: %s in appmap",(char*) cctxt->req->context);
            err =  (LDTP_ERROR_WIN_NAME_NOT_FOUND_IN_APPMAP);
            return NULL;
      }

      cur_component = get_object_def (cur_window, object_name, NULL, FALSE);
      if (!cur_component) {
            if (object_name)
                  g_print ("Unable to find object name: %s in appmap", object_name);
            err =  (LDTP_ERROR_OBJ_NAME_NOT_FOUND_IN_APPMAP);
            return NULL;
      }

      object_property = get_property (cur_component, property, NULL);
      if (object_property)
            g_print ("Property is : %s\n", object_property);
      return object_property;
}

static gboolean 
check_name_with_hash_table (LDTPClientContext* cctxt, Accessible *object, char *name)
{
      /*
        This function is implemented to check whether the name obtained from
        Accessible_getName and get_realation_name matches with the name in the appmap
      */
      char * hash_child_index = NULL;
      char handle_child_index [256];
      sprintf (handle_child_index ,"%ld", Accessible_getIndexInParent (object));
      hash_child_index = get_property_from_hash_table (cctxt, name, "child_index");
      if (!hash_child_index)
            return FALSE;
      g_print ("Child indexes are %s %s\n", handle_child_index, hash_child_index);
      //FIXME :: Checking only the child_index, must check some other property also to be sure about the name
      if (g_ascii_strcasecmp (handle_child_index, hash_child_index) != 0 ) {
            return FALSE;
      }
      return TRUE;
}

static  char *
get_window_name (const AccessibleEvent *event)
{
      /*
        This function gets the window name for any given event .
        Bit costly in terms of time and memory since this loops to the window but this always gives the correct
      */
      //FIXME :: Should prevent the use if this function and use the callbacks from window related events

      char *tmp = NULL;
      char *name = NULL;
      Accessible *current_object = NULL;

      current_object = Accessible_getParent (event->source);
      while (1) {
            g_print ("Object role: %d\n ", Accessible_getRole (current_object));
            if (Accessible_getRole (current_object) == SPI_ROLE_APPLICATION) {
                  Accessible_unref (current_object);
                  return NULL;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_FRAME) {
                  tmp =  Accessible_getName (current_object);
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
                  Accessible_unref (current_object);
                  return name;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_DIALOG) {
                  tmp =  Accessible_getName (current_object);
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
                  Accessible_unref (current_object);
                  return name;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_ALERT) {
                  tmp =  Accessible_getName (current_object);
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
                  Accessible_unref (current_object);
                  return name;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_INVALID) {
                  Accessible_unref (current_object);
                  g_print ("Quitting invalid\n");
                  return NULL;
            }
            Accessible *tmp = NULL;
            tmp = Accessible_getParent (current_object);
            Accessible_unref (current_object);
            current_object = tmp;
      }
}

static  char *
get_window_type (const AccessibleEvent *event)
{
      /*
       * This function gets the window type for any given event .
       * Bit costly in terms of time and memory as this loops to the window from the object 
       * Gives the correct window name for all the events
       */
      
      //FIXME :: Should prevent the use if this function and use the callbacks from window related events

      char *tmp = NULL;
      char *name = NULL;
      Accessible *current_object = NULL;
      current_object = Accessible_getParent (event->source);
      while (1) {
            g_print ("The object role is : %d\n ", Accessible_getRole (current_object));
            if (Accessible_getRole (current_object) == SPI_ROLE_APPLICATION) {
                  Accessible_unref (current_object);
                  return NULL;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_FRAME) {
                  tmp =  Accessible_getRoleName (current_object);
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
                  Accessible_unref (current_object);
                  return name;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_DIALOG) {
                  tmp =  Accessible_getRoleName (current_object);
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
                  Accessible_unref (current_object);
                  return name;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_ALERT) {
                  tmp =  Accessible_getRoleName (current_object);
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
                  Accessible_unref (current_object);
                  return name;
            }
            else if (Accessible_getRole (current_object) == SPI_ROLE_INVALID) {
                  g_print ("Quitting invalid\n");
                  Accessible_unref (current_object);
                  return NULL;
            }
            Accessible *tmp = NULL;
            tmp = Accessible_getParent (current_object);
            Accessible_unref (current_object);
            current_object = tmp;
      }
}

static  char*
get_application_name (const AccessibleEvent *event)
{
      /*
       *  This function gets the application for any given event .
       *  Bit costly in terms of time and memory since this loops to the window 
       */
 
      Accessible *tmp = NULL;
      Accessible *parent = NULL;
      parent = Accessible_getParent (event->source);
      if (!parent)
            return NULL;
      while (1) {
            if (!parent)
                  return NULL;
            if (Accessible_getRole (parent) == SPI_ROLE_APPLICATION) {
                  char *name = NULL;
                  char *tmp_name = NULL;
                  tmp_name = Accessible_getName (parent);
                  Accessible_unref (parent);
                  if (tmp_name) {
                        name = g_strdup (tmp_name);
                        SPI_freeString (tmp_name);
                  }
                  return name;
            }
            else if (Accessible_getRole (parent) == SPI_ROLE_INVALID) {
                  Accessible_unref (parent);
                  return NULL;
            }
            tmp = Accessible_getParent (parent);
            Accessible_unref (parent);
            parent = tmp;
      }
}

static gboolean 
get_state_visible (Accessible *object)
{
      SPIBoolean visible = FALSE;
      AccessibleStateSet *state;

      state = Accessible_getStateSet (object);
      if (state) {
            visible = AccessibleStateSet_contains (state, SPI_STATE_VISIBLE);
            AccessibleStateSet_unref (state);
      }

      if (visible)
            return TRUE;
      else
            return FALSE;
}

static struct parent_path_info
get_path_to_top (Accessible *object)
{
      int i = 0;
      int role;
      int *temp = NULL, *child_index = NULL;
      PARENT_PATH_INFO path_info ;
      Accessible *tmp = NULL;
      Accessible *current = object;

      role = Accessible_getRole (current);
      while (role != SPI_ROLE_APPLICATION && 
             role != SPI_ROLE_INVALID) {
            if (Accessible_getIndexInParent (current) == -1) {
                  g_print ("Invalid child index in parent\n");
                  tmp = Accessible_getParent (current);
                  if (current != object) 
                        Accessible_unref (current);
                  current = tmp;
                  role = Accessible_getRole (current);
                  continue;
            }
            if (child_index == NULL) {
                  child_index = (int*) malloc (sizeof (int));
                  *(child_index+i) = Accessible_getIndexInParent (current);
            }
            else {
                  temp = realloc (child_index, (i+1) * sizeof (int));
                  child_index = temp;
                  *(child_index+i) = Accessible_getIndexInParent (current);
            }
            g_print ("Pushing %d to the stack \n", *(child_index+i));
            tmp = Accessible_getParent (current);
            if (tmp == NULL) {
                  /*
                    Unref below. So commenting this region
                    if (current != object) 
                        Accessible_unref (current);
                  */
                  g_print ("Get parent returning null\n");
                  break;
            }
            if (current != object && current)
                  Accessible_unref (current);
            current = tmp;
            i++;
            role = Accessible_getRole (current);
      }
      path_info.child_index = child_index;
      path_info.child_index_count = i;
      if (current != object)
            Accessible_unref (current);
      return path_info;
}


//The variable remap if TRUE then do a update_cur_appmap_handle , 
//FIXME :: Try to use update_cur_appmap_handle as less as possible
char*
get_name_from_hash_table (LDTPClientContext *cctxt,
                    Accessible *object,
                    char *window_name,
                    int window_type,
                    gboolean remap) {
      /*
        This function gets the name of the  object from the hash table . Uses the path to window and then gets the name
        Bit costly since this may call remap if required
        If gboolean remap is TRUE , then remap() is called first and then the object is searched 
      */
      char *object_name = NULL;
      GHashTable *ht = NULL;
      LDTPErrorCode err;
      PARENT_PATH_INFO path_info;

      if (remap == TRUE || !cctxt->app_map) {
            update_cur_window_appmap_handle (cctxt, &err);
            if (err != LDTP_ERROR_SUCCESS) {
                  g_print ("Could not update appmap\n");
                  return NULL;
            }
      }

      ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, TRUE);
      if (!ht) {
            // update_cur_window_appmap_handle (cctxt, &err);
            if (err != LDTP_ERROR_SUCCESS) {
                  g_print ("Could not update appmap\n");
                  return NULL;
            }
      }

      ht = get_object_def (cctxt->app_map, cctxt->req->context, NULL, TRUE); 
      path_info = get_path_to_top (object);
      object_name = get_unknown_obj_label (ht, cctxt->req->context, 
                                   path_info.child_index, 
                                   path_info.child_index_count,
                                   cctxt->log_fp);
      if (object_name)
            g_print ("Object name: %s from get_name_from_hash_table\n",object_name);
      return object_name;
}

static gboolean 
check_application (LDTPClientContext *cctxt, char* window_name)
{

      /*FIXME :: AS of now if either request or window name is null ,
       * the action is recorded , but the required action to be taken later
       */
      if (cctxt->req->application == NULL )
            return TRUE;
      if (window_name == NULL)
            return TRUE;
      // FIXME: Use g_utf8_collate
      if (g_ascii_strcasecmp (cctxt->req->application, "all") == 0)
            return TRUE;
      else if (g_utf8_collate (cctxt->req->application, window_name) == 0)
            return TRUE;
      else 
            return FALSE;
}

static char*
get_appmap_name (Accessible *object, char *name)
{     
      gboolean flag = FALSE;
      char *stripped_data = NULL;
      char *value = NULL;
      int role = Accessible_getRole (object);
      if (role == SPI_ROLE_FRAME || role == SPI_ROLE_DIALOG ||
          role == SPI_ROLE_ALERT || role == SPI_ROLE_FONT_CHOOSER ||
          role == SPI_ROLE_FILE_CHOOSER)
            flag = TRUE;

      if (g_utf8_strchr (name, -1, ' '))
            stripped_data = (char *) escape_character (name, ' ');
      else
            stripped_data = g_strdup (name);
      if (!flag && g_utf8_strchr (stripped_data, -1, '.')) {
            value = strip_delim (stripped_data, '.');
            g_free (stripped_data);
            stripped_data = g_strdup (value);
            g_free (value);
            value = NULL;
      }
      if (!flag && g_utf8_strchr (stripped_data, -1, ':')) {
            value = strip_delim (stripped_data, ':');
            g_free (stripped_data);
            stripped_data = g_strdup (value);
            g_free (value);
            value = NULL;
      }
      if (!flag && g_utf8_strchr (stripped_data, -1, '_')) {
            value = (char *)escape_character (stripped_data, '_');
            g_free (stripped_data);
            stripped_data = g_strdup (value);
            g_free (value);
            value = NULL;
      }
      if (role == SPI_ROLE_COMBO_BOX) {
            return g_strconcat ("cbo", stripped_data, NULL) ;
      }
      else
            return "ukn";
}

/*
 *The callbacks for various events  follows here
 */
static void 
mouse_click_cb (const AccessibleEvent *event, void *user_data)
{
      /* sp2hari : 
       * To avoid multiple callbacks , when the control first comes here , we set the value of clicked to false  
       * and the value is set back to true when any other event occurs in generic callback
       */
      char *name = NULL;
      char *role = NULL;
      int class_id = 0;
      //char *object_type ;
      static char *object_name = NULL;
      Accessible *combobox = NULL;
      Accessible *current_item = NULL;
      //LDTPErrorCode err;
      //GHashTable *ht = NULL;
      //PARENT_PATH_INFO path_info;
      LDTPClientContext *cctxt = (LDTPClientContext*) user_data;

      cctxt->req->context = get_window_text_in_appmap_format (cctxt->rec->window_name, cctxt->rec->window_role);
      name = Accessible_getName (event->source);
      if (!object_name)
            object_name = g_strdup (name);
      else if (g_utf8_collate (object_name, name) != 0) {
            g_free (object_name);
            object_name = g_strdup (name);
      }
      else if (g_utf8_collate (object_name, name) == 0 && cctxt->rec->clicked == FALSE) {
            /*
              FIXME: To avoid multiple re-entry, we are just returning back
            */
            SPI_freeString (name);
            return;
      }

      if (check_application (cctxt, get_application_name (event)) == FALSE)
            return ;
      class_id = Accessible_getRole (event->source);
      role = Accessible_getRoleName (event->source);
      if (role) {
            g_print ("DEBUG: Mouse Click of object type %d - %s\n", class_id, role);
            SPI_freeString (role);
      }

      if (class_id == SPI_ROLE_CHECK_BOX) {
            caculate_time_elapsed (cctxt->rec);
            check_box_cb (cctxt->rec->fp, event, cctxt->rec->window_name, cctxt->rec->window_type);
      }
      else if (class_id == SPI_ROLE_COMBO_BOX) {
            combobox = event->source;
            cctxt->rec->combobox_changed = TRUE;
            cctxt->rec->combobox_name = get_relation_name (event->source, NULL);
            if (cctxt->rec->combobox_name == NULL ||
                g_ascii_strcasecmp (cctxt->rec->combobox_name, "") == 0) {
                  cctxt->rec->combobox_name = get_name_from_hash_table (cctxt, event->source,
                                                            cctxt->rec->window_name,
                                                            cctxt->rec->window_role,
                                                            FALSE);
                  if (cctxt->rec->combobox_name == NULL ||
                      g_ascii_strcasecmp (cctxt->rec->combobox_name, "") == 0) {
                        g_free (cctxt->rec->combobox_name);
                        cctxt->rec->combobox_name = get_name_from_hash_table (cctxt , event->source,
                                                                  cctxt->rec->window_name,
                                                                  cctxt->rec->window_role,
                                                                  TRUE);
                  }
            }
      }
      else if (class_id ==  SPI_ROLE_LIST_ITEM) {
            current_item = event->source;
            class_id = Accessible_getRole (current_item);
            while (class_id != SPI_ROLE_COMBO_BOX &&  
                   class_id != SPI_ROLE_INVALID) {
                  Accessible *tmp = NULL;
                  tmp = Accessible_getParent (current_item);
                  if (current_item != event->source)
                        Accessible_unref (current_item);
                  current_item = tmp;
                  class_id = Accessible_getRole (current_item);
            }
            combobox = current_item;
            cctxt->rec->combobox_name = get_relation_name (combobox, NULL);
            name = Accessible_getRoleName (combobox);
            caculate_time_elapsed (cctxt->rec);
            combo_box_cb (cctxt->rec->fp, event,
                        cctxt->rec->window_name,
                        cctxt->rec->window_type,
                        name,
                        cctxt->rec->combobox_name);
            SPI_freeString (name);
            if (current_item != event->source)
                  Accessible_unref (current_item);
      }
      else if (class_id ==  SPI_ROLE_MENU_ITEM ||
             class_id == SPI_ROLE_CHECK_MENU_ITEM ||
             class_id == SPI_ROLE_RADIO_MENU_ITEM) {
            caculate_time_elapsed (cctxt->rec);
            menu_item_cb (cctxt->rec->fp, event,
                        cctxt->rec->window_name,
                        cctxt->rec->window_type,
                        cctxt->rec->combobox_changed,
                        cctxt->rec->combobox_name);
            cctxt->rec->combobox_changed = FALSE;
      }
      else if (class_id == SPI_ROLE_PUSH_BUTTON) {
            caculate_time_elapsed (cctxt->rec);
            push_button_cb (cctxt->rec->fp, event, cctxt->rec->window_name, cctxt->rec->window_type);
      }
      else if (class_id == SPI_ROLE_RADIO_BUTTON) {
            caculate_time_elapsed (cctxt->rec);
            radio_button_cb (cctxt->rec->fp, event, cctxt->rec->window_name, cctxt->rec->window_type);
      }
      else if (class_id == SPI_ROLE_SPIN_BUTTON) {
            caculate_time_elapsed (cctxt->rec);
            spin_button_cb (cctxt->rec->fp, event, cctxt->rec->window_name, cctxt->rec->window_type );
      }
      else if (class_id == SPI_ROLE_TOGGLE_BUTTON) {
            combobox = Accessible_getParent (event->source);
            if (Accessible_getRole (combobox) == SPI_ROLE_COMBO_BOX) { 
                  cctxt->rec->combobox_changed = TRUE;
                  cctxt->rec->combobox_name = get_relation_name (combobox, NULL);
                  if (cctxt->rec->combobox_name == NULL ||
                      g_ascii_strcasecmp (cctxt->rec->combobox_name, "") == 0) {
                        cctxt->rec->combobox_name = get_name_from_hash_table (cctxt,
                                                                  combobox,
                                                                  cctxt->rec->window_name,
                                                                  cctxt->rec->window_role,
                                                                  FALSE);
                  }
                  if (check_name_with_hash_table (cctxt, combobox,
                                          get_appmap_name (combobox,
                                                       cctxt->rec->combobox_name)) == FALSE) {
                        g_free (cctxt->rec->combobox_name);
                        cctxt->rec->combobox_name = get_name_from_hash_table (cctxt,
                                                                  combobox,
                                                                  cctxt->rec->window_name,
                                                                  cctxt->rec->window_role,
                                                                  TRUE);
                  }     
            }           
            else {
                  char *name = Accessible_getName (event->source);
                  caculate_time_elapsed (cctxt->rec);
                  if (name) {
                        toggle_button_cb (cctxt->rec->fp, event, cctxt->rec->window_name,
                                      cctxt->rec->window_type, name);
                        SPI_freeString (name);
                  }
            }
            Accessible_unref (combobox);
      }
      cctxt->rec->clicked = FALSE;
      caculate_time_elapsed (cctxt->rec);
}

static void
generic_cb (const AccessibleEvent *event, void *user_data)
{
      LDTPClientContext *cctxt = (LDTPClientContext*) user_data;
      if (cctxt->rec->clicked == FALSE) {
            cctxt->rec->clicked = TRUE;
            caculate_time_elapsed (cctxt->rec);
      }
}

static void 
selection_changed_cb (const AccessibleEvent *event, void *user_data)
{
      char *tmp = NULL;
      char *name = NULL;
      int class_id = 0;
      LDTPClientContext *cctxt = (LDTPClientContext*) user_data;

      class_id = Accessible_getRole (event->source);
      if (class_id == SPI_ROLE_PAGE_TAB_LIST) {
            //FIXME :: The if will fail when there a page tab opens from a already opened one
            //It was implemented this way in old record . Just copying :(
            if (g_ascii_strcasecmp (cctxt->rec->base_name, cctxt->req->application) == 0)
                  return;
            tmp = Accessible_getName (event->source);
            if (tmp != NULL && g_ascii_strcasecmp (tmp, "") != 0) {
                  name = g_strdup (tmp);
                  SPI_freeString (tmp);
            }
            else {
                  name = get_name_from_hash_table (cctxt,event->source,
                                           cctxt->rec->window_name,
                                           cctxt->rec->window_role,
                                           FALSE);
                  if (name == NULL || g_ascii_strcasecmp (name, "") == 0) {
                        name = get_name_from_hash_table (cctxt, event->source,
                                                 cctxt->rec->window_name,
                                                 cctxt->rec->window_role,
                                                 TRUE);
                  }
            }
            caculate_time_elapsed (cctxt->rec);
            page_tablist_cb (cctxt->rec->fp, event,
                         cctxt->rec->window_name,
                         cctxt->rec->window_type,
                         name );
            if (name)
                  g_print ("Page tab recorded for %s\n", name);
      }            
      else if (class_id == SPI_ROLE_TABLE) {
            caculate_time_elapsed (cctxt->rec);
            table_cb (cctxt->rec->fp, cctxt, event, get_window_name(event), get_window_type(event), cctxt->rec->window_role);
      }
      else if (class_id == SPI_ROLE_TREE_TABLE) {
            caculate_time_elapsed (cctxt->rec);
            tree_table_cb (cctxt->rec->fp, event, cctxt->rec->window_name, cctxt->rec->window_type);
      }
}

static void
text_changed_cb (const AccessibleEvent *event, void *user_data)
{
      FILE *debug;
      char *name, *role;
      static char *new_text = NULL;
      AccessibleText *text_obj = NULL;
      LDTPClientContext *cctxt = (LDTPClientContext*) user_data;

      // FIXME: Should be removed
      debug = fopen ("/tmp/text-debug.txt", "w");
      name = Accessible_getName (event->source);
      role = Accessible_getRoleName (event->source);
      if (name && role && event->type)
            g_print ("Text changed callback by %s of type %s of event type %s\n",
                   name, role, event->type);
      SPI_freeString (name);
      SPI_freeString (role);

      if (check_application (cctxt, get_application_name (event)) == FALSE) {
            return;
      }

      // If the text area is not editable then text change is not due to typed text. So ignore that
      if (Accessible_isEditableText (event->source) == FALSE)
            return;

      // If the text area is not visible , then also no need to record the text since that is not typed
      if (get_state_visible (event->source) == FALSE)
            return;

      // Return if the text name is not set since focus has not been th the field
      // this will remove most of recoding of text which are already set
      if (cctxt->rec->text_area_name == NULL ||
          g_ascii_strcasecmp (cctxt->rec->text_area_name , "") == 0)
            return;
      
      if (debug) {
            name = Accessible_getName (event->source);
            g_print ("==DEBUG== Change in text area with name %s\n", name);
            SPI_freeString (name);
      }

      if (cctxt->rec->text != NULL ) {
            //g_free (text);
            cctxt->rec->text = NULL;
      }

      cctxt->rec->text_changed = TRUE;
      text_obj = Accessible_getText (event->source);
      new_text = AccessibleText_getText (text_obj, 0, -1);
      cctxt->rec->text = g_strdup (new_text);

      g_print ("Text to be written: %s\nText area name: %s\n", cctxt->rec->text, cctxt->rec->text_area_name);

      SPI_freeString (new_text);
      AccessibleText_unref (text_obj);
      fclose (debug);
}

static void
focus_cb (const AccessibleEvent *event, void *user_data)
{
      LDTPClientContext *cctxt = (LDTPClientContext*) user_data;
      int class_id = Accessible_getRole (event->source);

      if (class_id == SPI_ROLE_TABLE_CELL) {
            Accessible *parent = Accessible_getParent (event->source);
            if (Accessible_getRole (parent) == SPI_ROLE_TREE_TABLE) {
                  caculate_time_elapsed (cctxt->rec);
                  tree_table_cb (cctxt->rec->fp, event ,cctxt->rec->window_name, cctxt->rec->window_type);
            }
            Accessible_unref (parent);
      }
      else if (class_id ==  SPI_ROLE_TEXT || class_id == SPI_ROLE_PASSWORD_TEXT) {
            char *name, *role;
            //GHashTable *ht = NULL;
            LDTPClientContext *cctxt = (LDTPClientContext*) user_data;

            name = Accessible_getName (event->source);
            role = Accessible_getRoleName (event->source);
            if (name && role && event->type)
                  g_print ("Focus callback by %s of type %s of event type %s\n", 
                         name, role, event->type);

            cctxt->rec->text_window_name = g_strdup (cctxt->rec->window_name);
            cctxt->rec->text_role = g_strdup (role);
            SPI_freeString (role);
            /* Trying to get  the text field name by three ways
             * 1.Accessible Name 
             * 2.get_relation_name
             * 3.searching hash table for names like txt0
             */

            if (name) {
                  cctxt->rec->text_area_name = g_strdup (name);
                  SPI_freeString (name);
            }

            if (cctxt->rec->text_area_name == NULL ||
                g_ascii_strcasecmp (cctxt->rec->text_area_name, "") == 0) {
                  cctxt->rec->text_area_name = get_relation_name (event->source, NULL);
            }
            if (cctxt->rec->text_area_name == NULL ||
                g_ascii_strcasecmp (cctxt->rec->text_area_name, "") == 0 ) {
                  g_print ("Trying to get name from hash table\n");                 
                  cctxt->rec->text_area_name = get_name_from_hash_table (cctxt, 
                                                   event->source, 
                                                   cctxt->rec->text_window_name, 
                                                   cctxt->rec->window_role,  
                                                   FALSE);

                  if (cctxt->rec->text_area_name == NULL ||
                      g_ascii_strcasecmp (cctxt->rec->text_area_name, "") == 0) {
                        cctxt->rec->text_area_name = get_name_from_hash_table (cctxt, 
                                                         event->source, 
                                                         cctxt->rec->text_window_name, 
                                                         cctxt->rec->window_role,  
                                                         TRUE);
                  }
                  if (cctxt->rec->text_area_name)
                        g_print ("Text area name: %s\n", cctxt->rec->text_area_name);
            }
      }
}

static void
window_cb (const AccessibleEvent *event, void *user_data)
{
      char *tmp = NULL;
      LDTPClientContext *cctxt = (LDTPClientContext*)user_data;

      g_print ("Window callback by %d\n", Accessible_getRole (event->source));
      if (Accessible_getRole (event->source) == SPI_ROLE_FRAME) {
            tmp = AccessibleWindowEvent_getTitleString (event);
            if (cctxt->rec->window_name)
                  g_free (cctxt->rec->window_name);
            cctxt->rec->window_name = g_strdup (tmp);
            SPI_freeString (tmp);
            tmp = Accessible_getRoleName (event->source);
            if (cctxt->rec->window_type)
                  g_free (cctxt->rec->window_type);
            g_print ("Changing window_name in window callback\n");
            cctxt->rec->window_type = g_strdup (tmp); 
            SPI_freeString (tmp);
      }
      if (cctxt->rec->window_name && cctxt->rec->window_type)
            g_print ("Window title: %s - Window type: %s\n", cctxt->rec->window_name, cctxt->rec->window_type);
}

//The following function determines the window_name and window_type for almost all the remaining callbacks
static void
state_change_cb (const AccessibleEvent *event, void *user_data)
{

      int role = -1;
      char *tmp = NULL;
      LDTPClientContext *cctxt = (LDTPClientContext*)user_data;

      role = Accessible_getRole (event->source);

      if (g_ascii_strcasecmp (event->type, "object:state-changed:active") == 0 && 
          (role == SPI_ROLE_DIALOG || role == SPI_ROLE_FRAME || role == SPI_ROLE_ALERT)) {
            cctxt->rec->window_role = role;
            if (cctxt->rec->window_name)
                  g_free (cctxt->rec->window_name);
            if (cctxt->rec->window_type)
                  g_free (cctxt->rec->window_type);
            tmp = Accessible_getName (event->source);
            cctxt->rec->window_name = g_strdup (tmp);
            SPI_freeString (tmp);
            tmp = Accessible_getRoleName (event->source);
            cctxt->rec->window_type = g_strdup (tmp);
            SPI_freeString (tmp);         
            //The following variable to use cctxt->rec->base_name is not a good idea but still using this from old record
            if (role == SPI_ROLE_FRAME) {
                  cctxt->rec->base_name = g_strdup (cctxt->req->application);
            }
            else if (role == SPI_ROLE_ALERT || role == SPI_ROLE_DIALOG ) {
                  cctxt->rec->base_name = cctxt->rec->window_name;
            }
      }

      if (cctxt->rec->text_changed == TRUE &&
          g_ascii_strcasecmp (event->type, "object:state-changed:focused") == 0) {
            cctxt->rec->text_changed = FALSE ;
            if (cctxt->rec->text && cctxt->rec->text_area_name)
                  g_print ("Text Recorded:\nText: %s \nName: %s\n",
                         cctxt->rec->text, cctxt->rec->text_area_name); 
            caculate_time_elapsed (cctxt->rec);
            text_cb (cctxt->rec->fp, event, cctxt->rec->text_window_name,
                   cctxt->rec->text_role, cctxt->rec->window_type,
                   cctxt->rec->text_area_name, cctxt->rec->text);
            g_free (cctxt->rec->text_role);
            if (cctxt->rec->text) {
                  g_free (cctxt->rec->text);
                  cctxt->rec->text = NULL;
            }
      }
}

static void
name_change_cb (const AccessibleEvent *event, void *user_data)
{
      char *tmp = NULL;
      LDTPClientContext *cctxt = (LDTPClientContext*)user_data;
      int class_id = Accessible_getRole (event->source);

      if (class_id == SPI_ROLE_FRAME || class_id == SPI_ROLE_DIALOG || class_id == SPI_ROLE_ALERT) {
            g_free (cctxt->rec->window_name);
            tmp = Accessible_getName (event->source);
            cctxt->rec->window_name = g_strdup (tmp);
            if (cctxt->rec->window_name)
                  g_print ("Setting the window title as %s\n", cctxt->rec->window_name);
            SPI_freeString (tmp);
      }
}

static void
start_record (LDTPClientContext *cctxt)
{
      cctxt->rec->text_listener = SPI_createAccessibleEventListener (text_changed_cb, cctxt);
      cctxt->rec->focus_listener = SPI_createAccessibleEventListener (focus_cb, cctxt);
      cctxt->rec->window_listener = SPI_createAccessibleEventListener (window_cb, cctxt);
      cctxt->rec->generic_listener = SPI_createAccessibleEventListener (generic_cb, cctxt);
      cctxt->rec->mouseclick_listener = SPI_createAccessibleEventListener (mouse_click_cb, cctxt); 
      cctxt->rec->name_changed_listener = SPI_createAccessibleEventListener (name_change_cb, cctxt);
      cctxt->rec->state_changed_listener = SPI_createAccessibleEventListener (state_change_cb, cctxt);
      cctxt->rec->selection_changed_listener = SPI_createAccessibleEventListener (selection_changed_cb, cctxt);

      SPI_registerGlobalEventListener (cctxt->rec->focus_listener, "focus:");
      SPI_registerGlobalEventListener (cctxt->rec->generic_listener, "focus:");
      SPI_registerGlobalEventListener (cctxt->rec->window_listener, "window:activate");
      SPI_registerGlobalEventListener (cctxt->rec->text_listener, "object:text-changed");
      SPI_registerGlobalEventListener (cctxt->rec->generic_listener, "object:state-changed");
      SPI_registerGlobalEventListener (cctxt->rec->state_changed_listener, "object:state-changed");
      SPI_registerGlobalEventListener (cctxt->rec->selection_changed_listener, "object:selection-changed");
      SPI_registerGlobalEventListener (cctxt->rec->mouseclick_listener, "Gtk:GtkWidget:button-press-event");
      SPI_registerGlobalEventListener (cctxt->rec->name_changed_listener, "object:property-change:accessible-name");

      cctxt->rec->timer = g_timer_new ();
      cctxt->rec->window_role = -1;
      cctxt->rec->text = NULL;
      cctxt->rec->text_area_name = NULL;
      cctxt->rec->text_window_name = NULL;
      cctxt->rec->base_name = NULL;
      cctxt->rec->window_name = NULL;
      cctxt->rec->window_type = NULL;
      cctxt->rec->text_role = NULL;
      cctxt->rec->combobox_name = NULL;
      cctxt->rec->text_changed = FALSE;
      cctxt->rec->clicked = TRUE;
      cctxt->rec->combobox_changed = FALSE;
}

static LDTPErrorCode
stop_record (LDTPClientContext *cctxt)
{
      /*
       * First deregister the global event listeners 
       * Unref the corresponding  event-listerners 
       * Close the opened tags(</RECORD>) and then Close the file 
       * Send the xml data to the client
       */
      uint32_t resp_size = 0;

      LDTPErrorCode err;
      char *resp_pckt = NULL;

      g_print ("==DEBUG== Inside Function stop_record\n");
      g_print ("Event Listeners Deregistered\n");
      if (cctxt->rec->text_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->text_listener);
            AccessibleEventListener_unref (cctxt->rec->text_listener);
      }
      if (cctxt->rec->focus_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->focus_listener);
            AccessibleEventListener_unref (cctxt->rec->focus_listener);
      }
      if (cctxt->rec->window_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->window_listener);
            AccessibleEventListener_unref (cctxt->rec->window_listener);
      }
      if (cctxt->rec->generic_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->generic_listener);
            AccessibleEventListener_unref (cctxt->rec->generic_listener);
      }
      if (cctxt->rec->mouseclick_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->mouseclick_listener);
            AccessibleEventListener_unref (cctxt->rec->mouseclick_listener);
      }
      if (cctxt->rec->name_changed_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->name_changed_listener);
            AccessibleEventListener_unref (cctxt->rec->name_changed_listener);
      }
      if (cctxt->rec->state_changed_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->state_changed_listener);
            AccessibleEventListener_unref (cctxt->rec->state_changed_listener);
      }
      if (cctxt->rec->selection_changed_listener != NULL) {
            SPI_deregisterGlobalEventListenerAll (cctxt->rec->selection_changed_listener);
            AccessibleEventListener_unref (cctxt->rec->selection_changed_listener); 
      }

      cctxt->rec->text_listener    = NULL;
      cctxt->rec->focus_listener   = NULL;
      cctxt->rec->window_listener  = NULL;
      cctxt->rec->generic_listener = NULL;
      cctxt->rec->mouseclick_listener    = NULL;
      cctxt->rec->state_changed_listener = NULL;
      cctxt->rec->name_changed_listener  = NULL;
      cctxt->rec->selection_changed_listener = NULL;

      g_print ("Event Listeners unrefed\n");

      g_print ("FP: %d - %s\n", fileno (cctxt->rec->fp), cctxt->rec->filename);
      if (cctxt->rec->fp && cctxt->rec->filename) {
            fprintf (cctxt->rec->fp, "</RECORD>\n");
            fclose (cctxt->rec->fp);
            cctxt->rec->fp = NULL;
            g_print ("file pointer closed\n");

            cctxt->resp->data = g_strdup (cctxt->rec->filename);
            cctxt->resp->data_len = g_utf8_strlen (cctxt->rec->filename, -1);
            g_free (cctxt->rec->filename);
            cctxt->rec->filename = NULL;

            err =  (LDTP_ERROR_SUCCESS);
      }
      else {
            err =  (LDTP_ERROR_WRONG_COMMAND_SEQUENCE);
      }
      /* 
         Notify to client
      */

      cctxt->resp->resp_status = err;
      generate_record_response_packet (cctxt, &err, &resp_pckt, &resp_size);
      if (err != LDTP_ERROR_SUCCESS) {
            log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (err), cctxt->log_fp);
            g_print ("Error generating response\n");
            return err;
      }
      send_response (cctxt->sock_fd, resp_pckt, resp_size, NULL);
      g_free (resp_pckt);
      g_print ("Client notified\n");

      if (cctxt->rec->timer) {
            g_timer_destroy (cctxt->rec->timer);
            cctxt->rec->timer = NULL;
      }
      return  (LDTP_ERROR_STOP_RECORD_THREAD);
}

LDTPErrorCode
record_main (LDTPClientContext* cctxt, int command)
{
      LDTPErrorCode error;
      if (cctxt->req->application && command)
            g_print ("Record_main command for the application %s - %d\n", cctxt->req->application, command);
      if (command == LDTP_CMD_STARTRECORD) {
            init_record_file (cctxt, &error);
            if (error != LDTP_ERROR_SUCCESS)
                  return error;
            start_record (cctxt);
            error =  (LDTP_ERROR_SUCCESS);
      }
      else if (command == LDTP_CMD_STOPRECORD) {
            error = stop_record (cctxt);
      }
      else
            error =  (LDTP_ERROR_INVALID_COMMAND);
      return error;
}

Generated by  Doxygen 1.6.0   Back to index