<commit_before>#include "browser/linux/inspectable_web_contents_view_linux.h"
#include <glib-object.h>
#include <gtk/gtk.h>

#include "base/strings/stringprintf.h"
#include "browser/browser_client.h"
#include "browser/inspectable_web_contents_impl.h"

#include "content/public/browser/web_contents_view.h"

namespace brightray {

namespace {

bool IsWidgetAncestryVisible(GtkWidget* widget) {
  GtkWidget* parent = widget;
  while (parent && gtk_widget_get_visible(parent))
    parent = gtk_widget_get_parent(parent);
  return !parent;
}

}

InspectableWebContentsView* CreateInspectableContentsView(
    InspectableWebContentsImpl* inspectable_web_contents) {
  return new InspectableWebContentsViewLinux(inspectable_web_contents);
}

InspectableWebContentsViewLinux::InspectableWebContentsViewLinux(
    InspectableWebContentsImpl* inspectable_web_contents)
    : inspectable_web_contents_(inspectable_web_contents),
      devtools_window_(NULL) {
}

InspectableWebContentsViewLinux::~InspectableWebContentsViewLinux() {
  if (devtools_window_) gtk_widget_destroy(devtools_window_);
}

#if 0  // some utility functions to debug GTK window hierarchies
static void dump_one(GtkWidget *wat, int indent) {
  GtkAllocation alloc;
  gtk_widget_get_allocation(wat, &alloc);
  fprintf(stderr, "%*s[%p] %s @%d,%d %dx%d",
    indent, "", wat,
    g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(wat)),
    alloc.x, alloc.y, alloc.width, alloc.height);
  if (GTK_IS_WINDOW(wat)) {
    fprintf(stderr, " - \"%s\"", gtk_window_get_title(GTK_WINDOW(wat)));
  }
  fputc('\n', stderr);
}

static void dump_the_whole_tree(GtkWidget *wat, int indent) {
  if (!wat) {
    fprintf(stderr, "(nil)\n");
    return;
  }
  dump_one(wat, indent);
  GList *kids = gtk_container_get_children(GTK_CONTAINER(wat));
  for (GList *p = kids; p; p = p->next) {
    dump_the_whole_tree(GTK_WIDGET(p->data), indent+2);
  }
}

static void dump_parents(GtkWidget *wat) {
  fprintf(stderr, "Parents:\n");
  for (GtkWidget *p = gtk_widget_get_parent(wat);
       p;
       p = gtk_widget_get_parent(p)) {
    dump_one(p, 2);
  }
}
#endif

gfx::NativeView InspectableWebContentsViewLinux::GetNativeView() const {
  auto web_contents = inspectable_web_contents_->GetWebContents();
  return web_contents->GetView()->GetNativeView();
}


/* This code is a little bit hairy.
   The dev tools can be in any one of five places:
   1. Unassigned and invisible.  This is the default state until someone asks
      to 'inspect element' for the first time.  In this case, devtools->parent is
      NULL.
   2. In an onscreen window, visible.
   3. In the bottom half of a GtkVPaned.
   4. In the right half of a GtkHPaned.
   5. In an offscreen window, invisible.  This is where they go once they have
      been displayed and the user asks to "close" them.  They can't be put back
      into the unassigned state.
   ShowDevTools() and is responsible for transitioning from any one of these
   states to the three visible states, 2-4, as indicated by the contents of the
   'dockside_' variable.  The helper functions ShowDevToolsInWindow and
   ShowDevToolsInPane focus on transitioning to states 2 and 3+4, respectively.
   These helper functions are responsible for the entire transition, including
   cleaning up any extraneous containers from the old state.

   Hiding the dev tools is taken care of by CloseDevTools (from paned states
   3+4 to invisible state 5) or by the "delete-event" signal on the
   devtools_window_ (from window state 2 to 5).

   Remember that GTK does reference counting, so a view with no refs and no
   parent will be freed.  Views that have a ref but no parents will lose their
   dimensions.  So it's best to move the devtools view from place to place with
   gtk_widget_reparent whenever possible.  Unfortunately, one cannot reparent
   things into a GtkPaned, so fairly brittle use of g_object_[un]ref and
   gtk_container_remove happens.
*/

void InspectableWebContentsViewLinux::ShowDevTools() {
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
  GtkWidget *parent = gtk_widget_get_parent(devtools);

  DLOG(INFO) << base::StringPrintf(
      "InspectableWebContentsViewLinux::ShowDevTools - " \
      "parent=%s@%p window=%p dockside=\"%s\"",
      g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(parent)),
      parent,
      devtools_window_,
      dockside_.c_str());

  if (!parent || GTK_IS_PANED(parent)) {
    if (dockside_ == "undocked")    ShowDevToolsInWindow();
    else if (dockside_ == "bottom") ShowDevToolsInPane(true);
    else if (dockside_ == "right")  ShowDevToolsInPane(false);
  } else {
    DCHECK(parent == devtools_window_);
    if (dockside_ == "undocked")    gtk_widget_show_all(parent);
    else if (dockside_ == "bottom") ShowDevToolsInPane(true);
    else if (dockside_ == "right")  ShowDevToolsInPane(false);
  }
}

