<commit_before>/*
 * Clutter.
 *
 * An OpenGL based 'interactive canvas' library.
 *
 * Authored By <NAME>  <<EMAIL>>
 *
 * Copyright (C) 2006 OpenedHand
 *
 * This library is free software; you can redistribute it and/or
 * modify it 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.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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.
 */

/**
 * SECTION:clutter-stage
 * @short_description: Top level visual element to which actors are placed.
 *
 * #ClutterStage is a top level 'window' on which child actors are placed
 * and manipulated.
 *
 * Clutter creates a default stage upon initialization, which can be retrieved
 * using clutter_stage_get_default(). Clutter always provides the default
 * stage, unless the backend is unable to create one. The stage returned
 * by clutter_stage_get_default() is guaranteed to always be the same.
 *
 * Backends might provide support for multiple stages. The support for this
 * feature can be checked at run-time using the clutter_feature_available()
 * function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used
 * supports multiple stages, new #ClutterStage instances can be created
 * using clutter_stage_new(). These stages must be managed by the developer
 * using clutter_actor_destroy(), which will take care of destroying all the
 * actors contained inside them.
 *
 * #ClutterStage is a proxy actor, wrapping the backend-specific
 * implementation of the windowing system. It is possible to subclass
 * #ClutterStage, as long as every overridden virtual function chains up to
 * the parent class corresponding function.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "clutter-backend.h"
#include "clutter-stage.h"
#include "clutter-main.h"
#include "clutter-color.h"
#include "clutter-util.h"
#include "clutter-marshal.h"
#include "clutter-master-clock.h"
#include "clutter-enum-types.h"
#include "clutter-private.h"
#include "clutter-debug.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-version.h" 	/* For flavour */
#include "clutter-id-pool.h"
#include "clutter-container.h"
#include "clutter-profile.h"
#include "clutter-input-device.h"

#include "cogl/cogl.h"

G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);

#define CLUTTER_STAGE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_STAGE, ClutterStagePrivate))

struct _ClutterStagePrivate
{
  /* the stage implementation */
  ClutterStageWindow *impl;
  guint               minimum_width;
  guint               minimum_height;

  ClutterColor        color;
  ClutterPerspective  perspective;
  ClutterFog          fog;

  gchar              *title;
  ClutterActor       *key_focused_actor;

  GQueue             *event_queue;

  guint redraw_pending         : 1;
  guint is_fullscreen          : 1;
  guint is_cursor_visible      : 1;
  guint is_user_resizable      : 1;
  guint use_fog                : 1;
  guint throttle_motion_events : 1;
  guint use_alpha              : 1;
};

enum
{
  PROP_0,

  PROP_COLOR,
  PROP_FULLSCREEN_SET,
  PROP_OFFSCREEN,
  PROP_CURSOR_VISIBLE,
  PROP_PERSPECTIVE,
  PROP_TITLE,
  PROP_USER_RESIZE,
  PROP_USE_FOG,
  PROP_FOG,
  PROP_USE_ALPHA,
  PROP_KEY_FOCUS
};

enum
{
  FULLSCREEN,
  UNFULLSCREEN,
  ACTIVATE,
  DEACTIVATE,
  DELETE_EVENT,

  LAST_SIGNAL
};

static guint stage_signals[LAST_SIGNAL] = { 0, };

static const ClutterColor default_stage_color = { 255, 255, 255, 255 };

static void
clutter_stage_get_preferred_width (ClutterActor *self,
                                   gfloat        for_height,
                                   gfloat       *min_width_p,
                                   gfloat       *natural_width_p)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  ClutterGeometry geom = { 0, };

  if (priv->impl == NULL)
    return;

  _clutter_stage_window_get_geometry (priv->impl, &geom);

  if (min_width_p)
    *min_width_p = geom.width;

  if (natural_width_p)
    *natural_width_p = geom.width;
}

