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

#include "base/sys_info.h"

#include <sys/system_properties.h>

#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"

namespace {

// Default version of Android to fall back to when actual version numbers
// cannot be acquired.
// TODO(dfalcantara): Keep this reasonably up to date with the latest publicly
//                    available version of Android.
static const int kDefaultAndroidMajorVersion = 4;
static const int kDefaultAndroidMinorVersion = 0;
static const int kDefaultAndroidBugfixVersion = 3;

// Parse out the OS version numbers from the system properties.
void ParseOSVersionNumbers(const char* os_version_str,
                           int32 *major_version,
                           int32 *minor_version,
                           int32 *bugfix_version) {
  if (os_version_str[0]) {
    // Try to parse out the version numbers from the string.
    int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
                          minor_version, bugfix_version);

    if (num_read > 0) {
      // If we don't have a full set of version numbers, make the extras 0.
      if (num_read < 2) *minor_version = 0;
      if (num_read < 3) *bugfix_version = 0;
      return;
    }
  }

  // For some reason, we couldn't parse the version number string.
  *major_version = kDefaultAndroidMajorVersion;
  *minor_version = kDefaultAndroidMinorVersion;
  *bugfix_version = kDefaultAndroidBugfixVersion;
}

// Parses a system property (specified with unit 'k','m' or 'g').
// Returns a value in bytes.
// Returns -1 if the string could not be parsed.
int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
  const int64 KB = 1024;
  const int64 MB = 1024 * KB;
  const int64 GB = 1024 * MB;
  if (str.size() == 0u)
    return -1;
  int64 unit_multiplier = 1;
  size_t length = str.size();
  if (str[length - 1] == 'k') {
    unit_multiplier = KB;
    length--;
  } else if (str[length - 1] == 'm') {
    unit_multiplier = MB;
    length--;
  } else if (str[length - 1] == 'g') {
    unit_multiplier = GB;
    length--;
  }
  int64 result = 0;
  bool parsed = base::StringToInt64(str.substr(0, length), &result);
  bool negative = result <= 0;
  bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier;
  if (!parsed || negative || overflow)
    return -1;
  return result * unit_multiplier;
}

int GetDalvikHeapSizeMB() {
  char heap_size_str[PROP_VALUE_MAX];
  __system_property_get("dalvik.vm.heapsize", heap_size_str);
  // dalvik.vm.heapsize property is writable by a root user.
  // Clamp it to reasonable range as a sanity check,
  // a typical android device will never have less than 48MB.
  const int64 MB = 1024 * 1024;
  int64 result = ParseSystemPropertyBytes(heap_size_str);
  if (result == -1) {
     // We should consider not exposing these values if they are not reliable.
     LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str;
     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3;
  }
  result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB;
  return static_cast<int>(result);
}

int GetDalvikHeapGrowthLimitMB() {
  char heap_size_str[PROP_VALUE_MAX];
  __system_property_get("dalvik.vm.heapgrowthlimit", heap_size_str);
  // dalvik.vm.heapgrowthlimit property is writable by a root user.
  // Clamp it to reasonable range as a sanity check,
  // a typical android device will never have less than 24MB.
  const int64 MB = 1024 * 1024;
  int64 result = ParseSystemPropertyBytes(heap_size_str);
  if (result == -1) {
     // We should consider not exposing these values if they are not reliable.
     LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str;
     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6;
  }
  result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB;
  return static_cast<int>(result);
}

}  // anonymous namespace

namespace base {

std::string SysInfo::OperatingSystemName() {
  return "Android";
}

std::string SysInfo::GetAndroidBuildCodename() {
  char os_version_codename_str[PROP_VALUE_MAX];
  __system_property_get("ro.build.version.codename", os_version_codename_str);
  return std::string(os_version_codename_str);
}

std::string SysInfo::GetAndroidBuildID() {
  char os_build_id_str[PROP_VALUE_MAX];
  __system_property_get("ro.build.id", os_build_id_str);
  return std::string(os_build_id_str);
}

std::string SysInfo::GetDeviceName() {
  char device_model_str[PROP_VALUE_MAX];
  __system_property_get("ro.product.model", device_model_str);
  return std::string(device_model_str);
}

std::string SysInfo::OperatingSystemVersion() {
  int32 major, minor, bugfix;
  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
  return StringPrintf("%d.%d.%d", major, minor, bugfix);
}

void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
                                            int32* minor_version,
                                            int32* bugfix_version) {
  // Read the version number string out from the properties.
  char os_version_str[PROP_VALUE_MAX];
  __system_property_get("ro.build.version.release", os_version_str);

  // Parse out the numbers.
  ParseOSVersionNumbers(os_version_str, major_version, minor_version,
                        bugfix_version);
}

int SysInfo::DalvikHeapSizeMB() {
  static int heap_size = GetDalvikHeapSizeMB();
  return heap_size;
}

int SysInfo::DalvikHeapGrowthLimitMB() {
  static int heap_growth_limit = GetDalvikHeapGrowthLimitMB();
  return heap_growth_limit;
}

}  // namespace base
<commit_msg>Bump up the fallback OS version number to 4.3.0<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/sys_info.h"

#include <sys/system_properties.h>

#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"

namespace {

// Default version of Android to fall back to when actual version numbers
// cannot be acquired.
// TODO(dfalcantara): Keep this reasonably up to date with the latest publicly
//                    available version of Android.
const int kDefaultAndroidMajorVersion = 4;
const int kDefaultAndroidMinorVersion = 3;
const int kDefaultAndroidBugfixVersion = 0;

// Parse out the OS version numbers from the system properties.
void ParseOSVersionNumbers(const char* os_version_str,
                           int32 *major_version,
                           int32 *minor_version,
                           int32 *bugfix_version) {
  if (os_version_str[0]) {
    // Try to parse out the version numbers from the string.
    int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
                          minor_version, bugfix_version);

    if (num_read > 0) {
      // If we don't have a full set of version numbers, make the extras 0.
      if (num_read < 2) *minor_version = 0;
      if (num_read < 3) *bugfix_version = 0;
      return;
    }
  }

  // For some reason, we couldn't parse the version number string.
  *major_version = kDefaultAndroidMajorVersion;
  *minor_version = kDefaultAndroidMinorVersion;
  *bugfix_version = kDefaultAndroidBugfixVersion;
}

// Parses a system property (specified with unit 'k','m' or 'g').
// Returns a value in bytes.
// Returns -1 if the string could not be parsed.
int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
  const int64 KB = 1024;
  const int64 MB = 1024 * KB;
  const int64 GB = 1024 * MB;
  if (str.size() == 0u)
    return -1;
  int64 unit_multiplier = 1;
  size_t length = str.size();
  if (str[length - 1] == 'k') {
    unit_multiplier = KB;
    length--;
  } else if (str[length - 1] == 'm') {
    unit_multiplier = MB;
    length--;
  } else if (str[length - 1] == 'g') {
    unit_multiplier = GB;
    length--;
  }
  int64 result = 0;
  bool parsed = base::StringToInt64(str.substr(0, length), &result);
  bool negative = result <= 0;
  bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier;
  if (!parsed || negative || overflow)
    return -1;
  return result * unit_multiplier;
}

int GetDalvikHeapSizeMB() {
  char heap_size_str[PROP_VALUE_MAX];
  __system_property_get("dalvik.vm.heapsize", heap_size_str);
  // dalvik.vm.heapsize property is writable by a root user.
  // Clamp it to reasonable range as a sanity check,
  // a typical android device will never have less than 48MB.
  const int64 MB = 1024 * 1024;
  int64 result = ParseSystemPropertyBytes(heap_size_str);
  if (result == -1) {
     // We should consider not exposing these values if they are not reliable.
     LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str;
     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3;
  }
  result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB;
  return static_cast<int>(result);
}

int GetDalvikHeapGrowthLimitMB() {
  char heap_size_str[PROP_VALUE_MAX];
  __system_property_get("dalvik.vm.heapgrowthlimit", heap_size_str);
  // dalvik.vm.heapgrowthlimit property is writable by a root user.
  // Clamp it to reasonable range as a sanity check,
  // a typical android device will never have less than 24MB.
  const int64 MB = 1024 * 1024;
  int64 result = ParseSystemPropertyBytes(heap_size_str);
  if (result == -1) {
     // We should consider not exposing these values if they are not reliable.
     LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str;
     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6;
  }
  result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB;
  return static_cast<int>(result);
}

}  // anonymous namespace

namespace base {

std::string SysInfo::OperatingSystemName() {
  return "Android";
}

std::string SysInfo::GetAndroidBuildCodename() {
  char os_version_codename_str[PROP_VALUE_MAX];
  __system_property_get("ro.build.version.codename", os_version_codename_str);
  return std::string(os_version_codename_str);
}

std::string SysInfo::GetAndroidBuildID() {
  char os_build_id_str[PROP_VALUE_MAX];
  __system_property_get("ro.build.id", os_build_id_str);
  return std::string(os_build_id_str);
}

std::string SysInfo::GetDeviceName() {
  char device_model_str[PROP_VALUE_MAX];
  __system_property_get("ro.product.model", device_model_str);
  return std::string(device_model_str);
}

std::string SysInfo::OperatingSystemVersion() {
  int32 major, minor, bugfix;
  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
  return StringPrintf("%d.%d.%d", major, minor, bugfix);
}

void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
                                            int32* minor_version,
                                            int32* bugfix_version) {
  // Read the version number string out from the properties.
  char os_version_str[PROP_VALUE_MAX];
  __system_property_get("ro.build.version.release", os_version_str);

  // Parse out the numbers.
  ParseOSVersionNumbers(os_version_str, major_version, minor_version,
                        bugfix_version);
}

int SysInfo::DalvikHeapSizeMB() {
  static int heap_size = GetDalvikHeapSizeMB();
  return heap_size;
}

int SysInfo::DalvikHeapGrowthLimitMB() {
  static int heap_growth_limit = GetDalvikHeapGrowthLimitMB();
  return heap_growth_limit;
}

}  // namespace base
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: app.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 14:11:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _BASICAPP_HXX
#define _BASICAPP_HXX

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif
#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif
#ifndef _WRKWIN_HXX //autogen
#include <vcl/wrkwin.hxx>
#endif
#ifndef _TIMER_HXX //autogen
#include <vcl/timer.hxx>
#endif
#ifndef _SFXBRDCST_HXX
#include <svtools/brdcst.hxx>
#endif
#ifndef _SFXLSTNER_HXX
#include <svtools/lstner.hxx>
#endif

class BasicFrame;
#include <basic/mybasic.hxx>

