ページ

2009年5月31日日曜日

開発したCocoaアプリにアイコンを設定する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

アイコン画像が既に手元にあるとする。



まずアイコン作成ソフト Icon Composer を起動する。


今回は 128x128ピクセルの画像だけ用意したので、これを 128の欄へドラッグ&ドロップする。


これよりも小さなサイズへ縮小して使い回すかどうか聞かれるので、その通りにしておく。


最後に simplecap.icns で保存しておく。


次にターゲットのプロパティを開く。


「アイコンファイル」へ simplecap.icns を指定する。


これでビルドすると、できあがったアプリケーションファイルのアイコンが指定したものに変わる。



参考:
ザリガニが見ていた...。
Cocoaアプリケーションのアイコンを設定する方法

2009年5月30日土曜日

SimpleCapアイコン(作成中)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

SimpleCapが遅れに遅れている。その一つがアイコン。

キャップにひっかけて。不気味だ。。


PCのキャプチャということで。


範囲選択にひっかけて。



ほぼこれに決まり。

2009年5月29日金曜日

http://xcatsan.blogspot.com/ - 対応をお願いします

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

突然googleから昨日メールが届いた。

ユーザー各位

ブログ http://xcatsan.blogspot.com/ はスパム ブログの可能性があります。これを解決するには、
http://www.blogger.com/unlock-blog.g?lockedBlogID=xxxxxxxxxxxxx にあるフォームに記入して、
ブログの確認をリクエストしてください。

確認を受けなければ、ブログは 20 日以内に削除され、この間は読者に対して警告ページを表示します。
Google はリクエストを受け取りますと、2 営業日以内にブログを確認してロックを解除いたします。
ブログがスパムでないことが確認されると、ブログのロックが解除され、Blogger ダッシュボードのメッ
セージが表示されなくなります。このブログがご自分のものでない場合は何もする必要はなく、ご自分の
ブログに影響はありません。

Google では自動分類機能を使用してスパムを検出しています。スパム検出システムは自動化されてい
るため、適切なブログが誤ってスパムと識別されることがあります。ご不便をおかけしますが何卒ご了
承ください。ただし、このようなシステムを使用することにより、不正業者ではないブログ利用者の方
々により多くの保存容量、帯域幅、エンジニアリング リソースをご利用いただけます。詳細について
はhttp://help.blogger.com/bin/answer.py?answer=42577 で Blogger のヘルプをご覧ください。

Google のスパム対策をご理解、ご支援いただき、ありがとうございます。

今後ともよろしくお願いいたします。

Blogger チーム

補足: ブログの確認をリクエストしなければ、ブログは 20 日以内に削除されます。
ブログの確認をリクエストするには、次のリンクをクリックしてください:
http://www.blogger.com/unlock-blog.g?lockedBlogID=xxxxxxxxxxx


なんてこった。ブログがスパムと勘違いされている?
ブログの編集画面へアクセスすると確かにロックされていた。


投稿時にも CAPTCHA認証が必要になったいる


仕方なくメール記載のURL へアクセスしてみる。



文字を入力して解除する。後でメールが来るとのこと。

- - - - -
自動でスパム検出しているんだろうけど、気分悪いな。やめて欲しい。

2009年5月28日木曜日

