Sophie

Sophie

distrib > Mageia > 3 > i586 > media > core-release-src > by-pkgid > 795bbad4dbe6d492b24b4c970241c726 > files > 4

ruby-selenium-webdriver-2.26.0-4.mga3.src.rpm

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/X.h>
#include <dlfcn.h>
#include <sys/utsname.h>
#include <string.h>
#include "print_events.h"
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

// Define this to prevent events from being faked.
//#undef NO_FAKING

//#define DEBUG_PRINTOUTS

#ifdef DEBUG_PRINTOUTS
FILE* g_out_stream = 0;
#define LOG(...) if (g_out_stream != NULL) { fprintf(g_out_stream, __VA_ARGS__); fflush(g_out_stream); }
#define OPEN_LOGGING_FILE { g_out_stream = fopen("/tmp/x_ignore_focus_log.txt", "a+"); }
#define CLOSE_LOGGING_FILE { fclose(g_out_stream); g_out_stream = NULL; }
#else
// This is to prevent compiler warning for unused variables.
void do_nothing(const char* fmt, ...) {}
#define LOG(...) do_nothing(__VA_ARGS__)
#define OPEN_LOGGING_FILE ;
#define CLOSE_LOGGING_FILE ;
#endif

int g_library_inited = FALSE;

struct _FocusKeepStatus {
  Window active_window;
  Window new_window;
  int during_switch;
  int during_close;
  int should_steal_focus;
  int encountered_focus_in_event;
  int active_window_from_close;
};

typedef struct _FocusKeepStatus FocusKeepStatus;

void init_focus_keep_struct(FocusKeepStatus* stat)
{
  stat->active_window = 0;
  stat->new_window = 0;
  stat->during_switch = FALSE;
  stat->during_close = FALSE;
  stat->should_steal_focus = FALSE;
  // This boolean is for remembering if we already had a FocusIn event and
  // never re-send that event as well, not to break clients which expect to get
  // FocusOut before FocusIn
  stat->encountered_focus_in_event = FALSE;
  // This remembers if the active was learnt due to a close
  stat->active_window_from_close = FALSE;
};

Window get_active_window(FocusKeepStatus* stat)
{
  return stat->active_window;
}

int is_focus_out(XEvent* ev)
{
  return (ev->type == FocusOut);
}

int is_focus_in(XEvent* ev)
{
  return (ev->type == FocusIn);
}

int is_reparent_notify(XEvent* ev)
{
  return (ev->type == ReparentNotify);
}

int is_destroy_notify(XEvent* ev)
{
  return (ev->type == DestroyNotify);
}

Window extract_window_id(XEvent* ev);

struct {
  Window window_id;
  Window* related_windows;
} g_cached_xquerytree;

void init_cached_xquerytree()
{
  g_cached_xquerytree.window_id = 0;
  g_cached_xquerytree.related_windows = 0;
}

// Performing XQueryTree after UnmapNotify for some of the
// windows will cause a crash. Cache to prevent it.
int cache_xquery_result(Display* dpy, Window for_win) {
  Window root_win = 0;
  Window parent_win = 0;
  Window* childs_list = NULL;
  unsigned int num_childs = 0;
  int k = 0;

  if ((g_cached_xquerytree.window_id == for_win) &&
      (g_cached_xquerytree.related_windows != NULL)) {
    return TRUE;
  }

  LOG("Invoking XQueryTree for window %#lx\n", for_win);
  int queryRes = XQueryTree(dpy, for_win, &root_win,
                            &parent_win, &childs_list, &num_childs);
  if (queryRes == 0) {
    LOG("XQueryTree failed, rc=%d\n", queryRes);
    return FALSE;
  }

  if (g_cached_xquerytree.related_windows != NULL) {
    free(g_cached_xquerytree.related_windows);
    g_cached_xquerytree.related_windows = NULL;
  }

  int numRelatedWindows = (1 /* parent_win */ +
                           1 /* actual win */ + num_childs + 1 /* NULL */);


  g_cached_xquerytree.related_windows = malloc(sizeof(Window) * numRelatedWindows);
  LOG("Allocated at address %p , numRelWindows: %d\n",
      g_cached_xquerytree.related_windows, numRelatedWindows);
  int relatedWinsIndex = 0;
  g_cached_xquerytree.related_windows[relatedWinsIndex++] = parent_win;
  g_cached_xquerytree.related_windows[relatedWinsIndex++] = for_win;

  if ((num_childs > 0) && (childs_list != NULL)) {
    for (k = 0; k < num_childs; k++) {
      g_cached_xquerytree.related_windows[relatedWinsIndex++] = childs_list[k];
    }
    XFree(childs_list);
    childs_list = NULL;
  }
  g_cached_xquerytree.related_windows[relatedWinsIndex] = 0;

  g_cached_xquerytree.window_id = for_win;

  return TRUE;
}