class EditList;
class AppWin;
class AppEdit;
class AppBasEd;
class MsgEdit;
class AppError;
class StatusLine;
class BasicPrinter;
struct TTLogMsg;

class BasicApp : public Application {
    short       nWait;              // Wait-Zaehler
public:
//  Help*       pHelp;              // Hilfesystem
    BasicFrame* pFrame;             // Frame Window
//  MenuBar*    pMainMenu;          // Hauptmenue
    Accelerator*    pMainAccel;     // Acceleratoren

    void  Main( );

    void  LoadIniFile();
    void  SetFocus();
    void  Wait( BOOL );
    DECL_LINK( LateInit, void * );

#ifdef DBG_UTIL
    DbgPrintLine DbgPrintMsgBox;
#endif
};

typedef USHORT FileType;

#define FT_NO_FILE          (FileType)0x00      // Ein Fehler ist aufgetreten ...
#define FT_BASIC_SOURCE     (FileType)0x01
#define FT_BASIC_INCLUDE    (FileType)0x02
#define FT_RESULT_FILE      (FileType)0x04
#define FT_RESULT_FILE_TXT  (FileType)0x08
#define FT_BASIC_LIBRARY    (FileType)0x10

struct WinInfoRec;
class DisplayHidDlg;

class FloatingExecutionStatus;

class BasicFrame : public WorkWindow, public SfxBroadcaster, public SfxListener
{
using SystemWindow::Notify;
using Window::Command;

virtual BOOL Close();               // Schliessen
    BOOL CloseAll();                // Alle Fenster schliessen
    BOOL CompileAll();              // Alle Texte compilieren
    AutoTimer aLineNum;             // Zeigt die Zeilennummer an
virtual void Resize();
virtual void Move();
virtual void GetFocus();
    void LoadLibrary();
    void SaveLibrary();
    BOOL bIsAutoRun;
    DisplayHidDlg* pDisplayHidDlg;

//  BreakPoint *pRunToCursorBP;

    SbxVariable *pEditVar;

    Timer aCheckFiles;      // Prfen der Dateien auf nderungen
    BOOL bAutoReload;
    BOOL bAutoSave;
    DECL_LINK( CheckAllFiles, Timer* );

    MyBasicRef  pBasic;             // BASIC-Engine

    String aAppName;                // Inhalt der Titelteile der App:
    String aAppFile;                // AppName AppFile [AppMode]
    String aAppMode;
    void UpdateTitle();
    DECL_LINK( CloseButtonClick, void* );
    DECL_LINK( FloatButtonClick, void* );
    DECL_LINK( HideButtonClick, void* );

    FloatingExecutionStatus *pExecutionStatus;

public:
    BOOL IsAutoRun();
    void SetAutoRun( BOOL bAuto );
    BOOL bInBreak;                  // TRUE, wenn im Break-Handler
    StatusLine* pStatus;            // Statuszeile
    EditList*   pList;              // List der Edit-Fenster
    AppWin*     pWork;              // aktuelles Edit-Fenster
    BasicPrinter* pPrn;             // Drucker
    BOOL bDisas;                    // TRUE: disassemble
    USHORT nFlags;                  // Debugging-Flags
    USHORT nMaximizedWindows;       // Anzahl der Fenster, die maximized sind
    void FocusWindow( AppWin *pWin );
    void WinMax_Restore();
    void WinShow_Hide();
    void RemoveWindow( AppWin *pWin );
    void AddWindow( AppWin *pWin );
    void WindowRenamed( AppWin *pWin );

    BasicFrame();
   ~BasicFrame();
    MyBasic& Basic()                { return *pBasic; }
    void AddToLRU(String const& aFile);
    void LoadLRU();
    DECL_LINK( InitMenu, Menu * );
    DECL_LINK( DeInitMenu, Menu * );
    DECL_LINK( HighlightMenu, Menu * );
    DECL_LINK( MenuCommand, Menu * );
    DECL_LINK( Accel, Accelerator * );
    DECL_LINK( ShowLineNr, AutoTimer * );
    MsgEdit* GetMsgTree( String aLogFileName );
    DECL_LINK( Log, TTLogMsg * );
    DECL_LINK( WinInfo, WinInfoRec * );
    BOOL LoadFile( String aFilename );
    long Command( short,BOOL=FALSE );// Kommando-Handler
    BOOL SaveAll();                 // Alle Fenster speichern
    BOOL QueryFileName( String& rName, FileType nFileType, BOOL bSave );// Dateinamen ermitteln
    DECL_LINK( ModuleWinExists, String* );
    DECL_LINK( WriteString, String* );
    AppBasEd* CreateModuleWin( SbModule* pMod );
    AppBasEd* FindModuleWin( const String& );
    AppError* FindErrorWin( const String& );
    AppWin* FindWin( const String& );
    AppWin* FindWin( USHORT nWinId );
    AppWin* IsWinValid( AppWin* pMaybeWin );
    USHORT BreakHandler();          // Break-Handler-Callback

    void SetEditVar( SbxVariable *pVar ){ pEditVar = pVar;}
    SbxVariable* GetEditVar(){ return pEditVar;}
    BOOL IsAutoReload() { return bAutoReload; }
    BOOL IsAutoSave() { return bAutoSave; }
    void LoadIniFile();

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

    void SetAppMode( const String &aNewMode ){ aAppMode = aNewMode; UpdateTitle(); }

    String GenRealString( const String &aResString );

};

extern BasicApp aBasicApp;

#endif
<commit_msg>INTEGRATION: CWS aquavcl04 (1.11.32); FILE MERGED 2007/11/07 15:32:42 gh 1.11.32.1: #i83007#about and settings dialog for MacOS<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: app.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: ihi $ $Date: 2008-01-14 15:49:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _BASICAPP_HXX
#define _BASICAPP_HXX

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif
#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif
#ifndef _WRKWIN_HXX //autogen
#include <vcl/wrkwin.hxx>
#endif
#ifndef _TIMER_HXX //autogen
#include <vcl/timer.hxx>
#endif
#ifndef _SFXBRDCST_HXX
#include <svtools/brdcst.hxx>
#endif
#ifndef _SFXLSTNER_HXX
#include <svtools/lstner.hxx>
#endif

class BasicFrame;
#include <basic/mybasic.hxx>

class EditList;
class AppWin;
class AppEdit;
class AppBasEd;
class MsgEdit;
class AppError;
class StatusLine;
class BasicPrinter;
struct TTLogMsg;

class BasicApp : public Application {
    short       nWait;              // Wait-Zaehler
public:
//  Help*       pHelp;              // Hilfesystem
    BasicFrame* pFrame;             // Frame Window
//  MenuBar*    pMainMenu;          // Hauptmenue
    Accelerator*    pMainAccel;     // Acceleratoren

    void  Main( );

    void  LoadIniFile();
    void  SetFocus();
    void  Wait( BOOL );
    DECL_LINK( LateInit, void * );

#ifdef DBG_UTIL
    DbgPrintLine DbgPrintMsgBox;
#endif
};

typedef USHORT FileType;

#define FT_NO_FILE          (FileType)0x00      // Ein Fehler ist aufgetreten ...
#define FT_BASIC_SOURCE     (FileType)0x01
#define FT_BASIC_INCLUDE    (FileType)0x02
#define FT_RESULT_FILE      (FileType)0x04
#define FT_RESULT_FILE_TXT  (FileType)0x08
#define FT_BASIC_LIBRARY    (FileType)0x10

struct WinInfoRec;
class DisplayHidDlg;

class FloatingExecutionStatus;

class BasicFrame : public WorkWindow, public SfxBroadcaster, public SfxListener
{
using SystemWindow::Notify;
using Window::Command;

virtual BOOL Close();               // Schliessen
    BOOL CloseAll();                // Alle Fenster schliessen
    BOOL CompileAll();              // Alle Texte compilieren
    AutoTimer aLineNum;             // Zeigt die Zeilennummer an
virtual void Resize();
virtual void Move();
virtual void GetFocus();
    void LoadLibrary();
    void SaveLibrary();
    BOOL bIsAutoRun;
    DisplayHidDlg* pDisplayHidDlg;

//  BreakPoint *pRunToCursorBP;

    SbxVariable *pEditVar;

    Timer aCheckFiles;      // Prfen der Dateien auf nderungen
    BOOL bAutoReload;
    BOOL bAutoSave;
    DECL_LINK( CheckAllFiles, Timer* );

    MyBasicRef  pBasic;             // BASIC-Engine

    String aAppName;                // Inhalt der Titelteile der App:
    String aAppFile;                // AppName AppFile [AppMode]
    String aAppMode;
    void UpdateTitle();
    DECL_LINK( CloseButtonClick, void* );
    DECL_LINK( FloatButtonClick, void* );
    DECL_LINK( HideButtonClick, void* );

    FloatingExecutionStatus *pExecutionStatus;

public:
    BOOL IsAutoRun();
    void SetAutoRun( BOOL bAuto );
    BOOL bInBreak;                  // TRUE, wenn im Break-Handler
    StatusLine* pStatus;            // Statuszeile
    EditList*   pList;              // List der Edit-Fenster
    AppWin*     pWork;              // aktuelles Edit-Fenster
    BasicPrinter* pPrn;             // Drucker
    BOOL bDisas;                    // TRUE: disassemble
    USHORT nFlags;                  // Debugging-Flags
    USHORT nMaximizedWindows;       // Anzahl der Fenster, die maximized sind
    void FocusWindow( AppWin *pWin );
    void WinMax_Restore();
    void WinShow_Hide();
    void RemoveWindow( AppWin *pWin );
    void AddWindow( AppWin *pWin );
    void WindowRenamed( AppWin *pWin );

    BasicFrame();
   ~BasicFrame();
    MyBasic& Basic()                { return *pBasic; }
    void AddToLRU(String const& aFile);
    void LoadLRU();
    DECL_LINK( InitMenu, Menu * );
    DECL_LINK( DeInitMenu, Menu * );
    DECL_LINK( HighlightMenu, Menu * );
    DECL_LINK( MenuCommand, Menu * );
    DECL_LINK( Accel, Accelerator * );
    DECL_LINK( ShowLineNr, AutoTimer * );
    MsgEdit* GetMsgTree( String aLogFileName );
    DECL_LINK( Log, TTLogMsg * );
    DECL_LINK( WinInfo, WinInfoRec * );
    BOOL LoadFile( String aFilename );
    long Command( short,BOOL=FALSE );// Kommando-Handler
    virtual void Command( const CommandEvent& rCEvt );      // Kommando-Handler
    BOOL SaveAll();                 // Alle Fenster speichern
    BOOL QueryFileName( String& rName, FileType nFileType, BOOL bSave );// Dateinamen ermitteln
    DECL_LINK( ModuleWinExists, String* );
    DECL_LINK( WriteString, String* );
    AppBasEd* CreateModuleWin( SbModule* pMod );
    AppBasEd* FindModuleWin( const String& );
    AppError* FindErrorWin( const String& );
    AppWin* FindWin( const String& );
    AppWin* FindWin( USHORT nWinId );
    AppWin* IsWinValid( AppWin* pMaybeWin );
    USHORT BreakHandler();          // Break-Handler-Callback

