<commit_before>// Copyright 2013 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/ui/libgtk2ui/app_indicator_icon.h"

#include <gtk/gtk.h>
#include <dlfcn.h>

#include "base/bind.h"
#include "base/file_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/ui/libgtk2ui/menu_util.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/image/image_skia.h"

namespace {

typedef enum {
  APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
  APP_INDICATOR_CATEGORY_COMMUNICATIONS,
  APP_INDICATOR_CATEGORY_SYSTEM_SERVICES,
  APP_INDICATOR_CATEGORY_HARDWARE,
  APP_INDICATOR_CATEGORY_OTHER
} AppIndicatorCategory;

typedef enum {
  APP_INDICATOR_STATUS_PASSIVE,
  APP_INDICATOR_STATUS_ACTIVE,
  APP_INDICATOR_STATUS_ATTENTION
} AppIndicatorStatus;

typedef AppIndicator* (*app_indicator_new_func)(const gchar* id,
                                                const gchar* icon_name,
                                                AppIndicatorCategory category);

typedef AppIndicator* (*app_indicator_new_with_path_func)(
    const gchar* id,
    const gchar* icon_name,
    AppIndicatorCategory category,
    const gchar* icon_theme_path);

typedef void (*app_indicator_set_status_func)(AppIndicator* self,
                                              AppIndicatorStatus status);

typedef void (*app_indicator_set_attention_icon_full_func)(
    AppIndicator* self,
    const gchar* icon_name,
    const gchar* icon_desc);

typedef void (*app_indicator_set_menu_func)(AppIndicator* self, GtkMenu* menu);

typedef void (*app_indicator_set_icon_full_func)(AppIndicator* self,
                                                 const gchar* icon_name,
                                                 const gchar* icon_desc);

typedef void (*app_indicator_set_icon_theme_path_func)(
    AppIndicator* self,
    const gchar* icon_theme_path);

bool g_attempted_load = false;
bool g_opened = false;

// Retrieved functions from libappindicator.
app_indicator_new_func app_indicator_new = NULL;
app_indicator_new_with_path_func app_indicator_new_with_path = NULL;
app_indicator_set_status_func app_indicator_set_status = NULL;
app_indicator_set_attention_icon_full_func
    app_indicator_set_attention_icon_full = NULL;
app_indicator_set_menu_func app_indicator_set_menu = NULL;
app_indicator_set_icon_full_func app_indicator_set_icon_full = NULL;
app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL;

void EnsureMethodsLoaded() {
  if (g_attempted_load)
    return;

  g_attempted_load = true;

  void* indicator_lib = dlopen("libappindicator.so", RTLD_LAZY);
  if (!indicator_lib) {
    indicator_lib = dlopen("libappindicator3.so.1", RTLD_LAZY);
  }
  if (!indicator_lib) {
    indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY);
  }
  if (!indicator_lib) {
    indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY);
  }
  if (!indicator_lib) {
    return;
  }

  g_opened = true;

  app_indicator_new = reinterpret_cast<app_indicator_new_func>(
      dlsym(indicator_lib, "app_indicator_new"));

  app_indicator_new_with_path =
      reinterpret_cast<app_indicator_new_with_path_func>(
          dlsym(indicator_lib, "app_indicator_new_with_path"));

  app_indicator_set_status = reinterpret_cast<app_indicator_set_status_func>(
      dlsym(indicator_lib, "app_indicator_set_status"));

  app_indicator_set_attention_icon_full =
      reinterpret_cast<app_indicator_set_attention_icon_full_func>(
          dlsym(indicator_lib, "app_indicator_set_attention_icon_full"));

  app_indicator_set_menu = reinterpret_cast<app_indicator_set_menu_func>(
      dlsym(indicator_lib, "app_indicator_set_menu"));

  app_indicator_set_icon_full =
      reinterpret_cast<app_indicator_set_icon_full_func>(
          dlsym(indicator_lib, "app_indicator_set_icon_full"));

  app_indicator_set_icon_theme_path =
      reinterpret_cast<app_indicator_set_icon_theme_path_func>(
          dlsym(indicator_lib, "app_indicator_set_icon_theme_path"));
}

base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr,
                                   int icon_change_count,
                                   std::string id) {
  scoped_ptr<gfx::ImageSkia> image(image_ptr);

  scoped_refptr<base::RefCountedMemory> png_data =
      gfx::Image(*image.get()).As1xPNGBytes();
  if (png_data->size() == 0) {
    // If the bitmap could not be encoded to PNG format, skip it.
    LOG(WARNING) << "Could not encode icon";
    return base::FilePath();
  }

  base::FilePath temp_dir;
  base::FilePath new_file_path;

  // Create a new temporary directory for each image since using a single
  // temporary directory seems to have issues when changing icons in quick
  // succession.
  if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_dir))
    return base::FilePath();
  new_file_path =
      temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count));
  int bytes_written =
      base::WriteFile(new_file_path,
                      png_data->front_as<char>(), png_data->size());

  if (bytes_written != static_cast<int>(png_data->size()))
    return base::FilePath();
  return new_file_path;
}

void DeleteTempImagePath(const base::FilePath& icon_file_path) {
  if (icon_file_path.empty())
    return;
  base::DeleteFile(icon_file_path, true);
}

}  // namespace

namespace libgtk2ui {

AppIndicatorIcon::AppIndicatorIcon(std::string id,
                                   const gfx::ImageSkia& image,
                                   const base::string16& tool_tip)
    : id_(id),
      icon_(NULL),
      gtk_menu_(NULL),
      menu_model_(NULL),
      icon_change_count_(0),
      block_activation_(false),
      weak_factory_(this) {
  EnsureMethodsLoaded();
  tool_tip_ = base::UTF16ToUTF8(tool_tip);
  SetImage(image);
}
AppIndicatorIcon::~AppIndicatorIcon() {
  if (icon_) {
    app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
    if (gtk_menu_)
      DestroyMenu();
    g_object_unref(icon_);
    content::BrowserThread::GetBlockingPool()->PostTask(
        FROM_HERE,
        base::Bind(&DeleteTempImagePath, icon_file_path_.DirName()));
  }
}

// static
bool AppIndicatorIcon::CouldOpen() {
  EnsureMethodsLoaded();
  return g_opened;
}

void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) {
  if (!g_opened)
    return;

  ++icon_change_count_;

  // We create a deep copy of the image since it may have been freed by the time
  // it's accessed in the other thread.
  scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy());
  base::PostTaskAndReplyWithResult(
      content::BrowserThread::GetBlockingPool()
          ->GetTaskRunnerWithShutdownBehavior(
                base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
      FROM_HERE,
      base::Bind(&CreateTempImageFile,
                 safe_image.release(),
                 icon_change_count_,
                 id_),
      base::Bind(&AppIndicatorIcon::SetImageFromFile,
                 weak_factory_.GetWeakPtr()));
}

void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
  // Ignore pressed images, since the standard on Linux is to not highlight
  // pressed status icons.
}

void AppIndicatorIcon::SetToolTip(const base::string16& tool_tip) {
  DCHECK(!tool_tip_.empty());
  tool_tip_ = base::UTF16ToUTF8(tool_tip);

  // We can set the click action label only if the icon exists. Also we only
  // need to update the label if it is shown and it's only shown if we are sure
  // that there is a click action or if there is no menu.
  if (icon_ && (delegate()->HasClickAction() || menu_model_ == NULL)) {
    GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_));
    for (GList* child = children; child; child = g_list_next(child))
      if (g_object_get_data(G_OBJECT(child->data), "click-action-item") !=
          NULL) {
        gtk_menu_item_set_label(GTK_MENU_ITEM(child->data),
                                tool_tip_.c_str());
        break;
      }
    g_list_free(children);
  }
}

void AppIndicatorIcon::UpdatePlatformContextMenu(ui::MenuModel* model) {
  if (!g_opened)
    return;

  if (gtk_menu_) {
    DestroyMenu();
  }
  menu_model_ = model;

  // The icon is created asynchronously so it might not exist when the menu is
  // set.
  if (icon_)
    SetMenu();
}

void AppIndicatorIcon::RefreshPlatformContextMenu() {
  gtk_container_foreach(
      GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
}

void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  if (icon_file_path.empty())
    return;

  base::FilePath old_path = icon_file_path_;
  icon_file_path_ = icon_file_path;

  std::string icon_name =
      icon_file_path_.BaseName().RemoveExtension().value();
  std::string icon_dir = icon_file_path_.DirName().value();
  if (!icon_) {
    icon_ =
        app_indicator_new_with_path(id_.c_str(),
                                    icon_name.c_str(),
                                    APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
                                    icon_dir.c_str());
    app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE);
    SetMenu();
  } else {
    // Currently we are creating a new temp directory every time the icon is
    // set. So we need to set the directory each time.
    app_indicator_set_icon_theme_path(icon_, icon_dir.c_str());
    app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon");

    // Delete previous icon directory.
    content::BrowserThread::GetBlockingPool()->PostTask(
        FROM_HERE,
        base::Bind(&DeleteTempImagePath, old_path.DirName()));
  }
}

void AppIndicatorIcon::SetMenu() {
  gtk_menu_ = gtk_menu_new();

  if (delegate()->HasClickAction() || menu_model_ == NULL) {
    CreateClickActionReplacement();
    if (menu_model_) {
      // Add separator before the other menu items.
      GtkWidget* menu_item = gtk_separator_menu_item_new();
      gtk_widget_show(menu_item);
      gtk_menu_shell_append(GTK_MENU_SHELL(gtk_menu_), menu_item);
    }
  }
  if (menu_model_) {
    BuildSubmenuFromModel(menu_model_,
                          gtk_menu_,
                          G_CALLBACK(OnMenuItemActivatedThunk),
                          &block_activation_,
                          this);
    RefreshPlatformContextMenu();
  }
  app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
}

