<commit_before>#ifndef ecmdStructs_H
#define ecmdStructs_H
// Copyright **********************************************************
//
// File ecmdStructs.H
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/**
  @file ecmdStructs.H
  @brief All the Structures required for the eCMD Capi
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <inttypes.h>
#include <vector>  /* For STL vector */
#include <string>

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//  Defines
//--------------------------------------------------------------------

#define ECMD_CAPI_VERSION ".1"          ///< eCMD API Version

/**
 @brief Structure used to designate which cec object/chip you would like the function to operate on

  - The valid bits are used by D/A functions to tell the calling function what level of granularity the function operates on
    Ex.  putmem/getmem display memory through the processor, they are only dependent on cage/node/pos because they do not use
          the cores to perform their function
         However put/getspr display architected registers from the processor, they will signify that cage/node/pos/core and depending
          on the particular spr referenced threads may be valid
  - The valid bits are used slightly differently for the queryFunctions they are used there to signify the
     what data coming in is valid to refine a query
*/
struct ecmdChipTarget {

  uint32_t cage;                ///< cage that contains node with chip
  uint32_t node;                ///< node that contains chip
  std::string chipType;         ///< name of chip to access
  uint32_t pos;                 ///< position of chip within node
  uint32_t core;                ///< which core on chip to access, if chip is multi-core
  uint32_t thread;              ///< which thread on chip to access, if chip is multi-threaded

  uint8_t chipTypeValid;        ///< chipType field is valid
  uint8_t cageValid;            ///< cage field is valid
  uint8_t nodeValid;            ///< node field is valid
  uint8_t posValid;             ///< pos field is valid
  uint8_t coreValid;            ///< core field is valid
  uint8_t threadValid;          ///< thread field is valid
  uint8_t ValidChecked;         ///< valid bits are valid
};

/**
 @brief Used in ecmdChipData to describe the interface macro used by the chip
*/
typedef enum {
  ECMD_INTERFACE_ACCESS,                ///< Standard Jtag Rochester Access Macro
  ECMD_INTERFACE_CFAM                   ///< CommonFirmwareAccessMacro - Fsi interface
} ecmdChipInterfaceType_t;

/**
 @brief Used for the ecmdQueryConfig function to return core data
*/
struct ecmdCoreData {
  uint32_t coreId;                      ///< core number of this entry
  uint8_t  numProcThreads;              ///< Number of threads per core this entry supports - only valid for Processors
};

/**
 @brief Used for the ecmdQueryConfig function to return chip data
*/
struct ecmdChipData {
  std::string   chipType;                       ///< name of chip
  uint32_t pos;                                 ///< Position of this entry
  uint8_t  numProcCores;                        ///< Number of cores this entry supports - only valid for Processor compute cores
  uint32_t chipEc;                              ///< EC level of this chip, usually 0-F (ec read from 'jtag' chip id or CFAM id)
  ecmdChipInterfaceType_t interfaceType;        ///< Interface Macro used by the chip
  uint32_t chipFlags;                           ///< Various additional info about the chip - bitmask of defines
  std::vector<ecmdCoreData> coreData;           ///< Vector of all cores requested in this chip - only valid for Processor compute cores - in numerical order by coreId
};

/**
 @brief Used for the ecmdQueryConfig function to return node data
*/
struct ecmdNodeData {
  uint32_t nodeId;                      ///< Node number of this entry
  std::vector<ecmdChipData> chipData;   ///< Vector of all chips requested in this node - in numerical order per chip by pos
};

/**
 @brief Used for the ecmdQueryConfig function to return cage data
*/
struct ecmdCageData {
  uint32_t cageId;                      ///< Cage number of this entry
  std::vector<ecmdNodeData> nodeData;   ///< Vector of all nodes requested in this cage - in numerical order by nodeId
};

/**
 @brief Used for the ecmdQueryRing function to return ring info
*/
struct ecmdRingData {
  std::vector<std::string> ringNames;   ///< Names used to reference this ring
  uint32_t address;                     ///< Address modifier
  int      bitLength;                   ///< length of ring
  bool     hasInversionMask;            ///< Ring has an inversion mask applied before scanning
  bool     supportsBroadsideLoad;       ///< This ring supports broadside load in simulation
  bool     isCheckable;                 ///< This ring can be run through the check_rings command
};

/**
 @brief Used for the ecmdQueryArray function to return array info
*/
struct ecmdArrayData {
  std::string arrayName; ///< Names used to reference this ring
  int length;            ///< length of array
  int width;             ///< width of array
};

/**
 @brief Used for the ecmdQuerySpy function to specify which type of spy we have @see ecmdSpyData
*/
typedef enum {
  ECMD_SPYTYPE_ALIAS,   ///< Spy is an alias
  ECMD_SPYTYPE_IDIAL,   ///< Spy is an iDial
  ECMD_SPYTYPE_EDIAL,   ///< Spy is an eDial
  ECMD_SPYTYPE_ECC      ///< Spy is an eccdef - do we need this ?
} ecmdSpyType_t;

/**
 @brief Used for the ecmdQuerySpy function to return spy info
*/
struct ecmdSpyData {
  std::string spyName;                  ///< Names used to reference this spy
  int bitLength;                        ///< length of spy
  ecmdSpyType_t spyType;                ///< Type of spy

  std::vector<std::string> enums;       ///< Possible enum values for Spy - I/P Can only provide this on a client, not on the FSP
};

/**
 @brief Used for the ecmdQueryFileLocation function to specify the file type you are looking for
*/
typedef enum {
  ECMD_FILE_SCANDEF,    ///< Scandef file type
  ECMD_FILE_SPYDEF,     ///< Spy Definition file
  ECMD_FILE_ARRAYDEF    ///< Array Definition file
} ecmdFileType_t;

#endif
<commit_msg>added ECMD_HELP_TEXT<commit_after>#ifndef ecmdStructs_H
#define ecmdStructs_H
// Copyright **********************************************************
//
// File ecmdStructs.H
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/**
  @file ecmdStructs.H
  @brief All the Structures required for the eCMD Capi
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <inttypes.h>
#include <vector>  /* For STL vector */
#include <string>

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//  Defines
//--------------------------------------------------------------------

#define ECMD_CAPI_VERSION ".1"          ///< eCMD API Version

/**
 @brief Structure used to designate which cec object/chip you would like the function to operate on

  - The valid bits are used by D/A functions to tell the calling function what level of granularity the function operates on
    Ex.  putmem/getmem display memory through the processor, they are only dependent on cage/node/pos because they do not use
          the cores to perform their function
         However put/getspr display architected registers from the processor, they will signify that cage/node/pos/core and depending
          on the particular spr referenced threads may be valid
  - The valid bits are used slightly differently for the queryFunctions they are used there to signify the
     what data coming in is valid to refine a query
*/
struct ecmdChipTarget {

  uint32_t cage;                ///< cage that contains node with chip
  uint32_t node;                ///< node that contains chip
  std::string chipType;         ///< name of chip to access
  uint32_t pos;                 ///< position of chip within node
  uint32_t core;                ///< which core on chip to access, if chip is multi-core
  uint32_t thread;              ///< which thread on chip to access, if chip is multi-threaded

  uint8_t chipTypeValid;        ///< chipType field is valid
  uint8_t cageValid;            ///< cage field is valid
  uint8_t nodeValid;            ///< node field is valid
  uint8_t posValid;             ///< pos field is valid
  uint8_t coreValid;            ///< core field is valid
  uint8_t threadValid;          ///< thread field is valid
  uint8_t ValidChecked;         ///< valid bits are valid
};

/**
 @brief Used in ecmdChipData to describe the interface macro used by the chip
*/
typedef enum {
  ECMD_INTERFACE_ACCESS,                ///< Standard Jtag Rochester Access Macro
  ECMD_INTERFACE_CFAM                   ///< CommonFirmwareAccessMacro - Fsi interface
} ecmdChipInterfaceType_t;

/**
 @brief Used for the ecmdQueryConfig function to return core data
*/
struct ecmdCoreData {
  uint32_t coreId;                      ///< core number of this entry
  uint8_t  numProcThreads;              ///< Number of threads per core this entry supports - only valid for Processors
};

/**
 @brief Used for the ecmdQueryConfig function to return chip data
*/
struct ecmdChipData {
  std::string   chipType;                       ///< name of chip
  uint32_t pos;                                 ///< Position of this entry
  uint8_t  numProcCores;                        ///< Number of cores this entry supports - only valid for Processor compute cores
  uint32_t chipEc;                              ///< EC level of this chip, usually 0-F (ec read from 'jtag' chip id or CFAM id)
  ecmdChipInterfaceType_t interfaceType;        ///< Interface Macro used by the chip
  uint32_t chipFlags;                           ///< Various additional info about the chip - bitmask of defines
  std::vector<ecmdCoreData> coreData;           ///< Vector of all cores requested in this chip - only valid for Processor compute cores - in numerical order by coreId
};

/**
 @brief Used for the ecmdQueryConfig function to return node data
*/
struct ecmdNodeData {
  uint32_t nodeId;                      ///< Node number of this entry
  std::vector<ecmdChipData> chipData;   ///< Vector of all chips requested in this node - in numerical order per chip by pos
};

/**
 @brief Used for the ecmdQueryConfig function to return cage data
*/
struct ecmdCageData {
  uint32_t cageId;                      ///< Cage number of this entry
  std::vector<ecmdNodeData> nodeData;   ///< Vector of all nodes requested in this cage - in numerical order by nodeId
};

/**
 @brief Used for the ecmdQueryRing function to return ring info
*/
struct ecmdRingData {
  std::vector<std::string> ringNames;   ///< Names used to reference this ring
  uint32_t address;                     ///< Address modifier
  int      bitLength;                   ///< length of ring
  bool     hasInversionMask;            ///< Ring has an inversion mask applied before scanning
  bool     supportsBroadsideLoad;       ///< This ring supports broadside load in simulation
  bool     isCheckable;                 ///< This ring can be run through the check_rings command
};

/**
 @brief Used for the ecmdQueryArray function to return array info
*/
struct ecmdArrayData {
  std::string arrayName; ///< Names used to reference this ring
  int length;            ///< length of array
  int width;             ///< width of array
};

/**
 @brief Used for the ecmdQuerySpy function to specify which type of spy we have @see ecmdSpyData
*/
typedef enum {
  ECMD_SPYTYPE_ALIAS,   ///< Spy is an alias
  ECMD_SPYTYPE_IDIAL,   ///< Spy is an iDial
  ECMD_SPYTYPE_EDIAL,   ///< Spy is an eDial
  ECMD_SPYTYPE_ECC      ///< Spy is an eccdef - do we need this ?
} ecmdSpyType_t;

/**
 @brief Used for the ecmdQuerySpy function to return spy info
*/
struct ecmdSpyData {
  std::string spyName;                  ///< Names used to reference this spy
  int bitLength;                        ///< length of spy
  ecmdSpyType_t spyType;                ///< Type of spy

  std::vector<std::string> enums;       ///< Possible enum values for Spy - I/P Can only provide this on a client, not on the FSP
};

/**
 @brief Used for the ecmdQueryFileLocation function to specify the file type you are looking for
*/
typedef enum {
  ECMD_FILE_SCANDEF,    ///< Scandef file type
  ECMD_FILE_SPYDEF,     ///< Spy Definition file
  ECMD_FILE_ARRAYDEF,   ///< Array Definition file
  ECMD_FILE_HELPTEXT    ///< eCMD Help Text file
} ecmdFileType_t;

