<commit_before>// $Id$

/*
Copyright (c) 2007, Trustees of Leland Stanford Junior University
All rights reserved.

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

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

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

/*vc.cpp
 *
 *this class describes a virtual channel in a router
 *it includes buffers and virtual channel state and controls
 *
 *This class calls the routing functions
 */

#include "globals.hpp"
#include "booksim.hpp"
#include "vc.hpp"

int VC::total_cycles = 0;
VC::state_info_t VC::state_info[] = {{"idle", 0},
				     {"routing", 0},
				     {"vc_alloc", 0},
				     {"active", 0},
				     {"vc_spec", 0},
				     {"vc_spec_grant", 0}};
int VC::occupancy = 0;

VC::VC( const Configuration& config, int outputs ) :
  Module( )
{
  _Init( config, outputs );
}

VC::VC( const Configuration& config, int outputs,
	Module *parent, const string& name ) :
  Module( parent, name )
{
  _Init( config, outputs );
}

VC::~VC( )
{
}

void VC::_Init( const Configuration& config, int outputs )
{
  _state      = idle;
  _state_time = 0;

  _size = int( config.GetInt( "vc_buf_size" ) );

  _route_set = new OutputSet( outputs );

  _occupied_cnt = 0;

  _total_cycles    = 0;
  _vc_alloc_cycles = 0;
  _active_cycles   = 0;
  _idle_cycles     = 0;
  _routing_cycles     = 0;

  _pri = 0;

  _out_port = 0 ;
  _out_vc = 0 ;

  _watched = false;
}

bool VC::AddFlit( Flit *f )
{
  bool success = false;

  if ( (int)_buffer.size( ) != _size ) {
    _buffer.push( f );
    success = true;
  }

  return success;
}

Flit *VC::FrontFlit( )
{
  Flit *f;

  if ( !_buffer.empty( ) ) {
    f = _buffer.front( );
  } else {
    f = 0;
  }

  return f;
}

Flit *VC::RemoveFlit( )
{
  Flit *f;

  if ( !_buffer.empty( ) ) {
    f = _buffer.front( );
    _buffer.pop( );
  } else {
    f = 0;
  }

  return f;
}

bool VC::Empty( ) const
{
  return _buffer.empty( );
}

bool VC::Full( ) const
{
  return (int)_buffer.size( ) == _size;
}

VC::eVCState VC::GetState( ) const
{
  return _state;
}

int VC::GetStateTime( ) const
{
  return _state_time;
}

void VC::SetState( eVCState s )
{
  Flit * f = FrontFlit();

  if(f && f->watch)
    cout << "VC " << _fullname << " changed state"
	 << " at time " << GetSimTime() << endl
	 << "  Old: " << state_info[_state].name
	 << " New: " << state_info[s].name << endl;

  // do not reset state time for speculation-related pseudo state transitions
  if(!((_state == vc_spec) && (s == vc_spec_grant)) &&
     !((_state == vc_spec_grant) && (s == active)))
    _state_time = 0;

  if ( (_state == idle) && (s != idle) ) {
    if ( f ) {
      _pri = f->pri;
    }

    _occupied_cnt++;
  }

  _state = s;

}

const OutputSet *VC::GetRouteSet( ) const
{
  return _route_set;
}

void VC::SetOutput( int port, int vc )
{
  _out_port = port;
  _out_vc   = vc;
}

int VC::GetOutputPort( ) const
{
  return _out_port;
}

int VC::GetOutputVC( ) const
{
  return _out_vc;
}

int VC::GetPriority( ) const
{
  return _pri;
}

int VC::GetSize() const
{
  return (int)_buffer.size();
}

void VC::Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel )
{
  rf( router, f, in_channel, _route_set, false );
}

void VC::AdvanceTime( )
{
  _state_time++;

  _total_cycles++; total_cycles++;
  switch( _state ) {
  case idle          : _idle_cycles++; break;
  case active        : _active_cycles++; break;
  case vc_spec_grant : _active_cycles++; break;
  case vc_alloc      : _vc_alloc_cycles++; break;
  case vc_spec       : _vc_alloc_cycles++; break;
  case routing       : _routing_cycles++; break;
  }
  state_info[_state].cycles++;
  occupancy += _buffer.size();
}

// ==== Debug functions ====

void VC::SetWatch( bool watch )
{
  _watched = watch;
}

bool VC::IsWatched( ) const
{
  return _watched;
}

void VC::Display( ) const
{
//  cout << _fullname << " : "
//       << "idle " << 100.0 * (double)_idle_cycles / (double)_total_cycles << "% "
//       << "vc_alloc " << 100.0 * (double)_vc_alloc_cycles / (double)_total_cycles << "% "
//       << "active " << 100.0 * (double)_active_cycles / (double)_total_cycles << "% "
//       << endl;
  if ( _state != VC::idle ) {
    cout << _fullname << ": "
	 << " state: " << state_info[_state].name
	 << " out_port: " << _out_port
	 << " out_vc: " << _out_vc
	 << " fill: " << _buffer.size()
	 << endl ;
  }
}

void VC::DisplayStats( )
{
  cout << "VC state breakdown:" << endl;
  for(eVCState state = state_min; state <= state_max; state = eVCState(state+1)) {
    cout << "  " << state_info[state].name
	 << ": " << (float)state_info[state].cycles/(float)total_cycles << endl;
  }
}
<commit_msg>re-add occupancy counter to VC class<commit_after>// $Id$

/*
Copyright (c) 2007, Trustees of Leland Stanford Junior University
All rights reserved.

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

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

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

/*vc.cpp
 *
 *this class describes a virtual channel in a router
 *it includes buffers and virtual channel state and controls
 *
 *This class calls the routing functions
 */

#include "globals.hpp"
#include "booksim.hpp"
#include "vc.hpp"

int VC::total_cycles = 0;
VC::state_info_t VC::state_info[] = {{"idle", 0},
				     {"routing", 0},
				     {"vc_alloc", 0},
				     {"active", 0},
				     {"vc_spec", 0},
				     {"vc_spec_grant", 0}};
int VC::occupancy = 0;

VC::VC( const Configuration& config, int outputs ) :
  Module( )
{
  _Init( config, outputs );
}

VC::VC( const Configuration& config, int outputs,
	Module *parent, const string& name ) :
  Module( parent, name )
{
  _Init( config, outputs );
}

VC::~VC( )
{
}

void VC::_Init( const Configuration& config, int outputs )
{
  _state      = idle;
  _state_time = 0;

  _size = int( config.GetInt( "vc_buf_size" ) );

  _route_set = new OutputSet( outputs );

  _occupied_cnt = 0;

  _total_cycles    = 0;
  _vc_alloc_cycles = 0;
  _active_cycles   = 0;
  _idle_cycles     = 0;
  _routing_cycles     = 0;

  _pri = 0;

  _out_port = 0 ;
  _out_vc = 0 ;

  _watched = false;
}

bool VC::AddFlit( Flit *f )
{
  bool success = false;

  if ( (int)_buffer.size( ) != _size ) {
    _buffer.push( f );
    success = true;
  }

  return success;
}

Flit *VC::FrontFlit( )
{
  Flit *f;

  if ( !_buffer.empty( ) ) {
    f = _buffer.front( );
  } else {
    f = 0;
  }

  return f;
}

Flit *VC::RemoveFlit( )
{
  Flit *f;

  if ( !_buffer.empty( ) ) {
    f = _buffer.front( );
    _buffer.pop( );
  } else {
    f = 0;
  }

  return f;
}

bool VC::Empty( ) const
{
  return _buffer.empty( );
}

bool VC::Full( ) const
{
  return (int)_buffer.size( ) == _size;
}

VC::eVCState VC::GetState( ) const
{
  return _state;
}

int VC::GetStateTime( ) const
{
  return _state_time;
}

void VC::SetState( eVCState s )
{
  Flit * f = FrontFlit();

  if(f && f->watch)
    cout << "VC " << _fullname << " changed state"
	 << " at time " << GetSimTime() << endl
	 << "  Old: " << state_info[_state].name
	 << " New: " << state_info[s].name << endl;

  // do not reset state time for speculation-related pseudo state transitions
  if(!((_state == vc_spec) && (s == vc_spec_grant)) &&
     !((_state == vc_spec_grant) && (s == active)))
    _state_time = 0;

  if ( (_state == idle) && (s != idle) ) {
    if ( f ) {
      _pri = f->pri;
    }

    _occupied_cnt++;
  }

  _state = s;

}

const OutputSet *VC::GetRouteSet( ) const
{
  return _route_set;
}

void VC::SetOutput( int port, int vc )
{
  _out_port = port;
  _out_vc   = vc;
}

int VC::GetOutputPort( ) const
{
  return _out_port;
}

int VC::GetOutputVC( ) const
{
  return _out_vc;
}

int VC::GetPriority( ) const
{
  return _pri;
}

int VC::GetSize() const
{
  return (int)_buffer.size();
}

void VC::Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel )
{
  rf( router, f, in_channel, _route_set, false );
}

void VC::AdvanceTime( )
{
  _state_time++;

  _total_cycles++; total_cycles++;
  switch( _state ) {
  case idle          : _idle_cycles++; break;
  case active        : _active_cycles++; break;
  case vc_spec_grant : _active_cycles++; break;
  case vc_alloc      : _vc_alloc_cycles++; break;
  case vc_spec       : _vc_alloc_cycles++; break;
  case routing       : _routing_cycles++; break;
  }
  state_info[_state].cycles++;
  occupancy += _buffer.size();
}

// ==== Debug functions ====

void VC::SetWatch( bool watch )
{
  _watched = watch;
}

bool VC::IsWatched( ) const
{
  return _watched;
}

void VC::Display( ) const
{
//  cout << _fullname << " : "
//       << "idle " << 100.0 * (double)_idle_cycles / (double)_total_cycles << "% "
//       << "vc_alloc " << 100.0 * (double)_vc_alloc_cycles / (double)_total_cycles << "% "
//       << "active " << 100.0 * (double)_active_cycles / (double)_total_cycles << "% "
//       << endl;
  if ( _state != VC::idle ) {
    cout << _fullname << ": "
	 << " state: " << state_info[_state].name
	 << " out_port: " << _out_port
	 << " out_vc: " << _out_vc
	 << " fill: " << _buffer.size()
	 << endl ;
  }
}

