<commit_before>#include "propagation.h"
#include <lightstep_carrier.pb.h>
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <ios>
#include <sstream>

namespace lightstep {
#define PREFIX_TRACER_STATE "ot-tracer-"
// Note: these constants are a convention of the OpenTracing basictracers.
const opentracing::string_view PrefixBaggage = "ot-baggage-";

const int FieldCount = 3;
const opentracing::string_view FieldNameTraceID = PREFIX_TRACER_STATE "traceid";
const opentracing::string_view FieldNameSpanID = PREFIX_TRACER_STATE "spanid";
const opentracing::string_view FieldNameSampled = PREFIX_TRACER_STATE "sampled";
#undef PREFIX_TRACER_STATE

//------------------------------------------------------------------------------
// Uint64ToHex
//------------------------------------------------------------------------------
static std::string Uint64ToHex(uint64_t u) {
  std::stringstream ss;
  ss << std::setfill('0') << std::setw(16) << std::hex << u;
  return ss.str();
}

//------------------------------------------------------------------------------
// HexToUint64
//------------------------------------------------------------------------------
static uint64_t HexToUint64(const std::string& s) {
  std::stringstream ss(s);
  uint64_t x;
  ss >> std::setw(16) >> std::hex >> x;
  return x;
}

//------------------------------------------------------------------------------
// InjectSpanContext
//------------------------------------------------------------------------------
static opentracing::expected<void> InjectSpanContext(
    BinaryCarrier& carrier, uint64_t trace_id, uint64_t span_id,
    const std::unordered_map<std::string, std::string>& baggage) noexcept try {
  carrier.Clear();
  auto basic = carrier.mutable_basic_ctx();
  basic->set_trace_id(trace_id);
  basic->set_span_id(span_id);
  basic->set_sampled(true);
  auto mutable_baggage = basic->mutable_baggage_items();
  for (auto& baggage_item : baggage) {
    (*mutable_baggage)[baggage_item.first] = baggage_item.second;
  }
  return {};
} catch (const std::bad_alloc&) {
  return opentracing::make_unexpected(
      std::make_error_code(std::errc::not_enough_memory));
}

opentracing::expected<void> InjectSpanContext(
    std::ostream& carrier, uint64_t trace_id, uint64_t span_id,
    const std::unordered_map<std::string, std::string>& baggage) {
  BinaryCarrier binary_carrier;
  auto result = InjectSpanContext(binary_carrier, trace_id, span_id, baggage);
  if (!result) {
    return result;
  }
  if (!binary_carrier.SerializeToOstream(&carrier)) {
    return opentracing::make_unexpected(
        std::make_error_code(std::io_errc::stream));
  }

  // Flush so that when we call carrier.good, we'll get an accurate view of the
  // error state.
  carrier.flush();
  if (!carrier.good()) {
    return opentracing::make_unexpected(
        std::make_error_code(std::io_errc::stream));
  }

  return {};
}

opentracing::expected<void> InjectSpanContext(
    const opentracing::TextMapWriter& carrier, uint64_t trace_id,
    uint64_t span_id,
    const std::unordered_map<std::string, std::string>& baggage) {
  std::string trace_id_hex, span_id_hex, baggage_key;
  try {
    trace_id_hex = Uint64ToHex(trace_id);
    span_id_hex = Uint64ToHex(span_id);
    baggage_key = PrefixBaggage;
  } catch (const std::bad_alloc&) {
    return opentracing::make_unexpected(
        std::make_error_code(std::errc::not_enough_memory));
  }
  auto result = carrier.Set(FieldNameTraceID, trace_id_hex);
  if (!result) {
    return result;
  }
  result = carrier.Set(FieldNameSpanID, span_id_hex);
  if (!result) {
    return result;
  }
  result = carrier.Set(FieldNameSampled, "true");
  if (!result) {
    return result;
  }
  for (const auto& baggage_item : baggage) {
    try {
      baggage_key.replace(std::begin(baggage_key) + PrefixBaggage.size(),
                          std::end(baggage_key), baggage_item.first);
    } catch (const std::bad_alloc&) {
      return opentracing::make_unexpected(
          std::make_error_code(std::errc::not_enough_memory));
    }
    result = carrier.Set(baggage_key, baggage_item.second);
    if (!result) {
      return result;
    }
  }
  return {};
}

//------------------------------------------------------------------------------
// ExtractSpanContext
//------------------------------------------------------------------------------
static opentracing::expected<bool> ExtractSpanContext(
    const BinaryCarrier& carrier, uint64_t& trace_id, uint64_t& span_id,
    std::unordered_map<std::string, std::string>& baggage) noexcept try {
  auto& basic = carrier.basic_ctx();
  trace_id = basic.trace_id();
  span_id = basic.span_id();
  for (const auto& entry : basic.baggage_items()) {
    baggage.emplace(entry.first, entry.second);
  }
  return true;
} catch (const std::bad_alloc&) {
  return opentracing::make_unexpected(
      std::make_error_code(std::errc::not_enough_memory));
}

opentracing::expected<bool> ExtractSpanContext(
    std::istream& carrier, uint64_t& trace_id, uint64_t& span_id,
    std::unordered_map<std::string, std::string>& baggage) try {
  // istream::peek returns EOF if it's in an error state, so check for an error
  // state first before checking for an empty stream.
  if (!carrier.good()) {
    return opentracing::make_unexpected(
        std::make_error_code(std::io_errc::stream));
  }

  // Check for the case when no span is encoded.
  if (carrier.peek() == EOF) {
    return false;
  }

  BinaryCarrier binary_carrier;
  if (!binary_carrier.ParseFromIstream(&carrier)) {
    return false;
  }
  return ExtractSpanContext(binary_carrier, trace_id, span_id, baggage);
} catch (const std::bad_alloc&) {
  return opentracing::make_unexpected(
      std::make_error_code(std::errc::not_enough_memory));
}

template <class KeyCompare>
static opentracing::expected<bool> ExtractSpanContext(
    const opentracing::TextMapReader& carrier, uint64_t& trace_id,
    uint64_t& span_id, std::unordered_map<std::string, std::string>& baggage,
    KeyCompare key_compare) {
  int count = 0;
  auto result = carrier.ForeachKey(
      [&](opentracing::string_view key,
          opentracing::string_view value) -> opentracing::expected<void> {
        try {
          if (key_compare(key, FieldNameTraceID)) {
            trace_id = HexToUint64(value);
            count++;
          } else if (key_compare(key, FieldNameSpanID)) {
            span_id = HexToUint64(value);
            count++;
          } else if (key_compare(key, FieldNameSampled)) {
            // Ignored
            count++;
          } else if (key.length() > PrefixBaggage.size() &&
                     key_compare(opentracing::string_view{key.data(),
                                                          PrefixBaggage.size()},
                                 PrefixBaggage)) {
            baggage.emplace(std::string{std::begin(key) + PrefixBaggage.size(),
                                        std::end(key)},
                            value);
          }
          return {};
        } catch (const std::bad_alloc&) {
          return opentracing::make_unexpected(
              std::make_error_code(std::errc::not_enough_memory));
        }
      });
  if (!result) {
    return opentracing::make_unexpected(result.error());
  }
  if (count == 0) {
    return false;
  }
  if (count > 0 && count != FieldCount) {
    return opentracing::make_unexpected(
        opentracing::span_context_corrupted_error);
  }
  return true;
}

opentracing::expected<bool> ExtractSpanContext(
    const opentracing::TextMapReader& carrier, uint64_t& trace_id,
    uint64_t& span_id, std::unordered_map<std::string, std::string>& baggage) {
  return ExtractSpanContext(carrier, trace_id, span_id, baggage,
                            std::equal_to<opentracing::string_view>());
}

// HTTP header field names are case insensitive, so we need to ignore case when
// comparing against the OpenTracing field names.
//
// See https://stackoverflow.com/a/5259004/4447365
opentracing::expected<bool> ExtractSpanContext(
    const opentracing::HTTPHeadersReader& carrier, uint64_t& trace_id,
    uint64_t& span_id, std::unordered_map<std::string, std::string>& baggage) {
  auto iequals = [](opentracing::string_view lhs,
                    opentracing::string_view rhs) {
    return lhs.length() == rhs.length() &&
           std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs),
                      [](char a, char b) {
                        return std::tolower(a) == std::tolower(b);
                      });
  };
  return ExtractSpanContext(carrier, trace_id, span_id, baggage, iequals);
}
}  // namespace lightstep
<commit_msg>s/std::io_errc::stream/std::errc::io_error/<commit_after>#include "propagation.h"
#include <lightstep_carrier.pb.h>
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <ios>
#include <sstream>