#endif
<|endoftext|>


<commit_before>#include "resources.h"

#include <SFML/System.hpp>
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dirent.h>
#endif
#include <cstdio>

PVector<ResourceProvider> resourceProviders;

ResourceProvider::ResourceProvider()
{
    resourceProviders.push_back(this);
}

bool ResourceProvider::searchMatch(const string name, const string searchPattern)
{
    std::vector<string> parts = searchPattern.split("*");
    int pos = 0;
    if (parts[0].length() > 0)
    {
        if (name.find(parts[0]) != 0)
            return false;
    }
    for(unsigned int n=1; n<parts.size(); n++)
    {
        int offset = name.find(parts[n], pos);
        if (offset < 0)
            return false;
        pos = offset + parts[n].length();
    }
    return pos == int(name.length());
}

string ResourceStream::readLine()
{
    string ret;
    char c;
    while(true)
    {
        if (read(&c, 1) < 1)
            return ret;
        if (c == '\n')
            return ret;
        ret += string(c);
    }
}

class FileResourceStream : public ResourceStream
{
    sf::FileInputStream stream;
    bool open_success;
public:
    FileResourceStream(string filename)
    {
        open_success = stream.open(filename);
    }
    virtual ~FileResourceStream()
    {
    }

    bool isOpen()
    {
        return open_success;
    }

    virtual sf::Int64 read(void* data, sf::Int64 size)
    {
        return stream.read(data, size);
    }
    virtual sf::Int64 seek(sf::Int64 position)
    {
        return stream.seek(position);
    }
    virtual sf::Int64 tell()
    {
        return stream.tell();
    }
    virtual sf::Int64 getSize()
    {
        return stream.getSize();
    }
};

DirectoryResourceProvider::DirectoryResourceProvider(string basepath)
: basepath(basepath)
{
}

P<ResourceStream> DirectoryResourceProvider::getResourceStream(string filename)
{
    P<FileResourceStream> stream = new FileResourceStream(basepath + filename);
    if (stream->isOpen())
        return stream;
    return nullptr;
}

std::vector<string> DirectoryResourceProvider::findResources(string searchPattern)
{
    std::vector<string> found_files;
    findResources(found_files, "", searchPattern);
    return found_files;
}

void DirectoryResourceProvider::findResources(std::vector<string>& found_files, const string path, const string searchPattern)
{
#ifdef _WIN32
    WIN32_FIND_DATAA data;
    string search_root(basepath + path);
    if (!search_root.endswith("/"))
    {
        search_root += "/";
    }
    HANDLE handle = FindFirstFileA((search_root + "*").c_str(), &data);
    if (handle == INVALID_HANDLE_VALUE)
        return;
    do
    {
        if (data.cFileName[0] == '.')
            continue;
        string name = path + string(data.cFileName);
        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            findResources(found_files, name + "/", searchPattern);
        }
        else
        {
            if (searchMatch(name, searchPattern))
                found_files.push_back(name);
        }
    } while (FindNextFileA(handle, &data));

    FindClose(handle);
#else
    DIR* dir = opendir((basepath + path).c_str());
    if (!dir)
        return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != nullptr)
    {
        if (entry->d_name[0] == '.')
            continue;
        string name = path + string(entry->d_name);
        if (searchMatch(name, searchPattern))
            found_files.push_back(name);
        findResources(found_files, path + string(entry->d_name) + "/", searchPattern);
    }
    closedir(dir);
#endif
}

P<ResourceStream> getResourceStream(string filename)
{
    foreach(ResourceProvider, rp, resourceProviders)
    {
        P<ResourceStream> stream = rp->getResourceStream(filename);
        if (stream)
            return stream;
    }
    return NULL;
}

std::vector<string> findResources(string searchPattern)
{
    std::vector<string> foundFiles;
    foreach(ResourceProvider, rp, resourceProviders)
    {
        std::vector<string> res = rp->findResources(searchPattern);
        foundFiles.insert(foundFiles.end(), res.begin(), res.end());
    }
    return foundFiles;
}
<commit_msg>Fix mingw build<commit_after>#include "resources.h"

#include <SFML/System.hpp>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dirent.h>
#endif
#include <cstdio>

PVector<ResourceProvider> resourceProviders;

ResourceProvider::ResourceProvider()
{
    resourceProviders.push_back(this);
}

bool ResourceProvider::searchMatch(const string name, const string searchPattern)
{
    std::vector<string> parts = searchPattern.split("*");
    int pos = 0;
    if (parts[0].length() > 0)
    {
        if (name.find(parts[0]) != 0)
            return false;
    }
    for(unsigned int n=1; n<parts.size(); n++)
    {
        int offset = name.find(parts[n], pos);
        if (offset < 0)
            return false;
        pos = offset + parts[n].length();
    }
    return pos == int(name.length());
}

string ResourceStream::readLine()
{
    string ret;
    char c;
    while(true)
    {
        if (read(&c, 1) < 1)
            return ret;
        if (c == '\n')
            return ret;
        ret += string(c);
    }
}

class FileResourceStream : public ResourceStream
{
    sf::FileInputStream stream;
    bool open_success;
public:
    FileResourceStream(string filename)
    {
        open_success = stream.open(filename);
    }
    virtual ~FileResourceStream()
    {
    }

    bool isOpen()
    {
        return open_success;
    }

    virtual sf::Int64 read(void* data, sf::Int64 size)
    {
        return stream.read(data, size);
    }
    virtual sf::Int64 seek(sf::Int64 position)
    {
        return stream.seek(position);
    }
    virtual sf::Int64 tell()
    {
        return stream.tell();
    }
    virtual sf::Int64 getSize()
    {
        return stream.getSize();
    }
};

DirectoryResourceProvider::DirectoryResourceProvider(string basepath)
: basepath(basepath)
{
}

P<ResourceStream> DirectoryResourceProvider::getResourceStream(string filename)
{
    P<FileResourceStream> stream = new FileResourceStream(basepath + filename);
    if (stream->isOpen())
        return stream;
    return nullptr;
}

std::vector<string> DirectoryResourceProvider::findResources(string searchPattern)
{
    std::vector<string> found_files;
    findResources(found_files, "", searchPattern);
    return found_files;
}

void DirectoryResourceProvider::findResources(std::vector<string>& found_files, const string path, const string searchPattern)
{
#ifdef _WIN32
    WIN32_FIND_DATAA data;
    string search_root(basepath + path);
    if (!search_root.endswith("/"))
    {
        search_root += "/";
    }
    HANDLE handle = FindFirstFileA((search_root + "*").c_str(), &data);
    if (handle == INVALID_HANDLE_VALUE)
        return;
    do
    {
        if (data.cFileName[0] == '.')
            continue;
        string name = path + string(data.cFileName);
        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            findResources(found_files, name + "/", searchPattern);
        }
        else
        {
            if (searchMatch(name, searchPattern))
                found_files.push_back(name);
        }
    } while (FindNextFileA(handle, &data));

    FindClose(handle);
#else
    DIR* dir = opendir((basepath + path).c_str());
    if (!dir)
        return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != nullptr)
    {
        if (entry->d_name[0] == '.')
            continue;
        string name = path + string(entry->d_name);
        if (searchMatch(name, searchPattern))
            found_files.push_back(name);
        findResources(found_files, path + string(entry->d_name) + "/", searchPattern);
    }
    closedir(dir);
#endif
}

P<ResourceStream> getResourceStream(string filename)
{
    foreach(ResourceProvider, rp, resourceProviders)
    {
        P<ResourceStream> stream = rp->getResourceStream(filename);
        if (stream)
            return stream;
    }
    return NULL;
}

std::vector<string> findResources(string searchPattern)
{
    std::vector<string> foundFiles;
    foreach(ResourceProvider, rp, resourceProviders)
    {
        std::vector<string> res = rp->findResources(searchPattern);
        foundFiles.insert(foundFiles.end(), res.begin(), res.end());
    }
    return foundFiles;
}
<|endoftext|>


<commit_before>#include "GlobalActionHelper.h"

#include <qt_windows.h>

#include <QDebug>
#include <QApplication>

QHash<QPair<quint32, quint32>, QAction *> GlobalActionHelper::actions_;

bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
                                            void *message, long *result) {
  Q_UNUSED (eventType);
  Q_UNUSED (result);
  MSG *msg = static_cast<MSG *>(message);
  if (msg->message == WM_HOTKEY) {
    const quint32 keycode = HIWORD (msg->lParam);
    const quint32 modifiers = LOWORD (msg->lParam);
    QAction *action = actions_.value (qMakePair (keycode, modifiers));
    Q_CHECK_PTR (action);
    action->activate (QAction::Trigger);
  }
  return false;
}

void GlobalActionHelper::init () {
  qApp->installNativeEventFilter (new GlobalActionHelper);
}

bool GlobalActionHelper::makeGlobal (QAction *action) {
  QKeySequence hotKey = action->shortcut ();
  if (hotKey.isEmpty ()) {
    return true;
  }
  Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
                                  Qt::AltModifier | Qt::MetaModifier;
  Qt::Key key = hotKey.isEmpty () ?
                Qt::Key (0) :
                Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
  Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
                               Qt::KeyboardModifiers (0) :
                               Qt::KeyboardModifiers (hotKey[0] & allMods);
  const quint32 nativeKey = nativeKeycode (key);
  const quint32 nativeMods = nativeModifiers (mods);
  const bool res = registerHotKey (nativeKey, nativeMods);
  if (res) {
    actions_.insert (qMakePair (nativeKey, nativeMods), action);
  }
  else {
    qWarning () << "Failed to register global hotkey:" << hotKey.toString ();
  }
  return res;
}

bool GlobalActionHelper::removeGlobal (QAction *action) {
  QKeySequence hotKey = action->shortcut ();
  if (hotKey.isEmpty ()) {
    return true;
  }
  Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
                                  Qt::AltModifier | Qt::MetaModifier;
  Qt::Key key = hotKey.isEmpty () ?
                Qt::Key (0) :
                Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
  Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
                               Qt::KeyboardModifiers (0) :
                               Qt::KeyboardModifiers (hotKey[0] & allMods);
  const quint32 nativeKey = nativeKeycode (key);
  const quint32 nativeMods = nativeModifiers (mods);
  if (!actions_.contains (qMakePair (nativeKey, nativeMods))) {
    return true;
  }
  const bool res = unregisterHotKey (nativeKey, nativeMods);
  if (res) {
    actions_.remove (qMakePair (nativeKey, nativeMods));
  }
  else {
    qWarning () << "Failed to unregister global hotkey:" << hotKey.toString ();
  }
  return res;
}

quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
  switch (key) {
    case Qt::Key_Escape:
      return VK_ESCAPE;
    case Qt::Key_Tab:
    case Qt::Key_Backtab:
      return VK_TAB;
    case Qt::Key_Backspace:
      return VK_BACK;
    case Qt::Key_Return:
    case Qt::Key_Enter:
      return VK_RETURN;
    case Qt::Key_Insert:
      return VK_INSERT;
    case Qt::Key_Delete:
      return VK_DELETE;
    case Qt::Key_Pause:
      return VK_PAUSE;
    case Qt::Key_Print:
      return VK_PRINT;
    case Qt::Key_Clear:
      return VK_CLEAR;
    case Qt::Key_Home:
      return VK_HOME;
    case Qt::Key_End:
      return VK_END;
    case Qt::Key_Left:
      return VK_LEFT;
    case Qt::Key_Up:
      return VK_UP;
    case Qt::Key_Right:
      return VK_RIGHT;
    case Qt::Key_Down:
      return VK_DOWN;
    case Qt::Key_PageUp:
      return VK_PRIOR;
    case Qt::Key_PageDown:
      return VK_NEXT;
    case Qt::Key_F1:
      return VK_F1;
    case Qt::Key_F2:
      return VK_F2;
    case Qt::Key_F3:
      return VK_F3;
    case Qt::Key_F4:
      return VK_F4;
    case Qt::Key_F5:
      return VK_F5;
    case Qt::Key_F6:
      return VK_F6;
    case Qt::Key_F7:
      return VK_F7;
    case Qt::Key_F8:
      return VK_F8;
    case Qt::Key_F9:
      return VK_F9;
    case Qt::Key_F10:
      return VK_F10;
    case Qt::Key_F11:
      return VK_F11;
    case Qt::Key_F12:
      return VK_F12;
    case Qt::Key_F13:
      return VK_F13;
    case Qt::Key_F14:
      return VK_F14;
    case Qt::Key_F15:
      return VK_F15;
    case Qt::Key_F16:
      return VK_F16;
    case Qt::Key_F17:
      return VK_F17;
    case Qt::Key_F18:
      return VK_F18;
    case Qt::Key_F19:
      return VK_F19;
    case Qt::Key_F20:
      return VK_F20;
    case Qt::Key_F21:
      return VK_F21;
    case Qt::Key_F22:
      return VK_F22;
    case Qt::Key_F23:
      return VK_F23;
    case Qt::Key_F24:
      return VK_F24;
    case Qt::Key_Space:
      return VK_SPACE;
    case Qt::Key_Asterisk:
      return VK_MULTIPLY;
    case Qt::Key_Plus:
      return VK_ADD;
    case Qt::Key_Comma:
      return VK_SEPARATOR;
    case Qt::Key_Minus:
      return VK_SUBTRACT;
    case Qt::Key_Slash:
      return VK_DIVIDE;
    case Qt::Key_MediaNext:
      return VK_MEDIA_NEXT_TRACK;
    case Qt::Key_MediaPrevious:
      return VK_MEDIA_PREV_TRACK;
    case Qt::Key_MediaPlay:
      return VK_MEDIA_PLAY_PAUSE;
    case Qt::Key_MediaStop:
      return VK_MEDIA_STOP;
    // couldn't find those in VK_*
    //case Qt::Key_MediaLast:
    //case Qt::Key_MediaRecord:
    case Qt::Key_VolumeDown:
      return VK_VOLUME_DOWN;
    case Qt::Key_VolumeUp:
      return VK_VOLUME_UP;
    case Qt::Key_VolumeMute:
      return VK_VOLUME_MUTE;

    // numbers
    case Qt::Key_0:
    case Qt::Key_1:
    case Qt::Key_2:
    case Qt::Key_3:
    case Qt::Key_4:
    case Qt::Key_5:
    case Qt::Key_6:
    case Qt::Key_7:
    case Qt::Key_8:
    case Qt::Key_9:
      return key;

    // letters
    case Qt::Key_A:
    case Qt::Key_B:
    case Qt::Key_C:
    case Qt::Key_D:
    case Qt::Key_E:
    case Qt::Key_F:
    case Qt::Key_G:
    case Qt::Key_H:
    case Qt::Key_I:
    case Qt::Key_J:
    case Qt::Key_K:
    case Qt::Key_L:
    case Qt::Key_M:
    case Qt::Key_N:
    case Qt::Key_O:
    case Qt::Key_P:
    case Qt::Key_Q:
    case Qt::Key_R:
    case Qt::Key_S:
    case Qt::Key_T:
    case Qt::Key_U:
    case Qt::Key_V:
    case Qt::Key_W:
    case Qt::Key_X:
    case Qt::Key_Y:
    case Qt::Key_Z:
      return key;

    default:
      return 0;
  }
}

quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
  // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
  quint32 native = 0;
  if (modifiers & Qt::ShiftModifier) {
    native |= MOD_SHIFT;
  }
  if (modifiers & Qt::ControlModifier) {
    native |= MOD_CONTROL;
  }
  if (modifiers & Qt::AltModifier) {
    native |= MOD_ALT;
  }
  if (modifiers & Qt::MetaModifier) {
    native |= MOD_WIN;
  }
  //if (modifiers & Qt::KeypadModifier)
  //if (modifiers & Qt::GroupSwitchModifier)
  return native;
}

bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
  return RegisterHotKey (0, nativeMods ^ nativeKey, nativeMods, nativeKey);
}

bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
  return UnregisterHotKey (0, nativeMods ^ nativeKey);
}
<commit_msg>Added linux support.<commit_after>#include "GlobalActionHelper.h"

#include <QDebug>
#include <QApplication>

QHash<QPair<quint32, quint32>, QAction *> GlobalActionHelper::actions_;

void GlobalActionHelper::init () {
  qApp->installNativeEventFilter (new GlobalActionHelper);
}

bool GlobalActionHelper::makeGlobal (QAction *action) {
  QKeySequence hotKey = action->shortcut ();
  if (hotKey.isEmpty ()) {
    return true;
  }
  Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
                                  Qt::AltModifier | Qt::MetaModifier;
  Qt::Key key = hotKey.isEmpty () ?
                Qt::Key (0) :
                Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
  Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
                               Qt::KeyboardModifiers (0) :
                               Qt::KeyboardModifiers (hotKey[0] & allMods);
  const quint32 nativeKey = nativeKeycode (key);
  const quint32 nativeMods = nativeModifiers (mods);
  const bool res = registerHotKey (nativeKey, nativeMods);
  if (res) {
    actions_.insert (qMakePair (nativeKey, nativeMods), action);
  }
  else {
    qWarning () << "Failed to register global hotkey:" << hotKey.toString ();
  }
  return res;
}

bool GlobalActionHelper::removeGlobal (QAction *action) {
  QKeySequence hotKey = action->shortcut ();
  if (hotKey.isEmpty ()) {
    return true;
  }
  Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
                                  Qt::AltModifier | Qt::MetaModifier;
  Qt::Key key = hotKey.isEmpty () ?
                Qt::Key (0) :
                Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
  Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
                               Qt::KeyboardModifiers (0) :
                               Qt::KeyboardModifiers (hotKey[0] & allMods);
  const quint32 nativeKey = nativeKeycode (key);
  const quint32 nativeMods = nativeModifiers (mods);
  if (!actions_.contains (qMakePair (nativeKey, nativeMods))) {
    return true;
  }
  const bool res = unregisterHotKey (nativeKey, nativeMods);
  if (res) {
    actions_.remove (qMakePair (nativeKey, nativeMods));
  }
  else {
    qWarning () << "Failed to unregister global hotkey:" << hotKey.toString ();
  }
  return res;
}

#if defined(Q_OS_LINUX)
#  include <QX11Info>
#  include <X11/Xlib.h>
#  include <xcb/xcb_event.h>

static bool error = false;

static int customHandler (Display *display, XErrorEvent *event) {
  Q_UNUSED (display);
  switch (event->error_code) {
    case BadAccess:
    case BadValue:
    case BadWindow:
      if (event->request_code == 33 /* X_GrabKey */ ||
          event->request_code == 34 /* X_UngrabKey */) {
        error = true;
      }
    default:
      return 0;
  }
}

bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
  Display *display = QX11Info::display ();
  Window window = QX11Info::appRootWindow ();
  Bool owner = True;
  int pointer = GrabModeAsync;
  int keyboard = GrabModeAsync;
  error = false;
  int (*handler)(Display *display, XErrorEvent *event) = XSetErrorHandler (customHandler);
  XGrabKey (display, nativeKey, nativeMods, window, owner, pointer, keyboard);
  // allow numlock
  XGrabKey (display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer, keyboard);
  XSync (display, False);
  XSetErrorHandler (handler);
  return !error;
}

bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
  Display *display = QX11Info::display ();
  Window window = QX11Info::appRootWindow ();
  error = false;
  int (*handler)(Display *display, XErrorEvent *event) = XSetErrorHandler (customHandler);
  XUngrabKey (display, nativeKey, nativeMods, window);
  // allow numlock
  XUngrabKey (display, nativeKey, nativeMods | Mod2Mask, window);
  XSync (display, False);
  XSetErrorHandler (handler);
  return !error;
}

bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
                                            void *message, long *result) {
  Q_UNUSED (eventType);
  Q_UNUSED (result);
  xcb_generic_event_t *event = static_cast<xcb_generic_event_t *>(message);
  if (event->response_type == XCB_KEY_PRESS) {
    xcb_key_press_event_t *keyEvent = static_cast<xcb_key_press_event_t *>(message);
    const quint32 keycode = keyEvent->detail;
    const quint32 modifiers = keyEvent->state & ~XCB_MOD_MASK_2;
    QAction *action = actions_.value (qMakePair (keycode, modifiers));
    if (action) {
      action->activate (QAction::Trigger);
    }
  }
  return false;
}

quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
  Display *display = QX11Info::display ();
  KeySym keySym =  XStringToKeysym (qPrintable (QKeySequence (key).toString ()));
  return XKeysymToKeycode (display, keySym);
}

quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
  quint32 native = 0;
  if (modifiers & Qt::ShiftModifier) {
    native |= ShiftMask;
  }
  if (modifiers & Qt::ControlModifier) {
    native |= ControlMask;
  }
  if (modifiers & Qt::AltModifier) {
    native |= Mod1Mask;
  }
  if (modifiers & Qt::MetaModifier) {
    native |= Mod4Mask;
  }
  return native;
}

#elif defined(Q_OS_WIN)
#  include <qt_windows.h>

bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
  return RegisterHotKey (0, nativeMods ^ nativeKey, nativeMods, nativeKey);
}

bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
  return UnregisterHotKey (0, nativeMods ^ nativeKey);
}

bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
                                            void *message, long *result) {
  Q_UNUSED (eventType);
  Q_UNUSED (result);
  MSG *msg = static_cast<MSG *>(message);
  if (msg->message == WM_HOTKEY) {
    const quint32 keycode = HIWORD (msg->lParam);
    const quint32 modifiers = LOWORD (msg->lParam);
    QAction *action = actions_.value (qMakePair (keycode, modifiers));
    if (action) {
      action->activate (QAction::Trigger);
    }
  }
  return false;
}

quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
  switch (key) {
    case Qt::Key_Escape:
      return VK_ESCAPE;
    case Qt::Key_Tab:
    case Qt::Key_Backtab:
      return VK_TAB;
    case Qt::Key_Backspace:
      return VK_BACK;
    case Qt::Key_Return:
    case Qt::Key_Enter:
      return VK_RETURN;
    case Qt::Key_Insert:
      return VK_INSERT;
    case Qt::Key_Delete:
      return VK_DELETE;
    case Qt::Key_Pause:
      return VK_PAUSE;
    case Qt::Key_Print:
      return VK_PRINT;
    case Qt::Key_Clear:
      return VK_CLEAR;
    case Qt::Key_Home:
      return VK_HOME;
    case Qt::Key_End:
      return VK_END;
    case Qt::Key_Left:
      return VK_LEFT;
    case Qt::Key_Up:
      return VK_UP;
    case Qt::Key_Right:
      return VK_RIGHT;
    case Qt::Key_Down:
      return VK_DOWN;
    case Qt::Key_PageUp:
      return VK_PRIOR;
    case Qt::Key_PageDown:
      return VK_NEXT;
    case Qt::Key_F1:
      return VK_F1;
    case Qt::Key_F2:
      return VK_F2;
    case Qt::Key_F3:
      return VK_F3;
    case Qt::Key_F4:
      return VK_F4;
    case Qt::Key_F5:
      return VK_F5;
    case Qt::Key_F6:
      return VK_F6;
    case Qt::Key_F7:
      return VK_F7;
    case Qt::Key_F8:
      return VK_F8;
    case Qt::Key_F9:
      return VK_F9;
    case Qt::Key_F10:
      return VK_F10;
    case Qt::Key_F11:
      return VK_F11;
    case Qt::Key_F12:
      return VK_F12;
    case Qt::Key_F13:
      return VK_F13;
    case Qt::Key_F14:
      return VK_F14;
    case Qt::Key_F15:
      return VK_F15;
    case Qt::Key_F16:
      return VK_F16;
    case Qt::Key_F17:
      return VK_F17;
    case Qt::Key_F18:
      return VK_F18;
    case Qt::Key_F19:
      return VK_F19;
    case Qt::Key_F20:
      return VK_F20;
    case Qt::Key_F21:
      return VK_F21;
    case Qt::Key_F22:
      return VK_F22;
    case Qt::Key_F23:
      return VK_F23;
    case Qt::Key_F24:
      return VK_F24;
    case Qt::Key_Space:
      return VK_SPACE;
    case Qt::Key_Asterisk:
      return VK_MULTIPLY;
    case Qt::Key_Plus:
      return VK_ADD;
    case Qt::Key_Comma:
      return VK_SEPARATOR;
    case Qt::Key_Minus:
      return VK_SUBTRACT;
    case Qt::Key_Slash:
      return VK_DIVIDE;
    case Qt::Key_MediaNext:
      return VK_MEDIA_NEXT_TRACK;
    case Qt::Key_MediaPrevious:
      return VK_MEDIA_PREV_TRACK;
    case Qt::Key_MediaPlay:
      return VK_MEDIA_PLAY_PAUSE;
    case Qt::Key_MediaStop:
      return VK_MEDIA_STOP;
    case Qt::Key_VolumeDown:
      return VK_VOLUME_DOWN;
    case Qt::Key_VolumeUp:
      return VK_VOLUME_UP;
    case Qt::Key_VolumeMute:
      return VK_VOLUME_MUTE;

    // numbers
    case Qt::Key_0:
    case Qt::Key_1:
    case Qt::Key_2:
    case Qt::Key_3:
    case Qt::Key_4:
    case Qt::Key_5:
    case Qt::Key_6:
    case Qt::Key_7:
    case Qt::Key_8:
    case Qt::Key_9:
      return key;

    // letters
    case Qt::Key_A:
    case Qt::Key_B:
    case Qt::Key_C:
    case Qt::Key_D:
    case Qt::Key_E:
    case Qt::Key_F:
    case Qt::Key_G:
    case Qt::Key_H:
    case Qt::Key_I:
    case Qt::Key_J:
    case Qt::Key_K:
    case Qt::Key_L:
    case Qt::Key_M:
    case Qt::Key_N:
    case Qt::Key_O:
    case Qt::Key_P:
    case Qt::Key_Q:
    case Qt::Key_R:
    case Qt::Key_S:
    case Qt::Key_T:
    case Qt::Key_U:
    case Qt::Key_V:
    case Qt::Key_W:
    case Qt::Key_X:
    case Qt::Key_Y:
    case Qt::Key_Z:
      return key;

    default:
      return 0;
  }
}

quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
  // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
  quint32 native = 0;
  if (modifiers & Qt::ShiftModifier) {
    native |= MOD_SHIFT;
  }
  if (modifiers & Qt::ControlModifier) {
    native |= MOD_CONTROL;
  }
  if (modifiers & Qt::AltModifier) {
    native |= MOD_ALT;
  }
  if (modifiers & Qt::MetaModifier) {
    native |= MOD_WIN;
  }
  //if (modifiers & Qt::KeypadModifier)
  //if (modifiers & Qt::GroupSwitchModifier)
  return native;
}
#endif
<|endoftext|>


<commit_before>/*
 * File:   Renderer.cpp
 * Author: morgan
 *
 * Created on February 15, 2014, 2:37 PM
 */

#include <ogli/util.h>
#include <glm/gtx/projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtx/transform2.hpp>
#include <glm/gtc/random.hpp>

#include "Renderer.h"
#include "Vertex.h"
#include "Mesh.h"
#include "Texture2D.h"
#include "Model.h"

namespace mo {

    Renderer::Renderer() :
    position_attribute_3P3N2UV_(0, 3, "position", sizeof (Vertex), sizeof (glm::vec3), 0),
    normal_attribute_3P3N2UV_(1, 3, "normal", sizeof (Vertex), sizeof (glm::vec3), sizeof (glm::vec3)),
    uv_attribute_3P3N2UV_(2, 2, "uv", sizeof (Vertex), sizeof (glm::vec2), sizeof (glm::vec3) + sizeof (glm::vec3)) {
        ogli::init(); // Should this be done int ogli or mo?

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glDepthMask(true);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        standard_vertex_source_ = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "uniform mat4 model_view_projection;\n"
                "uniform mat4 model_view;\n"
                "attribute vec3 position;\n"
                "attribute vec3 normal;\n"
                "attribute vec2 uv;\n"
                "varying vec3 v_position;\n"
                "varying vec3 v_normal\n;"
                "varying vec3 v_position2;\n"
                "varying vec2 v_uv;\n"
                "void main()\n"
                "{\n"
                "    v_uv = uv;\n"
                "    v_position2 = normalize((model_view_projection * vec4(position, 1.0)).xyz);\n"
                "    v_position = (model_view * vec4(position, 0.0)).xyz;\n"
                "    v_normal = normalize((model_view * vec4(normal, 0.0)).xyz);\n"
                "    gl_Position = model_view_projection * vec4(position, 1.0);\n"
                "}\n";

        standard_fragment_source_ = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "uniform vec4 color;\n"
                "uniform float opacity;\n"
                "uniform sampler2D texture;\n"
                "varying vec3 v_position;\n"
                "varying vec3 v_normal;\n"
                "varying vec3 v_position2;\n"
                "varying vec2 v_uv;\n"
                "void main() {\n"
                "vec3 ambient = vec3(0.3, 0.3, 0.3);\n"
                "float d = (v_position.z + 100.0)/5000.0;\n"

                "vec3 light = normalize(vec3(0.0, 500.0, 100.0) - v_position2);\n"
                "float intensity = max(dot(v_normal,light), 0.0) * 0.2;\n"

                "vec3 indirect = texture2D(texture, v_uv).rgb;\n"

                "gl_FragColor = vec4(indirect + intensity, 1.0*opacity);\n"
                "//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"

                "}\n";

        addProgram("standard", standard_vertex_source_, standard_fragment_source_);

        std::string text_vertex_source = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "uniform mat4 model_view_projection;\n"
                "uniform mat4 model_view;\n"
                "attribute vec3 position;\n"
                "attribute vec2 uv;\n"

                "varying vec2 v_position;\n"
                "varying vec2 v_uv;\n"

                "void main(){\n"
                "v_position = (model_view * vec4(position, 0.0)).xy;\n"
                "v_uv = uv;\n"
                "gl_Position = model_view_projection * vec4(position, 1.0);\n"
                "}\n";

        std::string text_fragment_source = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "varying vec3 v_position;\n"
                "varying vec2 v_uv;\n"
                "uniform sampler2D texture;\n"
                "uniform float opacity;\n"

                "void main() {\n"
                "gl_FragColor = texture2D(texture, v_uv);\n"
                "//gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
                "}\n";
        addProgram("text", text_vertex_source, text_fragment_source);
    }

    Renderer::~Renderer() {
    }

    void Renderer::addProgram(const std::string path, const std::string vertex_shader_source, const std::string fragment_shader_source) {
        auto vertex_shader = ogli::createShader(vertex_shader_source, GL_VERTEX_SHADER);
        auto fragment_shader = ogli::createShader(fragment_shader_source, GL_FRAGMENT_SHADER);

        auto program = ogli::createProgram();
        ogli::attachShader(program, vertex_shader);
        ogli::attachShader(program, fragment_shader);
        ogli::bindAttribute(program, position_attribute_3P3N2UV_);
        ogli::bindAttribute(program, normal_attribute_3P3N2UV_);
        ogli::bindAttribute(program, uv_attribute_3P3N2UV_);

        ogli::linkProgram(program);

        auto mvp_uniform = ogli::createUniform(program, "model_view_projection");
        auto mv_uniform = ogli::createUniform(program, "model_view");
        auto texture_uniform = ogli::createUniform(program, "texture");
        auto opacity_uniform = ogli::createUniform(program, "opacity");

        programs_.insert(ProgramPair(path, ProgramData{program, mvp_uniform, mv_uniform, texture_uniform, opacity_uniform}));
    }

    void Renderer::addProgram(const std::string path) {
        addProgram(path, ogli::loadText(path + ".vs"), ogli::loadText(path + ".fs"));
    }

    void Renderer::clear(const glm::vec3 color) {
        ogli::clearDepth(1.0f);
        ogli::clearColor(glm::vec4(color.r, color.g, color.b, 0.0f));
    }

    void Renderer::render(const Model & model, const glm::mat4 transform, const glm::mat4 view, const glm::mat4 projection, const float opacity, const std::string program_name) {
        if (array_buffers_.find(model.mesh->id()) == array_buffers_.end()) {
            array_buffers_.insert(ArrayPair(model.mesh->id(),
                    ogli::createArrayBuffer(model.mesh->verticesBegin(), model.mesh->verticesEnd())));
        }
        if (element_array_buffers_.find(model.mesh->id()) == element_array_buffers_.end()) {
            element_array_buffers_.insert(ElementPair(model.mesh->id(),
                    ogli::createElementArrayBuffer(model.mesh->elementsBegin(), model.mesh->elementsEnd())));
        }

        if (textures_.find(model.texture->id()) == textures_.end()) {
            ogli::TextureBuffer texture = ogli::createTexture(model.texture->begin(), model.texture->end(), model.texture->width(), model.texture->height());
            textures_.insert(std::pair<unsigned int, ogli::TextureBuffer>(model.texture->id(), texture));
        }

        glm::mat4 mv = projection * view;
        glm::mat4 mvp = projection * view * transform * model.transform();

        //ogli::useProgram(standard_program_);

        ogli::useProgram(programs_.at(program_name).program);

        //ogli::useProgram(std::get<0>(programs_.at(program_name)));
        ogli::bindBuffer(array_buffers_.at(model.mesh->id()));
        ogli::bindBuffer(element_array_buffers_.at(model.mesh->id()));

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures_.at(model.texture->id()));

        //TODO: General lighting, this is a hack.
        glm::mat3 rot_mat(view);
        glm::vec3 dir(view[3]);

        glm::vec3 camera_pos = -dir * rot_mat;

        ogli::uniform(programs_.at(program_name).mvp, mvp);
        ogli::uniform(programs_.at(program_name).mv, mv);
        ogli::uniform(programs_.at(program_name).texture);
        ogli::uniform(programs_.at(program_name).opacity, opacity);

