<commit_before>#include "ContentWindowManager.h"
#include "Content.h"
#include "DisplayGroupManager.h"
#include "main.h"

ContentWindowManager::ContentWindowManager(boost::shared_ptr<Content> content)
{
    // content dimensions
    content->getDimensions(contentWidth_, contentHeight_);

    // default position / size
    x_ = y_ = 0.;
    w_ = h_ = 0.25;

    // default to centered
    centerX_ = 0.5;
    centerY_ = 0.5;

    // default to no zoom
    zoom_ = 1.;

    // default window state
    selected_ = false;

    // set content object
    content_ = content;

    // receive updates to content dimensions
    connect(content.get(), SIGNAL(dimensionsChanged(int, int)), this, SLOT(setContentDimensions(int, int)));
}

boost::shared_ptr<Content> ContentWindowManager::getContent()
{
    return content_;
}

boost::shared_ptr<DisplayGroupManager> ContentWindowManager::getDisplayGroupManager()
{
    return displayGroupManager_.lock();
}

void ContentWindowManager::setDisplayGroupManager(boost::shared_ptr<DisplayGroupManager> displayGroupManager)
{
    // disconnect any existing signals to previous DisplayGroupManager
    boost::shared_ptr<DisplayGroupManager> oldDisplayGroupManager = getDisplayGroupManager();

    if(oldDisplayGroupManager != NULL)
    {
        disconnect(this, 0, oldDisplayGroupManager.get(), 0);
    }

    displayGroupManager_ = displayGroupManager;

    // make connections to new DisplayGroupManager
    // don't use queued connections; we want these to execute immediately and we're in the same thread
    if(displayGroupManager != NULL)
    {
        connect(this, SIGNAL(contentDimensionsChanged(int, int, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(coordinatesChanged(double, double, double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(positionChanged(double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(sizeChanged(double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(centerChanged(double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(zoomChanged(double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(selectedChanged(bool, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));

        // we don't call sendDisplayGroup() on movedToFront() or destroyed() since it happens already
    }
}

void ContentWindowManager::moveToFront(ContentWindowInterface * source)
{
    ContentWindowInterface::moveToFront(source);

    if(source != this)
    {
        getDisplayGroupManager()->moveContentWindowManagerToFront(shared_from_this());
    }
}

void ContentWindowManager::close(ContentWindowInterface * source)
{
    ContentWindowInterface::close(source);

    if(source != this)
    {
        getDisplayGroupManager()->removeContentWindowManager(shared_from_this());
    }
}

void ContentWindowManager::render()
{
    content_->render(shared_from_this());

    // optionally render the border
    bool showWindowBorders = true;

    boost::shared_ptr<DisplayGroupManager> dgm = getDisplayGroupManager();

    if(dgm != NULL)
    {
        showWindowBorders = dgm->getOptions()->getShowWindowBorders();
    }

    if(showWindowBorders == true)
    {
        double horizontalBorder = 5. / (double)g_configuration->getTotalHeight(); // 5 pixels
        double verticalBorder = (double)g_configuration->getTotalHeight() / (double)g_configuration->getTotalWidth() * horizontalBorder;

        glPushAttrib(GL_CURRENT_BIT);

        // color the border based on window state
        if(selected_ == true)
        {
            glColor4f(1,0,0,1);
        }
        else
        {
            glColor4f(1,1,1,1);
        }

        GLWindow::drawRectangle(x_-verticalBorder,y_-horizontalBorder,w_+2.*verticalBorder,h_+2.*horizontalBorder);

        glPopAttrib();
    }

    glPushAttrib(GL_CURRENT_BIT);

    // render buttons if any of the markers are over the window
    bool markerOverWindow = false;

    std::vector<boost::shared_ptr<Marker> > markers = getDisplayGroupManager()->getMarkers();

    for(unsigned int i=0; i<markers.size(); i++)
    {
        float markerX, markerY;
        markers[i]->getPosition(markerX, markerY);

        if(QRectF(x_, y_, w_, h_).contains(markerX, markerY) == true)
        {
            markerOverWindow = true;
            break;
        }
    }

    if(markerOverWindow == true)
    {
        // we need this to be slightly in front of the rest of the window
        glPushMatrix();
        glTranslatef(0,0,0.001);

        // button dimensions
        float buttonWidth, buttonHeight;
        getButtonDimensions(buttonWidth, buttonHeight);

        // draw close button
        QRectF closeRect(x_ + w_ - buttonWidth, y_, buttonWidth, buttonHeight);

        // semi-transparent background
        glColor4f(1,0,0,0.125);

        glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_BLEND);
        glDepthMask(GL_FALSE);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glBegin(GL_QUADS);
        glVertex2f(closeRect.x(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y()+closeRect.height());
        glVertex2f(closeRect.x(), closeRect.y()+closeRect.height());
        glEnd();

        glPopAttrib();

        glColor4f(1,0,0,1);

        glBegin(GL_LINE_LOOP);
        glVertex2f(closeRect.x(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y()+closeRect.height());
        glVertex2f(closeRect.x(), closeRect.y()+closeRect.height());
        glEnd();

        glBegin(GL_LINES);
        glVertex2f(closeRect.x(), closeRect.y());
        glVertex2f(closeRect.x() + closeRect.width(), closeRect.y() + closeRect.height());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y());
        glVertex2f(closeRect.x(), closeRect.y() + closeRect.height());
        glEnd();

        // resize indicator
        QRectF resizeRect(x_ + w_ - buttonWidth, y_ + h_ - buttonHeight, buttonWidth, buttonHeight);

        // semi-transparent background
        glColor4f(0.5,0.5,0.5,0.25);

        glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_BLEND);
        glDepthMask(GL_FALSE);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glBegin(GL_QUADS);
        glVertex2f(resizeRect.x(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y()+resizeRect.height());
        glVertex2f(resizeRect.x(), resizeRect.y()+resizeRect.height());
        glEnd();

        glPopAttrib();

        glColor4f(0.5,0.5,0.5,1);

        glBegin(GL_LINE_LOOP);
        glVertex2f(resizeRect.x(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y()+resizeRect.height());
        glVertex2f(resizeRect.x(), resizeRect.y()+resizeRect.height());
        glEnd();

        glBegin(GL_LINES);
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y());
        glVertex2f(resizeRect.x(), resizeRect.y() + resizeRect.height());
        glEnd();

        glPopMatrix();
    }

    glPopAttrib();
}
<commit_msg>changed default size for newly created windows.<commit_after>#include "ContentWindowManager.h"
#include "Content.h"
#include "DisplayGroupManager.h"
#include "main.h"

ContentWindowManager::ContentWindowManager(boost::shared_ptr<Content> content)
{
    // content dimensions
    content->getDimensions(contentWidth_, contentHeight_);

    // default position / size, assumes a 16/9 aspect ratio
    // the actual aspect ratio will be set after the content is loaded
    x_ = y_ = 0.;
    w_ = 0.1;
    h_ = (double)g_configuration->getTotalWidth() / (double)g_configuration->getTotalHeight() * 9/16. * w_;

    // default to centered
    centerX_ = 0.5;
    centerY_ = 0.5;

    // default to no zoom
    zoom_ = 1.;

    // default window state
    selected_ = false;

    // set content object
    content_ = content;

    // receive updates to content dimensions
    connect(content.get(), SIGNAL(dimensionsChanged(int, int)), this, SLOT(setContentDimensions(int, int)));
}

boost::shared_ptr<Content> ContentWindowManager::getContent()
{
    return content_;
}

boost::shared_ptr<DisplayGroupManager> ContentWindowManager::getDisplayGroupManager()
{
    return displayGroupManager_.lock();
}

void ContentWindowManager::setDisplayGroupManager(boost::shared_ptr<DisplayGroupManager> displayGroupManager)
{
    // disconnect any existing signals to previous DisplayGroupManager
    boost::shared_ptr<DisplayGroupManager> oldDisplayGroupManager = getDisplayGroupManager();

    if(oldDisplayGroupManager != NULL)
    {
        disconnect(this, 0, oldDisplayGroupManager.get(), 0);
    }

    displayGroupManager_ = displayGroupManager;

    // make connections to new DisplayGroupManager
    // don't use queued connections; we want these to execute immediately and we're in the same thread
    if(displayGroupManager != NULL)
    {
        connect(this, SIGNAL(contentDimensionsChanged(int, int, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(coordinatesChanged(double, double, double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(positionChanged(double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(sizeChanged(double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(centerChanged(double, double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(zoomChanged(double, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));
        connect(this, SIGNAL(selectedChanged(bool, ContentWindowInterface *)), displayGroupManager.get(), SLOT(sendDisplayGroup()));

        // we don't call sendDisplayGroup() on movedToFront() or destroyed() since it happens already
    }
}

void ContentWindowManager::moveToFront(ContentWindowInterface * source)
{
    ContentWindowInterface::moveToFront(source);

    if(source != this)
    {
        getDisplayGroupManager()->moveContentWindowManagerToFront(shared_from_this());
    }
}

void ContentWindowManager::close(ContentWindowInterface * source)
{
    ContentWindowInterface::close(source);

    if(source != this)
    {
        getDisplayGroupManager()->removeContentWindowManager(shared_from_this());
    }
}

void ContentWindowManager::render()
{
    content_->render(shared_from_this());

    // optionally render the border
    bool showWindowBorders = true;

    boost::shared_ptr<DisplayGroupManager> dgm = getDisplayGroupManager();

    if(dgm != NULL)
    {
        showWindowBorders = dgm->getOptions()->getShowWindowBorders();
    }

    if(showWindowBorders == true)
    {
        double horizontalBorder = 5. / (double)g_configuration->getTotalHeight(); // 5 pixels
        double verticalBorder = (double)g_configuration->getTotalHeight() / (double)g_configuration->getTotalWidth() * horizontalBorder;

        glPushAttrib(GL_CURRENT_BIT);

        // color the border based on window state
        if(selected_ == true)
        {
            glColor4f(1,0,0,1);
        }
        else
        {
            glColor4f(1,1,1,1);
        }

        GLWindow::drawRectangle(x_-verticalBorder,y_-horizontalBorder,w_+2.*verticalBorder,h_+2.*horizontalBorder);

        glPopAttrib();
    }

    glPushAttrib(GL_CURRENT_BIT);

    // render buttons if any of the markers are over the window
    bool markerOverWindow = false;

    std::vector<boost::shared_ptr<Marker> > markers = getDisplayGroupManager()->getMarkers();

    for(unsigned int i=0; i<markers.size(); i++)
    {
        float markerX, markerY;
        markers[i]->getPosition(markerX, markerY);

        if(QRectF(x_, y_, w_, h_).contains(markerX, markerY) == true)
        {
            markerOverWindow = true;
            break;
        }
    }

    if(markerOverWindow == true)
    {
        // we need this to be slightly in front of the rest of the window
        glPushMatrix();
        glTranslatef(0,0,0.001);

        // button dimensions
        float buttonWidth, buttonHeight;
        getButtonDimensions(buttonWidth, buttonHeight);

        // draw close button
        QRectF closeRect(x_ + w_ - buttonWidth, y_, buttonWidth, buttonHeight);

        // semi-transparent background
        glColor4f(1,0,0,0.125);

        glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_BLEND);
        glDepthMask(GL_FALSE);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glBegin(GL_QUADS);
        glVertex2f(closeRect.x(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y()+closeRect.height());
        glVertex2f(closeRect.x(), closeRect.y()+closeRect.height());
        glEnd();

        glPopAttrib();

        glColor4f(1,0,0,1);

        glBegin(GL_LINE_LOOP);
        glVertex2f(closeRect.x(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y()+closeRect.height());
        glVertex2f(closeRect.x(), closeRect.y()+closeRect.height());
        glEnd();

        glBegin(GL_LINES);
        glVertex2f(closeRect.x(), closeRect.y());
        glVertex2f(closeRect.x() + closeRect.width(), closeRect.y() + closeRect.height());
        glVertex2f(closeRect.x()+closeRect.width(), closeRect.y());
        glVertex2f(closeRect.x(), closeRect.y() + closeRect.height());
        glEnd();

        // resize indicator
        QRectF resizeRect(x_ + w_ - buttonWidth, y_ + h_ - buttonHeight, buttonWidth, buttonHeight);

        // semi-transparent background
        glColor4f(0.5,0.5,0.5,0.25);

        glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_BLEND);
        glDepthMask(GL_FALSE);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glBegin(GL_QUADS);
        glVertex2f(resizeRect.x(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y()+resizeRect.height());
        glVertex2f(resizeRect.x(), resizeRect.y()+resizeRect.height());
        glEnd();

        glPopAttrib();

        glColor4f(0.5,0.5,0.5,1);

        glBegin(GL_LINE_LOOP);
        glVertex2f(resizeRect.x(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y());
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y()+resizeRect.height());
        glVertex2f(resizeRect.x(), resizeRect.y()+resizeRect.height());
        glEnd();

        glBegin(GL_LINES);
        glVertex2f(resizeRect.x()+resizeRect.width(), resizeRect.y());
        glVertex2f(resizeRect.x(), resizeRect.y() + resizeRect.height());
        glEnd();

        glPopMatrix();
    }

    glPopAttrib();
}
<|endoftext|>


<commit_before>/*
This is the library to control the LCD Nanoshield

Copyright (c) 2013 Circuitar
This software is released under the MIT license. See the attached LICENSE file for details.
*/

#include "Nanoshield_LCD.h"

#define LCD_I2C_ADDRESS 0x27

// Bit masks
#define DISPLAY_ON     0x04
#define DISPLAY_OFF    0x00
#define CURSOR_ON      0x02
#define CURSOR_OFF     0x00
#define BLINK_ON       0x01
#define BLINK_OFF      0x00
#define BACKLIGHT_ON   0x80
#define BACKLIGHT_OFF  0x00
#define AUTOSCROLL_ON  0x01
#define AUTOSCROLL_OFF 0x00
#define LEFT_TO_RIGHT  0x02
#define RIGHT_TO_LEFT  0x00

Nanoshield_LCD::Nanoshield_LCD(byte a0, byte a1, byte a2) {
  // Select the three LSBs of the LCD address in the I2C bus
  i2cAddress = LCD_I2C_ADDRESS;
  if (!a0) i2cAddress &= 0x01;
  if (!a1) i2cAddress &= 0x02;
  if (!a2) i2cAddress &= 0x04;
  displayMask = DISPLAY_ON;
  cursorMask = CURSOR_OFF;
  blinkMask = BLINK_OFF;
  backlightMask = BACKLIGHT_ON;
  autoscrollMask = AUTOSCROLL_OFF;
  directionMask = LEFT_TO_RIGHT;
}

void Nanoshield_LCD::writeRegister(uint8_t addr, uint8_t data)
{
  Wire.beginTransmission(i2cAddress);
  Wire.write(addr);
  Wire.write(data);
  Wire.endTransmission();
}

void Nanoshield_LCD::writeLcd4(uint8_t data, bool rs)
{
  // Use only lower 4 bits of data
  data &= 0x0F;

  // Set to pin GP7 in MCP23008 to high if backlight is on
  data |= backlightMask;
  if (rs) data |= 0x40;
  writeRegister(0x0A, data);

  // Raise clock line
  data |= 0x10;
  writeRegister(0x0A, data);

  // Lower clock line
  data &= ~0x10;
  writeRegister(0x0A, data);
  delay(1);
}

void Nanoshield_LCD::writeLcd8(uint8_t data, bool rs)
{
  writeLcd4((data >> 4) & 0x0F, rs);
  writeLcd4(data & 0x0F, rs);
}

void Nanoshield_LCD::displayOnOffControl()
{
  writeLcd8(0x08 | displayMask | cursorMask | blinkMask, false);
}

void Nanoshield_LCD::entryModeSet()
{
  writeLcd8(0x04 | directionMask | autoscrollMask, false);
}

void Nanoshield_LCD::begin()
{
  // Initiate the Wire library and join the I2C bus as a master
  Wire.begin();

  // Configure all GPIO pins in MCP23008 as outputs and leave everything else as default
  writeRegister(0x00, 0x00);

  // Perform LCD reset by instruction in 4-bit mode as described in the HD44780 datasheet
  delay(50);
  writeLcd4(0x03, false);
  delay(5);
  writeLcd4(0x03, false);
  delayMicroseconds(100);
  writeLcd4(0x03, false);
  delay(5);
  writeLcd4(0x02, false);
  writeLcd8(0x28, false);
  writeLcd8(0x08, false); // Two lines, 5x8 dots per character
  writeLcd8(0x01, false);
  writeLcd8(0x06, false); // When writing, increment address and do not shift the display
  writeLcd8(0x0C, false);
  delayMicroseconds(100);
}

void Nanoshield_LCD::clear()
{
  writeLcd8(0x01, false);
}

void Nanoshield_LCD::home()
{
  writeLcd8(0x02, false);
  delay(1);
}

void Nanoshield_LCD::setCursor(uint8_t col, uint8_t row)
{
  // Get address in the first row
  uint8_t addr = col & 0x0F;

  // Add offset if it's not the first row
  if (row == 1) {
    addr += 0x40;
  }

  // Set DDRAM address
  writeLcd8(addr | 0x80, false);
}

size_t Nanoshield_LCD::write(uint8_t data)
{
  writeLcd8(data, true);
  return 1;
}

void Nanoshield_LCD::cursor()
{
  cursorMask = CURSOR_ON;
  displayOnOffControl();
}

void Nanoshield_LCD::noCursor()
{
  cursorMask = CURSOR_OFF;
  displayOnOffControl();
}

void Nanoshield_LCD::blink()
{
  blinkMask = BLINK_ON;
  displayOnOffControl();
}

void Nanoshield_LCD::noBlink()
{
  blinkMask = BLINK_OFF;
  displayOnOffControl();
}

void Nanoshield_LCD::display()
{
  displayMask = DISPLAY_ON;
  displayOnOffControl();
}

void Nanoshield_LCD::noDisplay()
{
  displayMask = DISPLAY_OFF;
  displayOnOffControl();
}

void Nanoshield_LCD::backlight()
{
  backlightMask = BACKLIGHT_ON;
  writeRegister(0x0A, backlightMask);
}

void Nanoshield_LCD::noBacklight()
{
  backlightMask = BACKLIGHT_OFF;
  writeRegister(0x0A, backlightMask);
}

void Nanoshield_LCD::scrollDisplayLeft()
{
  writeLcd8(0x18, false);
}

void Nanoshield_LCD::scrollDisplayRight()
{
  writeLcd8(0x1C, false);
}

void Nanoshield_LCD::autoscroll()
{
  autoscrollMask = AUTOSCROLL_ON;
  entryModeSet();
}

void Nanoshield_LCD::noAutoscroll()
{
  autoscrollMask = AUTOSCROLL_OFF;
  entryModeSet();
}

void Nanoshield_LCD::leftToRight()
{
  directionMask = LEFT_TO_RIGHT;
  entryModeSet();
}

void Nanoshield_LCD::rightToLeft()
{
  directionMask = RIGHT_TO_LEFT;
  entryModeSet();
}

void Nanoshield_LCD::createChar(uint8_t num, uint8_t data[])
{
  if (num > 7) return;

  // Address character position in CGRAM
  writeLcd8(0x40 | (num << 3), false);

  // Write character in CGRAM
  for (int i = 0; i < 8; i++) {
    writeLcd8(data[i], true);
  }
}
<commit_msg>Re-add includes that were removed incorrectly.<commit_after>/*
This is the library to control the LCD Nanoshield

Copyright (c) 2013 Circuitar
This software is released under the MIT license. See the attached LICENSE file for details.
*/

#include "Arduino.h"
#include <Wire.h>
#include "Nanoshield_LCD.h"

#define LCD_I2C_ADDRESS 0x27

// Bit masks
#define DISPLAY_ON     0x04
#define DISPLAY_OFF    0x00
#define CURSOR_ON      0x02
#define CURSOR_OFF     0x00
#define BLINK_ON       0x01
#define BLINK_OFF      0x00
#define BACKLIGHT_ON   0x80
#define BACKLIGHT_OFF  0x00
#define AUTOSCROLL_ON  0x01
#define AUTOSCROLL_OFF 0x00
#define LEFT_TO_RIGHT  0x02
#define RIGHT_TO_LEFT  0x00

Nanoshield_LCD::Nanoshield_LCD(byte a0, byte a1, byte a2) {
  // Select the three LSBs of the LCD address in the I2C bus
  i2cAddress = LCD_I2C_ADDRESS;
  if (!a0) i2cAddress &= 0x01;
  if (!a1) i2cAddress &= 0x02;
  if (!a2) i2cAddress &= 0x04;
  displayMask = DISPLAY_ON;
  cursorMask = CURSOR_OFF;
  blinkMask = BLINK_OFF;
  backlightMask = BACKLIGHT_ON;
  autoscrollMask = AUTOSCROLL_OFF;
  directionMask = LEFT_TO_RIGHT;
}

void Nanoshield_LCD::writeRegister(uint8_t addr, uint8_t data)
{
  Wire.beginTransmission(i2cAddress);
  Wire.write(addr);
  Wire.write(data);
  Wire.endTransmission();
}

void Nanoshield_LCD::writeLcd4(uint8_t data, bool rs)
{
  // Use only lower 4 bits of data
  data &= 0x0F;

  // Set to pin GP7 in MCP23008 to high if backlight is on
  data |= backlightMask;
  if (rs) data |= 0x40;
  writeRegister(0x0A, data);

  // Raise clock line
  data |= 0x10;
  writeRegister(0x0A, data);

  // Lower clock line
  data &= ~0x10;
  writeRegister(0x0A, data);
  delay(1);
}

void Nanoshield_LCD::writeLcd8(uint8_t data, bool rs)
{
  writeLcd4((data >> 4) & 0x0F, rs);
  writeLcd4(data & 0x0F, rs);
}

void Nanoshield_LCD::displayOnOffControl()
{
  writeLcd8(0x08 | displayMask | cursorMask | blinkMask, false);
}

void Nanoshield_LCD::entryModeSet()
{
  writeLcd8(0x04 | directionMask | autoscrollMask, false);
}

void Nanoshield_LCD::begin()
{
  // Initiate the Wire library and join the I2C bus as a master
  Wire.begin();

  // Configure all GPIO pins in MCP23008 as outputs and leave everything else as default
  writeRegister(0x00, 0x00);

  // Perform LCD reset by instruction in 4-bit mode as described in the HD44780 datasheet
  delay(50);
  writeLcd4(0x03, false);
  delay(5);
  writeLcd4(0x03, false);
  delayMicroseconds(100);
  writeLcd4(0x03, false);
  delay(5);
  writeLcd4(0x02, false);
  writeLcd8(0x28, false);
  writeLcd8(0x08, false); // Two lines, 5x8 dots per character
  writeLcd8(0x01, false);
  writeLcd8(0x06, false); // When writing, increment address and do not shift the display
  writeLcd8(0x0C, false);
  delayMicroseconds(100);
}

void Nanoshield_LCD::clear()
{
  writeLcd8(0x01, false);
}

void Nanoshield_LCD::home()
{
  writeLcd8(0x02, false);
  delay(1);
}

void Nanoshield_LCD::setCursor(uint8_t col, uint8_t row)
{
  // Get address in the first row
  uint8_t addr = col & 0x0F;

  // Add offset if it's not the first row
  if (row == 1) {
    addr += 0x40;
  }

  // Set DDRAM address
  writeLcd8(addr | 0x80, false);
}

size_t Nanoshield_LCD::write(uint8_t data)
{
  writeLcd8(data, true);
  return 1;
}

void Nanoshield_LCD::cursor()
{
  cursorMask = CURSOR_ON;
  displayOnOffControl();
}

void Nanoshield_LCD::noCursor()
{
  cursorMask = CURSOR_OFF;
  displayOnOffControl();
}

void Nanoshield_LCD::blink()
{
  blinkMask = BLINK_ON;
  displayOnOffControl();
}

void Nanoshield_LCD::noBlink()
{
  blinkMask = BLINK_OFF;
  displayOnOffControl();
}

void Nanoshield_LCD::display()
{
  displayMask = DISPLAY_ON;
  displayOnOffControl();
}

void Nanoshield_LCD::noDisplay()
{
  displayMask = DISPLAY_OFF;
  displayOnOffControl();
}

void Nanoshield_LCD::backlight()
{
  backlightMask = BACKLIGHT_ON;
  writeRegister(0x0A, backlightMask);
}

void Nanoshield_LCD::noBacklight()
{
  backlightMask = BACKLIGHT_OFF;
  writeRegister(0x0A, backlightMask);
}

void Nanoshield_LCD::scrollDisplayLeft()
{
  writeLcd8(0x18, false);
}

void Nanoshield_LCD::scrollDisplayRight()
{
  writeLcd8(0x1C, false);
}

void Nanoshield_LCD::autoscroll()
{
  autoscrollMask = AUTOSCROLL_ON;
  entryModeSet();
}

void Nanoshield_LCD::noAutoscroll()
{
  autoscrollMask = AUTOSCROLL_OFF;
  entryModeSet();
}

void Nanoshield_LCD::leftToRight()
{
  directionMask = LEFT_TO_RIGHT;
  entryModeSet();
}

void Nanoshield_LCD::rightToLeft()
{
  directionMask = RIGHT_TO_LEFT;
  entryModeSet();
}

void Nanoshield_LCD::createChar(uint8_t num, uint8_t data[])
{
  if (num > 7) return;

  // Address character position in CGRAM
  writeLcd8(0x40 | (num << 3), false);

  // Write character in CGRAM
  for (int i = 0; i < 8; i++) {
    writeLcd8(data[i], true);
  }
}
<|endoftext|>


<commit_before>/*
  pvsops.c: pvs and other spectral-based opcodes

  Copyright (C) 2017 Victor Lazzarini
  This file is part of Csound.

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

  Csound 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 Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/
#include <algorithm>
#include <plugin.h>

struct PVTrace : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  static constexpr char const *otypes = "f";
  static constexpr char const *itypes = "fk";

  int init() {
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error(Str("sliding not supported"));

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error(Str("fsig format not supported"));

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));
    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh](csnd::pv_bin f) {
                       return f.amp() >= thrsh ? f : csnd::pv_bin();
                     });
      framecount = fout.count(fin.count());
    }
    return OK;
  }
};

struct TVConv : csnd::Plugin<1, 6> {
  csnd::AuxMem<MYFLT> ir;
  csnd::AuxMem<MYFLT> in;
  csnd::AuxMem<MYFLT> insp;
  csnd::AuxMem<MYFLT> irsp;
  csnd::AuxMem<MYFLT> out;
  csnd::AuxMem<MYFLT> saved;
  csnd::AuxMem<MYFLT>::iterator itn;
  csnd::AuxMem<MYFLT>::iterator itr;
  csnd::AuxMem<MYFLT>::iterator itnsp;
  csnd::AuxMem<MYFLT>::iterator itrsp;
  uint32_t n;
  uint32_t fils;
  uint32_t pars;
  uint32_t ffts;
  csnd::fftp fwd, inv;
  typedef std::complex<MYFLT> cmplx;

  uint32_t rpow2(uint32_t n) {
    uint32_t v = 2;
    while (v <= n)
      v <<= 1;
    if ((n - (v >> 1)) < (v - n))
      return v >> 1;
    else
      return v;
  }

  cmplx *to_cmplx(MYFLT *f) { return reinterpret_cast<cmplx *>(f); }

  cmplx real_prod(cmplx &a, cmplx &b) {
    return cmplx(a.real() * b.real(), a.imag() * b.imag());
  }

  int init() {
    pars = inargs[4];
    fils = inargs[5];
    if (pars > fils)
      std::swap(pars, fils);
    if (pars > 1) {
      pars = rpow2(pars);
      fils = rpow2(fils) * 2;
      ffts = pars * 2;
      fwd = csound->fft_setup(ffts, FFT_FWD);
      inv = csound->fft_setup(ffts, FFT_INV);
      out.allocate(csound, ffts);
      insp.allocate(csound, fils);
      irsp.allocate(csound, fils);
      saved.allocate(csound, pars);
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
      itnsp = insp.begin();
      itrsp = insp.begin();
      n = 0;
    } else {
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
    }
    itn = in.begin();
    itr = ir.begin();
    return OK;
  }

  int pconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto *frz1 = inargs(2);
    auto *frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if(*frz1 > 0) itn[n] = *inp;
      if(*frz2 > 0) itr[n] = *irp;

      s = out[n] + saved[n];
      saved[n] = out[n + pars];
      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
        std::copy(itn, itn + ffts, itnsp);
        std::copy(itr, itr + ffts, itrsp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, itnsp);
        csound->rfft(fwd, itrsp);
	// increment iterators
        itnsp += ffts;
        itrsp += ffts;
	itn += ffts;
	itr += ffts;
        if (itnsp == insp.end()) {
          itnsp = insp.begin();
          itrsp = irsp.begin();
	  itn = in.begin();
	  itr = ir.begin();
	}
        // spectral delay line
        for (csnd::AuxMem<MYFLT>::iterator it1 = itnsp,
	     it2 = irsp.end() - ffts; it2 >= irsp.begin();
	     it1 += ffts, it2 -= ffts) {
	  if (it1 == insp.end()) it1 = insp.begin();
	  ins =  to_cmplx(it1);
          irs =  to_cmplx(it2);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
        }
        // IFFT
        csound->rfft(inv, out.data());
        n = 0;
      }
      frz1 += inc1;
      frz2 += inc2;
      irp++;
      inp++;
    }
    return OK;
  }

 int dconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto frz1 = inargs(2);
    auto frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

     for (auto &s : outsig) {
      if(*frz1 > 0) *itn++ = *inp;
      if(*frz2 > 0) *itr++ = *irp;
      if(itn == in.end()) itn = in.begin();
      if(itr == ir.end()) itr = ir.begin();
      s = 0.;
      for (csnd::AuxMem<MYFLT>::iterator it1 = itn,
	   it2 = ir.end() - 1; it2 >= ir.begin();
	   it1++, it2--) {
	if(it1 == in.end()) it1  = in.begin();
        s += *it1 * *it2;
      }
      frz1 += inc1;
      frz2 += inc2;
      inp++;
      irp++;
    }
    return OK;
  }

  int aperf() {
    if (pars > 1)
      return pconv();
    else
      return dconv();
  }
};

/*
class PrintThread : public csnd::Thread {
  std::atomic_bool splock;
  std::atomic_bool on;
  std::string message;

  void lock() {
    bool tmp = false;
    while(!splock.compare_exchange_weak(tmp,true))
      tmp = false;
  }

  void unlock() {
    splock = false;
  }

  uintptr_t run() {
    std::string old;
    while(on) {
      lock();
      if(old.compare(message)) {
       csound->message(message.c_str());
       old = message;
      }
      unlock();
    }
    return 0;
  }

public:
  PrintThread(csnd::Csound *csound)
    : Thread(csound), splock(false), on(true), message("") {};

  ~PrintThread(){
    on = false;
    join();
  }

  void set_message(const char *m) {
    lock();
    message = m;
    unlock();
  }

};

struct TPrint : csnd::Plugin<0, 1> {
  static constexpr char const *otypes = "";
  static constexpr char const *itypes = "S";
  PrintThread t;

  int init() {
    csound->plugin_deinit(this);
    csnd::constr(&t, csound);
    return OK;
  }

  int deinit() {
    csnd::destr(&t);
    return OK;
  }

  int kperf() {
    t.set_message(inargs.str_data(0).data);
    return OK;
  }
};
*/

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<PVTrace>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaxxii", csnd::thread::ia);
}
<commit_msg>fix freezing in dconv()<commit_after>/*
  pvsops.c: pvs and other spectral-based opcodes

  Copyright (C) 2017 Victor Lazzarini
  This file is part of Csound.

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

  Csound 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 Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/
#include <algorithm>
#include <plugin.h>

struct PVTrace : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  static constexpr char const *otypes = "f";
  static constexpr char const *itypes = "fk";

  int init() {
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error(Str("sliding not supported"));

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error(Str("fsig format not supported"));

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));
    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh](csnd::pv_bin f) {
                       return f.amp() >= thrsh ? f : csnd::pv_bin();
                     });
      framecount = fout.count(fin.count());
    }
    return OK;
  }
};

struct TVConv : csnd::Plugin<1, 6> {
  csnd::AuxMem<MYFLT> ir;
  csnd::AuxMem<MYFLT> in;
  csnd::AuxMem<MYFLT> insp;
  csnd::AuxMem<MYFLT> irsp;
  csnd::AuxMem<MYFLT> out;
  csnd::AuxMem<MYFLT> saved;
  csnd::AuxMem<MYFLT>::iterator itn;
  csnd::AuxMem<MYFLT>::iterator itr;
  csnd::AuxMem<MYFLT>::iterator itnsp;
  csnd::AuxMem<MYFLT>::iterator itrsp;
  uint32_t n;
  uint32_t fils;
  uint32_t pars;
  uint32_t ffts;
  csnd::fftp fwd, inv;
  typedef std::complex<MYFLT> cmplx;

  uint32_t rpow2(uint32_t n) {
    uint32_t v = 2;
    while (v <= n)
      v <<= 1;
    if ((n - (v >> 1)) < (v - n))
      return v >> 1;
    else
      return v;
  }

  cmplx *to_cmplx(MYFLT *f) { return reinterpret_cast<cmplx *>(f); }

  cmplx real_prod(cmplx &a, cmplx &b) {
    return cmplx(a.real() * b.real(), a.imag() * b.imag());
  }

  int init() {
    pars = inargs[4];
    fils = inargs[5];
    if (pars > fils)
      std::swap(pars, fils);
    if (pars > 1) {
      pars = rpow2(pars);
      fils = rpow2(fils) * 2;
      ffts = pars * 2;
      fwd = csound->fft_setup(ffts, FFT_FWD);
      inv = csound->fft_setup(ffts, FFT_INV);
      out.allocate(csound, ffts);
      insp.allocate(csound, fils);
      irsp.allocate(csound, fils);
      saved.allocate(csound, pars);
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
      itnsp = insp.begin();
      itrsp = insp.begin();
      n = 0;
    } else {
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
    }
    itn = in.begin();
    itr = ir.begin();
    return OK;
  }

  int pconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto *frz1 = inargs(2);
    auto *frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if(*frz1 > 0) itn[n] = *inp;
      if(*frz2 > 0) itr[n] = *irp;

      s = out[n] + saved[n];
      saved[n] = out[n + pars];
      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
        std::copy(itn, itn + ffts, itnsp);
        std::copy(itr, itr + ffts, itrsp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, itnsp);
        csound->rfft(fwd, itrsp);
	// increment iterators
        itnsp += ffts, itrsp += ffts;
	itn += ffts, itr += ffts;
        if (itnsp == insp.end()) {
          itnsp = insp.begin();
          itrsp = irsp.begin();
	  itn = in.begin();
	  itr = ir.begin();
	}
        // spectral delay line
        for (csnd::AuxMem<MYFLT>::iterator it1 = itnsp,
	     it2 = irsp.end() - ffts; it2 >= irsp.begin();
	     it1 += ffts, it2 -= ffts) {
	  if (it1 == insp.end()) it1 = insp.begin();
	  ins =  to_cmplx(it1);
          irs =  to_cmplx(it2);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
        }
        // IFFT
        csound->rfft(inv, out.data());
        n = 0;
      }
      frz1 += inc1, frz2 += inc2;
      irp++, inp++;
    }
    return OK;
  }

 int dconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto frz1 = inargs(2);
    auto frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

     for (auto &s : outsig) {
      if(*frz1 > 0) *itn = *inp;
      if(*frz2 > 0) *itr = *irp;
      itn++, itr++;
      if(itn == in.end()) {
	 itn = in.begin();
         itr = ir.begin();
      }
      s = 0.;
      for (csnd::AuxMem<MYFLT>::iterator it1 = itn,
	   it2 = ir.end() - 1; it2 >= ir.begin();
	   it1++, it2--) {
	if(it1 == in.end()) it1  = in.begin();
        s += *it1 * *it2;
      }
      frz1 += inc1, frz2 += inc2;
      inp++, irp++;
    }
    return OK;
  }

  int aperf() {
    if (pars > 1)
      return pconv();
    else
      return dconv();
  }
};

/*
class PrintThread : public csnd::Thread {
  std::atomic_bool splock;
  std::atomic_bool on;
  std::string message;

  void lock() {
    bool tmp = false;
    while(!splock.compare_exchange_weak(tmp,true))
      tmp = false;
  }

  void unlock() {
    splock = false;
  }

  uintptr_t run() {
    std::string old;
    while(on) {
      lock();
      if(old.compare(message)) {
       csound->message(message.c_str());
       old = message;
      }
      unlock();
    }
    return 0;
  }

public:
  PrintThread(csnd::Csound *csound)
    : Thread(csound), splock(false), on(true), message("") {};

  ~PrintThread(){
    on = false;
    join();
  }

  void set_message(const char *m) {
    lock();
    message = m;
    unlock();
  }

};

struct TPrint : csnd::Plugin<0, 1> {
  static constexpr char const *otypes = "";
  static constexpr char const *itypes = "S";
  PrintThread t;

  int init() {
    csound->plugin_deinit(this);
    csnd::constr(&t, csound);
    return OK;
  }

  int deinit() {
    csnd::destr(&t);
    return OK;
  }

  int kperf() {
    t.set_message(inargs.str_data(0).data);
    return OK;
  }
};
*/

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<PVTrace>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaxxii", csnd::thread::ia);
}
<|endoftext|>


<commit_before>/*
  pvsops.c: pvs and other spectral-based opcodes

  Copyright (C) 2017 Victor Lazzarini
  This file is part of Csound.

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

  Csound 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 Csound; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  02110-1301 USA
*/
#include <algorithm>
#include <plugin.h>

struct PVTrace : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  static constexpr char const *otypes = "f";
  static constexpr char const *itypes = "fk";

  int init() {
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error("sliding not supported");

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error("fsig format not supported");

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));
    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh](csnd::pv_bin f) {
                       return f.amp() >= thrsh ? f : csnd::pv_bin();
                     });
      framecount = fout.count(fin.count());
    }
    return OK;
  }
};

struct TVConv : csnd::Plugin<1, 6> {
  csnd::AuxMem<MYFLT> ir;
  csnd::AuxMem<MYFLT> in;
  csnd::AuxMem<MYFLT> insp;
  csnd::AuxMem<MYFLT> irsp;
  csnd::AuxMem<MYFLT> out;
  csnd::AuxMem<MYFLT> saved;
  csnd::AuxMem<MYFLT>::iterator itn;
  csnd::AuxMem<MYFLT>::iterator itr;
  csnd::AuxMem<MYFLT>::iterator itnsp;
  csnd::AuxMem<MYFLT>::iterator itrsp;
  uint32_t n;
  uint32_t fils;
  uint32_t pars;
  uint32_t ffts;
  csnd::fftp fwd, inv;
  typedef std::complex<MYFLT> cmplx;

  uint32_t rpow2(uint32_t n) {
    uint32_t v = 2;
    while (v <= n)
      v <<= 1;
    if ((n - (v >> 1)) < (v - n))
      return v >> 1;
    else
      return v;
  }

  cmplx *to_cmplx(MYFLT *f) { return reinterpret_cast<cmplx *>(f); }

  cmplx real_prod(cmplx &a, cmplx &b) {
    return cmplx(a.real() * b.real(), a.imag() * b.imag());
  }

  int init() {
    pars = inargs[4];
    fils = inargs[5];
    if (pars > fils)
      std::swap(pars, fils);
    if (pars > 1) {
      pars = rpow2(pars);
      fils = rpow2(fils) * 2;
      ffts = pars * 2;
      fwd = csound->fft_setup(ffts, FFT_FWD);
      inv = csound->fft_setup(ffts, FFT_INV);
      out.allocate(csound, ffts);
      insp.allocate(csound, fils);
      irsp.allocate(csound, fils);
      saved.allocate(csound, pars);
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
      itnsp = insp.begin();
      itrsp = insp.begin();
      n = 0;
    } else {
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
    }
    itn = in.begin();
    itr = ir.begin();
    return OK;
  }

  int pconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto *frz1 = inargs(2);
    auto *frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if (*frz1 > 0)
        itn[n] = *inp;
      if (*frz2 > 0)
        itr[n] = *irp;

      s = out[n] + saved[n];
      saved[n] = out[n + pars];
      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
        std::copy(itn, itn + ffts, itnsp);
        std::copy(itr, itr + ffts, itrsp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, itnsp);
        csound->rfft(fwd, itrsp);
        // increment iterators
        itnsp += ffts, itrsp += ffts;
        itn += ffts, itr += ffts;
        if (itnsp == insp.end()) {
          itnsp = insp.begin();
          itrsp = irsp.begin();
          itn = in.begin();
          itr = ir.begin();
        }
        // spectral delay line
        for (csnd::AuxMem<MYFLT>::iterator it1 = itnsp, it2 = irsp.end() - ffts;
             it2 >= irsp.begin(); it1 += ffts, it2 -= ffts) {
          if (it1 == insp.end())
            it1 = insp.begin();
          ins = to_cmplx(it1);
          irs = to_cmplx(it2);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
        }
        // IFFT
        csound->rfft(inv, out.data());
        n = 0;
      }
      frz1 += inc1, frz2 += inc2;
      irp++, inp++;
    }
    return OK;
  }

  int dconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto frz1 = inargs(2);
    auto frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if (*frz1 > 0)
        *itn = *inp;
      if (*frz2 > 0)
        *itr = *irp;
      itn++, itr++;
      if (itn == in.end()) {
        itn = in.begin();
        itr = ir.begin();
      }
      s = 0.;
      for (csnd::AuxMem<MYFLT>::iterator it1 = itn, it2 = ir.end() - 1;
           it2 >= ir.begin(); it1++, it2--) {
        if (it1 == in.end())
          it1 = in.begin();
        s += *it1 * *it2;
      }
      frz1 += inc1, frz2 += inc2;
      inp++, irp++;
    }
    return OK;
  }

  int aperf() {
    if (pars > 1)
      return pconv();
    else
      return dconv();
  }
};

/*
class PrintThread : public csnd::Thread {
  std::atomic_bool splock;
  std::atomic_bool on;
  std::string message;

  void lock() {
    bool tmp = false;
    while(!splock.compare_exchange_weak(tmp,true))
      tmp = false;
  }

  void unlock() {
    splock = false;
  }

  uintptr_t run() {
    std::string old;
    while(on) {
      lock();
      if(old.compare(message)) {
       csound->message(message.c_str());
       old = message;
      }
      unlock();
    }
    return 0;
  }

public:
  PrintThread(csnd::Csound *csound)
    : Thread(csound), splock(false), on(true), message("") {};

  ~PrintThread(){
    on = false;
    join();
  }

  void set_message(const char *m) {
    lock();
    message = m;
    unlock();
  }

};

struct TPrint : csnd::Plugin<0, 1> {
  static constexpr char const *otypes = "";
  static constexpr char const *itypes = "S";
  PrintThread t;

  int init() {
    csound->plugin_deinit(this);
    csnd::constr(&t, csound);
    return OK;
  }

  int deinit() {
    csnd::destr(&t);
    return OK;
  }

  int kperf() {
    t.set_message(inargs.str_data(0).data);
    return OK;
  }
};
*/

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<PVTrace>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaxxii", csnd::thread::ia);
}
<commit_msg>new pvstrace version<commit_after>/*
  pvsops.c: pvs and other spectral-based opcodes

  Copyright (C) 2017 Victor Lazzarini
  This file is part of Csound.

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

  Csound 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 Csound; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  02110-1301 USA
*/
#include <algorithm>
#include <plugin.h>

struct PVTrace : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  static constexpr char const *otypes = "f";
  static constexpr char const *itypes = "fk";

  int init() {
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error("sliding not supported");

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error("fsig format not supported");

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));
    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh](csnd::pv_bin f) {
                       return f.amp() >= thrsh ? f : csnd::pv_bin();
                     });
      framecount = fout.count(fin.count());
    }
    return OK;
  }
};

struct binamp {
  int bin;
  float amp;
};

struct PVTrace2 : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  csnd::AuxMem<binamp> binlist;
  static constexpr char const *otypes = "fk[]";
  static constexpr char const *itypes = "fk";

  int init() {
    csnd::Vector<MYFLT> &bins = outargs.vector_data<MYFLT>(1);
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error("sliding not supported");

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error("fsig format not supported");

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    binlist.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));

    bins.init(csound, inargs.fsig_data(0).nbins());

    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);
    csnd::Vector<MYFLT> &bins = outargs.vector_data<MYFLT>(1);
    csnd::AuxMem<binamp> &mbins = binlist;

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      int cnt = 0;
      int bin = 0;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh, &mbins, &cnt, &bin](csnd::pv_bin f) {
                       if(f.amp() >= thrsh) {
                       mbins[cnt].bin = bin++;
                       mbins[cnt++].amp = f.amp();
                       return f;
                       }
                       else {
                        bin++;
                        return csnd::pv_bin();
                       }
                     });
      std::sort(binlist.begin(), binlist.begin()+cnt, [](binamp &a, binamp &b) {
          return (a.amp > b.amp);
      });
      std::transform(binlist.begin(), binlist.begin()+cnt, bins.begin(),
                     [](binamp a) { return (MYFLT) a.bin;});

      std::fill(bins.begin()+cnt, bins.end(), FL(0.0));

      framecount = fout.count(fin.count());
    }

    return OK;
  }
};