void InspectableWebContentsViewLinux::CloseDevTools() {
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
  GtkWidget *parent = gtk_widget_get_parent(devtools);

  DLOG(INFO) << base::StringPrintf(
      "InspectableWebContentsViewLinux::CloseDevTools - " \
      "parent=%s@%p window=%p dockside=\"%s\"",
      g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(parent)),
      parent,
      devtools_window_,
      dockside_.c_str());

  if (!parent) {
    return;  // Not visible -> nothing to do
  } else if (GTK_IS_PANED(parent)) {
    GtkWidget *browser = GetBrowserWindow();
    GtkWidget *view = GetNativeView();

    if (!devtools_window_) MakeDevToolsWindow();
    gtk_widget_reparent(devtools, devtools_window_);
    g_object_ref(parent);
    gtk_container_remove(GTK_CONTAINER(browser), parent);
    gtk_widget_reparent(view, browser);
    g_object_unref(parent);
  } else {
    DCHECK(parent == devtools_window_);
    gtk_widget_hide(parent);
  }
}

bool InspectableWebContentsViewLinux::IsDevToolsOpened() {
  return devtools_window_ && IsWidgetAncestryVisible(devtools_window_);
}

bool InspectableWebContentsViewLinux::SetDockSide(const std::string& side) {
  DLOG(INFO) <<
      "InspectableWebContentsViewLinux::SetDockSide: \"" << side << "\"";
  if (side != "undocked" && side != "bottom" && side != "right")
    return false;  // unsupported display location
  if (dockside_ == side)
    return true;  // no change from current location

  dockside_ = side;

  // If devtools already has a parent, then we're being asked to move it.
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
  if (gtk_widget_get_parent(devtools)) {
    ShowDevTools();
  }

  return true;
}
<commit_msg>Fix IsDevToolsOpened when devtools is attched to pane on Linux.<commit_after>#include "browser/linux/inspectable_web_contents_view_linux.h"
#include <glib-object.h>
#include <gtk/gtk.h>

#include "base/strings/stringprintf.h"
#include "browser/browser_client.h"
#include "browser/inspectable_web_contents_impl.h"

#include "content/public/browser/web_contents_view.h"

namespace brightray {

namespace {

bool IsWidgetAncestryVisible(GtkWidget* widget) {
  GtkWidget* parent = widget;
  while (parent && gtk_widget_get_visible(parent))
    parent = gtk_widget_get_parent(parent);
  return !parent;
}

}

InspectableWebContentsView* CreateInspectableContentsView(
    InspectableWebContentsImpl* inspectable_web_contents) {
  return new InspectableWebContentsViewLinux(inspectable_web_contents);
}

InspectableWebContentsViewLinux::InspectableWebContentsViewLinux(
    InspectableWebContentsImpl* inspectable_web_contents)
    : inspectable_web_contents_(inspectable_web_contents),
      devtools_window_(NULL) {
}

InspectableWebContentsViewLinux::~InspectableWebContentsViewLinux() {
  if (devtools_window_) gtk_widget_destroy(devtools_window_);
}

#if 0  // some utility functions to debug GTK window hierarchies
static void dump_one(GtkWidget *wat, int indent) {
  GtkAllocation alloc;
  gtk_widget_get_allocation(wat, &alloc);
  fprintf(stderr, "%*s[%p] %s @%d,%d %dx%d",
    indent, "", wat,
    g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(wat)),
    alloc.x, alloc.y, alloc.width, alloc.height);
  if (GTK_IS_WINDOW(wat)) {
    fprintf(stderr, " - \"%s\"", gtk_window_get_title(GTK_WINDOW(wat)));
  }
  fputc('\n', stderr);
}

static void dump_the_whole_tree(GtkWidget *wat, int indent) {
  if (!wat) {
    fprintf(stderr, "(nil)\n");
    return;
  }
  dump_one(wat, indent);
  GList *kids = gtk_container_get_children(GTK_CONTAINER(wat));
  for (GList *p = kids; p; p = p->next) {
    dump_the_whole_tree(GTK_WIDGET(p->data), indent+2);
  }
}

static void dump_parents(GtkWidget *wat) {
  fprintf(stderr, "Parents:\n");
  for (GtkWidget *p = gtk_widget_get_parent(wat);
       p;
       p = gtk_widget_get_parent(p)) {
    dump_one(p, 2);
  }
}
#endif