void VC::DisplayStats( )
{
  cout << "VC state breakdown:" << endl;
  for(eVCState state = state_min; state <= state_max; state = eVCState(state+1)) {
    cout << "  " << state_info[state].name
	 << ": " << (float)state_info[state].cycles/(float)total_cycles << endl;
  }
  cout << "  occupancy: " << (float)occupancy/(float)total_cycles << endl;
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Alexander Sokoloff <sokoloff.a@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "lxqtmainmenu.h"
#include "lxqtmainmenuconfiguration.h"
#include <QDebug>
#include <XdgDesktopFile>
#include <XmlHelper>
#include <QSettings>
#include <QFileInfo>
#include <QAction>
#include <QTimer>
#include <QMessageBox>
#include <QEvent>
#include <QKeyEvent>
#include <LXQt/PowerManager>
#include <LXQt/ScreenSaver>
#include <lxqt-globalkeys.h>
#include <KF5/KWindowSystem/KWindowSystem>

#include <XdgIcon>
#include <XdgDesktopFile>
#include <XdgMenuWidget>

#ifdef HAVE_MENU_CACHE
#include "xdgcachedmenu.h"
#endif

#include <QPixmap>
#include <QStack>
#include <QCursor>

#define DEFAULT_SHORTCUT "Alt+F1"

/************************************************

 ************************************************/
KeyPressEventFilter::KeyPressEventFilter(QMenu *menu, QObject *parent):
    QObject(parent),
    mPreviousAction(0)
{
    mMenu = menu;
}

/************************************************

 ************************************************/
bool KeyPressEventFilter::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        QMenu* menu=0;

        if (obj == mMenu)
        {
            menu = mMenu;
        }
        else {
            foreach (QAction* action, mMenu->actions())
            {
                if (action->menu() && action->menu() == obj)
                    {
                        menu = action->menu();
                        break;
                    }
                }
            }

        if (menu == 0)
            return QObject::eventFilter(obj, event);

        QAction* currentAction = 0;
        if (menu->actions().indexOf(mPreviousAction) > -1) {
            for (int i=menu->actions().indexOf(mPreviousAction)+1; i<menu->actions().count(); i++)
            {
                if (menu->actions().at(i)->text().startsWith(QChar(keyEvent->key()), Qt::CaseInsensitive))
                {
                    currentAction = menu->actions().at(i);
                    break;
                }
            }
        }
        if (!currentAction)
        {
            foreach (QAction* action, menu->actions())
            {
                if (action->text().startsWith(QChar(keyEvent->key()), Qt::CaseInsensitive))
                {
                    currentAction = action;
                    break;
                }
            }
        }

        if (currentAction)
        {
            mPreviousAction = currentAction;
            menu->setActiveAction(currentAction);
            if (currentAction->menu())
            {
                currentAction->menu()->hide();
            }
        }
    }

    return QObject::eventFilter(obj, event);
}

/************************************************

 ************************************************/
LxQtMainMenu::LxQtMainMenu(const ILxQtPanelPluginStartupInfo &startupInfo):
    QObject(),
    ILxQtPanelPlugin(startupInfo),
    mMenu(0),
    mShortcut(0),
    mLockCascadeChanges(false)
{
#ifdef HAVE_MENU_CACHE
    mMenuCache = NULL;
    mMenuCacheNotify = 0;
#endif

    mButton.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    mButton.installEventFilter(this);

    connect(&mButton, SIGNAL(clicked()), this, SLOT(showMenu()));

    settingsChanged();

    connect(mShortcut, SIGNAL(activated()), this, SLOT(showHideMenu()));
    connect(mShortcut, SIGNAL(shortcutChanged(QString,QString)), this, SLOT(shortcutChanged(QString,QString)));
}

/************************************************

 ************************************************/
LxQtMainMenu::~LxQtMainMenu()
{
    mButton.removeEventFilter(this);
#ifdef HAVE_MENU_CACHE
    if(mMenuCache)
    {
        menu_cache_remove_reload_notify(mMenuCache, mMenuCacheNotify);
        menu_cache_unref(mMenuCache);
    }
#endif
}

/************************************************

 ************************************************/
void LxQtMainMenu::showHideMenu()
{
    if (mMenu && mMenu->isVisible())
        mMenu->hide();
    else
        showMenu();
}

/************************************************

 ************************************************/
void LxQtMainMenu::shortcutChanged(const QString &/*oldShortcut*/, const QString &newShortcut)
{
    if (!newShortcut.isEmpty())
    {
        mLockCascadeChanges = true;

        settings()->setValue("dialog/shortcut", newShortcut);
        settings()->sync();

        mLockCascadeChanges = false;
    }
}

/************************************************

 ************************************************/
void LxQtMainMenu::showMenu()
{
    if (!mMenu)
        return;

    int x=0, y=0;

    switch (panel()->position())
    {
        case ILxQtPanel::PositionTop:
            x = mButton.mapToGlobal(QPoint(0, 0)).x();
            y = panel()->globalGometry().bottom();
            break;

        case ILxQtPanel::PositionBottom:
            x = mButton.mapToGlobal(QPoint(0, 0)).x();
            y = panel()->globalGometry().top() - mMenu->sizeHint().height();
            break;

        case ILxQtPanel::PositionLeft:
            x = panel()->globalGometry().right();
            y = mButton.mapToGlobal(QPoint(0, 0)).y();
            break;

        case ILxQtPanel::PositionRight:
            x = panel()->globalGometry().left() - mMenu->sizeHint().width();
            y = mButton.mapToGlobal(QPoint(0, 0)).y();
            break;
    }

    // Just using Qt`s activateWindow() won't work on some WMs like Kwin.
    // Solution is to execute menu 1ms later using timer
    mButton.activateWindow();
    mMenu->exec(QPoint(x, y));
}

#ifdef HAVE_MENU_CACHE
// static
void LxQtMainMenu::menuCacheReloadNotify(MenuCache* cache, gpointer user_data)
{
    reinterpret_cast<LxQtMainMenu*>(user_data)->buildMenu();
}
#endif

/************************************************

 ************************************************/
void LxQtMainMenu::settingsChanged()
{
    if (mLockCascadeChanges)
        return;

    if (settings()->value("showText", false).toBool())
    {
        mButton.setText(settings()->value("text", "Start").toString());
        mButton.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    }
    else
    {
        mButton.setText("");
        mButton.setToolButtonStyle(Qt::ToolButtonIconOnly);
    }

    mLogDir = settings()->value("log_dir", "").toString();

    QString mMenuFile = settings()->value("menu_file", "").toString();
    if (mMenuFile.isEmpty())
        mMenuFile = XdgMenu::getMenuFileName();

#ifdef HAVE_MENU_CACHE
    menu_cache_init(0);
    if(mMenuCache)
    {
        menu_cache_remove_reload_notify(mMenuCache, mMenuCacheNotify);
        menu_cache_unref(mMenuCache);
    }
    mMenuCache = menu_cache_lookup(mMenuFile.toLocal8Bit());
    mMenuCacheNotify = menu_cache_add_reload_notify(mMenuCache, (MenuCacheReloadNotify)menuCacheReloadNotify, this);
#else
    mXdgMenu.setEnvironments(QStringList() << "X-LXQT" << "LxQt");
    mXdgMenu.setLogDir(mLogDir);

    bool res = mXdgMenu.read(mMenuFile);
    connect(&mXdgMenu, SIGNAL(changed()), this, SLOT(buildMenu()));
    if (res)
    {
        QTimer::singleShot(1000, this, SLOT(buildMenu()));
    }
    else
    {
        QMessageBox::warning(0, "Parse error", mXdgMenu.errorString());
        return;
    }
#endif

    QString shortcut = settings()->value("shortcut", DEFAULT_SHORTCUT).toString();
    if (shortcut.isEmpty())
        shortcut = DEFAULT_SHORTCUT;

    if (!mShortcut)
        mShortcut = GlobalKeyShortcut::Client::instance()->addAction(shortcut, QString("/panel/%1/show_hide").arg(settings()->group()), tr("Show/hide main menu"), this);
    else if (mShortcut->shortcut() != shortcut)
    {
        mShortcut->changeShortcut(shortcut);
    }

    realign();
}

/************************************************

 ************************************************/
void LxQtMainMenu::buildMenu()
{
#ifdef HAVE_MENU_CACHE
    XdgCachedMenu* menu = new XdgCachedMenu(mMenuCache, &mButton);
#else
    XdgMenuWidget *menu = new XdgMenuWidget(mXdgMenu, "", &mButton);
#endif
    menu->setObjectName("TopLevelMainMenu");
    menu->setStyle(&mTopMenuStyle);

    menu->addSeparator();

    mEventFilter = new KeyPressEventFilter(menu, this);
    foreach (QAction* action, menu->actions())
    {
        if (action->menu())
            action->menu()->installEventFilter(mEventFilter);
    }

    menu->installEventFilter(mEventFilter);

    QMenu *oldMenu = mMenu;
    mMenu = menu;
    delete oldMenu;

    if(settings()->value("customFont", false).toBool())
    {
        QFont menuFont = mMenu->font();
        menuFont.setPointSize(settings()->value("customFontSize").toInt());

        mMenu->setFont(menuFont);
        QList<QMenu*> subMenuList = mMenu->findChildren<QMenu*>();
        foreach (QMenu* subMenu, subMenuList)
        {
            subMenu->setFont(menuFont);
        }
    }
}

/************************************************

 ************************************************/
QDialog *LxQtMainMenu::configureDialog()
{
    return new LxQtMainMenuConfiguration(*settings(), DEFAULT_SHORTCUT);
}
/************************************************

 ************************************************/
bool LxQtMainMenu::eventFilter(QObject *obj, QEvent *event)
{
    if(obj == &mButton)
    {
        // the application is given a new QStyle
        if(event->type() == QEvent::StyleChange)
        {
            // reset proxy style for the menus so they can apply the new styles
            mTopMenuStyle.setBaseStyle(NULL);
            mMenuStyle.setBaseStyle(NULL);
        }
    }
    return false;
}