WebKit検証(34) - キャッシュ設定を変更(その2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

ネットで調べていると WebKit のソースコードらしきものが見つかった。

WebPreferences.m

この中にこんなコードがあった。

static WebCacheModel cacheModelForMainBundle(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// Apps that probably need the small setting
static const char* const documentViewerIDs[] = {
"Microsoft/com.microsoft.Messenger",
"com.adiumX.adiumX",
"com.alientechnology.Proteus",
"com.apple.Dashcode",
"com.apple.iChat",
"com.barebones.bbedit",
"com.barebones.textwrangler",
"com.barebones.yojimbo",
"com.equinux.iSale4",
"com.growl.growlframework",
"com.intrarts.PandoraMan",
"com.karelia.Sandvox",
"com.macromates.textmate",
"com.realmacsoftware.rapidweaverpro",
"com.red-sweater.marsedit",
"com.yahoo.messenger3",
"de.codingmonkeys.SubEthaEdit",
"fi.karppinen.Pyro",
"info.colloquy",
"kungfoo.tv.ecto",
};

// Apps that probably need the medium setting
static const char* const documentBrowserIDs[] = {
"com.apple.Dictionary",
"com.apple.Xcode",
"com.apple.dashboard.client",
"com.apple.helpviewer",
"com.culturedcode.xyle",
"com.macrabbit.CSSEdit",
"com.panic.Coda",
"com.ranchero.NetNewsWire",
"com.thinkmac.NewsLife",
"org.xlife.NewsFire",
"uk.co.opencommunity.vienna2",
};

// Apps that probably need the large setting
static const char* const primaryWebBrowserIDs[] = {
"com.app4mac.KidsBrowser"
"com.app4mac.wKiosk",
"com.freeverse.bumpercar",
"com.omnigroup.OmniWeb5",
"com.sunrisebrowser.Sunrise",
"net.hmdt-web.Shiira",
};

WebCacheModel cacheModel;

const char* bundleID = [[[NSBundle mainBundle] bundleIdentifier] UTF8String];
if (contains(documentViewerIDs, sizeof(documentViewerIDs) / sizeof(documentViewerIDs[0]), bundleID))
cacheModel = WebCacheModelDocumentViewer;
else if (contains(documentBrowserIDs, sizeof(documentBrowserIDs) / sizeof(documentBrowserIDs[0]), bundleID))
cacheModel = WebCacheModelDocumentBrowser;
else if (contains(primaryWebBrowserIDs, sizeof(primaryWebBrowserIDs) / sizeof(primaryWebBrowserIDs[0]), bundleID))
cacheModel = WebCacheModelPrimaryWebBrowser;
else {
bool isLegacyApp = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_CACHE_MODEL_API);
if (isLegacyApp)
cacheModel = WebCacheModelDocumentBrowser; // To avoid regressions in apps that depended on old WebKit's large cache.
else
cacheModel = WebCacheModelDocumentViewer; // To save memory.
}

[pool drain];

return cacheModel;
}


キャッシュモデルを自動判別しているようだが、どうもアプリの種類によって決めているようだ。

シイラがあった。
     "net.hmdt-web.Shiira",



進展無し...

2009年5月27日水曜日

WebKit検証(33) - キャッシュ設定を変更

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

キャッシュの効果は(当たり前だが)実感できて、Apple.com のページで確認したところ初回表示に5〜6秒かかるところが2回目以降は1秒未満で表示できた。

パラメータを変更してみよう。
試しにキャッシュ設定を切ってみる。

 WebPreferences* wpref = [_web preferences];
[wpref setUsesPageCache:NO];



実行するが、キャッシュファイルは作成されて実際にキャッシュの効果もあるようだ。ファイルの中身も変わらない。


試しに WebCacheModel を変更してみる。
enum {
WebCacheModelDocumentViewer = 0,
WebCacheModelDocumentBrowser = 1,
WebCacheModelPrimaryWebBrowser = 2
};
typedef NSUInteger WebCacheModel;



が、どれも動作に差異はなかった。

Apple.comトップページのキャッシュデータの件数もどれも同じ。
$ sqlite3 Cache.db 
SQLite version 3.4.0
Enter ".help" for instructions
sqlite> select count(*) from cfurl_cache_response;
121


- - - -
どうもこの方法では制御できないようだ。
以前は同じ WebPreferencesインスタンスを使い表示フォントを変更できたので、制御できそうなものだが、理由がわからない。

2009年5月26日火曜日

WebKit検証(32) - キャッシュの中身

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

キャッシュがどこかに作成されていないかと思い、探してみたところ ~/Library/Caches/ 配下に見つかった。


Cache.db というファイルが作成されていた。多分 SQLiteのDBと思い、sqlite3コマンドで読み込んでみたところその通りだった。