void AppIndicatorIcon::CreateClickActionReplacement() {
  DCHECK(!tool_tip_.empty());

  // Add "click replacement menu item".
  GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(tool_tip_.c_str());
  g_object_set_data(
      G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1));
  g_signal_connect(menu_item, "activate", G_CALLBACK(OnClickThunk), this);
  gtk_widget_show(menu_item);
  gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
}

void AppIndicatorIcon::DestroyMenu() {
  gtk_widget_destroy(gtk_menu_);
  gtk_menu_ = NULL;
  menu_model_ = NULL;
}

void AppIndicatorIcon::OnClick(GtkWidget* menu_item) {
  if (delegate())
    delegate()->OnClick();
}

void AppIndicatorIcon::OnMenuItemActivated(GtkWidget* menu_item) {
  if (block_activation_)
    return;

  ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item));
  if (!model) {
    // There won't be a model for "native" submenus like the "Input Methods"
    // context menu. We don't need to handle activation messages for submenus
    // anyway, so we can just return here.
    DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)));
    return;
  }

  // The activate signal is sent to radio items as they get deselected;
  // ignore it in this case.
  if (GTK_IS_RADIO_MENU_ITEM(menu_item) &&
      !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) {
    return;
  }

  int id;
  if (!GetMenuItemID(menu_item, &id))
    return;

  // The menu item can still be activated by hotkeys even if it is disabled.
  if (menu_model_->IsEnabledAt(id))
    ExecuteCommand(model, id);
}

}  // namespace libgtk2ui
<commit_msg>Revert of linux_aura: Add Trusty libappindicator. (https://codereview.chromium.org/297833013/)<commit_after>// Copyright 2013 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/ui/libgtk2ui/app_indicator_icon.h"

#include <gtk/gtk.h>
#include <dlfcn.h>

#include "base/bind.h"
#include "base/file_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/ui/libgtk2ui/menu_util.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/image/image_skia.h"

namespace {

typedef enum {
  APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
  APP_INDICATOR_CATEGORY_COMMUNICATIONS,
  APP_INDICATOR_CATEGORY_SYSTEM_SERVICES,
  APP_INDICATOR_CATEGORY_HARDWARE,
  APP_INDICATOR_CATEGORY_OTHER
} AppIndicatorCategory;

typedef enum {
  APP_INDICATOR_STATUS_PASSIVE,
  APP_INDICATOR_STATUS_ACTIVE,
  APP_INDICATOR_STATUS_ATTENTION
} AppIndicatorStatus;

typedef AppIndicator* (*app_indicator_new_func)(const gchar* id,
                                                const gchar* icon_name,
                                                AppIndicatorCategory category);

typedef AppIndicator* (*app_indicator_new_with_path_func)(
    const gchar* id,
    const gchar* icon_name,
    AppIndicatorCategory category,
    const gchar* icon_theme_path);

typedef void (*app_indicator_set_status_func)(AppIndicator* self,
                                              AppIndicatorStatus status);

typedef void (*app_indicator_set_attention_icon_full_func)(
    AppIndicator* self,
    const gchar* icon_name,
    const gchar* icon_desc);

typedef void (*app_indicator_set_menu_func)(AppIndicator* self, GtkMenu* menu);

typedef void (*app_indicator_set_icon_full_func)(AppIndicator* self,
                                                 const gchar* icon_name,
                                                 const gchar* icon_desc);

typedef void (*app_indicator_set_icon_theme_path_func)(
    AppIndicator* self,
    const gchar* icon_theme_path);

bool g_attempted_load = false;
bool g_opened = false;

// Retrieved functions from libappindicator.
app_indicator_new_func app_indicator_new = NULL;
app_indicator_new_with_path_func app_indicator_new_with_path = NULL;
app_indicator_set_status_func app_indicator_set_status = NULL;
app_indicator_set_attention_icon_full_func
    app_indicator_set_attention_icon_full = NULL;
app_indicator_set_menu_func app_indicator_set_menu = NULL;
app_indicator_set_icon_full_func app_indicator_set_icon_full = NULL;
app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL;

void EnsureMethodsLoaded() {
  if (g_attempted_load)
    return;

  g_attempted_load = true;

  void* indicator_lib = dlopen("libappindicator.so", RTLD_LAZY);
  if (!indicator_lib) {
    indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY);
  }
  if (!indicator_lib) {
    indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY);
  }
  if (!indicator_lib) {
    return;
  }

  g_opened = true;

  app_indicator_new = reinterpret_cast<app_indicator_new_func>(
      dlsym(indicator_lib, "app_indicator_new"));

  app_indicator_new_with_path =
      reinterpret_cast<app_indicator_new_with_path_func>(
          dlsym(indicator_lib, "app_indicator_new_with_path"));

  app_indicator_set_status = reinterpret_cast<app_indicator_set_status_func>(
      dlsym(indicator_lib, "app_indicator_set_status"));

  app_indicator_set_attention_icon_full =
      reinterpret_cast<app_indicator_set_attention_icon_full_func>(
          dlsym(indicator_lib, "app_indicator_set_attention_icon_full"));

  app_indicator_set_menu = reinterpret_cast<app_indicator_set_menu_func>(
      dlsym(indicator_lib, "app_indicator_set_menu"));

  app_indicator_set_icon_full =
      reinterpret_cast<app_indicator_set_icon_full_func>(
          dlsym(indicator_lib, "app_indicator_set_icon_full"));

  app_indicator_set_icon_theme_path =
      reinterpret_cast<app_indicator_set_icon_theme_path_func>(
          dlsym(indicator_lib, "app_indicator_set_icon_theme_path"));
}

base::FilePath CreateTempImageFile(gfx::ImageSkia* image_ptr,
                                   int icon_change_count,
                                   std::string id) {
  scoped_ptr<gfx::ImageSkia> image(image_ptr);

  scoped_refptr<base::RefCountedMemory> png_data =
      gfx::Image(*image.get()).As1xPNGBytes();
  if (png_data->size() == 0) {
    // If the bitmap could not be encoded to PNG format, skip it.
    LOG(WARNING) << "Could not encode icon";
    return base::FilePath();
  }

  base::FilePath temp_dir;
  base::FilePath new_file_path;

  // Create a new temporary directory for each image since using a single
  // temporary directory seems to have issues when changing icons in quick
  // succession.
  if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_dir))
    return base::FilePath();
  new_file_path =
      temp_dir.Append(id + base::StringPrintf("_%d.png", icon_change_count));
  int bytes_written =
      base::WriteFile(new_file_path,
                      png_data->front_as<char>(), png_data->size());

  if (bytes_written != static_cast<int>(png_data->size()))
    return base::FilePath();
  return new_file_path;
}

void DeleteTempImagePath(const base::FilePath& icon_file_path) {
  if (icon_file_path.empty())
    return;
  base::DeleteFile(icon_file_path, true);
}

}  // namespace

namespace libgtk2ui {

AppIndicatorIcon::AppIndicatorIcon(std::string id,
                                   const gfx::ImageSkia& image,
                                   const base::string16& tool_tip)
    : id_(id),
      icon_(NULL),
      gtk_menu_(NULL),
      menu_model_(NULL),
      icon_change_count_(0),
      block_activation_(false),
      weak_factory_(this) {
  EnsureMethodsLoaded();
  tool_tip_ = base::UTF16ToUTF8(tool_tip);
  SetImage(image);
}
AppIndicatorIcon::~AppIndicatorIcon() {
  if (icon_) {
    app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
    if (gtk_menu_)
      DestroyMenu();
    g_object_unref(icon_);
    content::BrowserThread::GetBlockingPool()->PostTask(
        FROM_HERE,
        base::Bind(&DeleteTempImagePath, icon_file_path_.DirName()));
  }
}

// static
bool AppIndicatorIcon::CouldOpen() {
  EnsureMethodsLoaded();
  return g_opened;
}

void AppIndicatorIcon::SetImage(const gfx::ImageSkia& image) {
  if (!g_opened)
    return;

  ++icon_change_count_;

  // We create a deep copy of the image since it may have been freed by the time
  // it's accessed in the other thread.
  scoped_ptr<gfx::ImageSkia> safe_image(image.DeepCopy());
  base::PostTaskAndReplyWithResult(
      content::BrowserThread::GetBlockingPool()
          ->GetTaskRunnerWithShutdownBehavior(
                base::SequencedWorkerPool::SKIP_ON_SHUTDOWN).get(),
      FROM_HERE,
      base::Bind(&CreateTempImageFile,
                 safe_image.release(),
                 icon_change_count_,
                 id_),
      base::Bind(&AppIndicatorIcon::SetImageFromFile,
                 weak_factory_.GetWeakPtr()));
}

void AppIndicatorIcon::SetPressedImage(const gfx::ImageSkia& image) {
  // Ignore pressed images, since the standard on Linux is to not highlight
  // pressed status icons.
}

void AppIndicatorIcon::SetToolTip(const base::string16& tool_tip) {
  DCHECK(!tool_tip_.empty());
  tool_tip_ = base::UTF16ToUTF8(tool_tip);

  // We can set the click action label only if the icon exists. Also we only
  // need to update the label if it is shown and it's only shown if we are sure
  // that there is a click action or if there is no menu.
  if (icon_ && (delegate()->HasClickAction() || menu_model_ == NULL)) {
    GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_));
    for (GList* child = children; child; child = g_list_next(child))
      if (g_object_get_data(G_OBJECT(child->data), "click-action-item") !=
          NULL) {
        gtk_menu_item_set_label(GTK_MENU_ITEM(child->data),
                                tool_tip_.c_str());
        break;
      }
    g_list_free(children);
  }
}