namespace lightstep {
#define PREFIX_TRACER_STATE "ot-tracer-"
// Note: these constants are a convention of the OpenTracing basictracers.
const opentracing::string_view PrefixBaggage = "ot-baggage-";

const int FieldCount = 3;
const opentracing::string_view FieldNameTraceID = PREFIX_TRACER_STATE "traceid";
const opentracing::string_view FieldNameSpanID = PREFIX_TRACER_STATE "spanid";
const opentracing::string_view FieldNameSampled = PREFIX_TRACER_STATE "sampled";
#undef PREFIX_TRACER_STATE

//------------------------------------------------------------------------------
// Uint64ToHex
//------------------------------------------------------------------------------
static std::string Uint64ToHex(uint64_t u) {
  std::stringstream ss;
  ss << std::setfill('0') << std::setw(16) << std::hex << u;
  return ss.str();
}

//------------------------------------------------------------------------------
// HexToUint64
//------------------------------------------------------------------------------
static uint64_t HexToUint64(const std::string& s) {
  std::stringstream ss(s);
  uint64_t x;
  ss >> std::setw(16) >> std::hex >> x;
  return x;
}

//------------------------------------------------------------------------------
// InjectSpanContext
//------------------------------------------------------------------------------
static opentracing::expected<void> InjectSpanContext(
    BinaryCarrier& carrier, uint64_t trace_id, uint64_t span_id,
    const std::unordered_map<std::string, std::string>& baggage) noexcept try {
  carrier.Clear();
  auto basic = carrier.mutable_basic_ctx();
  basic->set_trace_id(trace_id);
  basic->set_span_id(span_id);
  basic->set_sampled(true);
  auto mutable_baggage = basic->mutable_baggage_items();
  for (auto& baggage_item : baggage) {
    (*mutable_baggage)[baggage_item.first] = baggage_item.second;
  }
  return {};
} catch (const std::bad_alloc&) {
  return opentracing::make_unexpected(
      std::make_error_code(std::errc::not_enough_memory));
}

opentracing::expected<void> InjectSpanContext(
    std::ostream& carrier, uint64_t trace_id, uint64_t span_id,
    const std::unordered_map<std::string, std::string>& baggage) {
  BinaryCarrier binary_carrier;
  auto result = InjectSpanContext(binary_carrier, trace_id, span_id, baggage);
  if (!result) {
    return result;
  }
  if (!binary_carrier.SerializeToOstream(&carrier)) {
    return opentracing::make_unexpected(
        std::make_error_code(std::errc::io_error));
  }

  // Flush so that when we call carrier.good, we'll get an accurate view of the
  // error state.
  carrier.flush();
  if (!carrier.good()) {
    return opentracing::make_unexpected(
        std::make_error_code(std::errc::io_error));
  }

  return {};
}

opentracing::expected<void> InjectSpanContext(
    const opentracing::TextMapWriter& carrier, uint64_t trace_id,
    uint64_t span_id,
    const std::unordered_map<std::string, std::string>& baggage) {
  std::string trace_id_hex, span_id_hex, baggage_key;
  try {
    trace_id_hex = Uint64ToHex(trace_id);
    span_id_hex = Uint64ToHex(span_id);
    baggage_key = PrefixBaggage;
  } catch (const std::bad_alloc&) {
    return opentracing::make_unexpected(
        std::make_error_code(std::errc::not_enough_memory));
  }
  auto result = carrier.Set(FieldNameTraceID, trace_id_hex);
  if (!result) {
    return result;
  }
  result = carrier.Set(FieldNameSpanID, span_id_hex);
  if (!result) {
    return result;
  }
  result = carrier.Set(FieldNameSampled, "true");
  if (!result) {
    return result;
  }
  for (const auto& baggage_item : baggage) {
    try {
      baggage_key.replace(std::begin(baggage_key) + PrefixBaggage.size(),
                          std::end(baggage_key), baggage_item.first);
    } catch (const std::bad_alloc&) {
      return opentracing::make_unexpected(
          std::make_error_code(std::errc::not_enough_memory));
    }
    result = carrier.Set(baggage_key, baggage_item.second);
    if (!result) {
      return result;
    }
  }
  return {};
}

//------------------------------------------------------------------------------
// ExtractSpanContext
//------------------------------------------------------------------------------
static opentracing::expected<bool> ExtractSpanContext(
    const BinaryCarrier& carrier, uint64_t& trace_id, uint64_t& span_id,
    std::unordered_map<std::string, std::string>& baggage) noexcept try {
  auto& basic = carrier.basic_ctx();
  trace_id = basic.trace_id();
  span_id = basic.span_id();
  for (const auto& entry : basic.baggage_items()) {
    baggage.emplace(entry.first, entry.second);
  }
  return true;
} catch (const std::bad_alloc&) {
  return opentracing::make_unexpected(
      std::make_error_code(std::errc::not_enough_memory));
}

opentracing::expected<bool> ExtractSpanContext(
    std::istream& carrier, uint64_t& trace_id, uint64_t& span_id,
    std::unordered_map<std::string, std::string>& baggage) try {
  // istream::peek returns EOF if it's in an error state, so check for an error
  // state first before checking for an empty stream.
  if (!carrier.good()) {
    return opentracing::make_unexpected(
        std::make_error_code(std::errc::io_error));
  }

  // Check for the case when no span is encoded.
  if (carrier.peek() == EOF) {
    return false;
  }

  BinaryCarrier binary_carrier;
  if (!binary_carrier.ParseFromIstream(&carrier)) {
    return false;
  }
  return ExtractSpanContext(binary_carrier, trace_id, span_id, baggage);
} catch (const std::bad_alloc&) {
  return opentracing::make_unexpected(
      std::make_error_code(std::errc::not_enough_memory));
}

template <class KeyCompare>
static opentracing::expected<bool> ExtractSpanContext(
    const opentracing::TextMapReader& carrier, uint64_t& trace_id,
    uint64_t& span_id, std::unordered_map<std::string, std::string>& baggage,
    KeyCompare key_compare) {
  int count = 0;
  auto result = carrier.ForeachKey(
      [&](opentracing::string_view key,
          opentracing::string_view value) -> opentracing::expected<void> {
        try {
          if (key_compare(key, FieldNameTraceID)) {
            trace_id = HexToUint64(value);
            count++;
          } else if (key_compare(key, FieldNameSpanID)) {
            span_id = HexToUint64(value);
            count++;
          } else if (key_compare(key, FieldNameSampled)) {
            // Ignored
            count++;
          } else if (key.length() > PrefixBaggage.size() &&
                     key_compare(opentracing::string_view{key.data(),
                                                          PrefixBaggage.size()},
                                 PrefixBaggage)) {
            baggage.emplace(std::string{std::begin(key) + PrefixBaggage.size(),
                                        std::end(key)},
                            value);
          }
          return {};
        } catch (const std::bad_alloc&) {
          return opentracing::make_unexpected(
              std::make_error_code(std::errc::not_enough_memory));
        }
      });
  if (!result) {
    return opentracing::make_unexpected(result.error());
  }
  if (count == 0) {
    return false;
  }
  if (count > 0 && count != FieldCount) {
    return opentracing::make_unexpected(
        opentracing::span_context_corrupted_error);
  }
  return true;
}

opentracing::expected<bool> ExtractSpanContext(
    const opentracing::TextMapReader& carrier, uint64_t& trace_id,
    uint64_t& span_id, std::unordered_map<std::string, std::string>& baggage) {
  return ExtractSpanContext(carrier, trace_id, span_id, baggage,
                            std::equal_to<opentracing::string_view>());
}

// HTTP header field names are case insensitive, so we need to ignore case when
// comparing against the OpenTracing field names.
//
// See https://stackoverflow.com/a/5259004/4447365
opentracing::expected<bool> ExtractSpanContext(
    const opentracing::HTTPHeadersReader& carrier, uint64_t& trace_id,
    uint64_t& span_id, std::unordered_map<std::string, std::string>& baggage) {
  auto iequals = [](opentracing::string_view lhs,
                    opentracing::string_view rhs) {
    return lhs.length() == rhs.length() &&
           std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs),
                      [](char a, char b) {
                        return std::tolower(a) == std::tolower(b);
                      });
  };
  return ExtractSpanContext(carrier, trace_id, span_id, baggage, iequals);
}
}  // namespace lightstep
<|endoftext|>


<commit_before>#include "space.h"
#include "display.h"
#include "window.h"
#include "tree.h"
#include "border.h"
#include "keys.h"
#include "notifications.h"
#include "helpers.h"

extern kwm_mach KWMMach;
extern kwm_tiling KWMTiling;
extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_toggles KWMToggles;
extern kwm_mode KWMMode;
extern kwm_thread KWMThread;
extern kwm_border FocusedBorder;
extern kwm_border MarkedBorder;

void GetTagForMonocleSpace(space_info *Space, std::string &Tag)
{
    tree_node *Node = Space->RootNode;
    bool FoundFocusedWindow = false;
    int FocusedIndex = 0;
    int NumberOfWindows = 0;

    if(Node && KWMFocus.Window)
    {
        link_node *Link = Node->List;
        while(Link)
        {
            if(!FoundFocusedWindow)
                ++FocusedIndex;

            if(Link->WindowID == KWMFocus.Window->WID)
                FoundFocusedWindow = true;

            ++NumberOfWindows;
            Link = Link->Next;
        }
    }

    if(FoundFocusedWindow)
        Tag = "[" + std::to_string(FocusedIndex) + "/" + std::to_string(NumberOfWindows) + "]";
    else
        Tag = "[" + std::to_string(NumberOfWindows) + "]";
}

void GetTagForCurrentSpace(std::string &Tag)
{
    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        if(Space->Settings.Mode == SpaceModeBSP)
            Tag = "[bsp]";
        else if(Space->Settings.Mode == SpaceModeFloating)
            Tag = "[float]";
        else if(Space->Settings.Mode == SpaceModeMonocle)
            GetTagForMonocleSpace(Space, Tag);
    }
    else
    {
        if(KWMMode.Space == SpaceModeBSP)
            Tag = "[bsp]";
        else if(KWMMode.Space == SpaceModeFloating)
            Tag = "[float]";
        else if(KWMMode.Space == SpaceModeMonocle)
            Tag = "[monocle]";
    }
}

void MoveWindowToSpace(std::string SpaceID)
{
    if(!KWMFocus.Window)
        return;

    pthread_mutex_lock(&KWMThread.Lock);
    CGEventTapEnable(KWMMach.EventTap, false);
    DestroyApplicationNotifications();

    window_info *Window = KWMFocus.Window;
    bool WasWindowFloating = IsFocusedWindowFloating();
    if(!WasWindowFloating)
    {
        screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
        space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
        if(SpaceOfWindow->Settings.Mode == SpaceModeBSP)
            RemoveWindowFromBSPTree(ScreenOfWindow, Window->WID, false, false);
        else if(SpaceOfWindow->Settings.Mode == SpaceModeMonocle)
            RemoveWindowFromMonocleTree(ScreenOfWindow, Window->WID, false);
    }

    CGPoint CursorPos = GetCursorPos();
    CGPoint WindowPos = GetWindowPos(Window);
    CGPoint ClickPos = CGPointMake(WindowPos.x + 75, WindowPos.y + 7);

    CGEventRef ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, ClickPos, kCGMouseButtonLeft);
    CGEventSetFlags(ClickEvent, 0);
    CGEventPost(kCGHIDEventTap, ClickEvent);
    CFRelease(ClickEvent);
    usleep(150000);

    KwmEmitKeystroke(KWMHotkeys.SpacesKey, SpaceID);
    usleep(300000);

    KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
    KWMScreen.Current->ActiveSpace = GetActiveSpaceOfDisplay(KWMScreen.Current);
    ShouldActiveSpaceBeManaged();
    UpdateActiveWindowList(KWMScreen.Current);

    ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, ClickPos, kCGMouseButtonLeft);
    CGEventSetFlags(ClickEvent, 0);
    CGEventPost(kCGHIDEventTap, ClickEvent);
    CFRelease(ClickEvent);
    usleep(150000);

    if(!WasWindowFloating)
    {
        screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
        space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
        if(SpaceOfWindow->Settings.Mode == SpaceModeBSP)
            AddWindowToBSPTree(ScreenOfWindow, Window->WID);
        else if(SpaceOfWindow->Settings.Mode == SpaceModeMonocle)
            AddWindowToMonocleTree(ScreenOfWindow, Window->WID);
    }

    CGWarpMouseCursorPosition(CursorPos);
    CGEventTapEnable(KWMMach.EventTap, true);
    pthread_mutex_unlock(&KWMThread.Lock);
}

bool IsActiveSpaceFloating()
{
    return IsSpaceFloating(KWMScreen.Current->ActiveSpace);
}

bool IsSpaceFloating(int SpaceID)
{
    bool Result = false;

    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        std::map<int, space_info>::iterator It = KWMScreen.Current->Space.find(SpaceID);
        if(It != KWMScreen.Current->Space.end())
            Result = KWMScreen.Current->Space[SpaceID].Settings.Mode == SpaceModeFloating;
    }

    return Result;
}

space_info *GetActiveSpaceOfScreen(screen_info *Screen)
{
    space_info *Space = NULL;
    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);

    if(It == Screen->Space.end())
    {
        space_info Clear = {{{0}}};
        Screen->ActiveSpace = GetActiveSpaceOfDisplay(Screen);
        Screen->Space[Screen->ActiveSpace] = Clear;
        Space = &Screen->Space[Screen->ActiveSpace];
    }
    else
    {
        Space = &Screen->Space[Screen->ActiveSpace];
    }

    return Space;
}

bool IsSpaceInitializedForScreen(screen_info *Screen)
{
    if(!Screen)
        return false;

    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.Initialized;
}

bool DoesSpaceExistInMapOfScreen(screen_info *Screen)
{
    if(!Screen)
        return false;

    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.RootNode != NULL && It->second.Initialized;
}

bool IsSpaceTransitionInProgress()
{
    if(KWMScreen.Transitioning)
        return true;

    bool Result = false;
    std::map<unsigned int, screen_info>::iterator It;
    for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
    {
        screen_info *Screen = &It->second;
        if(!Screen->Identifier)
            Screen->Identifier = GetDisplayIdentifier(Screen);

        Result = Result || CGSManagedDisplayIsAnimating(CGSDefaultConnection, Screen->Identifier);
    }

    if(Result)
    {
        DEBUG("IsSpaceTransitionInProgress() Space transition detected")
        KWMScreen.Transitioning = true;
        ClearFocusedWindow();
        ClearMarkedWindow();
    }

    return Result;
}

