summaryrefslogtreecommitdiffstats
path: root/chrome/browser/window_sizer_linux.cc
blob: 9bdcd986bfcddcb338dadf17cc9ec47c7e071670 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/window_sizer.h"

#include <gtk/gtk.h>

#include "base/logging.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"

// Used to pad the default new window size.  On Windows, this is also used for
// positioning new windows (each window is offset from the previous one).
// Since we don't position windows, it's only used for the default new window
// size.
const int WindowSizer::kWindowTilePixels = 10;

// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
// monitor information from X via GDK.
class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
 public:
  DefaultMonitorInfoProvider() { }

  virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
    gfx::Rect rect;
    if (GetScreenWorkArea(&rect))
      return rect.Intersect(GetPrimaryMonitorBounds());

    // Return the best we've got.
    return GetPrimaryMonitorBounds();
  }

  virtual gfx::Rect GetPrimaryMonitorBounds() const {
    GdkScreen* screen = gdk_screen_get_default();
    GdkRectangle rect;
    gdk_screen_get_monitor_geometry(screen, 0, &rect);
    return gfx::Rect(rect);
  }

  virtual gfx::Rect GetMonitorWorkAreaMatching(
      const gfx::Rect& match_rect) const {
    // TODO(thestig) Implement multi-monitor support.
    return GetPrimaryMonitorWorkArea();
  }

  virtual gfx::Point GetBoundsOffsetMatching(
      const gfx::Rect& match_rect) const {
    // TODO(thestig) Implement multi-monitor support.
    return GetPrimaryMonitorWorkArea().origin();
  }

  void UpdateWorkAreas() {
    // TODO(thestig) Implement multi-monitor support.
    work_areas_.clear();
    work_areas_.push_back(GetPrimaryMonitorBounds());
  }

 private:
  // Get the available screen space as a gfx::Rect, or return false if
  // if it's unavailable (i.e. the window manager doesn't support
  // retrieving this).
  // TODO(thestig) Use _NET_CURRENT_DESKTOP here as well?
  bool GetScreenWorkArea(gfx::Rect* out_rect) const {
    gboolean ok;
    guchar* raw_data = NULL;
    gint data_len = 0;
    ok = gdk_property_get(gdk_get_default_root_window(),  // a gdk window
                          gdk_atom_intern("_NET_WORKAREA", FALSE),  // property
                          gdk_atom_intern("CARDINAL", FALSE),  // property type
                          0,  // byte offset into property
                          0xff,  // property length to retrieve
                          false,  // delete property after retrieval?
                          NULL,  // returned property type
                          NULL,  // returned data format
                          &data_len,  // returned data len
                          &raw_data);  // returned data
    if (!ok)
      return false;

    // We expect to get four longs back: x, y, width, height.
    if (data_len < static_cast<gint>(4 * sizeof(glong))) {
      NOTREACHED();
      g_free(raw_data);
      return false;
    }

    glong* data = reinterpret_cast<glong*>(raw_data);
    gint x = data[0];
    gint y = data[1];
    gint width = data[2];
    gint height = data[3];
    g_free(raw_data);

    out_rect->SetRect(x, y, width, height);
    return true;
  }

  DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
};

// static
WindowSizer::MonitorInfoProvider*
WindowSizer::CreateDefaultMonitorInfoProvider() {
  return new DefaultMonitorInfoProvider();
}

// static
gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
  scoped_ptr<MonitorInfoProvider> provider(CreateDefaultMonitorInfoProvider());
  gfx::Rect monitor_bounds = provider->GetPrimaryMonitorWorkArea();
  gfx::Point corner(monitor_bounds.x(), monitor_bounds.y());
  if (Browser* browser = BrowserList::GetLastActive()) {
    GtkWindow* window =
        reinterpret_cast<GtkWindow*>(browser->window()->GetNativeHandle());
    int x = 0, y = 0;
    gtk_window_get_position(window, &x, &y);
    // Limit to not overflow the work area right and bottom edges.
    gfx::Point limit(
        std::min(x + kWindowTilePixels, monitor_bounds.right() - size.width()),
        std::min(y + kWindowTilePixels,
                 monitor_bounds.bottom() - size.height()));
    // Adjust corner to now overflow the work area left and top edges, so
    // that if a popup does not fit the title-bar is remains visible.
    corner = gfx::Point(
        std::max(corner.x(), limit.x()),
        std::max(corner.y(), limit.y()));
  }
  return corner;
}