<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/app_list_controller.h"

#include "ash/ash_switches.h"
#include "ash/launcher/launcher.h"
#include "ash/root_window_controller.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "base/command_line.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/pagination_model.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/base/events/event.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/transform_util.h"
#include "ui/views/widget/widget.h"

namespace ash {
namespace internal {

namespace {

// Duration for show/hide animation in milliseconds.
const int kAnimationDurationMs = 200;

// Offset in pixels to animation away/towards the launcher.
const int kAnimationOffset = 8;

// The maximum shift in pixels when over-scroll happens.
const int kMaxOverScrollShift = 48;

// The minimal anchor position offset to make sure that the bubble is still on
// the screen with 8 pixels spacing on the left / right. This constant is a
// result of minimal bubble arrow sizes and offsets.
const int kMinimalAnchorPositionOffset = 57;

ui::Layer* GetLayer(views::Widget* widget) {
  return widget->GetNativeView()->layer();
}

// Gets arrow location based on shelf alignment.
views::BubbleBorder::Arrow GetBubbleArrow(aura::Window* window) {
  DCHECK(Shell::HasInstance());
  return ShelfLayoutManager::ForLauncher(window)->
      SelectValueForShelfAlignment(
          views::BubbleBorder::BOTTOM_CENTER,
          views::BubbleBorder::LEFT_CENTER,
          views::BubbleBorder::RIGHT_CENTER,
          views::BubbleBorder::TOP_CENTER);
}

// Offset given |rect| towards shelf.
gfx::Rect OffsetTowardsShelf(const gfx::Rect& rect, views::Widget* widget) {
  DCHECK(Shell::HasInstance());
  ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(
      widget->GetNativeView()->GetRootWindow());
  gfx::Rect offseted(rect);
  switch (shelf_alignment) {
    case SHELF_ALIGNMENT_BOTTOM:
      offseted.Offset(0, kAnimationOffset);
      break;
    case SHELF_ALIGNMENT_LEFT:
      offseted.Offset(-kAnimationOffset, 0);
      break;
    case SHELF_ALIGNMENT_RIGHT:
      offseted.Offset(kAnimationOffset, 0);
      break;
    case SHELF_ALIGNMENT_TOP:
      offseted.Offset(0, -kAnimationOffset);
      break;
  }

  return offseted;
}

// Using |button_bounds|, determine the anchor offset so that the bubble gets
// shown above the shelf (used for the alternate shelf theme).
gfx::Vector2d GetAnchorPositionOffsetToShelf(
    const gfx::Rect& button_bounds, views::Widget* widget) {
  DCHECK(Shell::HasInstance());
  ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(
      widget->GetNativeView()->GetRootWindow());
  gfx::Point anchor(button_bounds.CenterPoint());
  switch (shelf_alignment) {
    case SHELF_ALIGNMENT_TOP:
    case SHELF_ALIGNMENT_BOTTOM:
      if (base::i18n::IsRTL()) {
        int screen_width = widget->GetWorkAreaBoundsInScreen().width();
        return gfx::Vector2d(
            std::min(screen_width - kMinimalAnchorPositionOffset - anchor.x(),
                     0), 0);
      }
      return gfx::Vector2d(
          std::max(kMinimalAnchorPositionOffset - anchor.x(), 0), 0);
    case SHELF_ALIGNMENT_LEFT:
      return gfx::Vector2d(
          0, std::max(kMinimalAnchorPositionOffset - anchor.y(), 0));
    case SHELF_ALIGNMENT_RIGHT:
      return gfx::Vector2d(
          0, std::max(kMinimalAnchorPositionOffset - anchor.y(), 0));
    default:
      NOTREACHED();
      return gfx::Vector2d();
  }
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// AppListController, public:

AppListController::AppListController()
    : pagination_model_(new app_list::PaginationModel),
      is_visible_(false),
      view_(NULL),
      should_snap_back_(false) {
  Shell::GetInstance()->AddShellObserver(this);
  pagination_model_->AddObserver(this);
}

AppListController::~AppListController() {
  // Ensures app list view goes before the controller since pagination model
  // lives in the controller and app list view would access it on destruction.
  if (view_ && view_->GetWidget())
    view_->GetWidget()->CloseNow();

  Shell::GetInstance()->RemoveShellObserver(this);
  pagination_model_->RemoveObserver(this);
}

void AppListController::SetVisible(bool visible, aura::Window* window) {
  if (visible == is_visible_)
    return;

  is_visible_ = visible;

  // App list needs to know the new shelf layout in order to calculate its
  // UI layout when AppListView visibility changes.
  Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
      UpdateAutoHideState();

  if (view_) {
    ScheduleAnimation();
  } else if (is_visible_) {
    // AppListModel and AppListViewDelegate are owned by AppListView. They
    // will be released with AppListView on close.
    app_list::AppListView* view = new app_list::AppListView(
        Shell::GetInstance()->delegate()->CreateAppListViewDelegate());
    aura::Window* container = GetRootWindowController(window->GetRootWindow())->
        GetContainer(kShellWindowId_AppListContainer);
    if (ash::switches::UseAlternateShelfLayout()) {
      gfx::Rect applist_button_bounds = Launcher::ForWindow(container)->
          GetAppListButtonView()->GetBoundsInScreen();
      view->InitAsBubbleAttachedToAnchor(
          container,
          pagination_model_.get(),
          Launcher::ForWindow(container)->GetAppListButtonView(),
          GetAnchorPositionOffsetToShelf(applist_button_bounds,
              Launcher::ForWindow(container)->GetAppListButtonView()->
                  GetWidget()),
          GetBubbleArrow(container),
          true /* border_accepts_events */);
      view->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
    } else {
      view->InitAsBubbleAttachedToAnchor(
          container,
          pagination_model_.get(),
          Launcher::ForWindow(container)->GetAppListButtonView(),
          gfx::Vector2d(),
          GetBubbleArrow(container),
          true /* border_accepts_events */);
    }
    SetView(view);
    // By setting us as DnD recipient, the app list knows that we can
    // handle items.
    if (!CommandLine::ForCurrentProcess()->HasSwitch(
            ash::switches::kAshDisableDragAndDropAppListToLauncher)) {
      SetDragAndDropHostOfCurrentAppList(
          Launcher::ForWindow(window)->GetDragAndDropHostForAppList());
    }
  }
}

bool AppListController::IsVisible() const {
  return view_ && view_->GetWidget()->IsVisible();
}

aura::Window* AppListController::GetWindow() {
  return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL;
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, private:

void AppListController::SetDragAndDropHostOfCurrentAppList(
    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
  if (view_ && is_visible_)
    view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
}

void AppListController::SetView(app_list::AppListView* view) {
  DCHECK(view_ == NULL);
  DCHECK(is_visible_);

  view_ = view;
  views::Widget* widget = view_->GetWidget();
  widget->AddObserver(this);
  Shell::GetInstance()->AddPreTargetHandler(this);
  Launcher::ForWindow(widget->GetNativeWindow())->AddIconObserver(this);
  widget->GetNativeView()->GetRootWindow()->AddObserver(this);
  aura::client::GetFocusClient(widget->GetNativeView())->AddObserver(this);

  view_->ShowWhenReady();
}

void AppListController::ResetView() {
  if (!view_)
    return;

  views::Widget* widget = view_->GetWidget();
  widget->RemoveObserver(this);
  GetLayer(widget)->GetAnimator()->RemoveObserver(this);
  Shell::GetInstance()->RemovePreTargetHandler(this);
  Launcher::ForWindow(widget->GetNativeWindow())->RemoveIconObserver(this);
  widget->GetNativeView()->GetRootWindow()->RemoveObserver(this);
  aura::client::GetFocusClient(widget->GetNativeView())->RemoveObserver(this);
  view_ = NULL;
}

void AppListController::ScheduleAnimation() {
  // Stop observing previous animation.
  StopObservingImplicitAnimations();

  views::Widget* widget = view_->GetWidget();
  ui::Layer* layer = GetLayer(widget);
  layer->GetAnimator()->StopAnimating();

  gfx::Rect target_bounds;
  if (is_visible_) {
    target_bounds = widget->GetWindowBoundsInScreen();
    widget->SetBounds(OffsetTowardsShelf(target_bounds, widget));
  } else {
    target_bounds = OffsetTowardsShelf(widget->GetWindowBoundsInScreen(),
                                       widget);
  }

  ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
  animation.SetTransitionDuration(
      base::TimeDelta::FromMilliseconds(
          is_visible_ ? 0 : kAnimationDurationMs));
  animation.AddObserver(this);

  layer->SetOpacity(is_visible_ ? 1.0 : 0.0);
  widget->SetBounds(target_bounds);
}

void AppListController::ProcessLocatedEvent(ui::LocatedEvent* event) {
  // If the event happened on a menu, then the event should not close the app
  // list.
  aura::Window* target = static_cast<aura::Window*>(event->target());
  if (target) {
    RootWindowController* root_controller =
        GetRootWindowController(target->GetRootWindow());
    if (root_controller) {
      aura::Window* menu_container = root_controller->GetContainer(
          ash::internal::kShellWindowId_MenuContainer);
      if (menu_container->Contains(target))
        return;
    }
  }

  if (view_ && is_visible_) {
    aura::Window* window = view_->GetWidget()->GetNativeView();
    gfx::Point window_local_point(event->root_location());
    aura::Window::ConvertPointToTarget(window->GetRootWindow(),
                                       window,
                                       &window_local_point);
    // Use HitTest to respect the hit test mask of the bubble.
    if (!window->HitTest(window_local_point))
      SetVisible(false, window);
  }
}

void AppListController::UpdateBounds() {
  if (view_ && is_visible_)
    view_->UpdateBounds();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, aura::EventFilter implementation:

void AppListController::OnMouseEvent(ui::MouseEvent* event) {
  if (event->type() == ui::ET_MOUSE_PRESSED)
    ProcessLocatedEvent(event);
}

void AppListController::OnGestureEvent(ui::GestureEvent* event) {
  if (event->type() == ui::ET_GESTURE_TAP_DOWN)
    ProcessLocatedEvent(event);
}

////////////////////////////////////////////////////////////////////////////////
// AppListController,  aura::FocusObserver implementation:

void AppListController::OnWindowFocused(aura::Window* gained_focus,
                                        aura::Window* lost_focus) {
  if (gained_focus && view_ && is_visible_) {
    aura::Window* applist_container =
        GetRootWindowController(gained_focus->GetRootWindow())->GetContainer(
            kShellWindowId_AppListContainer);
    if (gained_focus->parent() != applist_container)
      SetVisible(false, gained_focus);
  }
}

////////////////////////////////////////////////////////////////////////////////
// AppListController,  aura::WindowObserver implementation:
void AppListController::OnWindowBoundsChanged(aura::Window* root,
                                              const gfx::Rect& old_bounds,
                                              const gfx::Rect& new_bounds) {
  UpdateBounds();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, ui::ImplicitAnimationObserver implementation:

void AppListController::OnImplicitAnimationsCompleted() {
  if (is_visible_ )
    view_->GetWidget()->Activate();
  else
    view_->GetWidget()->Close();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, views::WidgetObserver implementation:

void AppListController::OnWidgetDestroying(views::Widget* widget) {
  DCHECK(view_->GetWidget() == widget);
  if (is_visible_)
    SetVisible(false, widget->GetNativeView());
  ResetView();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, ShellObserver implementation:
void AppListController::OnShelfAlignmentChanged(aura::RootWindow* root_window) {
  if (view_)
    view_->SetBubbleArrow(GetBubbleArrow(view_->GetWidget()->GetNativeView()));
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, LauncherIconObserver implementation:

void AppListController::OnLauncherIconPositionsChanged() {
  UpdateBounds();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, PaginationModelObserver implementation:

void AppListController::TotalPagesChanged() {
}

void AppListController::SelectedPageChanged(int old_selected,
                                            int new_selected) {
}

void AppListController::TransitionStarted() {
}

void AppListController::TransitionChanged() {
  // |view_| could be NULL when app list is closed with a running transition.
  if (!view_)
    return;

  const app_list::PaginationModel::Transition& transition =
      pagination_model_->transition();
  if (pagination_model_->is_valid_page(transition.target_page))
    return;

  views::Widget* widget = view_->GetWidget();
  ui::LayerAnimator* widget_animator = GetLayer(widget)->GetAnimator();
  if (!pagination_model_->IsRevertingCurrentTransition()) {
    // Update cached |view_bounds_| if it is the first over-scroll move and
    // widget does not have running animations.
    if (!should_snap_back_ && !widget_animator->is_animating())
      view_bounds_ = widget->GetWindowBoundsInScreen();

    const int current_page = pagination_model_->selected_page();
    const int dir = transition.target_page > current_page ? -1 : 1;

    const double progress = 1.0 - pow(1.0 - transition.progress, 4);
    const int shift = kMaxOverScrollShift * progress * dir;

    gfx::Rect shifted(view_bounds_);
    shifted.set_x(shifted.x() + shift);
    widget->SetBounds(shifted);
    should_snap_back_ = true;
  } else if (should_snap_back_) {
    should_snap_back_ = false;
    ui::ScopedLayerAnimationSettings animation(widget_animator);
    animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
        app_list::kOverscrollPageTransitionDurationMs));
    widget->SetBounds(view_bounds_);
  }
}

}  // namespace internal
}  // namespace ash
<commit_msg>[ash] Update applist button status when applist is hiding by outside event of applist button.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/app_list_controller.h"

#include "ash/ash_switches.h"
#include "ash/launcher/launcher.h"
#include "ash/root_window_controller.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "base/command_line.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/pagination_model.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/base/events/event.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/transform_util.h"
#include "ui/views/widget/widget.h"

namespace ash {
namespace internal {

namespace {

// Duration for show/hide animation in milliseconds.
const int kAnimationDurationMs = 200;

// Offset in pixels to animation away/towards the launcher.
const int kAnimationOffset = 8;

// The maximum shift in pixels when over-scroll happens.
const int kMaxOverScrollShift = 48;

// The minimal anchor position offset to make sure that the bubble is still on
// the screen with 8 pixels spacing on the left / right. This constant is a
// result of minimal bubble arrow sizes and offsets.
const int kMinimalAnchorPositionOffset = 57;

ui::Layer* GetLayer(views::Widget* widget) {
  return widget->GetNativeView()->layer();
}

// Gets arrow location based on shelf alignment.
views::BubbleBorder::Arrow GetBubbleArrow(aura::Window* window) {
  DCHECK(Shell::HasInstance());
  return ShelfLayoutManager::ForLauncher(window)->
      SelectValueForShelfAlignment(
          views::BubbleBorder::BOTTOM_CENTER,
          views::BubbleBorder::LEFT_CENTER,
          views::BubbleBorder::RIGHT_CENTER,
          views::BubbleBorder::TOP_CENTER);
}

// Offset given |rect| towards shelf.
gfx::Rect OffsetTowardsShelf(const gfx::Rect& rect, views::Widget* widget) {
  DCHECK(Shell::HasInstance());
  ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(
      widget->GetNativeView()->GetRootWindow());
  gfx::Rect offseted(rect);
  switch (shelf_alignment) {
    case SHELF_ALIGNMENT_BOTTOM:
      offseted.Offset(0, kAnimationOffset);
      break;
    case SHELF_ALIGNMENT_LEFT:
      offseted.Offset(-kAnimationOffset, 0);
      break;
    case SHELF_ALIGNMENT_RIGHT:
      offseted.Offset(kAnimationOffset, 0);
      break;
    case SHELF_ALIGNMENT_TOP:
      offseted.Offset(0, -kAnimationOffset);
      break;
  }

  return offseted;
}

// Using |button_bounds|, determine the anchor offset so that the bubble gets
// shown above the shelf (used for the alternate shelf theme).
gfx::Vector2d GetAnchorPositionOffsetToShelf(
    const gfx::Rect& button_bounds, views::Widget* widget) {
  DCHECK(Shell::HasInstance());
  ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(
      widget->GetNativeView()->GetRootWindow());
  gfx::Point anchor(button_bounds.CenterPoint());
  switch (shelf_alignment) {
    case SHELF_ALIGNMENT_TOP:
    case SHELF_ALIGNMENT_BOTTOM:
      if (base::i18n::IsRTL()) {
        int screen_width = widget->GetWorkAreaBoundsInScreen().width();
        return gfx::Vector2d(
            std::min(screen_width - kMinimalAnchorPositionOffset - anchor.x(),
                     0), 0);
      }
      return gfx::Vector2d(
          std::max(kMinimalAnchorPositionOffset - anchor.x(), 0), 0);
    case SHELF_ALIGNMENT_LEFT:
      return gfx::Vector2d(
          0, std::max(kMinimalAnchorPositionOffset - anchor.y(), 0));
    case SHELF_ALIGNMENT_RIGHT:
      return gfx::Vector2d(
          0, std::max(kMinimalAnchorPositionOffset - anchor.y(), 0));
    default:
      NOTREACHED();
      return gfx::Vector2d();
  }
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// AppListController, public:

AppListController::AppListController()
    : pagination_model_(new app_list::PaginationModel),
      is_visible_(false),
      view_(NULL),
      should_snap_back_(false) {
  Shell::GetInstance()->AddShellObserver(this);
  pagination_model_->AddObserver(this);
}

AppListController::~AppListController() {
  // Ensures app list view goes before the controller since pagination model
  // lives in the controller and app list view would access it on destruction.
  if (view_ && view_->GetWidget())
    view_->GetWidget()->CloseNow();

  Shell::GetInstance()->RemoveShellObserver(this);
  pagination_model_->RemoveObserver(this);
}

void AppListController::SetVisible(bool visible, aura::Window* window) {
  if (visible == is_visible_)
    return;

  is_visible_ = visible;

  // App list needs to know the new shelf layout in order to calculate its
  // UI layout when AppListView visibility changes.
  Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
      UpdateAutoHideState();

  if (view_) {
    ScheduleAnimation();
  } else if (is_visible_) {
    // AppListModel and AppListViewDelegate are owned by AppListView. They
    // will be released with AppListView on close.
    app_list::AppListView* view = new app_list::AppListView(
        Shell::GetInstance()->delegate()->CreateAppListViewDelegate());
    aura::Window* container = GetRootWindowController(window->GetRootWindow())->
        GetContainer(kShellWindowId_AppListContainer);
    if (ash::switches::UseAlternateShelfLayout()) {
      gfx::Rect applist_button_bounds = Launcher::ForWindow(container)->
          GetAppListButtonView()->GetBoundsInScreen();
      view->InitAsBubbleAttachedToAnchor(
          container,
          pagination_model_.get(),
          Launcher::ForWindow(container)->GetAppListButtonView(),
          GetAnchorPositionOffsetToShelf(applist_button_bounds,
              Launcher::ForWindow(container)->GetAppListButtonView()->
                  GetWidget()),
          GetBubbleArrow(container),
          true /* border_accepts_events */);
      view->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
    } else {
      view->InitAsBubbleAttachedToAnchor(
          container,
          pagination_model_.get(),
          Launcher::ForWindow(container)->GetAppListButtonView(),
          gfx::Vector2d(),
          GetBubbleArrow(container),
          true /* border_accepts_events */);
    }
    SetView(view);
    // By setting us as DnD recipient, the app list knows that we can
    // handle items.
    if (!CommandLine::ForCurrentProcess()->HasSwitch(
            ash::switches::kAshDisableDragAndDropAppListToLauncher)) {
      SetDragAndDropHostOfCurrentAppList(
          Launcher::ForWindow(window)->GetDragAndDropHostForAppList());
    }
  }
  // Update applist button status when app list visibility is changed.
  Launcher::ForWindow(window)->GetAppListButtonView()->SchedulePaint();
}

bool AppListController::IsVisible() const {
  return view_ && view_->GetWidget()->IsVisible();
}

aura::Window* AppListController::GetWindow() {
  return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL;
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, private:

void AppListController::SetDragAndDropHostOfCurrentAppList(
    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
  if (view_ && is_visible_)
    view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
}

void AppListController::SetView(app_list::AppListView* view) {
  DCHECK(view_ == NULL);
  DCHECK(is_visible_);

  view_ = view;
  views::Widget* widget = view_->GetWidget();
  widget->AddObserver(this);
  Shell::GetInstance()->AddPreTargetHandler(this);
  Launcher::ForWindow(widget->GetNativeWindow())->AddIconObserver(this);
  widget->GetNativeView()->GetRootWindow()->AddObserver(this);
  aura::client::GetFocusClient(widget->GetNativeView())->AddObserver(this);

  view_->ShowWhenReady();
}

void AppListController::ResetView() {
  if (!view_)
    return;

  views::Widget* widget = view_->GetWidget();
  widget->RemoveObserver(this);
  GetLayer(widget)->GetAnimator()->RemoveObserver(this);
  Shell::GetInstance()->RemovePreTargetHandler(this);
  Launcher::ForWindow(widget->GetNativeWindow())->RemoveIconObserver(this);
  widget->GetNativeView()->GetRootWindow()->RemoveObserver(this);
  aura::client::GetFocusClient(widget->GetNativeView())->RemoveObserver(this);
  view_ = NULL;
}

void AppListController::ScheduleAnimation() {
  // Stop observing previous animation.
  StopObservingImplicitAnimations();

  views::Widget* widget = view_->GetWidget();
  ui::Layer* layer = GetLayer(widget);
  layer->GetAnimator()->StopAnimating();

  gfx::Rect target_bounds;
  if (is_visible_) {
    target_bounds = widget->GetWindowBoundsInScreen();
    widget->SetBounds(OffsetTowardsShelf(target_bounds, widget));
  } else {
    target_bounds = OffsetTowardsShelf(widget->GetWindowBoundsInScreen(),
                                       widget);
  }

  ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
  animation.SetTransitionDuration(
      base::TimeDelta::FromMilliseconds(
          is_visible_ ? 0 : kAnimationDurationMs));
  animation.AddObserver(this);

  layer->SetOpacity(is_visible_ ? 1.0 : 0.0);
  widget->SetBounds(target_bounds);
}

void AppListController::ProcessLocatedEvent(ui::LocatedEvent* event) {
  // If the event happened on a menu, then the event should not close the app
  // list.
  aura::Window* target = static_cast<aura::Window*>(event->target());
  if (target) {
    RootWindowController* root_controller =
        GetRootWindowController(target->GetRootWindow());
    if (root_controller) {
      aura::Window* menu_container = root_controller->GetContainer(
          ash::internal::kShellWindowId_MenuContainer);
      if (menu_container->Contains(target))
        return;
    }
  }

  if (view_ && is_visible_) {
    aura::Window* window = view_->GetWidget()->GetNativeView();
    gfx::Point window_local_point(event->root_location());
    aura::Window::ConvertPointToTarget(window->GetRootWindow(),
                                       window,
                                       &window_local_point);
    // Use HitTest to respect the hit test mask of the bubble.
    if (!window->HitTest(window_local_point))
      SetVisible(false, window);
  }
}

void AppListController::UpdateBounds() {
  if (view_ && is_visible_)
    view_->UpdateBounds();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, aura::EventFilter implementation:

void AppListController::OnMouseEvent(ui::MouseEvent* event) {
  if (event->type() == ui::ET_MOUSE_PRESSED)
    ProcessLocatedEvent(event);
}

void AppListController::OnGestureEvent(ui::GestureEvent* event) {
  if (event->type() == ui::ET_GESTURE_TAP_DOWN)
    ProcessLocatedEvent(event);
}

////////////////////////////////////////////////////////////////////////////////
// AppListController,  aura::FocusObserver implementation:

void AppListController::OnWindowFocused(aura::Window* gained_focus,
                                        aura::Window* lost_focus) {
  if (gained_focus && view_ && is_visible_) {
    aura::Window* applist_container =
        GetRootWindowController(gained_focus->GetRootWindow())->GetContainer(
            kShellWindowId_AppListContainer);
    if (gained_focus->parent() != applist_container)
      SetVisible(false, gained_focus);
  }
}

////////////////////////////////////////////////////////////////////////////////
// AppListController,  aura::WindowObserver implementation:
void AppListController::OnWindowBoundsChanged(aura::Window* root,
                                              const gfx::Rect& old_bounds,
                                              const gfx::Rect& new_bounds) {
  UpdateBounds();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, ui::ImplicitAnimationObserver implementation:

void AppListController::OnImplicitAnimationsCompleted() {
  if (is_visible_ )
    view_->GetWidget()->Activate();
  else
    view_->GetWidget()->Close();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, views::WidgetObserver implementation:

void AppListController::OnWidgetDestroying(views::Widget* widget) {
  DCHECK(view_->GetWidget() == widget);
  if (is_visible_)
    SetVisible(false, widget->GetNativeView());
  ResetView();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, ShellObserver implementation:
void AppListController::OnShelfAlignmentChanged(aura::RootWindow* root_window) {
  if (view_)
    view_->SetBubbleArrow(GetBubbleArrow(view_->GetWidget()->GetNativeView()));
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, LauncherIconObserver implementation:

void AppListController::OnLauncherIconPositionsChanged() {
  UpdateBounds();
}

////////////////////////////////////////////////////////////////////////////////
// AppListController, PaginationModelObserver implementation:

void AppListController::TotalPagesChanged() {
}

void AppListController::SelectedPageChanged(int old_selected,
                                            int new_selected) {
}

void AppListController::TransitionStarted() {
}

void AppListController::TransitionChanged() {
  // |view_| could be NULL when app list is closed with a running transition.
  if (!view_)
    return;

  const app_list::PaginationModel::Transition& transition =
      pagination_model_->transition();
  if (pagination_model_->is_valid_page(transition.target_page))
    return;

  views::Widget* widget = view_->GetWidget();
  ui::LayerAnimator* widget_animator = GetLayer(widget)->GetAnimator();
  if (!pagination_model_->IsRevertingCurrentTransition()) {
    // Update cached |view_bounds_| if it is the first over-scroll move and
    // widget does not have running animations.
    if (!should_snap_back_ && !widget_animator->is_animating())
      view_bounds_ = widget->GetWindowBoundsInScreen();

    const int current_page = pagination_model_->selected_page();
    const int dir = transition.target_page > current_page ? -1 : 1;

    const double progress = 1.0 - pow(1.0 - transition.progress, 4);
    const int shift = kMaxOverScrollShift * progress * dir;

    gfx::Rect shifted(view_bounds_);
    shifted.set_x(shifted.x() + shift);
    widget->SetBounds(shifted);
    should_snap_back_ = true;
  } else if (should_snap_back_) {
    should_snap_back_ = false;
    ui::ScopedLayerAnimationSettings animation(widget_animator);
    animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
        app_list::kOverscrollPageTransitionDurationMs));
    widget->SetBounds(view_bounds_);
  }
}

}  // namespace internal
}  // namespace ash
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: AccessibleSlideSorterObject.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-03 13:24:02 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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 library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "AccessibleSlideSorterObject.hxx"

#include "SlideSorter.hxx"
#include "controller/SlideSorterController.hxx"
#include "controller/SlsPageSelector.hxx"
#include "controller/SlsFocusManager.hxx"
#include "model/SlideSorterModel.hxx"
#include "model/SlsPageDescriptor.hxx"
#include "view/SlideSorterView.hxx"

#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#endif
#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#endif
#ifndef COMPHELPER_ACCESSIBLE_EVENT_NOTIFIER
#include <comphelper/accessibleeventnotifier.hxx>
#endif
#include <unotools/accessiblestatesethelper.hxx>

#include "sdpage.hxx"
#include "sdresid.hxx"

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

#include "glob.hrc"

using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::accessibility;

namespace accessibility {

AccessibleSlideSorterObject::AccessibleSlideSorterObject(
    const Reference<XAccessible>& rxParent,
    ::sd::slidesorter::SlideSorter& rSlideSorter,
    sal_uInt16 nPageNumber)
    : AccessibleSlideSorterObjectBase(::sd::MutexOwner::maMutex),
      mxParent(rxParent),
      mnPageNumber(nPageNumber),
      mrSlideSorter(rSlideSorter),
      mnClientId(0)
{
}

AccessibleSlideSorterObject::~AccessibleSlideSorterObject (void)
{
    if ( ! IsDisposed())
        dispose();
}

sal_uInt16 AccessibleSlideSorterObject::GetPageNumber (void) const
{
    return mnPageNumber;
}

void AccessibleSlideSorterObject::FireAccessibleEvent (
    short nEventId,
    const uno::Any& rOldValue,
    const uno::Any& rNewValue)
{
    if (mnClientId != 0)
    {
        AccessibleEventObject aEventObject;

        aEventObject.Source = Reference<XWeak>(this);
        aEventObject.EventId = nEventId;
        aEventObject.NewValue = rNewValue;
        aEventObject.OldValue = rOldValue;

        comphelper::AccessibleEventNotifier::addEvent(mnClientId, aEventObject);
    }
}

void SAL_CALL AccessibleSlideSorterObject::disposing (void)
{
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());

    // Send a disposing to all listeners.
    if (mnClientId != 0)
    {
        comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(mnClientId, *this);
        mnClientId =  0;
    }
}

//===== XAccessible ===========================================================

Reference<XAccessibleContext> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleContext (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return this;
}

//===== XAccessibleContext ====================================================

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleChildCount (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return 0;
}

Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleChild (sal_Int32 )
    throw (lang::IndexOutOfBoundsException, RuntimeException)
{
    ThrowIfDisposed();
    throw lang::IndexOutOfBoundsException();
}

Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleParent (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return mxParent;
}

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleIndexInParent()
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());
    sal_Int32 nIndexInParent(-1);

    if (mxParent.is())
    {
        Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
        if (xParentContext.is())
        {
            sal_Int32 nChildCount (xParentContext->getAccessibleChildCount());
            for (sal_Int32 i=0; i<nChildCount; ++i)
                if (xParentContext->getAccessibleChild(i).get()
                    == static_cast<XAccessible*>(this))
                {
                    nIndexInParent = i;
                    break;
                }
        }
    }

    return nIndexInParent;
}

sal_Int16 SAL_CALL AccessibleSlideSorterObject::getAccessibleRole (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    static sal_Int16 nRole = AccessibleRole::LIST_ITEM;
    return nRole;
}

::rtl::OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleDescription (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return String(SdResId(STR_PAGE));
}

::rtl::OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleName (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());

    SdPage* pPage = GetPage();
    if (pPage != NULL)
        return pPage->GetName();
    else
        return String();
}

Reference<XAccessibleRelationSet> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleRelationSet (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return Reference<XAccessibleRelationSet>();
}

Reference<XAccessibleStateSet> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleStateSet (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());
    ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper();

    if (mxParent.is())
    {
        // SELECTABLE
        pStateSet->AddState(AccessibleStateType::SELECTABLE);

        // SELECTED
        if (mrSlideSorter.GetController().GetPageSelector().IsPageSelected(mnPageNumber))
            pStateSet->AddState(AccessibleStateType::SELECTED);

        // FOCUSABLE
        pStateSet->AddState(AccessibleStateType::FOCUSABLE);

        // FOCUSED
        if (mrSlideSorter.GetController().GetFocusManager().GetFocusedPageIndex() == mnPageNumber)
            if (mrSlideSorter.GetController().GetFocusManager().IsFocusShowing())
                pStateSet->AddState(AccessibleStateType::FOCUSED);

        pStateSet->AddState(AccessibleStateType::ENABLED);
        pStateSet->AddState(AccessibleStateType::VISIBLE);
        pStateSet->AddState(AccessibleStateType::SHOWING);
        pStateSet->AddState(AccessibleStateType::ACTIVE);
    }

    return pStateSet;
}

lang::Locale SAL_CALL AccessibleSlideSorterObject::getLocale (void)
    throw (IllegalAccessibleComponentStateException,
        RuntimeException)
{
    ThrowIfDisposed();
    // Delegate request to parent.
    if (mxParent.is())
    {
        Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
        if (xParentContext.is())
            return xParentContext->getLocale ();
    }

    //  No locale and no parent.  Therefore throw exception to indicate this
    //  cluelessness.
    throw IllegalAccessibleComponentStateException();
}

//===== XAccessibleEventBroadcaster ===========================================

void SAL_CALL AccessibleSlideSorterObject::addEventListener(
    const Reference<XAccessibleEventListener>& rxListener)
    throw (RuntimeException)
{
    if (rxListener.is())
    {
        const osl::MutexGuard aGuard(maMutex);

        if (IsDisposed())
        {
            uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
            rxListener->disposing (lang::EventObject (x));
        }
        else
        {
            if (mnClientId == 0)
                mnClientId = comphelper::AccessibleEventNotifier::registerClient();
            comphelper::AccessibleEventNotifier::addEventListener(mnClientId, rxListener);
        }
    }
}

void SAL_CALL AccessibleSlideSorterObject::removeEventListener(
    const Reference<XAccessibleEventListener>& rxListener)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    if (rxListener.is())
    {
        const osl::MutexGuard aGuard(maMutex);

        sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
        if ( !nListenerCount )
        {
            // no listeners anymore
            // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
            // and at least to us not firing any events anymore, in case somebody calls
            // NotifyAccessibleEvent, again
            comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
            mnClientId = 0;
        }
    }
}

//===== XAccessibleComponent ==================================================

sal_Bool SAL_CALL AccessibleSlideSorterObject::containsPoint(const awt::Point& aPoint)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const awt::Size aSize (getSize());
    return (aPoint.X >= 0)
        && (aPoint.X < aSize.Width)
        && (aPoint.Y >= 0)
        && (aPoint.Y < aSize.Height);
}

Reference<XAccessible> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleAtPoint(const awt::Point& )
    throw (uno::RuntimeException)
{
    return NULL;
}

awt::Rectangle SAL_CALL AccessibleSlideSorterObject::getBounds (void)
    throw (RuntimeException)
{
    const vos::OGuard aSolarGuard( Application::GetSolarMutex() );

    Rectangle aBBox (mrSlideSorter.GetView().GetPageBoundingBox (
        mnPageNumber,
        ::sd::slidesorter::view::SlideSorterView::CS_SCREEN,
        ::sd::slidesorter::view::SlideSorterView::BBT_INFO));

    if (mxParent.is())
    {
        Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(), UNO_QUERY);
        if (xParentComponent.is())
        {
            awt::Rectangle aParentBBox (xParentComponent->getBounds());
            aBBox.Intersection(Rectangle(
                aParentBBox.X,
                aParentBBox.Y,
                aParentBBox.Width,
                aParentBBox.Height));
        }
    }

    return awt::Rectangle(
        aBBox.Left(),
        aBBox.Top(),
        aBBox.GetWidth(),
        aBBox.GetHeight());
}

awt::Point SAL_CALL AccessibleSlideSorterObject::getLocation ()
    throw (RuntimeException)
{
    const awt::Rectangle aBBox (getBounds());
    return awt::Point(aBBox.X, aBBox.Y);
}

awt::Point SAL_CALL AccessibleSlideSorterObject::getLocationOnScreen (void)
    throw (RuntimeException)
{
    const vos::OGuard aSolarGuard( Application::GetSolarMutex() );

    awt::Point aLocation (getLocation());

    if (mxParent.is())
    {
        Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(),UNO_QUERY);
        if (xParentComponent.is())
        {
            const awt::Point aParentLocationOnScreen(xParentComponent->getLocationOnScreen());
            aLocation.X += aParentLocationOnScreen.X;
            aLocation.Y += aParentLocationOnScreen.Y;
        }
    }

    return aLocation;
}

awt::Size SAL_CALL AccessibleSlideSorterObject::getSize (void)
    throw (RuntimeException)
{
    const awt::Rectangle aBBox (getBounds());
    return awt::Size(aBBox.Width,aBBox.Height);
}

void SAL_CALL AccessibleSlideSorterObject::grabFocus (void)
    throw (RuntimeException)
{
    // nothing to do
}

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getForeground (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    svtools::ColorConfig aColorConfig;
    UINT32 nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
    return static_cast<sal_Int32>(nColor);
}

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getBackground (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    UINT32 nColor = Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor();
    return static_cast<sal_Int32>(nColor);
}

//=====  XServiceInfo  ========================================================

::rtl::OUString SAL_CALL
       AccessibleSlideSorterObject::getImplementationName (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleSlideSorterObject"));
}

sal_Bool SAL_CALL
     AccessibleSlideSorterObject::supportsService (const OUString& sServiceName)
    throw (::com::sun::star::uno::RuntimeException)
{
    //  Iterate over all supported service names and return true if on of them
    //  matches the given name.
    uno::Sequence< ::rtl::OUString> aSupportedServices (
        getSupportedServiceNames ());
    for (int i=0; i<aSupportedServices.getLength(); i++)
        if (sServiceName == aSupportedServices[i])
            return sal_True;
    return sal_False;
}

uno::Sequence< ::rtl::OUString> SAL_CALL
       AccessibleSlideSorterObject::getSupportedServiceNames (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    static const OUString sServiceNames[2] = {
        OUString(RTL_CONSTASCII_USTRINGPARAM(
            "com.sun.star.accessibility.Accessible")),
        OUString(RTL_CONSTASCII_USTRINGPARAM(
            "com.sun.star.accessibility.AccessibleContext"))
    };
    return uno::Sequence<OUString> (sServiceNames, 2);
}

void AccessibleSlideSorterObject::ThrowIfDisposed (void)
    throw (lang::DisposedException)
{
    if (rBHelper.bDisposed || rBHelper.bInDispose)
    {
        OSL_TRACE ("Calling disposed object. Throwing exception:");
        throw lang::DisposedException (
            OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
            static_cast<uno::XWeak*>(this));
    }
}

sal_Bool AccessibleSlideSorterObject::IsDisposed (void)
{
    return (rBHelper.bDisposed || rBHelper.bInDispose);
}

SdPage* AccessibleSlideSorterObject::GetPage (void) const
{
    ::sd::slidesorter::model::SharedPageDescriptor pDescriptor(
        mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber));
    if (pDescriptor.get() != NULL)
        return pDescriptor->GetPage();
    else
        return NULL;
}

} // end of namespace ::accessibility
<commit_msg>INTEGRATION: CWS changefileheader (1.9.296); FILE MERGED 2008/04/01 15:34:07 thb 1.9.296.3: #i85898# Stripping all external header guards 2008/04/01 12:38:35 thb 1.9.296.2: #i85898# Stripping all external header guards 2008/03/31 13:56:54 rt 1.9.296.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: AccessibleSlideSorterObject.cxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "AccessibleSlideSorterObject.hxx"

#include "SlideSorter.hxx"
#include "controller/SlideSorterController.hxx"
#include "controller/SlsPageSelector.hxx"
#include "controller/SlsFocusManager.hxx"
#include "model/SlideSorterModel.hxx"
#include "model/SlsPageDescriptor.hxx"
#include "view/SlideSorterView.hxx"
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <comphelper/accessibleeventnotifier.hxx>
#include <unotools/accessiblestatesethelper.hxx>

#include "sdpage.hxx"
#include "sdresid.hxx"
#include <vcl/svapp.hxx>

#include "glob.hrc"

using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::accessibility;

namespace accessibility {

AccessibleSlideSorterObject::AccessibleSlideSorterObject(
    const Reference<XAccessible>& rxParent,
    ::sd::slidesorter::SlideSorter& rSlideSorter,
    sal_uInt16 nPageNumber)
    : AccessibleSlideSorterObjectBase(::sd::MutexOwner::maMutex),
      mxParent(rxParent),
      mnPageNumber(nPageNumber),
      mrSlideSorter(rSlideSorter),
      mnClientId(0)
{
}

AccessibleSlideSorterObject::~AccessibleSlideSorterObject (void)
{
    if ( ! IsDisposed())
        dispose();
}

sal_uInt16 AccessibleSlideSorterObject::GetPageNumber (void) const
{
    return mnPageNumber;
}

void AccessibleSlideSorterObject::FireAccessibleEvent (
    short nEventId,
    const uno::Any& rOldValue,
    const uno::Any& rNewValue)
{
    if (mnClientId != 0)
    {
        AccessibleEventObject aEventObject;

        aEventObject.Source = Reference<XWeak>(this);
        aEventObject.EventId = nEventId;
        aEventObject.NewValue = rNewValue;
        aEventObject.OldValue = rOldValue;

        comphelper::AccessibleEventNotifier::addEvent(mnClientId, aEventObject);
    }
}

void SAL_CALL AccessibleSlideSorterObject::disposing (void)
{
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());

