Macでの仮想デスクトップ

最近、Ubuntuで仮想デスクトップの有用性にようやく気づき、常に使用するようになりました。
そんなこともあり、ではMacでもやってみよう、と思いました。
概念というか操作体系も違っているので以下紹介しておきます。Mountain Lion上でMissionControlという機能の話となります。

まず現状のデスクトップの利用状況をみるためにトラックパッドを指三本で手前から奥へスライドさせます。(逆にスライドさせると元に戻ります。)
すると、

となります。
ここで扱うデスクトップを追加するには、まず、ポインタを画面の端へ持っていくと出現する「+」エリア(下図、赤枠)を表示させます。

そのエリアに中央のウィンドウをドラッグアンドドロップすると、

「デスクトップ2」として追加になりました。
この状態で上部のデスクトップをクリックして画面を切り替えることもできますが、3本指で奥から手前へスライドして元の画面に戻ったあと、3本指で左右にスライドさせることでもデスクトップを切り替えることができます。

ほかにもいろいろできそうですが、試してみてください。

Titanium StudioによるAndroid/iOSアプリ開発事始め

先日、AndroidとiOSの両プラットフォームで動作するゲームを作成することになりました。そこで開発環境を選定を行いました。
当初は、Unityを使用することにほぼ決めていたのですが、もっと選択肢があるのではと、急遽選定作業をやり直しました。すると無料で良い環境がいくつか見つかってきました。

  1. ngCore
  2. PhoneGap
  3. Titanium Mobile

です。ngCoreはマーケットがmobageに限定されるようで実績のない者には少し敷居が高いと感じました。(実際にアプリを提供するとなったときの話。開発自体はすごくやりやすそう。本気でビジネスにしていくときはこれかなと思いました。)
PhoneGapとTitanium Mobileはいろいろなところで比較されていました。総合的にはTitanium Mobileに軍配があがっているようです。PhoneGapのほうはWebKit上で動作するもの、TitaniumはNativeのアプリになっていること、ここが大きな違いのようです。楽をしたいならPhoneGap、こだわりたいならTitaniumといったところでしょうか。

私はこだわれるTitanium Mobileで開発していくことにし、早速、
JavaScriptとTitaniumではじめる iPhone/Androidアプリプログラミング

を読みました。非常に短時間で広い範囲を理解することができ、以降で説明する作業に取りかかれました。

まず、環境をダウンロードすべくhttps://www.appcelerator.comにて開発者登録をし、環境を構築し、サンプルアプリの起動まで確認しました。

赤枠で示したスタートアップのドキュメントがしっかりしていて、特に詰まることなくサンプルアプリ起動まで進められました。ドキュメントは英語ですが、図がほとんどですので問題なく進められると思います。

Tizen 2.0 alpha SDKをUbuntu 12.10へインストール

Tizen 2.0 alpha SDKをUbuntu 12.10へインストールについて、いくつかネット上に転がっていた情報とは異なる点があったので、その点を含めてインストール手順を書いておきます。

私はMacBook Proを使っています。すでにWindows 7をBootCampで利用するため、VMWare Fusionをインストールしていました。ここにUbuntu 12.10をインストールしました。Ubuntu Desktop 日本語 Remix CDを使用しました。

Tizen SDKインストールという本題からは話が逸れますが、Ubuntuが日本語環境にならないという現象に見舞われました。これは私の単純なミスでした。VMWare FusionでUbunutをインストールするときに、「簡易インストール」という機能があり、これを有効にしてインストールしていたためです。
「簡易インストールを使用」のチェックを外し、[続ける]をクリック。

さて、話を戻します。Ubuntuをインストール後、まずTizenに必要なパッケージをいくつか用意します。

まずはOracle Java 7

> sudo add-apt-repository pap:webupd8team/java
> sudo apt-get update
> sudo apt-get install oracle-java7-installer

