/* Adwaita - a GTK+ engine
 *
 * Copyright (C) 2012 Red Hat, Inc.
 *
 * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Authors: Cosimo Cecchi <cosimoc@gnome.org>
 */

#include <gmodule.h>
#include <glib.h>
#include <gtk/gtk.h>

#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif

/***************************************/
/* Register & Initialize Drawing Style */
/***************************************/
#define ADWAITA_TYPE_STYLE              (adwaita_style_get_type ())
#define ADWAITA_STYLE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), ADWAITA_TYPE_STYLE, AdwaitaStyle))
#define ADWAITA_STYLE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), ADWAITA_TYPE_STYLE, AdwaitaStyleClass))
#define ADWAITA_IS_STYLE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), ADWAITA_TYPE_STYLE))
#define ADWAITA_IS_STYLE_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), ADWAITA_TYPE_STYLE))
#define ADWAITA_STYLE_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), ADWAITA_TYPE_STYLE, AdwaitaStyleClass))
 
typedef struct
{
  GtkStyle parent_instance;
} AdwaitaStyle;
 
typedef struct
{
  GtkStyleClass parent_class;
} AdwaitaStyleClass;

G_DEFINE_DYNAMIC_TYPE (AdwaitaStyle, adwaita_style, GTK_TYPE_STYLE)

static void
do_toplevel_hack (GtkWidget   *widget,
                  const gchar *widget_name)
{
  gboolean tried_hack;

  tried_hack = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "adwaita-toplevel-hack"));

  if (!tried_hack)
    {
      g_object_set_data (G_OBJECT (widget),
                         "adwaita-toplevel-hack", GINT_TO_POINTER (1));
      gtk_widget_set_name (widget, widget_name);
    }
}

static gboolean
wm_is_fallback (void)
{
#ifdef GDK_WINDOWING_X11
  const gchar *name;
  name = gdk_x11_screen_get_window_manager_name (gdk_screen_get_default ());
  return g_strcmp0 (name, "GNOME Shell") != 0;
#else
  return TRUE;
#endif
}

static cairo_t * 
drawable_to_cairo (GdkDrawable  *window,
                   GdkRectangle *area)
{
  cairo_t *cr;

  g_return_val_if_fail (window != NULL, NULL);

  cr = (cairo_t*) gdk_cairo_create (window);
  cairo_set_line_width (cr, 1.0);
  cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
  cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);

  if (area)
    {
      cairo_rectangle (cr, area->x, area->y, area->width, area->height);
      cairo_clip_preserve (cr);
      cairo_new_path (cr);
    }

  return cr;
}

static void
adwaita_draw_box (GtkStyle * style,
                  GdkWindow * window,
                  GtkStateType state_type,
                  GtkShadowType shadow_type,
                  GdkRectangle * area,
                  GtkWidget * widget,
                  const gchar * detail, 
                  gint x, 
                  gint y, 
                  gint width, 
                  gint height)
{
  if (GTK_IS_MENU (widget) &&
      g_strcmp0 (detail, "menu") == 0 &&
      wm_is_fallback ())
    {
      cairo_t *cr = drawable_to_cairo (window, area);
      cairo_pattern_t *pattern = cairo_pattern_create_linear (x, y, x, y + height);
      gdouble stop_1, stop_2, stop_3;

      stop_1 = MIN (1.0, 6.0 / (gdouble) height);
      stop_2 = MAX (stop_1, 0.33);
      stop_3 = MAX (stop_2, 0.66);

      cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.66, 0.66, 0.66, 0.0);
      cairo_pattern_add_color_stop_rgba (pattern, stop_1, 0.66, 0.66, 0.66, 0.25);
      cairo_pattern_add_color_stop_rgba (pattern, stop_2, 0.66, 0.66, 0.66, 0.80);
      cairo_pattern_add_color_stop_rgba (pattern, stop_3, 0.66, 0.66, 0.66, 1.0);
      cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.66, 0.66, 0.66, 1.0);
      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);

      cairo_set_source (cr, pattern);
      cairo_rectangle (cr, x, y, width, height);
      cairo_stroke (cr);

      cairo_destroy (cr);
      cairo_pattern_destroy (pattern);
    }
  else
    {
      GTK_STYLE_CLASS (adwaita_style_parent_class)->draw_box (style, window, state_type, shadow_type,
                                                              area, widget, detail,
                                                              x, y, width, height);
    }
}