    // Send a disposing to all listeners.
    if (mnClientId != 0)
    {
        comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(mnClientId, *this);
        mnClientId =  0;
    }
}

//===== XAccessible ===========================================================

Reference<XAccessibleContext> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleContext (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return this;
}

//===== XAccessibleContext ====================================================

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleChildCount (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return 0;
}

Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleChild (sal_Int32 )
    throw (lang::IndexOutOfBoundsException, RuntimeException)
{
    ThrowIfDisposed();
    throw lang::IndexOutOfBoundsException();
}

Reference<XAccessible> SAL_CALL AccessibleSlideSorterObject::getAccessibleParent (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return mxParent;
}

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getAccessibleIndexInParent()
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());
    sal_Int32 nIndexInParent(-1);

    if (mxParent.is())
    {
        Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
        if (xParentContext.is())
        {
            sal_Int32 nChildCount (xParentContext->getAccessibleChildCount());
            for (sal_Int32 i=0; i<nChildCount; ++i)
                if (xParentContext->getAccessibleChild(i).get()
                    == static_cast<XAccessible*>(this))
                {
                    nIndexInParent = i;
                    break;
                }
        }
    }

    return nIndexInParent;
}

sal_Int16 SAL_CALL AccessibleSlideSorterObject::getAccessibleRole (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    static sal_Int16 nRole = AccessibleRole::LIST_ITEM;
    return nRole;
}

::rtl::OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleDescription (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return String(SdResId(STR_PAGE));
}

::rtl::OUString SAL_CALL AccessibleSlideSorterObject::getAccessibleName (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());