struct TVConv : csnd::Plugin<1, 6> {
  csnd::AuxMem<MYFLT> ir;
  csnd::AuxMem<MYFLT> in;
  csnd::AuxMem<MYFLT> insp;
  csnd::AuxMem<MYFLT> irsp;
  csnd::AuxMem<MYFLT> out;
  csnd::AuxMem<MYFLT> saved;
  csnd::AuxMem<MYFLT>::iterator itn;
  csnd::AuxMem<MYFLT>::iterator itr;
  csnd::AuxMem<MYFLT>::iterator itnsp;
  csnd::AuxMem<MYFLT>::iterator itrsp;
  uint32_t n;
  uint32_t fils;
  uint32_t pars;
  uint32_t ffts;
  csnd::fftp fwd, inv;
  typedef std::complex<MYFLT> cmplx;

  uint32_t rpow2(uint32_t n) {
    uint32_t v = 2;
    while (v <= n)
      v <<= 1;
    if ((n - (v >> 1)) < (v - n))
      return v >> 1;
    else
      return v;
  }

  cmplx *to_cmplx(MYFLT *f) { return reinterpret_cast<cmplx *>(f); }

  cmplx real_prod(cmplx &a, cmplx &b) {
    return cmplx(a.real() * b.real(), a.imag() * b.imag());
  }

