static void
awn_tooltip_set_mask (AwnTooltip *tooltip, gint width, gint height)
{
  GtkWidget *widget = GTK_WIDGET (tooltip);

  if (gtk_widget_is_composited (widget) == FALSE)
  {
    GdkBitmap *shaped_bitmap;
    shaped_bitmap = (GdkBitmap*) gdk_pixmap_new (NULL, width, height, 1);

    if (shaped_bitmap)
    {
      cairo_t *cr = gdk_cairo_create (shaped_bitmap);

      cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
      cairo_paint (cr);

      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
      cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
      cairo_translate (cr, 0.5, 0.5);

      
      awn_cairo_rounded_rect (cr, 0, 0, width, height,
                              TOOLTIP_ROUND_RADIUS, ROUND_ALL);
      cairo_fill (cr);

      cairo_destroy (cr);

      gtk_widget_shape_combine_mask (widget, NULL, 0, 0);
      gtk_widget_shape_combine_mask (widget, shaped_bitmap, 0, 0);

      g_object_unref (shaped_bitmap);
    }
  }
}
/* GObject Stuff */
static gboolean
awn_tooltip_expose_event (GtkWidget *widget, GdkEventExpose *expose)
{
  AwnTooltipPrivate *priv;
  cairo_t           *cr;
  GtkAllocation      alloc;
  gint               width, height;

  priv = AWN_TOOLTIP (widget)->priv;

  gtk_widget_get_allocation (widget, &alloc);

  width = alloc.width;
  height = alloc.height;

  cr = gdk_cairo_create (gtk_widget_get_window (widget));

  if (!cr)
  {
    return FALSE;
  }

  /* Clear the background to transparent */
  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  cairo_paint (cr);
  
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  cairo_set_line_width (cr, 1.0);
  
  /* Draw */
  awn_cairo_set_source_color (cr, priv->bg);

  awn_cairo_rounded_rect (cr, 0, 0, width, height,
                          TOOLTIP_ROUND_RADIUS, ROUND_ALL);

  if (priv->outline_color)
  {
    cairo_fill_preserve (cr);
    awn_cairo_set_source_color (cr, priv->outline_color);
    cairo_stroke (cr);
  }
  else
  {
    cairo_fill (cr);
  }

  /* Clean up */
  cairo_destroy (cr);

  gtk_container_propagate_expose (GTK_CONTAINER (widget), 
                                  gtk_bin_get_child (GTK_BIN (widget)),
                                  expose);

  return TRUE;
}
static void
paint_sad_face (cairo_t *cr)
{
    /* sad face */
    const gfloat EYE_SIZE = 0.04;
    gfloat EYE_POS_X, EYE_POS_Y;

    awn_cairo_rounded_rect(cr, 0.05, 0.05, 0.9, 0.9, 0.05, ROUND_ALL);
    cairo_stroke(cr);

#define MINI_RECT(cr, x, y) \
    cairo_rectangle (cr, x, y, EYE_SIZE, EYE_SIZE); \
    cairo_fill (cr);

    EYE_POS_X = 0.25;
    EYE_POS_Y = 0.30;

    /* left eye */
    MINI_RECT(cr, EYE_POS_X, EYE_POS_Y);
    MINI_RECT(cr, EYE_POS_X, EYE_POS_Y + 2*EYE_SIZE);
    MINI_RECT(cr, EYE_POS_X + EYE_SIZE, EYE_POS_Y + EYE_SIZE);
    MINI_RECT(cr, EYE_POS_X + 2*EYE_SIZE, EYE_POS_Y);
    MINI_RECT(cr, EYE_POS_X + 2*EYE_SIZE, EYE_POS_Y + 2*EYE_SIZE);

    /* right eye */
    EYE_POS_X = 0.65;

    MINI_RECT(cr, EYE_POS_X, EYE_POS_Y);
    MINI_RECT(cr, EYE_POS_X, EYE_POS_Y + 2*EYE_SIZE);
    MINI_RECT(cr, EYE_POS_X + EYE_SIZE, EYE_POS_Y + EYE_SIZE);
    MINI_RECT(cr, EYE_POS_X + 2*EYE_SIZE, EYE_POS_Y);
    MINI_RECT(cr, EYE_POS_X + 2*EYE_SIZE, EYE_POS_Y + 2*EYE_SIZE);

#undef MINI_RECT

    /* nose */
    cairo_curve_to(cr, 0.45, 0.48,
                   0.5, 0.53,
                   0.55, 0.48);
    cairo_stroke(cr);

    /* mouth */
    cairo_curve_to(cr, 0.25, 0.73,
                   0.5, 0.62,
                   0.77, 0.77);
    cairo_stroke(cr);

}
/**
 * awn_cairo_rounded_rect_shadow:
 *
 * Draws a shadow for rounded rectangle via cairo.
 */