    void SetEditVar( SbxVariable *pVar ){ pEditVar = pVar;}
    SbxVariable* GetEditVar(){ return pEditVar;}
    BOOL IsAutoReload() { return bAutoReload; }
    BOOL IsAutoSave() { return bAutoSave; }
    void LoadIniFile();

    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );

    void SetAppMode( const String &aNewMode ){ aAppMode = aNewMode; UpdateTitle(); }

    String GenRealString( const String &aResString );

};

extern BasicApp aBasicApp;

#endif
<|endoftext|>


<commit_before>AliAnalysisTaskEmcalJetMass* AddTaskEmcalJetMass(const char * njetsBase,
						 const Double_t R,
						 const char * nrhoBase,
						 const char * ntracks,
						 const char * nclusters,
						 const char *type,
						 const char *CentEst,
						 Int_t       pSel,
						 TString     trigClass      = "",
						 TString     kEmcalTriggers = "",
						 TString     nJetsUnsub     = "",
						 TString     optionName     = "") {

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr)
    {
      Error("AddTaskEmcalJetMass","No analysis manager found.");
      return 0;
    }
  Bool_t ismc=kFALSE;
  ismc = (mgr->GetMCtruthEventHandler())?kTRUE:kFALSE;

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler())
    {
      ::Error("AddTaskEmcalJetMass", "This task requires an input event handler");
      return NULL;
    }

  TString wagonName = Form("JetMass_%s_TC%s%s%s",njetsBase,trigClass.Data(),optionName.Data());

  //Configure jet tagger task
  AliAnalysisTaskEmcalJetMass *task = new AliAnalysisTaskEmcalJetMass(wagonName.Data());

  task->SetNCentBins(4);
  //task->SetVzRange(-10.,10.);

  AliParticleContainer *trackCont  = task->AddParticleContainer(ntracks);
  AliClusterContainer *clusterCont = task->AddClusterContainer(nclusters);

  task->SetJetContainerBase(0);

  TString strType(type);
  AliJetContainer *jetContBase = task->AddJetContainer(njetsBase,strType,R);
  if(jetContBase) {
    jetContBase->SetRhoName(nrhoBase);
    jetContBase->ConnectParticleContainer(trackCont);
    jetContBase->ConnectClusterContainer(clusterCont);
    jetContBase->SetPercAreaCut(0.6);
  }
  if(!nJetsUnsub.IsNull()) {
    AliJetContainer *jetContUS = task->AddJetContainer(nJetsUnsub.Data(),strType,R);
    if(jetContUS) {
      jetContUS->SetRhoName(nrhoBase);
      jetContUS->ConnectParticleContainer(trackCont);
      jetContUS->ConnectClusterContainer(clusterCont);
      jetContUS->SetPercAreaCut(0.6);
    }
  }

  task->SetCaloTriggerPatchInfoName(kEmcalTriggers.Data());
  task->SetCentralityEstimator(CentEst);
  task->SelectCollisionCandidates(pSel);
  task->SetUseAliAnaUtils(kFALSE);

  mgr->AddTask(task);

  //Connnect input
  mgr->ConnectInput (task, 0, mgr->GetCommonInputContainer() );

  //Connect output
  TString contName(wagonName);
  TString outputfile = Form("%s",AliAnalysisManager::GetCommonFileName());
  AliAnalysisDataContainer *coutput1 = mgr->CreateContainer(contName.Data(), TList::Class(),AliAnalysisManager::kOutputContainer,outputfile);
  mgr->ConnectOutput(task,1,coutput1);

  return task;

}

<commit_msg>fix bug<commit_after>AliAnalysisTaskEmcalJetMass* AddTaskEmcalJetMass(const char * njetsBase,
						 const Double_t R,
						 const char * nrhoBase,
						 const char * ntracks,
						 const char * nclusters,
						 const char *type,
						 const char *CentEst,
						 Int_t       pSel,
						 TString     trigClass      = "",
						 TString     kEmcalTriggers = "",
						 TString     nJetsUnsub     = "",
						 TString     optionName     = "") {

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr)
    {
      Error("AddTaskEmcalJetMass","No analysis manager found.");
      return 0;
    }
  Bool_t ismc=kFALSE;
  ismc = (mgr->GetMCtruthEventHandler())?kTRUE:kFALSE;

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler())
    {
      ::Error("AddTaskEmcalJetMass", "This task requires an input event handler");
      return NULL;
    }

  TString wagonName = Form("JetMass_%s_TC%s%s",njetsBase,trigClass.Data(),optionName.Data());

  //Configure jet tagger task
  AliAnalysisTaskEmcalJetMass *task = new AliAnalysisTaskEmcalJetMass(wagonName.Data());

  task->SetNCentBins(4);
  //task->SetVzRange(-10.,10.);

  AliParticleContainer *trackCont  = task->AddParticleContainer(ntracks);
  AliClusterContainer *clusterCont = task->AddClusterContainer(nclusters);

  task->SetJetContainerBase(0);

  TString strType(type);
  AliJetContainer *jetContBase = task->AddJetContainer(njetsBase,strType,R);
  if(jetContBase) {
    jetContBase->SetRhoName(nrhoBase);
    jetContBase->ConnectParticleContainer(trackCont);
    jetContBase->ConnectClusterContainer(clusterCont);
    jetContBase->SetPercAreaCut(0.6);
  }
  if(!nJetsUnsub.IsNull()) {
    AliJetContainer *jetContUS = task->AddJetContainer(nJetsUnsub.Data(),strType,R);
    if(jetContUS) {
      jetContUS->SetRhoName(nrhoBase);
      jetContUS->ConnectParticleContainer(trackCont);
      jetContUS->ConnectClusterContainer(clusterCont);
      jetContUS->SetPercAreaCut(0.6);
    }
  }

  task->SetCaloTriggerPatchInfoName(kEmcalTriggers.Data());
  task->SetCentralityEstimator(CentEst);
  task->SelectCollisionCandidates(pSel);
  task->SetUseAliAnaUtils(kFALSE);

  mgr->AddTask(task);

  //Connnect input
  mgr->ConnectInput (task, 0, mgr->GetCommonInputContainer() );

  //Connect output
  TString contName(wagonName);
  TString outputfile = Form("%s",AliAnalysisManager::GetCommonFileName());
  AliAnalysisDataContainer *coutput1 = mgr->CreateContainer(contName.Data(), TList::Class(),AliAnalysisManager::kOutputContainer,outputfile);
  mgr->ConnectOutput(task,1,coutput1);

  return task;

}

<|endoftext|>


<commit_before>#include <plugin.hpp>
#include <debug.hpp>
#include <output.hpp>
#include <core.hpp>
#include <view.hpp>
#include <workspace-manager.hpp>
#include <render-manager.hpp>
#include <algorithm>
#include <cmath>
#include <linux/input-event-codes.h>
#include "signal-definitions.hpp"
#include <animation.hpp>

#include "snap_signal.hpp"
#include "../wobbly/wobbly-signal.hpp"

extern "C"
{
#include <wlr/util/edges.h>
}

const std::string grid_view_id = "grid-view";

class wayfire_grid_view_cdata : public wf::custom_data_t
{
    wf_duration duration;
    bool is_active = true;

    wayfire_view view;
    wf::output_t *output;
    wf::effect_hook_t pre_hook;
    wf::signal_callback_t unmapped;

    int32_t tiled_edges = -1;
    wf_geometry target, initial;
    const wf::plugin_grab_interface_uptr& iface;
    wf_option animation_type;

    public:

    wayfire_grid_view_cdata(wayfire_view view,
        const wf::plugin_grab_interface_uptr& _iface,
        wf_option animation_type, wf_option animation_duration)
        : iface(_iface)
    {
        this->view = view;
        this->output = view->get_output();
        this->animation_type = animation_type;
        duration = wf_duration(animation_duration);

        if (!view->get_output()->activate_plugin(iface))
        {
            is_active = false;
            return;
        }

        pre_hook = [=] () {
            adjust_geometry();
        };
        output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);

        unmapped = [=] (wf::signal_data_t *data)
        {
            if (get_signaled_view(data) == view)
                destroy();
        };

        output->render->set_redraw_always(true);
        output->connect_signal("view-disappeared", &unmapped);
        output->connect_signal("detach-view", &unmapped);
    }

    void destroy()
    {
        view->erase_data<wayfire_grid_view_cdata>();
    }

    void adjust_target_geometry(wf_geometry geometry, int32_t target_edges)
    {
        target = geometry;
        initial = view->get_wm_geometry();
        this->tiled_edges = target_edges;

        auto type = animation_type->as_string();
        if (view->get_transformer("wobbly") || !is_active)
            type = "wobbly";

        if (type == "none")
        {
            set_end_state(geometry, tiled_edges);
            return destroy();
        }

        if (type == "wobbly")
        {
            /* Order is important here: first we set the view geometry, and
             * after that we set the snap request. Otherwise the wobbly plugin
             * will think the view actually moved */
            set_end_state(geometry, tiled_edges);
            snap_wobbly(view, geometry);

            if (!tiled_edges) // release snap, so subsequent size changes don't bother us
                snap_wobbly(view, geometry, false);

            return destroy();
        }

        /* Restore tiled edges if we don't need to set something special when
         * grid is ready */
        if (target_edges < 0)
            this->tiled_edges = view->tiled_edges;

        view->set_tiled(wf::TILED_EDGES_ALL);
        view->set_moving(1);
        view->set_resizing(1);
        duration.start();
    }

    void set_end_state(wf_geometry geometry, int32_t edges)
    {
        view->set_geometry(geometry);
        if (edges >= 0)
            view->set_tiled(edges);
    }

    void adjust_geometry()
    {
        if (!duration.running())
        {
            set_end_state(target, tiled_edges);
            view->set_moving(0);
            view->set_resizing(0);

            return destroy();
        }

        int cx = duration.progress(initial.x, target.x);
        int cy = duration.progress(initial.y, target.y);
        int cw = duration.progress(initial.width, target.width);
        int ch = duration.progress(initial.height, target.height);

        view->set_geometry({cx, cy, cw, ch});
    }

    ~wayfire_grid_view_cdata()
    {
        if (!is_active)
            return;

        output->render->rem_effect(&pre_hook);
        output->deactivate_plugin(iface);
        output->render->set_redraw_always(false);
        output->disconnect_signal("view-disappeared", &unmapped);
        output->disconnect_signal("detach-view", &unmapped);
    }
};

