root/ui/gfx/gtk_util.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetCursorImpl
  2. CommonInitFromCommandLine
  3. GtkInitFromCommandLine
  4. GdkInitFromCommandLine
  5. GdkPixbufFromSkBitmap
  6. SubtractRectanglesFromRegion
  7. GetCursor
  8. InitRCStyles
  9. GetCursorBlinkCycle

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/gtk_util.h"

#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <stdlib.h>

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "ui/gfx/rect.h"

namespace {

// A process wide singleton that manages our usage of gdk cursors.
// gdk_cursor_new() hits the disk in several places and GdkCursor instances can
// be reused throughout the process.
class GdkCursorCache {
 public:
  GdkCursorCache() {}
  ~GdkCursorCache() {
    for (GdkCursorMap::iterator i(cursors_.begin()); i != cursors_.end(); ++i) {
      gdk_cursor_unref(i->second);
    }
    cursors_.clear();
  }

  GdkCursor* GetCursorImpl(GdkCursorType type) {
    GdkCursorMap::iterator it = cursors_.find(type);
    GdkCursor* cursor = NULL;
    if (it == cursors_.end()) {
      cursor = gdk_cursor_new(type);
      cursors_.insert(std::make_pair(type, cursor));
    } else {
      cursor = it->second;
    }

    // It is not necessary to add a reference here. The callers can ref the
    // cursor if they need it for something.
    return cursor;
  }

 private:
  typedef std::map<GdkCursorType, GdkCursor*> GdkCursorMap;
  GdkCursorMap cursors_;

  DISALLOW_COPY_AND_ASSIGN(GdkCursorCache);
};

}  // namespace

namespace gfx {

static void CommonInitFromCommandLine(const CommandLine& command_line,
                                      void (*init_func)(gint*, gchar***)) {
  const std::vector<std::string>& args = command_line.argv();
  int argc = args.size();
  scoped_ptr<char *[]> argv(new char *[argc + 1]);
  for (size_t i = 0; i < args.size(); ++i) {
    // TODO(piman@google.com): can gtk_init modify argv? Just being safe
    // here.
    argv[i] = strdup(args[i].c_str());
  }
  argv[argc] = NULL;
  char **argv_pointer = argv.get();

  init_func(&argc, &argv_pointer);
  for (size_t i = 0; i < args.size(); ++i) {
    free(argv[i]);
  }
}

void GtkInitFromCommandLine(const CommandLine& command_line) {
  CommonInitFromCommandLine(command_line, gtk_init);
}

void GdkInitFromCommandLine(const CommandLine& command_line) {
  CommonInitFromCommandLine(command_line, gdk_init);
}

GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
  if (bitmap.isNull())
    return NULL;

  SkAutoLockPixels lock_pixels(bitmap);

  int width = bitmap.width();
  int height = bitmap.height();

  GdkPixbuf* pixbuf = gdk_pixbuf_new(
      GDK_COLORSPACE_RGB,  // The only colorspace gtk supports.
      TRUE,  // There is an alpha channel.
      8,
      width, height);

  // SkBitmaps are premultiplied, we need to unpremultiply them.
  const int kBytesPerPixel = 4;
  uint8* divided = gdk_pixbuf_get_pixels(pixbuf);

  for (int y = 0, i = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      uint32 pixel = bitmap.getAddr32(0, y)[x];

      int alpha = SkColorGetA(pixel);
      if (alpha != 0 && alpha != 255) {
        SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
        divided[i + 0] = SkColorGetR(unmultiplied);
        divided[i + 1] = SkColorGetG(unmultiplied);
        divided[i + 2] = SkColorGetB(unmultiplied);
        divided[i + 3] = alpha;
      } else {
        divided[i + 0] = SkColorGetR(pixel);
        divided[i + 1] = SkColorGetG(pixel);
        divided[i + 2] = SkColorGetB(pixel);
        divided[i + 3] = alpha;
      }
      i += kBytesPerPixel;
    }
  }

  return pixbuf;
}

void SubtractRectanglesFromRegion(GdkRegion* region,
                                  const std::vector<Rect>& cutouts) {
  for (size_t i = 0; i < cutouts.size(); ++i) {
    GdkRectangle rect = cutouts[i].ToGdkRectangle();
    GdkRegion* rect_region = gdk_region_rectangle(&rect);
    gdk_region_subtract(region, rect_region);
    // TODO(deanm): It would be nice to be able to reuse the GdkRegion here.
    gdk_region_destroy(rect_region);
  }
}

GdkCursor* GetCursor(int type) {
  CR_DEFINE_STATIC_LOCAL(GdkCursorCache, impl, ());
  return impl.GetCursorImpl(static_cast<GdkCursorType>(type));
}

void InitRCStyles() {
  static const char kRCText[] =
      // Make our dialogs styled like the GNOME HIG.
      //
      // TODO(evanm): content-area-spacing was introduced in a later
      // version of GTK, so we need to set that manually on all dialogs.
      // Perhaps it would make sense to have a shared FixupDialog() function.
      "style \"gnome-dialog\" {\n"
      "  xthickness = 12\n"
      "  GtkDialog::action-area-border = 0\n"
      "  GtkDialog::button-spacing = 6\n"
      "  GtkDialog::content-area-spacing = 18\n"
      "  GtkDialog::content-area-border = 12\n"
      "}\n"
      // Note we set it at the "application" priority, so users can override.
      "widget \"GtkDialog\" style : application \"gnome-dialog\"\n"

      // Make our about dialog special, so the image is flush with the edge.
      "style \"about-dialog\" {\n"
      "  GtkDialog::action-area-border = 12\n"
      "  GtkDialog::button-spacing = 6\n"
      "  GtkDialog::content-area-spacing = 18\n"
      "  GtkDialog::content-area-border = 0\n"
      "}\n"
      "widget \"about-dialog\" style : application \"about-dialog\"\n";

  gtk_rc_parse_string(kRCText);
}

base::TimeDelta GetCursorBlinkCycle() {
  // From http://library.gnome.org/devel/gtk/unstable/GtkSettings.html, this is
  // the default value for gtk-cursor-blink-time.
  static const gint kGtkDefaultCursorBlinkTime = 1200;

  gint cursor_blink_time = kGtkDefaultCursorBlinkTime;
  gboolean cursor_blink = TRUE;
  g_object_get(gtk_settings_get_default(),
               "gtk-cursor-blink-time", &cursor_blink_time,
               "gtk-cursor-blink", &cursor_blink,
               NULL);
  return cursor_blink ?
         base::TimeDelta::FromMilliseconds(cursor_blink_time) :
         base::TimeDelta();
}

}  // namespace gfx

/* [<][>][^][v][top][bottom][index][help] */