<commit_before>// 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 "views/widget/widget_gtk.h"

#include "app/drag_drop_types.h"
#include "app/gfx/path.h"
#include "app/os_exchange_data.h"
#include "app/os_exchange_data_provider_gtk.h"
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "views/widget/default_theme_provider.h"
#include "views/widget/drop_target_gtk.h"
#include "views/widget/root_view.h"
#include "views/widget/tooltip_manager_gtk.h"
#include "views/window/window_gtk.h"

namespace views {

// During drag and drop GTK sends a drag-leave during a drop. This means we
// have no way to tell the difference between a normal drag leave and a drop.
// To work around that we listen for DROP_START, then ignore the subsequent
// drag-leave that GTK generates.
class WidgetGtk::DropObserver : public MessageLoopForUI::Observer {
 public:
  DropObserver() { }

  virtual void WillProcessEvent(GdkEvent* event) {
    if (event->type == GDK_DROP_START) {
      WidgetGtk* widget = GetWidgetGtkForEvent(event);
      if (widget)
        widget->ignore_drag_leave_ = true;
    }
  }

  virtual void DidProcessEvent(GdkEvent* event) {
  }

 private:
  WidgetGtk* GetWidgetGtkForEvent(GdkEvent* event) {
    GtkWidget* gtk_widget = gtk_get_event_widget(event);
    if (!gtk_widget)
      return NULL;

    return WidgetGtk::GetViewForNative(gtk_widget);
  }

  DISALLOW_COPY_AND_ASSIGN(DropObserver);
};

// Returns the position of a widget on screen.
static void GetWidgetPositionOnScreen(GtkWidget* widget, int* x, int *y) {
  // First get the root window.
  GtkWidget* root = widget;
  while (root && !GTK_IS_WINDOW(root)) {
    root = gtk_widget_get_parent(root);
  }
  DCHECK(root);
  // Translate the coordinate from widget to root window.
  gtk_widget_translate_coordinates(widget, root, 0, 0, x, y);
  // Then adjust the position with the position of the root window.
  int window_x, window_y;
  gtk_window_get_position(GTK_WINDOW(root), &window_x, &window_y);
  *x += window_x;
  *y += window_y;
}

// Returns the view::Event::flags for a GdkEventButton.
static int GetFlagsForEventButton(const GdkEventButton& event) {
  int flags = Event::GetFlagsFromGdkState(event.state);
  switch (event.button) {
    case 1:
      flags |= Event::EF_LEFT_BUTTON_DOWN;
      break;
    case 2:
      flags |= Event::EF_MIDDLE_BUTTON_DOWN;
      break;
    case 3:
      flags |= Event::EF_RIGHT_BUTTON_DOWN;
      break;
    default:
      // We only deal with 1-3.
      break;
  }
  if (event.type == GDK_2BUTTON_PRESS)
    flags |= MouseEvent::EF_IS_DOUBLE_CLICK;
  return flags;
}

// static
GtkWidget* WidgetGtk::null_parent_ = NULL;

////////////////////////////////////////////////////////////////////////////////
// WidgetGtk, public:

WidgetGtk::WidgetGtk(Type type)
    : is_window_(false),
      type_(type),
      widget_(NULL),
      window_contents_(NULL),
      is_mouse_down_(false),
      has_capture_(false),
      last_mouse_event_was_move_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)),
      delete_on_destroy_(true),
      transparent_(false),
      ignore_drag_leave_(false),
      opacity_(255),
      drag_data_(NULL),
      in_paint_now_(false),
      is_active_(false),
      transient_to_parent_(false) {
  static bool installed_message_loop_observer = false;
  if (!installed_message_loop_observer) {
    installed_message_loop_observer = true;
    MessageLoopForUI* loop = MessageLoopForUI::current();
    if (loop)
      loop->AddObserver(new DropObserver());
  }

  if (type_ != TYPE_CHILD)
    focus_manager_.reset(new FocusManager(this));
}

WidgetGtk::~WidgetGtk() {
  if (type_ != TYPE_CHILD)
    ActiveWindowWatcherX::RemoveObserver(this);
  MessageLoopForUI::current()->RemoveObserver(this);
}

bool WidgetGtk::MakeTransparent() {
  // Transparency can only be enabled for windows/popups and only if we haven't
  // realized the widget.
  DCHECK(!widget_ && type_ != TYPE_CHILD);

  if (!gdk_screen_is_composited(gdk_screen_get_default())) {
    // Transparency is only supported for compositing window managers.
    DLOG(WARNING) << "compositing not supported";
    return false;
  }

  if (!gdk_screen_get_rgba_colormap(gdk_screen_get_default())) {
    // We need rgba to make the window transparent.
    return false;
  }

  transparent_ = true;
  return true;
}

void WidgetGtk::AddChild(GtkWidget* child) {
  gtk_container_add(GTK_CONTAINER(window_contents_), child);
}