void AppIndicatorIcon::UpdatePlatformContextMenu(ui::MenuModel* model) {
  if (!g_opened)
    return;

  if (gtk_menu_) {
    DestroyMenu();
  }
  menu_model_ = model;

  // The icon is created asynchronously so it might not exist when the menu is
  // set.
  if (icon_)
    SetMenu();
}

void AppIndicatorIcon::RefreshPlatformContextMenu() {
  gtk_container_foreach(
      GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
}

void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  if (icon_file_path.empty())
    return;

  base::FilePath old_path = icon_file_path_;
  icon_file_path_ = icon_file_path;

  std::string icon_name =
      icon_file_path_.BaseName().RemoveExtension().value();
  std::string icon_dir = icon_file_path_.DirName().value();
  if (!icon_) {
    icon_ =
        app_indicator_new_with_path(id_.c_str(),
                                    icon_name.c_str(),
                                    APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
                                    icon_dir.c_str());
    app_indicator_set_status(icon_, APP_INDICATOR_STATUS_ACTIVE);
    SetMenu();
  } else {
    // Currently we are creating a new temp directory every time the icon is
    // set. So we need to set the directory each time.
    app_indicator_set_icon_theme_path(icon_, icon_dir.c_str());
    app_indicator_set_icon_full(icon_, icon_name.c_str(), "icon");

    // Delete previous icon directory.
    content::BrowserThread::GetBlockingPool()->PostTask(
        FROM_HERE,
        base::Bind(&DeleteTempImagePath, old_path.DirName()));
  }
}

void AppIndicatorIcon::SetMenu() {
  gtk_menu_ = gtk_menu_new();

  if (delegate()->HasClickAction() || menu_model_ == NULL) {
    CreateClickActionReplacement();
    if (menu_model_) {
      // Add separator before the other menu items.
      GtkWidget* menu_item = gtk_separator_menu_item_new();
      gtk_widget_show(menu_item);
      gtk_menu_shell_append(GTK_MENU_SHELL(gtk_menu_), menu_item);
    }
  }
  if (menu_model_) {
    BuildSubmenuFromModel(menu_model_,
                          gtk_menu_,
                          G_CALLBACK(OnMenuItemActivatedThunk),
                          &block_activation_,
                          this);
    RefreshPlatformContextMenu();
  }
  app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
}

void AppIndicatorIcon::CreateClickActionReplacement() {
  DCHECK(!tool_tip_.empty());

  // Add "click replacement menu item".
  GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(tool_tip_.c_str());
  g_object_set_data(
      G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1));
  g_signal_connect(menu_item, "activate", G_CALLBACK(OnClickThunk), this);
  gtk_widget_show(menu_item);
  gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
}

void AppIndicatorIcon::DestroyMenu() {
  gtk_widget_destroy(gtk_menu_);
  gtk_menu_ = NULL;
  menu_model_ = NULL;
}

void AppIndicatorIcon::OnClick(GtkWidget* menu_item) {
  if (delegate())
    delegate()->OnClick();
}

void AppIndicatorIcon::OnMenuItemActivated(GtkWidget* menu_item) {
  if (block_activation_)
    return;

  ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item));
  if (!model) {
    // There won't be a model for "native" submenus like the "Input Methods"
    // context menu. We don't need to handle activation messages for submenus
    // anyway, so we can just return here.
    DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)));
    return;
  }

  // The activate signal is sent to radio items as they get deselected;
  // ignore it in this case.
  if (GTK_IS_RADIO_MENU_ITEM(menu_item) &&
      !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) {
    return;
  }

  int id;
  if (!GetMenuItemID(menu_item, &id))
    return;

  // The menu item can still be activated by hotkeys even if it is disabled.
  if (menu_model_->IsEnabledAt(id))
    ExecuteCommand(model, id);
}

}  // namespace libgtk2ui
<|endoftext|>


<commit_before>//===--- ElseAfterReturnCheck.cpp - clang-tidy-----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ElseAfterReturnCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {
namespace readability {

void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) {
  const auto ControlFlowInterruptorMatcher =
      stmt(anyOf(returnStmt().bind("return"), continueStmt().bind("continue"),
                 breakStmt().bind("break"),
                 expr(ignoringImplicit(cxxThrowExpr().bind("throw")))));
  Finder->addMatcher(
      compoundStmt(forEach(
          ifStmt(unless(isConstexpr()),
                 hasThen(stmt(
                     anyOf(ControlFlowInterruptorMatcher,
                           compoundStmt(has(ControlFlowInterruptorMatcher))))),
                 hasElse(stmt().bind("else")))
              .bind("if"))),
      this);
}

void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
  SourceLocation ElseLoc = If->getElseLoc();
  std::string ControlFlowInterruptor;
  for (const auto *BindingName : {"return", "continue", "break", "throw"})
    if (Result.Nodes.getNodeAs<Stmt>(BindingName))
      ControlFlowInterruptor = BindingName;

  DiagnosticBuilder Diag = diag(ElseLoc, "do not use 'else' after '%0'")
                           << ControlFlowInterruptor;
  Diag << tooling::fixit::createRemoval(ElseLoc);

  // FIXME: Removing the braces isn't always safe. Do a more careful analysis.
  // FIXME: Change clang-format to correctly un-indent the code.
  if (const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("else"))
    Diag << tooling::fixit::createRemoval(CS->getLBracLoc())
         << tooling::fixit::createRemoval(CS->getRBracLoc());
}

} // namespace readability
} // namespace tidy
} // namespace clang
<commit_msg>Convert two more files that were using Windows line endings and remove a stray single '\r' from one file. These are the last line ending issues I can find in the files containing parts of LLVM's file headers.<commit_after>//===--- ElseAfterReturnCheck.cpp - clang-tidy-----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ElseAfterReturnCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {
namespace readability {

void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) {
  const auto ControlFlowInterruptorMatcher =
      stmt(anyOf(returnStmt().bind("return"), continueStmt().bind("continue"),
                 breakStmt().bind("break"),
                 expr(ignoringImplicit(cxxThrowExpr().bind("throw")))));
  Finder->addMatcher(
      compoundStmt(forEach(
          ifStmt(unless(isConstexpr()),
                 hasThen(stmt(
                     anyOf(ControlFlowInterruptorMatcher,
                           compoundStmt(has(ControlFlowInterruptorMatcher))))),
                 hasElse(stmt().bind("else")))
              .bind("if"))),
      this);
}

void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
  SourceLocation ElseLoc = If->getElseLoc();
  std::string ControlFlowInterruptor;
  for (const auto *BindingName : {"return", "continue", "break", "throw"})
    if (Result.Nodes.getNodeAs<Stmt>(BindingName))
      ControlFlowInterruptor = BindingName;

  DiagnosticBuilder Diag = diag(ElseLoc, "do not use 'else' after '%0'")
                           << ControlFlowInterruptor;
  Diag << tooling::fixit::createRemoval(ElseLoc);

  // FIXME: Removing the braces isn't always safe. Do a more careful analysis.
  // FIXME: Change clang-format to correctly un-indent the code.
  if (const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("else"))
    Diag << tooling::fixit::createRemoval(CS->getLBracLoc())
         << tooling::fixit::createRemoval(CS->getRBracLoc());
}

} // namespace readability
} // namespace tidy
} // namespace clang
<|endoftext|>


<commit_before>
#include <iostream>
#include <fmt/ostream.h>
#include <vector>
#include <set>

#include <xl/library_extensions.h>
#include <xl/templates.h>
using xl::templates::ProviderPtr;

#include "../wrapped_class.h"

#include "../helper_functions.h"
#include "bindings_output.h"

using namespace xl::templates;

namespace v8toolkit::class_parser::bindings_output {

extern Template file_template;
extern Template class_template;
extern Template standard_includes_template;

extern std::map<string, Template> bindings_templates;

bool BindingsCriteria::operator()(WrappedClass const & c) {
    log.info(LogSubjects::BindingsOutput, "Checking criteria for {}", c.get_name_alias());
    if (c.bidirectional) {
        log.info(LogSubjects::Subjects::BindingsOutput, "Skipping generation of bindings for {} because it's a bidirectional type", c.get_name_alias());
        return false;
    }

    return true;
}

std::ostream & BindingsOutputStreamProvider::get_class_collection_stream() {
    this->count++;

    log.info(LogSubjects::BindingsOutput, "Starting bindings output file: {}", this->count);

    string class_wrapper_filename = fmt::format("v8toolkit_generated_class_wrapper_{}.cpp", this->count);

    this->output_stream.close();
    this->output_stream.open(class_wrapper_filename);

    return this->output_stream;
}

struct BindingsProviderContainer;

using P = xl::templates::DefaultProviders<BindingsProviderContainer>;

struct BindingsProviderContainer {