  int init() {
    pars = inargs[4];
    fils = inargs[5];
    if (pars > fils)
      std::swap(pars, fils);
    if (pars > 1) {
      pars = rpow2(pars);
      fils = rpow2(fils) * 2;
      ffts = pars * 2;
      fwd = csound->fft_setup(ffts, FFT_FWD);
      inv = csound->fft_setup(ffts, FFT_INV);
      out.allocate(csound, ffts);
      insp.allocate(csound, fils);
      irsp.allocate(csound, fils);
      saved.allocate(csound, pars);
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
      itnsp = insp.begin();
      itrsp = insp.begin();
      n = 0;
    } else {
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
    }
    itn = in.begin();
    itr = ir.begin();
    return OK;
  }

  int pconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto *frz1 = inargs(2);
    auto *frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if (*frz1 > 0)
        itn[n] = *inp;
      if (*frz2 > 0)
        itr[n] = *irp;

      s = out[n] + saved[n];
      saved[n] = out[n + pars];
      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
        std::copy(itn, itn + ffts, itnsp);
        std::copy(itr, itr + ffts, itrsp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, itnsp);
        csound->rfft(fwd, itrsp);
        // increment iterators
        itnsp += ffts, itrsp += ffts;
        itn += ffts, itr += ffts;
        if (itnsp == insp.end()) {
          itnsp = insp.begin();
          itrsp = irsp.begin();
          itn = in.begin();
          itr = ir.begin();
        }
        // spectral delay line
        for (csnd::AuxMem<MYFLT>::iterator it1 = itnsp, it2 = irsp.end() - ffts;
             it2 >= irsp.begin(); it1 += ffts, it2 -= ffts) {
          if (it1 == insp.end())
            it1 = insp.begin();
          ins = to_cmplx(it1);
          irs = to_cmplx(it2);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
        }
        // IFFT
        csound->rfft(inv, out.data());
        n = 0;
      }
      frz1 += inc1, frz2 += inc2;
      irp++, inp++;
    }
    return OK;
  }

  int dconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    auto frz1 = inargs(2);
    auto frz2 = inargs(3);
    auto inc1 = csound->is_asig(frz1);
    auto inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if (*frz1 > 0)
        *itn = *inp;
      if (*frz2 > 0)
        *itr = *irp;
      itn++, itr++;
      if (itn == in.end()) {
        itn = in.begin();
        itr = ir.begin();
      }
      s = 0.;
      for (csnd::AuxMem<MYFLT>::iterator it1 = itn, it2 = ir.end() - 1;
           it2 >= ir.begin(); it1++, it2--) {
        if (it1 == in.end())
          it1 = in.begin();
        s += *it1 * *it2;
      }
      frz1 += inc1, frz2 += inc2;
      inp++, irp++;
    }
    return OK;
  }

  int aperf() {
    if (pars > 1)
      return pconv();
    else
      return dconv();
  }
};