void WidgetGtk::RemoveChild(GtkWidget* child) {
  // We can be called after the contents widget has been destroyed, e.g. any
  // NativeViewHost not removed from the view hierarchy before the window is
  // closed.
  if (GTK_IS_CONTAINER(window_contents_))
    gtk_container_remove(GTK_CONTAINER(window_contents_), child);
}

void WidgetGtk::ReparentChild(GtkWidget* child) {
  gtk_widget_reparent(child, window_contents_);
}

void WidgetGtk::PositionChild(GtkWidget* child, int x, int y, int w, int h) {
  GtkAllocation alloc = { x, y, w, h };
  // For some reason we need to do both of these to size a widget.
  gtk_widget_size_allocate(child, &alloc);
  gtk_widget_set_size_request(child, w, h);
  gtk_fixed_move(GTK_FIXED(window_contents_), child, x, y);
}

void WidgetGtk::DoDrag(const OSExchangeData& data, int operation) {
  const OSExchangeDataProviderGtk& data_provider =
      static_cast<const OSExchangeDataProviderGtk&>(data.provider());
  GtkTargetList* targets = data_provider.GetTargetList();
  GdkEvent* current_event = gtk_get_current_event();
  DCHECK(current_event);
  gtk_drag_begin(window_contents_, targets,
                 static_cast<GdkDragAction>(
                     DragDropTypes::DragOperationToGdkDragAction(operation)),
                 1, current_event);
  gdk_event_free(current_event);
  gtk_target_list_unref(targets);

  drag_data_ = &data_provider;

  // Block the caller until drag is done by running a nested message loop.
  MessageLoopForUI::current()->Run(NULL);

  drag_data_ = NULL;
}