    static ProviderPtr get_provider(WrappedClass const & c) {

        log.info(LogSubjects::BindingsOutput, "get_provider WrappedClass: {}", c.get_name_alias());
        auto provider = P::make_provider(
            std::pair("comment", c.comment),
            std::pair("name", c.get_name_alias()),
            std::pair("long_name", c.class_name),
            std::pair("alias", c.get_name_alias()),
            std::pair("data_members", std::ref(c.get_members())),
            std::pair("member_functions", std::ref(c.get_member_functions())),
            std::pair("static_functions", std::ref(c.get_static_functions())),
            std::pair("constructor", c.get_constructors().size() == 0 || c.force_no_constructors ?
                                     fmt::format("class_wrapper.expose_static_methods(\"{}\", isolate);",
                                                 c.get_name_alias()) :
                                     fmt::format(
                                         "class_wrapper.add_constructor<{}>(\"{}\", isolate, {});",
                                         c.get_constructors().back()->get_parameter_types_string(),
                                         c.get_name_alias(), c.get_constructors().back()->get_default_argument_tuple_string())),
            std::pair("base_type_name", c.base_types.empty() ? "" : (*c.base_types.begin())->class_name),

            // convert to string because it may be a bidirectional type.   Full WrappedClass information isn't
            //   available for them.
//            xl::forward_as_pair("derived_types", xl::transform_if(c.derived_types, [](WrappedClass * c)->std::optional<std::string>{return c->get_name_alias();}))
            xl::forward_as_pair("derived_types", xl::transform(c.derived_types, [](WrappedClass * c){return c->class_name;}))
        );

        return provider;
    }

    static ProviderPtr get_provider(DataMember const & d) {
        log.info(LogSubjects::BindingsOutput, "get_provider DataMember: {}", d.long_name);

        return P::make_provider(
            std::pair("comment", d.comment),
            std::pair("name", d.long_name),
            std::pair("js_name", d.js_name),
            std::pair("declared_in", d.declared_in.get_name_alias()),
            std::pair("type", d.type.get_name()),
            std::pair("read_only", d.type.is_const() ? "_readonly" : ""),
            std::pair("member_pointer", fmt::format("&{}", d.long_name))
        );

    }

    static ProviderPtr get_provider(MemberFunction const & f) {
        log.info(LogSubjects::BindingsOutput, "get_provider MemberFunction: {}", f.name);

        return P::make_provider(
            std::pair("js_name", f.js_name),
            std::pair("name", f.name),
            std::pair("comment", f.comment),
            std::pair("binding_parameters", f.get_return_and_class_and_parameter_types_string()),
            std::pair("parameters", P::make_provider(f.parameters)),
            std::pair("return_type_name", f.return_type.get_jsdoc_type_name()),
            std::pair("return_comment", f.return_type_comment),
            std::pair("class_name", f.wrapped_class.get_name_alias()),
            std::pair("default_arg_tuple", f.get_default_argument_tuple_string())
        );
    }

    static ProviderPtr get_provider(StaticFunction const & f) {
        log.info(LogSubjects::BindingsOutput, "get_provider StaticFunction: {}", f.name);

        return P::make_provider(
            std::pair("name", f.name),
            std::pair("js_name", f.js_name),
            std::pair("comment", f.comment),
            std::pair("binding_parameters", f.get_return_and_parameter_types_string()),
            std::pair("parameters", P::make_provider(f.parameters)),
            std::pair("return_type_name", f.return_type.get_jsdoc_type_name()),
            std::pair("return_comment", f.return_type_comment),
            std::pair("class_name", f.wrapped_class.get_name_alias()),
            std::pair("default_arg_tuple", f.get_default_argument_tuple_string())
        );
    }

    static ProviderPtr get_provider(ClassFunction::ParameterInfo const & p) {
        log.info(LogSubjects::BindingsOutput, "get_provider ParameterInfo: {}", p.name);

        return P::make_provider(
            std::pair("type", p.type.get_jsdoc_type_name()),
            std::pair("name", p.name),
            std::pair("comment", p.description)
        );
    }

    static ProviderPtr get_provider(ClassFunction::TypeInfo const & t) {
        return P::make_provider("Implement me");
    }

}; // end BindingsProviderContainer

struct BindingFile {
    size_t max_declaration_count;
    size_t declaration_count = 0;

    BindingFile(size_t max_declaration_count) :
        max_declaration_count(max_declaration_count)
    {}

    /**
     * Whether this binding file can hold the specified WrappedClass
     * @param wrapped_class WrappedClass to see if this BindingFile can hold it
     * @return true if it can be held without exceeding declaration limit, false otherwise
     */
    bool can_hold(WrappedClass const * wrapped_class) {
        return declaration_count == 0 ||
               max_declaration_count == 0 ||
               this->declaration_count + wrapped_class->declaration_count <= max_declaration_count;
    }

    std::vector<WrappedClass const *> classes;

    // this is currently unused - it's not the clear win that it used to be
    std::set<WrappedClass const *> extern_templates;

    std::set<WrappedClass const *> explicit_instantiations;

    std::set<std::string> includes;

    std::vector<WrappedClass const *> const & get_classes() const {return this->classes;}
    auto & get_includes() const {return includes;}
    auto & get_explicit_instantiations()        const { return this->explicit_instantiations; }
    auto & get_extern_template_instantiations() const { return this->extern_templates; }

    void add_class(WrappedClass const * wrapped_class) {
//        std::cerr << fmt::format("adding to BindingFile: {}", wrapped_class->get_name_alias()) << std::endl;
        this->classes.push_back(wrapped_class);
        this->declaration_count += wrapped_class->declaration_count;
        assert(this->declaration_count <= this->max_declaration_count);

        auto base_type_includes = wrapped_class->get_base_type_includes();
        log.info(LogSubjects::Subjects::BindingsOutput, "Adding base type includes: {}", join(base_type_includes));
//        std::cerr << fmt::format("adding base type includes: {}", join(base_type_includes)) << std::endl;
        includes.insert(base_type_includes.begin(), base_type_includes.end());

        auto derived_type_includes = wrapped_class->get_derived_type_includes();
        log.info(LogSubjects::Subjects::BindingsOutput, "Adding base type includes: {}", join(derived_type_includes));
        includes.insert(derived_type_includes.begin(), derived_type_includes.end());

        this->explicit_instantiations.insert(wrapped_class);
    }
};

void BindingsOutputModule::process(std::vector < WrappedClass const*> wrapped_classes)
{
//    std::cerr << fmt::format("file template contents: {}", file_template.c_str()) << std::endl;

//    std::cerr << fmt::format("making bindings output") << std::endl;
//    std::cerr << fmt::format("all binding classes:") << std::endl;
//    for (auto c : wrapped_classes) {
//        std::cerr << fmt::format("{}: {}, derived_types: {}", c->get_short_name(), (void*)c, (void*)&c->derived_types) << std::endl;
//        for(auto d : c->derived_types) {
//            std::cerr << fmt::format(" - derived: {}", (void*)d) << std::endl;
//        }
//    }
    std::vector<BindingFile> binding_files{BindingFile(this->max_declarations_per_file)};

    std::set<WrappedClass const *> already_wrapped_classes;

    // go through all the classes until a full pass has been made with nothing new to be written out
    bool found_match = true;
    while (found_match) {
        found_match = false;

        // go through the list to see if there is anything left to write out
        for (auto & wrapped_class : wrapped_classes) {

            // if it has unmet dependencies or has already been mapped, skip it
            if (!wrapped_class->ready_for_wrapping(already_wrapped_classes)) {
//                std::cerr << fmt::format("Skipping because not ready_for_wrapping: {}", wrapped_class->class_name) << std::endl;
                continue;
            }

            log.info(LogSubjects::BindingsOutput, "Processing class: {}", wrapped_class->get_name_alias());
            already_wrapped_classes.insert(wrapped_class);
            found_match = true;

//            std::cerr << fmt::format("writing class {} to file with declaration_count = {}", wrapped_class->get_name_alias(),
//                                     wrapped_class->declaration_count) << std::endl;

            if (!binding_files.back().can_hold(wrapped_class)) {

                log.info(LogSubjects::BindingsOutput, "Bindings File full, rotating");
                binding_files.emplace_back(this->max_declarations_per_file);
            }

            binding_files.back().add_class(wrapped_class);

            // assert false - this shouldn't alter it
            already_wrapped_classes.insert(wrapped_class);
        }
    }

    if (already_wrapped_classes.size() != wrapped_classes.size()) {
//        cerr << fmt::format("Could not wrap all classes - wrapped {} out of {}",
//                            already_wrapped_classes.size(), wrapped_classes.size()) << endl;
    }

//    std::cerr << fmt::format("about to dump {} binding_files", binding_files.size()) << std::endl;
    for (int i = 0; i < binding_files.size(); i++) {

        auto & binding_file = binding_files[i];
        bool last_file = i == binding_files.size() - 1;
        int file_number = i + 1;

        // this takes care of providing the correct stream for each subsequent call
        auto & output_stream = this->output_stream_provider->get_class_collection_stream();
//        std::cerr << fmt::format("bindings_templates[file] contents: {}", bindings_templates["file"].c_str()) << std::endl;
        auto template_result = bindings_templates["file"].fill<BindingsProviderContainer>(
            P::make_provider(
                std::pair("file_number", fmt::format("{}", file_number)),
                std::pair("next_file_number", fmt::format("{}", file_number + 1)), // ok if it won't actually exist
                std::pair("classes", P::make_provider(binding_file.get_classes())),
                std::pair("includes", P::make_provider(std::bind(&BindingFile::get_includes, binding_file))),
                std::pair("extern_templates", P::make_provider(std::bind(&BindingFile::get_extern_template_instantiations, binding_file))),
                std::pair("explicit_instantiations", binding_file.get_explicit_instantiations()),
                std::pair("call_next_function", !last_file ? fmt::format("v8toolkit_initialize_class_wrappers_{}(isolate);", file_number + 1) : "")
            ),
            &bindings_templates
        );

        log.info(LogSubjects::Subjects::BindingsOutput, "Writing binding file {}", file_number);
        log.info(LogSubjects::Subjects::BindingsOutput, template_result);
        output_stream << template_result << std::flush;
    }

//    cerr << "Classes used that were not wrapped:" << endl;
    for (auto & wrapped_class : wrapped_classes) {
        if (!xl::contains(already_wrapped_classes, wrapped_class)) {
            for (auto used_class : wrapped_class->used_classes) {
                if (already_wrapped_classes.count(used_class) == 0) {
                    log.error(LogSubjects::Class, "Could not dump '{}' because it uses type '{}' that wasn't dumped", wrapped_class->get_name_alias(),
                                        used_class->get_name_alias());
                }
            }
        }
    }
}

string BindingsOutputModule::get_name() {
    return "BindingsOutputModule";
}

OutputCriteria & BindingsOutputModule::get_criteria() {
    return this->criteria;
}

Template class_template(R"({
    v8toolkit::V8ClassWrapper<{{long_name}}> & class_wrapper = isolate.wrap_class<{{long_name}}>();
    class_wrapper.set_class_name("{{alias}}");
{{<<member_functions|!!
    class_wrapper.add_method<{{binding_parameters}}>("{{js_name}}", &{{name}}, {{default_arg_tuple}});>>}}
{{<<static_functions|!!
    class_wrapper.add_static_method<{{binding_parameters}}>("{{js_name}}", &{{name}}, {{default_arg_tuple}});>>}}
{{<<data_members|!!
    class_wrapper.add_member{{read_only}}<{{member_pointer}}>("{{js_name}}");>>}}

    class_wrapper.set_parent_type<{{<<base_type_name>>}}>();

    class_wrapper.set_compatible_types<{{<<derived_types%, |!{{<name>}}>>}}>();

    class_wrapper.finalize(true);
    {{<constructor>}}
})");

