~ubuntu-branches/debian/sid/mutter/sid

« back to all changes in this revision

Viewing changes to src/core/util.c

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo Noronha Silva
  • Date: 2009-10-09 13:23:25 UTC
  • mfrom: (1.1.1 upstream) (0.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20091009132325-szsy1fm6qy9jmnpk
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#define _POSIX_C_SOURCE 200112L /* for fdopen() */
27
27
 
28
28
#include <config.h>
 
29
#include "common.h"
29
30
#include "util.h"
30
31
#include "main.h"
31
32
 
 
33
#include <clutter/clutter.h> /* For clutter_threads_add_repaint_func() */
 
34
 
32
35
#include <stdio.h>
33
36
#include <stdlib.h>
34
37
#include <unistd.h>
663
666
  return nexus_type;
664
667
}
665
668
 
 
669
/***************************************************************************
 
670
 * Later functions: like idles but integrated with the Clutter repaint loop
 
671
 ***************************************************************************/
 
672
 
 
673
static guint last_later_id = 0;
 
674
 
 
675
typedef struct
 
676
{
 
677
  guint id;
 
678
  MetaLaterType when;
 
679
  GSourceFunc func;
 
680
  gpointer data;
 
681
  GDestroyNotify notify;
 
682
  int source;
 
683
  gboolean run_once;
 
684
} MetaLater;
 
685
 
 
686
static GSList *laters = NULL;
 
687
/* This is a dummy timeline used to get the Clutter master clock running */
 
688
static ClutterTimeline *later_timeline;
 
689
static guint later_repaint_func = 0;
 
690
 
 
691
static void ensure_later_repaint_func (void);
 
692
 
 
693
static void
 
694
destroy_later (MetaLater *later)
 
695
{
 
696
  if (later->source)
 
697
    g_source_remove (later->source);
 
698
  if (later->notify)
 
699
    later->notify (later->data);
 
700
  g_slice_free (MetaLater, later);
 
701
}
 
702
 
 
703
/* Used to sort the list of laters with the highest priority
 
704
 * functions first.
 
705
 */
 
706
static int
 
707
compare_laters (gconstpointer a,
 
708
                gconstpointer b)
 
709
{
 
710
  return ((const MetaLater *)a)->when - ((const MetaLater *)b)->when;
 
711
}
 
712
 
 
713
static gboolean
 
714
run_repaint_laters (gpointer data)
 