static void
clutter_stage_get_preferred_height (ClutterActor *self,
                                    gfloat        for_width,
                                    gfloat       *min_height_p,
                                    gfloat       *natural_height_p)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  ClutterGeometry geom = { 0, };

  if (priv->impl == NULL)
    return;

  _clutter_stage_window_get_geometry (priv->impl, &geom);

  if (min_height_p)
    *min_height_p = geom.height;

  if (natural_height_p)
    *natural_height_p = geom.height;
}
static void
clutter_stage_allocate (ClutterActor           *self,
                        const ClutterActorBox  *box,
                        ClutterAllocationFlags  flags)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  ClutterGeometry geom = { 0, };
  gboolean origin_changed;
  gint width, height;

  origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? TRUE : FALSE;

  if (priv->impl == NULL)
    return;

  width = clutter_actor_box_get_width (box);
  height = clutter_actor_box_get_height (box);
  _clutter_stage_window_get_geometry (priv->impl, &geom);

  /* XXX: Until Cogl becomes fully responsible for backend windows Clutter
   * need to manually keep it informed of the current window size */
  _cogl_onscreen_clutter_backend_set_size (geom.width, geom.height);

  /* if the stage is fixed size (for instance, it's using a frame-buffer)
   * then we simply ignore any allocation request and override the
   * allocation chain.
   */
  if ((!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)))
    {
      ClutterActorClass *klass;

      CLUTTER_NOTE (LAYOUT,
                    "Following allocation to %dx%d (origin %s)",
                    width, height,
                    origin_changed ? "changed" : "not changed");

      klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
      klass->allocate (self, box, flags);

      /* Ensure the window is sized correctly */
      if (!priv->is_fullscreen &&
          ((geom.width != width) || (geom.height != height)))
        _clutter_stage_window_resize (priv->impl, width, height);
    }
  else
    {
      ClutterActorBox override = { 0, };
      ClutterActorClass *klass;

      override.x1 = 0;
      override.y1 = 0;
      override.x2 = geom.width;
      override.y2 = geom.height;

      CLUTTER_NOTE (LAYOUT,
                    "Overrigin original allocation of %dx%d "
                    "with %dx%d (origin %s)",
                    width, height,
                    (int) (override.x2),
                    (int) (override.y2),
                    origin_changed ? "changed" : "not changed");

      /* and store the overridden allocation */
      klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
      klass->allocate (self, &override, flags);
    }
}

static void
clutter_stage_paint (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  CoglColor stage_color;
  guint8 real_alpha;
  CLUTTER_STATIC_TIMER (stage_clear_timer,
                        "Painting actors", /* parent */
                        "Stage clear",
                        "The time spent clearing the stage",
                        0 /* no application private data */);

  CLUTTER_NOTE (PAINT, "Initializing stage paint");

  /* composite the opacity to the stage color */
  real_alpha = clutter_actor_get_opacity (self)
             * priv->color.alpha
             / 255;

  /* we use the real alpha to clear the stage if :use-alpha is
   * set; the effect depends entirely on how the Clutter backend
   */
  cogl_color_set_from_4ub (&stage_color,
                           priv->color.red,
                           priv->color.green,
                           priv->color.blue,
                           priv->use_alpha ? real_alpha
                                           : 255);
  cogl_color_premultiply (&stage_color);

  CLUTTER_TIMER_START (_clutter_uprof_context, stage_clear_timer);
  cogl_clear (&stage_color,
	      COGL_BUFFER_BIT_COLOR |
	      COGL_BUFFER_BIT_DEPTH);
  CLUTTER_TIMER_STOP (_clutter_uprof_context, stage_clear_timer);

  if (priv->use_fog)
    {
      /* we only expose the linear progression of the fog in
       * the ClutterStage API, and that ignores the fog density.
       * thus, we pass 1.0 as the density parameter
       */
      cogl_set_fog (&stage_color,
                    COGL_FOG_MODE_LINEAR,
                    1.0,
                    priv->fog.z_near,
                    priv->fog.z_far);
    }
  else
    cogl_disable_fog ();

  /* this will take care of painting every child */
  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self);
}

static void
clutter_stage_pick (ClutterActor       *self,
		    const ClutterColor *color)
{
  /* Note: we don't chain up to our parent as we don't want any geometry
   * emitted for the stage itself. The stage's pick id is effectively handled
   * by the call to cogl_clear done in clutter-main.c:_clutter_do_pick_async()
   */
  clutter_container_foreach (CLUTTER_CONTAINER (self),
                             CLUTTER_CALLBACK (clutter_actor_paint),
                             NULL);
}