    SdPage* pPage = GetPage();
    if (pPage != NULL)
        return pPage->GetName();
    else
        return String();
}

Reference<XAccessibleRelationSet> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleRelationSet (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    return Reference<XAccessibleRelationSet>();
}

Reference<XAccessibleStateSet> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleStateSet (void)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const vos::OGuard aSolarGuard (Application::GetSolarMutex());
    ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper();

    if (mxParent.is())
    {
        // SELECTABLE
        pStateSet->AddState(AccessibleStateType::SELECTABLE);

        // SELECTED
        if (mrSlideSorter.GetController().GetPageSelector().IsPageSelected(mnPageNumber))
            pStateSet->AddState(AccessibleStateType::SELECTED);

        // FOCUSABLE
        pStateSet->AddState(AccessibleStateType::FOCUSABLE);

        // FOCUSED
        if (mrSlideSorter.GetController().GetFocusManager().GetFocusedPageIndex() == mnPageNumber)
            if (mrSlideSorter.GetController().GetFocusManager().IsFocusShowing())
                pStateSet->AddState(AccessibleStateType::FOCUSED);

        pStateSet->AddState(AccessibleStateType::ENABLED);
        pStateSet->AddState(AccessibleStateType::VISIBLE);
        pStateSet->AddState(AccessibleStateType::SHOWING);
        pStateSet->AddState(AccessibleStateType::ACTIVE);
    }

    return pStateSet;
}