Template file_template(R"(
{{!standard_includes}}
// includes
{{<includes|!!
#include {{<include>}}>}}
// /includes

// explicit instantiations
{{<explicit_instantiations|!!
template class v8toolkit::V8ClassWrapper<{{<long_name>}}>;>}}
// /explicit instantiations

{{<extern_templates|!!
extern template {{class_name}}>}}

void v8toolkit_initialize_class_wrappers_{{next_file_number}}(v8toolkit::Isolate &); // may not exist -- that's ok
void v8toolkit_initialize_class_wrappers_{{file_number}}(v8toolkit::Isolate & isolate) {

{{classes|class}}

{{call_next_function}}

}
)");

Template standard_includes_template(R"(
#include "js_casts.h"
#include <v8toolkit/v8_class_wrapper_impl.h>

)");

std::map<string, Template> bindings_templates {
    std::pair("class", class_template),
    std::pair("file", file_template),
    std::pair("standard_includes", standard_includes_template)
};

} // end namespace v8toolkit::class_parser::bindings_output<commit_msg>looks like bidirectional classes DO need to be wrapped<commit_after>
#include <iostream>
#include <fmt/ostream.h>
#include <vector>
#include <set>

#include <xl/library_extensions.h>
#include <xl/templates.h>
using xl::templates::ProviderPtr;

#include "../wrapped_class.h"

#include "../helper_functions.h"
#include "bindings_output.h"

using namespace xl::templates;

namespace v8toolkit::class_parser::bindings_output {

extern Template file_template;
extern Template class_template;
extern Template standard_includes_template;

extern std::map<string, Template> bindings_templates;

bool BindingsCriteria::operator()(WrappedClass const & c) {
    log.info(LogSubjects::BindingsOutput, "Checking criteria for {}", c.get_name_alias());
    // if (c.bidirectional) {
    //     log.info(LogSubjects::Subjects::BindingsOutput, "Skipping generation of bindings for {} because it's a bidirectional type", c.get_name_alias());
    //     return false;
    // }

    return true;
}

std::ostream & BindingsOutputStreamProvider::get_class_collection_stream() {
    this->count++;

    log.info(LogSubjects::BindingsOutput, "Starting bindings output file: {}", this->count);

    string class_wrapper_filename = fmt::format("v8toolkit_generated_class_wrapper_{}.cpp", this->count);

    this->output_stream.close();
    this->output_stream.open(class_wrapper_filename);

    return this->output_stream;
}

struct BindingsProviderContainer;

using P = xl::templates::DefaultProviders<BindingsProviderContainer>;

struct BindingsProviderContainer {

    static ProviderPtr get_provider(WrappedClass const & c) {

        log.info(LogSubjects::BindingsOutput, "get_provider WrappedClass: {}", c.get_name_alias());
        auto provider = P::make_provider(
            std::pair("comment", c.comment),
            std::pair("name", c.get_name_alias()),
            std::pair("long_name", c.class_name),
            std::pair("alias", c.get_name_alias()),
            std::pair("data_members", std::ref(c.get_members())),
            std::pair("member_functions", std::ref(c.get_member_functions())),
            std::pair("static_functions", std::ref(c.get_static_functions())),
            std::pair("constructor", c.get_constructors().size() == 0 || c.force_no_constructors ?
                                     fmt::format("class_wrapper.expose_static_methods(\"{}\", isolate);",
                                                 c.get_name_alias()) :
                                     fmt::format(
                                         "class_wrapper.add_constructor<{}>(\"{}\", isolate, {});",
                                         c.get_constructors().back()->get_parameter_types_string(),
                                         c.get_name_alias(), c.get_constructors().back()->get_default_argument_tuple_string())),
            std::pair("base_type_name", c.base_types.empty() ? "" : (*c.base_types.begin())->class_name),

            // convert to string because it may be a bidirectional type.   Full WrappedClass information isn't
            //   available for them.
//            xl::forward_as_pair("derived_types", xl::transform_if(c.derived_types, [](WrappedClass * c)->std::optional<std::string>{return c->get_name_alias();}))
            xl::forward_as_pair("derived_types", xl::transform(c.derived_types, [](WrappedClass * c){return c->class_name;}))
        );

        return provider;
    }

    static ProviderPtr get_provider(DataMember const & d) {
        log.info(LogSubjects::BindingsOutput, "get_provider DataMember: {}", d.long_name);

        return P::make_provider(
            std::pair("comment", d.comment),
            std::pair("name", d.long_name),
            std::pair("js_name", d.js_name),
            std::pair("declared_in", d.declared_in.get_name_alias()),
            std::pair("type", d.type.get_name()),
            std::pair("read_only", d.type.is_const() ? "_readonly" : ""),
            std::pair("member_pointer", fmt::format("&{}", d.long_name))
        );

    }

    static ProviderPtr get_provider(MemberFunction const & f) {
        log.info(LogSubjects::BindingsOutput, "get_provider MemberFunction: {}", f.name);

        return P::make_provider(
            std::pair("js_name", f.js_name),
            std::pair("name", f.name),
            std::pair("comment", f.comment),
            std::pair("binding_parameters", f.get_return_and_class_and_parameter_types_string()),
            std::pair("parameters", P::make_provider(f.parameters)),
            std::pair("return_type_name", f.return_type.get_jsdoc_type_name()),
            std::pair("return_comment", f.return_type_comment),
            std::pair("class_name", f.wrapped_class.get_name_alias()),
            std::pair("default_arg_tuple", f.get_default_argument_tuple_string())
        );
    }

    static ProviderPtr get_provider(StaticFunction const & f) {
        log.info(LogSubjects::BindingsOutput, "get_provider StaticFunction: {}", f.name);

        return P::make_provider(
            std::pair("name", f.name),
            std::pair("js_name", f.js_name),
            std::pair("comment", f.comment),
            std::pair("binding_parameters", f.get_return_and_parameter_types_string()),
            std::pair("parameters", P::make_provider(f.parameters)),
            std::pair("return_type_name", f.return_type.get_jsdoc_type_name()),
            std::pair("return_comment", f.return_type_comment),
            std::pair("class_name", f.wrapped_class.get_name_alias()),
            std::pair("default_arg_tuple", f.get_default_argument_tuple_string())
        );
    }

    static ProviderPtr get_provider(ClassFunction::ParameterInfo const & p) {
        log.info(LogSubjects::BindingsOutput, "get_provider ParameterInfo: {}", p.name);

        return P::make_provider(
            std::pair("type", p.type.get_jsdoc_type_name()),
            std::pair("name", p.name),
            std::pair("comment", p.description)
        );
    }

    static ProviderPtr get_provider(ClassFunction::TypeInfo const & t) {
        return P::make_provider("Implement me");
    }

}; // end BindingsProviderContainer

struct BindingFile {
    size_t max_declaration_count;
    size_t declaration_count = 0;

    BindingFile(size_t max_declaration_count) :
        max_declaration_count(max_declaration_count)
    {}

    /**
     * Whether this binding file can hold the specified WrappedClass
     * @param wrapped_class WrappedClass to see if this BindingFile can hold it
     * @return true if it can be held without exceeding declaration limit, false otherwise
     */
    bool can_hold(WrappedClass const * wrapped_class) {
        return declaration_count == 0 ||
               max_declaration_count == 0 ||
               this->declaration_count + wrapped_class->declaration_count <= max_declaration_count;
    }

    std::vector<WrappedClass const *> classes;

    // this is currently unused - it's not the clear win that it used to be
    std::set<WrappedClass const *> extern_templates;

    std::set<WrappedClass const *> explicit_instantiations;

    std::set<std::string> includes;

    std::vector<WrappedClass const *> const & get_classes() const {return this->classes;}
    auto & get_includes() const {return includes;}
    auto & get_explicit_instantiations()        const { return this->explicit_instantiations; }
    auto & get_extern_template_instantiations() const { return this->extern_templates; }

    void add_class(WrappedClass const * wrapped_class) {
//        std::cerr << fmt::format("adding to BindingFile: {}", wrapped_class->get_name_alias()) << std::endl;
        this->classes.push_back(wrapped_class);
        this->declaration_count += wrapped_class->declaration_count;
        assert(this->declaration_count <= this->max_declaration_count);

        auto base_type_includes = wrapped_class->get_base_type_includes();
        log.info(LogSubjects::Subjects::BindingsOutput, "Adding base type includes: {}", join(base_type_includes));
//        std::cerr << fmt::format("adding base type includes: {}", join(base_type_includes)) << std::endl;
        includes.insert(base_type_includes.begin(), base_type_includes.end());

        auto derived_type_includes = wrapped_class->get_derived_type_includes();
        log.info(LogSubjects::Subjects::BindingsOutput, "Adding base type includes: {}", join(derived_type_includes));
        includes.insert(derived_type_includes.begin(), derived_type_includes.end());

        this->explicit_instantiations.insert(wrapped_class);
    }
};

void BindingsOutputModule::process(std::vector < WrappedClass const*> wrapped_classes)
{
//    std::cerr << fmt::format("file template contents: {}", file_template.c_str()) << std::endl;

//    std::cerr << fmt::format("making bindings output") << std::endl;
//    std::cerr << fmt::format("all binding classes:") << std::endl;
//    for (auto c : wrapped_classes) {
//        std::cerr << fmt::format("{}: {}, derived_types: {}", c->get_short_name(), (void*)c, (void*)&c->derived_types) << std::endl;
//        for(auto d : c->derived_types) {
//            std::cerr << fmt::format(" - derived: {}", (void*)d) << std::endl;
//        }
//    }
    std::vector<BindingFile> binding_files{BindingFile(this->max_declarations_per_file)};

    std::set<WrappedClass const *> already_wrapped_classes;

    // go through all the classes until a full pass has been made with nothing new to be written out
    bool found_match = true;
    while (found_match) {
        found_match = false;

        // go through the list to see if there is anything left to write out
        for (auto & wrapped_class : wrapped_classes) {

            // if it has unmet dependencies or has already been mapped, skip it
            if (!wrapped_class->ready_for_wrapping(already_wrapped_classes)) {
//                std::cerr << fmt::format("Skipping because not ready_for_wrapping: {}", wrapped_class->class_name) << std::endl;
                continue;
            }

            log.info(LogSubjects::BindingsOutput, "Processing class: {}", wrapped_class->get_name_alias());
            already_wrapped_classes.insert(wrapped_class);
            found_match = true;

//            std::cerr << fmt::format("writing class {} to file with declaration_count = {}", wrapped_class->get_name_alias(),
//                                     wrapped_class->declaration_count) << std::endl;

            if (!binding_files.back().can_hold(wrapped_class)) {

                log.info(LogSubjects::BindingsOutput, "Bindings File full, rotating");
                binding_files.emplace_back(this->max_declarations_per_file);
            }

            binding_files.back().add_class(wrapped_class);

            // assert false - this shouldn't alter it
            already_wrapped_classes.insert(wrapped_class);
        }
    }

    if (already_wrapped_classes.size() != wrapped_classes.size()) {
//        cerr << fmt::format("Could not wrap all classes - wrapped {} out of {}",
//                            already_wrapped_classes.size(), wrapped_classes.size()) << endl;
    }

//    std::cerr << fmt::format("about to dump {} binding_files", binding_files.size()) << std::endl;
    for (int i = 0; i < binding_files.size(); i++) {

        auto & binding_file = binding_files[i];
        bool last_file = i == binding_files.size() - 1;
        int file_number = i + 1;

        // this takes care of providing the correct stream for each subsequent call
        auto & output_stream = this->output_stream_provider->get_class_collection_stream();
//        std::cerr << fmt::format("bindings_templates[file] contents: {}", bindings_templates["file"].c_str()) << std::endl;
        auto template_result = bindings_templates["file"].fill<BindingsProviderContainer>(
            P::make_provider(
                std::pair("file_number", fmt::format("{}", file_number)),
                std::pair("next_file_number", fmt::format("{}", file_number + 1)), // ok if it won't actually exist
                std::pair("classes", P::make_provider(binding_file.get_classes())),
                std::pair("includes", P::make_provider(std::bind(&BindingFile::get_includes, binding_file))),
                std::pair("extern_templates", P::make_provider(std::bind(&BindingFile::get_extern_template_instantiations, binding_file))),
                std::pair("explicit_instantiations", binding_file.get_explicit_instantiations()),
                std::pair("call_next_function", !last_file ? fmt::format("v8toolkit_initialize_class_wrappers_{}(isolate);", file_number + 1) : "")
            ),
            &bindings_templates
        );

        log.info(LogSubjects::Subjects::BindingsOutput, "Writing binding file {}", file_number);
        log.info(LogSubjects::Subjects::BindingsOutput, template_result);
        output_stream << template_result << std::flush;
    }

//    cerr << "Classes used that were not wrapped:" << endl;
    for (auto & wrapped_class : wrapped_classes) {
        if (!xl::contains(already_wrapped_classes, wrapped_class)) {
            for (auto used_class : wrapped_class->used_classes) {
                if (already_wrapped_classes.count(used_class) == 0) {
                    log.error(LogSubjects::Class, "Could not dump '{}' because it uses type '{}' that wasn't dumped", wrapped_class->get_name_alias(),
                                        used_class->get_name_alias());
                }
            }
        }
    }
}

string BindingsOutputModule::get_name() {
    return "BindingsOutputModule";
}

OutputCriteria & BindingsOutputModule::get_criteria() {
    return this->criteria;
}

Template class_template(R"({
    v8toolkit::V8ClassWrapper<{{long_name}}> & class_wrapper = isolate.wrap_class<{{long_name}}>();
    class_wrapper.set_class_name("{{alias}}");
{{<<member_functions|!!
    class_wrapper.add_method<{{binding_parameters}}>("{{js_name}}", &{{name}}, {{default_arg_tuple}});>>}}
{{<<static_functions|!!
    class_wrapper.add_static_method<{{binding_parameters}}>("{{js_name}}", &{{name}}, {{default_arg_tuple}});>>}}
{{<<data_members|!!
    class_wrapper.add_member{{read_only}}<{{member_pointer}}>("{{js_name}}");>>}}

    class_wrapper.set_parent_type<{{<<base_type_name>>}}>();

    class_wrapper.set_compatible_types<{{<<derived_types%, |!{{<name>}}>>}}>();

    class_wrapper.finalize(true);
    {{<constructor>}}
})");

Template file_template(R"(
{{!standard_includes}}
// includes
{{<includes|!!
#include {{<include>}}>}}
// /includes

// explicit instantiations
{{<explicit_instantiations|!!
template class v8toolkit::V8ClassWrapper<{{<long_name>}}>;>}}
// /explicit instantiations

{{<extern_templates|!!
extern template {{class_name}}>}}

void v8toolkit_initialize_class_wrappers_{{next_file_number}}(v8toolkit::Isolate &); // may not exist -- that's ok
void v8toolkit_initialize_class_wrappers_{{file_number}}(v8toolkit::Isolate & isolate) {

{{classes|class}}

{{call_next_function}}

}
)");

Template standard_includes_template(R"(
#include "js_casts.h"
#include <v8toolkit/v8_class_wrapper_impl.h>

)");

std::map<string, Template> bindings_templates {
    std::pair("class", class_template),
    std::pair("file", file_template),
    std::pair("standard_includes", standard_includes_template)
};

} // end namespace v8toolkit::class_parser::bindings_output<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012-2013 Red Hat, Inc.
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <check.h>
#include <stdio.h>

#include "libdnf/dnf-types.h"
#include "libdnf/hy-util.h"
#include "test_suites.h"

START_TEST(test_detect_arch)
{
    char *arch;
    int ret = hy_detect_arch(&arch);
    int len = strlen(arch);
    ck_assert_int_gt(len, 0);
    ck_assert_int_eq(ret, 0);
    g_free(arch);
}
END_TEST

START_TEST(test_split_nevra)
{
    int ret;
    int epoch;
    char *name, *version, *release, *arch;

    const char *n = "meanwhile3.34.3-3:3.34-3.fc666.i686";
    fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
    ck_assert_str_eq(name, "meanwhile3.34.3");
    fail_unless(epoch == 3);
    ck_assert_str_eq(version, "3.34");
    ck_assert_str_eq(release, "3.fc666");
    ck_assert_str_eq(arch, "i686");
    g_free(name);
    g_free(version);
    g_free(release);
    g_free(arch);

    n = "python-meanwhile3.34.3-3:3.34-3.fc666.noarch";
    fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
    ck_assert_str_eq(name, "python-meanwhile3.34.3");
    fail_unless(epoch == 3);
    ck_assert_str_eq(version, "3.34");
    ck_assert_str_eq(release, "3.fc666");
    ck_assert_str_eq(arch, "noarch");
    g_free(name);
    g_free(version);
    g_free(release);
    g_free(arch);

    n = "easy-1.2.3-4.fc18.x86_64";
    hy_split_nevra(n, &name, &epoch, &version, &release, &arch);
    ck_assert_str_eq(name, "easy");
    fail_unless(epoch == 0);
    ck_assert_str_eq(version, "1.2.3");
    ck_assert_str_eq(release, "4.fc18");
    ck_assert_str_eq(arch, "x86_64");
    g_free(name);
    g_free(version);
    g_free(release);
    g_free(arch);

    n = "no.go";
    ret = hy_split_nevra(n, &name, &epoch, &version, &release, &arch);
    fail_unless(ret == DNF_ERROR_INTERNAL_ERROR);
}
END_TEST

Suite *
util_suite(void)
{
    Suite *s = suite_create("util");
    TCase *tc = tcase_create("Main");
    tcase_add_test(tc, test_detect_arch);
    tcase_add_test(tc, test_split_nevra);
    suite_add_tcase(s, tc);

    return s;
}
<commit_msg>Fix: Mising check of "hy_split_nevra()" return code<commit_after>/*
 * Copyright (C) 2012-2013 Red Hat, Inc.
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <check.h>
#include <stdio.h>

#include "libdnf/dnf-types.h"
#include "libdnf/hy-util.h"
#include "test_suites.h"

START_TEST(test_detect_arch)
{
    char *arch;
    int ret = hy_detect_arch(&arch);
    int len = strlen(arch);
    ck_assert_int_gt(len, 0);
    ck_assert_int_eq(ret, 0);
    g_free(arch);
}
END_TEST

START_TEST(test_split_nevra)
{
    int ret;
    int epoch;
    char *name, *version, *release, *arch;

    const char *n = "meanwhile3.34.3-3:3.34-3.fc666.i686";
    fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
    ck_assert_str_eq(name, "meanwhile3.34.3");
    fail_unless(epoch == 3);
    ck_assert_str_eq(version, "3.34");
    ck_assert_str_eq(release, "3.fc666");
    ck_assert_str_eq(arch, "i686");
    g_free(name);
    g_free(version);
    g_free(release);
    g_free(arch);

    n = "python-meanwhile3.34.3-3:3.34-3.fc666.noarch";
    fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
    ck_assert_str_eq(name, "python-meanwhile3.34.3");
    fail_unless(epoch == 3);
    ck_assert_str_eq(version, "3.34");
    ck_assert_str_eq(release, "3.fc666");
    ck_assert_str_eq(arch, "noarch");
    g_free(name);
    g_free(version);
    g_free(release);
    g_free(arch);

    n = "easy-1.2.3-4.fc18.x86_64";
    fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
    ck_assert_str_eq(name, "easy");
    fail_unless(epoch == 0);
    ck_assert_str_eq(version, "1.2.3");
    ck_assert_str_eq(release, "4.fc18");
    ck_assert_str_eq(arch, "x86_64");
    g_free(name);
    g_free(version);
    g_free(release);
    g_free(arch);

    n = "no.go";
    ret = hy_split_nevra(n, &name, &epoch, &version, &release, &arch);
    fail_unless(ret == DNF_ERROR_INTERNAL_ERROR);
}
END_TEST

Suite *
util_suite(void)
{
    Suite *s = suite_create("util");
    TCase *tc = tcase_create("Main");
    tcase_add_test(tc, test_detect_arch);
    tcase_add_test(tc, test_split_nevra);
    suite_add_tcase(s, tc);

    return s;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Tobias Leibner

#ifndef DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH
#define DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH

#include <utility>

#include <dune/gdt/operators/interfaces.hh>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/common/string.hh>
#include <dune/stuff/la/container.hh>

#include "interface.hh"

namespace Dune {
namespace GDT {
namespace TimeStepper {

/**
 * Takes two time steppers and performs a simple fractional step scheme (see e.g. LeVeque, "Finite Volume Methods for
 * Hyperbolic Problems", 2002, Section 17.1. In each time step t, the first stepper is applied up to time t+dt and the
 * result is taken as input for the second time stepper, which is also applied up to time t+dt. Initial values and time
 * are taken from the first time stepper.
 */
template <class FirstStepperImp, class SecondStepperImp>
class FractionalStep : public TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType,
                                                   typename FirstStepperImp::TimeFieldType>
{
  typedef TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType, typename FirstStepperImp::TimeFieldType>
      BaseType;

public:
  using typename BaseType::DiscreteFunctionType;
  using typename BaseType::TimeFieldType;
  using typename BaseType::DomainFieldType;
  using typename BaseType::RangeFieldType;
  using typename BaseType::SolutionType;

  typedef FirstStepperImp FirstStepperType;
  typedef SecondStepperImp SecondStepperType;

  using BaseType::current_solution;
  using BaseType::current_time;
  using BaseType::solution;

  FractionalStep(FirstStepperType& first_stepper, SecondStepperType& second_stepper)
    : BaseType(first_stepper.current_time(), first_stepper.current_solution())
    , first_stepper_(first_stepper)
    , second_stepper_(second_stepper)
  {
    first_stepper_.set_current_solution_pointer(current_solution());
    first_stepper_.set_solution_pointer(solution());
    second_stepper_.set_current_solution_pointer(current_solution());
    second_stepper_.set_solution_pointer(solution());
  } // constructor

  TimeFieldType step(const TimeFieldType dt, const TimeFieldType max_dt) override final
  {
    auto& t                       = current_time();
    const TimeFieldType actual_dt = std::min(dt, max_dt);
    const auto dt_1               = first_stepper_.solve(t + actual_dt, dt, -1, false);
    const auto dt_2               = second_stepper_.solve(t + actual_dt, dt, -1, false);
    t += actual_dt;
    return std::min(dt_1, dt_2);
  } // ... step(...)

private:
  FirstStepperType& first_stepper_;
  SecondStepperType& second_stepper_;
}; // class FractionalStep

} // namespace TimeStepper
} // namespace Stuff
} // namespace Dune