static void
clutter_stage_realize (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  gboolean is_realized;

  /* Make sure the viewport and projection matrix are valid for the
   * first paint (which will likely occur before the ConfigureNotify
   * is received)
   */
  CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES);

  g_assert (priv->impl != NULL);
  is_realized = _clutter_stage_window_realize (priv->impl);

  /* ensure that the stage is using the context if the
   * realization sequence was successful
   */
  if (is_realized)
    {
      ClutterBackend *backend = clutter_get_default_backend ();
      GError *error = NULL;

      /* We want to select the context without calling
         clutter_backend_ensure_context so that it doesn't call any
         Cogl functions. Otherwise it would create the Cogl context
         before we get a chance to check whether the GL version is
         valid */
      _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));

      /* Make sure Cogl can support the driver */
      if (!_cogl_check_driver_valid (&error))
        {
          g_critical ("The GL driver is not supported: %s",
                      error->message);
          g_clear_error (&error);
          CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
        }
      else
        CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
    }
  else
    CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}

static void
clutter_stage_unrealize (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  /* and then unrealize the implementation */
  g_assert (priv->impl != NULL);
  _clutter_stage_window_unrealize (priv->impl);

  CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);

  clutter_stage_ensure_current (CLUTTER_STAGE (self));
}

static void
clutter_stage_show (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);

  /* Possibly do an allocation run so that the stage will have the
     right size before we map it */
  _clutter_stage_maybe_relayout (self);

  g_assert (priv->impl != NULL);
  _clutter_stage_window_show (priv->impl, TRUE);
}

static void
clutter_stage_hide (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  g_assert (priv->impl != NULL);
  _clutter_stage_window_hide (priv->impl);

  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
}

static void
clutter_stage_emit_key_focus_event (ClutterStage *stage,
                                    gboolean      focus_in)
{
  ClutterStagePrivate *priv = stage->priv;

  if (priv->key_focused_actor == NULL)
    return;

  if (focus_in)
    g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
  else
    g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out");
}

static void
clutter_stage_real_activate (ClutterStage *stage)
{
  clutter_stage_emit_key_focus_event (stage, TRUE);
}

static void
clutter_stage_real_deactivate (ClutterStage *stage)
{
  clutter_stage_emit_key_focus_event (stage, FALSE);
}

static void
clutter_stage_real_fullscreen (ClutterStage *stage)
{
  ClutterStagePrivate *priv = stage->priv;
  ClutterGeometry geom;
  ClutterActorBox box;

  /* we need to force an allocation here because the size
   * of the stage might have been changed by the backend
   *
   * this is a really bad solution to the issues caused by
   * the fact that fullscreening the stage on the X11 backends
   * is really an asynchronous operation
   */
  _clutter_stage_window_get_geometry (priv->impl, &geom);

  box.x1 = 0;
  box.y1 = 0;
  box.x2 = geom.width;
  box.y2 = geom.height;

  clutter_actor_allocate (CLUTTER_ACTOR (stage),
                          &box,
                          CLUTTER_ALLOCATION_NONE);
}

void
_clutter_stage_queue_event (ClutterStage *stage,
			    ClutterEvent *event)
{
  ClutterStagePrivate *priv;
  gboolean first_event;
  ClutterInputDevice *device;

  g_return_if_fail (CLUTTER_IS_STAGE (stage));

  priv = stage->priv;

  first_event = priv->event_queue->length == 0;

  g_queue_push_tail (priv->event_queue, clutter_event_copy (event));

  if (first_event)
    {
      ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
      _clutter_master_clock_start_running (master_clock);
    }

  /* if needed, update the state of the input device of the event.
   * we do it here to avoid calling the same code from every backend
   * event processing function
   */
  device = clutter_event_get_device (event);
  if (device != NULL)
    {
      ClutterModifierType event_state = clutter_event_get_state (event);
      guint32 event_time = clutter_event_get_time (event);
      gfloat event_x, event_y;

      clutter_event_get_coords (event, &event_x, &event_y);

      _clutter_input_device_set_coords (device, event_x, event_y);
      _clutter_input_device_set_state (device, event_state);
      _clutter_input_device_set_time (device, event_time);
    }
}