715
{
 
716
  GSList *old_laters = laters;
 
717
  GSList *l;
 
718
  gboolean keep_timeline_running = FALSE;
 
719
  laters = NULL;
 
720
 
 
721
  for (l = old_laters; l; l = l->next)
 
722
    {
 
723
      MetaLater *later = l->data;
 
724
      if (later->source == 0 ||
 
725
          (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
 
726
        {
 
727
          if (later->func (later->data))
 
728
            {
 
729
              if (later->source == 0)
 
730
                keep_timeline_running = TRUE;
 
731
              laters = g_slist_insert_sorted (laters, later, compare_laters);
 
732
            }
 
733
          else
 
734
            destroy_later (later);
 
735
        }
 
736
      else
 
737
        laters = g_slist_insert_sorted (laters, later, compare_laters);
 
738
    }
 
739
 
 
740
  if (!keep_timeline_running)
 
741
    clutter_timeline_stop (later_timeline);
 
742
 
 
743
  g_slist_free (old_laters);
 
744
 
 
745
  /* Just keep the repaint func around - it's cheap if the list is empty */
 
746
  return TRUE;
 
747
}
 
748
 
 
749
static void
 
750
ensure_later_repaint_func (void)
 
751
{
 
752
  if (!later_timeline)
 
753
    later_timeline = clutter_timeline_new (G_MAXUINT);
 
754
 
 
755
  if (later_repaint_func == 0)
 
756
    later_repaint_func = clutter_threads_add_repaint_func (run_repaint_laters,
 
757
                                                           NULL, NULL);
 
758
 
 
759
  /* Make sure the repaint function gets run */
 
760
  clutter_timeline_start (later_timeline);
 
761
}
 
762
 
 
763
static gboolean
 
764
call_idle_later (gpointer data)
 
765
{
 
766
  MetaLater *later = data;
 
767
 
 
768
  if (!later->func (later->data))
 
769
    {
 
770
      laters = g_slist_remove (laters, later);
 
771
      later->source = 0;
 
772
      destroy_later (later);
 
773
      return FALSE;
 
774
    }
 
775
  else
 
776
    {
 
777
      later->run_once = TRUE;
 
778
      return TRUE;
 
779
    }
 
780
}
 
781
 
 
782
/**
 
783
 * meta_later_add:
 
784
 * @when:     enumeration value determining the phase at which to run the callback
 
785
 * @func:     callback to run later
 
786
 * @data:     data to pass to the callback
 
787
 * @notify:   function to call to destroy @data when it is no longer in use, or %NULL
 
788
 *
 
789
 * Sets up a callback  to be called at some later time. @when determines the
 
790
 * particular later occasion at which it is called. This is much like g_idle_add(),
 
791
 * except that the functions interact properly with clutter event handling.
 
792
 * If a "later" function is added from a clutter event handler, and is supposed
 
793
 * to be run before the stage is redrawn, it will be run before that redraw
 
794
 * of the stage, not the next one.
 
795
 *
 
796
 * Return value: an integer ID (guaranteed to be non-zero) that can be used
 
797
 *  to cancel the callback and prevent it from being run.
 
798
 */
 
799
guint
 
800
meta_later_add (MetaLaterType  when,
 
801
                GSourceFunc    func,
 
802
                gpointer       data,
 
803
                GDestroyNotify notify)
 
804
{
 
805
  MetaLater *later = g_slice_new0 (MetaLater);
 
806
 
 
807
  later->id = ++last_later_id;
 
808
  later->when = when;
 
809
  later->func = func;
 
810
  later->data = data;
 
811
  later->notify = notify;
 
812
 
 
813
  laters = g_slist_insert_sorted (laters, later, compare_laters);
 
814
 
 
815
  switch (when)
 
816
    {
 
817
    case META_LATER_RESIZE:
 
818
      /* We add this one two ways - as a high-priority idle and as a
 
819
       * repaint func. If we are in a clutter event callback, the repaint
 
820
       * handler will get hit first, and we'll take care of this function
 
821
       * there so it gets called before the stage is redrawn, even if
 
822
       * we haven't gotten back to the main loop. Otherwise, the idle
 
823
       * handler will get hit first and we want to call this function
 
824
       * there so it will happen before GTK+ repaints.
 
825
       */
 
826
      later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL);
 
827
      ensure_later_repaint_func ();
 
828
      break;
 
829
    case META_LATER_BEFORE_REDRAW:
 
830
      ensure_later_repaint_func ();
 
831
      break;
 
832
    case META_LATER_IDLE:
 
833
      later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL);
 
834
      break;
 
835
    }
 
836
 
 
837
  return later->id;
 
838
}
 
839
 
 
840
/**
 
841
 * meta_later_remove:
 
842
 * @later_id: the integer ID returned from meta_later_add()
 
843
 *
 
844
 * Removes a callback added with meta_later_add()
 
845
 */
 
846
void
 
847
meta_later_remove (guint later_id)
 
848
{
 
849
  GSList *l;
 
850
 
 
851
  for (l = laters; l; l = l->next)
 
852
    {
 
853
      MetaLater *later = l->data;
 
854
      if (later->id == later_id)
 
855
        {
 
856
          laters = g_slist_remove_link (laters, l);
 
857
          /* If this was a "repaint func" later, we just let the
 
858
           * repaint func run and get removed
 
859
           */
 
860
          destroy_later (later);
 
861
        }
 
862
    }
 
863
}
 
864
 
666
865
/* eof util.c */
667
866