void WidgetGtk::ActiveWindowChanged(GdkWindow* active_window) {
  if (!GetNativeView())
    return;

  bool was_active = IsActive();
  is_active_ = (active_window == GTK_WIDGET(GetNativeView())->window);
  if (!is_active_ && active_window && type_ != TYPE_CHILD) {
    // We're not active, but the force the window to be rendered as active if
    // a child window is transient to us.
    GtkWidget* widget = NULL;
    gdk_window_get_user_data(active_window,
                             reinterpret_cast<gpointer*>(&widget));
    is_active_ =<commit_msg>Fixes compile warning. If you have a better suggestion for this, let me know. Here's the warning I was getting without this:<commit_after>// 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 "views/widget/widget_gtk.h"

#include "app/drag_drop_types.h"
#include "app/gfx/path.h"
#include "app/os_exchange_data.h"
#include "app/os_exchange_data_provider_gtk.h"
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "views/widget/default_theme_provider.h"
#include "views/widget/drop_target_gtk.h"
#include "views/widget/root_view.h"
#include "views/widget/tooltip_manager_gtk.h"
#include "views/window/window_gtk.h"

namespace views {

// During drag and drop GTK sends a drag-leave during a drop. This means we
// have no way to tell the difference between a normal drag leave and a drop.
// To work around that we listen for DROP_START, then ignore the subsequent
// drag-leave that GTK generates.
class WidgetGtk::DropObserver : public MessageLoopForUI::Observer {
 public:
  DropObserver() { }

  virtual void WillProcessEvent(GdkEvent* event) {
    if (event->type == GDK_DROP_START) {
      WidgetGtk* widget = GetWidgetGtkForEvent(event);
      if (widget)
        widget->ignore_drag_leave_ = true;
    }
  }

  virtual void DidProcessEvent(GdkEvent* event) {
  }

 private:
  WidgetGtk* GetWidgetGtkForEvent(GdkEvent* event) {
    GtkWidget* gtk_widget = gtk_get_event_widget(event);
    if (!gtk_widget)
      return NULL;

    return WidgetGtk::GetViewForNative(gtk_widget);
  }

  DISALLOW_COPY_AND_ASSIGN(DropObserver);
};

// Returns the position of a widget on screen.
static void GetWidgetPositionOnScreen(GtkWidget* widget, int* x, int *y) {
  // First get the root window.
  GtkWidget* root = widget;
  while (root && !GTK_IS_WINDOW(root)) {
    root = gtk_widget_get_parent(root);
  }
  DCHECK(root);
  // Translate the coordinate from widget to root window.
  gtk_widget_translate_coordinates(widget, root, 0, 0, x, y);
  // Then adjust the position with the position of the root window.
  int window_x, window_y;
  gtk_window_get_position(GTK_WINDOW(root), &window_x, &window_y);
  *x += window_x;
  *y += window_y;
}

// Returns the view::Event::flags for a GdkEventButton.
static int GetFlagsForEventButton(const GdkEventButton& event) {
  int flags = Event::GetFlagsFromGdkState(event.state);
  switch (event.button) {
    case 1:
      flags |= Event::EF_LEFT_BUTTON_DOWN;
      break;
    case 2:
      flags |= Event::EF_MIDDLE_BUTTON_DOWN;
      break;
    case 3:
      flags |= Event::EF_RIGHT_BUTTON_DOWN;
      break;
    default:
      // We only deal with 1-3.
      break;
  }
  if (event.type == GDK_2BUTTON_PRESS)
    flags |= MouseEvent::EF_IS_DOUBLE_CLICK;
  return flags;
}

// static
GtkWidget* WidgetGtk::null_parent_ = NULL;

////////////////////////////////////////////////////////////////////////////////
// WidgetGtk, public:

WidgetGtk::WidgetGtk(Type type)
    : is_window_(false),
      type_(type),
      widget_(NULL),
      window_contents_(NULL),
      is_mouse_down_(false),
      has_capture_(false),
      last_mouse_event_was_move_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)),
      delete_on_destroy_(true),
      transparent_(false),
      ignore_drag_leave_(false),
      opacity_(255),
      drag_data_(NULL),
      in_paint_now_(false),
      is_active_(false),
      transient_to_parent_(false) {
  static bool installed_message_loop_observer = false;
  if (!installed_message_loop_observer) {
    installed_message_loop_observer = true;
    MessageLoopForUI* loop = MessageLoopForUI::current();
    if (loop)
      loop->AddObserver(new DropObserver());
  }

  if (type_ != TYPE_CHILD)
    focus_manager_.reset(new FocusManager(this));
}

WidgetGtk::~WidgetGtk() {
  if (type_ != TYPE_CHILD)
    ActiveWindowWatcherX::RemoveObserver(this);
  MessageLoopForUI::current()->RemoveObserver(this);
}

bool WidgetGtk::MakeTransparent() {
  // Transparency can only be enabled for windows/popups and only if we haven't
  // realized the widget.
  DCHECK(!widget_ && type_ != TYPE_CHILD);

  if (!gdk_screen_is_composited(gdk_screen_get_default())) {
    // Transparency is only supported for compositing window managers.
    DLOG(WARNING) << "compositing not supported";
    return false;
  }

  if (!gdk_screen_get_rgba_colormap(gdk_screen_get_default())) {
    // We need rgba to make the window transparent.
    return false;
  }

  transparent_ = true;
  return true;
}

void WidgetGtk::AddChild(GtkWidget* child) {
  gtk_container_add(GTK_CONTAINER(window_contents_), child);
}

void WidgetGtk::RemoveChild(GtkWidget* child) {
  // We can be called after the contents widget has been destroyed, e.g. any
  // NativeViewHost not removed from the view hierarchy before the window is
  // closed.
  if (GTK_IS_CONTAINER(window_contents_))
    gtk_container_remove(GTK_CONTAINER(window_contents_), child);
}

void WidgetGtk::ReparentChild(GtkWidget* child) {
  gtk_widget_reparent(child, window_contents_);
}

void WidgetGtk::PositionChild(GtkWidget* child, int x, int y, int w, int h) {
  GtkAllocation alloc = { x, y, w, h };
  // For some reason we need to do both of these to size a widget.
  gtk_widget_size_allocate(child, &alloc);
  gtk_widget_set_size_request(child, w, h);
  gtk_fixed_move(GTK_FIXED(window_contents_), child, x, y);
}

void WidgetGtk::DoDrag(const OSExchangeData& data, int operation) {
  const OSExchangeDataProviderGtk& data_provider =
      static_cast<const OSExchangeDataProviderGtk&>(data.provider());
  GtkTargetList* targets = data_provider.GetTargetList();
  GdkEvent* current_event = gtk_get_current_event();
  DCHECK(current_event);
  gtk_drag_begin(window_contents_, targets,
                 static_cast<GdkDragAction>(
                     DragDropTypes::DragOperationToGdkDragAction(operation)),
                 1, current_event);
  gdk_event_free(current_event);
  gtk_target_list_unref(targets);

  drag_data_ = &data_provider;

  // Block the caller until drag is done by running a nested message loop.
  MessageLoopForUI::current()->Run(NULL);

  drag_data_ = NULL;
}

void WidgetGtk::ActiveWindowChanged(GdkWindow* active_window) {
  if (!GetNativeView())
    return;

  bool was_active = IsActive();
  is_active_ = (active_window == GTK_WIDGET(GetNativeView())->window);
  if (!is_active_ && active_window && type_ != TYPE_CHILD) {
    // We're not active, but the force the window to be rendered as active if
    // a child window is transient to us.
    gpointer data = NULL;
    gdk_window_get_user_data(active_window, &data);
    GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
    is_active_ =
{'fraction_non_alphanumeric': 0.1157300868532403, 'fraction_numerical': 0.002375473238809294, 'mean_word_length': 3.897128316975645, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6481791', 'n_tokens_mistral': 4441, 'n_tokens_neox': 4355, 'n_words': 1064}