1 // Copyright (c) 2009 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/ui/window_sizer.h" 6 7 #include <gtk/gtk.h> 8 9 #include "base/logging.h" 10 #include "chrome/browser/ui/browser.h" 11 #include "chrome/browser/ui/browser_list.h" 12 #include "chrome/browser/ui/browser_window.h" 13 14 // Used to pad the default new window size. On Windows, this is also used for 15 // positioning new windows (each window is offset from the previous one). 16 // Since we don't position windows, it's only used for the default new window 17 // size. 18 const int WindowSizer::kWindowTilePixels = 10; 19 20 // An implementation of WindowSizer::MonitorInfoProvider that gets the actual 21 // monitor information from X via GDK. 22 class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider { 23 public: 24 DefaultMonitorInfoProvider() { } 25 26 virtual gfx::Rect GetPrimaryMonitorWorkArea() const { 27 gfx::Rect rect; 28 if (GetScreenWorkArea(&rect)) 29 return rect.Intersect(GetPrimaryMonitorBounds()); 30 31 // Return the best we've got. 32 return GetPrimaryMonitorBounds(); 33 } 34 35 virtual gfx::Rect GetPrimaryMonitorBounds() const { 36 GdkScreen* screen = gdk_screen_get_default(); 37 GdkRectangle rect; 38 gdk_screen_get_monitor_geometry(screen, 0, &rect); 39 return gfx::Rect(rect); 40 } 41 42 virtual gfx::Rect GetMonitorWorkAreaMatching( 43 const gfx::Rect& match_rect) const { 44 // TODO(thestig) Implement multi-monitor support. 45 return GetPrimaryMonitorWorkArea(); 46 } 47 48 virtual gfx::Point GetBoundsOffsetMatching( 49 const gfx::Rect& match_rect) const { 50 // TODO(thestig) Implement multi-monitor support. 51 return GetPrimaryMonitorWorkArea().origin(); 52 } 53 54 void UpdateWorkAreas() { 55 // TODO(thestig) Implement multi-monitor support. 56 work_areas_.clear(); 57 work_areas_.push_back(GetPrimaryMonitorBounds()); 58 } 59 60 private: 61 // Get the available screen space as a gfx::Rect, or return false if 62 // if it's unavailable (i.e. the window manager doesn't support 63 // retrieving this). 64 // TODO(thestig) Use _NET_CURRENT_DESKTOP here as well? 65 bool GetScreenWorkArea(gfx::Rect* out_rect) const { 66 gboolean ok; 67 guchar* raw_data = NULL; 68 gint data_len = 0; 69 ok = gdk_property_get(gdk_get_default_root_window(), // a gdk window 70 gdk_atom_intern("_NET_WORKAREA", FALSE), // property 71 gdk_atom_intern("CARDINAL", FALSE), // property type 72 0, // byte offset into property 73 0xff, // property length to retrieve 74 false, // delete property after retrieval? 75 NULL, // returned property type 76 NULL, // returned data format 77 &data_len, // returned data len 78 &raw_data); // returned data 79 if (!ok) 80 return false; 81 82 // We expect to get four longs back: x, y, width, height. 83 if (data_len < static_cast<gint>(4 * sizeof(glong))) { 84 NOTREACHED(); 85 g_free(raw_data); 86 return false; 87 } 88 89 glong* data = reinterpret_cast<glong*>(raw_data); 90 gint x = data[0]; 91 gint y = data[1]; 92 gint width = data[2]; 93 gint height = data[3]; 94 g_free(raw_data); 95 96 out_rect->SetRect(x, y, width, height); 97 return true; 98 } 99 100 DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider); 101 }; 102 103 // static 104 WindowSizer::MonitorInfoProvider* 105 WindowSizer::CreateDefaultMonitorInfoProvider() { 106 return new DefaultMonitorInfoProvider(); 107 } 108 109 // static 110 gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) { 111 scoped_ptr<MonitorInfoProvider> provider(CreateDefaultMonitorInfoProvider()); 112 gfx::Rect monitor_bounds = provider->GetPrimaryMonitorWorkArea(); 113 gfx::Point corner(monitor_bounds.x(), monitor_bounds.y()); 114 if (Browser* browser = BrowserList::GetLastActive()) { 115 GtkWindow* window = 116 reinterpret_cast<GtkWindow*>(browser->window()->GetNativeHandle()); 117 int x = 0, y = 0; 118 gtk_window_get_position(window, &x, &y); 119 // Limit to not overflow the work area right and bottom edges. 120 gfx::Point limit( 121 std::min(x + kWindowTilePixels, monitor_bounds.right() - size.width()), 122 std::min(y + kWindowTilePixels, 123 monitor_bounds.bottom() - size.height())); 124 // Adjust corner to now overflow the work area left and top edges, so 125 // that if a popup does not fit the title-bar is remains visible. 126 corner = gfx::Point( 127 std::max(corner.x(), limit.x()), 128 std::max(corner.y(), limit.y())); 129 } 130 return corner; 131 } 132