class wf_grid_slot_data : public wf::custom_data_t
{
    public:
        int slot;
};

nonstd::observer_ptr<wayfire_grid_view_cdata> ensure_grid_view(wayfire_view view,
        const wf::plugin_grab_interface_uptr& iface, wf_option animation_type,
        wf_option animation_duration)
{
    if (!view->has_data<wayfire_grid_view_cdata>())
    {
        view->store_data(std::make_unique<wayfire_grid_view_cdata>
            (view, iface, animation_type, animation_duration));
    }

    return view->get_data<wayfire_grid_view_cdata> ();
}

class wf_grid_saved_view_geometry : public wf::custom_data_t
{
    public:
    wf_geometry geometry;
    uint32_t tiled_edges;
};

/*
 * 7 8 9
 * 4 5 6
 * 1 2 3
 */
static uint32_t get_tiled_edges_for_slot(uint32_t slot)
{
    if (slot == 0)
        return 0;

    uint32_t edges = wf::TILED_EDGES_ALL;
    if (slot % 3 == 0)
        edges &= ~WLR_EDGE_LEFT;
    if (slot % 3 == 1)
        edges &= ~WLR_EDGE_RIGHT;
    if (slot <= 3)
        edges &= ~WLR_EDGE_TOP;
    if (slot >= 7)
        edges &= ~WLR_EDGE_BOTTOM;

    return edges;
}

static uint32_t get_slot_from_tiled_edges(uint32_t edges)
{
    for (int slot = 0; slot <= 9; slot++)
    {
        if (get_tiled_edges_for_slot(slot) == edges)
            return slot;
    }

    return 0;
}

class wayfire_grid : public wf::plugin_interface_t
{
    std::vector<std::string> slots = {"unused", "bl", "b", "br", "l", "c", "r", "tl", "t", "tr"};
    std::vector<std::string> default_keys = {
        "none",
        "<alt> <ctrl> KEY_KP1",
        "<alt> <ctrl> KEY_KP2",
        "<alt> <ctrl> KEY_KP3",
        "<alt> <ctrl> KEY_KP4",
        "<alt> <ctrl> KEY_KP5",
        "<alt> <ctrl> KEY_KP6",
        "<alt> <ctrl> KEY_KP7",
        "<alt> <ctrl> KEY_KP8",
        "<alt> <ctrl> KEY_KP9",
    };
    activator_callback bindings[10];
    wf_option keys[10];

    wf_option animation_duration, animation_type;

    wf_option restore_opt;
    std::string restore_opt_str;
    const std::string restore_opt_default = "toggle";

    activator_callback restore = [=] (wf_activator_source, uint32_t)
    {
        auto view = output->get_active_view();
        view->tile_request(0);
    };
    wf_option_callback restore_opt_changed = [=] ()
    {
        output->rem_binding(&restore);
        restore_opt_str = restore_opt->as_string();
        if (restore_opt_str != restore_opt_default)
            output->add_activator(restore_opt, &restore);
    };

    nonstd::observer_ptr<wayfire_grid_view_cdata>
        ensure_grid_view(wayfire_view view)
    {
        return ::ensure_grid_view(view, grab_interface,
            animation_type, animation_duration);
    }

    public:
    void init(wayfire_config *config)
    {
        grab_interface->name = "grid";
        grab_interface->capabilities = wf::CAPABILITY_MANAGE_DESKTOP;

        auto section = config->get_section("grid");
        animation_duration = section->get_option("duration", "300");
        animation_type = section->get_option("type", "simple");

        for (int i = 1; i < 10; i++)
        {
            keys[i] = section->get_option("slot_" + slots[i], default_keys[i]);

            bindings[i] = [=] (wf_activator_source, uint32_t)
            {
                auto view = output->get_active_view();
                if (!view || view->role != wf::VIEW_ROLE_TOPLEVEL)
                    return;

                handle_slot(view, i);
            };

            output->add_activator(keys[i], &bindings[i]);
        }

        restore_opt = section->get_option("restore", restore_opt_default);
        restore_opt_str = restore_opt->as_string();
        restore_opt_changed();
        restore_opt->add_updated_handler(&restore_opt_changed);

        output->connect_signal("reserved-workarea", &on_workarea_changed);
        output->connect_signal("view-snap", &on_snap_signal);
        output->connect_signal("query-snap-geometry", &on_snap_query);
        output->connect_signal("view-maximized-request", &on_maximize_signal);
        output->connect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }

    void handle_slot(wayfire_view view, int slot, wf_point delta = {0, 0})
    {
        view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(view)->adjust_target_geometry(
            get_slot_dimensions(slot) + delta,
            get_tiled_edges_for_slot(slot));
    }

    /* calculates the target geometry so that it is centered around the pointer */
    wf_geometry calculate_restored_geometry(wf_geometry base_restored)
    {
        GetTuple(cx, cy, output->get_cursor_position());
        base_restored.x = cx - base_restored.width / 2;
        base_restored.y = cy - base_restored.height / 2;

        /* if the view goes outside of the workarea, try to move it back inside */
        auto wa = output->workspace->get_workarea();
        if (base_restored.x + base_restored.width > wa.x + wa.width)
            base_restored.x = wa.x + wa.width - base_restored.width;
        if (base_restored.y + base_restored.height > wa.y + wa.width)
            base_restored.y = wa.y + wa.height - base_restored.width;
        if (base_restored.x < wa.x)
            base_restored.x = wa.x;
        if (base_restored.y < wa.y)
            base_restored.y = wa.y;

        return base_restored;
    }

    /*
     * 7 8 9
     * 4 5 6
     * 1 2 3
     * */
    wf_geometry get_slot_dimensions(int n)
    {
        auto area = output->workspace->get_workarea();
        int w2 = area.width / 2;
        int h2 = area.height / 2;

        if (n % 3 == 1)
            area.width = w2;
        if (n % 3 == 0)
            area.width = w2, area.x += w2;

        if (n >= 7)
            area.height = h2;
        else if (n <= 3)
            area.height = h2, area.y += h2;

        return area;
    }

    wf::signal_callback_t on_workarea_changed = [=] (wf::signal_data_t *data)
    {
        auto ev = static_cast<reserved_workarea_signal*> (data);
        for (auto& view : output->workspace->get_views_in_layer(wf::LAYER_WORKSPACE))
        {
            if (!view->is_mapped())
                continue;

            auto data = view->get_data_safe<wf_grid_slot_data>();

            /* Detect if the view was maximized outside of the grid plugin */
            auto wm = view->get_wm_geometry();
            if (view->tiled_edges && wm.width == ev->old_workarea.width
                && wm.height == ev->old_workarea.height)
            {
                data->slot = SLOT_CENTER;
            }

            if (!data->slot)
                continue;

            /* Workarea changed, and we have a view which is tiled into some slot.
             * We need to make sure it remains in its slot. So we calculate the
             * viewport of the view, and tile it there */
            auto output_geometry = output->get_relative_geometry();

            int vx = std::floor(1.0 * wm.x / output_geometry.width);
            int vy = std::floor(1.0 * wm.y / output_geometry.height);

            handle_slot(view, data->slot,
                {vx * output_geometry.width, vy * output_geometry.height});
        }
    };

    wf::signal_callback_t on_snap_query = [=] (wf::signal_data_t *data)
    {
        auto query = dynamic_cast<snap_query_signal*> (data);
        assert(query);
        query->out_geometry = get_slot_dimensions(query->slot);
    };

    wf::signal_callback_t on_snap_signal = [=] (wf::signal_data_t *ddata)
    {
        snap_signal *data = dynamic_cast<snap_signal*>(ddata);
        handle_slot(data->view, data->slot);
    };

    wf::signal_callback_t on_maximize_signal = [=] (wf::signal_data_t *ddata)
    {
        auto data = static_cast<view_tiled_signal*> (ddata);

        if (data->carried_out)
            return;
        data->carried_out = true;

        uint32_t slot = get_slot_from_tiled_edges(data->edges);
        if (slot > 0)
            data->desired_size = get_slot_dimensions(slot);

        /** XXX: If move is active, we want the restored geometry to be centered
         * around the cursor and visible on the screen */
        if (output->is_plugin_active("move") && !data->edges)
            data->desired_size = calculate_restored_geometry(data->desired_size);

        data->view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(data->view)->adjust_target_geometry(data->desired_size,
            get_tiled_edges_for_slot(slot));
    };

    wf::signal_callback_t on_fullscreen_signal = [=] (wf::signal_data_t *ev)
    {
        auto data = static_cast<view_fullscreen_signal*> (ev);
        static const std::string fs_data_name = "grid-saved-fs";

        if (data->carried_out)
            return;

        data->carried_out = true;
        ensure_grid_view(data->view)->adjust_target_geometry(
            data->desired_size, -1);
    };

    void fini()
    {
        for (int i = 1; i < 10; i++)
            output->rem_binding(&bindings[i]);

        output->rem_binding(&restore);

        output->disconnect_signal("reserved-workarea", &on_workarea_changed);
        output->disconnect_signal("view-snap", &on_snap_signal);
        output->disconnect_signal("query-snap-geometry", &on_snap_query);
        output->disconnect_signal("view-maximized-request", &on_maximize_signal);
        output->disconnect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_grid);
<commit_msg>grid: unsnap the view when not maximizing and using wobbly<commit_after>#include <plugin.hpp>
#include <debug.hpp>
#include <output.hpp>
#include <core.hpp>
#include <view.hpp>
#include <workspace-manager.hpp>
#include <render-manager.hpp>
#include <algorithm>
#include <cmath>
#include <linux/input-event-codes.h>
#include "signal-definitions.hpp"
#include <animation.hpp>

#include "snap_signal.hpp"
#include "../wobbly/wobbly-signal.hpp"

extern "C"
{
#include <wlr/util/edges.h>
}

const std::string grid_view_id = "grid-view";

class wayfire_grid_view_cdata : public wf::custom_data_t
{
    wf_duration duration;
    bool is_active = true;

    wayfire_view view;
    wf::output_t *output;
    wf::effect_hook_t pre_hook;
    wf::signal_callback_t unmapped;

    int32_t tiled_edges = -1;
    wf_geometry target, initial;
    const wf::plugin_grab_interface_uptr& iface;
    wf_option animation_type;

