<commit_before>#ifndef BUFFER_CACHE_ALT_ALT_HPP_
#define BUFFER_CACHE_ALT_ALT_HPP_

#include <vector>
#include <utility>

#include "buffer_cache/alt/page.hpp"
#include "buffer_cache/general_types.hpp"
#include "concurrency/auto_drainer.hpp"
#include "concurrency/semaphore.hpp"
#include "containers/two_level_array.hpp"
#include "repli_timestamp.hpp"
#include "utils.hpp"

class serializer_t;

namespace alt {

class alt_buf_lock_t;
class alt_cache_config_t;
class alt_cache_stats_t;
class alt_snapshot_node_t;

class alt_memory_tracker_t : public memory_tracker_t {
public:
    alt_memory_tracker_t();
    ~alt_memory_tracker_t();
    void inform_memory_change(uint64_t in_memory_size,
                              uint64_t memory_limit);
    void begin_txn_or_throttle(int64_t expected_change_count);
    void end_txn(int64_t saved_expected_change_count);
private:
    adjustable_semaphore_t semaphore_;
    DISABLE_COPYING(alt_memory_tracker_t);
};

class alt_cache_t : public home_thread_mixin_t {
public:
    explicit alt_cache_t(serializer_t *serializer,
                         const alt_cache_config_t &dynamic_config,
                         perfmon_collection_t *perfmon_collection);
    ~alt_cache_t();

    block_size_t max_block_size() const;
    // RSI: Remove this.
    block_size_t get_block_size() const { return max_block_size(); }

    // These todos come from the mirrored cache.  The real problem is that whole
    // cache account / priority thing is just one ghetto hack amidst a dozen other
    // throttling systems.  TODO: Come up with a consistent priority scheme,
    // i.e. define a "default" priority etc.  TODO: As soon as we can support it, we
    // might consider supporting a mem_cap paremeter.
    void create_cache_account(int priority, scoped_ptr_t<alt_cache_account_t> *out);

private:
    friend class alt_txn_t;  // for drainer_->lock()
    friend class alt_inner_txn_t;  // for &page_cache_
    friend class alt_buf_read_t;  // for &page_cache_
    friend class alt_buf_write_t;  // for &page_cache_

    friend class alt_buf_lock_t;  // for latest_snapshot_node and
                                  // push_latest_snapshot_node

    alt_snapshot_node_t *matching_snapshot_node_or_null(block_id_t block_id,
                                                        block_version_t block_version);
    void add_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);
    void remove_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);

    scoped_ptr_t<alt_cache_stats_t> stats_;

    // tracker_ is used for throttling (which can cause the alt_txn_t constructor to
    // block).  RSI: The throttling interface is bad (maybe) because it's worried
    // about transaction_t's passing one another(?) or maybe the callers are bad with
    // their use of chained mutexes.  Make sure that timestamps don't get mixed up in
    // their ordering, once they begin to play a role.
    alt_memory_tracker_t tracker_;
    page_cache_t page_cache_;

    two_level_nevershrink_array_t<intrusive_list_t<alt_snapshot_node_t> > snapshot_nodes_by_block_id_;

    scoped_ptr_t<auto_drainer_t> drainer_;

    DISABLE_COPYING(alt_cache_t);
};

class alt_inner_txn_t {
public:
    // This is public because scoped_ptr_t needs to call it.
    ~alt_inner_txn_t();

private:
    friend class alt_txn_t;
    alt_inner_txn_t(alt_cache_t *cache,
                    // Unused for read transactions, pass repli_timestamp_t::invalid.
                    repli_timestamp_t txn_recency,
                    alt_inner_txn_t *preceding_txn_or_null);

    alt_cache_t *cache() { return cache_; }

    page_txn_t *page_txn() { return &page_txn_; }

    alt_cache_t *cache_;
    page_txn_t page_txn_;

    DISABLE_COPYING(alt_inner_txn_t);
};

class alt_txn_t {
public:
    // Constructor for read-only transactions.
    // RSI: Generally speaking I don't think we use preceding_txn -- and should read
    // transactions use preceding_txn at all?
    explicit alt_txn_t(alt_cache_t *cache,
                       alt_read_access_t read_access,
                       alt_txn_t *preceding_txn = NULL);

    // RSI: Remove default parameter for expected_change_count.
    // RSI: Generally speaking I don't think we use preceding_txn and we should.
    alt_txn_t(alt_cache_t *cache,
              write_durability_t durability,
              repli_timestamp_t txn_timestamp,
              int64_t expected_change_count = 2,
              alt_txn_t *preceding_txn = NULL);

    ~alt_txn_t();

    alt_cache_t *cache() { return inner_->cache(); }
    page_txn_t *page_txn() { return inner_->page_txn(); }
    alt_access_t access() const { return access_; }

    void set_account(alt_cache_account_t *cache_account);

private:
    static void destroy_inner_txn(alt_inner_txn_t *inner,
                                  alt_cache_t *cache,
                                  int64_t saved_expected_change_count,
                                  auto_drainer_t::lock_t);

    const alt_access_t access_;

    // Only applicable if access_ == write.
    const write_durability_t durability_;
    const int64_t saved_expected_change_count_;  // RSI: A fugly relationship with
                                                 // the tracker.

    scoped_ptr_t<alt_inner_txn_t> inner_;
    DISABLE_COPYING(alt_txn_t);
};

// The intrusive list of alt_snapshot_node_t contains all the snapshot nodes for a
// given block id, in order by version.  (See
// alt_cache_t::snapshot_nodes_by_block_id_.)
class alt_snapshot_node_t : public intrusive_list_node_t<alt_snapshot_node_t> {
public:
    alt_snapshot_node_t(scoped_ptr_t<current_page_acq_t> &&acq);
    ~alt_snapshot_node_t();

private:
    // RSI: Should this really use friends?  Does this type need to be visible in the
    // header?
    friend class alt_buf_lock_t;
    friend class alt_cache_t;

    // This is never null (and is always a current_page_acq_t that has had
    // declare_snapshotted() called).
    scoped_ptr_t<current_page_acq_t> current_page_acq_;

    // RSP: std::map memory usage.
    // A NULL pointer associated with a block id indicates that the block is deleted.
    std::map<block_id_t, alt_snapshot_node_t *> children_;

    // The number of alt_buf_lock_t's referring to this node, plus the number of
    // alt_snapshot_node_t's referring to this node (via its children_ vector).
    int64_t ref_count_;

    DISABLE_COPYING(alt_snapshot_node_t);
};

class alt_buf_parent_t;

class alt_buf_lock_t {
public:
    alt_buf_lock_t();

    // RSI: These constructors definitely duplicate one another.  Too bad one
    // constructor can't call another (in GCC 4.4).  Maybe we could still dedup
    // these, though, or get rid of some.  (Make alt_access_t include create, and
    // separate it from page_access_t?)

    // Nonblocking constructor.
    alt_buf_lock_t(alt_buf_parent_t parent,
                   block_id_t block_id,
                   alt_access_t access);

    // Nonblocking constructor, creates a new block with a specified block id.
    alt_buf_lock_t(alt_txn_t *txn,
                   block_id_t block_id,
                   alt_create_t create);

    // Nonblocking constructor, IF parent->{access}_acq_signal() has already been
    // pulsed.  In either case, returns before the block is acquired, but after we're
    // _in line_ for the block.
    alt_buf_lock_t(alt_buf_lock_t *parent,
                   block_id_t block_id,
                   alt_access_t access);

    // Nonblocking constructor that acquires a block with a new block id.  `access`
    // must be `write`.
    alt_buf_lock_t(alt_buf_parent_t parent,
                   alt_create_t create);

    // Nonblocking constructor, IF parent->{access}_acq_signal() has already been
    // pulsed.  Allocates a block with a new block id.  `access` must be `write`.
    alt_buf_lock_t(alt_buf_lock_t *parent,
                   alt_create_t create);

    ~alt_buf_lock_t();

    alt_buf_lock_t(alt_buf_lock_t &&movee);
    alt_buf_lock_t &operator=(alt_buf_lock_t &&movee);

    void swap(alt_buf_lock_t &other);
    void reset_buf_lock();
    bool empty() const {
        return txn_ == NULL;
    }

    void snapshot_subtree();

    void detach_child(block_id_t child_id);

    block_id_t block_id() const {
        guarantee(txn_ != NULL);
        return current_page_acq()->block_id();
    }
    // RSI: Remove get_block_id().
    block_id_t get_block_id() const { return block_id(); }

    // RSI: Rename.
    repli_timestamp_t get_recency() const;

    alt_access_t access() const {
        guarantee(!empty());
        return current_page_acq()->access();
    }

    signal_t *read_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->read_acq_signal();
    }
    signal_t *write_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->write_acq_signal();
    }

    void mark_deleted();

    alt_txn_t *txn() const { return txn_; }
    alt_cache_t *cache() const { return txn_->cache(); }

private:
    static void wait_for_parent(alt_buf_parent_t parent, alt_access_t access);
    static alt_snapshot_node_t *
    get_or_create_child_snapshot_node(alt_cache_t *cache,
                                      alt_snapshot_node_t *parent,
                                      block_id_t child_id);
    static void create_empty_child_snapshot_nodes(alt_cache_t *cache,
                                                  block_version_t parent_version,
                                                  block_id_t parent_id,
                                                  block_id_t child_id);
    static void create_child_snapshot_nodes(alt_cache_t *cache,
                                            block_version_t parent_version,
                                            block_id_t parent_id,
                                            block_id_t child_id);
    current_page_acq_t *current_page_acq() const;

    friend class alt_buf_read_t;  // for get_held_page_for_read, access_ref_count_.
    friend class alt_buf_write_t;  // for get_held_page_for_write, access_ref_count_.

    page_t *get_held_page_for_read();
    page_t *get_held_page_for_write();

    alt_txn_t *txn_;

    scoped_ptr_t<current_page_acq_t> current_page_acq_;

    alt_snapshot_node_t *snapshot_node_;

    // Keeps track of how many alt_buf_{read|write}_t have been created for
    // this lock, for assertion/guarantee purposes.
    intptr_t access_ref_count_;

    // RSI: We should get rid of this variable.
    bool was_destroyed_;

    DISABLE_COPYING(alt_buf_lock_t);
};