#endif // DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH
<commit_msg>[timestepper.fractionalstep] change returned time step length<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Tobias Leibner

#ifndef DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH
#define DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH

#include <utility>

#include <dune/gdt/operators/interfaces.hh>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/common/string.hh>
#include <dune/stuff/la/container.hh>

#include "interface.hh"

namespace Dune {
namespace GDT {
namespace TimeStepper {

/**
 * Takes two time steppers and performs a simple fractional step scheme (see e.g. LeVeque, "Finite Volume Methods for
 * Hyperbolic Problems", 2002, Section 17.1. In each time step t, the first stepper is applied up to time t+dt and the
 * result is taken as input for the second time stepper, which is also applied up to time t+dt. Initial values and time
 * are taken from the first time stepper.
 */
template <class FirstStepperImp, class SecondStepperImp>
class FractionalStep : public TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType,
                                                   typename FirstStepperImp::TimeFieldType>
{
  typedef TimeStepperInterface<typename FirstStepperImp::DiscreteFunctionType, typename FirstStepperImp::TimeFieldType>
      BaseType;

public:
  using typename BaseType::DiscreteFunctionType;
  using typename BaseType::TimeFieldType;
  using typename BaseType::DomainFieldType;
  using typename BaseType::RangeFieldType;
  using typename BaseType::SolutionType;

  typedef FirstStepperImp FirstStepperType;
  typedef SecondStepperImp SecondStepperType;

  using BaseType::current_solution;
  using BaseType::current_time;
  using BaseType::solution;

  FractionalStep(FirstStepperType& first_stepper, SecondStepperType& second_stepper)
    : BaseType(first_stepper.current_time(), first_stepper.current_solution())
    , first_stepper_(first_stepper)
    , second_stepper_(second_stepper)
  {
    first_stepper_.set_current_solution_pointer(current_solution());
    first_stepper_.set_solution_pointer(solution());
    second_stepper_.set_current_solution_pointer(current_solution());
    second_stepper_.set_solution_pointer(solution());
  } // constructor

  TimeFieldType step(const TimeFieldType dt, const TimeFieldType max_dt) override final
  {
    auto& t                       = current_time();
    const TimeFieldType actual_dt = std::min(dt, max_dt);
    const auto dt_1               = first_stepper_.solve(t + actual_dt, dt, -1, false);
    const auto dt_2               = second_stepper_.solve(t + actual_dt, dt_1, -1, false);
    t += actual_dt;
    return dt_2;
  } // ... step(...)

private:
  FirstStepperType& first_stepper_;
  SecondStepperType& second_stepper_;
}; // class FractionalStep

} // namespace TimeStepper
} // namespace Stuff
} // namespace Dune