ターミナル

$ sqlite3 Cache.db 
SQLite version 3.4.0
Enter ".help" for instructions
sqlite> .tables
cfurl_cache_blob_data cfurl_cache_schema_version
cfurl_cache_response
sqlite>


3つのテーブルが作成されていた。定義や中のデータはこんな感じ。

cfulr_cache_schmea_version
(定義)

sqlite> .schema cfurl_cache_schema_version
CREATE TABLE cfurl_cache_schema_version(schema_version INTEGER);


(中身)
sqlite> select * from cfurl_cache_schema_version;
8



cfurl_cache_response
(定義)

sqlite> .schema cfurl_cache_response
CREATE TABLE cfurl_cache_response(
entry_ID INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
version INTEGER,
hash_value INTEGER,
storage_policy INTEGER,
request_key TEXT UNIQUE,
time_stamp NOT NULL DEFAULT CURRENT_TIMESTAMP);
CREATE INDEX request_key_index ON cfurl_cache_response(request_key);
CREATE INDEX time_stamp_index ON cfurl_cache_response(time_stamp);


(中身)
sqlite> select * from cfurl_cache_response;
1|0|462566830|0|http://www.apple.com/|2009-05-26 21:43:57
2|0|-632403425|0|http://images.apple.com/global/scripts/lib/prototype.js|2009-05-26 21:43:57
3|0|-1064591170|0|http://images.apple.com/global/scripts/lib/scriptaculous.js|2009-05-26 21:43:57
:
:



cfurl_cache_blob_data
(定義)

sqlite> .schema cfurl_cache_blob_data
CREATE TABLE cfurl_cache_blob_data(
entry_ID INTEGER PRIMARY KEY,
response_object BLOB,
request_object BLOB,
receiver_data BLOB,
proto_props BLOB,
user_info BLOB);
CREATE INDEX proto_props_index ON cfurl_cache_blob_data(entry_ID);


(中身)
sqlite> select * from cfurl_cache_blob_data where entry_ID=1;
entry_ID|response_object|request_object|receiver_data|proto_props|user_info
7|<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Array</key>
<array>
<dict>
<key>_CFURLString</key>
:
:
|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en-us">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="pics-label" content='(pics-1.1 "http://www.icra.org/ratingsv02.html" l gen true for "http://www.apple.com" r (cz 1 lz 1 nz 1 oz 1 vz 1) "http://www.rsac.org/ratingsv01.html" l gen true for "http://www.apple.com" r



cfurl_cache_response にキャッシュ対象の URLとタイムスタンプなどのメタ情報が保存され、cfurl_cache_blob_data に実際のデータ(HTMLや画像)が格納されているようだ。

Cache.db はアプリを終了しても消えずに残っていた。

*検証環境
usesPageCache=1
webCacheModel=0

2009年5月25日月曜日

WebKit検証(31) - キャッシュの利用

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

WebPreferecesではキャッシュに関して4つのメソッドを用意している。セッタ/フッタの組なので実質的な情報としては2種類。

setUsesPageCache:
usesPageCache
setCacheModel:
cacheModel


setUsesPageCache:usesPageCache はキャッシュの利用を制御する。

setCacheModel:cacheModel はキャッシュ方法(モデル)を制御する。

デフォルトがどうなっているのか調べてみる。
- (void)awakeFromNib
{
WebPreferences* wpref = [_web preferences];
NSLog(@"usesPageCache=%d", [wpref usesPageCache]);
NSLog(@"webCacheModel=%d", [wpref cacheModel]);
:
}


実行結果は次の通り。
WebPrefStudy[1042:10b] usesPageCache=1
WebPrefStudy[1042:10b] webCacheModel=0



キャッシュを利用するようになっていて、キャッシュモデルは 0 が使われている。

キャッシュモデルは3タイプあるようだ。
WebCacheModel として定数定義されている。