bool IsActiveSpaceManaged()
{
    space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
    return Space->Managed;
}

void ShouldActiveSpaceBeManaged()
{
    space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
    Space->Managed = CGSSpaceGetType(CGSDefaultConnection, KWMScreen.Current->ActiveSpace) == CGSSpaceTypeUser;
}

void FloatFocusedSpace()
{
    if(KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       IsActiveSpaceManaged())
    {
        space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        if(Space->Settings.Mode == SpaceModeFloating)
            return;

        DestroyNodeTree(Space->RootNode);
        Space->RootNode = NULL;

        Space->Settings.Mode = SpaceModeFloating;
        Space->Initialized = true;
        Space->NeedsUpdate = false;
        ClearFocusedWindow();
    }
}

void TileFocusedSpace(space_tiling_option Mode)
{
    if(KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       IsActiveSpaceManaged() &&
       FilterWindowList(KWMScreen.Current))
    {
        space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        if(Space->Settings.Mode == Mode)
            return;

        DestroyNodeTree(Space->RootNode);
        Space->RootNode = NULL;

        Space->Settings.Mode = Mode;
        std::vector<window_info*> WindowsOnDisplay = GetAllWindowsOnDisplay(KWMScreen.Current->ID);
        CreateWindowNodeTree(KWMScreen.Current, &WindowsOnDisplay);
    }
}

void UpdateActiveSpace()
{
    pthread_mutex_lock(&KWMThread.Lock);
    Assert(KWMScreen.Current)

    KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
    KWMScreen.Current->ActiveSpace = GetActiveSpaceOfDisplay(KWMScreen.Current);
    ShouldActiveSpaceBeManaged();

    space_info *Space = NULL;
    if(KWMScreen.PrevSpace != KWMScreen.Current->ActiveSpace)
    {
        DEBUG("UpdateActiveSpace() Space transition ended " << KWMScreen.PrevSpace << " -> " << KWMScreen.Current->ActiveSpace)

        Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        UpdateActiveWindowList(KWMScreen.Current);
        if(Space->FocusedWindowID != 0)
        {
            FocusWindowByID(Space->FocusedWindowID);
            MoveCursorToCenterOfFocusedWindow();
        }
    }
    else
    {
        std::map<unsigned int, screen_info>::iterator It;
        for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
        {
            screen_info *Screen = &It->second;
            if(Screen->ID == KWMScreen.Current->ID)
                continue;

            int ScreenCurrentSpace = Screen->ActiveSpace;
            int ScreenNewSpace = GetActiveSpaceOfDisplay(Screen);
            if(ScreenCurrentSpace != ScreenNewSpace)
            {
                DEBUG("space changed on monitor: " << Screen->ID)

                Screen->ActiveSpace = ScreenNewSpace;
                KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
                KWMScreen.Current = Screen;
                ShouldActiveSpaceBeManaged();
                Space = GetActiveSpaceOfScreen(Screen);
                UpdateActiveWindowList(Screen);
                FilterWindowList(Screen);
                break;
            }
        }
    }

    if(!Space || !Space->Managed || Space->Settings.Mode == SpaceModeFloating)
    {
        ClearFocusedWindow();
        ClearMarkedWindow();
        DestroyApplicationNotifications();
    }
    else if (Space->NeedsUpdate)
    {
        UpdateSpaceOfScreen(Space, KWMScreen.Current);
    }

    KWMScreen.Transitioning = false;
    pthread_mutex_unlock(&KWMThread.Lock);
}

space_settings *GetSpaceSettingsForDesktopID(int ScreenID, int DesktopID)
{
    space_identifier Lookup = { ScreenID, DesktopID };
    std::map<space_identifier, space_settings>::iterator It = KWMTiling.SpaceSettings.find(Lookup);
    if(It != KWMTiling.SpaceSettings.end())
        return &It->second;
    else
        return NULL;
}
<commit_msg>kwm: move UpdateSpaceOfScreen in space change cond<commit_after>#include "space.h"
#include "display.h"
#include "window.h"
#include "tree.h"
#include "border.h"
#include "keys.h"
#include "notifications.h"
#include "helpers.h"

extern kwm_mach KWMMach;
extern kwm_tiling KWMTiling;
extern kwm_screen KWMScreen;
extern kwm_focus KWMFocus;
extern kwm_toggles KWMToggles;
extern kwm_mode KWMMode;
extern kwm_thread KWMThread;
extern kwm_border FocusedBorder;
extern kwm_border MarkedBorder;

void GetTagForMonocleSpace(space_info *Space, std::string &Tag)
{
    tree_node *Node = Space->RootNode;
    bool FoundFocusedWindow = false;
    int FocusedIndex = 0;
    int NumberOfWindows = 0;

    if(Node && KWMFocus.Window)
    {
        link_node *Link = Node->List;
        while(Link)
        {
            if(!FoundFocusedWindow)
                ++FocusedIndex;

            if(Link->WindowID == KWMFocus.Window->WID)
                FoundFocusedWindow = true;

            ++NumberOfWindows;
            Link = Link->Next;
        }
    }

    if(FoundFocusedWindow)
        Tag = "[" + std::to_string(FocusedIndex) + "/" + std::to_string(NumberOfWindows) + "]";
    else
        Tag = "[" + std::to_string(NumberOfWindows) + "]";
}

void GetTagForCurrentSpace(std::string &Tag)
{
    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        if(Space->Settings.Mode == SpaceModeBSP)
            Tag = "[bsp]";
        else if(Space->Settings.Mode == SpaceModeFloating)
            Tag = "[float]";
        else if(Space->Settings.Mode == SpaceModeMonocle)
            GetTagForMonocleSpace(Space, Tag);
    }
    else
    {
        if(KWMMode.Space == SpaceModeBSP)
            Tag = "[bsp]";
        else if(KWMMode.Space == SpaceModeFloating)
            Tag = "[float]";
        else if(KWMMode.Space == SpaceModeMonocle)
            Tag = "[monocle]";
    }
}

void MoveWindowToSpace(std::string SpaceID)
{
    if(!KWMFocus.Window)
        return;

    pthread_mutex_lock(&KWMThread.Lock);
    CGEventTapEnable(KWMMach.EventTap, false);
    DestroyApplicationNotifications();

    window_info *Window = KWMFocus.Window;
    bool WasWindowFloating = IsFocusedWindowFloating();
    if(!WasWindowFloating)
    {
        screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
        space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
        if(SpaceOfWindow->Settings.Mode == SpaceModeBSP)
            RemoveWindowFromBSPTree(ScreenOfWindow, Window->WID, false, false);
        else if(SpaceOfWindow->Settings.Mode == SpaceModeMonocle)
            RemoveWindowFromMonocleTree(ScreenOfWindow, Window->WID, false);
    }

    CGPoint CursorPos = GetCursorPos();
    CGPoint WindowPos = GetWindowPos(Window);
    CGPoint ClickPos = CGPointMake(WindowPos.x + 75, WindowPos.y + 7);

    CGEventRef ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, ClickPos, kCGMouseButtonLeft);
    CGEventSetFlags(ClickEvent, 0);
    CGEventPost(kCGHIDEventTap, ClickEvent);
    CFRelease(ClickEvent);
    usleep(150000);

    KwmEmitKeystroke(KWMHotkeys.SpacesKey, SpaceID);
    usleep(300000);

    KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
    KWMScreen.Current->ActiveSpace = GetActiveSpaceOfDisplay(KWMScreen.Current);
    ShouldActiveSpaceBeManaged();
    UpdateActiveWindowList(KWMScreen.Current);

    ClickEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, ClickPos, kCGMouseButtonLeft);
    CGEventSetFlags(ClickEvent, 0);
    CGEventPost(kCGHIDEventTap, ClickEvent);
    CFRelease(ClickEvent);
    usleep(150000);

    if(!WasWindowFloating)
    {
        screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
        space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
        if(SpaceOfWindow->Settings.Mode == SpaceModeBSP)
            AddWindowToBSPTree(ScreenOfWindow, Window->WID);
        else if(SpaceOfWindow->Settings.Mode == SpaceModeMonocle)
            AddWindowToMonocleTree(ScreenOfWindow, Window->WID);
    }

    CGWarpMouseCursorPosition(CursorPos);
    CGEventTapEnable(KWMMach.EventTap, true);
    pthread_mutex_unlock(&KWMThread.Lock);
}

bool IsActiveSpaceFloating()
{
    return IsSpaceFloating(KWMScreen.Current->ActiveSpace);
}

bool IsSpaceFloating(int SpaceID)
{
    bool Result = false;

    if(IsSpaceInitializedForScreen(KWMScreen.Current))
    {
        std::map<int, space_info>::iterator It = KWMScreen.Current->Space.find(SpaceID);
        if(It != KWMScreen.Current->Space.end())
            Result = KWMScreen.Current->Space[SpaceID].Settings.Mode == SpaceModeFloating;
    }

    return Result;
}

space_info *GetActiveSpaceOfScreen(screen_info *Screen)
{
    space_info *Space = NULL;
    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);

    if(It == Screen->Space.end())
    {
        space_info Clear = {{{0}}};
        Screen->ActiveSpace = GetActiveSpaceOfDisplay(Screen);
        Screen->Space[Screen->ActiveSpace] = Clear;
        Space = &Screen->Space[Screen->ActiveSpace];
    }
    else
    {
        Space = &Screen->Space[Screen->ActiveSpace];
    }

    return Space;
}

bool IsSpaceInitializedForScreen(screen_info *Screen)
{
    if(!Screen)
        return false;

    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.Initialized;
}

bool DoesSpaceExistInMapOfScreen(screen_info *Screen)
{
    if(!Screen)
        return false;

    std::map<int, space_info>::iterator It = Screen->Space.find(Screen->ActiveSpace);
    if(It == Screen->Space.end())
        return false;
    else
        return It->second.RootNode != NULL && It->second.Initialized;
}

bool IsSpaceTransitionInProgress()
{
    if(KWMScreen.Transitioning)
        return true;

    bool Result = false;
    std::map<unsigned int, screen_info>::iterator It;
    for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
    {
        screen_info *Screen = &It->second;
        if(!Screen->Identifier)
            Screen->Identifier = GetDisplayIdentifier(Screen);

        Result = Result || CGSManagedDisplayIsAnimating(CGSDefaultConnection, Screen->Identifier);
    }

    if(Result)
    {
        DEBUG("IsSpaceTransitionInProgress() Space transition detected")
        KWMScreen.Transitioning = true;
        ClearFocusedWindow();
        ClearMarkedWindow();
    }

    return Result;
}

bool IsActiveSpaceManaged()
{
    space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
    return Space->Managed;
}

void ShouldActiveSpaceBeManaged()
{
    space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
    Space->Managed = CGSSpaceGetType(CGSDefaultConnection, KWMScreen.Current->ActiveSpace) == CGSSpaceTypeUser;
}

void FloatFocusedSpace()
{
    if(KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       IsActiveSpaceManaged())
    {
        space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        if(Space->Settings.Mode == SpaceModeFloating)
            return;

        DestroyNodeTree(Space->RootNode);
        Space->RootNode = NULL;

        Space->Settings.Mode = SpaceModeFloating;
        Space->Initialized = true;
        Space->NeedsUpdate = false;
        ClearFocusedWindow();
    }
}