class alt_buf_parent_t {
public:
    alt_buf_parent_t() : txn_(NULL), lock_or_null_(NULL) { }

    explicit alt_buf_parent_t(alt_buf_lock_t *lock)
        : txn_(lock->txn()), lock_or_null_(lock) {
        guarantee(lock != NULL);
        guarantee(!lock->empty());
    }
    // RSI: Replace this constructor with a create_dangerously static method.
    explicit alt_buf_parent_t(alt_txn_t *txn)
        : txn_(txn), lock_or_null_(NULL) { }

    alt_txn_t *txn() const {
        guarantee(txn_ != NULL);
        return txn_;
    }
    alt_cache_t *cache() const {
        guarantee(txn_ != NULL);
        return txn_->cache();
    }

private:
    friend class alt_buf_lock_t;
    alt_txn_t *txn_;
    alt_buf_lock_t *lock_or_null_;
};

class alt_buf_read_t {
public:
    explicit alt_buf_read_t(alt_buf_lock_t *lock);
    ~alt_buf_read_t();

    const void *get_data_read(uint32_t *block_size_out);
    // RSI: Remove.
    const void *get_data_read() {
        uint32_t unused_block_size;
        return get_data_read(&unused_block_size);
    }

private:
    alt_buf_lock_t *lock_;
    page_acq_t page_acq_;

    DISABLE_COPYING(alt_buf_read_t);
};

class alt_buf_write_t {
public:
    explicit alt_buf_write_t(alt_buf_lock_t *lock);
    ~alt_buf_write_t();

    void *get_data_write(uint32_t block_size);
    // Equivalent to passing the max_block_size.
    void *get_data_write();

private:
    alt_buf_lock_t *lock_;
    page_acq_t page_acq_;

    DISABLE_COPYING(alt_buf_write_t);
};

}  // namespace alt

#endif  // BUFFER_CACHE_ALT_ALT_HPP_
<commit_msg>Fixed some trivial style problems.<commit_after>#ifndef BUFFER_CACHE_ALT_ALT_HPP_
#define BUFFER_CACHE_ALT_ALT_HPP_

#include <map>
#include <vector>
#include <utility>

#include "buffer_cache/alt/page.hpp"
#include "buffer_cache/general_types.hpp"
#include "concurrency/auto_drainer.hpp"
#include "concurrency/semaphore.hpp"
#include "containers/two_level_array.hpp"
#include "repli_timestamp.hpp"
#include "utils.hpp"

class serializer_t;

namespace alt {

class alt_buf_lock_t;
class alt_cache_config_t;
class alt_cache_stats_t;
class alt_snapshot_node_t;

class alt_memory_tracker_t : public memory_tracker_t {
public:
    alt_memory_tracker_t();
    ~alt_memory_tracker_t();
    void inform_memory_change(uint64_t in_memory_size,
                              uint64_t memory_limit);
    void begin_txn_or_throttle(int64_t expected_change_count);
    void end_txn(int64_t saved_expected_change_count);
private:
    adjustable_semaphore_t semaphore_;
    DISABLE_COPYING(alt_memory_tracker_t);
};

class alt_cache_t : public home_thread_mixin_t {
public:
    explicit alt_cache_t(serializer_t *serializer,
                         const alt_cache_config_t &dynamic_config,
                         perfmon_collection_t *perfmon_collection);
    ~alt_cache_t();

    block_size_t max_block_size() const;
    // RSI: Remove this.
    block_size_t get_block_size() const { return max_block_size(); }

    // These todos come from the mirrored cache.  The real problem is that whole
    // cache account / priority thing is just one ghetto hack amidst a dozen other
    // throttling systems.  TODO: Come up with a consistent priority scheme,
    // i.e. define a "default" priority etc.  TODO: As soon as we can support it, we
    // might consider supporting a mem_cap paremeter.
    void create_cache_account(int priority, scoped_ptr_t<alt_cache_account_t> *out);

private:
    friend class alt_txn_t;  // for drainer_->lock()
    friend class alt_inner_txn_t;  // for &page_cache_
    friend class alt_buf_read_t;  // for &page_cache_
    friend class alt_buf_write_t;  // for &page_cache_

    friend class alt_buf_lock_t;  // for latest_snapshot_node and
                                  // push_latest_snapshot_node

    alt_snapshot_node_t *matching_snapshot_node_or_null(block_id_t block_id,
                                                        block_version_t block_version);
    void add_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);
    void remove_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);

    scoped_ptr_t<alt_cache_stats_t> stats_;

    // tracker_ is used for throttling (which can cause the alt_txn_t constructor to
    // block).  RSI: The throttling interface is bad (maybe) because it's worried
    // about transaction_t's passing one another(?) or maybe the callers are bad with
    // their use of chained mutexes.  Make sure that timestamps don't get mixed up in
    // their ordering, once they begin to play a role.
    alt_memory_tracker_t tracker_;
    page_cache_t page_cache_;

    two_level_nevershrink_array_t<intrusive_list_t<alt_snapshot_node_t> > snapshot_nodes_by_block_id_;

    scoped_ptr_t<auto_drainer_t> drainer_;

    DISABLE_COPYING(alt_cache_t);
};

class alt_inner_txn_t {
public:
    // This is public because scoped_ptr_t needs to call it.
    ~alt_inner_txn_t();

private:
    friend class alt_txn_t;
    alt_inner_txn_t(alt_cache_t *cache,
                    // Unused for read transactions, pass repli_timestamp_t::invalid.
                    repli_timestamp_t txn_recency,
                    alt_inner_txn_t *preceding_txn_or_null);

    alt_cache_t *cache() { return cache_; }

    page_txn_t *page_txn() { return &page_txn_; }

    alt_cache_t *cache_;
    page_txn_t page_txn_;

    DISABLE_COPYING(alt_inner_txn_t);
};

class alt_txn_t {
public:
    // Constructor for read-only transactions.
    // RSI: Generally speaking I don't think we use preceding_txn -- and should read
    // transactions use preceding_txn at all?
    explicit alt_txn_t(alt_cache_t *cache,
                       alt_read_access_t read_access,
                       alt_txn_t *preceding_txn = NULL);

    // RSI: Remove default parameter for expected_change_count.
    // RSI: Generally speaking I don't think we use preceding_txn and we should.
    alt_txn_t(alt_cache_t *cache,
              write_durability_t durability,
              repli_timestamp_t txn_timestamp,
              int64_t expected_change_count = 2,
              alt_txn_t *preceding_txn = NULL);

    ~alt_txn_t();

    alt_cache_t *cache() { return inner_->cache(); }
    page_txn_t *page_txn() { return inner_->page_txn(); }
    alt_access_t access() const { return access_; }

    void set_account(alt_cache_account_t *cache_account);

private:
    static void destroy_inner_txn(alt_inner_txn_t *inner,
                                  alt_cache_t *cache,
                                  int64_t saved_expected_change_count,
                                  auto_drainer_t::lock_t);

    const alt_access_t access_;

    // Only applicable if access_ == write.
    const write_durability_t durability_;
    const int64_t saved_expected_change_count_;  // RSI: A fugly relationship with
                                                 // the tracker.

    scoped_ptr_t<alt_inner_txn_t> inner_;
    DISABLE_COPYING(alt_txn_t);
};

// The intrusive list of alt_snapshot_node_t contains all the snapshot nodes for a
// given block id, in order by version.  (See
// alt_cache_t::snapshot_nodes_by_block_id_.)
class alt_snapshot_node_t : public intrusive_list_node_t<alt_snapshot_node_t> {
public:
    explicit alt_snapshot_node_t(scoped_ptr_t<current_page_acq_t> &&acq);
    ~alt_snapshot_node_t();

private:
    // RSI: Should this really use friends?  Does this type need to be visible in the
    // header?
    friend class alt_buf_lock_t;
    friend class alt_cache_t;

    // This is never null (and is always a current_page_acq_t that has had
    // declare_snapshotted() called).
    scoped_ptr_t<current_page_acq_t> current_page_acq_;

    // RSP: std::map memory usage.
    // A NULL pointer associated with a block id indicates that the block is deleted.
    std::map<block_id_t, alt_snapshot_node_t *> children_;

    // The number of alt_buf_lock_t's referring to this node, plus the number of
    // alt_snapshot_node_t's referring to this node (via its children_ vector).
    int64_t ref_count_;

    DISABLE_COPYING(alt_snapshot_node_t);
};

class alt_buf_parent_t;

class alt_buf_lock_t {
public:
    alt_buf_lock_t();

    // RSI: These constructors definitely duplicate one another.  Too bad one
    // constructor can't call another (in GCC 4.4).  Maybe we could still dedup
    // these, though, or get rid of some.  (Make alt_access_t include create, and
    // separate it from page_access_t?)

    // Nonblocking constructor.
    alt_buf_lock_t(alt_buf_parent_t parent,
                   block_id_t block_id,
                   alt_access_t access);

    // Nonblocking constructor, creates a new block with a specified block id.
    alt_buf_lock_t(alt_txn_t *txn,
                   block_id_t block_id,
                   alt_create_t create);

    // Nonblocking constructor, IF parent->{access}_acq_signal() has already been
    // pulsed.  In either case, returns before the block is acquired, but after we're
    // _in line_ for the block.
    alt_buf_lock_t(alt_buf_lock_t *parent,
                   block_id_t block_id,
                   alt_access_t access);

    // Nonblocking constructor that acquires a block with a new block id.  `access`
    // must be `write`.
    alt_buf_lock_t(alt_buf_parent_t parent,
                   alt_create_t create);