#endif // DUNE_GDT_TIMESTEPPER_FRACTIONAL_STEP_HH
<|endoftext|>


<commit_before>#include <vector>
#include <sstream>

#include <glow/Program.h>
#include <glow/logging.h>
#include <glow/StringSource.h>
#include <glow/String.h>
#include <glow/Error.h>
#include <glow/ObjectVisitor.h>
#include <glow/Version.h>

#include <glow/Shader.h>

#include <glow/ref_ptr.h>

#include "IncludeProcessor.h"

namespace
{

std::vector<const char*> collectCStrings(std::vector<std::string> & strings)
{
    std::vector<const char*> cStrings;

    for (const std::string & str : strings)
    {
        cStrings.push_back(str.c_str());
    }

    return cStrings;
}

}

namespace glow
{

Shader::Shader(const GLenum type, StringSource * source)
: Object(create(type))
, m_type(type)
, m_source(nullptr)
, m_compiled(false)
, m_compilationFailed(false)
{
	if (source)
		setSource(source);
}

Shader::Shader(const GLenum type, StringSource * source, const std::vector<std::string> & includePaths)
: Shader(type, source)
{
    setIncludePaths(includePaths);
}

Shader::Shader(const GLenum type)
: Shader(type, nullptr)
{
}

Shader * Shader::fromString(const GLenum type, const std::string & sourceString)
{
    return new Shader(type, new String(sourceString));
}

Shader::~Shader()
{
	if (m_source)
	{
		m_source->deregisterListener(this);
	}

	if (ownsGLObject())
	{
		glDeleteShader(m_id);
		CheckGLError();
	}
}

GLuint Shader::create(GLenum type)
{
	GLuint result = glCreateShader(type);
	CheckGLError();
	return result;
}

void Shader::accept(ObjectVisitor& visitor)
{
	visitor.visitShader(this);
}

GLenum Shader::type() const
{
	return m_type;
}

void Shader::setSource(StringSource * source)
{
    if (source == m_source)
        return;

	if (m_source)
		m_source->deregisterListener(this);

	m_source = source;

	if (m_source)
		m_source->registerListener(this);

	updateSource();
}

void Shader::setSource(const std::string & source)
{
    setSource(new String(source));
}

const StringSource* Shader::source() const
{
	return m_source;
}

void Shader::notifyChanged()
{
	updateSource();
}

void Shader::updateSource()
{
    if (m_source)
    {
        std::vector<std::string> sources;

        if (!GLEW_ARB_shading_language_include || Version::current() < Version(3, 2)) // fallback
        {
            ref_ptr<StringSource> resolvedSource = IncludeProcessor::resolveIncludes(m_source, m_includePaths);

            sources = resolvedSource->strings();
        }
        else
        {
            sources = m_source->strings();
        }

        std::vector<const char*> cStrings = collectCStrings(sources);

        glShaderSource(m_id, static_cast<GLint>(cStrings.size()), cStrings.data(), nullptr);
    }
    else
    {
        glShaderSource(m_id, 0, nullptr, nullptr);
    }

    invalidate();
}

void Shader::setIncludePaths(const std::vector<std::string> & includePaths)
{
    m_includePaths = includePaths;

    invalidate();
}

bool Shader::compile()
{
    if (m_compilationFailed)
        return false;

    if (glCompileShaderIncludeARB && Version::current() >= Version(3, 2))
    {
        std::vector<const char*> cStrings = collectCStrings(m_includePaths);
        glCompileShaderIncludeARB(m_id, static_cast<GLint>(cStrings.size()), cStrings.data(), nullptr);
        CheckGLError();
    }
    else
    {
        glCompileShader(m_id);
        CheckGLError();
    }

    m_compiled = checkCompileStatus();

    m_compilationFailed = !m_compiled;

    changed();

    return m_compiled;
}

bool Shader::isCompiled() const
{
	return m_compiled;
}

void Shader::invalidate()
{
    m_compiled = false;
    m_compilationFailed = false;
    changed();
}

GLint Shader::get(GLenum pname) const
{
    GLint value = 0;
    glGetShaderiv(m_id, pname, &value);
    CheckGLError();

    return value;
}

bool Shader::checkCompileStatus() const
{
    GLint status = get(GL_COMPILE_STATUS);

    if (GL_FALSE == status)
    {
        critical()
            << "Compiler error:" << std::endl
            << shaderString() << std::endl
            << infoLog();

        return false;
    }

    return true;
}

std::string Shader::infoLog() const
{
    GLsizei length = get(GL_INFO_LOG_LENGTH);
	std::vector<char> log(length);

	glGetShaderInfoLog(m_id, length, &length, log.data());
	CheckGLError();

	return std::string(log.data(), length);
}

std::string Shader::shaderString() const
{
	std::stringstream ss;

	ss << "Shader(" << typeString();

    std::string shortInfo = m_source->shortInfo();
    if (shortInfo.size() > 0)
        ss << ", " << shortInfo;

	ss << ")";

	return ss.str();
}

std::string Shader::typeString() const
{
	switch (m_type)
	{
	case GL_GEOMETRY_SHADER:
		return "GL_GEOMETRY_SHADER";
	case GL_FRAGMENT_SHADER:
		return "GL_FRAGMENT_SHADER";
	case GL_VERTEX_SHADER:
		return "GL_VERTEX_SHADER";
	case GL_TESS_EVALUATION_SHADER:
		return "GL_TESS_EVALUATION_SHADER";
	case GL_TESS_CONTROL_SHADER:
		return "GL_TESS_CONTROL_SHADER";
	case GL_COMPUTE_SHADER:
		return "GL_COMPUTE_SHADER";
	default:
		return "Unknown Shader Type";
	}
}

} // namespace glow
<commit_msg>Fix for Shader<commit_after>#include <vector>
#include <sstream>