void TileFocusedSpace(space_tiling_option Mode)
{
    if(KWMToggles.EnableTilingMode &&
       !IsSpaceTransitionInProgress() &&
       IsActiveSpaceManaged() &&
       FilterWindowList(KWMScreen.Current))
    {
        space_info *Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        if(Space->Settings.Mode == Mode)
            return;

        DestroyNodeTree(Space->RootNode);
        Space->RootNode = NULL;

        Space->Settings.Mode = Mode;
        std::vector<window_info*> WindowsOnDisplay = GetAllWindowsOnDisplay(KWMScreen.Current->ID);
        CreateWindowNodeTree(KWMScreen.Current, &WindowsOnDisplay);
    }
}

void UpdateActiveSpace()
{
    pthread_mutex_lock(&KWMThread.Lock);
    Assert(KWMScreen.Current)

    KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
    KWMScreen.Current->ActiveSpace = GetActiveSpaceOfDisplay(KWMScreen.Current);
    ShouldActiveSpaceBeManaged();

    space_info *Space = NULL;
    if(KWMScreen.PrevSpace != KWMScreen.Current->ActiveSpace)
    {
        DEBUG("UpdateActiveSpace() Space transition ended " << KWMScreen.PrevSpace << " -> " << KWMScreen.Current->ActiveSpace)

        Space = GetActiveSpaceOfScreen(KWMScreen.Current);
        UpdateActiveWindowList(KWMScreen.Current);

        if (Space->NeedsUpdate)
            UpdateSpaceOfScreen(Space, KWMScreen.Current);

        if(Space->FocusedWindowID != 0)
        {
            FocusWindowByID(Space->FocusedWindowID);
            MoveCursorToCenterOfFocusedWindow();
        }
    }
    else
    {
        std::map<unsigned int, screen_info>::iterator It;
        for(It = KWMTiling.DisplayMap.begin(); It != KWMTiling.DisplayMap.end(); ++It)
        {
            screen_info *Screen = &It->second;
            if(Screen->ID == KWMScreen.Current->ID)
                continue;

            int ScreenCurrentSpace = Screen->ActiveSpace;
            int ScreenNewSpace = GetActiveSpaceOfDisplay(Screen);
            if(ScreenCurrentSpace != ScreenNewSpace)
            {
                DEBUG("space changed on monitor: " << Screen->ID)

                Screen->ActiveSpace = ScreenNewSpace;
                KWMScreen.PrevSpace = KWMScreen.Current->ActiveSpace;
                KWMScreen.Current = Screen;
                ShouldActiveSpaceBeManaged();
                Space = GetActiveSpaceOfScreen(Screen);
                UpdateActiveWindowList(Screen);
                FilterWindowList(Screen);
                break;
            }
        }
    }

    if(!Space || !Space->Managed || Space->Settings.Mode == SpaceModeFloating)
    {
        ClearFocusedWindow();
        ClearMarkedWindow();
        DestroyApplicationNotifications();
    }

    KWMScreen.Transitioning = false;
    pthread_mutex_unlock(&KWMThread.Lock);
}

space_settings *GetSpaceSettingsForDesktopID(int ScreenID, int DesktopID)
{
    space_identifier Lookup = { ScreenID, DesktopID };
    std::map<space_identifier, space_settings>::iterator It = KWMTiling.SpaceSettings.find(Lookup);
    if(It != KWMTiling.SpaceSettings.end())
        return &It->second;
    else
        return NULL;
}
<|endoftext|>


<commit_before>/*
 * Convert an input and an output pipe to a duplex socket.
 *
 * This code is used in the test cases to convert stdin/stdout to a
 * single socket.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "duplex.hxx"
#include "system/fd-util.h"
#include "system/fd_util.h"
#include "event/event2.h"
#include "event/Callback.hxx"
#include "buffered_io.hxx"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"

#include <inline/compiler.h>
#include <daemon/log.h>

#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

struct Duplex {
    int read_fd;
    int write_fd;
    int sock_fd;
    bool sock_eof = false;

    SliceFifoBuffer from_read, to_write;

    struct event2 read_event, write_event, sock_event;

    Duplex(int _read_fd, int _write_fd, int _sock_fd)
        :read_fd(_read_fd), write_fd(_write_fd), sock_fd(_sock_fd) {
        from_read.Allocate(fb_pool_get());
        to_write.Allocate(fb_pool_get());

        event2_init(&read_event, read_fd,
                    MakeSimpleEventCallback(Duplex, ReadEventCallback), this,
                    nullptr);
        event2_set(&read_event, EV_READ);

        event2_init(&write_event, write_fd,
                    MakeSimpleEventCallback(Duplex, WriteEventCallback), this,
                    nullptr);

        event2_init(&sock_event, sock_fd,
                    MakeEventCallback(Duplex, SocketEventCallback), this,
                    nullptr);
        event2_persist(&sock_event);
        event2_set(&sock_event, EV_READ);
    }

    void Destroy();
    bool CheckDestroy();

    void ReadEventCallback();
    void WriteEventCallback();
    void SocketEventCallback(evutil_socket_t fd, short events);
};

void
Duplex::Destroy()
{
    if (read_fd >= 0) {
        event2_set(&read_event, 0);

        if (read_fd > 2)
            close(read_fd);

        read_fd = -1;
    }

    if (write_fd >= 0) {
        event2_set(&write_event, 0);

        if (write_fd > 2)
            close(write_fd);

        write_fd = -1;
    }

    if (sock_fd >= 0) {
        event2_set(&sock_event, 0);
        event2_commit(&sock_event);

        close(sock_fd);
        sock_fd = -1;
    }

    from_read.Free(fb_pool_get());
    to_write.Free(fb_pool_get());
}

bool
Duplex::CheckDestroy()
{
    if (read_fd < 0 && sock_eof && from_read.IsEmpty() && to_write.IsEmpty()) {
        Destroy();
        return true;
    } else
        return false;
}

inline void
Duplex::ReadEventCallback()
{
    event2_reset(&read_event);

    ssize_t nbytes = read_to_buffer(read_fd, from_read, INT_MAX);
    if (nbytes == -1) {
        daemon_log(1, "failed to read: %s\n", strerror(errno));
        Destroy();
        return;
    }

    if (nbytes == 0) {
        close(read_fd);
        read_fd = -1;
        if (CheckDestroy())
            return;
    }

    if (nbytes > 0)
        event2_or(&sock_event, EV_WRITE);

    if (read_fd >= 0 && !from_read.IsFull())
        event2_or(&read_event, EV_READ);
}

inline void
Duplex::WriteEventCallback()
{
    event2_reset(&write_event);

    ssize_t nbytes = write_from_buffer(write_fd, to_write);
    if (nbytes == -1) {
        Destroy();
        return;
    }

    if (nbytes > 0 && !sock_eof)
        event2_or(&sock_event, EV_READ);

    if (!to_write.IsEmpty())
        event2_or(&write_event, EV_WRITE);
}

inline void
Duplex::SocketEventCallback(evutil_socket_t fd, short events)
{
    event2_lock(&sock_event);
    event2_occurred_persist(&sock_event, events);

    if ((events & EV_READ) != 0) {
        ssize_t nbytes = recv_to_buffer(fd, to_write, INT_MAX);
        if (nbytes == -1) {
            daemon_log(1, "failed to read: %s\n", strerror(errno));
            Destroy();
            return;
        }

        if (nbytes == 0) {
            sock_eof = true;
            if (CheckDestroy())
                return;
        }

        if (likely(nbytes > 0))
            event2_or(&write_event, EV_WRITE);

        if (!to_write.IsFull())
            event2_or(&sock_event, EV_READ);
    }

    if ((events & EV_WRITE) != 0) {
        ssize_t nbytes = send_from_buffer(fd, from_read);
        if (nbytes == -1) {
            Destroy();
            return;
        }

        if (nbytes > 0 && read_fd >= 0)
            event2_or(&read_event, EV_READ);

        if (!from_read.IsEmpty())
            event2_or(&sock_event, EV_WRITE);
    }

    event2_unlock(&sock_event);
}

int
duplex_new(struct pool *pool, int read_fd, int write_fd)
{
    assert(pool != nullptr);
    assert(read_fd >= 0);
    assert(write_fd >= 0);

    int fds[2];
    if (socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
        return -1;

    if (fd_set_nonblock(fds[1], 1) < 0) {
        int save_errno = errno;
        close(fds[0]);
        close(fds[1]);
        errno = save_errno;
        return -1;
    }

    NewFromPool<Duplex>(*pool, read_fd, write_fd, fds[0]);
    return fds[1];
}
<commit_msg>duplex: move code to CloseRead(), CloseWrite(), CloseSocket()<commit_after>/*
 * Convert an input and an output pipe to a duplex socket.
 *
 * This code is used in the test cases to convert stdin/stdout to a
 * single socket.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "duplex.hxx"
#include "system/fd-util.h"
#include "system/fd_util.h"
#include "event/event2.h"
#include "event/Callback.hxx"
#include "buffered_io.hxx"
#include "pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"

#include <inline/compiler.h>
#include <daemon/log.h>

#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

struct Duplex {
    int read_fd;
    int write_fd;
    int sock_fd;
    bool sock_eof = false;

    SliceFifoBuffer from_read, to_write;

    struct event2 read_event, write_event, sock_event;

    Duplex(int _read_fd, int _write_fd, int _sock_fd)
        :read_fd(_read_fd), write_fd(_write_fd), sock_fd(_sock_fd) {
        from_read.Allocate(fb_pool_get());
        to_write.Allocate(fb_pool_get());

        event2_init(&read_event, read_fd,
                    MakeSimpleEventCallback(Duplex, ReadEventCallback), this,
                    nullptr);
        event2_set(&read_event, EV_READ);

        event2_init(&write_event, write_fd,
                    MakeSimpleEventCallback(Duplex, WriteEventCallback), this,
                    nullptr);

        event2_init(&sock_event, sock_fd,
                    MakeEventCallback(Duplex, SocketEventCallback), this,
                    nullptr);
        event2_persist(&sock_event);
        event2_set(&sock_event, EV_READ);
    }

    void CloseRead() {
        assert(read_fd >= 0);

        event2_set(&read_event, 0);

        if (read_fd > 2)
            close(read_fd);

        read_fd = -1;
    }

    void CloseWrite() {
        assert(write_fd >= 0);

        event2_set(&write_event, 0);

        if (write_fd > 2)
            close(write_fd);

        write_fd = -1;
    }

    void CloseSocket() {
        assert(sock_fd >= 0);

        event2_set(&sock_event, 0);
        event2_commit(&sock_event);

        close(sock_fd);
        sock_fd = -1;
    }

    void Destroy();
    bool CheckDestroy();

    void ReadEventCallback();
    void WriteEventCallback();
    void SocketEventCallback(evutil_socket_t fd, short events);
};

void
Duplex::Destroy()
{
    if (read_fd >= 0)
        CloseRead();

    if (write_fd >= 0)
        CloseWrite();

    if (sock_fd >= 0)
        CloseSocket();

    from_read.Free(fb_pool_get());
    to_write.Free(fb_pool_get());
}

bool
Duplex::CheckDestroy()
{
    if (read_fd < 0 && sock_eof && from_read.IsEmpty() && to_write.IsEmpty()) {
        Destroy();
        return true;
    } else
        return false;
}

inline void
Duplex::ReadEventCallback()
{
    event2_reset(&read_event);

    ssize_t nbytes = read_to_buffer(read_fd, from_read, INT_MAX);
    if (nbytes == -1) {
        daemon_log(1, "failed to read: %s\n", strerror(errno));
        Destroy();
        return;
    }

    if (nbytes == 0) {
        CloseRead();
        if (CheckDestroy())
            return;
    }

    if (nbytes > 0)
        event2_or(&sock_event, EV_WRITE);

    if (read_fd >= 0 && !from_read.IsFull())
        event2_or(&read_event, EV_READ);
}

inline void
Duplex::WriteEventCallback()
{
    event2_reset(&write_event);

    ssize_t nbytes = write_from_buffer(write_fd, to_write);
    if (nbytes == -1) {
        Destroy();
        return;
    }

    if (nbytes > 0 && !sock_eof)
        event2_or(&sock_event, EV_READ);

    if (!to_write.IsEmpty())
        event2_or(&write_event, EV_WRITE);
}

inline void
Duplex::SocketEventCallback(evutil_socket_t fd, short events)
{
    event2_lock(&sock_event);
    event2_occurred_persist(&sock_event, events);

    if ((events & EV_READ) != 0) {
        ssize_t nbytes = recv_to_buffer(fd, to_write, INT_MAX);
        if (nbytes == -1) {
            daemon_log(1, "failed to read: %s\n", strerror(errno));
            Destroy();
            return;
        }

        if (nbytes == 0) {
            sock_eof = true;
            if (CheckDestroy())
                return;
        }

        if (likely(nbytes > 0))
            event2_or(&write_event, EV_WRITE);

        if (!to_write.IsFull())
            event2_or(&sock_event, EV_READ);
    }

    if ((events & EV_WRITE) != 0) {
        ssize_t nbytes = send_from_buffer(fd, from_read);
        if (nbytes == -1) {
            Destroy();
            return;
        }

        if (nbytes > 0 && read_fd >= 0)
            event2_or(&read_event, EV_READ);

        if (!from_read.IsEmpty())
            event2_or(&sock_event, EV_WRITE);
    }

    event2_unlock(&sock_event);
}

int
duplex_new(struct pool *pool, int read_fd, int write_fd)
{
    assert(pool != nullptr);
    assert(read_fd >= 0);
    assert(write_fd >= 0);

    int fds[2];
    if (socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
        return -1;

    if (fd_set_nonblock(fds[1], 1) < 0) {
        int save_errno = errno;
        close(fds[0]);
        close(fds[1]);
        errno = save_errno;
        return -1;
    }

    NewFromPool<Duplex>(*pool, read_fd, write_fd, fds[0]);
    return fds[1];
}
<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <cmath>
#include <iostream>
#include <signal.h>

#include <QVBoxLayout>
#include <QMouseEvent>
#include <QPushButton>
#include <QGridLayout>

#include "window.hpp"
#include "settings.hpp"

#include "paint.hpp"
#include "sound.hpp"

volatile sig_atomic_t do_exit = 0;

MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
  main_layout = new QStackedLayout;

  GLWindow * glWindow = new GLWindow(this);
  main_layout->addWidget(glWindow);

  SettingsWindow * settingsWindow = new SettingsWindow(this);
  main_layout->addWidget(settingsWindow);

  main_layout->setMargin(0);
  setLayout(main_layout);
  QObject::connect(glWindow, SIGNAL(openSettings()), this, SLOT(openSettings()));
  QObject::connect(settingsWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings()));

  setStyleSheet(R"(
    * {
      color: white;
      background-color: #072339;
    }
  )");
}

void MainWindow::openSettings(){
  main_layout->setCurrentIndex(1);
}

void MainWindow::closeSettings(){
  main_layout->setCurrentIndex(0);
}

GLWindow::GLWindow(QWidget *parent) : QOpenGLWidget(parent) {
  timer = new QTimer(this);
  QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
}

GLWindow::~GLWindow() {
  makeCurrent();
  doneCurrent();
}

void GLWindow::initializeGL() {
  initializeOpenGLFunctions();
  std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;

  ui_state = new UIState();
  ui_init(ui_state);
  ui_state->fb_w = vwp_w;
  ui_state->fb_h = vwp_h;

  int err = pthread_create(&connect_thread_handle, NULL,
                           vision_connect_thread, ui_state);
  assert(err == 0);

  timer->start(50);
}

void GLWindow::timerUpdate(){
  pthread_mutex_lock(&ui_state->lock);

  ui_update_sizes(ui_state);

  check_messages(ui_state);
  if (ui_state->vision_connected){
    ui_update(ui_state);
  }
  pthread_mutex_unlock(&ui_state->lock);

  update();
}

void GLWindow::resizeGL(int w, int h) {
  std::cout << "resize " << w << "x" << h << std::endl;
}

void GLWindow::paintGL() {
  pthread_mutex_lock(&ui_state->lock);
  ui_draw(ui_state);
  pthread_mutex_unlock(&ui_state->lock);
}

void GLWindow::mousePressEvent(QMouseEvent *e) {
  // Settings button click
  if (!ui_state->scene.uilayout_sidebarcollapsed && e->x() <= sbr_w) {
    if (e->x() >= settings_btn_x && e->x() < (settings_btn_x + settings_btn_w)
        && e->y() >= settings_btn_y && e->y() < (settings_btn_y + settings_btn_h)) {
      emit openSettings();
    }
  }

  // Vision click
  if (ui_state->started && (e->x() >= ui_state->scene.ui_viz_rx - bdr_s)){
    ui_state->scene.uilayout_sidebarcollapsed = !ui_state->scene.uilayout_sidebarcollapsed;
  }

}

/* HACKS */
bool Sound::init(int volume) { return true; }
bool Sound::play(AudibleAlert alert) { printf("play sound: %d\n", (int)alert); return true; }
void Sound::stop() {}
void Sound::setVolume(int volume) {}
Sound::~Sound() {}