lang::Locale SAL_CALL AccessibleSlideSorterObject::getLocale (void)
    throw (IllegalAccessibleComponentStateException,
        RuntimeException)
{
    ThrowIfDisposed();
    // Delegate request to parent.
    if (mxParent.is())
    {
        Reference<XAccessibleContext> xParentContext (mxParent->getAccessibleContext());
        if (xParentContext.is())
            return xParentContext->getLocale ();
    }

    //  No locale and no parent.  Therefore throw exception to indicate this
    //  cluelessness.
    throw IllegalAccessibleComponentStateException();
}

//===== XAccessibleEventBroadcaster ===========================================

void SAL_CALL AccessibleSlideSorterObject::addEventListener(
    const Reference<XAccessibleEventListener>& rxListener)
    throw (RuntimeException)
{
    if (rxListener.is())
    {
        const osl::MutexGuard aGuard(maMutex);

        if (IsDisposed())
        {
            uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
            rxListener->disposing (lang::EventObject (x));
        }
        else
        {
            if (mnClientId == 0)
                mnClientId = comphelper::AccessibleEventNotifier::registerClient();
            comphelper::AccessibleEventNotifier::addEventListener(mnClientId, rxListener);
        }
    }
}

void SAL_CALL AccessibleSlideSorterObject::removeEventListener(
    const Reference<XAccessibleEventListener>& rxListener)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    if (rxListener.is())
    {
        const osl::MutexGuard aGuard(maMutex);

        sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
        if ( !nListenerCount )
        {
            // no listeners anymore
            // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
            // and at least to us not firing any events anymore, in case somebody calls
            // NotifyAccessibleEvent, again
            comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
            mnClientId = 0;
        }
    }
}