/*
class PrintThread : public csnd::Thread {
  std::atomic_bool splock;
  std::atomic_bool on;
  std::string message;

  void lock() {
    bool tmp = false;
    while(!splock.compare_exchange_weak(tmp,true))
      tmp = false;
  }

  void unlock() {
    splock = false;
  }

  uintptr_t run() {
    std::string old;
    while(on) {
      lock();
      if(old.compare(message)) {
       csound->message(message.c_str());
       old = message;
      }
      unlock();
    }
    return 0;
  }

public:
  PrintThread(csnd::Csound *csound)
    : Thread(csound), splock(false), on(true), message("") {};

  ~PrintThread(){
    on = false;
    join();
  }

  void set_message(const char *m) {
    lock();
    message = m;
    unlock();
  }

};

struct TPrint : csnd::Plugin<0, 1> {
  static constexpr char const *otypes = "";
  static constexpr char const *itypes = "S";
  PrintThread t;

  int init() {
    csound->plugin_deinit(this);
    csnd::constr(&t, csound);
    return OK;
  }

  int deinit() {
    csnd::destr(&t);
    return OK;
  }

  int kperf() {
    t.set_message(inargs.str_data(0).data);
    return OK;
  }
};
*/

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<PVTrace>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<PVTrace2>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaxxii", csnd::thread::ia);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: olecomponent.hxx,v $
 *
 *  $Revision: 1.17 $
 *
 *  last change: $Author: rt $ $Date: 2005-10-19 12:40:54 $
 *
 *  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 _INC_OLECOMPONENT_HXX_