GLuint visionimg_to_gl(const VisionImg *img, EGLImageKHR *pkhr, void **pph) {
  unsigned int texture;
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, *pph);
  glGenerateMipmap(GL_TEXTURE_2D);
  *pkhr = (EGLImageKHR)1; // not NULL
  return texture;
}

void visionimg_destroy_gl(EGLImageKHR khr, void *ph) {
  // empty
}

FramebufferState* framebuffer_init(const char* name, int32_t layer, int alpha,
                                   int *out_w, int *out_h) {
  return (FramebufferState*)1; // not null
}
<commit_msg>add more opengl info on startup to pc ui<commit_after>#include <cassert>
#include <iostream>
#include <cmath>
#include <iostream>
#include <signal.h>

#include <QVBoxLayout>
#include <QMouseEvent>
#include <QPushButton>
#include <QGridLayout>

#include "window.hpp"
#include "settings.hpp"

#include "paint.hpp"
#include "sound.hpp"

volatile sig_atomic_t do_exit = 0;

MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
  main_layout = new QStackedLayout;

  GLWindow * glWindow = new GLWindow(this);
  main_layout->addWidget(glWindow);

  SettingsWindow * settingsWindow = new SettingsWindow(this);
  main_layout->addWidget(settingsWindow);

  main_layout->setMargin(0);
  setLayout(main_layout);
  QObject::connect(glWindow, SIGNAL(openSettings()), this, SLOT(openSettings()));
  QObject::connect(settingsWindow, SIGNAL(closeSettings()), this, SLOT(closeSettings()));

  setStyleSheet(R"(
    * {
      color: white;
      background-color: #072339;
    }
  )");
}

void MainWindow::openSettings(){
  main_layout->setCurrentIndex(1);
}

void MainWindow::closeSettings(){
  main_layout->setCurrentIndex(0);
}

GLWindow::GLWindow(QWidget *parent) : QOpenGLWidget(parent) {
  timer = new QTimer(this);
  QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()));
}

GLWindow::~GLWindow() {
  makeCurrent();
  doneCurrent();
}

void GLWindow::initializeGL() {
  initializeOpenGLFunctions();
  std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
  std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl;
  std::cout << "OpenGL renderer: " << glGetString(GL_RENDERER) << std::endl;
  std::cout << "OpenGL language version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;

  ui_state = new UIState();
  ui_init(ui_state);
  ui_state->fb_w = vwp_w;
  ui_state->fb_h = vwp_h;

  int err = pthread_create(&connect_thread_handle, NULL,
                           vision_connect_thread, ui_state);
  assert(err == 0);

  timer->start(50);
}

void GLWindow::timerUpdate(){
  pthread_mutex_lock(&ui_state->lock);

  ui_update_sizes(ui_state);

  check_messages(ui_state);
  if (ui_state->vision_connected){
    ui_update(ui_state);
  }
  pthread_mutex_unlock(&ui_state->lock);

  update();
}

void GLWindow::resizeGL(int w, int h) {
  std::cout << "resize " << w << "x" << h << std::endl;
}

void GLWindow::paintGL() {
  pthread_mutex_lock(&ui_state->lock);
  ui_draw(ui_state);
  pthread_mutex_unlock(&ui_state->lock);
}

void GLWindow::mousePressEvent(QMouseEvent *e) {
  // Settings button click
  if (!ui_state->scene.uilayout_sidebarcollapsed && e->x() <= sbr_w) {
    if (e->x() >= settings_btn_x && e->x() < (settings_btn_x + settings_btn_w)
        && e->y() >= settings_btn_y && e->y() < (settings_btn_y + settings_btn_h)) {
      emit openSettings();
    }
  }

  // Vision click
  if (ui_state->started && (e->x() >= ui_state->scene.ui_viz_rx - bdr_s)){
    ui_state->scene.uilayout_sidebarcollapsed = !ui_state->scene.uilayout_sidebarcollapsed;
  }

}

/* HACKS */
bool Sound::init(int volume) { return true; }
bool Sound::play(AudibleAlert alert) { printf("play sound: %d\n", (int)alert); return true; }
void Sound::stop() {}
void Sound::setVolume(int volume) {}
Sound::~Sound() {}

GLuint visionimg_to_gl(const VisionImg *img, EGLImageKHR *pkhr, void **pph) {
  unsigned int texture;
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, *pph);
  glGenerateMipmap(GL_TEXTURE_2D);
  *pkhr = (EGLImageKHR)1; // not NULL
  return texture;
}

void visionimg_destroy_gl(EGLImageKHR khr, void *ph) {
  // empty
}