enum {
WebCacheModelDocumentViewer = 0,
WebCacheModelDocumentBrowser = 1,
WebCacheModelPrimaryWebBrowser = 2
};
typedef NSUInteger WebCacheModel;


ドキュメントによれば、用途とボリュームによって使い分けるようだ。

WebCacheModelDocumentViewerは、(一般のWebブラウザで行えるリンククリックなどの操作を伴わない)単純な文書ビューア向けのモデル。メモリ利用はこれが一番少ない。

WebCacheModelDocumentBrowserは、複数の文書を(行ったり来たりしつつ)見るような用途向け。

WebCacheModelPrimaryWebBrowserは、多くの文書を扱う用途で利用する。Webブラウザ向け。

- - - -
次回はモデルを変えて挙動の違いを見てみよう。

2009年5月24日日曜日

WebKit検証(30) - WebPreferences(3) - フォントを変えてみる

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

フォントの変化がわかりやすい様にサイズも変えてみた。

- (void) changeFont: (id) sender
{
:
[pref setStandardFontFamily:[new_font fontName]];
[pref setDefaultFontSize:(int)[new_font pointSize]];
}


実行して


フォントの種類とサイズを変える。


サイズが変わった。種類は変わっていない。


WebPreferencesのサンセリフ(SansSerif)を変えてみる。
[pref setSansSerifFontFamily:[new_font fontName]];


フォントの種類が明朝体になった。


- - - -
最近のサイトはフォント指定があるものが多いので、ブラウザ側のフォント設定はあまり意味をなさなくなってきている。もちろん細かく設定できればそれにこしたことは無いのだが実用上は問題なさそうなので、Webキャプチャを作る場合に設定できなくて良いかもしれない。

2009年5月23日土曜日

フォントを変更する(4) NSFontPanelの変更を反映する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

#changeFont: を捕まえられたので、今度は変更内容をWebPreferences へ反映する。

AppController.m

- (void) changeFont: (id) sender
{
WebPreferences* pref = [_web preferences];
NSFont* old_font = [NSFont fontWithName:[pref standardFontFamily]
size:13];

NSFont* new_font = [sender convertFont:old_font];

[pref setStandardFontFamily:[new_font fontName]];
}


NSFontManager#convertFont: を使うと NSFontPanelで設定したフォントの NSFontインスタンスが得られる。これを WebPreferences へ設定してやれば良い。

実行してみよう。


フォント名称の表示が変わった。
ただ WebViewのフォントは変わらないな。

2009年5月22日金曜日

フォントを変更する(3) NSFontPanelの変更を受け取る

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

NSFontManagerのdelegateには #changeFont: というメソッドがあって、NSFontPanelでフォントを変更すると呼び出されるらしい。

Responding to Font Changes

前回も実は AppController.m でこれを受け取るコードを入れておいた。
AppController.m

- (IBAction)showFontPanel:(id)sender
{
:
[[NSFontManager sharedFontManager] setDelegate:self];
:
}
- (void)changeFont: (id) sender
{
NSLog(@"%@", sender);
}


ところがフォント変更しても呼び出されない。
よくよくドキュメントを読むと、このメソッドを起動するメッセージは、レスポンダチェーンに投げられるとのことだった。AppController は単なる NSObject だから、これではメッセージを受け取れないわけだ。そこで少し修正を入れる。

