- add sources.
[platform/framework/web/crosswalk.git] / src / ui / gfx / screen_gtk.cc
1 // Copyright (c) 2012 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 "ui/gfx/screen.h"
6
7 #include <gdk/gdkx.h>
8 #include <gtk/gtk.h>
9
10 #include "base/logging.h"
11 #include "ui/gfx/display.h"
12
13 namespace {
14
15 bool GetScreenWorkArea(gfx::Rect* out_rect) {
16   gboolean ok;
17   guchar* raw_data = NULL;
18   gint data_len = 0;
19   ok = gdk_property_get(gdk_get_default_root_window(),  // a gdk window
20                         gdk_atom_intern("_NET_WORKAREA", FALSE),  // property
21                         gdk_atom_intern("CARDINAL", FALSE),  // property type
22                         0,  // byte offset into property
23                         0xff,  // property length to retrieve
24                         false,  // delete property after retrieval?
25                         NULL,  // returned property type
26                         NULL,  // returned data format
27                         &data_len,  // returned data len
28                         &raw_data);  // returned data
29   if (!ok)
30     return false;
31
32   // We expect to get four longs back: x, y, width, height.
33   if (data_len < static_cast<gint>(4 * sizeof(glong))) {
34     NOTREACHED();
35     g_free(raw_data);
36     return false;
37   }
38
39   glong* data = reinterpret_cast<glong*>(raw_data);
40   gint x = data[0];
41   gint y = data[1];
42   gint width = data[2];
43   gint height = data[3];
44   g_free(raw_data);
45
46   out_rect->SetRect(x, y, width, height);
47   return true;
48 }
49
50 gfx::Display GetDisplayForMonitorNum(GdkScreen* screen, gint monitor_num) {
51   GdkRectangle bounds;
52   gdk_screen_get_monitor_geometry(screen, monitor_num, &bounds);
53   // Use |monitor_num| as display id.
54   gfx::Display display(monitor_num, gfx::Rect(bounds));
55   if (gdk_screen_get_primary_monitor(screen) == monitor_num) {
56     gfx::Rect rect;
57     if (GetScreenWorkArea(&rect))
58       display.set_work_area(gfx::IntersectRects(rect, display.bounds()));
59   }
60   return display;
61 }
62
63 gfx::Display GetMonitorAreaNearestWindow(gfx::NativeView view) {
64   GdkScreen* screen = gdk_screen_get_default();
65   gint monitor_num = 0;
66   if (view && GTK_IS_WINDOW(view)) {
67     GtkWidget* top_level = gtk_widget_get_toplevel(view);
68     DCHECK(GTK_IS_WINDOW(top_level));
69     GtkWindow* window = GTK_WINDOW(top_level);
70     screen = gtk_window_get_screen(window);
71     monitor_num = gdk_screen_get_monitor_at_window(
72         screen,
73         gtk_widget_get_window(top_level));
74   }
75   return GetDisplayForMonitorNum(screen, monitor_num);
76 }
77
78 class ScreenGtk : public gfx::Screen {
79  public:
80   ScreenGtk() {
81   }
82
83   virtual ~ScreenGtk() {
84   }
85
86   virtual bool IsDIPEnabled() OVERRIDE {
87     return false;
88   }
89
90   virtual gfx::Point GetCursorScreenPoint() OVERRIDE {
91     gint x, y;
92     gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
93     return gfx::Point(x, y);
94   }
95
96   // Returns the window under the cursor.
97   virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE {
98     GdkWindow* window = gdk_window_at_pointer(NULL, NULL);
99     if (!window)
100       return NULL;
101
102     gpointer data = NULL;
103     gdk_window_get_user_data(window, &data);
104     GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
105     if (!widget)
106       return NULL;
107     widget = gtk_widget_get_toplevel(widget);
108     return GTK_IS_WINDOW(widget) ? GTK_WINDOW(widget) : NULL;
109   }
110
111   virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point)
112       OVERRIDE {
113     NOTIMPLEMENTED();
114     return NULL;
115   }
116
117   // Returns the number of displays.
118   // Mirrored displays are excluded; this method is intended to return the
119   // number of distinct, usable displays.
120   virtual int GetNumDisplays() const OVERRIDE {
121     // This query is kinda bogus for Linux -- do we want number of X screens?
122     // The number of monitors Xinerama has?  We'll just use whatever GDK uses.
123     GdkScreen* screen = gdk_screen_get_default();
124     return gdk_screen_get_n_monitors(screen);
125   }
126
127   virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE {
128     GdkScreen* screen = gdk_screen_get_default();
129     gint num_of_displays = gdk_screen_get_n_monitors(screen);
130     std::vector<gfx::Display> all_displays;
131     for (gint i = 0; i < num_of_displays; ++i)
132       all_displays.push_back(GetDisplayForMonitorNum(screen, i));
133     return all_displays;
134   }
135
136   // Returns the display nearest the specified window.
137   virtual gfx::Display GetDisplayNearestWindow(
138       gfx::NativeView view) const OVERRIDE {
139     // Do not use the _NET_WORKAREA here, this is supposed to be an area on a
140     // specific monitor, and _NET_WORKAREA is a hint from the WM that
141     // generally spans across all monitors.  This would make the work area
142     // larger than the monitor.
143     // TODO(danakj) This is a work-around as there is no standard way to get
144     // this area, but it is a rect that we should be computing.  The standard
145     // means to compute this rect would be to watch all windows with
146     // _NET_WM_STRUT(_PARTIAL) hints, and subtract their space from the
147     // physical area of the display to construct a work area.
148     // TODO(oshima): Implement Observer.
149     return GetMonitorAreaNearestWindow(view);
150   }
151
152   // Returns the the display nearest the specified point.
153   virtual gfx::Display GetDisplayNearestPoint(
154       const gfx::Point& point) const OVERRIDE {
155     GdkScreen* screen = gdk_screen_get_default();
156     gint monitor = gdk_screen_get_monitor_at_point(
157         screen, point.x(), point.y());
158     // TODO(oshima): Implement Observer.
159     return GetDisplayForMonitorNum(screen, monitor);
160   }
161
162   // Returns the display that most closely intersects the provided bounds.
163   virtual gfx::Display GetDisplayMatching(
164       const gfx::Rect& match_rect) const OVERRIDE {
165     std::vector<gfx::Display> displays = GetAllDisplays();
166     gfx::Display maxIntersectDisplay;
167     gfx::Rect maxIntersection;
168     for (std::vector<gfx::Display>::iterator it = displays.begin();
169          it != displays.end(); ++it) {
170       gfx::Rect displayIntersection = it->bounds();
171       displayIntersection.Intersect(match_rect);
172       if (displayIntersection.size().GetArea() >
173           maxIntersection.size().GetArea()) {
174         maxIntersectDisplay = *it;
175         maxIntersection = displayIntersection;
176       }
177     }
178     return maxIntersectDisplay.is_valid() ?
179         maxIntersectDisplay : GetPrimaryDisplay();
180   }
181
182   // Returns the primary display.
183   virtual gfx::Display GetPrimaryDisplay() const OVERRIDE {
184     GdkScreen* screen = gdk_screen_get_default();
185     gint primary_monitor_index = gdk_screen_get_primary_monitor(screen);
186     // TODO(oshima): Implement Observer.
187     return GetDisplayForMonitorNum(screen, primary_monitor_index);
188   }
189
190   virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {
191     // TODO(oshima): crbug.com/122863.
192   }
193
194   virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {
195     // TODO(oshima): crbug.com/122863.
196   }
197
198  private:
199   DISALLOW_COPY_AND_ASSIGN(ScreenGtk);
200 };
201
202 }  // namespace
203
204 namespace gfx {
205
206 Screen* CreateNativeScreen() {
207   return new ScreenGtk;
208 }
209
210 }  // namespace gfx