#define _INC_OLECOMPONENT_HXX_

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_
#include <com/sun/star/util/XCloseable.hpp>
#endif

#ifndef _COM_SUN_STAR_DATATRANSFER_XTRANSFERABLE_HPP_
#include <com/sun/star/datatransfer/XTransferable.hpp>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_VERBDESCRIPTOR_HPP_
#include <com/sun/star/embed/VerbDescriptor.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_SIZE_HPP_
#include <com/sun/star/awt/Size.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEL_HPP_
#include <com/sun/star/lang/XUnoTunnel.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE5_HXX_
#include <cppuhelper/implbase5.hxx>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFIABLE_HPP_
#include <com/sun/star/util/XModifiable.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFYLISTENER_HPP_
#include <com/sun/star/util/XModifyListener.hpp>
#endif

#include <vector>

namespace com { namespace sun { namespace star {
}}}

namespace cppu {
    class OMultiTypeInterfaceContainerHelper;
}

class OleWrapperClientSite;
class OleWrapperAdviseSink;
class OleEmbeddedObject;
struct OleComponentNative_Impl;

class OleComponent : public ::cppu::WeakImplHelper5< ::com::sun::star::util::XCloseable, ::com::sun::star::lang::XComponent,
                                                     ::com::sun::star::lang::XUnoTunnel, ::com::sun::star::util::XModifiable,
                                                     ::com::sun::star::datatransfer::XTransferable >
{
    ::osl::Mutex m_aMutex;
    ::cppu::OMultiTypeInterfaceContainerHelper* m_pInterfaceContainer;

    sal_Bool m_bDisposed;
    sal_Bool m_bModified;
    OleComponentNative_Impl* m_pNativeImpl;

    OleEmbeddedObject* m_pUnoOleObject;
    OleWrapperClientSite* m_pOleWrapClientSite;
    OleWrapperAdviseSink* m_pImplAdviseSink;

    ::rtl::OUString m_aTempURL;

    sal_Int32 m_nOLEMiscFlags;
    sal_Int32 m_nAdvConn;

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > m_aVerbList;
    ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > m_aDataFlavors;

    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory;

    sal_Bool m_bOleInitialized;

    sal_Bool InitializeObject_Impl();

    void CreateIStorageOnXInputStream_Impl(
                            const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream );
    void CreateNewIStorage_Impl();

    void RetrieveObjectDataFlavors_Impl();

    void Dispose();

public:
    OleComponent( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& m_xFactory,
                  OleEmbeddedObject* pOleObj );

    virtual ~OleComponent();

    OleComponent* createEmbeddedCopyOfLink();

    void disconnectEmbeddedObject();

    // ==== Initialization ==================================================
    void LoadEmbeddedObject( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream );

    void CreateObjectFromClipboard();

    void CreateNewEmbeddedObject( const ::com::sun::star::uno::Sequence< sal_Int8 >& aSeqCLSID );

    void CreateObjectFromData(
                        const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransfer );

    void CreateObjectFromFile( const ::rtl::OUString& aFileName );

    void CreateLinkFromFile( const ::rtl::OUString& aFileName );

    void InitEmbeddedCopyOfLink( OleComponent* pOleLinkComponent );

    // ======================================================================

    void RunObject(); // switch OLE object to running state

    void CloseObject(); // switch OLE object to loaded state

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > GetVerbList();

    void ExecuteVerb( sal_Int32 nVerbID );

    void SetHostName( const ::rtl::OUString& aContName, const ::rtl::OUString& aEmbDocName );

    void SetExtent( const ::com::sun::star::awt::Size& aVisAreaSize, sal_Int64 nAspect );

    ::com::sun::star::awt::Size GetExtent( sal_Int64 nAspect );
    ::com::sun::star::awt::Size GetReccomendedExtent( sal_Int64 nAspect );

    sal_Int64 GetMiscStatus( sal_Int64 nAspect );

    ::com::sun::star::uno::Sequence< sal_Int8 > GetCLSID();

    sal_Bool IsDirty();

    void StoreOwnTmpIfNecessary();
    void StoreObjectToStream( ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > xOutStream );

    sal_Bool SaveObject_Impl();
    sal_Bool OnShowWindow_Impl( sal_Bool bShow );
    void OnViewChange_Impl( sal_uInt32 dwAspect );

    sal_Bool GetGraphicalCache_Impl( const ::com::sun::star::datatransfer::DataFlavor& aFlavor,
                                     ::com::sun::star::uno::Any& aResult );

    // XCloseable
    virtual void SAL_CALL close( sal_Bool DeliverOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);

    // XTransferable
    virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors(  ) throw (::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::uno::RuntimeException);

    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);

    // XUnoTunnel
    virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) ;

    // XModifiable
    virtual sal_Bool SAL_CALL isModified() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setModified( sal_Bool bModified )
        throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener) throw(::com::sun::star::uno::RuntimeException);
};