    public:

    wayfire_grid_view_cdata(wayfire_view view,
        const wf::plugin_grab_interface_uptr& _iface,
        wf_option animation_type, wf_option animation_duration)
        : iface(_iface)
    {
        this->view = view;
        this->output = view->get_output();
        this->animation_type = animation_type;
        duration = wf_duration(animation_duration);

        if (!view->get_output()->activate_plugin(iface))
        {
            is_active = false;
            return;
        }

        pre_hook = [=] () {
            adjust_geometry();
        };
        output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);

        unmapped = [=] (wf::signal_data_t *data)
        {
            if (get_signaled_view(data) == view)
                destroy();
        };

        output->render->set_redraw_always(true);
        output->connect_signal("view-disappeared", &unmapped);
        output->connect_signal("detach-view", &unmapped);
    }

    void destroy()
    {
        view->erase_data<wayfire_grid_view_cdata>();
    }

    void adjust_target_geometry(wf_geometry geometry, int32_t target_edges)
    {
        target = geometry;
        initial = view->get_wm_geometry();

        /* Restore tiled edges if we don't need to set something special when
         * grid is ready */
        if (target_edges < 0) {
            this->tiled_edges = view->tiled_edges;
        } else {
            this->tiled_edges = target_edges;
        }

        auto type = animation_type->as_string();
        if (view->get_transformer("wobbly") || !is_active)
            type = "wobbly";

        if (type == "none")
        {
            set_end_state(geometry, tiled_edges);
            return destroy();
        }

        if (type == "wobbly")
        {
            /* Order is important here: first we set the view geometry, and
             * after that we set the snap request. Otherwise the wobbly plugin
             * will think the view actually moved */
            set_end_state(geometry, tiled_edges);
            snap_wobbly(view, geometry);

            if (tiled_edges <= 0) // release snap, so subsequent size changes don't bother us
                snap_wobbly(view, geometry, false);

            return destroy();
        }

        view->set_tiled(wf::TILED_EDGES_ALL);
        view->set_moving(1);
        view->set_resizing(1);
        duration.start();
    }

    void set_end_state(wf_geometry geometry, int32_t edges)
    {
        view->set_geometry(geometry);
        if (edges >= 0)
            view->set_tiled(edges);
    }

    void adjust_geometry()
    {
        if (!duration.running())
        {
            set_end_state(target, tiled_edges);
            view->set_moving(0);
            view->set_resizing(0);

            return destroy();
        }

        int cx = duration.progress(initial.x, target.x);
        int cy = duration.progress(initial.y, target.y);
        int cw = duration.progress(initial.width, target.width);
        int ch = duration.progress(initial.height, target.height);

        view->set_geometry({cx, cy, cw, ch});
    }

    ~wayfire_grid_view_cdata()
    {
        if (!is_active)
            return;

        output->render->rem_effect(&pre_hook);
        output->deactivate_plugin(iface);
        output->render->set_redraw_always(false);
        output->disconnect_signal("view-disappeared", &unmapped);
        output->disconnect_signal("detach-view", &unmapped);
    }
};

class wf_grid_slot_data : public wf::custom_data_t
{
    public:
        int slot;
};

nonstd::observer_ptr<wayfire_grid_view_cdata> ensure_grid_view(wayfire_view view,
        const wf::plugin_grab_interface_uptr& iface, wf_option animation_type,
        wf_option animation_duration)
{
    if (!view->has_data<wayfire_grid_view_cdata>())
    {
        view->store_data(std::make_unique<wayfire_grid_view_cdata>
            (view, iface, animation_type, animation_duration));
    }

    return view->get_data<wayfire_grid_view_cdata> ();
}

class wf_grid_saved_view_geometry : public wf::custom_data_t
{
    public:
    wf_geometry geometry;
    uint32_t tiled_edges;
};

/*
 * 7 8 9
 * 4 5 6
 * 1 2 3
 */
static uint32_t get_tiled_edges_for_slot(uint32_t slot)
{
    if (slot == 0)
        return 0;

    uint32_t edges = wf::TILED_EDGES_ALL;
    if (slot % 3 == 0)
        edges &= ~WLR_EDGE_LEFT;
    if (slot % 3 == 1)
        edges &= ~WLR_EDGE_RIGHT;
    if (slot <= 3)
        edges &= ~WLR_EDGE_TOP;
    if (slot >= 7)
        edges &= ~WLR_EDGE_BOTTOM;

    return edges;
}

static uint32_t get_slot_from_tiled_edges(uint32_t edges)
{
    for (int slot = 0; slot <= 9; slot++)
    {
        if (get_tiled_edges_for_slot(slot) == edges)
            return slot;
    }

    return 0;
}

class wayfire_grid : public wf::plugin_interface_t
{
    std::vector<std::string> slots = {"unused", "bl", "b", "br", "l", "c", "r", "tl", "t", "tr"};
    std::vector<std::string> default_keys = {
        "none",
        "<alt> <ctrl> KEY_KP1",
        "<alt> <ctrl> KEY_KP2",
        "<alt> <ctrl> KEY_KP3",
        "<alt> <ctrl> KEY_KP4",
        "<alt> <ctrl> KEY_KP5",
        "<alt> <ctrl> KEY_KP6",
        "<alt> <ctrl> KEY_KP7",
        "<alt> <ctrl> KEY_KP8",
        "<alt> <ctrl> KEY_KP9",
    };
    activator_callback bindings[10];
    wf_option keys[10];

    wf_option animation_duration, animation_type;

    wf_option restore_opt;
    std::string restore_opt_str;
    const std::string restore_opt_default = "toggle";

    activator_callback restore = [=] (wf_activator_source, uint32_t)
    {
        auto view = output->get_active_view();
        view->tile_request(0);
    };
    wf_option_callback restore_opt_changed = [=] ()
    {
        output->rem_binding(&restore);
        restore_opt_str = restore_opt->as_string();
        if (restore_opt_str != restore_opt_default)
            output->add_activator(restore_opt, &restore);
    };

    nonstd::observer_ptr<wayfire_grid_view_cdata>
        ensure_grid_view(wayfire_view view)
    {
        return ::ensure_grid_view(view, grab_interface,
            animation_type, animation_duration);
    }

    public:
    void init(wayfire_config *config)
    {
        grab_interface->name = "grid";
        grab_interface->capabilities = wf::CAPABILITY_MANAGE_DESKTOP;

        auto section = config->get_section("grid");
        animation_duration = section->get_option("duration", "300");
        animation_type = section->get_option("type", "simple");

        for (int i = 1; i < 10; i++)
        {
            keys[i] = section->get_option("slot_" + slots[i], default_keys[i]);

            bindings[i] = [=] (wf_activator_source, uint32_t)
            {
                auto view = output->get_active_view();
                if (!view || view->role != wf::VIEW_ROLE_TOPLEVEL)
                    return;

                handle_slot(view, i);
            };

            output->add_activator(keys[i], &bindings[i]);
        }

        restore_opt = section->get_option("restore", restore_opt_default);
        restore_opt_str = restore_opt->as_string();
        restore_opt_changed();
        restore_opt->add_updated_handler(&restore_opt_changed);

        output->connect_signal("reserved-workarea", &on_workarea_changed);
        output->connect_signal("view-snap", &on_snap_signal);
        output->connect_signal("query-snap-geometry", &on_snap_query);
        output->connect_signal("view-maximized-request", &on_maximize_signal);
        output->connect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }

    void handle_slot(wayfire_view view, int slot, wf_point delta = {0, 0})
    {
        view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(view)->adjust_target_geometry(
            get_slot_dimensions(slot) + delta,
            get_tiled_edges_for_slot(slot));
    }

    /* calculates the target geometry so that it is centered around the pointer */
    wf_geometry calculate_restored_geometry(wf_geometry base_restored)
    {
        GetTuple(cx, cy, output->get_cursor_position());
        base_restored.x = cx - base_restored.width / 2;
        base_restored.y = cy - base_restored.height / 2;

        /* if the view goes outside of the workarea, try to move it back inside */
        auto wa = output->workspace->get_workarea();
        if (base_restored.x + base_restored.width > wa.x + wa.width)
            base_restored.x = wa.x + wa.width - base_restored.width;
        if (base_restored.y + base_restored.height > wa.y + wa.width)
            base_restored.y = wa.y + wa.height - base_restored.width;
        if (base_restored.x < wa.x)
            base_restored.x = wa.x;
        if (base_restored.y < wa.y)
            base_restored.y = wa.y;

        return base_restored;
    }

    /*
     * 7 8 9
     * 4 5 6
     * 1 2 3
     * */
    wf_geometry get_slot_dimensions(int n)
    {
        auto area = output->workspace->get_workarea();
        int w2 = area.width / 2;
        int h2 = area.height / 2;

        if (n % 3 == 1)
            area.width = w2;
        if (n % 3 == 0)
            area.width = w2, area.x += w2;

        if (n >= 7)
            area.height = h2;
        else if (n <= 3)
            area.height = h2, area.y += h2;

        return area;
    }

    wf::signal_callback_t on_workarea_changed = [=] (wf::signal_data_t *data)
    {
        auto ev = static_cast<reserved_workarea_signal*> (data);
        for (auto& view : output->workspace->get_views_in_layer(wf::LAYER_WORKSPACE))
        {
            if (!view->is_mapped())
                continue;

            auto data = view->get_data_safe<wf_grid_slot_data>();

            /* Detect if the view was maximized outside of the grid plugin */
            auto wm = view->get_wm_geometry();
            if (view->tiled_edges && wm.width == ev->old_workarea.width
                && wm.height == ev->old_workarea.height)
            {
                data->slot = SLOT_CENTER;
            }

            if (!data->slot)
                continue;

            /* Workarea changed, and we have a view which is tiled into some slot.
             * We need to make sure it remains in its slot. So we calculate the
             * viewport of the view, and tile it there */
            auto output_geometry = output->get_relative_geometry();

            int vx = std::floor(1.0 * wm.x / output_geometry.width);
            int vy = std::floor(1.0 * wm.y / output_geometry.height);

            handle_slot(view, data->slot,
                {vx * output_geometry.width, vy * output_geometry.height});
        }
    };

    wf::signal_callback_t on_snap_query = [=] (wf::signal_data_t *data)
    {
        auto query = dynamic_cast<snap_query_signal*> (data);
        assert(query);
        query->out_geometry = get_slot_dimensions(query->slot);
    };

    wf::signal_callback_t on_snap_signal = [=] (wf::signal_data_t *ddata)
    {
        snap_signal *data = dynamic_cast<snap_signal*>(ddata);
        handle_slot(data->view, data->slot);
    };