void
awn_cairo_rounded_rect_shadow(cairo_t *cr, double rx0, double ry0,
                              double width, double height,
                              double radius, AwnCairoRoundCorners state,
                              double shadow_radius, double shadow_alpha)
{
  cairo_pattern_t *pat;

  const double rx1 = rx0 + width;
  const double ry1 = ry0 + height;

  const double xr = rx0 + radius;
  const double yr = ry0 + radius;

  cairo_save (cr);

  cairo_rectangle (cr, rx0 - shadow_radius, ry0 - shadow_radius,
                   width + shadow_radius * 2, height + shadow_radius * 2);

  awn_cairo_rounded_rect (cr, rx0, ry0, width, height, radius, state);
  cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);

  cairo_clip (cr);

  /* top left */
  pat = cairo_pattern_create_radial (xr, yr, radius,
                                     xr, yr, radius + shadow_radius);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, shadow_alpha);
  cairo_pattern_add_color_stop_rgba (pat, 1./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.0);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, rx0 - shadow_radius, ry0 - shadow_radius,
                   radius + shadow_radius, radius + shadow_radius);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* top */
  pat = cairo_pattern_create_linear (0.0, ry0 - shadow_radius, 0.0, ry0);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, 0.0);
  cairo_pattern_add_color_stop_rgba (pat, 2./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, shadow_alpha);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, xr, ry0 - shadow_radius,
                   width - radius * 2, shadow_radius);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* top right */
  pat = cairo_pattern_create_radial (rx1 - radius, yr, radius,
                                     rx1 - radius, yr, radius + shadow_radius);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, shadow_alpha);
  cairo_pattern_add_color_stop_rgba (pat, 1./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.0);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, rx1 - radius, ry0 - shadow_radius,
                   radius + shadow_radius, radius + shadow_radius);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* right */
  pat = cairo_pattern_create_linear (rx1, 0.0, rx1 + shadow_radius, 0.0);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, shadow_alpha);
  cairo_pattern_add_color_stop_rgba (pat, 1./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.0);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, rx1, ry0 + radius,
                   shadow_radius, height - radius * 2);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* bottom right */
  pat = cairo_pattern_create_radial (rx1 - radius, ry1 - radius, radius,
                                     rx1 - radius, ry1 - radius,
                                     radius + shadow_radius);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, shadow_alpha);
  cairo_pattern_add_color_stop_rgba (pat, 1./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.0);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, rx1 - radius, ry1 - radius,
                   radius + shadow_radius, radius + shadow_radius);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* bottom */
  pat = cairo_pattern_create_linear (0.0, ry1, 0.0, ry1 + shadow_radius);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, shadow_alpha);
  cairo_pattern_add_color_stop_rgba (pat, 1./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.0);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, xr, ry1,
                   width - radius * 2, shadow_radius);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* bottom left */
  pat = cairo_pattern_create_radial (xr, ry1 - radius, radius,
                                     xr, ry1 - radius, radius + shadow_radius);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, shadow_alpha);
  cairo_pattern_add_color_stop_rgba (pat, 1./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, 0.0);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, rx0 - shadow_radius, ry1 - radius,
                   radius + shadow_radius, radius + shadow_radius);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  /* left */
  pat = cairo_pattern_create_linear (rx0 - shadow_radius, 0.0, rx0, 0.0);
  cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.0, 0.0, 0.0, 0.0);
  cairo_pattern_add_color_stop_rgba (pat, 2./3, 0.0, 0.0, 0.0, shadow_alpha/2);
  cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.0, 0.0, 0.0, shadow_alpha);

  cairo_set_source (cr, pat);
  cairo_rectangle (cr, rx0 - shadow_radius, yr,
                   shadow_radius, height - radius * 2);
  cairo_fill (cr);

  cairo_pattern_destroy (pat);

  cairo_restore (cr);
}
static gboolean
awn_throbber_expose_event (GtkWidget *widget, GdkEventExpose *event)
{
    AwnThrobberPrivate *priv = AWN_THROBBER (widget)->priv;
    cairo_t *cr;
    gint w, h;
    GtkPositionType pos_type;

    /* clip the drawing region, nvidia likes it */
    AwnEffects *fx = awn_overlayable_get_effects (AWN_OVERLAYABLE (widget));
    cr = awn_effects_cairo_create_clipped (fx, event);

    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);

    // we'll paint to [0,0] - [1,1], so scale's needed
    g_object_get (G_OBJECT (widget), "icon-width", &w, "icon-height", &h, NULL);
    cairo_scale (cr, w, h);

    switch (priv->type)
    {
    case AWN_THROBBER_TYPE_NORMAL:
    {
        const gdouble RADIUS = 0.0625;
        const gdouble DIST = 0.3;
        const gdouble OTHER = DIST * 0.707106781; /* sqrt(2)/2 */
        const gint COUNT = 8;
        const gint counter = priv->counter;

        cairo_set_line_width (cr, 1. / priv->size);
        cairo_translate (cr, 0.5, 0.5);
        cairo_scale (cr, 1, -1);

#define PAINT_CIRCLE(cr, x, y, cnt) \
    awn_cairo_set_source_color_with_alpha_multiplier (cr, \
        priv->fill_color, ((counter+cnt) % COUNT) / (float)COUNT); \
    cairo_arc (cr, x, y, RADIUS, 0, 2*M_PI); \
    cairo_fill_preserve (cr); \
    awn_cairo_set_source_color_with_alpha_multiplier (cr, \
        priv->outline_color, ((counter+cnt) % COUNT) / (float)COUNT); \
    cairo_stroke (cr);

        PAINT_CIRCLE (cr, 0, DIST, 0);
        PAINT_CIRCLE (cr, OTHER, OTHER, 1);
        PAINT_CIRCLE (cr, DIST, 0, 2);
        PAINT_CIRCLE (cr, OTHER, -OTHER, 3);
        PAINT_CIRCLE (cr, 0, -DIST, 4);
        PAINT_CIRCLE (cr, -OTHER, -OTHER, 5);
        PAINT_CIRCLE (cr, -DIST, 0, 6);
        PAINT_CIRCLE (cr, -OTHER, OTHER, 7);

#undef PAINT_CIRCLE

        break;
    }
    case AWN_THROBBER_TYPE_SAD_FACE:
    {
        cairo_set_line_width (cr, 0.03);

        if (priv->fill_color == NULL)
        {
            GdkColor c;
            double r, g, b;

            c = gtk_widget_get_style (widget)->fg[GTK_STATE_NORMAL];
            r = c.red / 65535.0;
            g = c.green / 65535.0;
            b = c.blue / 65535.0;

            cairo_set_source_rgb (cr, r, g, b);
        }
        else
        {
            awn_cairo_set_source_color_with_alpha_multiplier (cr,
                    priv->fill_color,
                    0.75);
        }

        paint_sad_face (cr);

        break;
    }
    case AWN_THROBBER_TYPE_ARROW_1:
        cairo_rotate (cr, M_PI);
        cairo_translate (cr, -1.0, -1.0);
    // no break
    case AWN_THROBBER_TYPE_ARROW_2:
    {
        pos_type = awn_icon_get_pos_type (AWN_ICON (widget));

        if (pos_type == GTK_POS_LEFT || pos_type == GTK_POS_RIGHT)
        {
            cairo_rotate (cr, 0.5 * M_PI);
            cairo_translate (cr, 0.0, -1.0);
        }

        if (priv->outline_color)
        {
            cairo_set_line_width (cr, 3.5 / priv->size);
            awn_cairo_set_source_color (cr, priv->outline_color);

            cairo_move_to (cr, 0.125, 0.375);
            cairo_line_to (cr, 0.875, 0.5);
            cairo_line_to (cr, 0.125, 0.625);
            cairo_stroke (cr);
        }

        cairo_set_line_width (cr, 1.75 / priv->size);

        if (priv->fill_color == NULL)
        {
            GdkColor c = gtk_widget_get_style (widget)->fg[GTK_STATE_NORMAL];
            double r = c.red / 65535.0;
            double g = c.green / 65535.0;
            double b = c.blue / 65535.0;

            cairo_set_source_rgb (cr, r, g, b);
        }
        else
        {
            awn_cairo_set_source_color (cr, priv->fill_color);
        }

        cairo_move_to (cr, 0.125, 0.375);
        cairo_line_to (cr, 0.875, 0.5);
        cairo_line_to (cr, 0.125, 0.625);
        cairo_stroke (cr);

        break;
    }
    case AWN_THROBBER_TYPE_CLOSE_BUTTON:
    {
        cairo_set_line_width (cr, 1. / priv->size);

        cairo_pattern_t *pat = cairo_pattern_create_linear (0.0, 0.0, 0.5, 1.0);
        cairo_pattern_add_color_stop_rgb (pat, 0.0, 0.97254, 0.643137, 0.403921);
        //cairo_pattern_add_color_stop_rgb (pat, 0.0, 0.0, 0.0, 0.0); // test
        cairo_pattern_add_color_stop_rgb (pat, 0.7, 0.98823, 0.4, 0.0);
        cairo_pattern_add_color_stop_rgb (pat, 1.0, 0.98823, 0.4, 0.0);

        cairo_set_source (cr, pat);
        //cairo_arc (cr, 0.5, 0.5, 0.4, 0.0, 2 * M_PI);
        awn_cairo_rounded_rect (cr, 0.1, 0.1, 0.8, 0.8, 0.15, ROUND_ALL);
        cairo_fill_preserve (cr);

        cairo_pattern_destroy (pat);

        cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
        cairo_stroke (cr);

        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
        cairo_set_line_width (cr, 2./priv->size);

        /*  \  starting with the upper point  */
        cairo_move_to (cr, 0.3, 0.25);
        cairo_line_to (cr, 0.7, 0.75);
        cairo_stroke (cr);
        /*  /  starting with the upper point  */
        cairo_move_to (cr, 0.7, 0.25);
        cairo_line_to (cr, 0.3, 0.75);
        cairo_stroke (cr);
        break;
    }
    default:
        break;
    }

    /* let effects know we're finished */
    awn_effects_cairo_destroy (fx);

    return TRUE;
}
static gboolean render(GtkWidget ** pwidget, gint interval, Uptime_plug_data **p)
{
  char buf[256];
  glibtop_uptime uptime;
  long tmp;
  Uptime_plug_data * data = *p;
  static int width = -1;
  static int height = -1;
  cairo_text_extents_t    extents;
  dashboard_cairo_widget c_widge;
  float mult;

  data->timer = data->timer - interval;

  if ((data->timer <= 0) || (data->forceupdate))
  {
    data->forceupdate = FALSE;
    glibtop_get_uptime(&uptime);
    tmp = uptime.uptime;
    data->seconds = tmp % 60;
    tmp = tmp / 60; //tmp is now minutes
    data->minutes = tmp % 60;
    tmp = tmp / 60; //tmp now hours
    data->hours = tmp % 24;
    tmp = tmp / 24;
    data->days = tmp;

    if (data->show_seconds)
    {
      snprintf(buf, sizeof(buf), "Up Time:%d:%02d:%02d:%02d", data->days,
               data->hours, data->minutes,
               data->seconds);
    }
    else
    {
      snprintf(buf, sizeof(buf), "Up Time:%d:%02d:%02d", data->days,
               data->hours, data->minutes);
    }

    if (data->show_seconds)
    {
      data->timer = 900;
    }
    else
    {
      data->timer = 1000 * 55;
    }

    /*there is an issue if this widget starts out overly large... the maintable sizes itself too
    and doesn't properly resize itself downwards...  So we start small for the first second
    and that way give it time to shrink before adjusting to a large scale */
    if (width < 0)
    {
      snprintf(buf, sizeof(buf), "Up Time:%d:%02d:%02d:%02d", data->days,
               data->hours, data->minutes,
               data->seconds);
      *pwidget = get_cairo_widget(&c_widge, 200, 30);
      mult = 1;
      use_bg_rgba_colour(c_widge.cr);
      cairo_set_operator(c_widge.cr, CAIRO_OPERATOR_SOURCE);
      cairo_paint(c_widge.cr);
      data->timer = interval;
    }
    else
    {
      mult = data->size_mult;
      *pwidget = get_cairo_widget(&c_widge, width * mult, height * mult);
      awn_cairo_rounded_rect(c_widge.cr, 0, 0, width*mult, height*mult, height*mult*0.1, ROUND_ALL);

      cairo_set_source_rgba(c_widge.cr, data->bg.red, data->bg.green, data->bg.blue, data->bg.alpha);
      cairo_fill(c_widge.cr);
    }

    cairo_select_font_face(c_widge.cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);

    cairo_set_font_size(c_widge.cr, dashboard_get_font_size(DASHBOARD_FONT_SMALL)*mult);

    cairo_set_source_rgba(c_widge.cr, data->fg.red, data->fg.green, data->fg.blue, data->fg.alpha);

    cairo_move_to(c_widge.cr, 5.0*mult, height*mult*0.7);

    if (width < 0)
    {
      cairo_text_extents(c_widge.cr, buf, &extents);
      height = extents.height + 2;
      width = extents.width + 10;
      return TRUE;
    }

    cairo_show_text(c_widge.cr, buf);

    del_cairo_widget(&c_widge);

    return TRUE;
  }
  else
  {
    return FALSE;
  }
}