• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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