int lookup_in_xquery_cache(Window ev_win)
{
  int ret_val = FALSE;
  int k = 0;
  if (g_cached_xquerytree.related_windows == NULL) {
    LOG("related_windows is NULL, cache is inconsistent.\n");
    return FALSE;
  }
  while ((g_cached_xquerytree.related_windows[k] != 0) && (!ret_val)) {
    if (g_cached_xquerytree.related_windows[k] == ev_win) {
      ret_val = TRUE;
    }
    k++;
  }

  return ret_val;
}

int window_ids_difference(Window win_one, Window win_two)
{
  return (abs(win_one - win_two));
}

int event_on_active_or_adj_window(Display* dpy, XEvent* ev, Window active_win)
{
  Window ev_win;
  int ret_val = FALSE;

  ev_win = extract_window_id(ev);

  // This is probably also essential as on focus in events on new windows
  // XQueryTree should not be called yet.
  if (active_win == ev_win) {
    return TRUE;
  }

  if (cache_xquery_result(dpy, active_win)) {
    ret_val = lookup_in_xquery_cache(ev_win);
  } else {
    // Fall back to +/-1 comparison...
    ret_val = (abs(active_win - ev_win) <= 1);
  }

  return ret_val;
}

#define MAX_BUFFER_SIZE (256)

void identify_switch_situation(FocusKeepStatus* stat)
{
  char switch_data[MAX_BUFFER_SIZE];
  FILE* switch_fp = fopen("/tmp/switch_window_started", "r");

  if (switch_fp != NULL) {
    // In the middle of a window switch.
    Window old_active = get_active_window(stat);
    stat->active_window = 0;
    stat->during_switch = TRUE;
    memset(switch_data, '\0', MAX_BUFFER_SIZE);
    fread(switch_data, sizeof(char), MAX_BUFFER_SIZE, switch_fp);
    fclose(switch_fp);
    unlink("/tmp/switch_window_started");
    if (strstr(switch_data, "close:") == switch_data) {
      stat->during_close = TRUE;
    }
    LOG("Window switching detected, active was: %#lx info: %s close: %d\n",
        old_active, switch_data, stat->during_close);
  }
}

void set_active_window(FocusKeepStatus* stat, XEvent* ev)
{
  stat->active_window = extract_window_id(ev);
  if (stat->during_close) {
    stat->active_window_from_close = TRUE;
  } else {
    stat->active_window_from_close = FALSE;
  }
  stat->encountered_focus_in_event = FALSE;
  stat->during_switch = FALSE;
  unlink("/tmp/switch_window_started");
  LOG("Setting Active Window due to FocusIn: %#lx (from close: %d)\n",
      get_active_window(stat), stat->active_window_from_close);
}

void identify_new_window_situation(FocusKeepStatus* stat, XEvent* ev)
{
  Window new_win = extract_window_id(ev);
  assert(is_reparent_notify(ev));

  if (get_active_window(stat) != 0) {
    stat->new_window = new_win;
    LOG("New window being created: %#lx\n", stat->new_window);
  } else {
    LOG("Reparent notify for window: %#lx, but no active.\n", new_win);
  }
}

