bubble_window.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/frame/bubble_window.h"
6
7#include <gtk/gtk.h>
8
9#include "chrome/browser/chromeos/frame/bubble_frame_view.h"
10#include "chrome/browser/chromeos/wm_ipc.h"
11#include "third_party/cros/chromeos_wm_ipc_enums.h"
12#include "ui/gfx/skia_utils_gtk.h"
13#include "views/window/non_client_view.h"
14
15namespace chromeos {
16
17bool IsInsideCircle(int x0, int y0, int x1, int y1, int r) {
18  return (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) <= r * r;
19}
20
21void SetRegionUnionWithPoint(int i, int j, GdkRegion* region) {
22  GdkRectangle rect = {i, j, 1, 1};
23  gdk_region_union_with_rect(region, &rect);
24}
25
26// static
27const SkColor BubbleWindow::kBackgroundColor = SK_ColorWHITE;
28
29BubbleWindow::BubbleWindow(views::WindowDelegate* window_delegate)
30    : views::WindowGtk(window_delegate) {
31  MakeTransparent();
32}
33
34void BubbleWindow::Init(GtkWindow* parent, const gfx::Rect& bounds) {
35  views::WindowGtk::Init(parent, bounds);
36
37  // Turn on double buffering so that the hosted GtkWidgets does not
38  // flash as in http://crosbug.com/9065.
39  EnableDoubleBuffer(true);
40
41  GdkColor background_color = gfx::SkColorToGdkColor(kBackgroundColor);
42  gtk_widget_modify_bg(GetNativeView(), GTK_STATE_NORMAL, &background_color);
43
44  // A work-around for http://crosbug.com/8538. All GdkWidnow of top-level
45  // GtkWindow should participate _NET_WM_SYNC_REQUEST protocol and window
46  // manager should only show the window after getting notified. And we
47  // should only notify window manager after at least one paint is done.
48  // TODO(xiyuan): Figure out the right fix.
49  gtk_widget_realize(GetNativeView());
50  gdk_window_set_back_pixmap(GetNativeView()->window, NULL, FALSE);
51  gtk_widget_realize(window_contents());
52  gdk_window_set_back_pixmap(window_contents()->window, NULL, FALSE);
53}
54
55void BubbleWindow::TrimMargins(int margin_left, int margin_right,
56                               int margin_top, int margin_bottom,
57                               int border_radius) {
58  gfx::Size size = GetNonClientView()->GetPreferredSize();
59  const int w = size.width() - margin_left - margin_right;
60  const int h = size.height() - margin_top - margin_bottom;
61  GdkRectangle rect0 = {0, border_radius, w, h - 2 * border_radius};
62  GdkRectangle rect1 = {border_radius, 0, w - 2 * border_radius, h};
63  GdkRegion* region = gdk_region_rectangle(&rect0);
64  gdk_region_union_with_rect(region, &rect1);
65
66  // Top Left
67  for (int i = 0; i < border_radius; ++i) {
68    for (int j = 0; j < border_radius; ++j) {
69      if (IsInsideCircle(i + 0.5, j + 0.5, border_radius, border_radius,
70                         border_radius)) {
71        SetRegionUnionWithPoint(i, j, region);
72      }
73    }
74  }
75  // Top Right
76  for (int i = w - border_radius - 1; i < w; ++i) {
77    for (int j = 0; j < border_radius; ++j) {
78      if (IsInsideCircle(i + 0.5, j + 0.5, w - border_radius - 1,
79                         border_radius, border_radius)) {
80        SetRegionUnionWithPoint(i, j, region);
81      }
82    }
83  }
84  // Bottom Left
85  for (int i = 0; i < border_radius; ++i) {
86    for (int j = h - border_radius - 1; j < h; ++j) {
87      if (IsInsideCircle(i + 0.5, j + 0.5, border_radius, h - border_radius - 1,
88                         border_radius)) {
89        SetRegionUnionWithPoint(i, j, region);
90      }
91    }
92  }
93  // Bottom Right
94  for (int i = w - border_radius - 1; i < w; ++i) {
95    for (int j = h - border_radius - 1; j < h; ++j) {
96      if (IsInsideCircle(i + 0.5, j + 0.5, w - border_radius - 1,
97                         h - border_radius - 1, border_radius)) {
98        SetRegionUnionWithPoint(i, j, region);
99      }
100    }
101  }
102
103  gdk_window_shape_combine_region(window_contents()->window, region,
104                                  margin_left, margin_top);
105  gdk_region_destroy(region);
106}
107
108views::Window* BubbleWindow::Create(
109    gfx::NativeWindow parent,
110    const gfx::Rect& bounds,
111    Style style,
112    views::WindowDelegate* window_delegate) {
113  BubbleWindow* window = new BubbleWindow(window_delegate);
114  window->GetNonClientView()->SetFrameView(new BubbleFrameView(window, style));
115  window->Init(parent, bounds);
116
117  if (style == STYLE_XSHAPE) {
118    const int kMarginLeft = 14;
119    const int kMarginRight = 14;
120    const int kMarginTop = 12;
121    const int kMarginBottom = 16;
122    const int kBorderRadius = 8;
123    window->TrimMargins(kMarginLeft, kMarginRight, kMarginTop, kMarginBottom,
124                        kBorderRadius);
125  }
126
127  return window;
128}
129
130}  // namespace chromeos
131