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 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 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 33 BubbleWindow::BubbleWindow(views::WindowDelegate* window_delegate) 34 : views::WindowGtk(window_delegate) { 35 MakeTransparent(); 36 } 37 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 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 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