FramebufferState* framebuffer_init(const char* name, int32_t layer, int alpha,
                                   int *out_w, int *out_h) {
  return (FramebufferState*)1; // not null
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013, William Magato
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ''AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the copyright holder(s) or contributors.
*/

#include <malloc.h>
#include <cstdlib>

#include <iostream>

#include <llamaos/memory/Memory.h>
#include <llamaos/xen/Block.h>
#include <llamaos/xen/Hypercall.h>
#include <llamaos/xen/Hypervisor.h>
#include <llamaos/xen/Xenstore.h>
#include <llamaos/Trace.h>
#include <xen/io/xenbus.h>
#include <llamaos/llamaOS.h>

// using namespace std;
using std::string;
using std::min;
using std::cout;
using std::endl;
using std::vector;

using namespace llamaos::xen;

Block::Block (const string &key)
   :  frontend_key(key),
      shared_ring(static_cast<blkif_sring_t *>(memalign (PAGE_SIZE, PAGE_SIZE))),
      _private(),
      shared_buffer(static_cast<char *>(memalign (PAGE_SIZE, PAGE_SIZE))),
      shared_ring_ref(0),
      shared_buffer_ref(0),
      port(0),
      name(""),
      dev(""),
      vdev(0),
      sector_size(0),
      sectors(0),
      size(0),
      position(0)
{
   Xenstore &xenstore = Hypervisor::get_instance ()->xenstore;

   // find the backend location
   string backend_key = xenstore.read_string(frontend_key + "/backend");
   domid_t backend_id = xenstore.read<domid_t>(frontend_key + "/backend-id");

   // wait for backend to initialize
   cout << "waiting for block backend init..." << endl;
   while (   (xenstore.read_string(backend_key + "/state") != "2")
          && (xenstore.read_string(backend_key + "/state") != "3"));

   // setup resources and share with backend
   memset (shared_ring, 0, PAGE_SIZE);
   SHARED_RING_INIT(shared_ring);
   FRONT_RING_INIT(&_private, shared_ring, PAGE_SIZE);

   shared_ring_ref = Hypervisor::get_instance ()->grant_table.grant_access (backend_id, shared_ring);

   Hypercall::event_channel_alloc_unbound (0, port);
   xenstore.write<grant_ref_t> (frontend_key + "/ring-ref", shared_ring_ref);
   xenstore.write<evtchn_port_t> (frontend_key + "/event-channel", port);

   // make this device's state XenbusStateInitWait
   xenstore.write_string(frontend_key + "/state", "3");

   // wait for backend to connect
   cout << "waiting for block backend connect..." << endl;
   while (xenstore.read_string(backend_key + "/state") != "4");

   // read block properties
   name = xenstore.read_string(backend_key + "/params").substr(4);
   dev = xenstore.read_string(backend_key + "/dev");
   vdev = xenstore.read<blkif_vdev_t>(frontend_key + "/virtual-device");
   sector_size = xenstore.read<unsigned int>(backend_key + "/sector-size");
   sectors = xenstore.read<unsigned int>(backend_key + "/sectors");
   size = sectors * sector_size;

   cout << "Block: " << name << ", " << dev << endl;
   cout << "  sector size: " << sector_size << endl;
   cout << "  sectors: " << sectors << endl;
   cout << "  total: " << size << endl;

   // make this device's state connected
   xenstore.write_string(frontend_key + "/state", "4");

   shared_buffer_ref = Hypervisor::get_instance ()->grant_table.grant_access (backend_id, shared_buffer);
}

Block::~Block ()
{

}

ssize_t Block::read (void *buf, size_t nbytes)
{
   if (nbytes < size)
   {
      cout << "buf passed to Block::read is too small." << endl;
      return -1;
   }

   for (unsigned int i = 0; i < sectors; i += 8)
   {
      blkif_request_t *request = RING_GET_REQUEST(&_private, _private.req_prod_pvt++);
      request->operation = BLKIF_OP_READ;
      request->handle = vdev;
      request->id = 0;
      request->nr_segments = 8;
      request->sector_number = i;
      request->seg [0].gref = shared_buffer_ref;
      request->seg [0].first_sect = 0;
      request->seg [0].last_sect = 7;

      RING_PUSH_REQUESTS(&_private);
      Hypercall::event_channel_send (port);

      // spin unitl response
      do { rmb(); } while (!RING_HAS_UNCONSUMED_RESPONSES(&_private));

      blkif_response_t *response = RING_GET_RESPONSE(&_private, _private.rsp_cons++);

      if (response->status == BLKIF_RSP_OKAY)
      {
         char *char_buf = static_cast<char *>(buf);
         memcpy(&char_buf[position], shared_buffer, 4096);
         position += 4096;
      }
      else
      {
         cout << response->status << " error reading block device " << name << ", sector " << i << endl;
         return -1;
      }
   }

   return size;
}
<commit_msg>fixed Block error when reading last sectors<commit_after>/*
Copyright (c) 2013, William Magato
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ''AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the copyright holder(s) or contributors.
*/

#include <malloc.h>
#include <cstdlib>

#include <iostream>

#include <llamaos/memory/Memory.h>
#include <llamaos/xen/Block.h>
#include <llamaos/xen/Hypercall.h>
#include <llamaos/xen/Hypervisor.h>
#include <llamaos/xen/Xenstore.h>
#include <llamaos/Trace.h>
#include <xen/io/xenbus.h>
#include <llamaos/llamaOS.h>

// using namespace std;
using std::string;
using std::min;
using std::cout;
using std::endl;
using std::vector;

using namespace llamaos::xen;

Block::Block (const string &key)
   :  frontend_key(key),
      shared_ring(static_cast<blkif_sring_t *>(memalign (PAGE_SIZE, PAGE_SIZE))),
      _private(),
      shared_buffer(static_cast<char *>(memalign (PAGE_SIZE, PAGE_SIZE))),
      shared_ring_ref(0),
      shared_buffer_ref(0),
      port(0),
      name(""),
      dev(""),
      vdev(0),
      sector_size(0),
      sectors(0),
      size(0),
      position(0)
{
   Xenstore &xenstore = Hypervisor::get_instance ()->xenstore;

   // find the backend location
   string backend_key = xenstore.read_string(frontend_key + "/backend");
   domid_t backend_id = xenstore.read<domid_t>(frontend_key + "/backend-id");

   // wait for backend to initialize
   cout << "waiting for block backend init..." << endl;
   while (   (xenstore.read_string(backend_key + "/state") != "2")
          && (xenstore.read_string(backend_key + "/state") != "3"));

   // setup resources and share with backend
   memset (shared_ring, 0, PAGE_SIZE);
   SHARED_RING_INIT(shared_ring);
   FRONT_RING_INIT(&_private, shared_ring, PAGE_SIZE);

   shared_ring_ref = Hypervisor::get_instance ()->grant_table.grant_access (backend_id, shared_ring);

   Hypercall::event_channel_alloc_unbound (0, port);
   xenstore.write<grant_ref_t> (frontend_key + "/ring-ref", shared_ring_ref);
   xenstore.write<evtchn_port_t> (frontend_key + "/event-channel", port);

   // make this device's state XenbusStateInitWait
   xenstore.write_string(frontend_key + "/state", "3");

   // wait for backend to connect
   cout << "waiting for block backend connect..." << endl;
   while (xenstore.read_string(backend_key + "/state") != "4");

   // read block properties
   name = xenstore.read_string(backend_key + "/params").substr(4);
   dev = xenstore.read_string(backend_key + "/dev");
   vdev = xenstore.read<blkif_vdev_t>(frontend_key + "/virtual-device");
   sector_size = xenstore.read<unsigned int>(backend_key + "/sector-size");
   sectors = xenstore.read<unsigned int>(backend_key + "/sectors");
   size = sectors * sector_size;

   cout << "Block: " << name << ", " << dev << endl;
   cout << "  sector size: " << sector_size << endl;
   cout << "  sectors: " << sectors << endl;
   cout << "  total: " << size << endl;

   // make this device's state connected
   xenstore.write_string(frontend_key + "/state", "4");

   shared_buffer_ref = Hypervisor::get_instance ()->grant_table.grant_access (backend_id, shared_buffer);
}

Block::~Block ()
{

}

ssize_t Block::read (void *buf, size_t nbytes)
{
   if (nbytes < size)
   {
      cout << "buf passed to Block::read is too small." << endl;
      return -1;
   }

   for (unsigned int i = 0; i < sectors; i += 8)
   {
      blkif_request_t *request = RING_GET_REQUEST(&_private, _private.req_prod_pvt++);
      request->operation = BLKIF_OP_READ;
      request->handle = vdev;
      request->id = 0;
      request->nr_segments = 1;
      request->sector_number = i;
      request->seg [0].gref = shared_buffer_ref;
      request->seg [0].first_sect = 0;
      request->seg [0].last_sect = 7;

      RING_PUSH_REQUESTS(&_private);
      Hypercall::event_channel_send (port);

      // spin unitl response
      do { rmb(); } while (!RING_HAS_UNCONSUMED_RESPONSES(&_private));

      blkif_response_t *response = RING_GET_RESPONSE(&_private, _private.rsp_cons++);

      if (response->status == BLKIF_RSP_OKAY)
      {
         char *char_buf = static_cast<char *>(buf);
         memcpy(&char_buf[position], shared_buffer, 4096);
         position += 4096;
      }
      else
      {
         cout << response->status << " error reading block device " << name << ", sector " << i << endl;
         return -1;
      }
   }

   return size;
}
<|endoftext|>


<commit_before>
#include "FontLoader.h"
#include "base/Texture.h"
#include "base/Font.h"
#include "base/File.h"

#include <memory.h>
#define STBTT_malloc(x,u)  malloc(x)
#define STBTT_free(x,u)    free(x)

#define STB_TRUETYPE_IMPLEMENTATION
#include "StbTrueType.cpp"

#include <stdio.h>

namespace three {

  Font * FontLoader::loadFont(const char * path, float fontSize, int textureWidth, int textureHeight)
  {
    Font * font = 0;

    unsigned char * data;
    int length;
    if (fileContent(path, &data, length))
    {
      font = new Font();
      unsigned char * image = new unsigned char[textureWidth * textureHeight];

      stbtt_bakedchar charDef[96];
      stbtt_BakeFontBitmap(data, 0, fontSize, image, textureWidth, textureHeight, 32, 96, charDef);
      delete[] data;

      // Create the texture
      Texture * texture = new Texture();
      texture->images[0] = image;
      texture->width = textureWidth;
      texture->height = textureHeight;
      texture->format = AlphaFormat;
      texture->imageDataType = UnsignedByteType;
      texture->type = Texture2D;
      font->texture = texture;

      // Copy glyph info
      for (int i = 0; i < 96; ++i)
      {
        float x = 0.0f, y = 0.0f;
        Font::Glyph & glyph = font->glyphs[i];
        stbtt_aligned_quad quad;

        stbtt_GetBakedQuad(charDef, textureWidth, textureHeight, i, &x, &y, &quad, 1);

        float offsetX = quad.x0 < 0.0f ? -quad.x0 : 0.0f;
        glyph.topLeft = Vector2(quad.x0 + offsetX, quad.y0);
        glyph.bottomRight = Vector2(quad.x1 + offsetX, quad.y1);
        glyph.uvTopLeft = Vector2(quad.s0, quad.t0);
        glyph.uvBottomRight = Vector2(quad.s1, quad.t1);
        glyph.advance = x;
      }
    }

    return font;
  }

}<commit_msg>Font texture are now created with both luminance and alpha<commit_after>
#include "FontLoader.h"
#include "base/Texture.h"
#include "base/Font.h"
#include "base/File.h"

#include <memory.h>
#define STBTT_malloc(x,u)  malloc(x)
#define STBTT_free(x,u)    free(x)

#define STB_TRUETYPE_IMPLEMENTATION
#include "StbTrueType.cpp"

#include <stdio.h>

namespace three {

  Font * FontLoader::loadFont(const char * path, float fontSize, int textureWidth, int textureHeight)
  {
    Font * font = 0;

    unsigned char * data;
    int length;
    if (fileContent(path, &data, length))
    {
      font = new Font();
      unsigned char * alpha = new unsigned char[textureWidth * textureHeight];

      stbtt_bakedchar charDef[96];
      stbtt_BakeFontBitmap(data, 0, fontSize, alpha, textureWidth, textureHeight, 32, 96, charDef);
      delete[] data;

      // Construct an luminance-alpha texture
      unsigned char * image = new unsigned char[textureWidth * textureHeight * 2];
      for (int i = 0, len = textureWidth * textureHeight; i < len; ++i)
      {
        image[i * 2 + 0] = 255;
        image[i * 2 + 1] = alpha[i];
      }

      // Create the texture
      Texture * texture = new Texture();
      texture->images[0] = image;
      texture->width = textureWidth;
      texture->height = textureHeight;
      texture->format = LuminanceAlphaFormat;
      texture->imageDataType = UnsignedByteType;
      texture->type = Texture2D;
      font->texture = texture;

      // Copy glyph info
      for (int i = 0; i < 96; ++i)
      {
        float x = 0.0f, y = 0.0f;
        Font::Glyph & glyph = font->glyphs[i];
        stbtt_aligned_quad quad;

        stbtt_GetBakedQuad(charDef, textureWidth, textureHeight, i, &x, &y, &quad, 1);

        float offsetX = quad.x0 < 0.0f ? -quad.x0 : 0.0f;
        glyph.topLeft = Vector2(quad.x0 + offsetX, quad.y0);
        glyph.bottomRight = Vector2(quad.x1 + offsetX, quad.y1);
        glyph.uvTopLeft = Vector2(quad.s0, quad.t0);
        glyph.uvBottomRight = Vector2(quad.s1, quad.t1);
        glyph.advance = x;
      }
    }

    return font;
  }

}<|endoftext|>


<commit_before>/*
    Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
    Copyright (C) 2013 basysKom GmbH <info@basyskom.com>
    Copyright (C) 2013 Collabora Ltd. <info@collabora.com>

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 2.1
    as published by the Free Software Foundation.

    This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file
 *   @brief Extracted from QtGstreamer to avoid overly complex dependency
 *   @author Gus Grubba <mavlink@grubba.com>
 */

#include "videonode.h"
#include "videomaterial.h"

#include <QtQuick/QSGFlatColorMaterial>

VideoNode::VideoNode()
  : QSGGeometryNode()
{
    setFlags(OwnsGeometry | OwnsMaterial, true);
    setMaterialTypeSolidBlack();
}

void VideoNode::changeFormat(const BufferFormat & format)
{
    setMaterial(VideoMaterial::create(format));
    setGeometry(0);
    m_materialType = MaterialTypeVideo;
}

void VideoNode::setMaterialTypeSolidBlack()
{
    QSGFlatColorMaterial *m = new QSGFlatColorMaterial;
    m->setColor(Qt::black);
    setMaterial(m);
    setGeometry(0);
    m_materialType = MaterialTypeSolidBlack;
}

void VideoNode::setCurrentFrame(GstBuffer* buffer)
{
    Q_ASSERT (m_materialType == MaterialTypeVideo);
    static_cast<VideoMaterial*>(material())->setCurrentFrame(buffer);
    markDirty(DirtyMaterial);
}

void VideoNode::updateColors(int brightness, int contrast, int hue, int saturation)
{
    Q_ASSERT (m_materialType == MaterialTypeVideo);
    static_cast<VideoMaterial*>(material())->updateColors(brightness, contrast, hue, saturation);
    markDirty(DirtyMaterial);
}

/* Helpers */
template <typename V>
static inline void setGeom(V *v, const QPointF &p)
{
    v->x = p.x();
    v->y = p.y();
}

static inline void setTex(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
{
    v->tx = p.x();
    v->ty = p.y();
}

void VideoNode::updateGeometry(const PaintAreas & areas)
{
    QSGGeometry *g = geometry();

    if (m_materialType == MaterialTypeVideo) {
        if (!g)
            g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);

        QSGGeometry::TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();

        // Set geometry first
        setGeom(v + 0, areas.videoArea.topLeft());
        setGeom(v + 1, areas.videoArea.bottomLeft());
        setGeom(v + 2, areas.videoArea.topRight());
        setGeom(v + 3, areas.videoArea.bottomRight());

        // and then texture coordinates
        setTex(v + 0, areas.sourceRect.topLeft());
        setTex(v + 1, areas.sourceRect.bottomLeft());
        setTex(v + 2, areas.sourceRect.topRight());
        setTex(v + 3, areas.sourceRect.bottomRight());
    } else {
        if (!g)
            g = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);

        QSGGeometry::Point2D *v = g->vertexDataAsPoint2D();

        setGeom(v + 0, areas.videoArea.topLeft());
        setGeom(v + 1, areas.videoArea.bottomLeft());
        setGeom(v + 2, areas.videoArea.topRight());
        setGeom(v + 3, areas.videoArea.bottomRight());
    }

    if (!geometry())
        setGeometry(g);

    markDirty(DirtyGeometry);
}
<commit_msg>videonode: Do not finish if material is different<commit_after>/*
    Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
    Copyright (C) 2013 basysKom GmbH <info@basyskom.com>
    Copyright (C) 2013 Collabora Ltd. <info@collabora.com>

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 2.1
    as published by the Free Software Foundation.

    This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file
 *   @brief Extracted from QtGstreamer to avoid overly complex dependency
 *   @author Gus Grubba <mavlink@grubba.com>
 */