#undef DEFAULT_SHORTCUT
<commit_msg>Fix mainmenu's focus<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Alexander Sokoloff <sokoloff.a@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "lxqtmainmenu.h"
#include "lxqtmainmenuconfiguration.h"
#include <QDebug>
#include <XdgDesktopFile>
#include <XmlHelper>
#include <QSettings>
#include <QFileInfo>
#include <QAction>
#include <QTimer>
#include <QMessageBox>
#include <QEvent>
#include <QKeyEvent>
#include <LXQt/PowerManager>
#include <LXQt/ScreenSaver>
#include <lxqt-globalkeys.h>
#include <KF5/KWindowSystem/KWindowSystem>

#include <XdgIcon>
#include <XdgDesktopFile>
#include <XdgMenuWidget>

#ifdef HAVE_MENU_CACHE
#include "xdgcachedmenu.h"
#endif

#include <QPixmap>
#include <QStack>
#include <QCursor>

#define DEFAULT_SHORTCUT "Alt+F1"

/************************************************

 ************************************************/
KeyPressEventFilter::KeyPressEventFilter(QMenu *menu, QObject *parent):
    QObject(parent),
    mPreviousAction(0)
{
    mMenu = menu;
}

/************************************************

 ************************************************/
bool KeyPressEventFilter::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

        QMenu* menu=0;

        if (obj == mMenu)
        {
            menu = mMenu;
        }
        else {
            foreach (QAction* action, mMenu->actions())
            {
                if (action->menu() && action->menu() == obj)
                    {
                        menu = action->menu();
                        break;
                    }
                }
            }

        if (menu == 0)
            return QObject::eventFilter(obj, event);

        QAction* currentAction = 0;
        if (menu->actions().indexOf(mPreviousAction) > -1) {
            for (int i=menu->actions().indexOf(mPreviousAction)+1; i<menu->actions().count(); i++)
            {
                if (menu->actions().at(i)->text().startsWith(QChar(keyEvent->key()), Qt::CaseInsensitive))
                {
                    currentAction = menu->actions().at(i);
                    break;
                }
            }
        }
        if (!currentAction)
        {
            foreach (QAction* action, menu->actions())
            {
                if (action->text().startsWith(QChar(keyEvent->key()), Qt::CaseInsensitive))
                {
                    currentAction = action;
                    break;
                }
            }
        }

        if (currentAction)
        {
            mPreviousAction = currentAction;
            menu->setActiveAction(currentAction);
            if (currentAction->menu())
            {
                currentAction->menu()->hide();
            }
        }
    }

    return QObject::eventFilter(obj, event);
}

/************************************************

 ************************************************/
LxQtMainMenu::LxQtMainMenu(const ILxQtPanelPluginStartupInfo &startupInfo):
    QObject(),
    ILxQtPanelPlugin(startupInfo),
    mMenu(0),
    mShortcut(0),
    mLockCascadeChanges(false)
{
#ifdef HAVE_MENU_CACHE
    mMenuCache = NULL;
    mMenuCacheNotify = 0;
#endif

    mButton.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    mButton.installEventFilter(this);

    settingsChanged();

    connect(mShortcut, SIGNAL(activated()), this, SLOT(showHideMenu()));
    connect(mShortcut, SIGNAL(shortcutChanged(QString,QString)), this, SLOT(shortcutChanged(QString,QString)));
}

/************************************************

 ************************************************/
LxQtMainMenu::~LxQtMainMenu()
{
    mButton.removeEventFilter(this);
#ifdef HAVE_MENU_CACHE
    if(mMenuCache)
    {
        menu_cache_remove_reload_notify(mMenuCache, mMenuCacheNotify);
        menu_cache_unref(mMenuCache);
    }
#endif
}

/************************************************

 ************************************************/
void LxQtMainMenu::showHideMenu()
{
    if (mMenu && mMenu->isVisible())
        mMenu->hide();
    else
        showMenu();
}

/************************************************

 ************************************************/
void LxQtMainMenu::shortcutChanged(const QString &/*oldShortcut*/, const QString &newShortcut)
{
    if (!newShortcut.isEmpty())
    {
        mLockCascadeChanges = true;

        settings()->setValue("dialog/shortcut", newShortcut);
        settings()->sync();

        mLockCascadeChanges = false;
    }
}

/************************************************

 ************************************************/
void LxQtMainMenu::showMenu()
{
    if (!mMenu)
        return;

    int x=0, y=0;

    switch (panel()->position())
    {
        case ILxQtPanel::PositionTop:
            x = mButton.mapToGlobal(QPoint(0, 0)).x();
            y = panel()->globalGometry().bottom();
            break;

        case ILxQtPanel::PositionBottom:
            x = mButton.mapToGlobal(QPoint(0, 0)).x();
            y = panel()->globalGometry().top() - mMenu->sizeHint().height();
            break;

        case ILxQtPanel::PositionLeft:
            x = panel()->globalGometry().right();
            y = mButton.mapToGlobal(QPoint(0, 0)).y();
            break;

        case ILxQtPanel::PositionRight:
            x = panel()->globalGometry().left() - mMenu->sizeHint().width();
            y = mButton.mapToGlobal(QPoint(0, 0)).y();
            break;
    }

    mButton.activateWindow();
    mMenu->popup(QPoint(x, y));
    KWindowSystem::forceActiveWindow(mMenu->winId());
    mMenu->setFocus(Qt::ActiveWindowFocusReason);
}

#ifdef HAVE_MENU_CACHE
// static
void LxQtMainMenu::menuCacheReloadNotify(MenuCache* cache, gpointer user_data)
{
    reinterpret_cast<LxQtMainMenu*>(user_data)->buildMenu();
}
#endif

/************************************************

 ************************************************/
void LxQtMainMenu::settingsChanged()
{
    if (mLockCascadeChanges)
        return;

    if (settings()->value("showText", false).toBool())
    {
        mButton.setText(settings()->value("text", "Start").toString());
        mButton.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    }
    else
    {
        mButton.setText("");
        mButton.setToolButtonStyle(Qt::ToolButtonIconOnly);
    }

    mLogDir = settings()->value("log_dir", "").toString();

    QString mMenuFile = settings()->value("menu_file", "").toString();
    if (mMenuFile.isEmpty())
        mMenuFile = XdgMenu::getMenuFileName();

#ifdef HAVE_MENU_CACHE
    menu_cache_init(0);
    if(mMenuCache)
    {
        menu_cache_remove_reload_notify(mMenuCache, mMenuCacheNotify);
        menu_cache_unref(mMenuCache);
    }
    mMenuCache = menu_cache_lookup(mMenuFile.toLocal8Bit());
    mMenuCacheNotify = menu_cache_add_reload_notify(mMenuCache, (MenuCacheReloadNotify)menuCacheReloadNotify, this);
#else
    mXdgMenu.setEnvironments(QStringList() << "X-LXQT" << "LxQt");
    mXdgMenu.setLogDir(mLogDir);

    bool res = mXdgMenu.read(mMenuFile);
    connect(&mXdgMenu, SIGNAL(changed()), this, SLOT(buildMenu()));
    if (res)
    {
        QTimer::singleShot(1000, this, SLOT(buildMenu()));
    }
    else
    {
        QMessageBox::warning(0, "Parse error", mXdgMenu.errorString());
        return;
    }
#endif

    QString shortcut = settings()->value("shortcut", DEFAULT_SHORTCUT).toString();
    if (shortcut.isEmpty())
        shortcut = DEFAULT_SHORTCUT;

    if (!mShortcut)
        mShortcut = GlobalKeyShortcut::Client::instance()->addAction(shortcut, QString("/panel/%1/show_hide").arg(settings()->group()), tr("Show/hide main menu"), this);
    else if (mShortcut->shortcut() != shortcut)
    {
        mShortcut->changeShortcut(shortcut);
    }

    realign();
}

/************************************************

 ************************************************/
void LxQtMainMenu::buildMenu()
{
#ifdef HAVE_MENU_CACHE
    XdgCachedMenu* menu = new XdgCachedMenu(mMenuCache, &mButton);
#else
    XdgMenuWidget *menu = new XdgMenuWidget(mXdgMenu, "", &mButton);
#endif

    // needed for menu's focus and for making invisible on taskbar
    menu->setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
    menu->setAttribute(Qt::WA_TranslucentBackground);
    KWindowSystem::setType(menu->winId(), NET::Menu);

    menu->setObjectName("TopLevelMainMenu");
    menu->setStyle(&mTopMenuStyle);

    menu->addSeparator();

    mEventFilter = new KeyPressEventFilter(menu, this);
    foreach (QAction* action, menu->actions())
    {
        if (action->menu())
            action->menu()->installEventFilter(mEventFilter);
    }

    menu->installEventFilter(mEventFilter);

    QMenu *oldMenu = mMenu;
    mMenu = menu;
    delete oldMenu;

    if(settings()->value("customFont", false).toBool())
    {
        QFont menuFont = mMenu->font();
        menuFont.setPointSize(settings()->value("customFontSize").toInt());

        mMenu->setFont(menuFont);
        QList<QMenu*> subMenuList = mMenu->findChildren<QMenu*>();
        foreach (QMenu* subMenu, subMenuList)
        {
            subMenu->setFont(menuFont);
        }
    }
}

/************************************************

 ************************************************/
QDialog *LxQtMainMenu::configureDialog()
{
    return new LxQtMainMenuConfiguration(*settings(), DEFAULT_SHORTCUT);
}
/************************************************

 ************************************************/
bool LxQtMainMenu::eventFilter(QObject *obj, QEvent *event)
{
    if(obj == &mButton)
    {
        // the application is given a new QStyle
        if(event->type() == QEvent::StyleChange)
        {
            // reset proxy style for the menus so they can apply the new styles
            mTopMenuStyle.setBaseStyle(NULL);
            mMenuStyle.setBaseStyle(NULL);
            return true;
        }

        if (event->type() == QEvent::MouseButtonRelease)
        {
            showHideMenu();
            return true;
        }
    }

    if (obj == mMenu)
    {
        if (event->type() == QEvent::FocusOut)
        {
            showHideMenu();
            return true;
        }
    }

    return false;
}