gboolean
_clutter_stage_has_queued_events (ClutterStage *stage)
{
  ClutterStagePrivate *priv;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);

  priv = stage->priv;

  return priv->event_queue->length > 0;
}

void
_clutter_stage_process_queued_events (ClutterStage *stage)
{
  ClutterStagePrivate *priv;
  GList *events, *l;

  g_return_if_fail (CLUTTER_IS_STAGE (stage));

  priv = stage->priv;

  if (priv->event_queue->length == 0)
    return;

  /* In case the stage gets destroyed during event processing */
  g_object_ref (stage);

  /* Steal events before starting processing to avoid reentrancy
   * issues */
  events = priv->event_queue->head;
  priv->event_queue->head =  NULL;
  priv->event_queue->tail = NULL;
  priv->event_queue->length = 0;

  for (l = events; l != NULL; l = l->next)
    {
      ClutterEvent *event;
      ClutterEvent *next_event;

      event = l->data;
      next_event = l->next ? l->next->data : NULL;

      /* Skip consecutive motion events */
      if (priv->throttle_motion_events &&
          next_event &&
	  event->type == CLUTTER_MOTION &&
	  (next_event->type == CLUTTER_MOTION ||
	   next_event->type == CLUTTER_LEAVE))
	{
	  CLUTTER_NOTE (EVENT,
			"Omitting motion event at %.2f, %.2f",
			event->motion.x, event->motion.y);
	  goto next_event;
	}

      _clutter_process_event (event);

    next_event:
      clutter_event_free (event);<commit_msg>device: Motion events compression should honour the device<commit_after>/*
 * Clutter.
 *
 * An OpenGL based 'interactive canvas' library.
 *
 * Authored By <NAME>  <<EMAIL>>
 *
 * Copyright (C) 2006 OpenedHand
 *
 * This library is free software; you can redistribute it and/or
 * modify it 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.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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.
 */

/**
 * SECTION:clutter-stage
 * @short_description: Top level visual element to which actors are placed.
 *
 * #ClutterStage is a top level 'window' on which child actors are placed
 * and manipulated.
 *
 * Clutter creates a default stage upon initialization, which can be retrieved
 * using clutter_stage_get_default(). Clutter always provides the default
 * stage, unless the backend is unable to create one. The stage returned
 * by clutter_stage_get_default() is guaranteed to always be the same.
 *
 * Backends might provide support for multiple stages. The support for this
 * feature can be checked at run-time using the clutter_feature_available()
 * function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used
 * supports multiple stages, new #ClutterStage instances can be created
 * using clutter_stage_new(). These stages must be managed by the developer
 * using clutter_actor_destroy(), which will take care of destroying all the
 * actors contained inside them.
 *
 * #ClutterStage is a proxy actor, wrapping the backend-specific
 * implementation of the windowing system. It is possible to subclass
 * #ClutterStage, as long as every overridden virtual function chains up to
 * the parent class corresponding function.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "clutter-backend.h"
#include "clutter-stage.h"
#include "clutter-main.h"
#include "clutter-color.h"
#include "clutter-util.h"
#include "clutter-marshal.h"
#include "clutter-master-clock.h"
#include "clutter-enum-types.h"
#include "clutter-private.h"
#include "clutter-debug.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-version.h" 	/* For flavour */
#include "clutter-id-pool.h"
#include "clutter-container.h"
#include "clutter-profile.h"
#include "clutter-input-device.h"

#include "cogl/cogl.h"

G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);

#define CLUTTER_STAGE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_STAGE, ClutterStagePrivate))

struct _ClutterStagePrivate
{
  /* the stage implementation */
  ClutterStageWindow *impl;
  guint               minimum_width;
  guint               minimum_height;

  ClutterColor        color;
  ClutterPerspective  perspective;
  ClutterFog          fog;

  gchar              *title;
  ClutterActor       *key_focused_actor;

  GQueue             *event_queue;

  guint redraw_pending         : 1;
  guint is_fullscreen          : 1;
  guint is_cursor_visible      : 1;
  guint is_user_resizable      : 1;
  guint use_fog                : 1;
  guint throttle_motion_events : 1;
  guint use_alpha              : 1;
};

enum
{
  PROP_0,

  PROP_COLOR,
  PROP_FULLSCREEN_SET,
  PROP_OFFSCREEN,
  PROP_CURSOR_VISIBLE,
  PROP_PERSPECTIVE,
  PROP_TITLE,
  PROP_USER_RESIZE,
  PROP_USE_FOG,
  PROP_FOG,
  PROP_USE_ALPHA,
  PROP_KEY_FOCUS
};

enum
{
  FULLSCREEN,
  UNFULLSCREEN,
  ACTIVATE,
  DEACTIVATE,
  DELETE_EVENT,

  LAST_SIGNAL
};

static guint stage_signals[LAST_SIGNAL] = { 0, };

static const ClutterColor default_stage_color = { 255, 255, 255, 255 };

static void
clutter_stage_get_preferred_width (ClutterActor *self,
                                   gfloat        for_height,
                                   gfloat       *min_width_p,
                                   gfloat       *natural_width_p)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  ClutterGeometry geom = { 0, };

  if (priv->impl == NULL)
    return;

  _clutter_stage_window_get_geometry (priv->impl, &geom);

  if (min_width_p)
    *min_width_p = geom.width;

  if (natural_width_p)
    *natural_width_p = geom.width;
}