    wf::signal_callback_t on_maximize_signal = [=] (wf::signal_data_t *ddata)
    {
        auto data = static_cast<view_tiled_signal*> (ddata);

        if (data->carried_out)
            return;
        data->carried_out = true;

        uint32_t slot = get_slot_from_tiled_edges(data->edges);
        if (slot > 0)
            data->desired_size = get_slot_dimensions(slot);

        /** XXX: If move is active, we want the restored geometry to be centered
         * around the cursor and visible on the screen */
        if (output->is_plugin_active("move") && !data->edges)
            data->desired_size = calculate_restored_geometry(data->desired_size);

        data->view->get_data_safe<wf_grid_slot_data>()->slot = slot;
        ensure_grid_view(data->view)->adjust_target_geometry(data->desired_size,
            get_tiled_edges_for_slot(slot));
    };

    wf::signal_callback_t on_fullscreen_signal = [=] (wf::signal_data_t *ev)
    {
        auto data = static_cast<view_fullscreen_signal*> (ev);
        static const std::string fs_data_name = "grid-saved-fs";

        if (data->carried_out)
            return;

        data->carried_out = true;
        ensure_grid_view(data->view)->adjust_target_geometry(
            data->desired_size, -1);
    };

    void fini()
    {
        for (int i = 1; i < 10; i++)
            output->rem_binding(&bindings[i]);

        output->rem_binding(&restore);

        output->disconnect_signal("reserved-workarea", &on_workarea_changed);
        output->disconnect_signal("view-snap", &on_snap_signal);
        output->disconnect_signal("query-snap-geometry", &on_snap_query);
        output->disconnect_signal("view-maximized-request", &on_maximize_signal);
        output->disconnect_signal("view-fullscreen-request", &on_fullscreen_signal);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_grid);
<|endoftext|>


<commit_before>/*******************************************************************************
 * thrill/net/flow_control_channel.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Emanuel Jöbstl <emanuel.joebstl@gmail.com>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <thrill/net/flow_control_channel.hpp>

namespace thrill {
namespace net {

// TODO

} // namespace net
} // namespace thrill

/******************************************************************************/
<commit_msg>Removing empty flow_control_channel.cpp<commit_after><|endoftext|>


<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_POLYGON_COLLISION_DETECTION_HPP__
#define LASERCAKE_POLYGON_COLLISION_DETECTION_HPP__

#include <cassert>
#include <vector>
#include <array>

#include "utils.hpp"
#include "boost/rational.hpp"

// 64 bits though these ints are, you can't really do collision detection with them except for things
//  with a max distance of about 14 bits between any of the parts of them.

struct polygon_collision_info_cache {
  polygon_collision_info_cache():is_valid(false){}
  bool is_valid;
  vector3<int64_t> translation_amount;
  int64_t denom;
  int64_t a_times_denom;
  int64_t b_times_denom;
  int amount_twisted;
  std::vector<vector3<int64_t>> adjusted_vertices;
};

struct bounding_box {
  bounding_box():is_anywhere(false){}
  bounding_box(vector3<int64_t> loc):is_anywhere(true),min(loc),max(loc){}
  bounding_box(vector3<int64_t> min, vector3<int64_t> max):is_anywhere(true),min(min),max(max){}

  bool is_anywhere;
  vector3<int64_t> min, max;

  bool contains(vector3<int64_t> const& v)const;
  bool overlaps(bounding_box const& o)const;
  void combine_with(bounding_box const& o);
  void restrict_to(bounding_box const& o);
};
inline std::ostream& operator<<(std::ostream& os, bounding_box const& bb) {
  return os << '[' << bb.min << ',' << bb.max << ']';
}

struct line_segment {
  line_segment(std::array<vector3<int64_t>, 2> ends):ends(ends){}
  line_segment(vector3<int64_t> end1, vector3<int64_t> end2):ends({{end1, end2}}){}
  std::array<vector3<int64_t>, 2> ends;

  void translate(vector3<int64_t> t);
  bounding_box bounds()const;
};

struct convex_polygon {
  // The structure simply trusts that you will provide a convex, coplanar sequence of points. Failure to do so will result in undefined behavior.
  void setup_cache_if_needed()const;
  convex_polygon(std::vector<vector3<int64_t>> const& vertices):vertices(vertices){ assert(vertices.size() >= 3); }
  polygon_collision_info_cache const& get_cache()const { return cache; }
  std::vector<vector3<int64_t>> const& get_vertices()const { return vertices; }
  void translate(vector3<int64_t> t);
  bounding_box bounds()const;
private:
  std::vector<vector3<int64_t>> vertices;
  mutable polygon_collision_info_cache cache;
};

class shape {
public:
  shape(                                       ): bounds_cache_is_valid(false)                {}
  shape(               line_segment const& init): bounds_cache_is_valid(false)                { segments.push_back(init); }
  shape(             convex_polygon const& init): bounds_cache_is_valid(false)                { polygons.push_back(init); }
  shape(std::vector<convex_polygon> const& init): bounds_cache_is_valid(false), polygons(init){}
  shape(               bounding_box const& init);

  shape(shape const& o):bounds_cache(o.bounds_cache),bounds_cache_is_valid(o.bounds_cache_is_valid),segments(o.segments),polygons(o.polygons) {}

  void translate(vector3<int64_t> t);

  bool intersects(shape const& other)const;
  // returns (was there an intersection?, what fraction of the length of the line segment was the first)
  std::pair<bool, boost::rational<int64_t>> first_intersection(line_segment const& other)const;
  bounding_box bounds()const;

  std::vector<  line_segment> const& get_segments()const { return segments; }
  std::vector<convex_polygon> const& get_polygons()const { return polygons; }
private:
  mutable bounding_box bounds_cache;
  mutable bool bounds_cache_is_valid;

  std::vector<  line_segment> segments;
  std::vector<convex_polygon> polygons;
};

/*bool intersects(line_segment l, convex_polygon const& p);
bool intersects(convex_polygon const& p1, convex_polygon const& p2);
bool intersects(line_segment const& l, std::vector<convex_polygon> const& ps);
bool intersects(std::vector<convex_polygon> const& ps1, std::vector<convex_polygon> const& ps2);*/

#endif

<commit_msg>add ==/!= to bounding_box<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_POLYGON_COLLISION_DETECTION_HPP__
#define LASERCAKE_POLYGON_COLLISION_DETECTION_HPP__

#include <cassert>
#include <vector>
#include <array>

#include "utils.hpp"
#include "boost/rational.hpp"

// 64 bits though these ints are, you can't really do collision detection with them except for things
//  with a max distance of about 14 bits between any of the parts of them.

struct polygon_collision_info_cache {
  polygon_collision_info_cache():is_valid(false){}
  bool is_valid;
  vector3<int64_t> translation_amount;
  int64_t denom;
  int64_t a_times_denom;
  int64_t b_times_denom;
  int amount_twisted;
  std::vector<vector3<int64_t>> adjusted_vertices;
};

struct bounding_box {
  bounding_box():is_anywhere(false){}
  bounding_box(vector3<int64_t> loc):is_anywhere(true),min(loc),max(loc){}
  bounding_box(vector3<int64_t> min, vector3<int64_t> max):is_anywhere(true),min(min),max(max){}

  bool is_anywhere;
  vector3<int64_t> min, max;

  bool contains(vector3<int64_t> const& v)const;
  bool overlaps(bounding_box const& o)const;
  void combine_with(bounding_box const& o);
  void restrict_to(bounding_box const& o);
};
inline bool operator==(bounding_box const& b1, bounding_box const& b2) {
  return (b1.is_anywhere == false && b2.is_anywhere == false) ||
    (b1.is_anywhere == b2.is_anywhere && b1.min == b2.min && b1.max == b2.max);
}
inline bool operator!=(bounding_box const& b1, bounding_box const& b2) {
  return !(b1 == b2);
}
inline std::ostream& operator<<(std::ostream& os, bounding_box const& bb) {
  return os << '[' << bb.min << ',' << bb.max << ']';
}

struct line_segment {
  line_segment(std::array<vector3<int64_t>, 2> ends):ends(ends){}
  line_segment(vector3<int64_t> end1, vector3<int64_t> end2):ends({{end1, end2}}){}
  std::array<vector3<int64_t>, 2> ends;

  void translate(vector3<int64_t> t);
  bounding_box bounds()const;
};

struct convex_polygon {
  // The structure simply trusts that you will provide a convex, coplanar sequence of points. Failure to do so will result in undefined behavior.
  void setup_cache_if_needed()const;
  convex_polygon(std::vector<vector3<int64_t>> const& vertices):vertices(vertices){ assert(vertices.size() >= 3); }
  polygon_collision_info_cache const& get_cache()const { return cache; }
  std::vector<vector3<int64_t>> const& get_vertices()const { return vertices; }
  void translate(vector3<int64_t> t);
  bounding_box bounds()const;
private:
  std::vector<vector3<int64_t>> vertices;
  mutable polygon_collision_info_cache cache;
};

class shape {
public:
  shape(                                       ): bounds_cache_is_valid(false)                {}
  shape(               line_segment const& init): bounds_cache_is_valid(false)                { segments.push_back(init); }
  shape(             convex_polygon const& init): bounds_cache_is_valid(false)                { polygons.push_back(init); }
  shape(std::vector<convex_polygon> const& init): bounds_cache_is_valid(false), polygons(init){}
  shape(               bounding_box const& init);

  shape(shape const& o):bounds_cache(o.bounds_cache),bounds_cache_is_valid(o.bounds_cache_is_valid),segments(o.segments),polygons(o.polygons) {}

  void translate(vector3<int64_t> t);

  bool intersects(shape const& other)const;
  // returns (was there an intersection?, what fraction of the length of the line segment was the first)
  std::pair<bool, boost::rational<int64_t>> first_intersection(line_segment const& other)const;
  bounding_box bounds()const;

  std::vector<  line_segment> const& get_segments()const { return segments; }
  std::vector<convex_polygon> const& get_polygons()const { return polygons; }
private:
  mutable bounding_box bounds_cache;
  mutable bool bounds_cache_is_valid;