void identify_active_destroyed(FocusKeepStatus* stat, XEvent* ev)
{
  assert(is_destroy_notify(ev));

  if (extract_window_id(ev) == get_active_window(stat)) {
    LOG("Active window: %#lx is destroyed!\n", get_active_window(stat));
    stat->active_window = 0;
  }
}

void steal_focus_back_if_needed(FocusKeepStatus* stat, Display* dpy)
{
  if ((stat->should_steal_focus) && (get_active_window(stat) != 0)) {
    stat->should_steal_focus = FALSE;

    if ((!stat->during_close) || (stat->active_window_from_close)) {
      LOG("Stealing focus back to %#lx\n", get_active_window(stat));
      stat->new_window = 0;

      XSetInputFocus(dpy, get_active_window(stat), RevertToParent, CurrentTime);
      // Allow a focus in event to flow again to the window considered
      // active.
      stat->encountered_focus_in_event = FALSE;
    } else {
      LOG("Not stealing focus back. During close: %d Active from close: %d.\n",
          stat->during_close, stat->active_window_from_close);
      // Set during_close to false here - This is the point where the state
      // transition is done - specifically, we consider the entire close
      // process to be completed.
      stat->during_close = FALSE;
    }
  }
}

int should_discard_focus_out_event(FocusKeepStatus* stat, Display* dpy,
                                   XEvent *ev)
{
  int ret_val = FALSE;
  if (is_focus_out(ev) == FALSE) {
    return FALSE;
  }

  const int detail = ev->xfocus.detail;

  if (stat->new_window != 0) {
    /*
    if (!(event_on_active_or_adj_window(dpy, ev, stat->new_window)
        || event_on_active_or_adj_window(dpy, ev, get_active_window(stat)))) {
      LOG( "ERROR - Event on window %#lx, which is neither new nor active.\n",
           extract_window_id(ev));
    } else */ {
      LOG("Event on new/active (%#lx) during new window creation, allowing.",
          extract_window_id(ev));
      LOG(" New: %#lx Active: %#lx\n", stat->new_window, stat->active_window);
    }
    return FALSE;
  }

  if (event_on_active_or_adj_window(dpy, ev, get_active_window(stat))) {
    // If moving ownership between sub-windows of the same Firefox window.
    if ((detail == NotifyAncestor) || (detail == NotifyInferior)) {
      // Allow this one.
      LOG("Focus will move to ancestor / inferior (%d). Allowing.\n", detail);
      stat->encountered_focus_in_event = FALSE;
    } else {
      // Disallow transfer of focus to outside windows.
      if (!stat->active_window_from_close) {
        ret_val = TRUE;
      } else {
        LOG("FocusOut event, but active window from close. Not discarding.\n");
      }
    }
  } else {
    LOG("Got Focus out event on window %#lx but active window is %#lx\n",
        extract_window_id(ev), get_active_window(stat));
  }

  return ret_val;
}