あとはSDKの提供元(https://developer.tizen.org/downloads/sdk)
In Ubuntu®, the following packages: procps, gettext, libdbus-1-3, libcurl3, expect, gtk2-engines-pixbuf, grep, zip, make, and qemu-user-static
という情報があるので、足りないものを

> sudo apt-get install gettext libcurl3 expect libgnome2-0

でインストールしました。これで事前準備完了です。(この時点ではですが。)

次はインストーラの用意です。今回は(imageではなくて、)ネットワークを利用するので、
SDKの提供元からInstall Manager(tizen-sdk-2.0-ubuntu32.bin)をダウンロードします。

> chmod +x tizen-sdk-2.0-ubuntu32.bin
> ./tizen-sdk-2.0-ubuntu32.bin

これでWizardにしたがっていけば、インストール完了です。

インストール後、推奨環境(11.10など)でないためか、いくつかおかしな点がわかってきました。
まず、Unityのランチャーなどには登録されません。
ですので、コマンドラインからIDEを起動しました。

> ./tizen-sdk/ide/startup.sh

無事に立ち上がりましたが、Tizen Web Projectを新規作成しようとしたところで、次のエラーがでました。


Unhandled event loop exception
No more handles

An SWT error has occurred.
You are recommended to exit the workbench.
Subsequent errors may happen and may terminate the workbench without warning.
See the .log file for more details.
Do you want to exit the workbench?

これらエラーは以下で対応できました。

> sudo apt-get install libwebkitgtk-1.0.0

さて、無事プロジェクトを作成できるようになりましたので、実際にエミュレータで動かしたく、エミュレータマネージャーでエミュレータの生成を行います。

> ./tizen-sdk/tools/emulator/bin/emulator-manager

x86-standardでエミュレータを作成します。そして、作成エミューレータを起動すべく、「Launch」ボタンをクリックします。
ここで、何も反応がない状態となりました。どうやら起動に失敗しているようです。

作成したエミュレータはx86エミュレータと連携して動いているようなですので、まずx86エミュレータが動作しているのかを確認してみると、

> ./tizen-sdk/tools/emulator/bin/emulator-x86
./tizen-sdk/tools/emulator/bin/emulator-x86: error while loading shared libraries: libSDL-1.2.so.0: cannot open shared object file: No such file or directory

とlibSDL-1.2.so.0がない旨を返してきます。

そこで、

> sudo apt-get install libsdl1.2debian

すると、

> ./tizen-sdk/tools/emulator/bin/emulator-x86
Segmentation fault (コアダンプ)

とlibSDL-1.2.so.0を見つけられるようになります。(コアをはいていますが、emulator-x86が本来単独で動くものではなく、無理矢理動かしているからだと思われます。)
ちなみに、推奨環境バージョンのUbuntuでは元々/usr/lib/i386-linux-gnu/libSDL-1.2.so.0が置かれていました。

さて、emulator-managerを起動し、「Launch」ボタンをクリックします。
起動しました。

ひとまず、Tizenの開発を進められる状態になったと思っています。
しかしながら、「推奨環境でやるべきだったなぁ」というのが本音というか反省すべき点です。

Mountain Lionにおけるホイールスクロール方向の変更

Lionからのことらしいですが、ホイールによるスクロールの方向が逆になっています。iPhoneやiPadなどのタッチパネルでのスクロール動作に合わせた結果のようです。
しばらく気にせず使用していましたが、MacからWindows、あるいはWidowsからMacへ作業環境を変更した直後数分慣れるまでの煩わしさを解消する必要性を感じ、Mac側のスクロール方向を従来のものに戻すことにしました。

方法は、「システム環境設定」→「マウス」にて、
「スクロール方向:ナチュラル」についているチェックを外すのみです。

ミラーリングポートに接続する機器のIP

かなりの期間、知らずにいたことですが、ミラーリングポートにパケットキャプチャの目的で接続する機器にそのネットワークのIPがふられている必要がないということ。

IPが何であろうがミラーリングポートにはパケットが流れてくるため、接続する機器は否応なしにパケットを見ることができます。
ですので、ネットワーク障害が発生したら、下記のようなミラーリングポート付きのハブとWiresharkのようなパケットをみることのできるソフトの入ったノートPCを持って行き、ネットワーク設定なしで即解析にはいることができます。

vectorの気遣い

vectorで(ポインタではなく)オブジェクト自体を取り扱う場合、push_backしたときに次のことが行われています。

  • push_backの対象となるオブジェクトをコピーコンストラクタでコピー
  • 既にpush_back済みのものがあれば、再びコピーコンストラクタでそのコピーを作り、元々コピーしてあったものをデストラクタで始末する。

実際にコードを書いて確認してみました。
まずは、クラス定義から。

class Hoge
{
public:
  int num;
  Hoge(int num);
  Hoge(const Hoge& me);
  ~Hoge();
  void printAbc(void);
};

Hoge::Hoge(int aNum)
{
  num = aNum;
  printf("constructer %d\n", num);
}

Hoge::Hoge(const Hoge& me) : num(me.num)
{
  printf("copy constructer %d\n", num);
}

Hoge::~Hoge()
{
  printf("destructer %d\n", num);
}

実際にvectorを使ってクラスHogeのオブジェクトを操作してみます。

int main(int argc, char** argv)
{
  Hoge sample1(1);
  Hoge sample2(2);
  std::vector<Hoge> iremono;

  iremono.push_back(sample1);
  iremono.push_back(sample2);

  return 0;
}

コンパイルして実行しますと、次のような結果が得られます。

constructer 1
constructer 2
copy constructer 1
copy constructer 2
copy constructer 1
destructer 1
destructer 1
destructer 2
destructer 2
destructer 1

最初のコンストラクタ二つは、ソースの3,4行目によるものです。このコンストラクタに対するデストラクタは、最後の二つで、mainを抜ける際に、ローカル変数であるsample1,sample2に対して発生しています。
最初のコピーコンストラクタは一回目のpush_back時に、つまりsample1のpush時に発生しています。そして次のコピーコンストラクタは二回目のpush_back時、つまりsample2のpush時に発生しています。直後、一回目のコピーコンストラクタでコピーされたもののコピーが発生しています。そして、次のデストラクタで一回目のpush_back時にコピーしたもののデストラクタが発生しています。
つまり、push_back時にはpushしたものがコピーされるだけではなく、既に入っているものも同時にコピーし直されます。

そして、次のデストラクタ二つはローカル変数iremonoがmainから抜けるとき、中のオブジェクトのデストラクタが発生することを示しています。このように明示しなくても中のオブジェクトをデストラクトしてくれるのは、vectorで(ポインタではなく)オブジェクト自体を持つことのメリットだと思います。ちなみに、このときのデストラクタの発生する順番はpush_backした順番です。

私はvectorでオブジェクト自体を持つのは避けるようにしています。上記のようなメリットはあるのですが、vectorの「気遣い」であるコピーコンストラクタ、デストラクタに、反って戸惑わされる恐れがあるからです。それよりも「後始末をしっかりする」ことさえ注意していればよい「ポインタを持つ」方が楽なのでは、と考えています。

Androidでスクリーンショット

以前iPhoneユーザがお手軽にスクリーンショットを撮っているのをみて、Androidでもできないかと調べてみたのですが、手順がややこしくとても実用的なものではなかったので諦めていました。
ところが今日、何気にAndroidのSDカードの直下を見てみると「screen shot」という見慣れないフォルダができているのを発見しました。中を見ると、2週間ほどまえの日付のホーム画面の画像がPNGで保存されていました。
さっそく再調査してみたところ、一部機種(私はGALAPAGOS SoftBank 003SHを使っています。)はホームボタンと電源ボタンの同時押しでスクリーンショットが撮れるとのこと。
試してみると見事に撮れました。

2週間ほど前に意図せず撮れていたスクリーンショットが功を奏したかたちとなりました。

MacBook Pro(15-Inch, Early 2011)のメモリ4GB→16GB増設

MacBook Pro(15-Inch, Early 2011)

を現在のSnow Leopard から Mountain Lionにしようと思ったのですが、どうも現在の4GBのメモリでは苦しそうだということが、いろいろな方のブログなどからわかりました。

そこで今回のメモリの増設となりました。このMacBook Proの公式な対応メモリ容量のMAXは8GBなのですが、いろいろな方の情報だと16GBも可能、とのことでしたので、8GBメモリの二枚挿し、16GBに増設することにしました。

肝心のメモリは、Transcend JetRam ノートPC用増設メモリ PC3-10600(DDR3-1333) 8GB 永久保証 JM1333KSH-8G
(※2019年10月31日現在の最新モデル)
を2枚購入しました。Tポイントも使えましたので、合計5000円ほどで購入しました。
また、裏ぶたをあけるためのドライバを100円ショップで購入しました。

数日後、メモリが無事届きました。
届いたメモリ

さっそく裏ぶたをはずそうとしたのですが、どうしても緩められないネジがありました。100円ショップで購入した#00のプラスドライバーではグリップに力が入らないためのようで、しっかりしたドライバーを買う必要があると判断し、
VESSEL(ベッセル) マイクロドライバー No.9900 +00×75

を購入しました。

数日後、ドライバーが無事届きました。
届いたドライバー

半信半疑でしたが、届いたドライバーを使うとあっけなく裏ぶたを開けることができました。
蓋開け直後

中央部にメモリのスロットがあり、両サイドのフックを広げて外すと二枚重なっているのがわかります。
二枚重なっているメモリ

二枚を届いたメモリと交換し、裏ぶたを閉めて、動作確認をしました。
mac_16gb

BootCampに入れているWindows7でも当然16GBになっています。
win_16gb

メモリ増設成功です。

コマンドラインからmp4動画の任意場面をキャプチャする

キャプチャに使用するプログラムはフリーの動画プレイヤーとして有名なVLC Media Playerです。
インストールするとGUIで使用できるのはもちろんですが、CUIでも使用できます。
そして、VLCにはキャプチャ機能が備わっており、CUIからも使用できます。つまり、これはプログラムから起動(例えばfork&exec)させ、裏(GUI表示なし)でキャプチャができることを意味しています。

キャプチャは以下のコマンドで可能です。

cvlc hoge.mp4 --rate=1 --video-filter=scene --vout=dummy --start-time=0 --stop-time=0.5 --scene-format=jpg --scene-ratio=500 --scene-prefix=foo --scene-replace --scene-path=. vlc://quit

start-timeとstop-timeでキャプチャする対象となるシーンの位置を指定します。(単位は秒)
できるだけコマンド実行を早く終わらせるために、start-timeとstop-timeの間は小さくしたほうがいいです。(ちなみに同じ値にするとキャプチャできません。)
scene-ratioはキャプチャをする間隔(何フレーム毎にキャプチャするか)で、上記のように比較的大きな値にしておけばキャプチャは1度しか行われません。(上記の場合0.5秒間なので500フレームもあるはずないということです。最初のフレームをキャプチャした後、次のキャプチャまで500フレーム待ちますが、その前にstop-timeになって終了、、、という流れです。)

実行後、実行したディレクトリに
foo.jpg
というファイルができているはずです。

vectorに詰め込んだオブジェクト解放するための便利関数

久しぶりにテンプレート関数を使おうとしたときのいくつかの間違いを覚書として書いておきます。

Utilityクラスなるものを用意し、次のような静的メソッドを宣言、定義しました。

Utility.h

template<typename T>
static void Utility::releaser(std::vector<T*>& v);

Utility.cpp

template<typename T>
void Utility::releaser(std::vector<T*>& v)
{
  std::vector<T*>::iterator it;
  it = v.begin();
  while(it != v.end()){
    delete (*it);
    it = v.erase(it);
  }
}

これをコンパイルすると、

.cpp: 静的メンバ関数 ‘static void Utility::releaser(std::vector<T*>&)’ 内:
.cpp:???:???: エラー: need ‘typename’ before ‘std::vector<T*>::iterator’ because ‘std::vector<T*>’ is a dependent scope
.cpp:???:???: エラー: expected ‘;’ before ‘it’
.cpp:???:???: エラー: ‘it’ was not declared in this scope

といったエラーがでます。

because ‘std::vector’ is a dependent scope
はstd::vectorという部分がTに依存するため、型なのか変数名なのか、何なのか分からない、ということ言っています。
(VC++の場合は、問題なくコンパイルが通るらしいです。)

need ‘typename’ before ‘std::vector::iterator’
型だと分かるように「typename」をつけてください、と言っています。
この時点でこのコンパイラ自身は型だとわかっているようですが、どんなコンパイラでも通るように厳しく戒めてくれている、という理解です。

Utility.cpp

template<typename T>
void Utility::releaser(std::vector<T*>& v)
{
  typename std::vector<T*>::iterator it;

  it = v.begin();
  while(it != v.end()){
    delete (*it);
    it = v.erase(it);
  }
}

言われた通りにつけてみましたが、今度は、

Hoge.o: In function `hogehoge(void)':
Hoge.cpp:???: undefined reference to `void Utility::releaser<Hoge>(std::vector<Hoge*, std::allocator<Hoge*> >&)'

と怒られてしまいました。
これは実際にHoge.cppでUtility::releaserを使用している個所でその実体が何か分からない、ということを言っています。
Utility.cppにおいて、クラスHogeを考慮したテンプレート関数の実体化を行っていない、かつ、Hoge.cppでも実体化を行っていないためです。
そこで、Hoge.cppで実体化が行われるように、Utility.h、つまりヘッダにテンプレートの実装を書きます。
Utility.cppの実装は消去し、

Utility.h

template<typename T>
static void Utility::releaser(std::vector<T*>& v)
{
  typename std::vector<T*>::iterator it;

  it = v.begin();
  while(it != v.end()){
    delete (*it);
    it = v.erase(it);
  }
};

これで、テンプレート関数が使えます。

どうしても定義と実装を分けたい場合は、
明示的実装というものがあり、分けることもできるそうです。
予めテンプレートの使用パターンを宣言しておくというやり方です。
また、exportという記述子があり、定義と実装を分け、予めのパターン列挙も必要ないそうです。
ただし、こちらは対応コンパイラが少ないそうです。

このあたりのお話は、こちらが参考になりました。
http://d.hatena.ne.jp/pknight/20090826/1251303641
http://d.hatena.ne.jp/pknight/20090826/1251307608