#include "videonode.h"
#include "videomaterial.h"

#include <QtQuick/QSGFlatColorMaterial>

VideoNode::VideoNode()
  : QSGGeometryNode()
{
    setFlags(OwnsGeometry | OwnsMaterial, true);
    setMaterialTypeSolidBlack();
}

void VideoNode::changeFormat(const BufferFormat & format)
{
    setMaterial(VideoMaterial::create(format));
    setGeometry(0);
    m_materialType = MaterialTypeVideo;
}

void VideoNode::setMaterialTypeSolidBlack()
{
    QSGFlatColorMaterial *m = new QSGFlatColorMaterial;
    m->setColor(Qt::black);
    setMaterial(m);
    setGeometry(0);
    m_materialType = MaterialTypeSolidBlack;
}

void VideoNode::setCurrentFrame(GstBuffer* buffer)
{
    if (m_materialType != MaterialTypeVideo) {
        return;
    }
    static_cast<VideoMaterial*>(material())->setCurrentFrame(buffer);
    markDirty(DirtyMaterial);
}

void VideoNode::updateColors(int brightness, int contrast, int hue, int saturation)
{
    if (m_materialType != MaterialTypeVideo) {
        return;
    }
    static_cast<VideoMaterial*>(material())->updateColors(brightness, contrast, hue, saturation);
    markDirty(DirtyMaterial);
}

/* Helpers */
template <typename V>
static inline void setGeom(V *v, const QPointF &p)
{
    v->x = p.x();
    v->y = p.y();
}

static inline void setTex(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
{
    v->tx = p.x();
    v->ty = p.y();
}

void VideoNode::updateGeometry(const PaintAreas & areas)
{
    QSGGeometry *g = geometry();

    if (m_materialType == MaterialTypeVideo) {
        if (!g)
            g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);

        QSGGeometry::TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();

        // Set geometry first
        setGeom(v + 0, areas.videoArea.topLeft());
        setGeom(v + 1, areas.videoArea.bottomLeft());
        setGeom(v + 2, areas.videoArea.topRight());
        setGeom(v + 3, areas.videoArea.bottomRight());

        // and then texture coordinates
        setTex(v + 0, areas.sourceRect.topLeft());
        setTex(v + 1, areas.sourceRect.bottomLeft());
        setTex(v + 2, areas.sourceRect.topRight());
        setTex(v + 3, areas.sourceRect.bottomRight());
    } else {
        if (!g)
            g = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);

        QSGGeometry::Point2D *v = g->vertexDataAsPoint2D();

        setGeom(v + 0, areas.videoArea.topLeft());
        setGeom(v + 1, areas.videoArea.bottomLeft());
        setGeom(v + 2, areas.videoArea.topRight());
        setGeom(v + 3, areas.videoArea.bottomRight());
    }

    if (!geometry())
        setGeometry(g);

    markDirty(DirtyGeometry);
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2019 Google LLC.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *      Implementation for the Weave Device Layer Network Telemetry object.
 *
 */

#include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>

#if WEAVE_DEVICE_CONFIG_ENABLE_NETWORK_TELEMETRY

#include <Weave/DeviceLayer/NetworkTelemetryManager.h>

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY
#include <Weave/DeviceLayer/ThreadStackManager.h>
#endif

#if WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY
#include <Weave/Support/TraitEventUtils.h>
#include <Weave/DeviceLayer/internal/ServiceTunnelAgent.h>
#include <Weave/Profiles/weave-tunneling/WeaveTunnelAgent.h>
#include <weave/trait/telemetry/tunnel/TelemetryTunnelTrait.h>
#endif

using namespace nl::Weave::DeviceLayer;
using namespace nl::Weave::DeviceLayer::Internal;

NetworkTelemetryManager NetworkTelemetryManager::sInstance;

WeaveTelemetryBase::WeaveTelemetryBase()
{
}

void WeaveTelemetryBase::Init(uint32_t aIntervalMsec)
{
    SetPollingInterval(aIntervalMsec);
    Enable();
}

void WeaveTelemetryBase::Enable(void)
{
    mEnabled = true;
    StartPollingTimer();
}

void WeaveTelemetryBase::Disable(void)
{
    mEnabled = false;
    StopPollingTimer();
}

void WeaveTelemetryBase::StartPollingTimer(void)
{
    SystemLayer.StartTimer(mInterval, sHandleTimer, this);
}

void WeaveTelemetryBase::StopPollingTimer(void)
{
    SystemLayer.CancelTimer(sHandleTimer, this);
}

void WeaveTelemetryBase::HandleTimer(void)
{
    GetTelemetryStatsAndLogEvent();

    StartPollingTimer();
}

NetworkTelemetryManager::NetworkTelemetryManager(void)
{
}

WEAVE_ERROR NetworkTelemetryManager::Init(void)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;

    WeaveLogProgress(DeviceLayer, "Initiating Network Telemetry & Topology\n");

#if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY
    mWiFiTelemetry.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS);
#endif

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY
    mThreadTelemetry.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS);
    mThreadTopology.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS);
#endif

#if WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY
    mTunnelTelemetry.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TUNNEL_TELEMETRY_INTERVAL_MS);
#endif

    return err;
}