int should_discard_focus_in_event(FocusKeepStatus* stat, Display* dpy,
                                  XEvent *ev)
{
  int ret_val = FALSE;
  if (is_focus_in(ev) == FALSE) {
    return FALSE;
  }

  // Event not on active window - It's either on a new window currently being
  // created or on a different firefox one. On the first case, it will
  // be allowed through, but blocked on the second case.
  if (!event_on_active_or_adj_window(dpy, ev, get_active_window(stat))) {
    LOG("Got Focus in event on window %#lx but active window is %#lx\n",
        extract_window_id(ev), get_active_window(stat));

    if (stat->new_window != 0) {
      // If we are in the process of a new window creation, do not ignore
      // this focus in event - allow it both for the new window
      // and for a child window of it. However, if this is a focus in
      // event for a child window (not the new window itself), then
      // steal focus back from it afterwards.
      ret_val = FALSE;
      Window curr_win = extract_window_id(ev);
      if (curr_win == stat->new_window) {
        LOG("FocusIn event on new window - allowing.\n");
      } else {
        //if (event_on_active_or_adj_window(dpy, ev, stat->new_window) == FALSE) {
        if (window_ids_difference(curr_win, stat->new_window) > 4) {
          LOG("ERROR - Event on window %#lx\n", extract_window_id(ev));
        } else {
          LOG("FocusIn event on child of new window - steal focus!\n");
        }
        stat->should_steal_focus = TRUE;
      }
    } else {
      // Second case: No new window creation process disallow focus in
      ret_val = TRUE;
    }
  } else {
    // Event actually on the active window or an inferior window
    // of it.
    if (stat->encountered_focus_in_event == FALSE) {
      // If a focus in event for this window was not yet encountered,
      // allow this focus in event and ignore in the future.
      stat->encountered_focus_in_event = TRUE;
      ret_val = FALSE;
    } else {
      ret_val = TRUE;
    }
  }

  return ret_val;
}

#ifndef NO_FAKING
// Real functions
void fake_keymap_notify_event(XEvent* outEvent, XEvent* sourceEvent)
{
  XEvent ev;
  ev.type = KeymapNotify;
  ev.xkeymap.serial = sourceEvent->xfocus.serial;
  ev.xkeymap.send_event = sourceEvent->xfocus.send_event;
  ev.xkeymap.display = sourceEvent->xfocus.display;
  ev.xkeymap.window = sourceEvent->xfocus.window;
  //bzero(ev.xkeymap.key_vector, 32);
  *outEvent = ev;
}

#else
// Dummy functions - faking will not happen.
void fake_keymap_notify_event(XEvent* outEvent, XEvent* sourceEvent)
{
  LOG("*** Not faking keymap notify event.\n");
  *outEvent = *sourceEvent;
}

static int XSetInputFocus(Display *display, Window focus, int revert_to,
                          Time time)
{
  LOG("*** Not stealing focus.\n");
  return 1;
}

#endif

int is_emulated_32bit()
{
#ifdef __i386__
    struct utsname sys_info;
    int uname_res = uname(&sys_info);
    // In case of error, most chances are - not emulated.
    if (uname_res != 0) {
      return FALSE;
    }

    const char arch_64[] = "x86_64";
    if (strncmp(sys_info.machine, arch_64, strlen(arch_64)) == 0) {
      return TRUE;
    }

    return FALSE;
#else
    return FALSE;
#endif
}

#define MAX_LIBRARY_PATH (1024)

// Returns the window ID from every type of event
// that should be handled.
Window extract_window_id(XEvent* ev) {
  switch (ev->type) {
    case FocusIn:
      return ev->xfocus.window;
      break;
    case FocusOut:
      return ev->xfocus.window;
      break;
    case Expose:
      return ev->xexpose.window;
      break;
    case VisibilityNotify:
      return ev->xvisibility.window;
      break;
    case CreateNotify:
      return ev->xcreatewindow.window;
      break;
    case MapNotify:
      return ev->xmap.window;
      break;
    case PropertyNotify:
      return ev->xproperty.window;
      break;
    case DestroyNotify:
      return ev->xdestroywindow.window;
      break;
    case ConfigureNotify:
      return ev->xconfigure.window;
      break;
    case MotionNotify:
      return ev->xmotion.window;
      break;
    case UnmapNotify:
      return ev->xunmap.window;
      break;
    case EnterNotify:
    case LeaveNotify:
      return ev->xcrossing.window;
      break;
    case ReparentNotify:
      return ev->xreparent.window;
      break;
    case ClientMessage:
      return ev->xclient.window;
      break;
    case ButtonPress:
    case ButtonRelease:
      return ev->xbutton.window;
      break;
    case NoExpose:
      break;
    default:
      LOG("Unknown event type %d\n", ev->type);
  };
  return 0;
}