#endif

<commit_msg>INTEGRATION: CWS optstor2 (1.15.18.1.2); FILE MERGED 2005/11/10 17:11:20 mav 1.15.18.1.2.2: RESYNC: (1.15.18.1-1.17); FILE MERGED 2005/10/13 14:57:57 mav 1.15.18.1.2.1: #i55785# let object own the temporary file<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: olecomponent.hxx,v $
 *
 *  $Revision: 1.18 $
 *
 *  last change: $Author: obo $ $Date: 2006-01-20 09:51:43 $
 *
 *  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 _INC_OLECOMPONENT_HXX_
#define _INC_OLECOMPONENT_HXX_

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_
#include <com/sun/star/util/XCloseable.hpp>
#endif

#ifndef _COM_SUN_STAR_DATATRANSFER_XTRANSFERABLE_HPP_
#include <com/sun/star/datatransfer/XTransferable.hpp>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_XOPTIMIZEDSTORAGE_HPP_
#include <com/sun/star/embed/XOptimizedStorage.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_VERBDESCRIPTOR_HPP_
#include <com/sun/star/embed/VerbDescriptor.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_SIZE_HPP_
#include <com/sun/star/awt/Size.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEL_HPP_
#include <com/sun/star/lang/XUnoTunnel.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE5_HXX_
#include <cppuhelper/implbase5.hxx>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFIABLE_HPP_
#include <com/sun/star/util/XModifiable.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFYLISTENER_HPP_
#include <com/sun/star/util/XModifyListener.hpp>
#endif

#include <vector>

namespace com { namespace sun { namespace star {
}}}

namespace cppu {
    class OMultiTypeInterfaceContainerHelper;
}

class OleWrapperClientSite;
class OleWrapperAdviseSink;
class OleEmbeddedObject;
struct OleComponentNative_Impl;

class OleComponent : public ::cppu::WeakImplHelper5< ::com::sun::star::util::XCloseable, ::com::sun::star::lang::XComponent,
                                                     ::com::sun::star::lang::XUnoTunnel, ::com::sun::star::util::XModifiable,
                                                     ::com::sun::star::datatransfer::XTransferable >
{
    ::osl::Mutex m_aMutex;
    ::cppu::OMultiTypeInterfaceContainerHelper* m_pInterfaceContainer;

    sal_Bool m_bDisposed;
    sal_Bool m_bModified;
    OleComponentNative_Impl* m_pNativeImpl;

    OleEmbeddedObject* m_pUnoOleObject;
    OleWrapperClientSite* m_pOleWrapClientSite;
    OleWrapperAdviseSink* m_pImplAdviseSink;

    sal_Int32 m_nOLEMiscFlags;
    sal_Int32 m_nAdvConn;

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > m_aVerbList;
    ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > m_aDataFlavors;

    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory;

    sal_Bool m_bOleInitialized;

    sal_Bool InitializeObject_Impl();

    void CreateNewIStorage_Impl();

    void RetrieveObjectDataFlavors_Impl();

    void Dispose();

public:
    OleComponent( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& m_xFactory,
                  OleEmbeddedObject* pOleObj );

    virtual ~OleComponent();

    OleComponent* createEmbeddedCopyOfLink();

    void disconnectEmbeddedObject();

    // ==== Initialization ==================================================
    void LoadEmbeddedObject( const ::rtl::OUString& aTempURL );

    void CreateObjectFromClipboard();

    void CreateNewEmbeddedObject( const ::com::sun::star::uno::Sequence< sal_Int8 >& aSeqCLSID );

    void CreateObjectFromData(
                        const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransfer );

    void CreateObjectFromFile( const ::rtl::OUString& aFileName );

    void CreateLinkFromFile( const ::rtl::OUString& aFileName );

    void InitEmbeddedCopyOfLink( OleComponent* pOleLinkComponent );

    // ======================================================================

    void RunObject(); // switch OLE object to running state

    void CloseObject(); // switch OLE object to loaded state

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > GetVerbList();

    void ExecuteVerb( sal_Int32 nVerbID );

    void SetHostName( const ::rtl::OUString& aContName, const ::rtl::OUString& aEmbDocName );

    void SetExtent( const ::com::sun::star::awt::Size& aVisAreaSize, sal_Int64 nAspect );

    ::com::sun::star::awt::Size GetExtent( sal_Int64 nAspect );
    ::com::sun::star::awt::Size GetReccomendedExtent( sal_Int64 nAspect );

    sal_Int64 GetMiscStatus( sal_Int64 nAspect );

    ::com::sun::star::uno::Sequence< sal_Int8 > GetCLSID();

    sal_Bool IsDirty();

    void StoreOwnTmpIfNecessary();

    sal_Bool SaveObject_Impl();
    sal_Bool OnShowWindow_Impl( sal_Bool bShow );
    void OnViewChange_Impl( sal_uInt32 dwAspect );

    sal_Bool GetGraphicalCache_Impl( const ::com::sun::star::datatransfer::DataFlavor& aFlavor,
                                     ::com::sun::star::uno::Any& aResult );

    // XCloseable
    virtual void SAL_CALL close( sal_Bool DeliverOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);

    // XTransferable
    virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors(  ) throw (::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::uno::RuntimeException);

    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);

    // XUnoTunnel
    virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) ;

    // XModifiable
    virtual sal_Bool SAL_CALL isModified() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setModified( sal_Bool bModified )
        throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener) throw(::com::sun::star::uno::RuntimeException);
};

#endif

<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>

#include <libport/assert.hh>
#include <libport/containers.hh>
#include <libport/debug.hh>
#include <libport/escape.hh>
#include <libport/foreach.hh>
#include <libport/ip-semaphore.hh>
#include <libport/pthread.h>
#include <libport/windows.hh>
#include <libport/unistd.h>

#ifndef WIN32
# include <syslog.h>
#endif

#ifndef LIBPORT_DEBUG_DISABLE

namespace libport
{

  namespace debug
  {
    categories_type& get_categories()
    {
      static categories_type categories;
      return categories;
    }
    int& categories_largest()
    {
      static int res = 0;
      return res;
    }

    int add_category(const std::string& name)
    {
      get_categories()[name] = true;
      int size = name.size();
      if (size > categories_largest())
        categories_largest() = size;
      return 42;
    }

    int enable_category(const std::string& name)
    {
      get_categories()[name] = true;
      return 42;
    }

    int disable_category(const std::string& name)
    {
      get_categories()[name] = false;
      return 42;
    }

    bool test_category(const std::string& name)
    {
      return get_categories()[name];
    }
  }

