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