    // Nonblocking constructor, IF parent->{access}_acq_signal() has already been
    // pulsed.  Allocates a block with a new block id.  `access` must be `write`.
    alt_buf_lock_t(alt_buf_lock_t *parent,
                   alt_create_t create);

    ~alt_buf_lock_t();

    alt_buf_lock_t(alt_buf_lock_t &&movee);
    alt_buf_lock_t &operator=(alt_buf_lock_t &&movee);

    void swap(alt_buf_lock_t &other);
    void reset_buf_lock();
    bool empty() const {
        return txn_ == NULL;
    }

    void snapshot_subtree();

    void detach_child(block_id_t child_id);

    block_id_t block_id() const {
        guarantee(txn_ != NULL);
        return current_page_acq()->block_id();
    }
    // RSI: Remove get_block_id().
    block_id_t get_block_id() const { return block_id(); }

    // RSI: Rename.
    repli_timestamp_t get_recency() const;

    alt_access_t access() const {
        guarantee(!empty());
        return current_page_acq()->access();
    }

    signal_t *read_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->read_acq_signal();
    }
    signal_t *write_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->write_acq_signal();
    }

    void mark_deleted();

    alt_txn_t *txn() const { return txn_; }
    alt_cache_t *cache() const { return txn_->cache(); }

private:
    static void wait_for_parent(alt_buf_parent_t parent, alt_access_t access);
    static alt_snapshot_node_t *
    get_or_create_child_snapshot_node(alt_cache_t *cache,
                                      alt_snapshot_node_t *parent,
                                      block_id_t child_id);
    static void create_empty_child_snapshot_nodes(alt_cache_t *cache,
                                                  block_version_t parent_version,
                                                  block_id_t parent_id,
                                                  block_id_t child_id);
    static void create_child_snapshot_nodes(alt_cache_t *cache,
                                            block_version_t parent_version,
                                            block_id_t parent_id,
                                            block_id_t child_id);
    current_page_acq_t *current_page_acq() const;

    friend class alt_buf_read_t;  // for get_held_page_for_read, access_ref_count_.
    friend class alt_buf_write_t;  // for get_held_page_for_write, access_ref_count_.

    page_t *get_held_page_for_read();
    page_t *get_held_page_for_write();

    alt_txn_t *txn_;

    scoped_ptr_t<current_page_acq_t> current_page_acq_;

    alt_snapshot_node_t *snapshot_node_;

    // Keeps track of how many alt_buf_{read|write}_t have been created for
    // this lock, for assertion/guarantee purposes.
    intptr_t access_ref_count_;

    // RSI: We should get rid of this variable.
    bool was_destroyed_;

    DISABLE_COPYING(alt_buf_lock_t);
};

class alt_buf_parent_t {
public:
    alt_buf_parent_t() : txn_(NULL), lock_or_null_(NULL) { }

    explicit alt_buf_parent_t(alt_buf_lock_t *lock)
        : txn_(lock->txn()), lock_or_null_(lock) {
        guarantee(lock != NULL);
        guarantee(!lock->empty());
    }
    // RSI: Replace this constructor with a create_dangerously static method.
    explicit alt_buf_parent_t(alt_txn_t *txn)
        : txn_(txn), lock_or_null_(NULL) { }

    alt_txn_t *txn() const {
        guarantee(txn_ != NULL);
        return txn_;
    }
    alt_cache_t *cache() const {
        guarantee(txn_ != NULL);
        return txn_->cache();
    }

private:
    friend class alt_buf_lock_t;
    alt_txn_t *txn_;
    alt_buf_lock_t *lock_or_null_;
};

class alt_buf_read_t {
public:
    explicit alt_buf_read_t(alt_buf_lock_t *lock);
    ~alt_buf_read_t();

    const void *get_data_read(uint32_t *block_size_out);
    // RSI: Remove.
    const void *get_data_read() {
        uint32_t unused_block_size;
        return get_data_read(&unused_block_size);
    }

private:
    alt_buf_lock_t *lock_;
    page_acq_t page_acq_;

    DISABLE_COPYING(alt_buf_read_t);
};

class alt_buf_write_t {
public:
    explicit alt_buf_write_t(alt_buf_lock_t *lock);
    ~alt_buf_write_t();

    void *get_data_write(uint32_t block_size);
    // Equivalent to passing the max_block_size.
    void *get_data_write();

private:
    alt_buf_lock_t *lock_;
    page_acq_t page_acq_;

    DISABLE_COPYING(alt_buf_write_t);
};

}  // namespace alt

#endif  // BUFFER_CACHE_ALT_ALT_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbIceViewer.h"
#include "otbDEMHandler.h"

void error_callback(int, const char* description)
{
  std::cerr << description << std::endl;
}

int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    std::cerr << "Usage: " << argv[0] << " img1 ... imgN" << std::endl << std::endl;

    return EXIT_FAILURE;
  }

  char* demdir    = getenv("OTB_DEM_DIR");
  char* geoidfile = getenv("OTB_GEOID_FILE");

  otb::DEMHandler::Pointer demHandler = otb::DEMHandler::Instance();

  if (demdir != nullptr)
  {
    std::cout << "Configuring DEM directory: " << demdir << std::endl;
    demHandler->OpenDEMDirectory(demdir);
  }

  if (geoidfile != nullptr)
  {
    std::cout << "Configuring geoid file: " << geoidfile << std::endl;
    demHandler->OpenGeoidFile(geoidfile);
  }

  otb::IceViewer::Pointer viewer = otb::IceViewer::New();

  // Initialize viewer
  try
  {
    viewer->Initialize(800, 600);
  }
  catch (itk::ExceptionObject& err)
  {
    std::cerr << "Failed to initialized viewer: " << err << std::endl;
    return EXIT_FAILURE;
  }

  for (int i = 1; i < argc; ++i)
  {
    try
    {
      viewer->AddImage(argv[i], argv[i]);
    }
    catch (itk::ExceptionObject& err)
    {
      std::cerr << "Failed to open object as image: " << err << std::endl;
      try
      {
        viewer->AddVector(argv[i], argv[i]);
      }
      catch (itk::ExceptionObject& err2)
      {
        std::cerr << "Failed to open object as vector: " << err2 << std::endl;
        std::cerr << "Could not open file " << argv[i] << " as an image or a vector, skipping." << std::endl;
      }
    }
    catch (std::runtime_error& err)
    {
      std::cerr << "Runtime error: " << err.what() << std::endl;
      return EXIT_FAILURE;
    }
  }

  std::cout << "Press F1 for help" << std::endl;

  viewer->Start();

  return EXIT_SUCCESS;
}
<commit_msg>BUG: use the new DEMHandler API in Ice<commit_after>/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbIceViewer.h"
#include "otbDEMHandler.h"

void error_callback(int, const char* description)
{
  std::cerr << description << std::endl;
}

int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    std::cerr << "Usage: " << argv[0] << " img1 ... imgN" << std::endl << std::endl;

    return EXIT_FAILURE;
  }

  char* demdir    = getenv("OTB_DEM_DIR");
  char* geoidfile = getenv("OTB_GEOID_FILE");

  auto& demHandler = otb::DEMHandler::GetInstance();

  if (demdir != nullptr)
  {
    std::cout << "Configuring DEM directory: " << demdir << std::endl;
    demHandler.OpenDEMDirectory(demdir);
  }

  if (geoidfile != nullptr)
  {
    std::cout << "Configuring geoid file: " << geoidfile << std::endl;
    demHandler.OpenGeoidFile(geoidfile);
  }

  otb::IceViewer::Pointer viewer = otb::IceViewer::New();

  // Initialize viewer
  try
  {
    viewer->Initialize(800, 600);
  }
  catch (itk::ExceptionObject& err)
  {
    std::cerr << "Failed to initialized viewer: " << err << std::endl;
    return EXIT_FAILURE;
  }

  for (int i = 1; i < argc; ++i)
  {
    try
    {
      viewer->AddImage(argv[i], argv[i]);
    }
    catch (itk::ExceptionObject& err)
    {
      std::cerr << "Failed to open object as image: " << err << std::endl;
      try
      {
        viewer->AddVector(argv[i], argv[i]);
      }
      catch (itk::ExceptionObject& err2)
      {
        std::cerr << "Failed to open object as vector: " << err2 << std::endl;
        std::cerr << "Could not open file " << argv[i] << " as an image or a vector, skipping." << std::endl;
      }
    }
    catch (std::runtime_error& err)
    {
      std::cerr << "Runtime error: " << err.what() << std::endl;
      return EXIT_FAILURE;
    }
  }

  std::cout << "Press F1 for help" << std::endl;

  viewer->Start();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: salgeom.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2007-04-11 18:06:34 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _SV_SALGEOM_HXX
#define _SV_SALGEOM_HXX

typedef struct _SalFrameGeometry {
    // screen position of upper left corner of drawable area in pixel
    int                 nX, nY;
    // dimensions of the drawable area in pixel
    unsigned int        nWidth, nHeight;
    // thickness of the decoration in pixel
    unsigned int        nLeftDecoration,
                        nTopDecoration,
                        nRightDecoration,
                        nBottomDecoration;
} SalFrameGeometry;

#endif // _SV_SALGEOM_HXX
<commit_msg>INTEGRATION: CWS presenterview (1.2.24); FILE MERGED 2007/10/12 13:25:56 pl 1.2.24.1: #i82554# add WB_SYSTEMCHILDWINDOW<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: salgeom.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-03 15:47:24 $
 *
 *  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
 *
 ************************************************************************/

#ifndef _SV_SALGEOM_HXX
#define _SV_SALGEOM_HXX