        ogli::attribute(position_attribute_3P3N2UV_);
        ogli::attribute(normal_attribute_3P3N2UV_);
        ogli::attribute(uv_attribute_3P3N2UV_);
        int num_elements = std::distance(model.mesh->elementsBegin(), model.mesh->elementsEnd());
        if (num_elements > 0){
            ogli::drawElements(num_elements);
        }
        else {
            ogli::drawArrays(std::distance(model.mesh->verticesBegin(), model.mesh->verticesEnd()));
        }
        if (!model.valid()) {
            ogli::updateArrayBuffer(array_buffers_.at(model.mesh->id()), model.mesh->verticesBegin(), model.mesh->verticesEnd());
        }
    }

}<commit_msg>Renderer.<commit_after>/*
 * File:   Renderer.cpp
 * Author: morgan
 *
 * Created on February 15, 2014, 2:37 PM
 */

#include <ogli/util.h>
#include <glm/gtx/projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtx/transform2.hpp>
#include <glm/gtc/random.hpp>

#include "Renderer.h"
#include "Vertex.h"
#include "Mesh.h"
#include "Texture2D.h"
#include "Model.h"

namespace mo {

    Renderer::Renderer() :
    position_attribute_3P3N2UV_(0, 3, "position", sizeof (Vertex), sizeof (glm::vec3), 0),
    normal_attribute_3P3N2UV_(1, 3, "normal", sizeof (Vertex), sizeof (glm::vec3), sizeof (glm::vec3)),
    uv_attribute_3P3N2UV_(2, 2, "uv", sizeof (Vertex), sizeof (glm::vec2), sizeof (glm::vec3) + sizeof (glm::vec3)) {
        ogli::init(); // Should this be done int ogli or mo?

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glDepthMask(true);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        standard_vertex_source_ = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "uniform mat4 model_view_projection;\n"
                "uniform mat4 model_view;\n"
                "attribute vec3 position;\n"
                "attribute vec3 normal;\n"
                "attribute vec2 uv;\n"
                "varying vec3 v_position;\n"
                "varying vec3 v_normal\n;"
                "varying vec3 v_position2;\n"
                "varying vec2 v_uv;\n"
                "void main()\n"
                "{\n"
                "    v_uv = uv;\n"
                "    v_position2 = normalize((model_view_projection * vec4(position, 1.0)).xyz);\n"
                "    v_position = (model_view * vec4(position, 0.0)).xyz;\n"
                "    v_normal = normalize((model_view * vec4(normal, 0.0)).xyz);\n"
                "    gl_Position = model_view_projection * vec4(position, 1.0);\n"
                "}\n";

        standard_fragment_source_ = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "uniform vec4 color;\n"
                "uniform float opacity;\n"
                "uniform sampler2D texture;\n"
                "varying vec3 v_position;\n"
                "varying vec3 v_normal;\n"
                "varying vec3 v_position2;\n"
                "varying vec2 v_uv;\n"
                "void main() {\n"
                "vec3 ambient = vec3(0.3, 0.3, 0.3);\n"
                "float d = (v_position.z + 100.0)/5000.0;\n"

                "vec3 light = normalize(vec3(0.0, 500.0, 100.0) - v_position2);\n"
                "float intensity = max(dot(v_normal,light), 0.0) * 0.2;\n"

                "vec3 indirect = texture2D(texture, v_uv).rgb;\n"

                "gl_FragColor = vec4(indirect + intensity, 1.0*opacity);\n"
                "//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"

                "}\n";

        addProgram("standard", standard_vertex_source_, standard_fragment_source_);

        std::string text_vertex_source = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "uniform mat4 model_view_projection;\n"
                "uniform mat4 model_view;\n"
                "attribute vec3 position;\n"
                "attribute vec2 uv;\n"

                "varying vec2 v_position;\n"
                "varying vec2 v_uv;\n"

                "void main(){\n"
                "v_position = (model_view * vec4(position, 0.0)).xy;\n"
                "v_uv = uv;\n"
                "gl_Position = model_view_projection * vec4(position, 1.0);\n"
                "}\n";

        std::string text_fragment_source = "#ifdef GL_ES\n"
                "precision mediump float;\n"
                "precision mediump int;\n"
                "#endif\n"
                "varying vec3 v_position;\n"
                "varying vec2 v_uv;\n"
                "uniform sampler2D texture;\n"
                "uniform float opacity;\n"

                "void main() {\n"
                "gl_FragColor = texture2D(texture, v_uv);\n"
                "gl_FragColor.w = gl_FragColor.w * opacity;\n"
                "//gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
                "}\n";
        addProgram("text", text_vertex_source, text_fragment_source);
    }

    Renderer::~Renderer() {
    }

    void Renderer::addProgram(const std::string path, const std::string vertex_shader_source, const std::string fragment_shader_source) {
        auto vertex_shader = ogli::createShader(vertex_shader_source, GL_VERTEX_SHADER);
        auto fragment_shader = ogli::createShader(fragment_shader_source, GL_FRAGMENT_SHADER);

        auto program = ogli::createProgram();
        ogli::attachShader(program, vertex_shader);
        ogli::attachShader(program, fragment_shader);
        ogli::bindAttribute(program, position_attribute_3P3N2UV_);
        ogli::bindAttribute(program, normal_attribute_3P3N2UV_);
        ogli::bindAttribute(program, uv_attribute_3P3N2UV_);

        ogli::linkProgram(program);

        auto mvp_uniform = ogli::createUniform(program, "model_view_projection");
        auto mv_uniform = ogli::createUniform(program, "model_view");
        auto texture_uniform = ogli::createUniform(program, "texture");
        auto opacity_uniform = ogli::createUniform(program, "opacity");

        programs_.insert(ProgramPair(path, ProgramData{program, mvp_uniform, mv_uniform, texture_uniform, opacity_uniform}));
    }

    void Renderer::addProgram(const std::string path) {
        addProgram(path, ogli::loadText(path + ".vs"), ogli::loadText(path + ".fs"));
    }

    void Renderer::clear(const glm::vec3 color) {
        ogli::clearDepth(1.0f);
        ogli::clearColor(glm::vec4(color.r, color.g, color.b, 0.0f));
    }

    void Renderer::render(const Model & model, const glm::mat4 transform, const glm::mat4 view, const glm::mat4 projection, const float opacity, const std::string program_name) {
        if (array_buffers_.find(model.mesh->id()) == array_buffers_.end()) {
            array_buffers_.insert(ArrayPair(model.mesh->id(),
                    ogli::createArrayBuffer(model.mesh->verticesBegin(), model.mesh->verticesEnd())));
        }
        if (element_array_buffers_.find(model.mesh->id()) == element_array_buffers_.end()) {
            element_array_buffers_.insert(ElementPair(model.mesh->id(),
                    ogli::createElementArrayBuffer(model.mesh->elementsBegin(), model.mesh->elementsEnd())));
        }

        if (textures_.find(model.texture->id()) == textures_.end()) {
            ogli::TextureBuffer texture = ogli::createTexture(model.texture->begin(), model.texture->end(), model.texture->width(), model.texture->height());
            textures_.insert(std::pair<unsigned int, ogli::TextureBuffer>(model.texture->id(), texture));
        }

        glm::mat4 mv = projection * view;
        glm::mat4 mvp = projection * view * transform * model.transform();

        //ogli::useProgram(standard_program_);

        ogli::useProgram(programs_.at(program_name).program);

        //ogli::useProgram(std::get<0>(programs_.at(program_name)));
        ogli::bindBuffer(array_buffers_.at(model.mesh->id()));
        ogli::bindBuffer(element_array_buffers_.at(model.mesh->id()));

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures_.at(model.texture->id()));

        //TODO: General lighting, this is a hack.
        glm::mat3 rot_mat(view);
        glm::vec3 dir(view[3]);

        glm::vec3 camera_pos = -dir * rot_mat;

        ogli::uniform(programs_.at(program_name).mvp, mvp);
        ogli::uniform(programs_.at(program_name).mv, mv);
        ogli::uniform(programs_.at(program_name).texture);
        ogli::uniform(programs_.at(program_name).opacity, opacity);

        ogli::attribute(position_attribute_3P3N2UV_);
        ogli::attribute(normal_attribute_3P3N2UV_);
        ogli::attribute(uv_attribute_3P3N2UV_);
        int num_elements = std::distance(model.mesh->elementsBegin(), model.mesh->elementsEnd());
        if (num_elements > 0){
            ogli::drawElements(num_elements);
        }
        else {
            ogli::drawArrays(std::distance(model.mesh->verticesBegin(), model.mesh->verticesEnd()));
        }
        if (!model.valid()) {
            ogli::updateArrayBuffer(array_buffers_.at(model.mesh->id()), model.mesh->verticesBegin(), model.mesh->verticesEnd());
        }
    }

}<|endoftext|>