//===== XAccessibleComponent ==================================================

sal_Bool SAL_CALL AccessibleSlideSorterObject::containsPoint(const awt::Point& aPoint)
    throw (uno::RuntimeException)
{
    ThrowIfDisposed();
    const awt::Size aSize (getSize());
    return (aPoint.X >= 0)
        && (aPoint.X < aSize.Width)
        && (aPoint.Y >= 0)
        && (aPoint.Y < aSize.Height);
}

Reference<XAccessible> SAL_CALL
    AccessibleSlideSorterObject::getAccessibleAtPoint(const awt::Point& )
    throw (uno::RuntimeException)
{
    return NULL;
}

awt::Rectangle SAL_CALL AccessibleSlideSorterObject::getBounds (void)
    throw (RuntimeException)
{
    const vos::OGuard aSolarGuard( Application::GetSolarMutex() );

    Rectangle aBBox (mrSlideSorter.GetView().GetPageBoundingBox (
        mnPageNumber,
        ::sd::slidesorter::view::SlideSorterView::CS_SCREEN,
        ::sd::slidesorter::view::SlideSorterView::BBT_INFO));

    if (mxParent.is())
    {
        Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(), UNO_QUERY);
        if (xParentComponent.is())
        {
            awt::Rectangle aParentBBox (xParentComponent->getBounds());
            aBBox.Intersection(Rectangle(
                aParentBBox.X,
                aParentBBox.Y,
                aParentBBox.Width,
                aParentBBox.Height));
        }
    }

    return awt::Rectangle(
        aBBox.Left(),
        aBBox.Top(),
        aBBox.GetWidth(),
        aBBox.GetHeight());
}

awt::Point SAL_CALL AccessibleSlideSorterObject::getLocation ()
    throw (RuntimeException)
{
    const awt::Rectangle aBBox (getBounds());
    return awt::Point(aBBox.X, aBBox.Y);
}

awt::Point SAL_CALL AccessibleSlideSorterObject::getLocationOnScreen (void)
    throw (RuntimeException)
{
    const vos::OGuard aSolarGuard( Application::GetSolarMutex() );

    awt::Point aLocation (getLocation());

    if (mxParent.is())
    {
        Reference<XAccessibleComponent> xParentComponent(mxParent->getAccessibleContext(),UNO_QUERY);
        if (xParentComponent.is())
        {
            const awt::Point aParentLocationOnScreen(xParentComponent->getLocationOnScreen());
            aLocation.X += aParentLocationOnScreen.X;
            aLocation.Y += aParentLocationOnScreen.Y;
        }
    }

    return aLocation;
}

awt::Size SAL_CALL AccessibleSlideSorterObject::getSize (void)
    throw (RuntimeException)
{
    const awt::Rectangle aBBox (getBounds());
    return awt::Size(aBBox.Width,aBBox.Height);
}

void SAL_CALL AccessibleSlideSorterObject::grabFocus (void)
    throw (RuntimeException)
{
    // nothing to do
}

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getForeground (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    svtools::ColorConfig aColorConfig;
    UINT32 nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
    return static_cast<sal_Int32>(nColor);
}

sal_Int32 SAL_CALL AccessibleSlideSorterObject::getBackground (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    UINT32 nColor = Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor();
    return static_cast<sal_Int32>(nColor);
}

//=====  XServiceInfo  ========================================================

::rtl::OUString SAL_CALL
       AccessibleSlideSorterObject::getImplementationName (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleSlideSorterObject"));
}

sal_Bool SAL_CALL
     AccessibleSlideSorterObject::supportsService (const OUString& sServiceName)
    throw (::com::sun::star::uno::RuntimeException)
{
    //  Iterate over all supported service names and return true if on of them
    //  matches the given name.
    uno::Sequence< ::rtl::OUString> aSupportedServices (
        getSupportedServiceNames ());
    for (int i=0; i<aSupportedServices.getLength(); i++)
        if (sServiceName == aSupportedServices[i])
            return sal_True;
    return sal_False;
}

uno::Sequence< ::rtl::OUString> SAL_CALL
       AccessibleSlideSorterObject::getSupportedServiceNames (void)
    throw (::com::sun::star::uno::RuntimeException)
{
    static const OUString sServiceNames[2] = {
        OUString(RTL_CONSTASCII_USTRINGPARAM(
            "com.sun.star.accessibility.Accessible")),
        OUString(RTL_CONSTASCII_USTRINGPARAM(
            "com.sun.star.accessibility.AccessibleContext"))
    };
    return uno::Sequence<OUString> (sServiceNames, 2);
}

void AccessibleSlideSorterObject::ThrowIfDisposed (void)
    throw (lang::DisposedException)
{
    if (rBHelper.bDisposed || rBHelper.bInDispose)
    {
        OSL_TRACE ("Calling disposed object. Throwing exception:");
        throw lang::DisposedException (
            OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
            static_cast<uno::XWeak*>(this));
    }
}

sal_Bool AccessibleSlideSorterObject::IsDisposed (void)
{
    return (rBHelper.bDisposed || rBHelper.bInDispose);
}

SdPage* AccessibleSlideSorterObject::GetPage (void) const
{
    ::sd::slidesorter::model::SharedPageDescriptor pDescriptor(
        mrSlideSorter.GetModel().GetPageDescriptor(mnPageNumber));
    if (pDescriptor.get() != NULL)
        return pDescriptor->GetPage();
    else
        return NULL;
}

} // end of namespace ::accessibility
<|endoftext|>


<commit_before>/*
  This program does a PAM authentication check using the username on
  the command line and reading the password from stdin (to be more
  secure).  When PAM mode is enabled and users request LDAP/PAM
  authentication (irodsAuthScheme of 'PAM' or 'pam'), the irodsAgent
  spawns this process and writes the input password on stdin.  You can
  also run this manually, entering the password after PamAuthCheck is
  started; which will be echoed:
  $ ./PamAuthCheck testuser2
  asfkskdlfkd
  Authenticated
  $

  You may need to install PAM libraries, such as libpam0g-dev:
  sudo apt-get install libpam0g-dev

  This is built when PAM is enabled (in config/config.mk, change
  # PAM_AUTH = 1
  to
  PAM_AUTH = 1

  But you can also build it via:
  gcc PamAuthCheck.c -L /usr/lib -l pam -o PamAuthCheck

  It needs to be set UID root:
    sudo chown root PamAuthCheck
    sudo chmod u+s PamAuthCheck

  You may need to add the following (or equivalent) to the /etc/pam.conf file.
  # check authorization
  check   auth       required     pam_unix_auth.so
  check   account    required     pam_unix_acct.so

  Loosely based on various PAM examples.
*/

#include <security/pam_appl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <stdint.h>
#include <map>

namespace {
    const char pam_service[] = "irods";

    struct AppData {
        bool debug_mode;
    };

    int
    null_conv( int num_msg, const struct pam_message **msg,
               struct pam_response **resp, void *appdata_ptr ) {

        const AppData &appdata = *static_cast<AppData*>( appdata_ptr );
        if ( appdata.debug_mode ) {
            std::map<int, const char*> pam_message_types;
            pam_message_types[PAM_PROMPT_ECHO_OFF] = "PAM_PROMPT_ECHO_OFF";
            pam_message_types[PAM_PROMPT_ECHO_ON] = "PAM_PROMPT_ECHO_ON";
            pam_message_types[PAM_ERROR_MSG] = "PAM_ERROR_MSG";
            pam_message_types[PAM_TEXT_INFO] = "PAM_TEXT_INFO";

            printf( "null_conv: num_msg: %d\n", num_msg );
            for ( int i = 0; i < num_msg; ++i ) {
                const int msg_style = msg[i]->msg_style;
                printf( "  null_conv: msg index: %d\n", i );
                printf( "    null_conv: msg_style: %d -> %s\n", msg_style, pam_message_types[msg_style] );
                printf( "    null_conv: msg: %s\n", msg[i]->msg );
            }
        }

        if ( num_msg < 1 ) {
            return PAM_SUCCESS;
        }

        // read the password from stdin
        std::string password;
        std::getline( std::cin, password );
        if ( appdata.debug_mode ) {
            printf( "null_conv: password bytes: %ju\n", ( uintmax_t )password.size() );
        }

        *resp = static_cast<pam_response*>( malloc( sizeof( **resp ) ) );
        if ( *resp == NULL ) {
            fprintf( stderr, "null_conv: PamAuthCheck: malloc error\n" );
            return PAM_BUF_ERR;
        }

        ( *resp )->resp = strdup( password.c_str() );
        if ( ( *resp )->resp == NULL ) {
            free( *resp );
            fprintf( stderr, "PamAuthCheck: malloc error\n" );
            return PAM_BUF_ERR;
        }

        ( *resp )->resp_retcode = 0;
        return PAM_SUCCESS;
    }
}