  std::vector<  line_segment> segments;
  std::vector<convex_polygon> polygons;
};

/*bool intersects(line_segment l, convex_polygon const& p);
bool intersects(convex_polygon const& p1, convex_polygon const& p2);
bool intersects(line_segment const& l, std::vector<convex_polygon> const& ps);
bool intersects(std::vector<convex_polygon> const& ps1, std::vector<convex_polygon> const& ps2);*/

#endif

<|endoftext|>


<commit_before>#include "output_hls.h"
#include <mist/defines.h>
#include <mist/http_parser.h>
#include <mist/stream.h>
#include <unistd.h>

namespace Mist {
  ///\brief Builds an index file for HTTP Live streaming.
  ///\return The index file for HTTP Live Streaming.
  std::string OutHLS::liveIndex(){
    std::stringstream result;
    result << "#EXTM3U\r\n";
    int audioId = -1;
    std::string audioName;
    for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
      if (it->second.codec == "AAC"){
        audioId = it->first;
        audioName = it->second.getIdentifier();
        break;
      }
    }
    for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
      if (it->second.codec == "H264"){
        int bWidth = it->second.bps * 2;
        if (audioId != -1){
          bWidth += myMeta.tracks[audioId].bps * 2;
        }
        result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << bWidth * 10 << "\r\n";
        result << it->first;
        if (audioId != -1){
          result << "_" << audioId;
        }
        result << "/index.m3u8\r\n";
      }
    }
#if DEBUG >= 8
    std::cerr << "Sending this index:" << std::endl << result.str() << std::endl;
#endif
    return result.str();
  }

  std::string OutHLS::liveIndex(int tid){
    updateMeta();
    std::stringstream result;
    //parse single track
    int longestFragment = 0;
    if (!myMeta.tracks[tid].fragments.size()){
      DEBUG_MSG(DLVL_FAIL, "liveIndex called with track %d, which has no fragments!", tid);
      return "";
    }
    for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); (it + 1) != myMeta.tracks[tid].fragments.end(); it++){
      if (it->getDuration() > longestFragment){
        longestFragment = it->getDuration();
      }
    }
    result << "#EXTM3U\r\n"
        "#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n"
        "#EXT-X-MEDIA-SEQUENCE:" << myMeta.tracks[tid].missedFrags << "\r\n";
    for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); it != myMeta.tracks[tid].fragments.end(); it++){
      long long int starttime = myMeta.tracks[tid].getKey(it->getNumber()).getTime();

      if (it != (myMeta.tracks[tid].fragments.end() - 1)){
        result << "#EXTINF:" << ((it->getDuration() + 500) / 1000) << ", no desc\r\n" << starttime << "_" << it->getDuration() + starttime << ".ts\r\n";
      }
    }
    if ( !myMeta.live){
      result << "#EXT-X-ENDLIST\r\n";
    }
#if DEBUG >= 8
    std::cerr << "Sending this index:" << std::endl << result.str() << std::endl;
#endif
    return result.str();
  } //liveIndex

  OutHLS::OutHLS(Socket::Connection & conn) : Output(conn) {
    haveAvcc = false;
    myConn.setHost(config->getString("ip"));
    streamName = config->getString("streamname");
  }

  OutHLS::~OutHLS() {}

  void OutHLS::onFail(){
    HTTP_S.Clean(); //make sure no parts of old requests are left in any buffers
    HTTP_S.SetBody("Stream not found. Sorry, we tried.");
    HTTP_S.SendResponse("404", "Stream not found", myConn);
    Output::onFail();
  }

  void OutHLS::init(Util::Config * cfg){
    Output::init(cfg);
    capa["name"] = "HLS";
    capa["desc"] = "Enables HTTP protocol Apple-specific streaming (also known as HLS).";
    capa["deps"] = "HTTP";
    capa["url_rel"] = "/hls/$/index.m3u8";
    capa["url_prefix"] = "/hls/$/";
    capa["socket"] = "http_hls";
    capa["codecs"][0u][0u].append("H264");
    capa["codecs"][0u][1u].append("AAC");
    capa["methods"][0u]["handler"] = "http";
    capa["methods"][0u]["type"] = "html5/application/vnd.apple.mpegurl";
    capa["methods"][0u]["priority"] = 9ll;
    cfg->addBasicConnectorOptions(capa);
    config = cfg;
  }

  void OutHLS::sendNext(){
    Socket::Buffer ToPack;
    char * ContCounter = 0;
    bool IsKeyFrame = false;

    char * dataPointer = 0;
    unsigned int dataLen = 0;
    currentPacket.getString("data", dataPointer, dataLen);

    if (currentPacket.getTime() >= until){
      DEBUG_MSG(DLVL_DEVEL, "(%d) Done sending fragment", getpid() );
      stop();
      wantRequest = true;
      HTTP_S.Chunkify("", 0, myConn);
      HTTP_S.Clean();
      return;
    }

    //detect packet type, and put converted data into ToPack.
    if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){
      ToPack.append(TS::Packet::getPESVideoLeadIn(0ul, currentPacket.getTime() * 90));

      IsKeyFrame = currentPacket.getInt("keyframe");
      if (IsKeyFrame){
        if (!haveAvcc){
          avccbox.setPayload(myMeta.tracks[currentPacket.getTrackId()].init);
          haveAvcc = true;
        }
        ToPack.append(avccbox.asAnnexB());
      }
      unsigned int i = 0;
      while (i + 4 < (unsigned int)dataLen){
        unsigned int ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3];
        if (ThisNaluSize + i + 4 > (unsigned int)dataLen){
          DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen);
          break;
        }
        ToPack.append("\000\000\000\001", 4);
        i += 4;
        ToPack.append(dataPointer + i, ThisNaluSize);
        i += ThisNaluSize;
      }
      ContCounter = &VideoCounter;
    }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){
      if (AppleCompat){
        ToPack.append(TS::Packet::getPESAudioLeadIn(7+dataLen, lastVid));
      }else{
        ToPack.append(TS::Packet::getPESAudioLeadIn(7+dataLen, currentPacket.getTime() * 90));
      }
      ToPack.append(TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init));
      ToPack.append(dataPointer, dataLen);
      ContCounter = &AudioCounter;
    }

    bool first = true;
    //send TS packets
    while (ToPack.size()){
      if (PacketNumber % 42 == 0){
        HTTP_S.Chunkify(TS::PAT, 188, myConn);
        HTTP_S.Chunkify(TS::PMT, 188, myConn);
        PacketNumber += 2;
      }
      PackData.Clear();
      /// \todo Update according to sendHeader()'s generated data.
      //0x100 - 1 + currentPacket.getTrackId()
      if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){
        PackData.PID(0x100);
      }else{
        PackData.PID(0x101);
      }
      PackData.ContinuityCounter((*ContCounter)++);
      if (first){
        PackData.UnitStart(1);
        if (IsKeyFrame){
          PackData.RandomAccess(1);
          PackData.PCR(currentPacket.getTime() * 27000);
        }
        first = false;
      }
      unsigned int toSend = PackData.AddStuffing(ToPack.bytes(184));
      std::string gonnaSend = ToPack.remove(toSend);
      PackData.FillFree(gonnaSend);
      HTTP_S.Chunkify(PackData.ToString(), 188, myConn);
      PacketNumber ++;
    }
  }

  int OutHLS::canSeekms(unsigned int ms){
    //no tracks? Frame too new by definition.
    if ( !myMeta.tracks.size()){
      return 1;
    }
    //loop trough all the tracks
    for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
      //return "too late" if one track is past this point
      if (ms < it->second.firstms){
        return -1;
      }
      //return "too early" if one track is not yet at this point
      if (ms > it->second.lastms){
        return 1;
      }
    }
    return 0;
  }

  void OutHLS::onRequest(){
    while (HTTP_R.Read(myConn)){
      DEBUG_MSG(DLVL_DEVEL, "Received request: %s", HTTP_R.getUrl().c_str());
      AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos);
      initialize();
      if (HTTP_R.url.find(".m3u") == std::string::npos){
        std::string tmpStr = HTTP_R.getUrl();
        std::string fmtStr = "/hls/" + streamName + "/%u_%u/%llu_%llu.ts";
        long long unsigned int from;
        if (sscanf(tmpStr.c_str(), fmtStr.c_str(), &vidTrack, &audTrack, &from, &until) != 4){
          fmtStr = "/hls/" + streamName + "/%u/%llu_%llu.ts";
          if (sscanf(tmpStr.c_str(), fmtStr.c_str(), &vidTrack, &from, &until) != 3){
            WARN_MSG("Could not parse URL: %s", HTTP_R.getUrl().c_str());
            HTTP_S.Clean();
            HTTP_S.SetBody("The HLS URL wasn't understood - what did you want, exactly?\n");
            myConn.SendNow(HTTP_S.BuildResponse("404", "URL mismatch"));
            HTTP_R.Clean(); //clean for any possible next requests
            continue;
          }else{
            selectedTracks.clear();
            selectedTracks.insert(vidTrack);
          }
        }else{
          selectedTracks.clear();
          selectedTracks.insert(vidTrack);
          selectedTracks.insert(audTrack);
        }

        if (myMeta.live){
          /// \todo Detection of out-of-range parts.
          int seekable = canSeekms(from);
          if (seekable < 0){
            HTTP_S.Clean();
            HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
            myConn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
            HTTP_R.Clean(); //clean for any possible next requests
            DEBUG_MSG(DLVL_WARN, "Fragment @ %llu too old", from);
            continue;
          }
          if (seekable > 0){
            HTTP_S.Clean();
            HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
            myConn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
            HTTP_R.Clean(); //clean for any possible next requests
            DEBUG_MSG(DLVL_WARN, "Fragment @ %llu not available yet", from);
            continue;
          }
        }

        seek(from);
        lastVid = from * 90;

        HTTP_S.Clean();
        HTTP_S.SetHeader("Content-Type", "video/mp2t");
        HTTP_S.StartResponse(HTTP_R, myConn);
        PacketNumber = 0;
        parseData = true;
        wantRequest = false;
      }else{
        initialize();
        std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1);
        HTTP_S.Clean();
        if (HTTP_R.url.find(".m3u8") != std::string::npos){
          HTTP_S.SetHeader("Content-Type", "audio/x-mpegurl");
        }else{
          HTTP_S.SetHeader("Content-Type", "audio/mpegurl");
        }
        HTTP_S.SetHeader("Cache-Control", "no-cache");
        std::string manifest;
        if (request.find("/") == std::string::npos){
          manifest = liveIndex();
        }else{
          int selectId = atoi(request.substr(0,request.find("/")).c_str());
          manifest = liveIndex(selectId);
        }
        HTTP_S.SetBody(manifest);
        HTTP_S.SendResponse("200", "OK", myConn);
      }
      HTTP_R.Clean(); //clean for any possible next requests
    }
  }
}
<commit_msg>HLS will now force-skip the first fragment if live and there are more than 2 fragments buffered.<commit_after>#include "output_hls.h"
#include <mist/defines.h>
#include <mist/http_parser.h>
#include <mist/stream.h>
#include <unistd.h>