#undef DEFAULT_SHORTCUT
<|endoftext|>


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

#include "chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h"

#include <dwmapi.h>

#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_frame_common_win.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/theme_image_mapper.h"
#include "grit/theme_resources.h"
#include "ui/base/theme_provider.h"
#include "ui/views/controls/menu/native_menu_win.h"

#pragma comment(lib, "dwmapi.lib")

namespace {

const int kClientEdgeThickness = 3;
// We need to offset the DWMFrame into the toolbar so that the blackness
// doesn't show up on our rounded corners.
const int kDWMFrameTopOffset = 3;

// DesktopThemeProvider maps resource ids using MapThemeImage(). This is
// necessary for BrowserDesktopRootWindowHostWin so that it uses the windows
// theme images rather than the ash theme images.
class DesktopThemeProvider : public ui::ThemeProvider {
 public:
  explicit DesktopThemeProvider(ui::ThemeProvider* delegate)
      : delegate_(delegate) {
  }

  virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE {
    return delegate_->GetImageSkiaNamed(
        chrome::MapThemeImage(chrome::HOST_DESKTOP_TYPE_NATIVE, id));
  }

  virtual SkColor GetColor(int id) const OVERRIDE {
    return delegate_->GetColor(id);
  }
  virtual bool GetDisplayProperty(int id, int* result) const OVERRIDE {
    return delegate_->GetDisplayProperty(id, result);
  }
  virtual bool ShouldUseNativeFrame() const OVERRIDE {
    return delegate_->ShouldUseNativeFrame();
  }
  virtual bool HasCustomImage(int id) const OVERRIDE {
    return delegate_->HasCustomImage(chrome::MapThemeImage(
                                         chrome::HOST_DESKTOP_TYPE_NATIVE, id));
  }
  virtual base::RefCountedMemory* GetRawData(
      int id,
      ui::ScaleFactor scale_factor) const OVERRIDE {
    return delegate_->GetRawData(id, scale_factor);
  }

 private:
  ui::ThemeProvider* delegate_;