<commit_before>/* * This file is part of meego-im-framework *
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * Contact: Nokia Corporation (directui@nokia.com)
 *
 * If you have questions regarding the use of this file, please contact
 * Nokia at directui@nokia.com.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

#include "mimrotationanimation.h"
#include "qdebug.h"
#include "mimremotewindow.h"
#include "mimxapplication.h"
#include "mpassthruwindow.h"

#include <QBitmap>
#include <QDesktopWidget>
#include <QGraphicsScene>
#include <QObject>
#include <QPropertyAnimation>
#include <QResizeEvent>
#include <QX11Info>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

SnapshotPixmapItem::SnapshotPixmapItem(QGraphicsItem *parent) :
        QObject(),
        QGraphicsPixmapItem(parent)
{
}

SnapshotPixmapItem::SnapshotPixmapItem(QPixmap pixmap, QGraphicsItem *parent) :
        QObject(),
        QGraphicsPixmapItem(pixmap, parent)
{
}

SnapshotPixmapItem::~SnapshotPixmapItem() {}

MImDamageMonitor::MImDamageMonitor(MImRemoteWindow* remoteWin,
                                   QObject* parent) :
    QObject(parent),
    timeoutTimer(),
    damageDetected(false)
{
    timeoutTimer.setInterval(1000);
    timeoutTimer.setSingleShot(true);
    connect(&timeoutTimer,SIGNAL(timeout()),
            this,SLOT(timeoutExpired()));

    remoteWindowChanged(remoteWin);
}

void
MImDamageMonitor::remoteWindowChanged(MImRemoteWindow *newRemoteWindow)
{
    remoteWindow = newRemoteWindow;
}

void
MImDamageMonitor::activate()
{
    damageDetected = false;
    // reset triggers
    cancel();
    connect(remoteWindow, SIGNAL(contentUpdated(QRegion)),
            this, SLOT(contentUpdated(QRegion)));
}

void
MImDamageMonitor::waitForDamage()
{
    timeoutTimer.start();
    if (damageDetected) {
        qDebug() << __PRETTY_FUNCTION__ << " - damage already received, emitting signal.";
        cancel();
        Q_EMIT damageReceivedOrTimeout();
    }
}

void
MImDamageMonitor::contentUpdated(QRegion)
{
    damageDetected = true;
    // Emit signal only after client called waitForDamage().
    if (timeoutTimer.isActive()) {
        qDebug() << __PRETTY_FUNCTION__ << " - damage received, emitting signal.";
        cancel();
        Q_EMIT damageReceivedOrTimeout();
    }
}

void
MImDamageMonitor::cancel()
{
    timeoutTimer.stop();
    if (remoteWindow) {
        disconnect(remoteWindow, SIGNAL(contentUpdated(QRegion)),
                   this, SLOT(contentUpdated(QRegion)));
    }
}

void
MImDamageMonitor::timeoutExpired()
{
    qDebug() << __PRETTY_FUNCTION__;
    cancel();
    Q_EMIT damageReceivedOrTimeout();
}

namespace {
    qreal rotateAngle(int startAngle, int endAngle) {
        // Special cases ensuring shortest rotation angle according to original code from
        // MCrossFadedOrientationAnimationPrivate::setRootElementRotationAnimationValues.
        if (startAngle == 270 && endAngle == 90) {
            return 180.0;
        } else if (startAngle == 180 && endAngle == 0) {
            return 180.0;
        } else if (startAngle == 270 && endAngle == 0) {
            return 90.0;
        } else if (startAngle == 0 && endAngle == 270) {
            return -90.0;
        } else {
            return endAngle - startAngle;
        }
    }
}

MImRotationAnimation::MImRotationAnimation(QWidget* snapshotWidget, QWidget* parent, MImXApplication *application) :
        QGraphicsView(new QGraphicsScene(), parent),
        snapshotWidget(snapshotWidget),
        remoteWindow(0),
        animationStartPixmapItem(0),
        animationEndPixmapItem(0),
        startOrientationAngle(0),
        currentOrientationAngle(0),
        aboutToChangeReceived(false),
        damageMonitor(0),
        mApplication(application)
{
    // Animation plays on top of a black backround,
    // covering up the underlying application.
    setBackgroundBrush(QBrush(Qt::black));

    // Get rid of Meegotouch decorations.
    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

    // Avoid drawing transparent pixel borders.
    setFrameShape(QFrame::NoFrame);

    // We do not want input focus for that window.
    setAttribute(Qt::WA_X11DoNotAcceptFocus);

    // Avoid a white flicker when popping up our
    // extra window for the animation.
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent);
    viewport()->setAttribute(Qt::WA_NoSystemBackground);
    viewport()->setAttribute(Qt::WA_OpaquePaintEvent);

    // Remove all animation elements from scene and hide.
    connect(&rotationAnimationGroup, SIGNAL(finished()),
            this, SLOT(clearScene()));

    connect(mApplication, SIGNAL(remoteWindowChanged(MImRemoteWindow*)),
            this, SLOT(remoteWindowChanged(MImRemoteWindow*)), Qt::UniqueConnection);

    damageMonitor = new MImDamageMonitor(remoteWindow, this);
    connect(damageMonitor, SIGNAL(damageReceivedOrTimeout()),
            this, SLOT(startAnimation()));

    hide();

    if (QApplication::desktop()) {
        resize(QApplication::desktop()->screenGeometry().size());
    }
}

void
MImRotationAnimation::cancelAnimation()
{
    // disableAnimation() slot is connected to passThruWindowUnmapped()
    // So, in order to be on the safe side. We clean the scene.
    if (rotationAnimationGroup.state() != QAbstractAnimation::Stopped) {
        rotationAnimationGroup.stop();
    }

    damageMonitor->cancel();
    clearScene();

    aboutToChangeReceived = false;
}

void
MImRotationAnimation::resizeEvent(QResizeEvent *event)
{
    setSceneRect(QRect(QPoint(0,0),event->size()));
}

void
MImRotationAnimation::setupScene()
{
    animationStartPixmapItem = new SnapshotPixmapItem(compositeWindowStart);
    // See crossfadedorientationanimationstyle.css for the origin of these values.
    animationStartPixmapItem->setTransformOriginPoint(240,240);
    animationStartPixmapItem->setPos(0,0);
    if (scene()) {
        scene()->addItem(animationStartPixmapItem);
    }
}

void
MImRotationAnimation::showInitial()
{
    show();
    // We need to be on the screen really fast, otherwise you would
    // see the meegotouch orientation change in the window under us.
    // Going through the event loop will take about 800ms, which is too long.
    // Thus, requesting a synchronous update here.
    // TODO: Not a perfect solution, in rare cases and high load situations
    // application is updating the screen faster than meego-im-uiserver.
    repaint();
}

void
MImRotationAnimation::showEvent(QShowEvent*) {
    // Setting _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_INPUT
    // prevents the underlying app from losing focus and
    // avoid window decorations such as the slide-in animation.
    static Atom input = XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE_INPUT", False);
    static Atom window_type = XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE", False);
    XChangeProperty(QX11Info::display(), effectiveWinId(), window_type, XA_ATOM, 32,
                    PropModeReplace, (unsigned char *) &input, 1);
}

void
MImRotationAnimation::setupAnimation(int fromAngle, int toAngle) {

    qreal hiddenOpacity = 0;
    qreal visibleOpacity = 1.0;

    // See crossfadedorientationanimationstyle.css for the origin of the animation parameters.
    int duration = 500;

    QPropertyAnimation* startAnimations[2];
    QPropertyAnimation* endAnimations[4];

    startAnimations[0] = new QPropertyAnimation();
    startAnimations[1] = new QPropertyAnimation();
    endAnimations[0] = new QPropertyAnimation();
    endAnimations[1] = new QPropertyAnimation();
    endAnimations[2] = new QPropertyAnimation();
    endAnimations[3] = new QPropertyAnimation();

    int initialRotationOfTarget = fromAngle - toAngle;
    int rotateBy = rotateAngle(fromAngle, toAngle);

    QPixmap remoteWindowPixmap;
    if (remoteWindow) {
        // This is the live pixmap of the application coming from X.
        // It stays live if it's used in read-only mode.
        remoteWindowPixmap = remoteWindow->windowPixmap();
    }
    animationEndPixmapItem = new SnapshotPixmapItem(remoteWindowPixmap);
    animationEndPixmapItem->setPos(0,0);
    animationEndPixmapItem->setTransformOriginPoint(240,240);
    animationEndPixmapItem->setRotation(initialRotationOfTarget);
    animationEndPixmapItem->setOpacity(hiddenOpacity);

    animationEndVkbOverlayItem = new SnapshotPixmapItem(grabVkbOnly());
    animationEndVkbOverlayItem->setPos(0,0);
    animationEndVkbOverlayItem->setTransformOriginPoint(240,240);
    animationEndVkbOverlayItem->setRotation(initialRotationOfTarget);
    animationEndVkbOverlayItem->setOpacity(hiddenOpacity);

    if (scene()) {
        scene()->addItem(animationEndPixmapItem);
        scene()->addItem(animationEndVkbOverlayItem);
    }

    startAnimations[0]->setPropertyName("rotation");
    startAnimations[0]->setStartValue(0);
    startAnimations[0]->setEndValue(rotateBy);
    startAnimations[0]->setEasingCurve(QEasingCurve::InOutExpo);
    startAnimations[0]->setDuration(duration);

    startAnimations[1]->setPropertyName("opacity");
    startAnimations[1]->setStartValue(visibleOpacity);
    startAnimations[1]->setEndValue(hiddenOpacity);
    startAnimations[1]->setEasingCurve(QEasingCurve::InOutExpo);
    startAnimations[1]->setDuration(duration);

    endAnimations[0]->setPropertyName("rotation");
    endAnimations[0]->setStartValue(initialRotationOfTarget);
    endAnimations[0]->setEndValue(initialRotationOfTarget+rotateBy);
    endAnimations[0]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[0]->setDuration(duration);

    endAnimations[1]->setPropertyName("opacity");
    endAnimations[1]->setStartValue(hiddenOpacity);
    endAnimations[1]->setEndValue(visibleOpacity);
    endAnimations[1]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[1]->setDuration(duration);

    // same for vkb overlay
    endAnimations[2]->setPropertyName("rotation");
    endAnimations[2]->setStartValue(initialRotationOfTarget);
    endAnimations[2]->setEndValue(initialRotationOfTarget+rotateBy);
    endAnimations[2]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[2]->setDuration(duration);

    endAnimations[3]->setPropertyName("opacity");
    endAnimations[3]->setStartValue(hiddenOpacity);
    endAnimations[3]->setEndValue(visibleOpacity);
    endAnimations[3]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[3]->setDuration(duration);

    startAnimations[0]->setTargetObject(animationStartPixmapItem);
    startAnimations[1]->setTargetObject(animationStartPixmapItem);
    endAnimations[0]->setTargetObject(animationEndPixmapItem);
    endAnimations[1]->setTargetObject(animationEndPixmapItem);
    endAnimations[2]->setTargetObject(animationEndVkbOverlayItem);
    endAnimations[3]->setTargetObject(animationEndVkbOverlayItem);

    rotationAnimationGroup.clear();
    rotationAnimationGroup.addAnimation(startAnimations[0]);
    rotationAnimationGroup.addAnimation(startAnimations[1]);
    rotationAnimationGroup.addAnimation(endAnimations[0]);
    rotationAnimationGroup.addAnimation(endAnimations[1]);
    rotationAnimationGroup.addAnimation(endAnimations[2]);
    rotationAnimationGroup.addAnimation(endAnimations[3]);
}

MImRotationAnimation::~MImRotationAnimation() {
    QGraphicsScene *myScene = scene();
    setScene(0);
    delete myScene;

    delete damageMonitor;
    damageMonitor = 0;

    rotationAnimationGroup.clear();
}

QPixmap
MImRotationAnimation::grabComposited()
{
    if (!remoteWindow || remoteWindow->windowPixmap().isNull()) {
        return QPixmap();
    }

    // Explicitly copying here since we want to paint the keyboard on top.
    // Qt is unable to render text into QPixmap, therefore we use QImage here.
    QImage grabImage(remoteWindow->windowPixmap().toImage());

    // Overlay keyboard, transparency not required
    QPainter painter(&grabImage);
    snapshotWidget->render(&painter,QPoint(0,0),QRect(0,0,width(),height()));

    return QPixmap::fromImage(grabImage);
}

QPixmap
MImRotationAnimation::grabVkbOnly()
{
    mApplication->setSuppressBackground(true);
    // We need to work with a QImage here, otherwise we lose the
    // transparency of the see-through part of the keyboard image.
    QImage grabImage(size(),QImage::Format_ARGB32);
    grabImage.fill(Qt::transparent);

    // Fill empty QImage with keyboard snapshot.
    QPainter painter(&grabImage);
    snapshotWidget->render(&painter,QPoint(0,0),QRect(0,0,width(),height()));
    // QPainter needs to be closed before returning
    // new QPixmap generated from QImage.
    painter.end();

    mApplication->setSuppressBackground(false);

    return QPixmap::fromImage(grabImage);
}

void
MImRotationAnimation::remoteWindowChanged(MImRemoteWindow* newRemoteWindow) {
    remoteWindow = newRemoteWindow;
    damageMonitor->remoteWindowChanged(newRemoteWindow);

    // Stop playing animations when underlying window is unmapped.
    if (!remoteWindow) {
        qDebug() << __PRETTY_FUNCTION__ << " - remote window gone, cancelling animation.";
        cancelAnimation();
    }
}

void
MImRotationAnimation::appOrientationAboutToChange(int toAngle) {
    qDebug() << __PRETTY_FUNCTION__ << " - toAngle: " << toAngle;

    if (!mApplication->passThruWindow()->isVisible()
        || toAngle == currentOrientationAngle
        || aboutToChangeReceived) {
        return;
    }
    startOrientationAngle = currentOrientationAngle;

    // Assuming that in self-composited case we don't need
    // extra redirection, we're already redirected.
    if (!mApplication->selfComposited() && remoteWindow) {
        remoteWindow->redirect();
    }

    // Capturing initial snapshot that's used for the beginning of the rotation.
    compositeWindowStart = grabComposited();

    // Do not do anything if no initial snapshot is available
    if (compositeWindowStart.isNull())
        return;

    // Clean up if we were still in the middle of a previous rotation animation.
    rotationAnimationGroup.stop();
    if (scene()) {
        scene()->clear();
    }

    setupScene();
    showInitial();

    damageMonitor->activate();

    // Unfortunately, we need to shield against appOrientationChangeFinishedEvents
    // that come in without a previous "AboutToChange" event.
    aboutToChangeReceived = true;
}

void
MImRotationAnimation::appOrientationChangeFinished(int toAngle) {
    qDebug() << __PRETTY_FUNCTION__ << " - toAngle: " << toAngle
            << " startOrientationAngle: " << startOrientationAngle;

    currentOrientationAngle = toAngle;

    if (!mApplication->passThruWindow()->isVisible()
        || toAngle == startOrientationAngle
        || !aboutToChangeReceived) {
        clearScene();
        aboutToChangeReceived = false;
        return;
    }

    setupAnimation(startOrientationAngle, toAngle);

    damageMonitor->waitForDamage();
}

void
MImRotationAnimation::startAnimation()
{
    qDebug() << __PRETTY_FUNCTION__;

    rotationAnimationGroup.start();
    aboutToChangeReceived = false;
}

void MImRotationAnimation::clearScene() {
    // When self-compositing is off, we don't need to maintain
    // the redirection.
    if (mApplication->selfComposited() && remoteWindow) {
        remoteWindow->unredirect();
    }

    hide();

    if (scene()) {
        scene()->clear();
    }

    compositeWindowStart = QPixmap();
}
<commit_msg>Fix unredirecting in self-compositing mode<commit_after>/* * This file is part of meego-im-framework *
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * Contact: Nokia Corporation (directui@nokia.com)
 *
 * If you have questions regarding the use of this file, please contact
 * Nokia at directui@nokia.com.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

#include "mimrotationanimation.h"
#include "qdebug.h"
#include "mimremotewindow.h"
#include "mimxapplication.h"
#include "mpassthruwindow.h"

#include <QBitmap>
#include <QDesktopWidget>
#include <QGraphicsScene>
#include <QObject>
#include <QPropertyAnimation>
#include <QResizeEvent>
#include <QX11Info>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

SnapshotPixmapItem::SnapshotPixmapItem(QGraphicsItem *parent) :
        QObject(),
        QGraphicsPixmapItem(parent)
{
}

SnapshotPixmapItem::SnapshotPixmapItem(QPixmap pixmap, QGraphicsItem *parent) :
        QObject(),
        QGraphicsPixmapItem(pixmap, parent)
{
}

SnapshotPixmapItem::~SnapshotPixmapItem() {}

MImDamageMonitor::MImDamageMonitor(MImRemoteWindow* remoteWin,
                                   QObject* parent) :
    QObject(parent),
    timeoutTimer(),
    damageDetected(false)
{
    timeoutTimer.setInterval(1000);
    timeoutTimer.setSingleShot(true);
    connect(&timeoutTimer,SIGNAL(timeout()),
            this,SLOT(timeoutExpired()));

    remoteWindowChanged(remoteWin);
}

void
MImDamageMonitor::remoteWindowChanged(MImRemoteWindow *newRemoteWindow)
{
    remoteWindow = newRemoteWindow;
}

void
MImDamageMonitor::activate()
{
    damageDetected = false;
    // reset triggers
    cancel();
    connect(remoteWindow, SIGNAL(contentUpdated(QRegion)),
            this, SLOT(contentUpdated(QRegion)));
}

void
MImDamageMonitor::waitForDamage()
{
    timeoutTimer.start();
    if (damageDetected) {
        qDebug() << __PRETTY_FUNCTION__ << " - damage already received, emitting signal.";
        cancel();
        Q_EMIT damageReceivedOrTimeout();
    }
}

void
MImDamageMonitor::contentUpdated(QRegion)
{
    damageDetected = true;
    // Emit signal only after client called waitForDamage().
    if (timeoutTimer.isActive()) {
        qDebug() << __PRETTY_FUNCTION__ << " - damage received, emitting signal.";
        cancel();
        Q_EMIT damageReceivedOrTimeout();
    }
}

void
MImDamageMonitor::cancel()
{
    timeoutTimer.stop();
    if (remoteWindow) {
        disconnect(remoteWindow, SIGNAL(contentUpdated(QRegion)),
                   this, SLOT(contentUpdated(QRegion)));
    }
}

void
MImDamageMonitor::timeoutExpired()
{
    qDebug() << __PRETTY_FUNCTION__;
    cancel();
    Q_EMIT damageReceivedOrTimeout();
}

namespace {
    qreal rotateAngle(int startAngle, int endAngle) {
        // Special cases ensuring shortest rotation angle according to original code from
        // MCrossFadedOrientationAnimationPrivate::setRootElementRotationAnimationValues.
        if (startAngle == 270 && endAngle == 90) {
            return 180.0;
        } else if (startAngle == 180 && endAngle == 0) {
            return 180.0;
        } else if (startAngle == 270 && endAngle == 0) {
            return 90.0;
        } else if (startAngle == 0 && endAngle == 270) {
            return -90.0;
        } else {
            return endAngle - startAngle;
        }
    }
}

MImRotationAnimation::MImRotationAnimation(QWidget* snapshotWidget, QWidget* parent, MImXApplication *application) :
        QGraphicsView(new QGraphicsScene(), parent),
        snapshotWidget(snapshotWidget),
        remoteWindow(0),
        animationStartPixmapItem(0),
        animationEndPixmapItem(0),
        startOrientationAngle(0),
        currentOrientationAngle(0),
        aboutToChangeReceived(false),
        damageMonitor(0),
        mApplication(application)
{
    // Animation plays on top of a black backround,
    // covering up the underlying application.
    setBackgroundBrush(QBrush(Qt::black));

    // Get rid of Meegotouch decorations.
    setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);

    // Avoid drawing transparent pixel borders.
    setFrameShape(QFrame::NoFrame);

    // We do not want input focus for that window.
    setAttribute(Qt::WA_X11DoNotAcceptFocus);

    // Avoid a white flicker when popping up our
    // extra window for the animation.
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent);
    viewport()->setAttribute(Qt::WA_NoSystemBackground);
    viewport()->setAttribute(Qt::WA_OpaquePaintEvent);

    // Remove all animation elements from scene and hide.
    connect(&rotationAnimationGroup, SIGNAL(finished()),
            this, SLOT(clearScene()));

    connect(mApplication, SIGNAL(remoteWindowChanged(MImRemoteWindow*)),
            this, SLOT(remoteWindowChanged(MImRemoteWindow*)), Qt::UniqueConnection);

    damageMonitor = new MImDamageMonitor(remoteWindow, this);
    connect(damageMonitor, SIGNAL(damageReceivedOrTimeout()),
            this, SLOT(startAnimation()));

    hide();

    if (QApplication::desktop()) {
        resize(QApplication::desktop()->screenGeometry().size());
    }
}

void
MImRotationAnimation::cancelAnimation()
{
    // disableAnimation() slot is connected to passThruWindowUnmapped()
    // So, in order to be on the safe side. We clean the scene.
    if (rotationAnimationGroup.state() != QAbstractAnimation::Stopped) {
        rotationAnimationGroup.stop();
    }

    damageMonitor->cancel();
    clearScene();

    aboutToChangeReceived = false;
}

void
MImRotationAnimation::resizeEvent(QResizeEvent *event)
{
    setSceneRect(QRect(QPoint(0,0),event->size()));
}

void
MImRotationAnimation::setupScene()
{
    animationStartPixmapItem = new SnapshotPixmapItem(compositeWindowStart);
    // See crossfadedorientationanimationstyle.css for the origin of these values.
    animationStartPixmapItem->setTransformOriginPoint(240,240);
    animationStartPixmapItem->setPos(0,0);
    if (scene()) {
        scene()->addItem(animationStartPixmapItem);
    }
}

void
MImRotationAnimation::showInitial()
{
    show();
    // We need to be on the screen really fast, otherwise you would
    // see the meegotouch orientation change in the window under us.
    // Going through the event loop will take about 800ms, which is too long.
    // Thus, requesting a synchronous update here.
    // TODO: Not a perfect solution, in rare cases and high load situations
    // application is updating the screen faster than meego-im-uiserver.
    repaint();
}

void
MImRotationAnimation::showEvent(QShowEvent*) {
    // Setting _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_INPUT
    // prevents the underlying app from losing focus and
    // avoid window decorations such as the slide-in animation.
    static Atom input = XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE_INPUT", False);
    static Atom window_type = XInternAtom(QX11Info::display(), "_NET_WM_WINDOW_TYPE", False);
    XChangeProperty(QX11Info::display(), effectiveWinId(), window_type, XA_ATOM, 32,
                    PropModeReplace, (unsigned char *) &input, 1);
}

void
MImRotationAnimation::setupAnimation(int fromAngle, int toAngle) {

    qreal hiddenOpacity = 0;
    qreal visibleOpacity = 1.0;

    // See crossfadedorientationanimationstyle.css for the origin of the animation parameters.
    int duration = 500;

    QPropertyAnimation* startAnimations[2];
    QPropertyAnimation* endAnimations[4];

    startAnimations[0] = new QPropertyAnimation();
    startAnimations[1] = new QPropertyAnimation();
    endAnimations[0] = new QPropertyAnimation();
    endAnimations[1] = new QPropertyAnimation();
    endAnimations[2] = new QPropertyAnimation();
    endAnimations[3] = new QPropertyAnimation();

    int initialRotationOfTarget = fromAngle - toAngle;
    int rotateBy = rotateAngle(fromAngle, toAngle);

    QPixmap remoteWindowPixmap;
    if (remoteWindow) {
        // This is the live pixmap of the application coming from X.
        // It stays live if it's used in read-only mode.
        remoteWindowPixmap = remoteWindow->windowPixmap();
    }
    animationEndPixmapItem = new SnapshotPixmapItem(remoteWindowPixmap);
    animationEndPixmapItem->setPos(0,0);
    animationEndPixmapItem->setTransformOriginPoint(240,240);
    animationEndPixmapItem->setRotation(initialRotationOfTarget);
    animationEndPixmapItem->setOpacity(hiddenOpacity);

    animationEndVkbOverlayItem = new SnapshotPixmapItem(grabVkbOnly());
    animationEndVkbOverlayItem->setPos(0,0);
    animationEndVkbOverlayItem->setTransformOriginPoint(240,240);
    animationEndVkbOverlayItem->setRotation(initialRotationOfTarget);
    animationEndVkbOverlayItem->setOpacity(hiddenOpacity);

    if (scene()) {
        scene()->addItem(animationEndPixmapItem);
        scene()->addItem(animationEndVkbOverlayItem);
    }

    startAnimations[0]->setPropertyName("rotation");
    startAnimations[0]->setStartValue(0);
    startAnimations[0]->setEndValue(rotateBy);
    startAnimations[0]->setEasingCurve(QEasingCurve::InOutExpo);
    startAnimations[0]->setDuration(duration);

    startAnimations[1]->setPropertyName("opacity");
    startAnimations[1]->setStartValue(visibleOpacity);
    startAnimations[1]->setEndValue(hiddenOpacity);
    startAnimations[1]->setEasingCurve(QEasingCurve::InOutExpo);
    startAnimations[1]->setDuration(duration);

    endAnimations[0]->setPropertyName("rotation");
    endAnimations[0]->setStartValue(initialRotationOfTarget);
    endAnimations[0]->setEndValue(initialRotationOfTarget+rotateBy);
    endAnimations[0]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[0]->setDuration(duration);

    endAnimations[1]->setPropertyName("opacity");
    endAnimations[1]->setStartValue(hiddenOpacity);
    endAnimations[1]->setEndValue(visibleOpacity);
    endAnimations[1]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[1]->setDuration(duration);

    // same for vkb overlay
    endAnimations[2]->setPropertyName("rotation");
    endAnimations[2]->setStartValue(initialRotationOfTarget);
    endAnimations[2]->setEndValue(initialRotationOfTarget+rotateBy);
    endAnimations[2]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[2]->setDuration(duration);

    endAnimations[3]->setPropertyName("opacity");
    endAnimations[3]->setStartValue(hiddenOpacity);
    endAnimations[3]->setEndValue(visibleOpacity);
    endAnimations[3]->setEasingCurve(QEasingCurve::InOutExpo);
    endAnimations[3]->setDuration(duration);

    startAnimations[0]->setTargetObject(animationStartPixmapItem);
    startAnimations[1]->setTargetObject(animationStartPixmapItem);
    endAnimations[0]->setTargetObject(animationEndPixmapItem);
    endAnimations[1]->setTargetObject(animationEndPixmapItem);
    endAnimations[2]->setTargetObject(animationEndVkbOverlayItem);
    endAnimations[3]->setTargetObject(animationEndVkbOverlayItem);

    rotationAnimationGroup.clear();
    rotationAnimationGroup.addAnimation(startAnimations[0]);
    rotationAnimationGroup.addAnimation(startAnimations[1]);
    rotationAnimationGroup.addAnimation(endAnimations[0]);
    rotationAnimationGroup.addAnimation(endAnimations[1]);
    rotationAnimationGroup.addAnimation(endAnimations[2]);
    rotationAnimationGroup.addAnimation(endAnimations[3]);
}

MImRotationAnimation::~MImRotationAnimation() {
    QGraphicsScene *myScene = scene();
    setScene(0);
    delete myScene;

    delete damageMonitor;
    damageMonitor = 0;

    rotationAnimationGroup.clear();
}

QPixmap
MImRotationAnimation::grabComposited()
{
    if (!remoteWindow || remoteWindow->windowPixmap().isNull()) {
        return QPixmap();
    }

    // Explicitly copying here since we want to paint the keyboard on top.
    // Qt is unable to render text into QPixmap, therefore we use QImage here.
    QImage grabImage(remoteWindow->windowPixmap().toImage());

    // Overlay keyboard, transparency not required
    QPainter painter(&grabImage);
    snapshotWidget->render(&painter,QPoint(0,0),QRect(0,0,width(),height()));

    return QPixmap::fromImage(grabImage);
}

QPixmap
MImRotationAnimation::grabVkbOnly()
{
    mApplication->setSuppressBackground(true);
    // We need to work with a QImage here, otherwise we lose the
    // transparency of the see-through part of the keyboard image.
    QImage grabImage(size(),QImage::Format_ARGB32);
    grabImage.fill(Qt::transparent);

    // Fill empty QImage with keyboard snapshot.
    QPainter painter(&grabImage);
    snapshotWidget->render(&painter,QPoint(0,0),QRect(0,0,width(),height()));
    // QPainter needs to be closed before returning
    // new QPixmap generated from QImage.
    painter.end();

    mApplication->setSuppressBackground(false);

    return QPixmap::fromImage(grabImage);
}

void
MImRotationAnimation::remoteWindowChanged(MImRemoteWindow* newRemoteWindow) {
    remoteWindow = newRemoteWindow;
    damageMonitor->remoteWindowChanged(newRemoteWindow);

    // Stop playing animations when underlying window is unmapped.
    if (!remoteWindow) {
        qDebug() << __PRETTY_FUNCTION__ << " - remote window gone, cancelling animation.";
        cancelAnimation();
    }
}

void
MImRotationAnimation::appOrientationAboutToChange(int toAngle) {
    qDebug() << __PRETTY_FUNCTION__ << " - toAngle: " << toAngle;

    if (!mApplication->passThruWindow()->isVisible()
        || toAngle == currentOrientationAngle
        || aboutToChangeReceived) {
        return;
    }
    startOrientationAngle = currentOrientationAngle;

    // Assuming that in self-composited case we don't need
    // extra redirection, we're already redirected.
    if (not mApplication->selfComposited() && remoteWindow) {
        remoteWindow->redirect();
    }

    // Capturing initial snapshot that's used for the beginning of the rotation.
    compositeWindowStart = grabComposited();

    // Do not do anything if no initial snapshot is available
    if (compositeWindowStart.isNull())
        return;

    // Clean up if we were still in the middle of a previous rotation animation.
    rotationAnimationGroup.stop();
    if (scene()) {
        scene()->clear();
    }

    setupScene();
    showInitial();

    damageMonitor->activate();

    // Unfortunately, we need to shield against appOrientationChangeFinishedEvents
    // that come in without a previous "AboutToChange" event.
    aboutToChangeReceived = true;
}

void
MImRotationAnimation::appOrientationChangeFinished(int toAngle) {
    qDebug() << __PRETTY_FUNCTION__ << " - toAngle: " << toAngle
            << " startOrientationAngle: " << startOrientationAngle;

    currentOrientationAngle = toAngle;

    if (!mApplication->passThruWindow()->isVisible()
        || toAngle == startOrientationAngle
        || !aboutToChangeReceived) {
        clearScene();
        aboutToChangeReceived = false;
        return;
    }

    setupAnimation(startOrientationAngle, toAngle);

    damageMonitor->waitForDamage();
}

void
MImRotationAnimation::startAnimation()
{
    qDebug() << __PRETTY_FUNCTION__;

    rotationAnimationGroup.start();
    aboutToChangeReceived = false;
}

void MImRotationAnimation::clearScene() {
    // When self-compositing is off, we don't need to maintain
    // the redirection.
    if (not mApplication->selfComposited() && remoteWindow) {
        remoteWindow->unredirect();
    }

    hide();

    if (scene()) {
        scene()->clear();
    }

    compositeWindowStart = QPixmap();
}
<|endoftext|>


<commit_before>#include "plot_view.hpp"
#include "plot.hpp"

#include <QPainter>
#include <QDebug>
#include <algorithm>
#include <iostream>

using namespace std;

namespace datavis {

PlotView::PlotView(QWidget * parent):
    QWidget(parent)
{}

void PlotView::addPlot(Plot * plot)
{
    m_plots.push_back(plot);

    updatePlotMap();
    updateViewMap();
}

void PlotView::updateViewMap()
{
    auto size = this->size();

    int margin = 10;

    QTransform map;
    map.translate(margin, size.height() - margin);
    map.scale(size.width() - 2 * margin, - (size.height() - 2 * margin));

    m_view_map = m_plot_map * map;
}

void PlotView::updatePlotMap()
{
    Plot::Range total_range;

    {
        bool first = true;
        for (auto plot : m_plots)
        {
            if (plot->isEmpty())
                continue;

            auto range = plot->range();

            if (first)
                total_range = range;
            else
            {
                double min_x = min(total_range.min.x(), range.min.x());
                double min_y = min(total_range.min.y(), range.min.y());
                double max_x = max(total_range.max.x(), range.max.x());
                double max_y = max(total_range.max.y(), range.max.y());

                total_range.min = QPointF(min_x, min_y);
                total_range.max = QPointF(max_x, max_y);
            }
            first = false;
        }
    }
#if 0
    cout << "View range: "
         << "(" << total_range.min.x() << "," << total_range.max.x() << ")"
         << " -> "
         << "(" << total_range.min.y() << "," << total_range.max.y() << ")"
         << endl;
#endif
    QPointF extent = total_range.max - total_range.min;
    QPointF offset = total_range.min;

    //qDebug() << "offset:" << offset;
    //qDebug() << "extent:" << extent;

    double x_scale = extent.x() == 0 ? 1 : 1.0 / extent.x();
    double y_scale = extent.y() == 0 ? 1 : 1.0 / extent.y();

    //qDebug() << "x scale:" << x_scale;
    //qDebug() << "y scale:" << y_scale;

    QTransform transform;
    transform.scale(x_scale, y_scale);
    transform.translate(offset.x(), -offset.y());

    m_plot_map = transform;
}

void PlotView::resizeEvent(QResizeEvent*)
{
    updateViewMap();
}

void PlotView::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);

    painter.fillRect(rect(), Qt::white);

    for (auto plot : m_plots)
    {
        if (plot->isEmpty())
            continue;

        plot->plot(&painter, m_view_map);
    }
}

}
<commit_msg>Plot view: Fix horizontal offset<commit_after>#include "plot_view.hpp"
#include "plot.hpp"

#include <QPainter>
#include <QDebug>
#include <algorithm>
#include <iostream>

using namespace std;

namespace datavis {

PlotView::PlotView(QWidget * parent):
    QWidget(parent)
{}

void PlotView::addPlot(Plot * plot)
{
    m_plots.push_back(plot);

    updatePlotMap();
    updateViewMap();
}

void PlotView::updateViewMap()
{
    auto size = this->size();

    int margin = 10;

    QTransform map;
    map.translate(margin, size.height() - margin);
    map.scale(size.width() - 2 * margin, - (size.height() - 2 * margin));

    m_view_map = m_plot_map * map;
}

void PlotView::updatePlotMap()
{
    Plot::Range total_range;

    {
        bool first = true;
        for (auto plot : m_plots)
        {
            if (plot->isEmpty())
                continue;

            auto range = plot->range();

            if (first)
                total_range = range;
            else
            {
                double min_x = min(total_range.min.x(), range.min.x());
                double min_y = min(total_range.min.y(), range.min.y());
                double max_x = max(total_range.max.x(), range.max.x());
                double max_y = max(total_range.max.y(), range.max.y());

                total_range.min = QPointF(min_x, min_y);
                total_range.max = QPointF(max_x, max_y);
            }
            first = false;
        }
    }
#if 0
    cout << "View range: "
         << "(" << total_range.min.x() << "," << total_range.max.x() << ")"
         << " -> "
         << "(" << total_range.min.y() << "," << total_range.max.y() << ")"
         << endl;
#endif
    QPointF extent = total_range.max - total_range.min;
    QPointF offset = total_range.min;
#if 0
    qDebug() << "offset:" << offset;
    qDebug() << "extent:" << extent;
#endif
    double x_scale = extent.x() == 0 ? 1 : 1.0 / extent.x();
    double y_scale = extent.y() == 0 ? 1 : 1.0 / extent.y();
#if 0
    qDebug() << "x scale:" << x_scale;
    qDebug() << "y scale:" << y_scale;
#endif
    QTransform transform;
    transform.scale(x_scale, y_scale);
    transform.translate(-offset.x(), -offset.y());

    m_plot_map = transform;
}

void PlotView::resizeEvent(QResizeEvent*)
{
    updateViewMap();
}

void PlotView::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);

    painter.fillRect(rect(), Qt::white);

    for (auto plot : m_plots)
    {
        if (plot->isEmpty())
            continue;

        plot->plot(&painter, m_view_map);
    }
}

}
<|endoftext|>