static void
clutter_stage_get_preferred_height (ClutterActor *self,
                                    gfloat        for_width,
                                    gfloat       *min_height_p,
                                    gfloat       *natural_height_p)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  ClutterGeometry geom = { 0, };

  if (priv->impl == NULL)
    return;

  _clutter_stage_window_get_geometry (priv->impl, &geom);

  if (min_height_p)
    *min_height_p = geom.height;

  if (natural_height_p)
    *natural_height_p = geom.height;
}
static void
clutter_stage_allocate (ClutterActor           *self,
                        const ClutterActorBox  *box,
                        ClutterAllocationFlags  flags)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  ClutterGeometry geom = { 0, };
  gboolean origin_changed;
  gint width, height;

  origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? TRUE : FALSE;

  if (priv->impl == NULL)
    return;

  width = clutter_actor_box_get_width (box);
  height = clutter_actor_box_get_height (box);
  _clutter_stage_window_get_geometry (priv->impl, &geom);

  /* XXX: Until Cogl becomes fully responsible for backend windows Clutter
   * need to manually keep it informed of the current window size */
  _cogl_onscreen_clutter_backend_set_size (geom.width, geom.height);

  /* if the stage is fixed size (for instance, it's using a frame-buffer)
   * then we simply ignore any allocation request and override the
   * allocation chain.
   */
  if ((!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)))
    {
      ClutterActorClass *klass;

      CLUTTER_NOTE (LAYOUT,
                    "Following allocation to %dx%d (origin %s)",
                    width, height,
                    origin_changed ? "changed" : "not changed");

      klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
      klass->allocate (self, box, flags);

      /* Ensure the window is sized correctly */
      if (!priv->is_fullscreen &&
          ((geom.width != width) || (geom.height != height)))
        _clutter_stage_window_resize (priv->impl, width, height);
    }
  else
    {
      ClutterActorBox override = { 0, };
      ClutterActorClass *klass;

      override.x1 = 0;
      override.y1 = 0;
      override.x2 = geom.width;
      override.y2 = geom.height;

      CLUTTER_NOTE (LAYOUT,
                    "Overrigin original allocation of %dx%d "
                    "with %dx%d (origin %s)",
                    width, height,
                    (int) (override.x2),
                    (int) (override.y2),
                    origin_changed ? "changed" : "not changed");

      /* and store the overridden allocation */
      klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
      klass->allocate (self, &override, flags);
    }
}