#include <glow/Program.h>
#include <glow/logging.h>
#include <glow/StringSource.h>
#include <glow/String.h>
#include <glow/Error.h>
#include <glow/ObjectVisitor.h>
#include <glow/Version.h>

#include <glow/Shader.h>

#include <glow/ref_ptr.h>

#include "IncludeProcessor.h"

namespace
{

std::vector<const char*> collectCStrings(std::vector<std::string> & strings)
{
    std::vector<const char*> cStrings;

    for (const std::string & str : strings)
    {
        cStrings.push_back(str.c_str());
    }

    return cStrings;
}

}

namespace glow
{

Shader::Shader(const GLenum type, StringSource * source)
: Object(create(type))
, m_type(type)
, m_source(nullptr)
, m_compiled(false)
, m_compilationFailed(false)
{
	if (source)
		setSource(source);
}

Shader::Shader(const GLenum type, StringSource * source, const std::vector<std::string> & includePaths)
: Shader(type, source)
{
    setIncludePaths(includePaths);
}

Shader::Shader(const GLenum type)
: Shader(type, nullptr)
{
}

Shader * Shader::fromString(const GLenum type, const std::string & sourceString)
{
    return new Shader(type, new String(sourceString));
}

Shader::~Shader()
{
	if (m_source)
	{
		m_source->deregisterListener(this);
	}

	if (ownsGLObject())
	{
		glDeleteShader(m_id);
		CheckGLError();
	}
}

GLuint Shader::create(GLenum type)
{
	GLuint result = glCreateShader(type);
	CheckGLError();
	return result;
}

void Shader::accept(ObjectVisitor& visitor)
{
	visitor.visitShader(this);
}

GLenum Shader::type() const
{
	return m_type;
}

void Shader::setSource(StringSource * source)
{
    if (source == m_source)
        return;

	if (m_source)
		m_source->deregisterListener(this);

	m_source = source;

	if (m_source)
		m_source->registerListener(this);

	updateSource();
}

void Shader::setSource(const std::string & source)
{
    setSource(new String(source));
}

const StringSource* Shader::source() const
{
	return m_source;
}

void Shader::notifyChanged()
{
	updateSource();
}

void Shader::updateSource()
{
    std::vector<std::string> sources;

    if (m_source)
    {
        if (!GLEW_ARB_shading_language_include || Version::current() < Version(3, 2)) // fallback
        {
            ref_ptr<StringSource> resolvedSource = IncludeProcessor::resolveIncludes(m_source, m_includePaths);

            sources = resolvedSource->strings();
        }
        else
        {
            sources = m_source->strings();
        }
    }

    std::vector<const char*> cStrings = collectCStrings(sources);

    glShaderSource(m_id, static_cast<GLint>(cStrings.size()), cStrings.data(), nullptr);
    CheckGLError();

    invalidate();
}

void Shader::setIncludePaths(const std::vector<std::string> & includePaths)
{
    m_includePaths = includePaths;

    invalidate();
}

bool Shader::compile()
{
    if (m_compilationFailed)
        return false;

    if (GLEW_ARB_shading_language_include && glCompileShaderIncludeARB && Version::current() >= Version(4, 0))
    {
        std::vector<const char*> cStrings = collectCStrings(m_includePaths);
        glCompileShaderIncludeARB(m_id, static_cast<GLint>(cStrings.size()), cStrings.data(), nullptr);
        CheckGLError();
    }
    else
    {
        glCompileShader(m_id);
        CheckGLError();
    }

    m_compiled = checkCompileStatus();

    m_compilationFailed = !m_compiled;

    changed();

    return m_compiled;
}

bool Shader::isCompiled() const
{
	return m_compiled;
}

void Shader::invalidate()
{
    m_compiled = false;
    m_compilationFailed = false;
    changed();
}

GLint Shader::get(GLenum pname) const
{
    GLint value = 0;
    glGetShaderiv(m_id, pname, &value);
    CheckGLError();

    return value;
}

bool Shader::checkCompileStatus() const
{
    GLint status = get(GL_COMPILE_STATUS);

    if (GL_FALSE == status)
    {
        critical()
            << "Compiler error:" << std::endl
            << shaderString() << std::endl
            << infoLog();

        return false;
    }

    return true;
}

std::string Shader::infoLog() const
{
    GLsizei length = get(GL_INFO_LOG_LENGTH);
	std::vector<char> log(length);

	glGetShaderInfoLog(m_id, length, &length, log.data());
	CheckGLError();

	return std::string(log.data(), length);
}

std::string Shader::shaderString() const
{
	std::stringstream ss;

	ss << "Shader(" << typeString();

    std::string shortInfo = m_source->shortInfo();
    if (shortInfo.size() > 0)
        ss << ", " << shortInfo;

	ss << ")";

	return ss.str();
}

std::string Shader::typeString() const
{
	switch (m_type)
	{
	case GL_GEOMETRY_SHADER:
		return "GL_GEOMETRY_SHADER";
	case GL_FRAGMENT_SHADER:
		return "GL_FRAGMENT_SHADER";
	case GL_VERTEX_SHADER:
		return "GL_VERTEX_SHADER";
	case GL_TESS_EVALUATION_SHADER:
		return "GL_TESS_EVALUATION_SHADER";
	case GL_TESS_CONTROL_SHADER:
		return "GL_TESS_CONTROL_SHADER";
	case GL_COMPUTE_SHADER:
		return "GL_COMPUTE_SHADER";
	default:
		return "Unknown Shader Type";
	}
}

} // namespace glow
<|endoftext|>