まずレスポンダチェーンに参加させるために AppController を NSWindowController のサブクラスにする。
AppController.h
@interface AppController : NSWindowController {
   :


次に Interface Builder上で NSWindowControllerのアウトレット"window"に、今回のウィンドウを指定する。


最後にコーディング。フォントの「選択する..」が押された時の処理を書く。
AppController.m
- (IBAction)showFontPanel:(id)sender
{
WebPreferences* pref = [_web preferences];
NSFont* font = [NSFont fontWithName:[pref standardFontFamily]
size:13];
[[sender window] makeFirstResponder:[sender window]];

NSFontManager* fm = [NSFontManager sharedFontManager];
[fm setDelegate:self];
[fm orderFrontFontPanel:self];
[fm setSelectedFont:font isMultiple:NO];
}



さて実行してフォントを変えてみる。


(コンソールに)出た。
2009-05-22 21:46:48.085 WebPrefStudy[15993:10b] 
2009-05-22 21:46:58.807 WebPrefStudy[15993:10b]



ポイントはレスポンダチェーンに参加させること。NSWindowControllerのアウトレット"window"をきちんと接続しないとやはりメッセージは飛んでこない。
それとウィンドウをファーストレスポンダーにしないとやはり飛んでこなかった。
 [[sender window] makeFirstResponder:[sender window]];



参考:
Re: NSFontManager changeFont not called

2009年5月21日木曜日

フォントを変更する(2) 現在のフォントをNSFontPanelへ反映させる

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

今度は現在使っているフォントを NSFontPanelへ反映してみる。
これには NSFontPanel#setPanelFont:isMultiple: を使う。

こんな感じ。

- (IBAction)showFontPanel:(id)sender
{
NSFontPanel* panel = [NSFontPanel sharedFontPanel];
WebPreferences* pref = [_web preferences];
NSFont* font = [NSFont fontWithName:[pref standardFontFamily] size:13];
[panel makeKeyAndOrderFront:self];
[panel setPanelFont:font isMultiple:NO];

[[NSFontManager sharedFontManager] setDelegate:self];
}


するとこうなる。


NSFontPanelを表示すると Times, 13pt が選択されている。

2009年5月20日水曜日

フォントを変更する(1) NSFontPanel表示

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

(前回からの続き)

次は「選択ボタン」を押したらフォントパネルを表示しよう。Interface Builderでできると思いきや方法がわからなかった。

とりあえずはADCのサンプルなどを参考にコードを書く。
PDF Annotation Editor

まずアクションを追加する。
AppController.h

- (IBAction)showFontPanel:(id)sender;


Interface Builderでここへ「選択ボタン」のアクションを追加する。

次にボタンが押されたときのコードを実装する。
AppController.m
- (IBAction)showFontPanel:(id)sender
{
[[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self];
[[NSFontManager sharedFontManager] setDelegate:self];
}



実行して「選択ボタン」を押す。


出た。

(当たり前だが)表示されているフォントとはまったく無関係。これをこれから関係づけていく。

2009年5月19日火曜日

WebKit検証(29) - WebPreferences(2) - Cocoaバインディング

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

WebPreferecnes の扱いは下記が詳しい。
WebPreferences を Cocoa バインディングで設定する

これを参考にしてまずは標準フォントの設定をやってみよう。

まず Interface Builderで NSObjectController を追加する。


これを AppController のアウトレットへ接続する。
AppController.h

@interface AppController : NSObject {
:
IBOutlet NSObjectController* _pref_controller;
}


そしてそのContentにWebPreferencesを設定する。
AppController.m
- (void)awakeFromNib
{
WebPreferences* wpref = [_web preferences];
[_pref_controller setContent:wpref];
:
}



最後に NSTextFiledとNSObjectControllerをバインディングする。
この NSTextFieldを選択し、


バインディング項目を設定する。


実行してみよう。



出た。

2009年5月18日月曜日

WebKit検証(28) - WebPreferences

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

プリファレンスの検証に入る。今日は検証用プロジェクトのベースを作っただけ。

2009年5月17日日曜日

webKit検証(27) - Webウィンドウを重ねる(5)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

気になる事が一つある。

先日作った NSWindowを2つ重ねる Webキャプチャで、起動直後には WebViewの載ったウィンドウが後ろに隠れて表示されない。


ウィンドウをクリックすると表に出てくるようになる。



色々試したがうまくいかない。

[_frame_window orderWindow:NSWindowBelow relativeTo:[_web_window windowNumber]];
[_frame_window makeKeyAndOrderFront:nil];
 :
 :


初期状態で一番上に表示するにはどうしたら良いのだろうか。

2009年5月16日土曜日

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

また新しい iPhoneのプログラミング本が出ていた。

2009年5月15日金曜日

webKit検証(26) - Webウィンドウを重ねる(4)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回は WebViewが載るウィンドウがファーストレスポンダ(Key Window)になれなかった。
そこで NSWindowのサブクラスを作ることにした。

WebWindow.h

@interface WebWindow : NSWindow {

}

@end


WebWindow.m
@implementation WebWindow
- (BOOL)canBecomeKeyWindow
{
return YES;
}
@end


わざわざサブクラス化したのは #canBecomeKeyWindow をオーバーライドしたかったから。YESを返す事でファーストレスポンダになれる。ただ実際にはこれだけでは不足でコントローラー側で NSWindow#makeKeyAndOrderFront: を呼出してやる必要があった。
 [_web_window makeKeyAndOrderFront:nil];


実行する。

WebView が普通に操作できてテキストボックスの入力もできる。


Flashページを表示してキャプチャする。


できた。


- - - -
Webキャプチャの大筋はこれでおさえられただろうか。

2009年5月14日木曜日

webKit検証(25) - Webウィンドウを重ねる(3)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

サンプルに NSWindow#addChildWindow:ordered: を使ってみる。



これで表示に関しては違和感がなくなった。

が、何故かファーストレスポンダになれない。WebView上に表示されたテキストボックスに文字を入力しようとすると、外側のウィンドウの URL欄に文字が入ってしまう。

2009年5月13日水曜日

複数のNSWindowを紐づける

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

NSWindowのリファレンスを眺めていると複数のウィンドウを紐付けられることがわかった。

NSWindow#addChildWindow:ordered:

どんな動きになるのかサンプルを作って確かめてみよう。

サンプル:PiledWindows.zip

まず InterfaceBuilderで2つのウィンドウを用意し、これを AppController のアウトレットに接続する。


AppController.h

@interface AppController : NSObject {

IBOutlet NSWindow* _window1;
IBOutlet NSWindow* _window2;
}
@end


紐付けは awakeFromNibで行う。
AppController.m
- (void)awakeFromNib
{
[_window1 addChildWindow:_window2
ordered:NSWindowAbove];
}



実行してみよう。2つのウィンドウが表示される。


子ウィンドウを移動すると通常通り任意の場所へ移動できる。
重なり順に NSWindowAbove を指定しているので、必ず子ウィンドウが上にくる。親ウィンドウをクリックしてアクティブにしても下に表示されたまま。




次に親ウィンドウを移動すると、おお。
子ウィンドウが位置関係を保ったままついてくる。こんな機能があったのか。

- - - -
これがあればわざわざ透明にすることもなく簡単に WebViewを重ねられる。
次回やってみよう。

2009年5月12日火曜日

webKit検証(24) - Webウィンドウを重ねる(2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

ウィンドウを単純に重ねると重なり順やフォーカスの問題などがあって意外と面倒なことがわかった。そこで外側のウィンドウの中をくり抜いて(透明にして)その下に Webページを表示するウィンドウを当てはめてみた。

InterfaceBuilderでカスタムビューを貼付ける。


そのビューを透明色で塗りつぶす。するとこうなる。

なおウィンドウの属性で不透明設定をNOにしないと真っ黒になる。またくり抜いた部分に影がかかるのでこれをoffにしておく。

 [_frame_window setOpaque:NO];
[_frame_window setHasShadow:NO];



さてこの状態で Webページを表示するウィンドウを当てはめる。するとこうなる。


- - - -
これもSpacesなどで操作していると変な挙動が起きる。やはり2つのウィンドウを重ねるのは無理がある気がしてきた。どうするか。

2009年5月11日月曜日

WebKit検証(23) - Webウィンドウを重ねる

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

次は WebView が載ったウィンドウを重ねる。

こんな感じ。


実装のポイントは次の通り。

まず位置と大きさを外側のウィンドウ内の表示範囲に合わせる。正確なものはここでは不要なのでおおざっぱな位置と大きさを決めるメソッドを用意しこれを使う。

- (NSRect)calcRect
{
NSRect rect = [_frame_window frame];
rect.size.height -= 120.0;
rect.size.width -= 40.0;
rect.origin.x += 20;
rect.origin.y += 50;

return rect;
}


コントローラを外側のウィンドウの Delegateに設定し NSWindow#windowDidMove: と NSWindow#windowDidResize: を実装し、この中で位置と大きさを合わせる。
- (void)resizeWebWindow
{
[_web_window setFrame:[self calcRect] display:YES];
}
- (void)windowDidMove:(NSNotification *)notification
{
[self resizeWebWindow];
}

- (void)windowDidResize:(NSNotification *)notification
{
[self resizeWebWindow];
}


キャプチャ時には一旦ウィンドウを非表示にする。
- (IBAction)capture:(id)sender
{
[_web_window orderOut:nil];
   :
  // キャプチャ処理
   :
[self resizeWebWindow];
[_web_window makeKeyAndOrderFront:nil];
}


- - - -
外側のウィンドウを移動した時に Webページのウィンドウが遅れたり、重なりかたが変だったりと細かいところで問題はあるが、それらしい形になってきた。

2009年5月10日日曜日

WebKit検証(22) - 操作用ウィンドウ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

まずは外枠にあたる操作用のウィンドウを用意する。前回までのサンプルのウィンドウを広げる。中の開いている部分に別のウィンドウを重ねて表示する。


プログレスバーも付けてみた。

次はWebページを表示するウィンドウの重ね合わせてみる。

2009年5月9日土曜日

WebKit検証(21) - 見ているページをキャプチャするには?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

さて基本的な検証ができたので、もう一歩進んでアプリへの実装を考える。

Paparazzi の様に入力された URLのページをキャプチャするだけであれば、これまで検証した方法で簡単にできる。
ただそれだと使い勝手が悪い。できれば SnapWebなどの様に簡易ブラウザを操作して、任意のタイミングで表示ページをキャプチャできるような方が使いやすい。ただし、その場合は見ていてる状態を変えずにこれまで検証してきたようなウィンドウサイズの変更を行わなければならない(例:表示中の Flashを任意のタイミングでキャプチャ)。


以前見た SnapWebではブラウザ部分が操作ボタンなどとは別ウィンドウになっていた。方法としては良いと思うが、ウィンドウを拡大した場合は見た目がわるい。SnapWebの場合はキャプチャ時には非表示になっていたので、恐らくその間にウィンドウを拡大していたのだと思われる。まずはこの方法をとってみよう。

続く..

2009年5月8日金曜日

WebKit検証(20) - 隠しウィンドウを使ってキャプチャ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前回のウィンドウの表示位置を (-1000, -1000)に変えてみる。

 NSRect rect = NSMakeRect(-1000, -1000, 100, 100);
_window = [[NSWindow alloc] initWithContentRect:rect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];


Load、Capture を実行する。

Webページは表示されないが、問題なくキャプチャできた。

2009年5月7日木曜日

webKit検証(19) - Flash#9 ウィンドウを大きく(再チャレンジ)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

ようやくウィンドウサイズを自由にできる方法がわかったのでキャプチャに使ってみる。仕切り直しにコードを新しく書き直した。

サンプル:WebViewSample-1.zip

InterfaceBuilderでコントロール用の小さなウィンドウを用意する。


アプリケーションを起動したタイミングで WebViewとそれを表示するボーダレスウィンドウをコードから作成する。
AppController.m

- (void)awakeFromNib
{
NSRect rect = NSMakeRect(0, 0, 100, 100);
_window = [[NSWindow alloc] initWithContentRect:rect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
_view = [[WebView alloc] initWithFrame:rect];

[[[_view mainFrame] frameView] setAllowsScrolling:NO];

[_window setContentView:_view];

[_window makeKeyAndOrderFront:nil];
}


最初は左下に 100x100の小さなウィンドウ(白)が現れる。


URLを入力し Loadボタンで読み込み、Captureボタンでキャプチャする。Webページの大きさに合わせてウィンドウが拡大される。


キャプチャコードはこんな感じ。Paparazzi! で使われていた NSBitmapImageRep#initWithFocusedViewRect: を使ってみた。
- (IBAction)capture:(id)sender
{
// (1) filename
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDesktopDirectory, NSUserDomainMask, YES);
NSString* path = [NSString stringWithFormat:@"%@/test2.png",
[paths objectAtIndex:0], nil];

// (2) size
NSRect rect = [[[[_view mainFrame] frameView] documentView] bounds];
[_window setContentSize:rect.size];

// (3) capture
[_view lockFocus];
NSBitmapImageRep* bitmap_rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect];
[_view unlockFocus];

NSData* data = [bitmap_rep representationUsingType:NSPNGFileType
properties:[NSDictionary dictionary]];
[data writeToFile:path atomically:YES];
}


出た。Flashも行けそうだ。


- - - -
ずいぶん時間がかかったが、再現力の高い方法が見つかった(メモリは大量に使いそうだが)。

2009年5月6日水曜日

ウィンドウサイズの制約解除〜NSBorderlessWindowMask

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

色々試行錯誤していてウィンドウサイズの制約解除をする方法がわかった。
何の事はない、ボーダレスのウィンドウを作成すればステータスバーやDockの制約は受けずに自由な位置に任意のサイズのウィンドウを作成することができる。

InterfaceBuilderではなくコード中でウィンドウを作成する。

こんな感じ。

 _window = [[NSWindow alloc] initWithContentRect:rect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];


スタイルマスクに NSBorderlessWindowMask を指定する。
タイトルバーが付く通常のウィンドウは NSTitledWindowMask を指定する。

NSWindow.h
enum {
NSBorderlessWindowMask = 0,
NSTitledWindowMask = 1 << 0,
NSClosableWindowMask = 1 << 1,
NSMiniaturizableWindowMask = 1 << 2,
NSResizableWindowMask = 1 << 3

};


- - -
これでWebページ全体を表示できるウィンドウが作れる。

2009年5月5日火曜日

Paparazzi! を試す(2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

Paparazzi! は古いバージョンだがソースコードが用意されている。ポイントだけ引用してみる。

PaparazziController.m

- (id)initWithWindow:(NSWindow *)window {
if (self = [super initWithWindow:window]) {
webWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(-16000.0, -16000.0, 100.0, 100.0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO];
webView = [[WebView alloc] initWithFrame:NSMakeRect(-16000.0, -16000.0, 100.0, 100.0)];
   :


なるほど。表示領域外にウィンドウと WebViewを作っている。

- (IBAction)fetch:(id)sender {
   :
[webWindow setContentSize:newSize];

[webView setFrameSize:newSize];

[self validateInputSchemeForControl:urlField];

[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:url]];
}


サイズを調整し URLを表示する。

- (void)takeScreenshot {
   :
[webView lockFocus];
bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:cropBounds];
[webView unlockFocus];
   :


NSBitmapImageRep#initWithFocusedViewRect: を使いキャプチャしている。このメソッドは #lockFocus 対象のビューが表示している内容をビットマップイメージに落とす。隠れている部分はイメージに落ちないので、Webページ全体をキャプチャする場合、あらかじめビューのサイズを大きくとっておく必要がある。んん。これはこれまで試していた方法に近い。

表示領域ではウィンドウのサイズに制約がかかっていたが、表示領域外であれば制約がかからないということだろうか。

2009年5月4日月曜日

Paparazzi! を試す

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

WEB画面のキャプチャツール Paparazzi (0.4.3) でFlashページをキャプチャしてみる。



正しく再現されているようだ。

2009年5月3日日曜日

SimpleCap調整(QuickConfigにマウスカーソルを追加)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

QuickConfigにマウスカーソル設定を追加した。



しばらく使って様子見。

今日はそれだけ。