static void
clutter_stage_paint (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  CoglColor stage_color;
  guint8 real_alpha;
  CLUTTER_STATIC_TIMER (stage_clear_timer,
                        "Painting actors", /* parent */
                        "Stage clear",
                        "The time spent clearing the stage",
                        0 /* no application private data */);

  CLUTTER_NOTE (PAINT, "Initializing stage paint");

  /* composite the opacity to the stage color */
  real_alpha = clutter_actor_get_opacity (self)
             * priv->color.alpha
             / 255;

  /* we use the real alpha to clear the stage if :use-alpha is
   * set; the effect depends entirely on how the Clutter backend
   */
  cogl_color_set_from_4ub (&stage_color,
                           priv->color.red,
                           priv->color.green,
                           priv->color.blue,
                           priv->use_alpha ? real_alpha
                                           : 255);
  cogl_color_premultiply (&stage_color);

  CLUTTER_TIMER_START (_clutter_uprof_context, stage_clear_timer);
  cogl_clear (&stage_color,
	      COGL_BUFFER_BIT_COLOR |
	      COGL_BUFFER_BIT_DEPTH);
  CLUTTER_TIMER_STOP (_clutter_uprof_context, stage_clear_timer);

  if (priv->use_fog)
    {
      /* we only expose the linear progression of the fog in
       * the ClutterStage API, and that ignores the fog density.
       * thus, we pass 1.0 as the density parameter
       */
      cogl_set_fog (&stage_color,
                    COGL_FOG_MODE_LINEAR,
                    1.0,
                    priv->fog.z_near,
                    priv->fog.z_far);
    }
  else
    cogl_disable_fog ();

  /* this will take care of painting every child */
  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self);
}

static void
clutter_stage_pick (ClutterActor       *self,
		    const ClutterColor *color)
{
  /* Note: we don't chain up to our parent as we don't want any geometry
   * emitted for the stage itself. The stage's pick id is effectively handled
   * by the call to cogl_clear done in clutter-main.c:_clutter_do_pick_async()
   */
  clutter_container_foreach (CLUTTER_CONTAINER (self),
                             CLUTTER_CALLBACK (clutter_actor_paint),
                             NULL);
}

static void
clutter_stage_realize (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
  gboolean is_realized;

  /* Make sure the viewport and projection matrix are valid for the
   * first paint (which will likely occur before the ConfigureNotify
   * is received)
   */
  CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES);

  g_assert (priv->impl != NULL);
  is_realized = _clutter_stage_window_realize (priv->impl);

  /* ensure that the stage is using the context if the
   * realization sequence was successful
   */
  if (is_realized)
    {
      ClutterBackend *backend = clutter_get_default_backend ();
      GError *error = NULL;

      /* We want to select the context without calling
         clutter_backend_ensure_context so that it doesn't call any
         Cogl functions. Otherwise it would create the Cogl context
         before we get a chance to check whether the GL version is
         valid */
      _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));

      /* Make sure Cogl can support the driver */
      if (!_cogl_check_driver_valid (&error))
        {
          g_critical ("The GL driver is not supported: %s",
                      error->message);
          g_clear_error (&error);
          CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
        }
      else
        CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
    }
  else
    CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}

static void
clutter_stage_unrealize (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  /* and then unrealize the implementation */
  g_assert (priv->impl != NULL);
  _clutter_stage_window_unrealize (priv->impl);

  CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);

  clutter_stage_ensure_current (CLUTTER_STAGE (self));
}

static void
clutter_stage_show (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);

  /* Possibly do an allocation run so that the stage will have the
     right size before we map it */
  _clutter_stage_maybe_relayout (self);

  g_assert (priv->impl != NULL);
  _clutter_stage_window_show (priv->impl, TRUE);
}

static void
clutter_stage_hide (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  g_assert (priv->impl != NULL);
  _clutter_stage_window_hide (priv->impl);

  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
}

static void
clutter_stage_emit_key_focus_event (ClutterStage *stage,
                                    gboolean      focus_in)
{
  ClutterStagePrivate *priv = stage->priv;

  if (priv->key_focused_actor == NULL)
    return;

  if (focus_in)
    g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
  else
    g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out");
}

static void
clutter_stage_real_activate (ClutterStage *stage)
{
  clutter_stage_emit_key_focus_event (stage, TRUE);
}

static void
clutter_stage_real_deactivate (ClutterStage *stage)
{
  clutter_stage_emit_key_focus_event (stage, FALSE);
}