int main( int argc, char *argv[] ) {

    const char *username = NULL;
    if ( argc == 2 || argc == 3 ) {
        username = argv[1];
    }
    else {
        fprintf( stderr, "Usage: PamAuthCheck username [extra-arg-activates-debug-mode]\n" );
        return 2;
    }

    const bool debug_mode = argc == 3;

    AppData appdata;
    appdata.debug_mode = debug_mode;
    pam_conv conv = { null_conv, &appdata };
    pam_handle_t *pamh = NULL;
    const int retval_pam_start = pam_start( pam_service, username, &conv, &pamh );
    if ( debug_mode ) {
        printf( "retval_pam_start: %d\n", retval_pam_start );
    }

    if ( retval_pam_start != PAM_SUCCESS ) {
        fprintf( stderr, "PamAuthCheck: pam_start error\n" );
        return 3;
    }

    // check username-password
    const int retval_pam_authenticate = pam_authenticate( pamh, 0 );
    if ( debug_mode ) {
        printf( "retval_pam_authenticate: %d\n", retval_pam_authenticate );
    }

    if ( retval_pam_authenticate == PAM_SUCCESS ) {
        fprintf( stdout, "Authenticated\n" );
    }
    else {
        fprintf( stdout, "Not Authenticated\n" );
    }

    // close Linux-PAM
    if ( pam_end( pamh, retval_pam_authenticate ) != PAM_SUCCESS ) {
        pamh = NULL;
        fprintf( stderr, "PamAuthCheck: failed to release authenticator\n" );
        return 4;
    }

    // indicate success (valid username and password) or not
    return retval_pam_authenticate == PAM_SUCCESS ? 0 : 1;
}
<commit_msg>[#2346] PamAuthCheck read password once from stdin<commit_after>/*
  This program does a PAM authentication check using the username on
  the command line and reading the password from stdin (to be more
  secure).  When PAM mode is enabled and users request LDAP/PAM
  authentication (irodsAuthScheme of 'PAM' or 'pam'), the irodsAgent
  spawns this process and writes the input password on stdin.  You can
  also run this manually, entering the password after PamAuthCheck is
  started; which will be echoed:
  $ ./PamAuthCheck testuser2
  asfkskdlfkd
  Authenticated
  $

  You may need to install PAM libraries, such as libpam0g-dev:
  sudo apt-get install libpam0g-dev

  This is built when PAM is enabled (in config/config.mk, change
  # PAM_AUTH = 1
  to
  PAM_AUTH = 1

  But you can also build it via:
  gcc PamAuthCheck.c -L /usr/lib -l pam -o PamAuthCheck

  It needs to be set UID root:
    sudo chown root PamAuthCheck
    sudo chmod u+s PamAuthCheck

  You may need to add the following (or equivalent) to the /etc/pam.conf file.
  # check authorization
  check   auth       required     pam_unix_auth.so
  check   account    required     pam_unix_acct.so

  Loosely based on various PAM examples.
*/

#include <security/pam_appl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <stdint.h>
#include <map>
#include <string>

namespace {
    const char pam_service[] = "irods";

    struct AppData {
        bool debug_mode;
        std::string password;
    };

    int
    null_conv( int num_msg, const struct pam_message **msg,
               struct pam_response **resp, void *appdata_ptr ) {

        const AppData &appdata = *static_cast<AppData*>( appdata_ptr );
        if ( appdata.debug_mode ) {
            std::map<int, const char*> pam_message_types;
            pam_message_types[PAM_PROMPT_ECHO_OFF] = "PAM_PROMPT_ECHO_OFF";
            pam_message_types[PAM_PROMPT_ECHO_ON] = "PAM_PROMPT_ECHO_ON";
            pam_message_types[PAM_ERROR_MSG] = "PAM_ERROR_MSG";
            pam_message_types[PAM_TEXT_INFO] = "PAM_TEXT_INFO";

            printf( "null_conv: num_msg: %d\n", num_msg );
            for ( int i = 0; i < num_msg; ++i ) {
                const int msg_style = msg[i]->msg_style;
                printf( "  null_conv: msg index: %d\n", i );
                printf( "    null_conv: msg_style: %d -> %s\n", msg_style, pam_message_types[msg_style] );
                printf( "    null_conv: msg: %s\n", msg[i]->msg );
            }
        }

        if ( num_msg < 1 ) {
            return PAM_SUCCESS;
        }

        *resp = static_cast<pam_response*>( malloc( sizeof( **resp ) ) );
        if ( *resp == NULL ) {
            fprintf( stderr, "null_conv: PamAuthCheck: malloc error\n" );
            return PAM_BUF_ERR;
        }

        ( *resp )->resp = strdup( appdata.password.c_str() );
        if ( ( *resp )->resp == NULL ) {
            free( *resp );
            fprintf( stderr, "PamAuthCheck: malloc error\n" );
            return PAM_BUF_ERR;
        }

        ( *resp )->resp_retcode = 0;
        return PAM_SUCCESS;
    }
}

int main( int argc, char *argv[] ) {

    const char *username = NULL;
    if ( argc == 2 || argc == 3 ) {
        username = argv[1];
    }
    else {
        fprintf( stderr, "Usage: PamAuthCheck username [extra-arg-activates-debug-mode]\n" );
        return 2;
    }

    AppData appdata;
    appdata.debug_mode = argc == 3;

    // read the password from stdin
    std::getline( std::cin, appdata.password );
    if ( appdata.debug_mode ) {
        printf( "password bytes: %ju\n", ( uintmax_t )appdata.password.size() );
    }

    pam_conv conv = { null_conv, &appdata };
    pam_handle_t *pamh = NULL;
    const int retval_pam_start = pam_start( pam_service, username, &conv, &pamh );
    if ( appdata.debug_mode ) {
        printf( "retval_pam_start: %d\n", retval_pam_start );
    }

    if ( retval_pam_start != PAM_SUCCESS ) {
        fprintf( stderr, "PamAuthCheck: pam_start error\n" );
        return 3;
    }

    // check username-password
    const int retval_pam_authenticate = pam_authenticate( pamh, 0 );
    if ( appdata.debug_mode ) {
        printf( "retval_pam_authenticate: %d\n", retval_pam_authenticate );
    }

    if ( retval_pam_authenticate == PAM_SUCCESS ) {
        fprintf( stdout, "Authenticated\n" );
    }
    else {
        fprintf( stdout, "Not Authenticated\n" );
    }

    // close Linux-PAM
    if ( pam_end( pamh, retval_pam_authenticate ) != PAM_SUCCESS ) {
        pamh = NULL;
        fprintf( stderr, "PamAuthCheck: failed to release authenticator\n" );
        return 4;
    }

    // indicate success (valid username and password) or not
    return retval_pam_authenticate == PAM_SUCCESS ? 0 : 1;
}
<|endoftext|>


<commit_before>
namespace freeflow {

inline
Transfer::Transfer(int f, uint8_t* b, std::size_t n) :
  fd(f), buff(b), n_bytes(n), fd_state(1), n_transferred(0)
{ }

inline
Transfer::operator int()
{
  return fd_state < 0 ? fd_state : n_transferred;
}

inline int
transfer_available(Transfer& t, std::size_t (*op)(int, void*, std::size_t))
{
  // Read the remainder to the buff
  t.fd_state = op(t.fd, t.buff+t.n_transferred, t.n_bytes-t.n_transferred);
  // If successful update bytes read
  if (t.fd_state > 0)
    t.n_transferred += t.fd_state;
  // Return fd state on failure or number of bytes read
  return t.fd_state < 0 ? t.fd_state : t.n_transferred;
}

inline int
transfer_all(Transfer& t, std::size_t (*op)(int, void*, std::size_t))
{
  // More to read and fd state good
  while(t.n_transferred < t.n_bytes and t.fd_state > 0) {
    // Read the remainder to the buff
    t.fd_state = op(t.fd, t.buff+t.n_transferred, t.n_bytes-t.n_transferred);
    // If successful update bytes read
    if (t.fd_state > 0)
      t.n_transferred += t.fd_state;
  }
  // Return fd state on failure or number of bytes read
  return t.fd_state < 0 ? t.fd_state : t.n_transferred;
}

inline int
read_available(Transfer& t)
{
  return transfer_available(t, ::read);
}

inline int
read_all(Transfer& t)
{
  return transfer_all(t, ::read);
}

inline int
write_available(Transfer& t)
{
  return transfer_available(t, ::write);
}

inline int
write_all(Transfer& t)
{
  return transfer_all(t, ::write);
}

} // namespace freeflow
<commit_msg>Fixed cast for compilation<commit_after>
namespace freeflow {

inline
Transfer::Transfer(int f, uint8_t* b, std::size_t n) :
  fd(f), buff(b), n_bytes(n), fd_state(1), n_transferred(0)
{ }

inline
Transfer::operator int()
{
  return fd_state < 0 ? fd_state : n_transferred;
}

inline int
transfer_available(Transfer& t, ssize_t (*op)(int, void*, size_t))
{
  // Read the remainder to the buff
  t.fd_state = op(t.fd, t.buff+t.n_transferred, t.n_bytes-t.n_transferred);
  // If successful update bytes read
  if (t.fd_state > 0)
    t.n_transferred += t.fd_state;
  // Return fd state on failure or number of bytes read
  return t.fd_state < 0 ? t.fd_state : t.n_transferred;
}

inline int
transfer_all(Transfer& t, ssize_t (*op)(int, void*, size_t))
{
  // More to read and fd state good
  while(t.n_transferred < t.n_bytes and t.fd_state > 0) {
    // Read the remainder to the buff
    t.fd_state = op(t.fd, t.buff+t.n_transferred, t.n_bytes-t.n_transferred);
    // If successful update bytes read
    if (t.fd_state > 0)
      t.n_transferred += t.fd_state;
  }
  // Return fd state on failure or number of bytes read
  return t.fd_state < 0 ? t.fd_state : t.n_transferred;
}

inline int
read_available(Transfer& t)
{
  return transfer_available(t, ::read);
}

inline int
read_all(Transfer& t)
{
  return transfer_all(t, ::read);
}

inline int
write_available(Transfer& t)
{
  return transfer_available(t, (ssize_t (*)(int, void*, size_t))::write);
}

inline int
write_all(Transfer& t)
{
  return transfer_all(t, (ssize_t (*)(int, void*, size_t))::write);
}

} // namespace freeflow
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------------------
// Name:        main.cc
// Purpose:     Core application
// Author:      Michael Van Donselaar
// Modified by:
// Created:     2003
// Copyright:   (c) Michael Van Donselaar ( michael@vandonselaar.org )
// Licence:     GPL
//----------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------
// GCC implementation
//----------------------------------------------------------------------------------------

#if defined(__GNUG__) && ! defined(__APPLE__)
    #pragma implementation "main.h"
#endif

//----------------------------------------------------------------------------------------
// Standard wxWindows headers
//----------------------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// For all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWindows headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

//----------------------------------------------------------------------------------------
// Header of this .cpp file
//----------------------------------------------------------------------------------------

#include "main.h"
#include "devices.h"
#include "prefs.h"
#include "accounts.h"
#include "wx/tokenzr.h"

//----------------------------------------------------------------------------------------
// Remaining headers
//----------------------------------------------------------------------------------------

#include "app.h"
#include "frame.h"
#include "wx/dirdlg.h"

//----------------------------------------------------------------------------------------
// forward decls for callbacks
//----------------------------------------------------------------------------------------
extern "C" {
     static int iaxc_callback(iaxc_event e);
     int        doTestCall(int ac, char **av);
}

//----------------------------------------------------------------------------------------
// Static variables
//----------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------
// wxWindows macro: Declare the application.
//----------------------------------------------------------------------------------------

// Create a new application object: this macro will allow wxWindows to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also declares the accessor function
// wxGetApp() which will return the reference of the right type (i.e. theApp and
// not wxApp).

IMPLEMENT_APP( theApp )

//----------------------------------------------------------------------------------------
// Public methods
//----------------------------------------------------------------------------------------

bool theApp::OnInit()
{
    wxConfig *config = new wxConfig("iaxComm");

    wxString str;
    wxString reginfo;
    long     dummy;
    bool     bCont;

#ifndef __WXMAC__
// XXX this seems broken on mac with wx-2.4.2
    m_single_instance_checker = new wxSingleInstanceChecker(_T("iaxcomm.lock"));

    // And if a copy is alreay running, then abort...
    if ( m_single_instance_checker->IsAnotherRunning() ) {
        wxMessageDialog second_instance_messagedialog( (wxWindow*)NULL,
                  _( "Another instance is already running." ),
                  _( "Startup Error" ),
                  wxOK | wxICON_INFORMATION );
        second_instance_messagedialog.ShowModal();
        // Returning FALSE from within wxApp::OnInit() will terminate the application.
        return FALSE;
    }
#endif

    config->SetPath("/Prefs");

    // Load up the XML Resource handler, to be able to load XML resources..

    wxXmlResource::Get()->InitAllHandlers();

    // Load up enough XML resources to construct a main frame

    load_xrc_resource( "frame.xrc" );
    load_xrc_resource( "menubar.xrc" );
    load_xrc_resource( "panel.xrc" );
    load_xrc_resource( "prefs.xrc" );
    load_xrc_resource( "directory.xrc" );
    load_xrc_resource( "devices.xrc" );

    extern void InitXmlResource();
    InitXmlResource();

    IncomingRing.Init( 880, 960, 16000, 48000, 10);
    RingbackTone.Init( 440, 480, 16000, 48000, 10);
    IntercomTone.Init( 440, 960,  6000,  6000,  1);

    // Read in some config info
    nCalls           = config->Read("nCalls", 2);
    DefaultAccount   = config->Read("DefaultAccount", "");

    IncomingRingName = config->Read("RingTone", "");
    RingBackToneName = config->Read("RingBack", "");
    IntercomToneName = config->Read("Intercom", "");

    IncomingRing.LoadTone(IncomingRingName, 10);
    RingbackTone.LoadTone(RingBackToneName, 10);
    IntercomTone.LoadTone(IntercomToneName,  1);

    if(DefaultAccount.IsEmpty()) {
        bool     bCont;
        long     dummy;
        wxString Name;
        wxString Path;

        Path = config->GetPath();
        config->SetPath("/Accounts");
        bCont = config->GetFirstGroup(Name, dummy);
        while ( bCont ) {
            DefaultAccount = Name;
            bCont = config->GetNextGroup(Name, dummy);
        }

        config->SetPath(Path);
    }

    // Create an instance of the main frame.
    // Using a pointer since behaviour will be when close the frame, it will
    // Destroy() itself, which will safely call "delete" when the time is right.
    // [The constructor is empty, since using the default value for parent, which is
    // NULL].

    theFrame = new MyFrame();

    if(DefaultAccount.IsEmpty()) {
        // If we never did find a default account, must be a new install

        AddAccountDialog dialog(theFrame, "");

        dialog.SetTitle("Welcome to iaxComm!");
      #ifdef PROVIDER
        dialog.AccountName->SetValue("asterisk");
        dialog.HostName->SetValue("asterisk");
      #endif

        dialog.ShowModal();
    }

    // This is of dubious usefulness unless an app is a dialog-only app. This
    // is the first created frame, so it is the top window already.

    SetTopWindow( theFrame );

    // Show the main frame. Unlike most controls, frames don't show immediately upon
    // construction, but instead wait for a specific Show() function.

    theFrame->Show( TRUE );

  #ifdef __WXMSW__
    theTaskBarIcon.SetIcon(wxICON(application));
  #endif

    if(iaxc_initialize(AUDIO_INTERNAL_PA, nCalls)) {
        wxFatalError(_("Couldn't Initialize IAX Client "));
    }

    SetAudioDevices(InputDevice,
                    OutputDevice,
                    RingDevice);

    iaxc_set_encode_format(IAXC_FORMAT_GSM);
    iaxc_set_silence_threshold(-99);
    iaxc_set_event_callback(iaxc_callback);

    iaxc_start_processing_thread();

    // Callerid from wxConfig
    Name   = config->Read("Name", "IaxComm User");
    Number = config->Read("Number",  "700000000");
    SetCallerID(Name, Number);

    // Register from wxConfig
    config->SetPath("/Accounts");
    bCont = config->GetFirstGroup(str, dummy);
    while ( bCont ) {
        RegisterByName(str);
        bCont = config->GetNextGroup(str, dummy);
    }

    return TRUE;
}

void theApp::RegisterByName(wxString RegName)
{
    wxConfig    *config = new wxConfig("iaxComm");
    wxChar      KeyPath[256];
    wxListItem  item;

    wxStringTokenizer tok(RegName, _T(":@"));
    char user[256], pass[256], host[256];

    if(strlen(RegName) == 0)
        return;

    if(tok.CountTokens() == 3) {

        strncpy( user , tok.GetNextToken().c_str(), 256);
        strncpy( pass , tok.GetNextToken().c_str(), 256);
        strncpy( host , tok.GetNextToken().c_str(), 256);
    } else {
        // Check if it's a Speed Dial
        wxStrcpy(KeyPath,     "/Accounts/");
        wxStrcat(KeyPath,     RegName);
        config->SetPath(KeyPath);
        if(!config->Exists(KeyPath)) {
            theFrame->SetStatusText("Register format error");
            return;
        }
        wxStrcpy(user, config->Read("Username", ""));
        wxStrcpy(pass, config->Read("Password", ""));
        wxStrcpy(host, config->Read("Host", ""));
    }
    iaxc_register(user, pass, host);
}

int theApp::OnExit(void)
{
    // Delete the single instance checker
#ifndef __WXMAC__
    delete m_single_instance_checker;
#endif
    return 0;
}

//----------------------------------------------------------------------------------------
// Private methods
//----------------------------------------------------------------------------------------

void theApp::load_xrc_resource( const wxString& xrc_filename )
{
    wxConfig        *config = new wxConfig("iaxComm");
    wxString         xrc_fullname;
    static wxString  xrc_subdirectory = "";

#ifdef __WXMAC__
    if(xrc_subdirectory.IsEmpty()) {
        CFBundleRef mainBundle = CFBundleGetMainBundle ();
        CFURLRef resDir = CFBundleCopyResourcesDirectoryURL (mainBundle);
        CFURLRef resDirAbs = CFURLCopyAbsoluteURL (resDir);
        CFStringRef resPath = CFURLCopyFileSystemPath(resDirAbs, kCFURLPOSIXPathStyle);
        char path[1024];
        CFStringGetCString(resPath, path, 1024, kCFStringEncodingASCII);
        xrc_subdirectory = wxString(path) + wxFILE_SEP_PATH + _T("rc");
    }
#endif

    // First, look where we got the last xrc
    if(!xrc_subdirectory.IsEmpty()) {
        xrc_fullname = xrc_subdirectory + wxFILE_SEP_PATH + xrc_filename;
        if ( ::wxFileExists( xrc_fullname ) ) {
            wxXmlResource::Get()->Load( xrc_fullname );
            return;
        }
    }

    // Next, check where config points
    if(config->Exists("/Prefs/XRCDirectory")) {
        xrc_fullname = config->Read("/Prefs/XRCDirectory", "") + wxFILE_SEP_PATH + xrc_filename;
        if ( ::wxFileExists( xrc_fullname ) ) {
            wxXmlResource::Get()->Load( xrc_fullname );
            return;
        }
    }

    // Third, check in cwd
    xrc_fullname = wxGetCwd() + wxFILE_SEP_PATH + "rc" + wxFILE_SEP_PATH + xrc_filename;
    if ( ::wxFileExists( xrc_fullname ) ) {
        wxXmlResource::Get()->Load( xrc_fullname );
        return;
    }

    wxString dirHome;
    wxGetHomeDir(&dirHome);

    // Last, look in ~/rc
    xrc_fullname = dirHome + wxFILE_SEP_PATH + xrc_filename;
    if ( ::wxFileExists( xrc_fullname ) ) {
        wxXmlResource::Get()->Load( xrc_fullname );
        return;
    }
}

#ifdef __WXMSW__
BEGIN_EVENT_TABLE(MyTaskBarIcon, wxTaskBarIcon)
    EVT_MENU(XRCID("TaskBarRestore"), MyTaskBarIcon::OnRestore)
    EVT_MENU(XRCID("TaskBarHide"),    MyTaskBarIcon::OnHide)
    EVT_MENU(XRCID("TaskBarExit"),    MyTaskBarIcon::OnExit)
END_EVENT_TABLE()

void MyTaskBarIcon::OnRestore(wxCommandEvent&)
{
    wxGetApp().theFrame->Show(TRUE);
}

void MyTaskBarIcon::OnHide(wxCommandEvent&)
{
    wxGetApp().theFrame->Show(FALSE);
}

void MyTaskBarIcon::OnExit(wxCommandEvent&)
{
    wxGetApp().theFrame->Close(TRUE);
    wxGetApp().ProcessIdle();
}

void MyTaskBarIcon::OnLButtonDClick(wxEvent&)
{
    wxGetApp().theFrame->Close(TRUE);
    wxGetApp().ProcessIdle();
}

void MyTaskBarIcon::OnRButtonDown(wxEvent&)
{
    PopupMenu(wxXmlResource::Get()->LoadMenu(wxT("TaskBarMenu")));
}

void MyTaskBarIcon::OnLButtonDown(wxEvent&)
{
    wxGetApp().theFrame->Show(TRUE);
}
#endif

//----------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------

extern "C" {

   /* yes, using member variables, and polling for changes
    * isn't really a nice way to do callbacks.  BUT, I've tried the
    * "right" ways, unsuccessfully:
    *
    * 1) I've tried using wxGuiMutexEnter/Leave, but that deadlocks (and it should, I guess),
    * because sometimes these _are_ called in response to GUI events (i.e. the status callback eventually
    * gets called when you press hang up.
    *
    * 2) I've tried using events and ::wxPostEvent, but that also deadlocks (at least on GTK),
    * because it calls wxWakeUpIdle, which calls wxGuiMutexEnter, which deadlocks also, for some reason.
    *
    * So, this isn't ideal, but it works, until I can figure out a better way
    */

    // handle events via posting.
  #ifdef USE_GUILOCK
    static int iaxc_callback(iaxc_event e)
    {
        int ret;
        if (!wxThread::IsMain()) wxMutexGuiEnter();
            ret = wxGetApp().theFrame->HandleIAXEvent(&e);
        if (!wxThread::IsMain()) wxMutexGuiLeave();
            return ret;
    }
  #else
    static int iaxc_callback(iaxc_event e)
    {
        iaxc_event *copy;
        wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, IAXCLIENT_EVENT);

        copy = (iaxc_event *)malloc(sizeof(iaxc_event));
        memcpy(copy,&e,sizeof(iaxc_event));

        evt.SetClientData(copy);

        //fprintf(stderr, "Posting Event\n");
        wxPostEvent(wxGetApp().theFrame, evt);

        // pretend we handle all events.
        return 1;
    }
  #endif

}
<commit_msg>Remove obsolete API call for formats.<commit_after>//----------------------------------------------------------------------------------------
// Name:        main.cc
// Purpose:     Core application
// Author:      Michael Van Donselaar
// Modified by:
// Created:     2003
// Copyright:   (c) Michael Van Donselaar ( michael@vandonselaar.org )
// Licence:     GPL
//----------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------
// GCC implementation
//----------------------------------------------------------------------------------------

#if defined(__GNUG__) && ! defined(__APPLE__)
    #pragma implementation "main.h"
#endif

//----------------------------------------------------------------------------------------
// Standard wxWindows headers
//----------------------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// For all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWindows headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

//----------------------------------------------------------------------------------------
// Header of this .cpp file
//----------------------------------------------------------------------------------------

#include "main.h"
#include "devices.h"
#include "prefs.h"
#include "accounts.h"
#include "wx/tokenzr.h"

//----------------------------------------------------------------------------------------
// Remaining headers
//----------------------------------------------------------------------------------------

#include "app.h"
#include "frame.h"
#include "wx/dirdlg.h"

//----------------------------------------------------------------------------------------
// forward decls for callbacks
//----------------------------------------------------------------------------------------
extern "C" {
     static int iaxc_callback(iaxc_event e);
     int        doTestCall(int ac, char **av);
}

//----------------------------------------------------------------------------------------
// Static variables
//----------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------
// wxWindows macro: Declare the application.
//----------------------------------------------------------------------------------------

// Create a new application object: this macro will allow wxWindows to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also declares the accessor function
// wxGetApp() which will return the reference of the right type (i.e. theApp and
// not wxApp).

IMPLEMENT_APP( theApp )

//----------------------------------------------------------------------------------------
// Public methods
//----------------------------------------------------------------------------------------

bool theApp::OnInit()
{
    wxConfig *config = new wxConfig("iaxComm");

    wxString str;
    wxString reginfo;
    long     dummy;
    bool     bCont;

#ifndef __WXMAC__
// XXX this seems broken on mac with wx-2.4.2
    m_single_instance_checker = new wxSingleInstanceChecker(_T("iaxcomm.lock"));

    // And if a copy is alreay running, then abort...
    if ( m_single_instance_checker->IsAnotherRunning() ) {
        wxMessageDialog second_instance_messagedialog( (wxWindow*)NULL,
                  _( "Another instance is already running." ),
                  _( "Startup Error" ),
                  wxOK | wxICON_INFORMATION );
        second_instance_messagedialog.ShowModal();
        // Returning FALSE from within wxApp::OnInit() will terminate the application.
        return FALSE;
    }
#endif

    config->SetPath("/Prefs");

    // Load up the XML Resource handler, to be able to load XML resources..

    wxXmlResource::Get()->InitAllHandlers();

    // Load up enough XML resources to construct a main frame

    load_xrc_resource( "frame.xrc" );
    load_xrc_resource( "menubar.xrc" );
    load_xrc_resource( "panel.xrc" );
    load_xrc_resource( "prefs.xrc" );
    load_xrc_resource( "directory.xrc" );
    load_xrc_resource( "devices.xrc" );

    extern void InitXmlResource();
    InitXmlResource();

    IncomingRing.Init( 880, 960, 16000, 48000, 10);
    RingbackTone.Init( 440, 480, 16000, 48000, 10);
    IntercomTone.Init( 440, 960,  6000,  6000,  1);

    // Read in some config info
    nCalls           = config->Read("nCalls", 2);
    DefaultAccount   = config->Read("DefaultAccount", "");

    IncomingRingName = config->Read("RingTone", "");
    RingBackToneName = config->Read("RingBack", "");
    IntercomToneName = config->Read("Intercom", "");

    IncomingRing.LoadTone(IncomingRingName, 10);
    RingbackTone.LoadTone(RingBackToneName, 10);
    IntercomTone.LoadTone(IntercomToneName,  1);

    if(DefaultAccount.IsEmpty()) {
        bool     bCont;
        long     dummy;
        wxString Name;
        wxString Path;

        Path = config->GetPath();
        config->SetPath("/Accounts");
        bCont = config->GetFirstGroup(Name, dummy);
        while ( bCont ) {
            DefaultAccount = Name;
            bCont = config->GetNextGroup(Name, dummy);
        }

        config->SetPath(Path);
    }

    // Create an instance of the main frame.
    // Using a pointer since behaviour will be when close the frame, it will
    // Destroy() itself, which will safely call "delete" when the time is right.
    // [The constructor is empty, since using the default value for parent, which is
    // NULL].

    theFrame = new MyFrame();

    if(DefaultAccount.IsEmpty()) {
        // If we never did find a default account, must be a new install

        AddAccountDialog dialog(theFrame, "");

        dialog.SetTitle("Welcome to iaxComm!");
      #ifdef PROVIDER
        dialog.AccountName->SetValue("asterisk");
        dialog.HostName->SetValue("asterisk");
      #endif

        dialog.ShowModal();
    }

    // This is of dubious usefulness unless an app is a dialog-only app. This
    // is the first created frame, so it is the top window already.

    SetTopWindow( theFrame );

    // Show the main frame. Unlike most controls, frames don't show immediately upon
    // construction, but instead wait for a specific Show() function.

    theFrame->Show( TRUE );

  #ifdef __WXMSW__
    theTaskBarIcon.SetIcon(wxICON(application));
  #endif

    if(iaxc_initialize(AUDIO_INTERNAL_PA, nCalls)) {
        wxFatalError(_("Couldn't Initialize IAX Client "));
    }

    SetAudioDevices(InputDevice,
                    OutputDevice,
                    RingDevice);

    iaxc_set_silence_threshold(-99);
    iaxc_set_event_callback(iaxc_callback);

    iaxc_start_processing_thread();

    // Callerid from wxConfig
    Name   = config->Read("Name", "IaxComm User");
    Number = config->Read("Number",  "700000000");
    SetCallerID(Name, Number);

    // Register from wxConfig
    config->SetPath("/Accounts");
    bCont = config->GetFirstGroup(str, dummy);
    while ( bCont ) {
        RegisterByName(str);
        bCont = config->GetNextGroup(str, dummy);
    }

    return TRUE;
}

void theApp::RegisterByName(wxString RegName)
{
    wxConfig    *config = new wxConfig("iaxComm");
    wxChar      KeyPath[256];
    wxListItem  item;

    wxStringTokenizer tok(RegName, _T(":@"));
    char user[256], pass[256], host[256];

    if(strlen(RegName) == 0)
        return;

    if(tok.CountTokens() == 3) {

        strncpy( user , tok.GetNextToken().c_str(), 256);
        strncpy( pass , tok.GetNextToken().c_str(), 256);
        strncpy( host , tok.GetNextToken().c_str(), 256);
    } else {
        // Check if it's a Speed Dial
        wxStrcpy(KeyPath,     "/Accounts/");
        wxStrcat(KeyPath,     RegName);
        config->SetPath(KeyPath);
        if(!config->Exists(KeyPath)) {
            theFrame->SetStatusText("Register format error");
            return;
        }
        wxStrcpy(user, config->Read("Username", ""));
        wxStrcpy(pass, config->Read("Password", ""));
        wxStrcpy(host, config->Read("Host", ""));
    }
    iaxc_register(user, pass, host);
}

int theApp::OnExit(void)
{
    // Delete the single instance checker
#ifndef __WXMAC__
    delete m_single_instance_checker;
#endif
    return 0;
}

//----------------------------------------------------------------------------------------
// Private methods
//----------------------------------------------------------------------------------------

void theApp::load_xrc_resource( const wxString& xrc_filename )
{
    wxConfig        *config = new wxConfig("iaxComm");
    wxString         xrc_fullname;
    static wxString  xrc_subdirectory = "";

#ifdef __WXMAC__
    if(xrc_subdirectory.IsEmpty()) {
        CFBundleRef mainBundle = CFBundleGetMainBundle ();
        CFURLRef resDir = CFBundleCopyResourcesDirectoryURL (mainBundle);
        CFURLRef resDirAbs = CFURLCopyAbsoluteURL (resDir);
        CFStringRef resPath = CFURLCopyFileSystemPath(resDirAbs, kCFURLPOSIXPathStyle);
        char path[1024];
        CFStringGetCString(resPath, path, 1024, kCFStringEncodingASCII);
        xrc_subdirectory = wxString(path) + wxFILE_SEP_PATH + _T("rc");
    }
#endif

    // First, look where we got the last xrc
    if(!xrc_subdirectory.IsEmpty()) {
        xrc_fullname = xrc_subdirectory + wxFILE_SEP_PATH + xrc_filename;
        if ( ::wxFileExists( xrc_fullname ) ) {
            wxXmlResource::Get()->Load( xrc_fullname );
            return;
        }
    }

    // Next, check where config points
    if(config->Exists("/Prefs/XRCDirectory")) {
        xrc_fullname = config->Read("/Prefs/XRCDirectory", "") + wxFILE_SEP_PATH + xrc_filename;
        if ( ::wxFileExists( xrc_fullname ) ) {
            wxXmlResource::Get()->Load( xrc_fullname );
            return;
        }
    }

    // Third, check in cwd
    xrc_fullname = wxGetCwd() + wxFILE_SEP_PATH + "rc" + wxFILE_SEP_PATH + xrc_filename;
    if ( ::wxFileExists( xrc_fullname ) ) {
        wxXmlResource::Get()->Load( xrc_fullname );
        return;
    }

    wxString dirHome;
    wxGetHomeDir(&dirHome);

    // Last, look in ~/rc
    xrc_fullname = dirHome + wxFILE_SEP_PATH + xrc_filename;
    if ( ::wxFileExists( xrc_fullname ) ) {
        wxXmlResource::Get()->Load( xrc_fullname );
        return;
    }
}

#ifdef __WXMSW__
BEGIN_EVENT_TABLE(MyTaskBarIcon, wxTaskBarIcon)
    EVT_MENU(XRCID("TaskBarRestore"), MyTaskBarIcon::OnRestore)
    EVT_MENU(XRCID("TaskBarHide"),    MyTaskBarIcon::OnHide)
    EVT_MENU(XRCID("TaskBarExit"),    MyTaskBarIcon::OnExit)
END_EVENT_TABLE()

void MyTaskBarIcon::OnRestore(wxCommandEvent&)
{
    wxGetApp().theFrame->Show(TRUE);
}

void MyTaskBarIcon::OnHide(wxCommandEvent&)
{
    wxGetApp().theFrame->Show(FALSE);
}

void MyTaskBarIcon::OnExit(wxCommandEvent&)
{
    wxGetApp().theFrame->Close(TRUE);
    wxGetApp().ProcessIdle();
}

void MyTaskBarIcon::OnLButtonDClick(wxEvent&)
{
    wxGetApp().theFrame->Close(TRUE);
    wxGetApp().ProcessIdle();
}

void MyTaskBarIcon::OnRButtonDown(wxEvent&)
{
    PopupMenu(wxXmlResource::Get()->LoadMenu(wxT("TaskBarMenu")));
}

void MyTaskBarIcon::OnLButtonDown(wxEvent&)
{
    wxGetApp().theFrame->Show(TRUE);
}
#endif

//----------------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------------

extern "C" {

   /* yes, using member variables, and polling for changes
    * isn't really a nice way to do callbacks.  BUT, I've tried the
    * "right" ways, unsuccessfully:
    *
    * 1) I've tried using wxGuiMutexEnter/Leave, but that deadlocks (and it should, I guess),
    * because sometimes these _are_ called in response to GUI events (i.e. the status callback eventually
    * gets called when you press hang up.
    *
    * 2) I've tried using events and ::wxPostEvent, but that also deadlocks (at least on GTK),
    * because it calls wxWakeUpIdle, which calls wxGuiMutexEnter, which deadlocks also, for some reason.
    *
    * So, this isn't ideal, but it works, until I can figure out a better way
    */

    // handle events via posting.
  #ifdef USE_GUILOCK
    static int iaxc_callback(iaxc_event e)
    {
        int ret;
        if (!wxThread::IsMain()) wxMutexGuiEnter();
            ret = wxGetApp().theFrame->HandleIAXEvent(&e);
        if (!wxThread::IsMain()) wxMutexGuiLeave();
            return ret;
    }
  #else
    static int iaxc_callback(iaxc_event e)
    {
        iaxc_event *copy;
        wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, IAXCLIENT_EVENT);

        copy = (iaxc_event *)malloc(sizeof(iaxc_event));
        memcpy(copy,&e,sizeof(iaxc_event));

        evt.SetClientData(copy);

        //fprintf(stderr, "Posting Event\n");
        wxPostEvent(wxGetApp().theFrame, evt);

        // pretend we handle all events.
        return 1;
    }
  #endif

}
<|endoftext|>