void* get_xlib_handle()
{
  void* ret_handle = NULL;
  char library[MAX_LIBRARY_PATH + 1];
  // If we're not emulating a 32 bit mode (which is either native 32 bit
  // or native 64 bit) - use the ordinary path for libX11
  if (is_emulated_32bit() == FALSE) {
    snprintf(library, MAX_LIBRARY_PATH, "/usr/lib/libX11.so.6");
  } else {
    // Use a path that usually contains the 32 bit libs in a 64 bit system.
    snprintf(library, MAX_LIBRARY_PATH, "/usr/lib32/libX11.so.6");
  }

  ret_handle = dlopen(library, RTLD_LAZY);
  if (ret_handle == NULL) {
    fprintf(stderr, "Failed to dlopen %s\n", library);
    fprintf(stderr, "dlerror says: %s\n", dlerror());
  }

  return ret_handle;
}

void print_event_to_log(Display* dpy, XEvent* ev)
{
#ifdef DEBUG_PRINTOUTS
  if ((ev->type != PropertyNotify) && (ev->type != ConfigureNotify)) {
    print_event(g_out_stream, ev, dpy);
  }
#endif
}

// This global variable is intentionally declared here - as I wish the rest
// of the functions will act on it as a parameter.
FocusKeepStatus g_focus_status;

int XNextEvent(Display *display, XEvent *outEvent) {
  // Code to pull the real function handle from X11 library.
  void *handle = NULL;

  //This will turn the function proto into a function pointer declaration
  int (*real_func)(Display *display, XEvent *outEvent) = NULL;
  handle = get_xlib_handle();

  if (handle == NULL) {
    return -1;
  }

  // The real event from XNextEvent
  XEvent realEvent;

  // Find the real function.
  real_func = dlsym(handle, "XNextEvent");
  // Invoke the real function.
  int rf_ret = real_func(display, &realEvent);

  OPEN_LOGGING_FILE;

  if (g_library_inited == FALSE) {
    LOG("Library initialized.\n");
    g_library_inited = TRUE;
    init_cached_xquerytree();
    init_focus_keep_struct(&g_focus_status);
  }


  // This display object will be used to inquire X server
  // about inferior and parent windows.
  Display* dpy = display;
  //assert(dpy != NULL);

  print_event_to_log(dpy, &realEvent);

  // Is the event on a window other than the active one?
  // If so, update gActiveWindow on two cases:
  // 1. It's the first window known to the module.
  // 2. It's the second window known to the module. The second
  // window is the actual browser window (the first one is just a
  // set-up one).
  //
  if ((get_active_window(&g_focus_status) == 0) && (is_focus_in(&realEvent))) {
    set_active_window(&g_focus_status, &realEvent);
  } else {
    identify_switch_situation(&g_focus_status);
  }

  if (is_reparent_notify(&realEvent)) {
    identify_new_window_situation(&g_focus_status, &realEvent);
  }

  if (is_destroy_notify(&realEvent)) {
    identify_active_destroyed(&g_focus_status, &realEvent);
  }

  if ((g_focus_status.during_switch == TRUE) ||
      (get_active_window(&g_focus_status) == 0)) {
      LOG("During switch: %d Active win: %#lx during close: %d\n",
          g_focus_status.during_switch, get_active_window(&g_focus_status),
          g_focus_status.during_close);
    *outEvent = realEvent;
  } else if (should_discard_focus_out_event(&g_focus_status, dpy, &realEvent)) {
    // Fake an event!
    fake_keymap_notify_event(outEvent, &realEvent);
    LOG("Fake event for focus out.\n");
  }  else if (should_discard_focus_in_event(&g_focus_status, dpy, &realEvent)) {
    fake_keymap_notify_event(outEvent, &realEvent);
    LOG("Fake event for focus in.\n");
  } else {
    *outEvent = realEvent;
  }

  steal_focus_back_if_needed(&g_focus_status, dpy);

  dlclose(handle);
  CLOSE_LOGGING_FILE;
  return rf_ret;
}