namespace Mist {
  ///\brief Builds an index file for HTTP Live streaming.
  ///\return The index file for HTTP Live Streaming.
  std::string OutHLS::liveIndex(){
    std::stringstream result;
    result << "#EXTM3U\r\n";
    int audioId = -1;
    std::string audioName;
    for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
      if (it->second.codec == "AAC"){
        audioId = it->first;
        audioName = it->second.getIdentifier();
        break;
      }
    }
    for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
      if (it->second.codec == "H264"){
        int bWidth = it->second.bps * 2;
        if (audioId != -1){
          bWidth += myMeta.tracks[audioId].bps * 2;
        }
        result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << bWidth * 10 << "\r\n";
        result << it->first;
        if (audioId != -1){
          result << "_" << audioId;
        }
        result << "/index.m3u8\r\n";
      }
    }
#if DEBUG >= 8
    std::cerr << "Sending this index:" << std::endl << result.str() << std::endl;
#endif
    return result.str();
  }

  std::string OutHLS::liveIndex(int tid){
    updateMeta();
    std::stringstream result;
    //parse single track
    int longestFragment = 0;
    if (!myMeta.tracks[tid].fragments.size()){
      DEBUG_MSG(DLVL_FAIL, "liveIndex called with track %d, which has no fragments!", tid);
      return "";
    }
    for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); (it + 1) != myMeta.tracks[tid].fragments.end(); it++){
      if (it->getDuration() > longestFragment){
        longestFragment = it->getDuration();
      }
    }
    result << "#EXTM3U\r\n"
        "#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n"
        "#EXT-X-MEDIA-SEQUENCE:" << myMeta.tracks[tid].missedFrags << "\r\n";
    for (std::deque<DTSC::Fragment>::iterator it = myMeta.tracks[tid].fragments.begin(); it != myMeta.tracks[tid].fragments.end(); it++){
      if (myMeta.live && myMeta.tracks[tid].fragments.size() > 2 && it == myMeta.tracks[tid].fragments.begin()){
        //skip the first fragment if live and there are more than 2 fragments.
        continue;
      }
      long long int starttime = myMeta.tracks[tid].getKey(it->getNumber()).getTime();

      if (it != (myMeta.tracks[tid].fragments.end() - 1)){
        result << "#EXTINF:" << ((it->getDuration() + 500) / 1000) << ", no desc\r\n" << starttime << "_" << it->getDuration() + starttime << ".ts\r\n";
      }
    }
    if ( !myMeta.live){
      result << "#EXT-X-ENDLIST\r\n";
    }
#if DEBUG >= 8
    std::cerr << "Sending this index:" << std::endl << result.str() << std::endl;
#endif
    return result.str();
  } //liveIndex

  OutHLS::OutHLS(Socket::Connection & conn) : Output(conn) {
    haveAvcc = false;
    myConn.setHost(config->getString("ip"));
    streamName = config->getString("streamname");
  }

  OutHLS::~OutHLS() {}

  void OutHLS::onFail(){
    HTTP_S.Clean(); //make sure no parts of old requests are left in any buffers
    HTTP_S.SetBody("Stream not found. Sorry, we tried.");
    HTTP_S.SendResponse("404", "Stream not found", myConn);
    Output::onFail();
  }

  void OutHLS::init(Util::Config * cfg){
    Output::init(cfg);
    capa["name"] = "HLS";
    capa["desc"] = "Enables HTTP protocol Apple-specific streaming (also known as HLS).";
    capa["deps"] = "HTTP";
    capa["url_rel"] = "/hls/$/index.m3u8";
    capa["url_prefix"] = "/hls/$/";
    capa["socket"] = "http_hls";
    capa["codecs"][0u][0u].append("H264");
    capa["codecs"][0u][1u].append("AAC");
    capa["methods"][0u]["handler"] = "http";
    capa["methods"][0u]["type"] = "html5/application/vnd.apple.mpegurl";
    capa["methods"][0u]["priority"] = 9ll;
    cfg->addBasicConnectorOptions(capa);
    config = cfg;
  }

  void OutHLS::sendNext(){
    Socket::Buffer ToPack;
    char * ContCounter = 0;
    bool IsKeyFrame = false;

    char * dataPointer = 0;
    unsigned int dataLen = 0;
    currentPacket.getString("data", dataPointer, dataLen);

    if (currentPacket.getTime() >= until){
      DEBUG_MSG(DLVL_DEVEL, "(%d) Done sending fragment", getpid() );
      stop();
      wantRequest = true;
      HTTP_S.Chunkify("", 0, myConn);
      HTTP_S.Clean();
      return;
    }

    //detect packet type, and put converted data into ToPack.
    if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){
      ToPack.append(TS::Packet::getPESVideoLeadIn(0ul, currentPacket.getTime() * 90));

      IsKeyFrame = currentPacket.getInt("keyframe");
      if (IsKeyFrame){
        if (!haveAvcc){
          avccbox.setPayload(myMeta.tracks[currentPacket.getTrackId()].init);
          haveAvcc = true;
        }
        ToPack.append(avccbox.asAnnexB());
      }
      unsigned int i = 0;
      while (i + 4 < (unsigned int)dataLen){
        unsigned int ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3];
        if (ThisNaluSize + i + 4 > (unsigned int)dataLen){
          DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen);
          break;
        }
        ToPack.append("\000\000\000\001", 4);
        i += 4;
        ToPack.append(dataPointer + i, ThisNaluSize);
        i += ThisNaluSize;
      }
      ContCounter = &VideoCounter;
    }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){
      if (AppleCompat){
        ToPack.append(TS::Packet::getPESAudioLeadIn(7+dataLen, lastVid));
      }else{
        ToPack.append(TS::Packet::getPESAudioLeadIn(7+dataLen, currentPacket.getTime() * 90));
      }
      ToPack.append(TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init));
      ToPack.append(dataPointer, dataLen);
      ContCounter = &AudioCounter;
    }

    bool first = true;
    //send TS packets
    while (ToPack.size()){
      if (PacketNumber % 42 == 0){
        HTTP_S.Chunkify(TS::PAT, 188, myConn);
        HTTP_S.Chunkify(TS::PMT, 188, myConn);
        PacketNumber += 2;
      }
      PackData.Clear();
      /// \todo Update according to sendHeader()'s generated data.
      //0x100 - 1 + currentPacket.getTrackId()
      if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){
        PackData.PID(0x100);
      }else{
        PackData.PID(0x101);
      }
      PackData.ContinuityCounter((*ContCounter)++);
      if (first){
        PackData.UnitStart(1);
        if (IsKeyFrame){
          PackData.RandomAccess(1);
          PackData.PCR(currentPacket.getTime() * 27000);
        }
        first = false;
      }
      unsigned int toSend = PackData.AddStuffing(ToPack.bytes(184));
      std::string gonnaSend = ToPack.remove(toSend);
      PackData.FillFree(gonnaSend);
      HTTP_S.Chunkify(PackData.ToString(), 188, myConn);
      PacketNumber ++;
    }
  }

  int OutHLS::canSeekms(unsigned int ms){
    //no tracks? Frame too new by definition.
    if ( !myMeta.tracks.size()){
      return 1;
    }
    //loop trough all the tracks
    for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
      //return "too late" if one track is past this point
      if (ms < it->second.firstms){
        return -1;
      }
      //return "too early" if one track is not yet at this point
      if (ms > it->second.lastms){
        return 1;
      }
    }
    return 0;
  }

  void OutHLS::onRequest(){
    while (HTTP_R.Read(myConn)){
      DEBUG_MSG(DLVL_DEVEL, "Received request: %s", HTTP_R.getUrl().c_str());
      AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos);
      initialize();
      if (HTTP_R.url.find(".m3u") == std::string::npos){
        std::string tmpStr = HTTP_R.getUrl();
        std::string fmtStr = "/hls/" + streamName + "/%u_%u/%llu_%llu.ts";
        long long unsigned int from;
        if (sscanf(tmpStr.c_str(), fmtStr.c_str(), &vidTrack, &audTrack, &from, &until) != 4){
          fmtStr = "/hls/" + streamName + "/%u/%llu_%llu.ts";
          if (sscanf(tmpStr.c_str(), fmtStr.c_str(), &vidTrack, &from, &until) != 3){
            WARN_MSG("Could not parse URL: %s", HTTP_R.getUrl().c_str());
            HTTP_S.Clean();
            HTTP_S.SetBody("The HLS URL wasn't understood - what did you want, exactly?\n");
            myConn.SendNow(HTTP_S.BuildResponse("404", "URL mismatch"));
            HTTP_R.Clean(); //clean for any possible next requests
            continue;
          }else{
            selectedTracks.clear();
            selectedTracks.insert(vidTrack);
          }
        }else{
          selectedTracks.clear();
          selectedTracks.insert(vidTrack);
          selectedTracks.insert(audTrack);
        }

        if (myMeta.live){
          /// \todo Detection of out-of-range parts.
          int seekable = canSeekms(from);
          if (seekable < 0){
            HTTP_S.Clean();
            HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
            myConn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
            HTTP_R.Clean(); //clean for any possible next requests
            DEBUG_MSG(DLVL_WARN, "Fragment @ %llu too old", from);
            continue;
          }
          if (seekable > 0){
            HTTP_S.Clean();
            HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
            myConn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
            HTTP_R.Clean(); //clean for any possible next requests
            DEBUG_MSG(DLVL_WARN, "Fragment @ %llu not available yet", from);
            continue;
          }
        }

        seek(from);
        lastVid = from * 90;

        HTTP_S.Clean();
        HTTP_S.SetHeader("Content-Type", "video/mp2t");
        HTTP_S.StartResponse(HTTP_R, myConn);
        PacketNumber = 0;
        parseData = true;
        wantRequest = false;
      }else{
        initialize();
        std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1);
        HTTP_S.Clean();
        if (HTTP_R.url.find(".m3u8") != std::string::npos){
          HTTP_S.SetHeader("Content-Type", "audio/x-mpegurl");
        }else{
          HTTP_S.SetHeader("Content-Type", "audio/mpegurl");
        }
        HTTP_S.SetHeader("Cache-Control", "no-cache");
        std::string manifest;
        if (request.find("/") == std::string::npos){
          manifest = liveIndex();
        }else{
          int selectId = atoi(request.substr(0,request.find("/")).c_str());
          manifest = liveIndex(selectId);
        }
        HTTP_S.SetBody(manifest);
        HTTP_S.SendResponse("200", "OK", myConn);
      }
      HTTP_R.Clean(); //clean for any possible next requests
    }
  }
}
<|endoftext|>