Home | History | Annotate | Download | only in frame
      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