blob: 7a2820e735c7f138b8358fdd391d0ea74c60f435 [file] [log] [blame]
// Copyright (c) 2010 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.
#ifndef VIEWS_WIDGET_WIDGET_GTK_H_
#define VIEWS_WIDGET_WIDGET_GTK_H_
#pragma once
#include <gtk/gtk.h>
#include "app/active_window_watcher_x.h"
#include "app/gtk_signal.h"
#include "base/message_loop.h"
#include "gfx/size.h"
#include "views/focus/focus_manager.h"
#include "views/widget/widget.h"
class OSExchangeData;
class OSExchangeDataProviderGtk;
namespace gfx {
class Rect;
}
namespace views {
class DefaultThemeProvider;
class DropTargetGtk;
class FocusSearch;
class TooltipManagerGtk;
class View;
class WindowGtk;
// Widget implementation for GTK.
class WidgetGtk
: public Widget,
public FocusTraversable,
public ActiveWindowWatcherX::Observer {
public:
// Type of widget.
enum Type {
// Used for popup type windows (bubbles, menus ...).
// NOTE: on X windows of this type can NOT get focus. If you need a popup
// like widget that can be focused use TYPE_WINDOW and set the window type
// to WINDOW_TYPE_CHROME_INFO_BUBBLE.
TYPE_POPUP,
// A top level window with no title or control buttons.
TYPE_WINDOW,
// A top level, decorated window.
TYPE_DECORATED_WINDOW,
// A child widget.
TYPE_CHILD
};
explicit WidgetGtk(Type type);
virtual ~WidgetGtk();
// Marks this window as transient to its parent. A window that is transient
// to its parent results in the parent rendering active when the child is
// active.
// This must be invoked before Init. This is only used for types other than
// TYPE_CHILD. The default is false.
// See gtk_window_set_transient_for for details.
void make_transient_to_parent() {
DCHECK(!widget_);
transient_to_parent_ = true;
}
// Returns the transient parent. See make_transient_to_parent for details on
// what the transient parent is.
GtkWindow* GetTransientParent() const;
// Makes the background of the window totally transparent. This must be
// invoked before Init. This does a couple of checks and returns true if
// the window can be made transparent. The actual work of making the window
// transparent is done by ConfigureWidgetForTransparentBackground.
// This works for both child and window types.
bool MakeTransparent();
bool is_transparent() const { return transparent_; }
// Enable/Disable double buffering.This is neccessary to prevent
// flickering in ScrollView, which has both native and view
// controls.
void EnableDoubleBuffer(bool enabled);
bool is_double_buffered() const { return is_double_buffered_; }
// Makes the window pass all events through to any windows behind it.
// This must be invoked before Init. This does a couple of checks and returns
// true if the window can be made to ignore events. The actual work of making
// the window ignore events is done by ConfigureWidgetForIgnoreEvents.
bool MakeIgnoreEvents();
bool is_ignore_events() const { return ignore_events_; }
// Sets whether or not we are deleted when the widget is destroyed. The
// default is true.
void set_delete_on_destroy(bool delete_on_destroy) {
delete_on_destroy_ = delete_on_destroy;
}
// Adds and removes the specified widget as a child of this widget's contents.
// These methods make sure to add the widget to the window's contents
// container if this widget is a window.
void AddChild(GtkWidget* child);
void RemoveChild(GtkWidget* child);
// A safe way to reparent a child widget to this widget. Calls
// gtk_widget_reparent which handles refcounting to avoid destroying the
// widget when removing it from its old parent.
void ReparentChild(GtkWidget* child);
// Positions a child GtkWidget at the specified location and bounds.
void PositionChild(GtkWidget* child, int x, int y, int w, int h);
// Parent GtkWidget all children are added to. When this WidgetGtk corresponds
// to a top level window, this is the GtkFixed within the GtkWindow, not the
// GtkWindow itself. For child widgets, this is the same GtkFixed as
// |widget_|.
GtkWidget* window_contents() const { return window_contents_; }
// Starts a drag on this widget. This blocks until the drag is done.
void DoDrag(const OSExchangeData& data, int operation);
// Are we in PaintNow? See use in root_view_gtk for details on what this is
// used for.
bool in_paint_now() const { return in_paint_now_; }
// Sets the focus traversable parents.
void SetFocusTraversableParent(FocusTraversable* parent);
void SetFocusTraversableParentView(View* parent_view);
// Invoked when the active status changes.
virtual void IsActiveChanged();
// Sets initial focus on a new window. On X11/Gtk, window creation
// is asynchronous and a focus request has to be made after a window
// gets created. This will not be called on a TYPE_CHILD widget.
virtual void SetInitialFocus() {}
// Gets the WidgetGtk in the userdata section of the widget.
static WidgetGtk* GetViewForNative(GtkWidget* widget);
// Sets the drop target to NULL. This is invoked by DropTargetGTK when the
// drop is done.
void ResetDropTarget();
// Returns the RootView for |widget|.
static RootView* GetRootViewForWidget(GtkWidget* widget);
// Gets the requested size of the widget. This can be the size
// stored in properties for a GtkViewsFixed, or in the requisitioned
// size of other kinds of widgets.
void GetRequestedSize(gfx::Size* out) const;
// Overriden from ActiveWindowWatcherX::Observer.
virtual void ActiveWindowChanged(GdkWindow* active_window);
// Overridden from Widget:
virtual void Init(gfx::NativeView parent, const gfx::Rect& bounds);
virtual void InitWithWidget(Widget* parent, const gfx::Rect& bounds);
virtual WidgetDelegate* GetWidgetDelegate();
virtual void SetWidgetDelegate(WidgetDelegate* delegate);
virtual void SetContentsView(View* view);
virtual void GetBounds(gfx::Rect* out, bool including_frame) const;
virtual void SetBounds(const gfx::Rect& bounds);
virtual void MoveAbove(Widget* other);
virtual void SetShape(gfx::NativeRegion region);
virtual void Close();
virtual void CloseNow();
virtual void Show();
virtual void Hide();
virtual gfx::NativeView GetNativeView() const;
virtual void PaintNow(const gfx::Rect& update_rect);
virtual void SetOpacity(unsigned char opacity);
virtual void SetAlwaysOnTop(bool on_top);
virtual RootView* GetRootView();
virtual Widget* GetRootWidget() const;
virtual bool IsVisible() const;
virtual bool IsActive() const;
virtual void GenerateMousePressedForView(View* view,
const gfx::Point& point);
virtual TooltipManager* GetTooltipManager();
virtual bool GetAccelerator(int cmd_id, menus::Accelerator* accelerator);
virtual Window* GetWindow();
virtual const Window* GetWindow() const;
virtual void SetNativeWindowProperty(const std::wstring& name,
void* value);
virtual void* GetNativeWindowProperty(const std::wstring& name);
virtual ThemeProvider* GetThemeProvider() const;
virtual ThemeProvider* GetDefaultThemeProvider() const;
virtual FocusManager* GetFocusManager();
virtual void ViewHierarchyChanged(bool is_add, View *parent,
View *child);
virtual bool ContainsNativeView(gfx::NativeView native_view);
// Overridden from FocusTraversable:
virtual FocusSearch* GetFocusSearch();
virtual FocusTraversable* GetFocusTraversableParent();
virtual View* GetFocusTraversableParentView();
// Clears the focus on the native widget having the focus.
virtual void ClearNativeFocus();
// Handles a keyboard event by sending it to our focus manager.
// Returns true if it's handled by the focus manager.
bool HandleKeyboardEvent(GdkEventKey* event);
protected:
// If widget containes another widget, translates event coordinates to the
// contained widget's coordinates, else returns original event coordinates.
template<class Event> bool GetContainedWidgetEventCoordinates(Event* event,
int* x,
int* y) {
if (event == NULL || x == NULL || y == NULL)
return false;
*x = event->x;
*y = event->y;
GdkWindow* dest = GTK_WIDGET(window_contents_)->window;
if (event->window != dest) {
int dest_x, dest_y;
gdk_window_get_root_origin(dest, &dest_x, &dest_y);
*x = event->x_root - dest_x;
*y = event->y_root - dest_y;
return true;
}
return false;
}
// Returns the view::Event::flags for a GdkEventButton.
static int GetFlagsForEventButton(const GdkEventButton& event);
// Event handlers:
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnButtonPress, GdkEventButton*);
CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnSizeRequest, GtkRequisition*);
CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnSizeAllocate, GtkAllocation*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnPaint, GdkEventExpose*);
CHROMEGTK_CALLBACK_4(WidgetGtk, void, OnDragDataGet,
GdkDragContext*, GtkSelectionData*, guint, guint);
CHROMEGTK_CALLBACK_6(WidgetGtk, void, OnDragDataReceived,
GdkDragContext*, gint, gint, GtkSelectionData*,
guint, guint);
CHROMEGTK_CALLBACK_4(WidgetGtk, gboolean, OnDragDrop,
GdkDragContext*, gint, gint, guint);
CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnDragEnd, GdkDragContext*);
CHROMEGTK_CALLBACK_2(WidgetGtk, gboolean, OnDragFailed,
GdkDragContext*, GtkDragResult);
CHROMEGTK_CALLBACK_2(WidgetGtk, void, OnDragLeave,
GdkDragContext*, guint);
CHROMEGTK_CALLBACK_4(WidgetGtk, gboolean, OnDragMotion,
GdkDragContext*, gint, gint, guint);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnEnterNotify, GdkEventCrossing*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnLeaveNotify, GdkEventCrossing*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnMotionNotify, GdkEventMotion*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnButtonRelease, GdkEventButton*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnFocusIn, GdkEventFocus*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnFocusOut, GdkEventFocus*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnKeyEvent, GdkEventKey*);
CHROMEGTK_CALLBACK_4(WidgetGtk, gboolean, OnQueryTooltip,
gint, gint, gboolean, GtkTooltip*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnScroll, GdkEventScroll*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnVisibilityNotify,
GdkEventVisibility*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnGrabBrokeEvent, GdkEvent*);
CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnGrabNotify, gboolean);
CHROMEGTK_CALLBACK_0(WidgetGtk, void, OnDestroy);
CHROMEGTK_CALLBACK_0(WidgetGtk, void, OnShow);
CHROMEGTK_CALLBACK_0(WidgetGtk, void, OnHide);
void set_mouse_down(bool mouse_down) { is_mouse_down_ = mouse_down; }
// Do we own the mouse grab?
bool has_capture() const { return has_capture_; }
// Returns whether capture should be released on mouse release. The default
// is true.
virtual bool ReleaseCaptureOnMouseReleased() { return true; }
// Does a mouse grab on this widget.
virtual void DoGrab();
// Releases a grab done by this widget.
virtual void ReleaseGrab();
// Invoked when input grab is stolen by other GtkWidget in the same
// application.
virtual void HandleGrabBroke();
// Are we a subclass of WindowGtk?
bool is_window_;
// For test code to provide a customized focus manager.
void set_focus_manager(FocusManager* focus_manager) {
delete focus_manager_;
focus_manager_ = focus_manager;
}
private:
class DropObserver;
friend class DropObserver;
virtual RootView* CreateRootView();
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnWindowPaint, GdkEventExpose*);
// Process a mouse click.
bool ProcessMousePressed(GdkEventButton* event);
void ProcessMouseReleased(GdkEventButton* event);
// Process scroll event.
bool ProcessScroll(GdkEventScroll* event);
static void SetRootViewForWidget(GtkWidget* widget, RootView* root_view);
// Returns the first ancestor of |widget| that is a window.
static Window* GetWindowImpl(GtkWidget* widget);
// Creates the GtkWidget.
void CreateGtkWidget(GtkWidget* parent, const gfx::Rect& bounds);
// Invoked from create widget to enable the various bits needed for a
// transparent background. This is only invoked if MakeTransparent has been
// invoked.
void ConfigureWidgetForTransparentBackground(GtkWidget* parent);
// Invoked from create widget to enable the various bits needed for a
// window which doesn't receive events. This is only invoked if
// MakeIgnoreEvents has been invoked.
void ConfigureWidgetForIgnoreEvents();
// A utility function to draw a transparent background onto the |widget|.
static void DrawTransparentBackground(GtkWidget* widget,
GdkEventExpose* event);
const Type type_;
// Our native views. If we're a window/popup, then widget_ is the window and
// window_contents_ is a GtkFixed. If we're not a window/popup, then widget_
// and window_contents_ point to the same GtkFixed.
GtkWidget* widget_;
GtkWidget* window_contents_;
// Child GtkWidgets created with no parent need to be parented to a valid top
// level window otherwise Gtk throws a fit. |null_parent_| is an invisible
// popup that such GtkWidgets are parented to.
static GtkWidget* null_parent_;
// The TooltipManager.
// WARNING: RootView's destructor calls into the TooltipManager. As such, this
// must be destroyed AFTER root_view_.
scoped_ptr<TooltipManagerGtk> tooltip_manager_;
scoped_ptr<DropTargetGtk> drop_target_;
// The focus manager keeping track of focus for this Widget and any of its
// children. NULL for non top-level widgets.
// WARNING: RootView's destructor calls into the FocusManager. As such, this
// must be destroyed AFTER root_view_.
FocusManager* focus_manager_;
// The root of the View hierarchy attached to this window.
scoped_ptr<RootView> root_view_;
// If true, the mouse is currently down.
bool is_mouse_down_;
// Have we done a mouse grab?
bool has_capture_;
// The following are used to detect duplicate mouse move events and not
// deliver them. Displaying a window may result in the system generating
// duplicate move events even though the mouse hasn't moved.
// If true, the last event was a mouse move event.
bool last_mouse_event_was_move_;
// Coordinates of the last mouse move event, in screen coordinates.
int last_mouse_move_x_;
int last_mouse_move_y_;
// The following factory is used to delay destruction.
ScopedRunnableMethodFactory<WidgetGtk> close_widget_factory_;
// See description above setter.
bool delete_on_destroy_;
// See description above make_transparent for details.
bool transparent_;
// See description above MakeIgnoreEvents for details.
bool ignore_events_;
scoped_ptr<DefaultThemeProvider> default_theme_provider_;
// See note in DropObserver for details on this.
bool ignore_drag_leave_;
unsigned char opacity_;
// This is non-null during the life of DoDrag and contains the actual data
// for the drag.
const OSExchangeDataProviderGtk* drag_data_;
// See description above getter for details.
bool in_paint_now_;
// Are we active?
bool is_active_;
// See make_transient_to_parent for a description.
bool transient_to_parent_;
// Last size supplied to OnSizeAllocate. We cache this as any time the
// size of a GtkWidget changes size_allocate is called, even if the size
// didn't change. If we didn't cache this and ignore calls when the size
// hasn't changed, we can end up getting stuck in a never ending loop.
gfx::Size size_;
// This is initially false and when the first focus-in event is received this
// is set to true and no additional processing is done. Subsequently when
// focus-in is received we do the normal focus manager processing.
//
// This behavior is necessitated by Gtk/X sending focus events
// asynchronously. The initial sequence for windows is typically: show,
// request focus on some widget. Because of async events on Gtk this becomes
// show, request focus, get focus in event which ends up clearing focus
// (first request to FocusManager::RestoreFocusedView ends up clearing focus).
bool got_initial_focus_in_;
// If true, we've received a focus-in event. If false we've received a
// focus-out event. We can get multiple focus-out events in a row, we use
// this to determine whether we should process the event.
bool has_focus_;
// Non owned pointer to optional delegate. May be NULL if no delegate is
// being used.
WidgetDelegate* delegate_;
// If true, the window stays on top of the screen. This is only used
// for types other than TYPE_CHILD.
bool always_on_top_;
// If true, we enable the content widget's double buffering.
// This is false by default.
bool is_double_buffered_;
// Indicates if we should handle the upcoming Alt key release event.
bool should_handle_menu_key_release_;
DISALLOW_COPY_AND_ASSIGN(WidgetGtk);
};
} // namespace views
#endif // VIEWS_WIDGET_WIDGET_GTK_H_