void
adwaita_draw_flat_box (GtkStyle      *style,
                       GdkWindow     *window,
                       GtkStateType   state_type,
                       GtkShadowType  shadow_type,
                       GdkRectangle  *area,
                       GtkWidget     *widget,
                       const gchar   *detail,
                       gint           x,
                       gint	      y,
                       gint	      width,
                       gint	      height)
{
  gboolean tried_ooo_hack;
  const gchar *app_name;

  GTK_STYLE_CLASS (adwaita_style_parent_class)->draw_flat_box (style, window, state_type, shadow_type,
                                                               area, widget, detail,
                                                               x, y, width, height);

  /* HACK: this is totally awful, but I don't see a better way to "tag" the OO.o hierarchy */
  if (!GTK_IS_WINDOW (widget) ||
      (gtk_window_get_window_type (GTK_WINDOW (widget)) != GTK_WINDOW_TOPLEVEL))
    return;

  app_name = g_get_application_name ();
  if (g_str_has_prefix (app_name, "OpenOffice.org"))
    do_toplevel_hack (widget, "openoffice-toplevel");
  else if (g_str_has_prefix (app_name, "LibreOffice"))
    do_toplevel_hack (widget, "libreoffice-toplevel");
}

static void
adwaita_style_init (AdwaitaStyle *style)
{
}

static void
adwaita_style_class_init (AdwaitaStyleClass * klass)
{
  GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
 
  style_class->draw_box = adwaita_draw_box;
  style_class->draw_flat_box = adwaita_draw_flat_box;
}

static void
adwaita_style_class_finalize (AdwaitaStyleClass * klass)
{
}

/**********************************/ 
/* Register & Initialize RC Style */ 
/**********************************/ 
#define ADWAITA_TYPE_RC_STYLE              (adwaita_rc_style_get_type ())
#define ADWAITA_RC_STYLE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), ADWAITA_TYPE_RC_STYLE, AdwaitaRcStyle))
#define ADWAITA_RC_STYLE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), ADWAITA_TYPE_RC_STYLE, AdwaitaRcStyleClass))
#define ADWAITA_IS_RC_STYLE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), ADWAITA_TYPE_RC_STYLE))
#define ADWAITA_IS_RC_STYLE_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), ADWAITA_TYPE_RC_STYLE))
#define ADWAITA_RC_STYLE_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), ADWAITA_TYPE_RC_STYLE, AdwaitaRcStyleClass))
 
typedef struct
{
  GtkRcStyle parent_instance;
} AdwaitaRcStyle;
 
typedef struct
{
  GtkRcStyleClass parent_class;
} AdwaitaRcStyleClass;

G_DEFINE_DYNAMIC_TYPE (AdwaitaRcStyle, adwaita_rc_style, GTK_TYPE_RC_STYLE)

static GtkStyle *
adwaita_rc_style_create_style (GtkRcStyle *rc_style)
{
  return g_object_new (ADWAITA_TYPE_STYLE, NULL);
}

static void
adwaita_rc_style_init (AdwaitaRcStyle *rc_style)
{
}

static void
adwaita_rc_style_class_init (AdwaitaRcStyleClass * klass)
{
  GtkRcStyleClass *rc_class = GTK_RC_STYLE_CLASS (klass);

  rc_class->create_style = adwaita_rc_style_create_style;
}

static void
adwaita_rc_style_class_finalize (AdwaitaRcStyleClass * klass)
{
}

/**************** 
 * Engine Hooks * 
 ****************/
void
theme_init (GTypeModule * module)
{
  adwaita_rc_style_register_type (module);
  adwaita_style_register_type (module);
}
 
void
theme_exit (void)
{
}
 
GtkRcStyle *
theme_create_rc_style (void)
{
  return g_object_new (ADWAITA_TYPE_RC_STYLE, NULL);
}