  Debug::Debug()
    : categories_stack_()
    , level_stack_()
    , locations_(getenv("GD_LOC"))
    , timestamps_(getenv("GD_TIME"))
    , filter_(levels::log)
  {
    push_level(levels::log);
    if (const char* lvl_c = getenv("GD_LEVEL"))
      filter(lvl_c);
  }

  Debug::~Debug()
  {}

  void
  Debug::filter(levels::Level lvl)
  {
    filter_ = lvl;
  }

  void
  Debug::filter(const std::string& lvl)
  {
    if (lvl == "NONE" || lvl == "0")
      filter(Debug::levels::none);
    else if (lvl == "LOG" || lvl == "1")
      filter(Debug::levels::log);
    else if (lvl == "TRACE" || lvl == "2")
      filter(Debug::levels::trace);
    else if (lvl == "DEBUG" || lvl == "3")
      filter(Debug::levels::debug);
    else if (lvl == "DUMP" || lvl == "4")
      filter(Debug::levels::dump);
    else
      // Don't use GD_ABORT here, we can be in the debugger constructor!
      assert(!"invalid debug level (NONE, LOG, TRACE, DEBUG, DUMP or [0-4])");
  }

  Debug::levels::Level
  Debug::level() const
  {
    return filter_;
  }

# ifdef LIBPORT_HAVE_IP_SEMAPHORE
  static IPSemaphore& sem()
  {
    static IPSemaphore res(1);
    return res;
  }
# endif

  void
  Debug::debug(const std::string& msg,
               types::Type type,
               const std::string& fun,
               const std::string& file,
               unsigned line)
  {
    if (disabled())
      return;

    {
# ifdef LIBPORT_HAVE_IP_SEMAPHORE
      IPSemaphore::Lock lock(sem());
# endif
      message(msg, type, fun, file, line);
    }
  }

  libport::Finally::action_type
  Debug::push_category(const std::string& category)
  {
    categories_stack_.push_back(category);
    return boost::bind(&Debug::pop_category, this);
  }

  libport::Finally::action_type
  Debug::push_level(levels::Level lvl)
  {
    level_stack_.push_back(lvl);
    return boost::bind(&Debug::pop_level, this);
  }

  bool
  Debug::disabled()
  {
    return (level_stack_.back() > filter_
            || categories_stack_.empty()
            || !debug::test_category(categories_stack_.back()));
  }

  static void noop()
  {}

  libport::Finally::action_type
  Debug::push(const std::string& msg,
              const std::string& fun,
              const std::string& file,
              unsigned line)
  {
    if (disabled())
      return noop;
    message_push(msg, fun, file, line);
    return boost::bind(&Debug::pop, this);
  }

  void
  Debug::pop_category()
  {
    assert(!categories_stack_.empty());
    categories_stack_.pop_back();
  }

  void
  Debug::pop_level()
  {
    level_stack_.pop_back();
  }

  std::string
  Debug::category()
  {
    std::string res = (categories_stack_.empty()
                       ? "NONE"
                       : categories_stack_.back());
    int size = res.size();
    int largest = debug::categories_largest();
    if (size < largest)
    {
      int diff = largest - size;
      res = std::string(diff / 2, ' ')
        + res
        + std::string(diff / 2 + diff % 2, ' ');
    }

    return res;
  }

#define ATTRIBUTE(Name)                         \
                                                \
  void Debug::Name(bool v)                      \
  {                                             \
    Name##_ = v;                                \
  }                                             \
                                                \
  bool Debug::Name()                            \
  {                                             \
    return Name##_;                             \
  }                                             \

  ATTRIBUTE(locations);
  ATTRIBUTE(timestamps);

#undef ATTRIBUTE

  void Debug::abort(const std::string& msg)
  {
    GD_ERROR(msg);
    libport::abort();
  }

  namespace opts
  {

    void cb_debug_fun(const std::string& lvl)
    {
      GD_DEBUGGER->filter(lvl);
    }

    OptionValued::callback_type cb_debug(&cb_debug_fun);

    OptionValue
    debug("set the debug level in NONE, LOG (default), TRACE, DEBUG, DUMP",
          "debug", 'd', "LEVEL", &cb_debug);

  }

  ConsoleDebug::ConsoleDebug()
    : indent_(0)
  {}

  static void show_time()
  {
    time_t     now;
    struct tm  *ts;
    char       buf[80];

    now = time(NULL);
    ts = localtime(&now);
    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
    std::cerr << buf;
  }

  void
  ConsoleDebug::color(int color, bool bold)
  {
    static bool tty = isatty(STDOUT_FILENO);
    static bool force = getenv("GD_COLOR");
    boost::format format("[33;0%s;%sm");
    if (tty || force)
      std::cerr << str(format % (bold ? 1 : 0) % color);
  }

  void
  ConsoleDebug::reset()
  {
    color(0);
  }

  static Debug::colors::Color
  msg_color(Debug::types::Type type)
  {
    switch (type)
    {
      case Debug::types::info:
        return Debug::colors::white;
      case Debug::types::warn:
        return Debug::colors::yellow;
      case Debug::types::error:
        return Debug::colors::red;
    };
    GD_UNREACHABLE();
  }

  void
  ConsoleDebug::message(const std::string& msg,
                        types::Type type,
                        const std::string& fun,
                        const std::string& file,
                        unsigned line)
  {
    Debug::colors::Color c = msg_color(type);
    if (timestamps())
    {
      color(c);
      show_time();
      std::cerr << "    ";
    }
    color(colors::purple);
    std::cerr << "[" << category() << "] ";
    {
      static bool pid = getenv("GD_PID");
      if (pid)
        std::cerr << "[" << getpid() << "] ";
    }
#ifndef WIN32
    {
      static bool thread = getenv("GD_THREAD");
      if (thread)
        std::cerr << "[" << pthread_self() << "] ";
    }
#endif
    color(c);
    for (unsigned i = 0; i < indent_; ++i)
      std::cerr << " ";
    std::cerr << msg;
    if (locations())
    {
      color(colors::blue);
      std::cerr << "    (" << fun << ", " << file << ":" << line << ")";
    }
    color(colors::white);
    std::cerr << std::endl;
  }

  void
  ConsoleDebug::message_push(const std::string& msg,
                             const std::string& fun,
                             const std::string& file,
                             unsigned line)
  {
    debug(msg, types::info, fun, file, line);
    indent_ += 2;
  }

  void
  ConsoleDebug::pop()
  {
    indent_ -= 2;
  }

  std::string gd_ihexdump(const unsigned char* data, unsigned size)
  {
    std::stringstream ss;
    ss << libport::escape(std::string((const char*)data, (size_t)(size)));
    std::string res = "\"" + ss.str() + "\" ";
    bool first = true;
    for (unsigned i = 0; i < size; ++i)
    {
      if (first)
        first = false;
      else
        res += " ";
      boost::format format("0x%x");
      // This is sick, but we have to cast to int, or boost::format
      // will print the character.
      res += str(format % static_cast<unsigned int>(data[i]));
    }
    return res;
  }

#ifndef WIN32
  /*-------------.
  | Syslog debug |
  `-------------*/

  SyslogDebug::SyslogDebug(const std::string& program)
  {
    boost::format format("Opening syslog session for '%s'");

    openlog(strdup(program.c_str()), LOG_PID, LOG_DAEMON);
    syslog(LOG_INFO | LOG_DAEMON, "%s", (format % program).str().c_str());
  }

  SyslogDebug::~SyslogDebug()
  {
    syslog(LOG_INFO | LOG_DAEMON, "Closing syslog session.");
    closelog();
  }

  static
  int type_to_prio(Debug::types::Type t)
  {
    switch (t)
    {
#define CASE(In, Out)                           \
      case Debug::types::In: return Out; break
      CASE(info,  LOG_INFO);
      CASE(warn,  LOG_WARNING);
      CASE(error, LOG_ERR);
      // Pacify Gcc.
    }
    libport::abort();
#undef CASE
  }

  void
  SyslogDebug::message(const std::string& msg,
                        types::Type type,
                        const std::string& fun,
                        const std::string& file,
                        unsigned line)
  {
    std::stringstream s;
    s << "[" << category() << "] ";
    for (unsigned i = 0; i < indent_; ++i)
      s << " ";
    s << msg;
    if (locations())
      s << "    (" << fun << ", " << file << ":" << line << ")";
    int prio = type_to_prio(type) | LOG_DAEMON;
    syslog(prio, "%s", s.str().c_str());
  }

  void
  SyslogDebug::message_push(const std::string& msg,
                             const std::string& fun,
                             const std::string& file,
                             unsigned line)
  {
    debug(msg, types::info, fun, file, line);
    indent_ += 2;
  }

  void
  SyslogDebug::pop()
  {
    indent_ -= 2;
  }
#endif

  boost::function0<Debug*> make_debugger;

  typedef std::map<pthread_t, Debug*> map_type;
  // Do not make it an actual object, as it is sometimes used on
  // dtors, and the order to destruction is not specified.  Using a
  // dynamically allocated object protects us from this.
  static map_type* pdebuggers = new map_type;

  namespace debug
  {
    void clear()
    {
#if FIXME
      typedef std::pair<pthread_t, Debug*> entry;
      foreach (entry p, *pdebuggers)
      {
        delete p.second;
        p.second = 0;
      }
#endif
      delete pdebuggers;
      pdebuggers = 0;
    }
  }

  Debug* debugger()
  {
    map_type& debuggers = *pdebuggers;
    pthread_t id = pthread_self();
    if (!libport::mhas(debuggers, id))
    {
      if (make_debugger.empty())
      {
        debuggers[id] = new ConsoleDebug;
        GD_WARN("GD_INIT was not invoked, defaulting to console logs");
      }
      else
        debuggers[id] = make_debugger();
      debuggers[id]->push_category("NONE");
    }
    return debuggers[id];
  }

  GD_ADD_CATEGORY(NONE);

}

#endif
<commit_msg>debug: only use shared lock if GD_USE_LOCK or GD_PID is set.<commit_after>#include <cassert>
#include <iostream>

#include <libport/assert.hh>
#include <libport/containers.hh>
#include <libport/debug.hh>
#include <libport/escape.hh>
#include <libport/foreach.hh>
#include <libport/ip-semaphore.hh>
#include <libport/pthread.h>
#include <libport/windows.hh>
#include <libport/unistd.h>

#ifndef WIN32
# include <syslog.h>
#endif

#ifndef LIBPORT_DEBUG_DISABLE

namespace libport
{

  namespace debug
  {
    categories_type& get_categories()
    {
      static categories_type categories;
      return categories;
    }
    int& categories_largest()
    {
      static int res = 0;
      return res;
    }