  DISALLOW_COPY_AND_ASSIGN(DesktopThemeProvider);
};

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, public:

BrowserDesktopRootWindowHostWin::BrowserDesktopRootWindowHostWin(
    views::internal::NativeWidgetDelegate* native_widget_delegate,
    views::DesktopNativeWidgetAura* desktop_native_widget_aura,
    const gfx::Rect& initial_bounds,
    BrowserView* browser_view,
    BrowserFrame* browser_frame)
    : DesktopRootWindowHostWin(native_widget_delegate,
                               desktop_native_widget_aura,
                               initial_bounds),
      browser_view_(browser_view),
      browser_frame_(browser_frame) {
  scoped_ptr<ui::ThemeProvider> theme_provider(
      new DesktopThemeProvider(ThemeServiceFactory::GetForProfile(
                                   browser_view->browser()->profile())));
  browser_frame->SetThemeProvider(theme_provider.Pass());
}

BrowserDesktopRootWindowHostWin::~BrowserDesktopRootWindowHostWin() {
}

views::NativeMenuWin* BrowserDesktopRootWindowHostWin::GetSystemMenu() {
  if (!system_menu_.get()) {
    SystemMenuInsertionDelegateWin insertion_delegate;
    system_menu_.reset(
        new views::NativeMenuWin(browser_frame_->GetSystemMenuModel(),
                                 GetHWND()));
    system_menu_->Rebuild(&insertion_delegate);
  }
  return system_menu_.get();
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, BrowserDesktopRootWindowHost implementation:

views::DesktopRootWindowHost*
    BrowserDesktopRootWindowHostWin::AsDesktopRootWindowHost() {
  return this;
}

int BrowserDesktopRootWindowHostWin::GetMinimizeButtonOffset() const {
  return minimize_button_metrics_.GetMinimizeButtonOffsetX();
}

bool BrowserDesktopRootWindowHostWin::UsesNativeSystemMenu() const {
  return true;
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, views::DesktopRootWindowHostWin overrides:

int BrowserDesktopRootWindowHostWin::GetInitialShowState() const {
  STARTUPINFO si = {0};
  si.cb = sizeof(si);
  si.dwFlags = STARTF_USESHOWWINDOW;
  GetStartupInfo(&si);
  return si.wShowWindow;
}

bool BrowserDesktopRootWindowHostWin::GetClientAreaInsets(
    gfx::Insets* insets) const {
  // Use the default client insets for an opaque frame or a glass popup/app
  // frame.
  if (!GetWidget()->ShouldUseNativeFrame() ||
      !browser_view_->IsBrowserTypeNormal()) {
    return false;
  }

  int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
  // In fullscreen mode, we have no frame. In restored mode, we draw our own
  // client edge over part of the default frame.
  if (GetWidget()->IsFullscreen())
    border_thickness = 0;
  else if (!IsMaximized())
    border_thickness -= kClientEdgeThickness;
  insets->Set(0, border_thickness, border_thickness, border_thickness);
  return true;
}

void BrowserDesktopRootWindowHostWin::HandleFrameChanged() {
  // We need to update the glass region on or off before the base class adjusts
  // the window region.
  UpdateDWMFrame();
  DesktopRootWindowHostWin::HandleFrameChanged();
}

bool BrowserDesktopRootWindowHostWin::PreHandleMSG(UINT message,
                                                   WPARAM w_param,
                                                   LPARAM l_param,
                                                   LRESULT* result) {
  switch (message) {
    case WM_ACTIVATE:
      if (LOWORD(w_param) != WA_INACTIVE)
        minimize_button_metrics_.OnHWNDActivated();
      return false;
    case WM_ENDSESSION:
      browser::SessionEnding();
      return true;
    case WM_INITMENUPOPUP:
      GetSystemMenu()->UpdateStates();
      return true;
  }
  return DesktopRootWindowHostWin::PreHandleMSG(
      message, w_param, l_param, result);
}

void BrowserDesktopRootWindowHostWin::PostHandleMSG(UINT message,
                                                    WPARAM w_param,
                                                    LPARAM l_param) {
  switch (message) {
  case WM_CREATE:
    minimize_button_metrics_.Init(GetHWND());
    break;
  case WM_WINDOWPOSCHANGED:
    UpdateDWMFrame();

    // Windows lies to us about the position of the minimize button before a
    // window is visible.  We use this position to place the OTR avatar in RTL
    // mode, so when the window is shown, we need to re-layout and schedule a
    // paint for the non-client frame view so that the icon top has the correct
    // position when the window becomes visible.  This fixes bugs where the icon
    // appears to overlay the minimize button.
    // Note that we will call Layout every time SetWindowPos is called with
    // SWP_SHOWWINDOW, however callers typically are careful about not
    // specifying this flag unless necessary to avoid flicker.
    // This may be invoked during creation on XP and before the non_client_view
    // has been created.
    WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(l_param);
    if (window_pos->flags & SWP_SHOWWINDOW && GetWidget()->non_client_view()) {
      GetWidget()->non_client_view()->Layout();
      GetWidget()->non_client_view()->SchedulePaint();
    }
    break;
  }
}

bool BrowserDesktopRootWindowHostWin::IsUsingCustomFrame() const {
  // App panel windows draw their own frame.
  if (browser_view_->IsPanel())
    return true;

  // We don't theme popup or app windows, so regardless of whether or not a
  // theme is active for normal browser windows, we don't want to use the custom
  // frame for popups/apps.
  if (!browser_view_->IsBrowserTypeNormal() &&
      !DesktopRootWindowHostWin::IsUsingCustomFrame()) {
    return false;
  }

  // Otherwise, we use the native frame when we're told we should by the theme
  // provider (e.g. no custom theme is active).
  return !GetWidget()->GetThemeProvider()->ShouldUseNativeFrame();
}

bool BrowserDesktopRootWindowHostWin::ShouldUseNativeFrame() {
  if (!views::DesktopRootWindowHostWin::ShouldUseNativeFrame())
    return false;
  return chrome::ShouldUseNativeFrame(browser_view_,
                                      GetWidget()->GetThemeProvider());
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, private:

void BrowserDesktopRootWindowHostWin::UpdateDWMFrame() {
  // For "normal" windows on Aero, we always need to reset the glass area
  // correctly, even if we're not currently showing the native frame (e.g.
  // because a theme is showing), so we explicitly check for that case rather
  // than checking browser_frame_->ShouldUseNativeFrame() here.  Using that here
  // would mean we wouldn't reset the glass area to zero when moving from the
  // native frame to an opaque frame, leading to graphical glitches behind the
  // opaque frame.  Instead, we use that function below to tell us whether the
  // frame is currently native or opaque.
  if (!GetWidget()->client_view() || !browser_view_->IsBrowserTypeNormal() ||
      !DesktopRootWindowHostWin::ShouldUseNativeFrame())
    return;

  MARGINS margins = { 0 };

  // If the opaque frame is visible, we use the default (zero) margins.
  // Otherwise, we need to figure out how to extend the glass in.
  if (GetWidget()->ShouldUseNativeFrame()) {
    // In fullscreen mode, we don't extend glass into the client area at all,
    // because the GDI-drawn text in the web content composited over it will
    // become semi-transparent over any glass area.
    if (!IsMaximized() && !GetWidget()->IsFullscreen()) {
      margins.cxLeftWidth = kClientEdgeThickness + 1;
      margins.cxRightWidth = kClientEdgeThickness + 1;
      margins.cyBottomHeight = kClientEdgeThickness + 1;
      margins.cyTopHeight = kClientEdgeThickness + 1;
    }
    // In maximized mode, we only have a titlebar strip of glass, no side/bottom
    // borders.
    if (!browser_view_->IsFullscreen()) {
      gfx::Rect tabstrip_bounds(
          browser_frame_->GetBoundsForTabStrip(browser_view_->tabstrip()));
      margins.cyTopHeight = tabstrip_bounds.bottom() + kDWMFrameTopOffset;
    }
  }

  DwmExtendFrameIntoClientArea(GetHWND(), &margins);
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHost, public:

// static
BrowserDesktopRootWindowHost*
    BrowserDesktopRootWindowHost::CreateBrowserDesktopRootWindowHost(
        views::internal::NativeWidgetDelegate* native_widget_delegate,
        views::DesktopNativeWidgetAura* desktop_native_widget_aura,
        const gfx::Rect& initial_bounds,
        BrowserView* browser_view,
        BrowserFrame* browser_frame) {
  return new BrowserDesktopRootWindowHostWin(native_widget_delegate,
                                             desktop_native_widget_aura,
                                             initial_bounds,
                                             browser_view,
                                             browser_frame);
}
<commit_msg>Fix an AURA browser crash which occurs at times when the browser window is being closed.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/frame/browser_desktop_root_window_host_win.h"

#include <dwmapi.h>

#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_frame_common_win.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/system_menu_insertion_delegate_win.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/theme_image_mapper.h"
#include "grit/theme_resources.h"
#include "ui/base/theme_provider.h"
#include "ui/views/controls/menu/native_menu_win.h"

#pragma comment(lib, "dwmapi.lib")

namespace {

const int kClientEdgeThickness = 3;
// We need to offset the DWMFrame into the toolbar so that the blackness
// doesn't show up on our rounded corners.
const int kDWMFrameTopOffset = 3;

// DesktopThemeProvider maps resource ids using MapThemeImage(). This is
// necessary for BrowserDesktopRootWindowHostWin so that it uses the windows
// theme images rather than the ash theme images.
class DesktopThemeProvider : public ui::ThemeProvider {
 public:
  explicit DesktopThemeProvider(ui::ThemeProvider* delegate)
      : delegate_(delegate) {
  }

  virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE {
    return delegate_->GetImageSkiaNamed(
        chrome::MapThemeImage(chrome::HOST_DESKTOP_TYPE_NATIVE, id));
  }

  virtual SkColor GetColor(int id) const OVERRIDE {
    return delegate_->GetColor(id);
  }
  virtual bool GetDisplayProperty(int id, int* result) const OVERRIDE {
    return delegate_->GetDisplayProperty(id, result);
  }
  virtual bool ShouldUseNativeFrame() const OVERRIDE {
    return delegate_->ShouldUseNativeFrame();
  }
  virtual bool HasCustomImage(int id) const OVERRIDE {
    return delegate_->HasCustomImage(chrome::MapThemeImage(
                                         chrome::HOST_DESKTOP_TYPE_NATIVE, id));
  }
  virtual base::RefCountedMemory* GetRawData(
      int id,
      ui::ScaleFactor scale_factor) const OVERRIDE {
    return delegate_->GetRawData(id, scale_factor);
  }

 private:
  ui::ThemeProvider* delegate_;

  DISALLOW_COPY_AND_ASSIGN(DesktopThemeProvider);
};

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, public:

BrowserDesktopRootWindowHostWin::BrowserDesktopRootWindowHostWin(
    views::internal::NativeWidgetDelegate* native_widget_delegate,
    views::DesktopNativeWidgetAura* desktop_native_widget_aura,
    const gfx::Rect& initial_bounds,
    BrowserView* browser_view,
    BrowserFrame* browser_frame)
    : DesktopRootWindowHostWin(native_widget_delegate,
                               desktop_native_widget_aura,
                               initial_bounds),
      browser_view_(browser_view),
      browser_frame_(browser_frame) {
  scoped_ptr<ui::ThemeProvider> theme_provider(
      new DesktopThemeProvider(ThemeServiceFactory::GetForProfile(
                                   browser_view->browser()->profile())));
  browser_frame->SetThemeProvider(theme_provider.Pass());
}

BrowserDesktopRootWindowHostWin::~BrowserDesktopRootWindowHostWin() {
}

views::NativeMenuWin* BrowserDesktopRootWindowHostWin::GetSystemMenu() {
  if (!system_menu_.get()) {
    SystemMenuInsertionDelegateWin insertion_delegate;
    system_menu_.reset(
        new views::NativeMenuWin(browser_frame_->GetSystemMenuModel(),
                                 GetHWND()));
    system_menu_->Rebuild(&insertion_delegate);
  }
  return system_menu_.get();
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, BrowserDesktopRootWindowHost implementation:

views::DesktopRootWindowHost*
    BrowserDesktopRootWindowHostWin::AsDesktopRootWindowHost() {
  return this;
}

int BrowserDesktopRootWindowHostWin::GetMinimizeButtonOffset() const {
  return minimize_button_metrics_.GetMinimizeButtonOffsetX();
}

bool BrowserDesktopRootWindowHostWin::UsesNativeSystemMenu() const {
  return true;
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, views::DesktopRootWindowHostWin overrides:

int BrowserDesktopRootWindowHostWin::GetInitialShowState() const {
  STARTUPINFO si = {0};
  si.cb = sizeof(si);
  si.dwFlags = STARTF_USESHOWWINDOW;
  GetStartupInfo(&si);
  return si.wShowWindow;
}

bool BrowserDesktopRootWindowHostWin::GetClientAreaInsets(
    gfx::Insets* insets) const {
  // Use the default client insets for an opaque frame or a glass popup/app
  // frame.
  if (!GetWidget()->ShouldUseNativeFrame() ||
      !browser_view_->IsBrowserTypeNormal()) {
    return false;
  }

  int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
  // In fullscreen mode, we have no frame. In restored mode, we draw our own
  // client edge over part of the default frame.
  if (GetWidget()->IsFullscreen())
    border_thickness = 0;
  else if (!IsMaximized())
    border_thickness -= kClientEdgeThickness;
  insets->Set(0, border_thickness, border_thickness, border_thickness);
  return true;
}

void BrowserDesktopRootWindowHostWin::HandleFrameChanged() {
  // We need to update the glass region on or off before the base class adjusts
  // the window region.
  UpdateDWMFrame();
  DesktopRootWindowHostWin::HandleFrameChanged();
}

bool BrowserDesktopRootWindowHostWin::PreHandleMSG(UINT message,
                                                   WPARAM w_param,
                                                   LPARAM l_param,
                                                   LRESULT* result) {
  switch (message) {
    case WM_ACTIVATE:
      if (LOWORD(w_param) != WA_INACTIVE)
        minimize_button_metrics_.OnHWNDActivated();
      return false;
    case WM_ENDSESSION:
      browser::SessionEnding();
      return true;
    case WM_INITMENUPOPUP:
      GetSystemMenu()->UpdateStates();
      return true;
  }
  return DesktopRootWindowHostWin::PreHandleMSG(
      message, w_param, l_param, result);
}

void BrowserDesktopRootWindowHostWin::PostHandleMSG(UINT message,
                                                    WPARAM w_param,
                                                    LPARAM l_param) {
  switch (message) {
  case WM_CREATE:
    minimize_button_metrics_.Init(GetHWND());
    break;
  case WM_WINDOWPOSCHANGED:
    UpdateDWMFrame();

    // Windows lies to us about the position of the minimize button before a
    // window is visible.  We use this position to place the OTR avatar in RTL
    // mode, so when the window is shown, we need to re-layout and schedule a
    // paint for the non-client frame view so that the icon top has the correct
    // position when the window becomes visible.  This fixes bugs where the icon
    // appears to overlay the minimize button.
    // Note that we will call Layout every time SetWindowPos is called with
    // SWP_SHOWWINDOW, however callers typically are careful about not
    // specifying this flag unless necessary to avoid flicker.
    // This may be invoked during creation on XP and before the non_client_view
    // has been created.
    WINDOWPOS* window_pos = reinterpret_cast<WINDOWPOS*>(l_param);
    if (window_pos->flags & SWP_SHOWWINDOW && GetWidget()->non_client_view()) {
      GetWidget()->non_client_view()->Layout();
      GetWidget()->non_client_view()->SchedulePaint();
    }
    break;
  }
}

bool BrowserDesktopRootWindowHostWin::IsUsingCustomFrame() const {
  // App panel windows draw their own frame.
  if (browser_view_->IsPanel())
    return true;

  // We don't theme popup or app windows, so regardless of whether or not a
  // theme is active for normal browser windows, we don't want to use the custom
  // frame for popups/apps.
  if (!browser_view_->IsBrowserTypeNormal() &&
      !DesktopRootWindowHostWin::IsUsingCustomFrame()) {
    return false;
  }

  // Otherwise, we use the native frame when we're told we should by the theme
  // provider (e.g. no custom theme is active).
  return !GetWidget()->GetThemeProvider()->ShouldUseNativeFrame();
}

bool BrowserDesktopRootWindowHostWin::ShouldUseNativeFrame() {
  if (!views::DesktopRootWindowHostWin::ShouldUseNativeFrame())
    return false;
  // This function can get called when the Browser window is closed i.e. in the
  // context of the BrowserView destructor.
  if (!browser_view_->browser())
    return false;
  return chrome::ShouldUseNativeFrame(browser_view_,
                                      GetWidget()->GetThemeProvider());
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHostWin, private:

void BrowserDesktopRootWindowHostWin::UpdateDWMFrame() {
  // For "normal" windows on Aero, we always need to reset the glass area
  // correctly, even if we're not currently showing the native frame (e.g.
  // because a theme is showing), so we explicitly check for that case rather
  // than checking browser_frame_->ShouldUseNativeFrame() here.  Using that here
  // would mean we wouldn't reset the glass area to zero when moving from the
  // native frame to an opaque frame, leading to graphical glitches behind the
  // opaque frame.  Instead, we use that function below to tell us whether the
  // frame is currently native or opaque.
  if (!GetWidget()->client_view() || !browser_view_->IsBrowserTypeNormal() ||
      !DesktopRootWindowHostWin::ShouldUseNativeFrame())
    return;

  MARGINS margins = { 0 };

  // If the opaque frame is visible, we use the default (zero) margins.
  // Otherwise, we need to figure out how to extend the glass in.
  if (GetWidget()->ShouldUseNativeFrame()) {
    // In fullscreen mode, we don't extend glass into the client area at all,
    // because the GDI-drawn text in the web content composited over it will
    // become semi-transparent over any glass area.
    if (!IsMaximized() && !GetWidget()->IsFullscreen()) {
      margins.cxLeftWidth = kClientEdgeThickness + 1;
      margins.cxRightWidth = kClientEdgeThickness + 1;
      margins.cyBottomHeight = kClientEdgeThickness + 1;
      margins.cyTopHeight = kClientEdgeThickness + 1;
    }
    // In maximized mode, we only have a titlebar strip of glass, no side/bottom
    // borders.
    if (!browser_view_->IsFullscreen()) {
      gfx::Rect tabstrip_bounds(
          browser_frame_->GetBoundsForTabStrip(browser_view_->tabstrip()));
      margins.cyTopHeight = tabstrip_bounds.bottom() + kDWMFrameTopOffset;
    }
  }

  DwmExtendFrameIntoClientArea(GetHWND(), &margins);
}

////////////////////////////////////////////////////////////////////////////////
// BrowserDesktopRootWindowHost, public:

// static
BrowserDesktopRootWindowHost*
    BrowserDesktopRootWindowHost::CreateBrowserDesktopRootWindowHost(
        views::internal::NativeWidgetDelegate* native_widget_delegate,
        views::DesktopNativeWidgetAura* desktop_native_widget_aura,
        const gfx::Rect& initial_bounds,
        BrowserView* browser_view,
        BrowserFrame* browser_frame) {
  return new BrowserDesktopRootWindowHostWin(native_widget_delegate,
                                             desktop_native_widget_aura,
                                             initial_bounds,
                                             browser_view,
                                             browser_frame);
}
<|endoftext|>


<commit_before>#ifndef SUCCINCT_GRAPH_SG_HPP
#define SUCCINCT_GRAPH_SG_HPP

#include <iostream>
#include <fstream>
#include <map>
#include <omp.h>
#include "cpp/vg.pb.h"
#include "sdsl/bit_vectors.hpp"
#include "sdsl/enc_vector.hpp"
#include "sdsl/dac_vector.hpp"
#include "sdsl/vlc_vector.hpp"
#include "sdsl/wavelet_trees.hpp"
//#include "sdsl/csa_bitcompressed.hpp"
#include "sdsl/csa_wt.hpp"
#include "sdsl/suffix_arrays.hpp"
#include "dynamic.hpp"

namespace xg {

using namespace std;
using namespace sdsl;
using namespace vg;

class Traversal {
public:
    int64_t id;
    bool rev;
    Traversal(int64_t i, bool r) : id(i), rev(r) { }
};

class XGPath;
typedef pair<int64_t, bool> Side;

class XG {
public:

    XG(void) : start_marker('#'),
               end_marker('$'),
               seq_length(0),
               node_count(0),
               edge_count(0),
               path_count(0) { }
    ~XG(void) { }
    XG(istream& in);
    XG(Graph& graph);
    void from_stream(istream& in, bool validate_graph = false, bool print_graph = false);
    void from_graph(Graph& graph, bool validate_graph = false, bool print_graph = false);
    void build(map<int64_t, string>& node_label,
               map<Side, set<Side> >& from_to,
               map<Side, set<Side> >& to_from,
               map<string, map<int, Mapping>>& path_nodes,
               bool validate_graph,
               bool print_graph);
    void load(istream& in);
    size_t serialize(std::ostream& out,
                     sdsl::structure_tree_node* v = NULL,
                     std::string name = "");
    size_t seq_length;
    size_t node_count;
    size_t edge_count;
    size_t path_count;

    size_t id_to_rank(int64_t id) const;
    int64_t rank_to_id(size_t rank) const;
    size_t max_node_rank(void) const;
    Node node(int64_t id) const; // gets node sequence
    string node_sequence(int64_t id) const;
    vector<Edge> edges_of(int64_t id) const;
    vector<Edge> edges_to(int64_t id) const;
    vector<Edge> edges_from(int64_t id) const;
    vector<Edge> edges_on_start(int64_t id) const;
    vector<Edge> edges_on_end(int64_t id) const;
    size_t node_rank_as_entity(int64_t id) const;
    size_t edge_rank_as_entity(int64_t id1, bool from_start, int64_t id2, bool to_end) const;
    bool entity_is_node(size_t rank) const;
    size_t entity_rank_as_node_rank(size_t rank) const;
    bool has_edge(int64_t id1, bool is_start, int64_t id2, bool is_end) const;

    Path path(const string& name) const;
    size_t path_rank(const string& name) const;
    size_t max_path_rank(void) const;
    string path_name(size_t rank) const;
    vector<size_t> paths_of_entity(size_t rank) const;
    vector<size_t> paths_of_node(int64_t id) const;
    vector<size_t> paths_of_edge(int64_t id1, bool from_start, int64_t id2, bool to_end) const;
    map<string, vector<Mapping>> node_mappings(int64_t id) const;
    bool path_contains_node(const string& name, int64_t id) const;
    bool path_contains_edge(const string& name,
                            int64_t id1, bool from_start,
                            int64_t id2, bool to_end) const;
    bool path_contains_entity(const string& name, size_t rank) const;
    void add_paths_to_graph(map<int64_t, Node*>& nodes, Graph& g) const;
    size_t node_occs_in_path(int64_t id, const string& name) const;
    vector<size_t> node_ranks_in_path(int64_t id, const string& name) const;
    vector<size_t> node_positions_in_path(int64_t id, const string& name) const;
    int64_t node_at_path_position(const string& name, size_t pos) const;
    Mapping mapping_at_path_position(const string& name, size_t pos) const;
    size_t path_length(const string& name) const;

    void neighborhood(int64_t id, size_t steps, Graph& g) const;
    //void for_path_range(string& name, int64_t start, int64_t stop, function<void(Node)> lambda);
    void get_path_range(string& name, int64_t start, int64_t stop, Graph& g) const;
    // basic method to query regions of the graph
    // add_paths flag allows turning off the (potentially costly, and thread-locking) addition of paths
    // when these are not necessary
    void expand_context(Graph& g, size_t steps, bool add_paths = true) const;
    void get_connected_nodes(Graph& g) const;
    void get_id_range(int64_t id1, int64_t id2, Graph& g) const;

    // gPBWT interface
    // Insert a thread. Path name must be unique or empty.
    void insert_thread(const Path& t);
    // Read all the threads embedded in the graph.
    list<Path> extract_threads() const;
    // Extract a particular thread by name. Name may not be empty.
    Path extract_thread(const string& name) const;
    // Count matches to a subthread among embedded threads
    size_t count_matches(const Path& t) const;

    /**
     * Represents the search state for the graph PBWT, so that you can continue
     * a search with more of a thread, or backtrack.
     *
     * By default, represents an un-started search (with no first visited side)
     * that can be extended to the whole collection of visits to a side.
     */
    struct ThreadSearchState {
        // What side have we just arrived at in the search?
        int64_t currentSide = 0;
        // What is the first visit at that side that is selected?
        int64_t rangeStart = 0;
        // And what is the past-the-last visit that is selected?
        int64_t rangeEnd = numeric_limits<int64_t>::max();

        // How many visits are selected?
        inline int64_t count() {
            return rangeEnd - rangeStart;
        }

        // Return true if the range has nothing selected.
        inline bool isEmpty() {
            return rangeEnd <= rangeStart;
        }
    };

    // Extend a search with the given section of a thread.
    void extend(ThreadSearchState& state, const Path& t) const;

    char start_marker;
    char end_marker;

private:

    // sequence/integer vector
    int_vector<> s_iv;
    // node starts in sequence, provides id schema
    // rank_1(i) = id
    // select_1(id) = i
    bit_vector s_bv; // node positions in siv
    rank_support_v<1> s_bv_rank;
    bit_vector::select_1_type s_bv_select;
    // compressed version, unused...
    rrr_vector<> s_cbv;
    rrr_vector<>::rank_1_type s_cbv_rank;
    rrr_vector<>::select_1_type s_cbv_select;

    // maintain old ids from input, ranked as in s_iv and s_bv
    int_vector<> i_iv;
    int64_t min_id; // id ranges don't have to start at 0
    int64_t max_id;
    int_vector<> r_iv; // ids-id_min is the rank

    // maintain forward links
    int_vector<> f_iv;
    bit_vector f_bv;
    rank_support_v<1> f_bv_rank;
    bit_vector::select_1_type f_bv_select;
    bit_vector f_from_start_bv;
    bit_vector f_to_end_bv;
    sd_vector<> f_from_start_cbv;
    sd_vector<> f_to_end_cbv;

    // and the same data in the reverse direction
    int_vector<> t_iv;
    bit_vector t_bv;
    rank_support_v<1> t_bv_rank;
    bit_vector::select_1_type t_bv_select;
    // these bit vectors are only used during construction
    // perhaps they should be moved?
    bit_vector t_from_start_bv;
    bit_vector t_to_end_bv;
    // used at runtime
    sd_vector<> t_from_start_cbv;
    sd_vector<> t_to_end_cbv;

    // edge table, allows o(1) determination of edge existence
    int_vector<> e_iv;

    //csa_wt<> e_csa;
    //csa_sada<> e_csa;

    // allows lookups of id->rank mapping
    //wt_int<> i_wt;

    // paths: serialized as bitvectors over nodes and edges
    int_vector<> pn_iv; // path names
    csa_wt<> pn_csa; // path name compressed suffix array
    bit_vector pn_bv;  // path name starts in uncompressed version of csa
    rank_support_v<1> pn_bv_rank;
    bit_vector::select_1_type pn_bv_select;
    int_vector<> pi_iv; // path ids by rank in the path names

    // probably these should get compressed, for when we have whole genomes with many chromosomes
    // the growth in required memory is quadratic but the stored matrix is sparse
    vector<XGPath*> paths; // path entity membership

    // entity->path membership
    int_vector<> ep_iv;
    bit_vector ep_bv; // entity delimiters in ep_iv
    rank_support_v<1> ep_bv_rank;
    bit_vector::select_1_type ep_bv_select;

    // Succinct thread storage

    // Threads are haplotype paths in the graph with no edits allowed, starting
    // and stopping at node boundaries.

    // We keep our strings in this dynamic succinct rank-select string from DYNAMIC.
    using dynamic_int_vector = dyn::rle_str;

    // TODO: Explain the whole graph PBWT extension here

    // Basically we keep usage counts for every element in the graph, and and
    // array of next-node-start sides for each side in the graph. We number
    // sides as 2 * xg internal node ID, +1 if it's a right side. This leaves us
    // 0 and 1 free for representing the null destination side and to use as a
    // per-side array run separator, respectively.

    // This holds, for each node and edge (with indexes as in the entity vector
    // f_iv), the usage count (i.e. the number of times it is visited by encoded
    // threads). This doesn't have to be dynamic since the length will never
    // change.
    int_vector<> h_iv;

    // This holds the concatenated Benedict arrays (holding the next node's
    // entry side visited after the current entry side for the threads sorted in
    // reverse prefix lexicographic order). They are separated with 1s, with 0s
    // noting the null side (i.e. the thread ends at this node).
    dynamic_int_vector bs_iv;

    // We need the w function, which we call the "where_to" function. It tells
    // you, from a given visit at a given side, what visit offset if you go to
    // another side.
    int64_t where_to(int64_t current_side, int64_t visit_offset, int64_t new_side);
};

class XGPath {
public:
    XGPath(void) : member_count(0) { }
    ~XGPath(void) { }
    XGPath(const string& path_name,
           const vector<Mapping>& path,
           size_t entity_count,
           XG& graph,
           const map<int64_t, string>& node_label);
    string name;
    size_t member_count;
    sd_vector<> members;
    wt_int<> ids;
    sd_vector<> directions; // forward or backward through nodes
    int_vector<> positions;
    int_vector<> ranks;
    bit_vector offsets;
    rank_support_v<1> offsets_rank;
    bit_vector::select_1_type offsets_select;
    void load(istream& in);
    size_t serialize(std::ostream& out,
                     sdsl::structure_tree_node* v = NULL,
                     std::string name = "");
    Mapping mapping(size_t offset); // 0-based
};

Mapping new_mapping(const string& name, int64_t id, size_t rank, bool is_reverse);
void parse_region(const string& target, string& name, int64_t& start, int64_t& end);
void to_text(ostream& out, Graph& graph);

}

#endif
<commit_msg>Add a cache for thread start counts<commit_after>#ifndef SUCCINCT_GRAPH_SG_HPP
#define SUCCINCT_GRAPH_SG_HPP

#include <iostream>
#include <fstream>
#include <map>
#include <omp.h>
#include "cpp/vg.pb.h"
#include "sdsl/bit_vectors.hpp"
#include "sdsl/enc_vector.hpp"
#include "sdsl/dac_vector.hpp"
#include "sdsl/vlc_vector.hpp"
#include "sdsl/wavelet_trees.hpp"
//#include "sdsl/csa_bitcompressed.hpp"
#include "sdsl/csa_wt.hpp"
#include "sdsl/suffix_arrays.hpp"
#include "dynamic.hpp"

namespace xg {

using namespace std;
using namespace sdsl;
using namespace vg;

class Traversal {
public:
    int64_t id;
    bool rev;
    Traversal(int64_t i, bool r) : id(i), rev(r) { }
};

class XGPath;
typedef pair<int64_t, bool> Side;

class XG {
public:

    XG(void) : start_marker('#'),
               end_marker('$'),
               seq_length(0),
               node_count(0),
               edge_count(0),
               path_count(0) { }
    ~XG(void) { }
    XG(istream& in);
    XG(Graph& graph);
    void from_stream(istream& in, bool validate_graph = false, bool print_graph = false);
    void from_graph(Graph& graph, bool validate_graph = false, bool print_graph = false);
    void build(map<int64_t, string>& node_label,
               map<Side, set<Side> >& from_to,
               map<Side, set<Side> >& to_from,
               map<string, map<int, Mapping>>& path_nodes,
               bool validate_graph,
               bool print_graph);
    void load(istream& in);
    size_t serialize(std::ostream& out,
                     sdsl::structure_tree_node* v = NULL,
                     std::string name = "");
    size_t seq_length;
    size_t node_count;
    size_t edge_count;
    size_t path_count;

    size_t id_to_rank(int64_t id) const;
    int64_t rank_to_id(size_t rank) const;
    size_t max_node_rank(void) const;
    Node node(int64_t id) const; // gets node sequence
    string node_sequence(int64_t id) const;
    vector<Edge> edges_of(int64_t id) const;
    vector<Edge> edges_to(int64_t id) const;
    vector<Edge> edges_from(int64_t id) const;
    vector<Edge> edges_on_start(int64_t id) const;
    vector<Edge> edges_on_end(int64_t id) const;
    size_t node_rank_as_entity(int64_t id) const;
    size_t edge_rank_as_entity(int64_t id1, bool from_start, int64_t id2, bool to_end) const;
    bool entity_is_node(size_t rank) const;
    size_t entity_rank_as_node_rank(size_t rank) const;
    bool has_edge(int64_t id1, bool is_start, int64_t id2, bool is_end) const;

    Path path(const string& name) const;
    size_t path_rank(const string& name) const;
    size_t max_path_rank(void) const;
    string path_name(size_t rank) const;
    vector<size_t> paths_of_entity(size_t rank) const;
    vector<size_t> paths_of_node(int64_t id) const;
    vector<size_t> paths_of_edge(int64_t id1, bool from_start, int64_t id2, bool to_end) const;
    map<string, vector<Mapping>> node_mappings(int64_t id) const;
    bool path_contains_node(const string& name, int64_t id) const;
    bool path_contains_edge(const string& name,
                            int64_t id1, bool from_start,
                            int64_t id2, bool to_end) const;
    bool path_contains_entity(const string& name, size_t rank) const;
    void add_paths_to_graph(map<int64_t, Node*>& nodes, Graph& g) const;
    size_t node_occs_in_path(int64_t id, const string& name) const;
    vector<size_t> node_ranks_in_path(int64_t id, const string& name) const;
    vector<size_t> node_positions_in_path(int64_t id, const string& name) const;
    int64_t node_at_path_position(const string& name, size_t pos) const;
    Mapping mapping_at_path_position(const string& name, size_t pos) const;
    size_t path_length(const string& name) const;

    void neighborhood(int64_t id, size_t steps, Graph& g) const;
    //void for_path_range(string& name, int64_t start, int64_t stop, function<void(Node)> lambda);
    void get_path_range(string& name, int64_t start, int64_t stop, Graph& g) const;
    // basic method to query regions of the graph
    // add_paths flag allows turning off the (potentially costly, and thread-locking) addition of paths
    // when these are not necessary
    void expand_context(Graph& g, size_t steps, bool add_paths = true) const;
    void get_connected_nodes(Graph& g) const;
    void get_id_range(int64_t id1, int64_t id2, Graph& g) const;

    // gPBWT interface
    // Insert a thread. Path name must be unique or empty.
    void insert_thread(const Path& t);
    // Read all the threads embedded in the graph.
    list<Path> extract_threads() const;
    // Extract a particular thread by name. Name may not be empty.
    Path extract_thread(const string& name) const;
    // Count matches to a subthread among embedded threads
    size_t count_matches(const Path& t) const;

    /**
     * Represents the search state for the graph PBWT, so that you can continue
     * a search with more of a thread, or backtrack.
     *
     * By default, represents an un-started search (with no first visited side)
     * that can be extended to the whole collection of visits to a side.
     */
    struct ThreadSearchState {
        // What side have we just arrived at in the search?
        int64_t currentSide = 0;
        // What is the first visit at that side that is selected?
        int64_t rangeStart = 0;
        // And what is the past-the-last visit that is selected?
        int64_t rangeEnd = numeric_limits<int64_t>::max();

        // How many visits are selected?
        inline int64_t count() {
            return rangeEnd - rangeStart;
        }

        // Return true if the range has nothing selected.
        inline bool isEmpty() {
            return rangeEnd <= rangeStart;
        }
    };

    // Extend a search with the given section of a thread.
    void extend(ThreadSearchState& state, const Path& t) const;

    char start_marker;
    char end_marker;

private:

    // sequence/integer vector
    int_vector<> s_iv;
    // node starts in sequence, provides id schema
    // rank_1(i) = id
    // select_1(id) = i
    bit_vector s_bv; // node positions in siv
    rank_support_v<1> s_bv_rank;
    bit_vector::select_1_type s_bv_select;
    // compressed version, unused...
    rrr_vector<> s_cbv;
    rrr_vector<>::rank_1_type s_cbv_rank;
    rrr_vector<>::select_1_type s_cbv_select;

    // maintain old ids from input, ranked as in s_iv and s_bv
    int_vector<> i_iv;
    int64_t min_id; // id ranges don't have to start at 0
    int64_t max_id;
    int_vector<> r_iv; // ids-id_min is the rank

    // maintain forward links
    int_vector<> f_iv;
    bit_vector f_bv;
    rank_support_v<1> f_bv_rank;
    bit_vector::select_1_type f_bv_select;
    bit_vector f_from_start_bv;
    bit_vector f_to_end_bv;
    sd_vector<> f_from_start_cbv;
    sd_vector<> f_to_end_cbv;

    // and the same data in the reverse direction
    int_vector<> t_iv;
    bit_vector t_bv;
    rank_support_v<1> t_bv_rank;
    bit_vector::select_1_type t_bv_select;
    // these bit vectors are only used during construction
    // perhaps they should be moved?
    bit_vector t_from_start_bv;
    bit_vector t_to_end_bv;
    // used at runtime
    sd_vector<> t_from_start_cbv;
    sd_vector<> t_to_end_cbv;

    // edge table, allows o(1) determination of edge existence
    int_vector<> e_iv;

    //csa_wt<> e_csa;
    //csa_sada<> e_csa;

    // allows lookups of id->rank mapping
    //wt_int<> i_wt;

    // paths: serialized as bitvectors over nodes and edges
    int_vector<> pn_iv; // path names
    csa_wt<> pn_csa; // path name compressed suffix array
    bit_vector pn_bv;  // path name starts in uncompressed version of csa
    rank_support_v<1> pn_bv_rank;
    bit_vector::select_1_type pn_bv_select;
    int_vector<> pi_iv; // path ids by rank in the path names

    // probably these should get compressed, for when we have whole genomes with many chromosomes
    // the growth in required memory is quadratic but the stored matrix is sparse
    vector<XGPath*> paths; // path entity membership

    // entity->path membership
    int_vector<> ep_iv;
    bit_vector ep_bv; // entity delimiters in ep_iv
    rank_support_v<1> ep_bv_rank;
    bit_vector::select_1_type ep_bv_select;

    // Succinct thread storage

    // Threads are haplotype paths in the graph with no edits allowed, starting
    // and stopping at node boundaries.

    // We keep our strings in this dynamic succinct rank-select string from DYNAMIC.
    using dynamic_int_vector = dyn::rle_str;

    // TODO: Explain the whole graph PBWT extension here

    // Basically we keep usage counts for every element in the graph, and and
    // array of next-node-start sides for each side in the graph. We number
    // sides as 2 * xg internal node ID, +1 if it's a right side. This leaves us
    // 0 and 1 free for representing the null destination side and to use as a
    // per-side array run separator, respectively.

    // This holds, for each node and edge (with indexes as in the entity vector
    // f_iv), the usage count (i.e. the number of times it is visited by encoded
    // threads). This doesn't have to be dynamic since the length will never
    // change.
    int_vector<> h_iv;

    // This (as an extension to the algorithm described in the paper) holds the
    // number of threads beginning at each node. This isn't any extra
    // information relative to what's in the usage count array, but it's cheaper
    // (probably) to maintain this rather than to scan through all the edges on
    // a side every time.
    // ts stands for "thread start"
    int_vector<> ts_iv;

    // This holds the concatenated Benedict arrays (holding the next node's
    // entry side visited after the current entry side for the threads sorted in
    // reverse prefix lexicographic order). They are separated with 1s, with 0s
    // noting the null side (i.e. the thread ends at this node).
    dynamic_int_vector bs_iv;

    // We need the w function, which we call the "where_to" function. It tells
    // you, from a given visit at a given side, what visit offset if you go to
    // another side.
    int64_t where_to(int64_t current_side, int64_t visit_offset, int64_t new_side);
};

class XGPath {
public:
    XGPath(void) : member_count(0) { }
    ~XGPath(void) { }
    XGPath(const string& path_name,
           const vector<Mapping>& path,
           size_t entity_count,
           XG& graph,
           const map<int64_t, string>& node_label);
    string name;
    size_t member_count;
    sd_vector<> members;
    wt_int<> ids;
    sd_vector<> directions; // forward or backward through nodes
    int_vector<> positions;
    int_vector<> ranks;
    bit_vector offsets;
    rank_support_v<1> offsets_rank;
    bit_vector::select_1_type offsets_select;
    void load(istream& in);
    size_t serialize(std::ostream& out,
                     sdsl::structure_tree_node* v = NULL,
                     std::string name = "");
    Mapping mapping(size_t offset); // 0-based
};

Mapping new_mapping(const string& name, int64_t id, size_t rank, bool is_reverse);
void parse_region(const string& target, string& name, int64_t& start, int64_t& end);
void to_text(ostream& out, Graph& graph);

}

#endif
<|endoftext|>


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

#include "ReadBarcode.h"
#include "TextUtfEncoding.h"
#include "ZXNumeric.h"

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cctype>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

using namespace ZXing;

static void PrintUsage(const char* exePath)
{
	std::cout << "Usage: " << exePath << " [-fast] [-rotate] [-format <FORMAT[,...]>] <png image path>\n"
			  << "    -fast    Skip some lines/pixels during detection\n"
			  << "    -rotate  Also try rotated image during detection\n"
			  << "    -format  Only detect given format(s)\n"
			  << "    -ispure  Assume the image contains only a 'pure'/perfect code\n"
			  << "\n"
			  << "Supported formats are:\n";
	for (auto f : BarcodeFormats::all()) {
		std::cout << "    " << ToString(f) << "\n";
	}
	std::cout << "Formats can be lowercase, with or without underscore, separated by ',', '|' and/or ' '\n";
}

static bool ParseOptions(int argc, char* argv[], DecodeHints* hints, std::string* filePath)
{
	hints->setTryHarder(true);
	for (int i = 1; i < argc; ++i) {
		if (strcmp(argv[i], "-fast") == 0) {
			hints->setTryHarder(false);
		}
		else if (strcmp(argv[i], "-rotate") == 0) {
			hints->setTryRotate(true);
		}
		else if (strcmp(argv[i], "-ispure") == 0) {
			hints->setIsPure(true);
			hints->setBinarizer(Binarizer::FixedThreshold);
		}
		else if (strcmp(argv[i], "-format") == 0) {
			if (++i == argc)
				return false;
			try {
				hints->setFormats(BarcodeFormatsFromString(argv[i]));
			} catch (const std::exception& e) {
				std::cerr << e.what() << "\n";
				return false;
			}
		}
		else {
			*filePath = argv[i];
		}
	}

	return !filePath->empty();
}

std::ostream& operator<<(std::ostream& os, const Position& points) {
	for (const auto& p : points)
		os << p.x << "x" << p.y << " ";
	return os;
}

int main(int argc, char* argv[])
{
	DecodeHints hints;
	std::string filePath;

	if (!ParseOptions(argc, argv, &hints, &filePath)) {
		PrintUsage(argv[0]);
		return -1;
	}

	int width, height, channels;
	std::unique_ptr<stbi_uc, void(*)(void*)> buffer(stbi_load(filePath.c_str(), &width, &height, &channels, 4), stbi_image_free);
	if (buffer == nullptr) {
		std::cerr << "Failed to read image: " << filePath << "\n";
		return -1;
	}

	auto result = ReadBarcode({buffer.get(), width, height, ImageFormat::RGBX}, hints);

	std::cout << "Text:     \"" << TextUtfEncoding::ToUtf8(result.text()) << "\"\n"
			  << "Format:   " << ToString(result.format()) << "\n"
			  << "Position: " << result.position() << "\n"
			  << "Rotation: " << std::lround(result.position().rotation() * kDegPerRad) << "\n"
			  << "Error:    " << ToString(result.status()) << "\n";
	auto errLevel = result.metadata().getString(ResultMetadata::Key::ERROR_CORRECTION_LEVEL);
	if (!errLevel.empty()) {
		std::cout << "EC Level: " << TextUtfEncoding::ToUtf8(errLevel) << "\n";
	}

	return static_cast<int>(result.status());
}
<commit_msg>ZXingReader: output more metadata<commit_after>/*
* Copyright 2016 Nu-book Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "ReadBarcode.h"
#include "TextUtfEncoding.h"
#include "ZXNumeric.h"

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cctype>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

using namespace ZXing;

static void PrintUsage(const char* exePath)
{
	std::cout << "Usage: " << exePath << " [-fast] [-rotate] [-format <FORMAT[,...]>] <png image path>\n"
			  << "    -fast    Skip some lines/pixels during detection\n"
			  << "    -rotate  Also try rotated image during detection\n"
			  << "    -format  Only detect given format(s)\n"
			  << "    -ispure  Assume the image contains only a 'pure'/perfect code\n"
			  << "\n"
			  << "Supported formats are:\n";
	for (auto f : BarcodeFormats::all()) {
		std::cout << "    " << ToString(f) << "\n";
	}
	std::cout << "Formats can be lowercase, with or without underscore, separated by ',', '|' and/or ' '\n";
}

static bool ParseOptions(int argc, char* argv[], DecodeHints* hints, std::string* filePath)
{
	hints->setTryHarder(true);
	for (int i = 1; i < argc; ++i) {
		if (strcmp(argv[i], "-fast") == 0) {
			hints->setTryHarder(false);
		}
		else if (strcmp(argv[i], "-rotate") == 0) {
			hints->setTryRotate(true);
		}
		else if (strcmp(argv[i], "-ispure") == 0) {
			hints->setIsPure(true);
			hints->setBinarizer(Binarizer::FixedThreshold);
		}
		else if (strcmp(argv[i], "-format") == 0) {
			if (++i == argc)
				return false;
			try {
				hints->setFormats(BarcodeFormatsFromString(argv[i]));
			} catch (const std::exception& e) {
				std::cerr << e.what() << "\n";
				return false;
			}
		}
		else {
			*filePath = argv[i];
		}
	}

	return !filePath->empty();
}

std::ostream& operator<<(std::ostream& os, const Position& points) {
	for (const auto& p : points)
		os << p.x << "x" << p.y << " ";
	return os;
}

int main(int argc, char* argv[])
{
	DecodeHints hints;
	std::string filePath;

	if (!ParseOptions(argc, argv, &hints, &filePath)) {
		PrintUsage(argv[0]);
		return -1;
	}

	int width, height, channels;
	std::unique_ptr<stbi_uc, void(*)(void*)> buffer(stbi_load(filePath.c_str(), &width, &height, &channels, 4), stbi_image_free);
	if (buffer == nullptr) {
		std::cerr << "Failed to read image: " << filePath << "\n";
		return -1;
	}

	auto result = ReadBarcode({buffer.get(), width, height, ImageFormat::RGBX}, hints);

	std::cout << "Text:     \"" << TextUtfEncoding::ToUtf8(result.text()) << "\"\n"
			  << "Format:   " << ToString(result.format()) << "\n"
			  << "Position: " << result.position() << "\n"
			  << "Rotation: " << std::lround(result.position().rotation() * kDegPerRad) << "\n"
			  << "Error:    " << ToString(result.status()) << "\n";

	std::map<ResultMetadata::Key, const char*> keys = {{ResultMetadata::ERROR_CORRECTION_LEVEL, "EC Level: "},
													   {ResultMetadata::SUGGESTED_PRICE, "Price:    "},
													   {ResultMetadata::ISSUE_NUMBER, "Issue #   "},
													   {ResultMetadata::UPC_EAN_EXTENSION, "Extension:"}};

	for (auto key : keys) {
		auto value = TextUtfEncoding::ToUtf8(result.metadata().getString(key.first));
		if (value.size())
			std::cout << key.second << value << "\n";
	}

	return static_cast<int>(result.status());
}
<|endoftext|>