typedef struct _SalFrameGeometry {
    // screen position of upper left corner of drawable area in pixel
    int                 nX, nY;
    // dimensions of the drawable area in pixel
    unsigned int        nWidth, nHeight;
    // thickness of the decoration in pixel
    unsigned int        nLeftDecoration,
                        nTopDecoration,
                        nRightDecoration,
                        nBottomDecoration;
    unsigned int        nScreenNumber;

    _SalFrameGeometry() :
    nX( 0 ), nY( 0 ), nWidth( 1 ), nHeight( 1 ),
    nLeftDecoration( 0 ), nTopDecoration( 0 ),
    nRightDecoration( 0 ), nBottomDecoration( 0 ),
    nScreenNumber( 0 )
    {}
} SalFrameGeometry;

#endif // _SV_SALGEOM_HXX
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "audiooutput.h"
#include <QVector>
#include <QtCore/QCoreApplication>

#include <sys/ioctl.h>
#include <iostream>
#include <QSet>
#include "mediaobject.h"
#include "backend.h"
#include "events.h"
#include "wirecall.h"
#include "xineengine.h"
#include "xinethread.h"
#include "keepreference.h"
#include "audiodataoutput.h"

#include <xine/audio_out.h>

// the gcc 4.0 STL includes assert.h
#undef assert

namespace Phonon
{
namespace Xine
{

AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput(new AudioOutputXT, parent)
{
}

AudioOutput::~AudioOutput()
{
    //debug() << Q_FUNC_INFO ;
}

AudioOutputXT::~AudioOutputXT()
{
    if (m_audioPort) {
        xine_close_audio_driver(m_xine, m_audioPort);
        m_audioPort = 0;
        debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port destroyed";
    }
}

qreal AudioOutput::volume() const
{
    return m_volume;
}

int AudioOutput::outputDevice() const
{
    return m_device.index();
}

void AudioOutput::setVolume(qreal newVolume)
{
    m_volume = newVolume;

    int xinevolume = static_cast<int>(m_volume * 100);
    if (xinevolume > 200) {
        xinevolume = 200;
    } else if (xinevolume < 0) {
        xinevolume = 0;
    }

    upstreamEvent(new UpdateVolumeEvent(xinevolume));
    emit volumeChanged(m_volume);
}

xine_audio_port_t *AudioOutputXT::audioPort() const
{
    return m_audioPort;
}

static QByteArray audioDriverFor(const QByteArray &driver)
{
    if (driver == "alsa" || driver == "oss" || driver == "pulseaudio" || driver == "esd" ||
            driver == "arts" || driver == "jack") {
        return driver;
    }
    return QByteArray();
}

static bool lookupConfigEntry(xine_t *xine, const char *key, xine_cfg_entry_t *entry, const char *driver)
{
    if(!xine_config_lookup_entry(xine, key, entry)) {
        // the config key is not registered yet - it is registered when the output
        // plugin is opened. So we open the plugin and close it again, then we can set the
        // setting. :(
        xine_audio_port_t *port = xine_open_audio_driver(xine, driver, 0);
        if (port) {
            xine_close_audio_driver(xine, port);
            // port == 0 does not have to be fatal, since it might be only the default device
            // that cannot be opened
        }
        // now the config key should be registered
        if(!xine_config_lookup_entry(xine, key, entry)) {
            qWarning() << "cannot configure the device on Xine's" << driver << "output plugin";
            return false;
        }
    }
    return true;
}

xine_audio_port_t *AudioOutput::createPort(const AudioOutputDevice &deviceDesc)
{
    K_XT(AudioOutput);
    xine_audio_port_t *port = 0;
    if (!deviceDesc.isValid()) {
        // use null output for invalid devices
        port = xine_open_audio_driver(xt->m_xine, "none", 0);
        debug() << Q_FUNC_INFO << "----------------------------------------------- null audio_port created";
        return port;
    }

    typedef QPair<QByteArray, QString> PhononDeviceAccess;
    QList<PhononDeviceAccess> deviceAccessList = deviceAccessListFor(deviceDesc);
    if (deviceAccessList.isEmpty()) {
        const QByteArray &outputPlugin = Backend::audioDriverFor(deviceDesc.index());
        if (outputPlugin == "alsa") {
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=0"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=1"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=2"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=3"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=4"));
        } else if (outputPlugin == "oss") {
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp1"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp2"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp3"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp4"));
        } else {
            debug() << Q_FUNC_INFO << "use output plugin:" << outputPlugin;
            port = xine_open_audio_driver(xt->m_xine, outputPlugin.constData(), 0);
            debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
            return port;
        }
    }
    const QList<PhononDeviceAccess> &_deviceAccessList = deviceAccessList;
    foreach (const PhononDeviceAccess &access, _deviceAccessList) {
        const QByteArray &outputPlugin = audioDriverFor(access.first);
        if (outputPlugin.isEmpty()) {
            continue;
        }
        const QString &handle = access.second;
        if (outputPlugin == "alsa") {
            xine_cfg_entry_t deviceConfig;
            if (!lookupConfigEntry(xt->m_xine, "audio.device.alsa_default_device",
                        &deviceConfig, "alsa")) {
                continue;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_STRING);
            QByteArray deviceStr = handle.toUtf8();
            deviceConfig.str_value = deviceStr.data();
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            const int err = xine_config_lookup_entry(xt->m_xine, "audio.device.alsa_front_device",
                    &deviceConfig);
            Q_ASSERT(err); Q_UNUSED(err);
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_STRING);
            deviceConfig.str_value = deviceStr.data();
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            port = xine_open_audio_driver(xt->m_xine, "alsa", 0);
            if (port) {
                debug() << Q_FUNC_INFO << "use ALSA device: " << handle;
                debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
                return port;
            }
        } else if (outputPlugin == "pulseaudio") {
            xine_cfg_entry_t deviceConfig;
            if (!lookupConfigEntry(xt->m_xine, "audio.pulseaudio_device", &deviceConfig,
                    "pulseaudio")) {
                continue;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_STRING);
            QByteArray deviceStr = handle.toUtf8();
            deviceStr.replace('\n', ':');
            deviceConfig.str_value = deviceStr.data();
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            port = xine_open_audio_driver(xt->m_xine, "pulseaudio", 0);
            if (port) {
                debug() << Q_FUNC_INFO << "use PulseAudio: " << handle;
                debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
                return port;
            }
        } else if (outputPlugin == "oss") {
            xine_cfg_entry_t deviceConfig;
            if (!lookupConfigEntry(xt->m_xine, "audio.device.oss_device_name", &deviceConfig,
                        "oss")) {
                continue;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_ENUM);
            deviceConfig.num_value = 0;
            xine_config_update_entry(xt->m_xine, &deviceConfig);
            if(!xine_config_lookup_entry(xt->m_xine, "audio.device.oss_device_number",
                        &deviceConfig)) {
                qWarning() << "cannot set the OSS device on Xine's OSS output plugin";
                return 0;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_NUM);
            const QByteArray &deviceStr = handle.toUtf8();
            char lastChar = deviceStr[deviceStr.length() - 1];
            int deviceNumber = -1;
            if (lastChar >= '0' || lastChar <= '9') {
                deviceNumber = lastChar - '0';
                char lastChar = deviceStr[deviceStr.length() - 2];
                if (lastChar >= '0' || lastChar <= '9') {
                    deviceNumber += 10 * (lastChar - '0');
                }
            }
            deviceConfig.num_value = deviceNumber;
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            port = xine_open_audio_driver(xt->m_xine, "oss", 0);
            if (port) {
                debug() << Q_FUNC_INFO << "use OSS device: " << handle;
                debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
                return port;
            }
        }
    }
    return port;
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    return setOutputDevice(AudioOutputDevice::fromIndex(newDevice));
}

bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
    K_XT(AudioOutput);
    if (!xt->m_xine) {
        // remeber the choice until we have a xine_t
        m_device = newDevice;
        return true;
    }

    xine_audio_port_t *port = createPort(newDevice);
    if (!port) {
        debug() << Q_FUNC_INFO << "new audio port is invalid";
        return false;
    }

    KeepReference<> *keep = new KeepReference<>;
    keep->addObject(xt);
    keep->ready();

    AudioOutputXT *newXt = new AudioOutputXT;
    newXt->m_audioPort = port;
    newXt->m_xine = xt->m_xine;
    m_threadSafeObject = newXt;

    m_device = newDevice;
    SourceNode *src = source();
    if (src) {
        QList<WireCall> wireCall;
        QList<WireCall> unwireCall;
        wireCall << WireCall(src, this);
        unwireCall << WireCall(src, QExplicitlySharedDataPointer<SinkNodeXT>(xt));
        QCoreApplication::postEvent(XineThread::instance(), new RewireEvent(wireCall, unwireCall));
        graphChanged();
    }

    AudioDataOutputXT *dataOutput = dynamic_cast<AudioDataOutputXT*>(m_source->threadSafeObject().data());
    if (dataOutput)
        dataOutput->intercept(xt->m_audioPort);

    return true;
}

void AudioOutput::xineEngineChanged()
{
    K_XT(AudioOutput);
    if (xt->m_xine) {
        xine_audio_port_t *port = createPort(m_device);
        if (!port) {
            debug() << Q_FUNC_INFO << "stored audio port is invalid";
            QMetaObject::invokeMethod(this, "audioDeviceFailed", Qt::QueuedConnection);
            return;
        }

        // our XT object is in a wirecall, better not delete it

        Q_ASSERT(xt->m_audioPort == 0);
        xt->m_audioPort = port;

        AudioDataOutputXT *dataOutput = dynamic_cast<AudioDataOutputXT*>(m_source->threadSafeObject().data());
        if (dataOutput)
            dataOutput->intercept(xt->m_audioPort);
    }
}

void AudioOutput::aboutToChangeXineEngine()
{
    K_XT(AudioOutput);
    if (xt->m_audioPort) {
        AudioOutputXT *xt2 = new AudioOutputXT;
        xt2->m_xine = xt->m_xine;
        xt2->m_audioPort = xt->m_audioPort;
        xt->m_audioPort = 0;
        KeepReference<> *keep = new KeepReference<>;
        keep->addObject(xt2);
        keep->ready();
    }
}