#if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY
void WiFiTelemetry::GetTelemetryStatsAndLogEvent(void)
{
    WEAVE_ERROR err;

    err = ConnectivityMgr().GetAndLogWifiStatsCounters();
    SuccessOrExit(err);

exit:
    return;
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY
void ThreadTelemetry::GetTelemetryStatsAndLogEvent(void)
{
    WEAVE_ERROR err;

    err = ThreadStackMgr().GetAndLogThreadStatsCounters();
    SuccessOrExit(err);

exit:
    return;
}

void ThreadTopology::GetTelemetryStatsAndLogEvent(void)
{
    WEAVE_ERROR err;

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY_FULL
    err = ThreadStackMgr().GetAndLogThreadTopologyFull();
    SuccessOrExit(err);
#else
    err = ThreadStackMgr().GetAndLogThreadTopologyMinimal();
    SuccessOrExit(err);
#endif

exit:
    return;
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY

#if WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY
void TunnelTelemetry::GetTelemetryStatsAndLogEvent(void)
{
    nl::Weave::Profiles::DataManagement_Current::event_id_t eventId;
    nl::Weave::Profiles::WeaveTunnel::WeaveTunnelStatistics tunnelStats;
    Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TelemetryTunnelStatsEvent statsEvent;

    ServiceTunnelAgent.GetWeaveTunnelStatistics(tunnelStats);

    statsEvent.txBytesToService       = tunnelStats.mPrimaryStats.mTxBytesToService;
    statsEvent.rxBytesFromService     = tunnelStats.mPrimaryStats.mRxBytesFromService;
    statsEvent.txMessagesToService    = tunnelStats.mPrimaryStats.mTxMessagesToService;
    statsEvent.rxMessagesFromService  = tunnelStats.mPrimaryStats.mRxMessagesFromService;
    statsEvent.tunnelDownCount        = tunnelStats.mPrimaryStats.mTunnelDownCount;
    statsEvent.tunnelConnAttemptCount = tunnelStats.mPrimaryStats.mTunnelConnAttemptCount;

    statsEvent.lastTimeTunnelWentDown    = tunnelStats.mPrimaryStats.mLastTimeTunnelWentDown;
    statsEvent.lastTimeTunnelEstablished = tunnelStats.mPrimaryStats.mLastTimeTunnelEstablished;

    statsEvent.droppedMessagesCount = tunnelStats.mDroppedMessagesCount;

    switch (ServiceTunnelAgent.GetWeaveTunnelAgentState())
    {
    case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_Initialized_NoTunnel:
        statsEvent.currentTunnelState = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_NO_TUNNEL;
        break;
    case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_PrimaryTunModeEstablished:
        statsEvent.currentTunnelState = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_PRIMARY_ESTABLISHED;
        break;
    case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_BkupOnlyTunModeEstablished:
        statsEvent.currentTunnelState =
            Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_BACKUP_ONLY_ESTABLISHED;
        break;
    case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_PrimaryAndBkupTunModeEstablished:
        statsEvent.currentTunnelState =
            Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_PRIMARY_AND_BACKUP_ESTABLISHED;
        break;
    default:
        break;
    }

    switch (tunnelStats.mCurrentActiveTunnel)
    {
    case nl::Weave::Profiles::WeaveTunnel::kType_TunnelUnknown:
        statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_NONE;
        break;
    case nl::Weave::Profiles::WeaveTunnel::kType_TunnelPrimary:
        statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_PRIMARY;
        break;
    case nl::Weave::Profiles::WeaveTunnel::kType_TunnelBackup:
        statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_BACKUP;
        break;
    case nl::Weave::Profiles::WeaveTunnel::kType_TunnelShortcut:
        statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_SHORTCUT;
        break;
    default:
        break;
    }

    WeaveLogProgress(DeviceLayer,
                     "Weave Tunnel Counters\n"
                     "Tx Messages:                   %d\n"
                     "Rx Messages:                   %d\n"
                     "Tunnel Down Count:             %d\n"
                     "Tunnel Conn Attempt Count:     %d\n"
                     "Tunnel State:                  %d\n"
                     "CurrentActiveTunnel:           %d\n",
                     statsEvent.txMessagesToService, statsEvent.rxMessagesFromService, statsEvent.tunnelDownCount, statsEvent.tunnelConnAttemptCount,
                     statsEvent.currentTunnelState, statsEvent.currentActiveTunnel);

    WeaveLogProgress(DeviceLayer,
                     "Weave Tunnel Time Stamps\n"
                     "LastTime TunnelWentDown:       %" PRIu64 "\n"
                     "LastTime TunnelEstablished:    %" PRIu64 "\n",
                     statsEvent.lastTimeTunnelWentDown, statsEvent.lastTimeTunnelEstablished);

    eventId = nl::LogEvent(&statsEvent);
    WeaveLogProgress(DeviceLayer, "Weave Tunnel Tolopoly Stats Event Id: %u\n", eventId);

    return;
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY

#endif // WEAVE_DEVICE_CONFIG_ENABLE_NETWORK_TELEMETRY
<commit_msg>Fix a bug in network telemetry manager<commit_after>/*
 *
 *    Copyright (c) 2019 Google LLC.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 *    @file
 *      Implementation for the Weave Device Layer Network Telemetry object.
 *
 */

#include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>

#if WEAVE_DEVICE_CONFIG_ENABLE_NETWORK_TELEMETRY

#include <Weave/DeviceLayer/NetworkTelemetryManager.h>

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY
#include <Weave/DeviceLayer/ThreadStackManager.h>
#endif

#if WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY
#include <Weave/Support/TraitEventUtils.h>
#include <Weave/DeviceLayer/internal/ServiceTunnelAgent.h>
#include <Weave/Profiles/weave-tunneling/WeaveTunnelAgent.h>
#include <weave/trait/telemetry/tunnel/TelemetryTunnelTrait.h>
#endif

using namespace nl::Weave::DeviceLayer;
using namespace nl::Weave::DeviceLayer::Internal;

NetworkTelemetryManager NetworkTelemetryManager::sInstance;

WeaveTelemetryBase::WeaveTelemetryBase()
{
    mEnabled = false;
}

void WeaveTelemetryBase::Init(uint32_t aIntervalMsec)
{
    SetPollingInterval(aIntervalMsec);
    Enable();
}

void WeaveTelemetryBase::Enable(void)
{
    mEnabled = true;
    StartPollingTimer();
}

void WeaveTelemetryBase::Disable(void)
{
    mEnabled = false;
    StopPollingTimer();
}

void WeaveTelemetryBase::StartPollingTimer(void)
{
    SystemLayer.StartTimer(mInterval, sHandleTimer, this);
}

void WeaveTelemetryBase::StopPollingTimer(void)
{
    SystemLayer.CancelTimer(sHandleTimer, this);
}

void WeaveTelemetryBase::HandleTimer(void)
{
    GetTelemetryStatsAndLogEvent();

    StartPollingTimer();
}

NetworkTelemetryManager::NetworkTelemetryManager(void)
{
}

WEAVE_ERROR NetworkTelemetryManager::Init(void)
{
    WEAVE_ERROR err = WEAVE_NO_ERROR;

    WeaveLogProgress(DeviceLayer, "Initiating Network Telemetry & Topology");

#if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY
    mWiFiTelemetry.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS);
#endif

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY
    mThreadTelemetry.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS);
    mThreadTopology.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS);
#endif

#if WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY
    mTunnelTelemetry.Init(WEAVE_DEVICE_CONFIG_DEFAULT_TUNNEL_TELEMETRY_INTERVAL_MS);
#endif

    return err;
}

#if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY
void WiFiTelemetry::GetTelemetryStatsAndLogEvent(void)
{
    WEAVE_ERROR err;

    if (ConnectivityMgr().IsWiFiStationProvisioned() &&
        ConnectivityMgr().IsWiFiStationEnabled() &&
        ConfigurationMgr().IsPairedToAccount())
    {
        err = ConnectivityMgr().GetAndLogWifiStatsCounters();
        SuccessOrExit(err);
    }

exit:
    return;
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY
void ThreadTelemetry::GetTelemetryStatsAndLogEvent(void)
{
    WEAVE_ERROR err;

    if (ConnectivityMgr().IsThreadProvisioned() &&
        ConnectivityMgr().IsThreadEnabled() &&
        ConfigurationMgr().IsPairedToAccount())
    {
        err = ThreadStackMgr().GetAndLogThreadStatsCounters();
        SuccessOrExit(err);
    }

exit:
    return;
}

void ThreadTopology::GetTelemetryStatsAndLogEvent(void)
{
    WEAVE_ERROR err;

    if (ConnectivityMgr().IsThreadProvisioned() &&
        ConnectivityMgr().IsThreadEnabled() &&
        ConfigurationMgr().IsPairedToAccount())
    {
#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY_FULL
        err = ThreadStackMgr().GetAndLogThreadTopologyFull();
        SuccessOrExit(err);
#else
        err = ThreadStackMgr().GetAndLogThreadTopologyMinimal();
        SuccessOrExit(err);
#endif
    }

exit:
    return;
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY

#if WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY
void TunnelTelemetry::GetTelemetryStatsAndLogEvent(void)
{
    if (ConnectivityMgr().GetServiceTunnelMode() == ConnectivityManager::kServiceTunnelMode_Enabled &&
        ConfigurationMgr().IsPairedToAccount())
    {
        nl::Weave::Profiles::DataManagement_Current::event_id_t eventId;
        nl::Weave::Profiles::WeaveTunnel::WeaveTunnelStatistics tunnelStats;
        Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TelemetryTunnelStatsEvent statsEvent;

        ServiceTunnelAgent.GetWeaveTunnelStatistics(tunnelStats);

        statsEvent.txBytesToService       = tunnelStats.mPrimaryStats.mTxBytesToService;
        statsEvent.rxBytesFromService     = tunnelStats.mPrimaryStats.mRxBytesFromService;
        statsEvent.txMessagesToService    = tunnelStats.mPrimaryStats.mTxMessagesToService;
        statsEvent.rxMessagesFromService  = tunnelStats.mPrimaryStats.mRxMessagesFromService;
        statsEvent.tunnelDownCount        = tunnelStats.mPrimaryStats.mTunnelDownCount;
        statsEvent.tunnelConnAttemptCount = tunnelStats.mPrimaryStats.mTunnelConnAttemptCount;

        statsEvent.lastTimeTunnelWentDown    = tunnelStats.mPrimaryStats.mLastTimeTunnelWentDown;
        statsEvent.lastTimeTunnelEstablished = tunnelStats.mPrimaryStats.mLastTimeTunnelEstablished;

        statsEvent.droppedMessagesCount = tunnelStats.mDroppedMessagesCount;

        switch (ServiceTunnelAgent.GetWeaveTunnelAgentState())
        {
        case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_Initialized_NoTunnel:
            statsEvent.currentTunnelState = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_NO_TUNNEL;
            break;
        case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_PrimaryTunModeEstablished:
            statsEvent.currentTunnelState = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_PRIMARY_ESTABLISHED;
            break;
        case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_BkupOnlyTunModeEstablished:
            statsEvent.currentTunnelState =
                Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_BACKUP_ONLY_ESTABLISHED;
            break;
        case nl::Weave::Profiles::WeaveTunnel::WeaveTunnelAgent::kState_PrimaryAndBkupTunModeEstablished:
            statsEvent.currentTunnelState =
                Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_STATE_PRIMARY_AND_BACKUP_ESTABLISHED;
            break;
        default:
            break;
        }

        switch (tunnelStats.mCurrentActiveTunnel)
        {
        case nl::Weave::Profiles::WeaveTunnel::kType_TunnelUnknown:
            statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_NONE;
            break;
        case nl::Weave::Profiles::WeaveTunnel::kType_TunnelPrimary:
            statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_PRIMARY;
            break;
        case nl::Weave::Profiles::WeaveTunnel::kType_TunnelBackup:
            statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_BACKUP;
            break;
        case nl::Weave::Profiles::WeaveTunnel::kType_TunnelShortcut:
            statsEvent.currentActiveTunnel = Schema::Weave::Trait::Telemetry::Tunnel::TelemetryTunnelTrait::TUNNEL_TYPE_SHORTCUT;
            break;
        default:
            break;
        }

        WeaveLogProgress(DeviceLayer,
                         "Weave Tunnel Counters\n"
                         "Tx Messages:                   %d\n"
                         "Rx Messages:                   %d\n"
                         "Tunnel Down Count:             %d\n"
                         "Tunnel Conn Attempt Count:     %d\n"
                         "Tunnel State:                  %d\n"
                         "CurrentActiveTunnel:           %d\n",
                         statsEvent.txMessagesToService, statsEvent.rxMessagesFromService, statsEvent.tunnelDownCount, statsEvent.tunnelConnAttemptCount,
                         statsEvent.currentTunnelState, statsEvent.currentActiveTunnel);

        WeaveLogProgress(DeviceLayer,
                         "Weave Tunnel Time Stamps\n"
                         "LastTime TunnelWentDown:       %" PRIu64 "\n"
                         "LastTime TunnelEstablished:    %" PRIu64 "\n",
                         statsEvent.lastTimeTunnelWentDown, statsEvent.lastTimeTunnelEstablished);

        eventId = nl::LogEvent(&statsEvent);
        WeaveLogProgress(DeviceLayer, "Weave Tunnel Tolopoly Stats Event Id: %u\n", eventId);
    }

    return;
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_TUNNEL_TELEMETRY

#endif // WEAVE_DEVICE_CONFIG_ENABLE_NETWORK_TELEMETRY
<|endoftext|>