gfx::NativeView InspectableWebContentsViewLinux::GetNativeView() const {
  auto web_contents = inspectable_web_contents_->GetWebContents();
  return web_contents->GetView()->GetNativeView();
}


/* This code is a little bit hairy.
   The dev tools can be in any one of five places:
   1. Unassigned and invisible.  This is the default state until someone asks
      to 'inspect element' for the first time.  In this case, devtools->parent is
      NULL.
   2. In an onscreen window, visible.
   3. In the bottom half of a GtkVPaned.
   4. In the right half of a GtkHPaned.
   5. In an offscreen window, invisible.  This is where they go once they have
      been displayed and the user asks to "close" them.  They can't be put back
      into the unassigned state.
   ShowDevTools() and is responsible for transitioning from any one of these
   states to the three visible states, 2-4, as indicated by the contents of the
   'dockside_' variable.  The helper functions ShowDevToolsInWindow and
   ShowDevToolsInPane focus on transitioning to states 2 and 3+4, respectively.
   These helper functions are responsible for the entire transition, including
   cleaning up any extraneous containers from the old state.

   Hiding the dev tools is taken care of by CloseDevTools (from paned states
   3+4 to invisible state 5) or by the "delete-event" signal on the
   devtools_window_ (from window state 2 to 5).

   Remember that GTK does reference counting, so a view with no refs and no
   parent will be freed.  Views that have a ref but no parents will lose their
   dimensions.  So it's best to move the devtools view from place to place with
   gtk_widget_reparent whenever possible.  Unfortunately, one cannot reparent
   things into a GtkPaned, so fairly brittle use of g_object_[un]ref and
   gtk_container_remove happens.
*/

void InspectableWebContentsViewLinux::ShowDevTools() {
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
  GtkWidget *parent = gtk_widget_get_parent(devtools);

  DLOG(INFO) << base::StringPrintf(
      "InspectableWebContentsViewLinux::ShowDevTools - " \
      "parent=%s@%p window=%p dockside=\"%s\"",
      g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(parent)),
      parent,
      devtools_window_,
      dockside_.c_str());

  if (!parent || GTK_IS_PANED(parent)) {
    if (dockside_ == "undocked")    ShowDevToolsInWindow();
    else if (dockside_ == "bottom") ShowDevToolsInPane(true);
    else if (dockside_ == "right")  ShowDevToolsInPane(false);
  } else {
    DCHECK(parent == devtools_window_);
    if (dockside_ == "undocked")    gtk_widget_show_all(parent);
    else if (dockside_ == "bottom") ShowDevToolsInPane(true);
    else if (dockside_ == "right")  ShowDevToolsInPane(false);
  }
}

void InspectableWebContentsViewLinux::CloseDevTools() {
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
  GtkWidget *parent = gtk_widget_get_parent(devtools);

  DLOG(INFO) << base::StringPrintf(
      "InspectableWebContentsViewLinux::CloseDevTools - " \
      "parent=%s@%p window=%p dockside=\"%s\"",
      g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(parent)),
      parent,
      devtools_window_,
      dockside_.c_str());

  if (!parent) {
    return;  // Not visible -> nothing to do
  } else if (GTK_IS_PANED(parent)) {
    GtkWidget *browser = GetBrowserWindow();
    GtkWidget *view = GetNativeView();

    if (!devtools_window_) MakeDevToolsWindow();
    gtk_widget_reparent(devtools, devtools_window_);
    g_object_ref(parent);
    gtk_container_remove(GTK_CONTAINER(browser), parent);
    gtk_widget_reparent(view, browser);
    g_object_unref(parent);
  } else {
    DCHECK(parent == devtools_window_);
    gtk_widget_hide(parent);
  }
}

bool InspectableWebContentsViewLinux::IsDevToolsOpened() {
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget* devtools = devtools_web_contents->GetView()->GetNativeView();
  return IsWidgetAncestryVisible(devtools);
}

bool InspectableWebContentsViewLinux::SetDockSide(const std::string& side) {
  DLOG(INFO) <<
      "InspectableWebContentsViewLinux::SetDockSide: \"" << side << "\"";
  if (side != "undocked" && side != "bottom" && side != "right")
    return false;  // unsupported display location
  if (dockside_ == side)
    return true;  // no change from current location

  dockside_ = side;

  // If devtools already has a parent, then we're being asked to move it.
  auto devtools_web_contents =
      inspectable_web_contents()->devtools_web_contents();
  GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
  if (gtk_widget_get_parent(devtools)) {
    ShowDevTools();
  }

  return true;
}

{'fraction_non_alphanumeric': 0.10587144182064635, 'fraction_numerical': 0.0025683099093957336, 'mean_word_length': 4.598242811501597, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 48, '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': '4111892', 'n_tokens_mistral': 4622, 'n_tokens_neox': 4537, 'n_words': 1126}