void AudioOutput::downstreamEvent(Event *e)
{
    Q_ASSERT(e);
    QCoreApplication::sendEvent(this, e);
    SinkNode::downstreamEvent(e);
}

void AudioOutputXT::rewireTo(SourceNodeXT *source)
{
    if (!source->audioOutputPort()) {
        return;
    }
    source->assert();
    xine_post_wire_audio_port(source->audioOutputPort(), m_audioPort);
    source->assert();
    SinkNodeXT::assert();
}

bool AudioOutput::event(QEvent *ev)
{
    switch (ev->type()) {
    case Event::AudioDeviceFailed:
        {
            ev->accept();
            // we don't know for sure which AudioPort failed. We also can't know from the
            // information libxine makes available. So we have to just try the old device again
            if (setOutputDevice(m_device)) {
                return true;
            }
            // we really need a different output device
            QMetaObject::invokeMethod(this, "audioDeviceFailed", Qt::QueuedConnection);
        }
        return true;
    default:
        return AbstractAudioOutput::event(ev);
    }
}

void AudioOutput::graphChanged()
{
    debug() << Q_FUNC_INFO;
    // we got connected to a new XineStream, it needs to know our m_volume
    int xinevolume = static_cast<int>(m_volume * 100);
    if (xinevolume > 200) {
        xinevolume = 200;
    } else if (xinevolume < 0) {
        xinevolume = 0;
    }
    upstreamEvent(new UpdateVolumeEvent(xinevolume));
}

}} //namespace Phonon::Xine

#include "audiooutput.moc"
// vim: sw=4 ts=4
<commit_msg>xine: Fix output when using PulseAudio after latest changes.<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "audiooutput.h"
#include <QVector>
#include <QtCore/QCoreApplication>

#include <sys/ioctl.h>
#include <iostream>
#include <QSet>
#include "mediaobject.h"
#include "backend.h"
#include "events.h"
#include "wirecall.h"
#include "xineengine.h"
#include "xinethread.h"
#include "keepreference.h"
#include "audiodataoutput.h"

#include <xine/audio_out.h>

// the gcc 4.0 STL includes assert.h
#undef assert

namespace Phonon
{
namespace Xine
{

AudioOutput::AudioOutput(QObject *parent)
    : AbstractAudioOutput(new AudioOutputXT, parent)
{
    // Always initialise the "device" in use.
    // This is needed for PulseAudio support as subsequent calls to setOutputDevice()
    // are suppressed
    setOutputDevice(0);
}

AudioOutput::~AudioOutput()
{
    //debug() << Q_FUNC_INFO ;
}

AudioOutputXT::~AudioOutputXT()
{
    if (m_audioPort) {
        xine_close_audio_driver(m_xine, m_audioPort);
        m_audioPort = 0;
        debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port destroyed";
    }
}

qreal AudioOutput::volume() const
{
    return m_volume;
}

int AudioOutput::outputDevice() const
{
    return m_device.index();
}

void AudioOutput::setVolume(qreal newVolume)
{
    m_volume = newVolume;

    int xinevolume = static_cast<int>(m_volume * 100);
    if (xinevolume > 200) {
        xinevolume = 200;
    } else if (xinevolume < 0) {
        xinevolume = 0;
    }

    upstreamEvent(new UpdateVolumeEvent(xinevolume));
    emit volumeChanged(m_volume);
}

xine_audio_port_t *AudioOutputXT::audioPort() const
{
    return m_audioPort;
}

static QByteArray audioDriverFor(const QByteArray &driver)
{
    if (driver == "alsa" || driver == "oss" || driver == "pulseaudio" || driver == "esd" ||
            driver == "arts" || driver == "jack") {
        return driver;
    }
    return QByteArray();
}

static bool lookupConfigEntry(xine_t *xine, const char *key, xine_cfg_entry_t *entry, const char *driver)
{
    if(!xine_config_lookup_entry(xine, key, entry)) {
        // the config key is not registered yet - it is registered when the output
        // plugin is opened. So we open the plugin and close it again, then we can set the
        // setting. :(
        xine_audio_port_t *port = xine_open_audio_driver(xine, driver, 0);
        if (port) {
            xine_close_audio_driver(xine, port);
            // port == 0 does not have to be fatal, since it might be only the default device
            // that cannot be opened
        }
        // now the config key should be registered
        if(!xine_config_lookup_entry(xine, key, entry)) {
            qWarning() << "cannot configure the device on Xine's" << driver << "output plugin";
            return false;
        }
    }
    return true;
}

xine_audio_port_t *AudioOutput::createPort(const AudioOutputDevice &deviceDesc)
{
    K_XT(AudioOutput);
    xine_audio_port_t *port = 0;
    if (!deviceDesc.isValid()) {
        // use null output for invalid devices
        port = xine_open_audio_driver(xt->m_xine, "none", 0);
        debug() << Q_FUNC_INFO << "----------------------------------------------- null audio_port created";
        return port;
    }

    typedef QPair<QByteArray, QString> PhononDeviceAccess;
    QList<PhononDeviceAccess> deviceAccessList = deviceAccessListFor(deviceDesc);
    if (deviceAccessList.isEmpty()) {
        const QByteArray &outputPlugin = Backend::audioDriverFor(deviceDesc.index());
        if (outputPlugin == "alsa") {
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=0"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=1"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=2"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=3"));
            deviceAccessList << PhononDeviceAccess("alsa", QLatin1String("default:CARD=4"));
        } else if (outputPlugin == "oss") {
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp1"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp2"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp3"));
            deviceAccessList << PhononDeviceAccess("oss", QLatin1String("/dev/dsp4"));
        } else {
            debug() << Q_FUNC_INFO << "use output plugin:" << outputPlugin;
            port = xine_open_audio_driver(xt->m_xine, outputPlugin.constData(), 0);
            debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
            return port;
        }
    }
    const QList<PhononDeviceAccess> &_deviceAccessList = deviceAccessList;
    foreach (const PhononDeviceAccess &access, _deviceAccessList) {
        const QByteArray &outputPlugin = audioDriverFor(access.first);
        if (outputPlugin.isEmpty()) {
            continue;
        }
        const QString &handle = access.second;
        if (outputPlugin == "alsa") {
            xine_cfg_entry_t deviceConfig;
            if (!lookupConfigEntry(xt->m_xine, "audio.device.alsa_default_device",
                        &deviceConfig, "alsa")) {
                continue;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_STRING);
            QByteArray deviceStr = handle.toUtf8();
            deviceConfig.str_value = deviceStr.data();
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            const int err = xine_config_lookup_entry(xt->m_xine, "audio.device.alsa_front_device",
                    &deviceConfig);
            Q_ASSERT(err); Q_UNUSED(err);
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_STRING);
            deviceConfig.str_value = deviceStr.data();
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            port = xine_open_audio_driver(xt->m_xine, "alsa", 0);
            if (port) {
                debug() << Q_FUNC_INFO << "use ALSA device: " << handle;
                debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
                return port;
            }
        } else if (outputPlugin == "pulseaudio") {
            xine_cfg_entry_t deviceConfig;
            if (!lookupConfigEntry(xt->m_xine, "audio.pulseaudio_device", &deviceConfig,
                    "pulseaudio")) {
                continue;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_STRING);
            QByteArray deviceStr = handle.toUtf8();
            deviceStr.replace('\n', ':');
            deviceConfig.str_value = deviceStr.data();
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            port = xine_open_audio_driver(xt->m_xine, "pulseaudio", 0);
            if (port) {
                debug() << Q_FUNC_INFO << "use PulseAudio: " << handle;
                debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
                return port;
            }
        } else if (outputPlugin == "oss") {
            xine_cfg_entry_t deviceConfig;
            if (!lookupConfigEntry(xt->m_xine, "audio.device.oss_device_name", &deviceConfig,
                        "oss")) {
                continue;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_ENUM);
            deviceConfig.num_value = 0;
            xine_config_update_entry(xt->m_xine, &deviceConfig);
            if(!xine_config_lookup_entry(xt->m_xine, "audio.device.oss_device_number",
                        &deviceConfig)) {
                qWarning() << "cannot set the OSS device on Xine's OSS output plugin";
                return 0;
            }
            Q_ASSERT(deviceConfig.type == XINE_CONFIG_TYPE_NUM);
            const QByteArray &deviceStr = handle.toUtf8();
            char lastChar = deviceStr[deviceStr.length() - 1];
            int deviceNumber = -1;
            if (lastChar >= '0' || lastChar <= '9') {
                deviceNumber = lastChar - '0';
                char lastChar = deviceStr[deviceStr.length() - 2];
                if (lastChar >= '0' || lastChar <= '9') {
                    deviceNumber += 10 * (lastChar - '0');
                }
            }
            deviceConfig.num_value = deviceNumber;
            xine_config_update_entry(xt->m_xine, &deviceConfig);

            port = xine_open_audio_driver(xt->m_xine, "oss", 0);
            if (port) {
                debug() << Q_FUNC_INFO << "use OSS device: " << handle;
                debug() << Q_FUNC_INFO << "----------------------------------------------- audio_port created";
                return port;
            }
        }
    }
    return port;
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    return setOutputDevice(AudioOutputDevice::fromIndex(newDevice));
}

bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
    K_XT(AudioOutput);
    if (!xt->m_xine) {
        // remeber the choice until we have a xine_t
        m_device = newDevice;
        return true;
    }

    xine_audio_port_t *port = createPort(newDevice);
    if (!port) {
        debug() << Q_FUNC_INFO << "new audio port is invalid";
        return false;
    }

    KeepReference<> *keep = new KeepReference<>;
    keep->addObject(xt);
    keep->ready();

    AudioOutputXT *newXt = new AudioOutputXT;
    newXt->m_audioPort = port;
    newXt->m_xine = xt->m_xine;
    m_threadSafeObject = newXt;

    m_device = newDevice;
    SourceNode *src = source();
    if (src) {
        QList<WireCall> wireCall;
        QList<WireCall> unwireCall;
        wireCall << WireCall(src, this);
        unwireCall << WireCall(src, QExplicitlySharedDataPointer<SinkNodeXT>(xt));
        QCoreApplication::postEvent(XineThread::instance(), new RewireEvent(wireCall, unwireCall));
        graphChanged();
    }

    AudioDataOutputXT *dataOutput = dynamic_cast<AudioDataOutputXT*>(m_source->threadSafeObject().data());
    if (dataOutput)
        dataOutput->intercept(xt->m_audioPort);

    return true;
}

void AudioOutput::xineEngineChanged()
{
    K_XT(AudioOutput);
    if (xt->m_xine) {
        xine_audio_port_t *port = createPort(m_device);
        if (!port) {
            debug() << Q_FUNC_INFO << "stored audio port is invalid";
            QMetaObject::invokeMethod(this, "audioDeviceFailed", Qt::QueuedConnection);
            return;
        }

        // our XT object is in a wirecall, better not delete it

        Q_ASSERT(xt->m_audioPort == 0);
        xt->m_audioPort = port;

        AudioDataOutputXT *dataOutput = dynamic_cast<AudioDataOutputXT*>(m_source->threadSafeObject().data());
        if (dataOutput)
            dataOutput->intercept(xt->m_audioPort);
    }
}

void AudioOutput::aboutToChangeXineEngine()
{
    K_XT(AudioOutput);
    if (xt->m_audioPort) {
        AudioOutputXT *xt2 = new AudioOutputXT;
        xt2->m_xine = xt->m_xine;
        xt2->m_audioPort = xt->m_audioPort;
        xt->m_audioPort = 0;
        KeepReference<> *keep = new KeepReference<>;
        keep->addObject(xt2);
        keep->ready();
    }
}

void AudioOutput::downstreamEvent(Event *e)
{
    Q_ASSERT(e);
    QCoreApplication::sendEvent(this, e);
    SinkNode::downstreamEvent(e);
}

void AudioOutputXT::rewireTo(SourceNodeXT *source)
{
    if (!source->audioOutputPort()) {
        return;
    }
    source->assert();
    xine_post_wire_audio_port(source->audioOutputPort(), m_audioPort);
    source->assert();
    SinkNodeXT::assert();
}

bool AudioOutput::event(QEvent *ev)
{
    switch (ev->type()) {
    case Event::AudioDeviceFailed:
        {
            ev->accept();
            // we don't know for sure which AudioPort failed. We also can't know from the
            // information libxine makes available. So we have to just try the old device again
            if (setOutputDevice(m_device)) {
                return true;
            }
            // we really need a different output device
            QMetaObject::invokeMethod(this, "audioDeviceFailed", Qt::QueuedConnection);
        }
        return true;
    default:
        return AbstractAudioOutput::event(ev);
    }
}

void AudioOutput::graphChanged()
{
    debug() << Q_FUNC_INFO;
    // we got connected to a new XineStream, it needs to know our m_volume
    int xinevolume = static_cast<int>(m_volume * 100);
    if (xinevolume > 200) {
        xinevolume = 200;
    } else if (xinevolume < 0) {
        xinevolume = 0;
    }
    upstreamEvent(new UpdateVolumeEvent(xinevolume));
}

}} //namespace Phonon::Xine

#include "audiooutput.moc"
// vim: sw=4 ts=4
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <rtl/bootstrap.hxx>
#include <comphelper/processfactory.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/ucb/UniversalContentBroker.hpp>

#include <vcl/vclmain.hxx>

#include <tools/urlobj.hxx>
#include <tools/stream.hxx>
#include <vcl/svapp.hxx>
#include <vcl/pngread.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/virdev.hxx>
#include <vcl/graphicfilter.hxx>

#  define FIXME_ALPHA_WORKING
#  define FIXME_ROUNDED_RECT_WORKING
#  define FIXME_DRAW_TRANSPARENT_WORKING
#if 0
#endif

using namespace css;

class DemoBase :
        public WorkWindow // hide OutputDevice if necessary
{
public:
    DemoBase() : WorkWindow( NULL, WB_APP | WB_STDWORK)
    {
    }
    OutputDevice &getOutDev() { return *this; }
};

class DemoWin : public DemoBase
{
    Bitmap   maIntroBW;
    BitmapEx maIntro;

public:
    DemoWin() : DemoBase()
    {
        // Needed to find images
        OUString aPath;
        rtl::Bootstrap::get("SYSBINDIR", aPath);
#ifdef FIXME_THIS_FAILS
        rtl::Bootstrap::set("BRAND_BASE_DIR", aPath + "/..");
        if (Application::LoadBrandBitmap("intro", maIntro))
            Application::Abort("Failed to load intro image");
#else
        aPath = aPath + "/intro.png";
        SvFileStream aFileStream( aPath, STREAM_READ );
        GraphicFilter aGraphicFilter(false);
        Graphic aGraphic;
        if (aGraphicFilter.ImportGraphic(aGraphic, aPath, aFileStream) != 0)
            Application::Abort("Failed to load intro image: " + aPath);
        maIntro = aGraphic.GetBitmapEx();
#endif
        maIntroBW = maIntro.GetBitmap();
        maIntroBW.Filter( BMP_FILTER_EMBOSS_GREY );
    }

    void drawToDevice(OutputDevice &r, bool bVdev);

    virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE
    {
        fprintf(stderr, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight());
        drawToDevice(getOutDev(), false);
    }

    std::vector<Rectangle> partitionAndClear(OutputDevice &rDev,
                                             int nX, int nY);

    void drawBackground(OutputDevice &rDev)
    {
        Rectangle r(Point(0,0), rDev.GetOutputSizePixel());
        Gradient aGradient;
        aGradient.SetStartColor(COL_BLUE);
        aGradient.SetEndColor(COL_GREEN);
        aGradient.SetStyle(GradientStyle_LINEAR);
//        aGradient.SetBorder(r.GetSize().Width()/20);
        rDev.DrawGradient(r, aGradient);
    }

    void drawRadialLines(OutputDevice &rDev, Rectangle r)
    {
        rDev.SetFillColor(Color(COL_LIGHTRED));
        rDev.SetLineColor(Color(COL_BLACK));
        rDev.DrawRect( r );

        // FIXME: notice these appear reflected at the bottom not the top.
        for(int i=0; i<r.GetHeight(); i+=15)
            rDev.DrawLine( Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i) );
        for(int i=0; i<r.GetWidth(); i+=15)
            rDev.DrawLine( Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()) );

        // Should draw a white-line across the middle
        Color aLastPixel( COL_WHITE );
        Point aCenter((r.Left() + r.Right())/2 - 4,
                      (r.Top() + r.Bottom())/2 - 4);
        for(int i=0; i<8; i++)
        {
            rDev.DrawPixel(aCenter, aLastPixel);
            aLastPixel = rDev.GetPixel(aCenter);
            aCenter.Move(1,1);
        }
    }

    void drawText(OutputDevice &rDev, Rectangle r)

    {
        rDev.SetTextColor( Color( COL_BLACK ) );
        vcl::Font aFont( OUString( "Times" ), Size( 0, 25 ) );
        rDev.SetFont( aFont );
        rDev.DrawText( r, OUString( "Just a simple text" ) );
    }

    void drawPoly(OutputDevice &rDev, Rectangle r)
 // pretty
    {
        drawCheckered(rDev, r);

        long nDx = r.GetWidth()/20;
        long nDy = r.GetHeight()/20;
        Rectangle aShrunk(r);
        aShrunk.Move(nDx, nDy);
        aShrunk.SetSize(Size(r.GetWidth()-nDx*2,
                             r.GetHeight()-nDy*2));
        Polygon aPoly(aShrunk);
        tools::PolyPolygon aPPoly(aPoly);
        rDev.SetLineColor(Color(COL_RED));
        rDev.SetFillColor(Color(COL_RED));
        // This hits the optional 'drawPolyPolygon' code-path
        rDev.DrawTransparent(aPPoly, 64);
    }
    void drawEllipse(OutputDevice &rDev, Rectangle r)

    {
        rDev.SetLineColor(Color(COL_RED));
        rDev.SetFillColor(Color(COL_GREEN));
        rDev.DrawEllipse(r);
    }
    void drawCheckered(OutputDevice &rDev, Rectangle r)

    {
        rDev.DrawCheckered(r.TopLeft(), r.GetSize());
    }
    void drawGradient(OutputDevice &rDev, Rectangle r)

    {
        Gradient aGradient;
        aGradient.SetStartColor(COL_YELLOW);
        aGradient.SetEndColor(COL_RED);
//        aGradient.SetAngle(45);
        aGradient.SetStyle(GradientStyle_RECT);
        aGradient.SetBorder(r.GetSize().Width()/20);
        rDev.DrawGradient(r, aGradient);
    }
    void drawBitmap(OutputDevice &rDev, Rectangle r)

    {
        Bitmap aBitmap(maIntroBW);
        aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY);
        rDev.DrawBitmap(r.TopLeft(), aBitmap);
    }
    void drawBitmapEx(OutputDevice &rDev, Rectangle r)

    {
        drawCheckered(rDev, r);

        BitmapEx aBitmap(maIntro);
        aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY);
#ifdef FIXME_ALPHA_WORKING
        AlphaMask aSemiTransp(aBitmap.GetSizePixel());
        aSemiTransp.Erase(64);
        rDev.DrawBitmapEx(r.TopLeft(), BitmapEx(aBitmap.GetBitmap(),
                                           aSemiTransp));
#else
        rDev.DrawBitmapEx(r.TopLeft(), aBitmap);