    int add_category(const std::string& name)
    {
      get_categories()[name] = true;
      int size = name.size();
      if (size > categories_largest())
        categories_largest() = size;
      return 42;
    }

    int enable_category(const std::string& name)
    {
      get_categories()[name] = true;
      return 42;
    }

    int disable_category(const std::string& name)
    {
      get_categories()[name] = false;
      return 42;
    }

    bool test_category(const std::string& name)
    {
      return get_categories()[name];
    }
  }

  Debug::Debug()
    : categories_stack_()
    , level_stack_()
    , locations_(getenv("GD_LOC"))
    , timestamps_(getenv("GD_TIME"))
    , filter_(levels::log)
  {
    push_level(levels::log);
    if (const char* lvl_c = getenv("GD_LEVEL"))
      filter(lvl_c);
  }

  Debug::~Debug()
  {}

  void
  Debug::filter(levels::Level lvl)
  {
    filter_ = lvl;
  }

  void
  Debug::filter(const std::string& lvl)
  {
    if (lvl == "NONE" || lvl == "0")
      filter(Debug::levels::none);
    else if (lvl == "LOG" || lvl == "1")
      filter(Debug::levels::log);
    else if (lvl == "TRACE" || lvl == "2")
      filter(Debug::levels::trace);
    else if (lvl == "DEBUG" || lvl == "3")
      filter(Debug::levels::debug);
    else if (lvl == "DUMP" || lvl == "4")
      filter(Debug::levels::dump);
    else
      // Don't use GD_ABORT here, we can be in the debugger constructor!
      assert(!"invalid debug level (NONE, LOG, TRACE, DEBUG, DUMP or [0-4])");
  }

  Debug::levels::Level
  Debug::level() const
  {
    return filter_;
  }

# ifdef LIBPORT_HAVE_IP_SEMAPHORE
  static IPSemaphore& sem()
  {
    static IPSemaphore res(1);
    return res;
  }
# endif

  void
  Debug::debug(const std::string& msg,
               types::Type type,
               const std::string& fun,
               const std::string& file,
               unsigned line)
  {
    if (disabled())
      return;

    {
# ifdef LIBPORT_HAVE_IP_SEMAPHORE
      static bool useLock = getenv("GD_USE_LOCK") || getenv("GD_PID");
      libport::Finally f;
      if (useLock)
      {
        --sem();
        f << boost::bind(&IPSemaphore::operator++, boost::ref(sem()));
      }
# endif
      message(msg, type, fun, file, line);
    }
  }

  libport::Finally::action_type
  Debug::push_category(const std::string& category)
  {
    categories_stack_.push_back(category);
    return boost::bind(&Debug::pop_category, this);
  }

  libport::Finally::action_type
  Debug::push_level(levels::Level lvl)
  {
    level_stack_.push_back(lvl);
    return boost::bind(&Debug::pop_level, this);
  }

  bool
  Debug::disabled()
  {
    return (level_stack_.back() > filter_
            || categories_stack_.empty()
            || !debug::test_category(categories_stack_.back()));
  }

  static void noop()
  {}

  libport::Finally::action_type
  Debug::push(const std::string& msg,
              const std::string& fun,
              const std::string& file,
              unsigned line)
  {
    if (disabled())
      return noop;
    message_push(msg, fun, file, line);
    return boost::bind(&Debug::pop, this);
  }

  void
  Debug::pop_category()
  {
    assert(!categories_stack_.empty());
    categories_stack_.pop_back();
  }

  void
  Debug::pop_level()
  {
    level_stack_.pop_back();
  }

  std::string
  Debug::category()
  {
    std::string res = (categories_stack_.empty()
                       ? "NONE"
                       : categories_stack_.back());
    int size = res.size();
    int largest = debug::categories_largest();
    if (size < largest)
    {
      int diff = largest - size;
      res = std::string(diff / 2, ' ')
        + res
        + std::string(diff / 2 + diff % 2, ' ');
    }

    return res;
  }

#define ATTRIBUTE(Name)                         \
                                                \
  void Debug::Name(bool v)                      \
  {                                             \
    Name##_ = v;                                \
  }                                             \
                                                \
  bool Debug::Name()                            \
  {                                             \
    return Name##_;                             \
  }                                             \

  ATTRIBUTE(locations);
  ATTRIBUTE(timestamps);

#undef ATTRIBUTE

  void Debug::abort(const std::string& msg)
  {
    GD_ERROR(msg);
    libport::abort();
  }

  namespace opts
  {

    void cb_debug_fun(const std::string& lvl)
    {
      GD_DEBUGGER->filter(lvl);
    }

    OptionValued::callback_type cb_debug(&cb_debug_fun);

    OptionValue
    debug("set the debug level in NONE, LOG (default), TRACE, DEBUG, DUMP",
          "debug", 'd', "LEVEL", &cb_debug);

  }

  ConsoleDebug::ConsoleDebug()
    : indent_(0)
  {}

  static void show_time()
  {
    time_t     now;
    struct tm  *ts;
    char       buf[80];

    now = time(NULL);
    ts = localtime(&now);
    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
    std::cerr << buf;
  }

  void
  ConsoleDebug::color(int color, bool bold)
  {
    static bool tty = isatty(STDOUT_FILENO);
    static bool force = getenv("GD_COLOR");
    boost::format format("[33;0%s;%sm");
    if (tty || force)
      std::cerr << str(format % (bold ? 1 : 0) % color);
  }

  void
  ConsoleDebug::reset()
  {
    color(0);
  }

  static Debug::colors::Color
  msg_color(Debug::types::Type type)
  {
    switch (type)
    {
      case Debug::types::info:
        return Debug::colors::white;
      case Debug::types::warn:
        return Debug::colors::yellow;
      case Debug::types::error:
        return Debug::colors::red;
    };
    GD_UNREACHABLE();
  }

  void
  ConsoleDebug::message(const std::string& msg,
                        types::Type type,
                        const std::string& fun,
                        const std::string& file,
                        unsigned line)
  {
    Debug::colors::Color c = msg_color(type);
    if (timestamps())
    {
      color(c);
      show_time();
      std::cerr << "    ";
    }
    color(colors::purple);
    std::cerr << "[" << category() << "] ";
    {
      static bool pid = getenv("GD_PID");
      if (pid)
        std::cerr << "[" << getpid() << "] ";
    }
#ifndef WIN32
    {
      static bool thread = getenv("GD_THREAD");
      if (thread)
        std::cerr << "[" << pthread_self() << "] ";
    }
#endif
    color(c);
    for (unsigned i = 0; i < indent_; ++i)
      std::cerr << " ";
    std::cerr << msg;
    if (locations())
    {
      color(colors::blue);
      std::cerr << "    (" << fun << ", " << file << ":" << line << ")";
    }
    color(colors::white);
    std::cerr << std::endl;
  }

  void
  ConsoleDebug::message_push(const std::string& msg,
                             const std::string& fun,
                             const std::string& file,
                             unsigned line)
  {
    debug(msg, types::info, fun, file, line);
    indent_ += 2;
  }

  void
  ConsoleDebug::pop()
  {
    indent_ -= 2;
  }

  std::string gd_ihexdump(const unsigned char* data, unsigned size)
  {
    std::stringstream ss;
    ss << libport::escape(std::string((const char*)data, (size_t)(size)));
    std::string res = "\"" + ss.str() + "\" ";
    bool first = true;
    for (unsigned i = 0; i < size; ++i)
    {
      if (first)
        first = false;
      else
        res += " ";
      boost::format format("0x%x");
      // This is sick, but we have to cast to int, or boost::format
      // will print the character.
      res += str(format % static_cast<unsigned int>(data[i]));
    }
    return res;
  }

#ifndef WIN32
  /*-------------.
  | Syslog debug |
  `-------------*/

  SyslogDebug::SyslogDebug(const std::string& program)
  {
    boost::format format("Opening syslog session for '%s'");

    openlog(strdup(program.c_str()), LOG_PID, LOG_DAEMON);
    syslog(LOG_INFO | LOG_DAEMON, "%s", (format % program).str().c_str());
  }

  SyslogDebug::~SyslogDebug()
  {
    syslog(LOG_INFO | LOG_DAEMON, "Closing syslog session.");
    closelog();
  }

  static
  int type_to_prio(Debug::types::Type t)
  {
    switch (t)
    {
#define CASE(In, Out)                           \
      case Debug::types::In: return Out; break
      CASE(info,  LOG_INFO);
      CASE(warn,  LOG_WARNING);
      CASE(error, LOG_ERR);
      // Pacify Gcc.
    }
    libport::abort();
#undef CASE
  }

  void
  SyslogDebug::message(const std::string& msg,
                        types::Type type,
                        const std::string& fun,
                        const std::string& file,
                        unsigned line)
  {
    std::stringstream s;
    s << "[" << category() << "] ";
    for (unsigned i = 0; i < indent_; ++i)
      s << " ";
    s << msg;
    if (locations())
      s << "    (" << fun << ", " << file << ":" << line << ")";
    int prio = type_to_prio(type) | LOG_DAEMON;
    syslog(prio, "%s", s.str().c_str());
  }

  void
  SyslogDebug::message_push(const std::string& msg,
                             const std::string& fun,
                             const std::string& file,
                             unsigned line)
  {
    debug(msg, types::info, fun, file, line);
    indent_ += 2;
  }

  void
  SyslogDebug::pop()
  {
    indent_ -= 2;
  }
#endif

  boost::function0<Debug*> make_debugger;

  typedef std::map<pthread_t, Debug*> map_type;
  // Do not make it an actual object, as it is sometimes used on
  // dtors, and the order to destruction is not specified.  Using a
  // dynamically allocated object protects us from this.
  static map_type* pdebuggers = new map_type;

  namespace debug
  {
    void clear()
    {
#if FIXME
      typedef std::pair<pthread_t, Debug*> entry;
      foreach (entry p, *pdebuggers)
      {
        delete p.second;
        p.second = 0;
      }
#endif
      delete pdebuggers;
      pdebuggers = 0;
    }
  }

  Debug* debugger()
  {
    map_type& debuggers = *pdebuggers;
    pthread_t id = pthread_self();
    if (!libport::mhas(debuggers, id))
    {
      if (make_debugger.empty())
      {
        debuggers[id] = new ConsoleDebug;
        GD_WARN("GD_INIT was not invoked, defaulting to console logs");
      }
      else
        debuggers[id] = make_debugger();
      debuggers[id]->push_category("NONE");
    }
    return debuggers[id];
  }

  GD_ADD_CATEGORY(NONE);

}

#endif
<|endoftext|>