static void
clutter_stage_real_fullscreen (ClutterStage *stage)
{
  ClutterStagePrivate *priv = stage->priv;
  ClutterGeometry geom;
  ClutterActorBox box;

  /* we need to force an allocation here because the size
   * of the stage might have been changed by the backend
   *
   * this is a really bad solution to the issues caused by
   * the fact that fullscreening the stage on the X11 backends
   * is really an asynchronous operation
   */
  _clutter_stage_window_get_geometry (priv->impl, &geom);

  box.x1 = 0;
  box.y1 = 0;
  box.x2 = geom.width;
  box.y2 = geom.height;

  clutter_actor_allocate (CLUTTER_ACTOR (stage),
                          &box,
                          CLUTTER_ALLOCATION_NONE);
}

void
_clutter_stage_queue_event (ClutterStage *stage,
			    ClutterEvent *event)
{
  ClutterStagePrivate *priv;
  gboolean first_event;
  ClutterInputDevice *device;

  g_return_if_fail (CLUTTER_IS_STAGE (stage));

  priv = stage->priv;

  first_event = priv->event_queue->length == 0;

  g_queue_push_tail (priv->event_queue, clutter_event_copy (event));

  if (first_event)
    {
      ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
      _clutter_master_clock_start_running (master_clock);
    }

  /* if needed, update the state of the input device of the event.
   * we do it here to avoid calling the same code from every backend
   * event processing function
   */
  device = clutter_event_get_device (event);
  if (device != NULL)
    {
      ClutterModifierType event_state = clutter_event_get_state (event);
      guint32 event_time = clutter_event_get_time (event);
      gfloat event_x, event_y;

      clutter_event_get_coords (event, &event_x, &event_y);

      _clutter_input_device_set_coords (device, event_x, event_y);
      _clutter_input_device_set_state (device, event_state);
      _clutter_input_device_set_time (device, event_time);
    }
}

gboolean
_clutter_stage_has_queued_events (ClutterStage *stage)
{
  ClutterStagePrivate *priv;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);

  priv = stage->priv;

  return priv->event_queue->length > 0;
}

void
_clutter_stage_process_queued_events (ClutterStage *stage)
{
  ClutterStagePrivate *priv;
  GList *events, *l;

  g_return_if_fail (CLUTTER_IS_STAGE (stage));

  priv = stage->priv;

  if (priv->event_queue->length == 0)
    return;

  /* In case the stage gets destroyed during event processing */
  g_object_ref (stage);

  /* Steal events before starting processing to avoid reentrancy
   * issues */
  events = priv->event_queue->head;
  priv->event_queue->head =  NULL;
  priv->event_queue->tail = NULL;
  priv->event_queue->length = 0;

  for (l = events; l != NULL; l = l->next)
    {
      ClutterEvent *event;
      ClutterEvent *next_event;
      ClutterInputDevice *device;
      ClutterInputDevice *next_device;
      gboolean check_device = FALSE;

      event = l->data;
      next_event = l->next ? l->next->data : NULL;

      device = clutter_event_get_device (event);

      if (next_event != NULL)
        next_device = clutter_event_get_device (next_event);
      else
        next_device = NULL;

      if (device != NULL && next_device != NULL)
        check_device = TRUE;

      /* Skip consecutive motion events coming from the same device */
      if (priv->throttle_motion_events &&
          next_event != NULL &&
	  event->type == CLUTTER_MOTION &&
	  (next_event->type == CLUTTER_MOTION ||
	   next_event->type == CLUTTER_LEAVE) &&
          (!check_device || (device == next_device)))
	{
          CLUTTER_NOTE (EVENT,
                        "Omitting motion event at %d, %d",
                        (int) event->motion.x,
                        (int) event->motion.y);
          goto next_event;
	}

      _clutter_process_event (event);

    next_event:
      clutter_event_free (event);
{'fraction_non_alphanumeric': 0.08684886003321758, 'fraction_numerical': 0.004831647289747849, 'mean_word_length': 2.9084149651835243, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 157, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6778759', 'n_tokens_mistral': 10823, 'n_tokens_neox': 10319, 'n_words': 2799}