#endif
    }
    void drawPolyPolgons(OutputDevice &rDev, Rectangle r)

    {
        struct {
            double nX, nY;
        } aPoints[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
                        { 0.9, 0.1 }, { 0.1, 0.9 },
                        { 0.1, 0.1 } };

        tools::PolyPolygon aPolyPoly;
        // Render 4x polygons & aggregate into another PolyPolygon
        for (int x = 0; x < 2; x++)
        {
            for (int y = 0; y < 2; y++)
            {
                Rectangle aSubRect(r);
                aSubRect.Move(x * r.GetWidth()/3, y * r.GetHeight()/3);
                aSubRect.SetSize(Size(r.GetWidth()/2, r.GetHeight()/4));
                Polygon aPoly(SAL_N_ELEMENTS(aPoints));
                for (size_t v = 0; v < SAL_N_ELEMENTS(aPoints); v++)
                {
                    aPoly.SetPoint(Point(aSubRect.Left() +
                                         aSubRect.GetWidth() * aPoints[v].nX,
                                         aSubRect.Top() +
                                         aSubRect.GetHeight() * aPoints[v].nY),
                                   v);
                }
                rDev.SetLineColor(Color(COL_YELLOW));
                rDev.SetFillColor(Color(COL_BLACK));
                rDev.DrawPolygon(aPoly);

                // now move and add to the polypolygon
                aPoly.Move(0, r.GetHeight()/2);
                aPolyPoly.Insert(aPoly);
            }
        }
        rDev.SetLineColor(Color(COL_LIGHTRED));
        rDev.SetFillColor(Color(COL_GREEN));
#ifdef FIXME_DRAW_TRANSPARENT_WORKING
        rDev.DrawTransparent(aPolyPoly, 50);
#else
        rDev.DrawPolyPolygon(aPolyPoly);
#endif
    }
    void drawToVirtualDevice(OutputDevice &rDev, Rectangle r)
    {
        VirtualDevice aNested;
        aNested.SetOutputSize(r.GetSize());
        Rectangle aWhole(Point(0,0), r.GetSize());
        // mini me
        drawToDevice(aNested, true);

        Bitmap aBitmap(aNested.GetBitmap(Point(0,0),aWhole.GetSize()));
        rDev.DrawBitmap(r.TopLeft(), aBitmap);
    }

    void fetchDrawBitmap(OutputDevice &rDev, Rectangle r)
    {
        // FIXME: should work ...
        Bitmap aBitmap(GetBitmap(Point(0,0),rDev.GetOutputSizePixel()));
        aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY);
        rDev.DrawBitmap(r.TopLeft(), aBitmap);
    }
};

std::vector<Rectangle> DemoWin::partitionAndClear(OutputDevice &rDev, int nX, int nY)
{
    Rectangle r;
    std::vector<Rectangle> aRegions;

    // Make small cleared area for these guys
    Size aSize(rDev.GetOutputSizePixel());
    long nBorderSize = aSize.Width() / 32;
    long nBoxWidth = (aSize.Width() - nBorderSize*(nX+1)) / nX;
    long nBoxHeight = (aSize.Height() - nBorderSize*(nY+1)) / nY;
    for (int y = 0; y < nY; y++ )
    {
        for (int x = 0; x < nX; x++ )
        {
            r.SetPos(Point(nBorderSize + (nBorderSize + nBoxWidth) * x,
                           nBorderSize + (nBorderSize + nBoxHeight) * y));
            r.SetSize(Size(nBoxWidth, nBoxHeight));

            // knock up a nice little border
            rDev.SetLineColor(COL_GRAY);
            rDev.SetFillColor(COL_LIGHTGRAY);
            if ((x + y) % 2)
                rDev.DrawRect(r);
            else
            {
#ifdef FIXME_ROUNDED_RECT_WORKING
                rDev.DrawRect(r, nBorderSize, nBorderSize);
#else
                rDev.DrawRect(r);
#endif
            }

            aRegions.push_back(r);
        }
    }

    return aRegions;
}

void DemoWin::drawToDevice(OutputDevice &rDev, bool bVdev)
{
    drawBackground(rDev);

    std::vector<Rectangle> aRegions(partitionAndClear(rDev, 4, 3));

    drawRadialLines(rDev, aRegions[0]);
    drawText(rDev, aRegions[1]);
    drawPoly(rDev, aRegions[2]);
    drawEllipse(rDev, aRegions[3]);
    drawCheckered(rDev, aRegions[4]);
    drawBitmapEx(rDev, aRegions[5]);
    drawBitmap(rDev, aRegions[6]);
    drawGradient(rDev, aRegions[7]);
    drawPolyPolgons(rDev, aRegions[8]);
    if (!bVdev)
        drawToVirtualDevice(rDev, aRegions[9]);
    // last - thumbnail all the above
    fetchDrawBitmap(rDev, aRegions[10]);
}

class DemoApp : public Application
{
public:
    DemoApp() {}

    virtual int Main() SAL_OVERRIDE
    {
        DemoWin aMainWin;
        aMainWin.SetText( "Interactive VCL demo" );
        aMainWin.Show();
        Application::Execute();
        return 0;
    }

protected:
    uno::Reference<lang::XMultiServiceFactory> xMSF;
    void Init() SAL_OVERRIDE
    {
        try
        {
            uno::Reference<uno::XComponentContext> xComponentContext
                = ::cppu::defaultBootstrap_InitialComponentContext();
            xMSF = uno::Reference<lang::XMultiServiceFactory>
                ( xComponentContext->getServiceManager(), uno::UNO_QUERY );
            if( !xMSF.is() )
                Application::Abort("Bootstrap failure - no service manager");

            ::comphelper::setProcessServiceFactory( xMSF );
        }
        catch (const uno::Exception &e)
        {
            Application::Abort("Bootstrap exception " + e.Message);
        }
    }
    void DeInit() SAL_OVERRIDE
    {
        uno::Reference< lang::XComponent >(
            comphelper::getProcessComponentContext(),
        uno::UNO_QUERY_THROW )-> dispose();
        ::comphelper::setProcessServiceFactory( NULL );
    }
};

void vclmain::createApplication()
{
    static DemoApp aApp;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>vcldemo: load and render some icons<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <rtl/bootstrap.hxx>
#include <comphelper/processfactory.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/ucb/UniversalContentBroker.hpp>

#include <vcl/vclmain.hxx>

#include <tools/urlobj.hxx>
#include <tools/stream.hxx>
#include <vcl/svapp.hxx>
#include <vcl/pngread.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/virdev.hxx>
#include <vcl/graphicfilter.hxx>

#if 0
#  define FIXME_SELF_INTERSECTING_WORKING
#  define FIXME_DRAW_BITMAPEX
#endif

using namespace css;

class DemoBase :
        public WorkWindow // hide OutputDevice if necessary
{
public:
    DemoBase() : WorkWindow( NULL, WB_APP | WB_STDWORK)
    {
    }
    OutputDevice &getOutDev() { return *this; }
};

class DemoWin : public DemoBase
{
    Bitmap   maIntroBW;
    BitmapEx maIntro;

public:
    DemoWin() : DemoBase()
    {
        // Needed to find images
        OUString aPath;
        rtl::Bootstrap::get("SYSBINDIR", aPath);
#ifdef FIXME_THIS_FAILS
        rtl::Bootstrap::set("BRAND_BASE_DIR", aPath + "/..");
        if (Application::LoadBrandBitmap("intro", maIntro))
            Application::Abort("Failed to load intro image");
#else
        aPath = aPath + "/intro.png";
        SvFileStream aFileStream( aPath, STREAM_READ );
        GraphicFilter aGraphicFilter(false);
        Graphic aGraphic;
        if (aGraphicFilter.ImportGraphic(aGraphic, aPath, aFileStream) != 0)
            Application::Abort("Failed to load intro image: " + aPath);
        maIntro = aGraphic.GetBitmapEx();
#endif
        maIntroBW = maIntro.GetBitmap();
        maIntroBW.Filter( BMP_FILTER_EMBOSS_GREY );
    }

    void drawToDevice(OutputDevice &r, bool bVdev);

    virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE
    {
        fprintf(stderr, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight());
        drawToDevice(getOutDev(), false);
    }

    std::vector<Rectangle> partitionAndClear(OutputDevice &rDev,
                                             int nX, int nY);

    void drawBackground(OutputDevice &rDev)
    {
        Rectangle r(Point(0,0), rDev.GetOutputSizePixel());
        Gradient aGradient;
        aGradient.SetStartColor(COL_BLUE);
        aGradient.SetEndColor(COL_GREEN);
        aGradient.SetStyle(GradientStyle_LINEAR);
//        aGradient.SetBorder(r.GetSize().Width()/20);
        rDev.DrawGradient(r, aGradient);
    }

    void drawRadialLines(OutputDevice &rDev, Rectangle r)
    {
        rDev.SetFillColor(Color(COL_LIGHTRED));
        rDev.SetLineColor(Color(COL_BLACK));
        rDev.DrawRect( r );

        for(int i=0; i<r.GetHeight(); i+=15)
            rDev.DrawLine( Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i) );
        for(int i=0; i<r.GetWidth(); i+=15)
            rDev.DrawLine( Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()) );

        // Should draw a white-line across the middle
        Color aLastPixel( COL_WHITE );
        Point aCenter((r.Left() + r.Right())/2 - 4,
                      (r.Top() + r.Bottom())/2 - 4);
        for(int i=0; i<8; i++)
        {
            rDev.DrawPixel(aCenter, aLastPixel);
            aLastPixel = rDev.GetPixel(aCenter);
            aCenter.Move(1,1);
        }
    }

    void drawText(OutputDevice &rDev, Rectangle r)

    {
        rDev.SetTextColor( Color( COL_BLACK ) );
        vcl::Font aFont( OUString( "Times" ), Size( 0, 25 ) );
        rDev.SetFont( aFont );
        rDev.DrawText( r, OUString( "Just a simple text" ) );
    }

    void drawPoly(OutputDevice &rDev, Rectangle r) // pretty
    {
        drawCheckered(rDev, r);

        long nDx = r.GetWidth()/20;
        long nDy = r.GetHeight()/20;
        Rectangle aShrunk(r);
        aShrunk.Move(nDx, nDy);
        aShrunk.SetSize(Size(r.GetWidth()-nDx*2,
                             r.GetHeight()-nDy*2));
        Polygon aPoly(aShrunk);
        tools::PolyPolygon aPPoly(aPoly);
        rDev.SetLineColor(Color(COL_RED));
        rDev.SetFillColor(Color(COL_RED));
        // This hits the optional 'drawPolyPolygon' code-path
        rDev.DrawTransparent(aPPoly, 64);
    }
    void drawEllipse(OutputDevice &rDev, Rectangle r)

    {
        rDev.SetLineColor(Color(COL_RED));
        rDev.SetFillColor(Color(COL_GREEN));
        rDev.DrawEllipse(r);
    }
    void drawCheckered(OutputDevice &rDev, Rectangle r)

    {
        rDev.DrawCheckered(r.TopLeft(), r.GetSize());
    }
    void drawGradient(OutputDevice &rDev, Rectangle r)

    {
        Gradient aGradient;
        aGradient.SetStartColor(COL_YELLOW);
        aGradient.SetEndColor(COL_RED);
//        aGradient.SetAngle(45);
        aGradient.SetStyle(GradientStyle_RECT);
        aGradient.SetBorder(r.GetSize().Width()/20);
        rDev.DrawGradient(r, aGradient);
    }
    void drawBitmap(OutputDevice &rDev, Rectangle r)

    {
        Bitmap aBitmap(maIntroBW);
        aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY);
        rDev.DrawBitmap(r.TopLeft(), aBitmap);
    }
    void drawBitmapEx(OutputDevice &rDev, Rectangle r)

    {
        drawCheckered(rDev, r);

        BitmapEx aBitmap(maIntro);
        aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY);
        AlphaMask aSemiTransp(aBitmap.GetSizePixel());
        aSemiTransp.Erase(64);
        rDev.DrawBitmapEx(r.TopLeft(), BitmapEx(aBitmap.GetBitmap(),
                                                aSemiTransp));
    }
    void drawPolyPolgons(OutputDevice &rDev, Rectangle r)

    {
        struct {
            double nX, nY;
        } aPoints[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
#ifdef FIXME_SELF_INTERSECTING_WORKING
                        { 0.9, 0.1 }, { 0.1, 0.9 },
                        { 0.1, 0.1 } };
#else
                        { 0.1, 0.9 }, { 0.5, 0.5 },
                        { 0.9, 0.1 }, { 0.1, 0.1 } };
#endif

        tools::PolyPolygon aPolyPoly;
        // Render 4x polygons & aggregate into another PolyPolygon
        for (int x = 0; x < 2; x++)
        {
            for (int y = 0; y < 2; y++)
            {
                Rectangle aSubRect(r);
                aSubRect.Move(x * r.GetWidth()/3, y * r.GetHeight()/3);
                aSubRect.SetSize(Size(r.GetWidth()/2, r.GetHeight()/4));
                Polygon aPoly(SAL_N_ELEMENTS(aPoints));
                for (size_t v = 0; v < SAL_N_ELEMENTS(aPoints); v++)
                {
                    aPoly.SetPoint(Point(aSubRect.Left() +
                                         aSubRect.GetWidth() * aPoints[v].nX,
                                         aSubRect.Top() +
                                         aSubRect.GetHeight() * aPoints[v].nY),
                                   v);
                }
                rDev.SetLineColor(Color(COL_YELLOW));
                rDev.SetFillColor(Color(COL_BLACK));
                rDev.DrawPolygon(aPoly);

                // now move and add to the polypolygon
                aPoly.Move(0, r.GetHeight()/2);
                aPolyPoly.Insert(aPoly);
            }
        }
        rDev.SetLineColor(Color(COL_LIGHTRED));
        rDev.SetFillColor(Color(COL_GREEN));
        rDev.DrawTransparent(aPolyPoly, 50);
    }
    void drawToVirtualDevice(OutputDevice &rDev, Rectangle r)
    {
        VirtualDevice aNested(rDev);
        aNested.SetOutputSizePixel(r.GetSize());
        Rectangle aWhole(Point(0,0), r.GetSize());
        // mini me
        drawToDevice(aNested, true);

        Bitmap aBitmap(aNested.GetBitmap(Point(0,0),aWhole.GetSize()));
        rDev.DrawBitmap(r.TopLeft(), aBitmap);
    }

    std::vector<BitmapEx> maIcons;
    void initIcons()
    {
        if (maIcons.size())
            return;

        const char *pNames[] = {
            "cmd/lc_openurl.png",
            "cmd/lc_newdoc.png",
            "cmd/lc_save.png",
            "cmd/lc_saveas.png",
            "cmd/lc_sendmail.png",
            "cmd/lc_editdoc.png",
            "cmd/lc_print.png",
            "cmd/lc_printpreview.png",
            "cmd/lc_cut.png",
            "cmd/lc_copy.png",
            "cmd/lc_paste.png",
            "cmd/lc_formatpaintbrush.png",
            "cmd/lc_undo.png",
            "cmd/lc_redo.png",
        };
        for (size_t i = 0; i < SAL_N_ELEMENTS(pNames); i++)
            maIcons.push_back(BitmapEx(OUString::createFromAscii(pNames[i])));
    }
    void drawIcons(OutputDevice &rDev, Rectangle r)
    {
        initIcons();

        Rectangle p(r);
        for (size_t i = 0; i < maIcons.size(); i++)
        {
            Size aSize(maIcons[i].GetSizePixel());
#ifdef FIXME_DRAW_BITMAPEX
            rDev.DrawBitmapEx(p.TopLeft(), maIcons[i]);
#else
            rDev.DrawBitmap(p.TopLeft(), maIcons[i].GetBitmap());
#endif
            p.Move(aSize.Width(), 0);
            if (p.Left() >= r.Right())
                break;
        }
    }

    void fetchDrawBitmap(OutputDevice &rDev, Rectangle r)
    {
        Bitmap aBitmap(GetBitmap(Point(0,0),rDev.GetOutputSizePixel()));
        aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY);
        rDev.DrawBitmap(r.TopLeft(), aBitmap);
    }
};

std::vector<Rectangle> DemoWin::partitionAndClear(OutputDevice &rDev, int nX, int nY)
{
    Rectangle r;
    std::vector<Rectangle> aRegions;

    // Make small cleared area for these guys
    Size aSize(rDev.GetOutputSizePixel());
    long nBorderSize = aSize.Width() / 32;
    long nBoxWidth = (aSize.Width() - nBorderSize*(nX+1)) / nX;
    long nBoxHeight = (aSize.Height() - nBorderSize*(nY+1)) / nY;
    for (int y = 0; y < nY; y++ )
    {
        for (int x = 0; x < nX; x++ )
        {
            r.SetPos(Point(nBorderSize + (nBorderSize + nBoxWidth) * x,
                           nBorderSize + (nBorderSize + nBoxHeight) * y));
            r.SetSize(Size(nBoxWidth, nBoxHeight));

            // knock up a nice little border
            rDev.SetLineColor(COL_GRAY);
            rDev.SetFillColor(COL_LIGHTGRAY);
            if ((x + y) % 2)
                rDev.DrawRect(r, nBorderSize, nBorderSize);
            else
                rDev.DrawRect(r);

            aRegions.push_back(r);
        }
    }

    return aRegions;
}

void DemoWin::drawToDevice(OutputDevice &rDev, bool bVdev)
{
    drawBackground(rDev);

    std::vector<Rectangle> aRegions(partitionAndClear(rDev, 4, 3));

    drawRadialLines(rDev, aRegions[0]);
    drawText(rDev, aRegions[1]);
    drawPoly(rDev, aRegions[2]);
    drawEllipse(rDev, aRegions[3]);
    drawCheckered(rDev, aRegions[4]);
    drawBitmapEx(rDev, aRegions[5]);
    drawBitmap(rDev, aRegions[6]);
    drawGradient(rDev, aRegions[7]);
    drawPolyPolgons(rDev, aRegions[8]);
    if (!bVdev)
        drawToVirtualDevice(rDev, aRegions[9]);
    drawIcons(rDev, aRegions[10]);
    // last - thumbnail all the above
    fetchDrawBitmap(rDev, aRegions[11]);
}

class DemoApp : public Application
{
public:
    DemoApp() {}

    virtual int Main() SAL_OVERRIDE
    {
        DemoWin aMainWin;
        aMainWin.SetText( "Interactive VCL demo" );
        aMainWin.Show();
        Application::Execute();
        return 0;
    }

protected:
    uno::Reference<lang::XMultiServiceFactory> xMSF;
    void Init() SAL_OVERRIDE
    {
        try
        {
            uno::Reference<uno::XComponentContext> xComponentContext
                = ::cppu::defaultBootstrap_InitialComponentContext();
            xMSF = uno::Reference<lang::XMultiServiceFactory>
                ( xComponentContext->getServiceManager(), uno::UNO_QUERY );
            if( !xMSF.is() )
                Application::Abort("Bootstrap failure - no service manager");

            ::comphelper::setProcessServiceFactory( xMSF );
        }
        catch (const uno::Exception &e)
        {
            Application::Abort("Bootstrap exception " + e.Message);
        }
    }
    void DeInit() SAL_OVERRIDE
    {
        uno::Reference< lang::XComponent >(
            comphelper::getProcessComponentContext(),
        uno::UNO_QUERY_THROW )-> dispose();
        ::comphelper::setProcessServiceFactory( NULL );
    }
};

void vclmain::createApplication()
{
    static DemoApp aApp;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>