2014/09/30

SIMBL Plugins

What is SIMBL ?

As the wiki says, SIMBL is an application enhancement (InputManager bundle) loader for Mac OS X developed by Mike Solomon. Now a days SIMBL is not maintained anymore but there is a new version of it called EasySIMBL, maintained by Nomura-san.
In short, it is a plugin loader for any Cocoa Application in OSX. So, If you have an app you want to hack (lets say add some extra functionality) to an App and that app does not brings Plugin functionality then EasySIMBL is your option.

First Steps

  1. Download and Install EasySIMBL.
  2. Create an Xcode project
    File > New > Project > OS X > Framework & Library > Bundle
  3. Follow further instructions from "Creating A SIMBL Plugin Bundle" from old SIMBL wiki page.
    Basically, make sure your Info.plist have SIMBLTargetApplications with appropriate values in BundleIdentifier, MaxBundleVersion and MinBundleVersion.

    For the more curious, there is an undocumented parameter: RequiredFrameworks. See details here. It says it has never been used but I personally think it could be useful in cases when your plugin requires a non-standard framework which is embedded in the target app. Using this key load your plugin only if the required frameworks exist.
  4. Start by implement load method as explained in the old wiki.
  5. Once you build your plugin you can move it manually onto EasySIMBL and set the Debug level to "Notice + Info + Debug" to see a bit more of information about the loading process of your plugin
  6. Open Console.app and see "All Messages" now open the target App and check what happens...

Debug

Obviously the process of manually copying the .bundle to ~/Library/Application\ Support/SIMBL/Plugins is tedious. We can do it a bit better:

# Copy the product to SIMBL plugins dir
SIMBL_PLUGIN_DIR="${HOME}/Library/Application Support/SIMBL/Plugins"
rm -rf "${SIMBL_PLUGIN_DIR}/${FULL_PRODUCT_NAME}"
cp -r "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" "${SIMBL_PLUGIN_DIR}/${FULL_PRODUCT_NAME}"

However, in the end this is not what we want. We want to be able to run the target app with the plugin and be able to set breakpoints, etc!.

Setting Xcode for plugin development

This step is not specific to EasySIMBL. Basically every plugin in OSX can be developed/debbuged in this way:
  1. Tell Xcode where to place product after build.
    In our case the location is: "~/Library/Application Support/SIMBL/Plugins". Do this by editing CONFIGURATION_BUILD_DIR on your target:
    .
    Note that some apps (that support plugins without the need of EasySIMBL) will require the plugin to be in ~/Library/Application Support/TheApp/Plugins/ or sometimes in /Applications/TheApp/Contents/Plugins. Just make sure you have enough access permissions so Xcode can write there (Hint: use chmod if needed).

    For example iPhoto.app
  2. Tell Xcode what application to start on "Run".
    In my case I just created a example plugin for Writer.App (That awesome app!). So I edit my schema. Product > Scheme > Edit Scheme...
  3. Specific to EasySIMBL. EasySIMBL seems not to load correctly the latest version of the plugin on Sandboxed apps. Nomura-san says he is aware of this issue and it can be work-arounded by un-checking and checking the "Use SIMBL" before each time we run our plugin.
  4. This is basically all. This is my 1 cent and comments are welcome :)


2014/08/08

Recent Posts Widget for Blogger

I got a little bored the standard "Blog Archive" widget. So I searched for a plain list of post on the widget site without luck but I found this useful helperblogger page which provided a script that uses below API to get the entire list of posts parse it and show it nicely.
GET https://www.blogger.com/feeds/blogID/posts/default
(Full documentation of Blogger's API can be found here)
So, what I did was to modify the code a bit for visual purposes and then brought it into my code. Just set below code as an "HTML/JS Widget":
<script type="text/javascript">
var numposts = 20;
var showpostdate = false;
var showpostsummary = false;
var numchars = 100;
function showrecentposts(json) {
    document.write('<ul>');
    for (var i = 0; i < numposts; i++) {
        var entry = json.feed.entry[i];
        var posttitle = entry.title.$t;
        var posturl;
        if (i == json.feed.entry.length) break;
        for (var k = 0; k < entry.link.length; k++) {
            if (entry.link[k].rel == 'alternate') {
                posturl = entry.link[k].href;
                break;
            }
        }
        posttitle = posttitle.link(posturl);
        var readmorelink = "»»";
        readmorelink = readmorelink.link(posturl);
        var postdate = entry.published.$t;
        var cdyear = postdate.substring(0, 4);
        var cdmonth = postdate.substring(5, 7);
        var cdday = postdate.substring(8, 10);
        var monthnames = new Array();
        if (showpostdate == true) {
            monthnames[1] = "Jan";
            monthnames[2] = "Feb";
            monthnames[3] = "Mar";
            monthnames[4] = "Apr";
            monthnames[5] = "May";
            monthnames[6] = "Jun";
            monthnames[7] = "Jul";
            monthnames[8] = "Aug";
            monthnames[9] = "Sep";
            monthnames[10] = "Oct";
            monthnames[11] = "Nov";
            monthnames[12] = "Dec";
        }
        if ("content" in entry) {
            var postcontent = entry.content.$t;
        } else if ("summary" in entry) {
            var postcontent = entry.summary.$t;
        } else {
            var postcontent = "";
        }
        var re = /<\S[^>]*>/g;
        postcontent = postcontent.replace(re, "");
        document.write('<li>► ');
        document.write(posttitle);
        if (showpostdate == true) {
            document.write(' - ' + cdday + ' ' + monthnames[parseInt(cdmonth, 10)] + ' ' + cdyear);
        }
        if (showpostsummary == true) {
            document.write('');
            if (postcontent.length < numchars) {
                document.write('<i>');
                document.write(postcontent);
                document.write('</i>');
            } else {
                document.write('<i>');
                postcontent = postcontent.substring(0, numchars);
                var quoteEnd = postcontent.lastIndexOf(" ");
                postcontent = postcontent.substring(0, quoteEnd);
                document.write(postcontent + '... ' + readmorelink);
                document.write('</i>');
            }
        }
        document.write('</li>');
    }
    document.write('</ul>');
}
</script>
<script src="http://nacho4d-nacho4d.blogspot.com/feeds/posts/default?orderby=published&alt=json-in-script&callback=showrecentposts">
</script>

My changes

  • Removed all custom ui modifications and put the post in a ul. The only custom ui stuff I did what to prepend "► " before all elements.
  • I thought of using feeds/posts/default instead of the full path http://nacho4d-nacho4d.blogspot.com/feeds/posts/default however it does not work on posts pages.


2014/07/27

Ubuntu server setup

Rackspace stuff... I have rebuilt my system many times, so these are some useful notes to begin with

First time login and another user creation

$ ssh root@ww.xx.yy.zz
$ sudo adduser username

Some additional steps:

$ sudo apt-get update
$ sudo apt-get install git-core curl build-essential openssl libssl-dev

Color $PS1

In ~/.bashrc find and uncomment: force_color_prompt=yes

Install Emacs24

http://blog.be-open.net/emacs/ubuntu-emacs24-install/
add-apt-repository ppa:cassou/emacs
apt-get update
apt-get install emacs24 emacs24-el
A piece of my ~/.emacs file
;; Add ~/.elisp directory to my load path.
;; Not needed since .emacs.d is read by default
(add-to-list 'load-path' "~/.emacs.d")

;; Show trailing white spaces
(setq-default show-trailing-whitespace t)
(set-face-background 'trailing-whitespace "#191970")

;; Adds Other Package manager repositories
(require 'package)
(add-to-list 'package-archives
             '("elpa" . "http://tromey.com/elpa/"))
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/"))
(add-to-list 'package-archives
             '("melpa" . "http://melpa.milkbox.net/packages/"))

Install Go

apt-get install golang

Install Nodejs

I stopped trying to make a web server with node. But these are the steps I used to follow
$ git clone https://github.com/joyent/node.git && cd node
$ git checkout -b v0.8.1 v0.8.1
$ ./configure
$ make
$ sudo make install
$ node -v

# Install npm
$ curl http://npmjs.org/install.sh | sudo sh
$ npm -v

# If perl complains:
# perl: warning: Please check that your locale settings:
#  LANGUAGE = (unset),
#  LC_ALL = (unset),
#  LC_CTYPE = "UTF-8",
#  LANG = "en_US.UTF-8"
#   are supported and installed on your system.
# Do:
$ export LANGUAGE=en_US.UTF-8
$ export LANG=en_US.UTF-8
$ export LC_ALL=en_US.UTF-8
$ locale-gen en_US.UTF-8
# and run it again



2014/01/02

Package xcb-shm was not found in the pkg-config search path

I tried running a hello world program in GTK from the official tutorial page

They basically say:

clang++ `pkg-config --cflags gtk+-2.0` hello.cpp `pkg-config --libs gtk+-2.0` -o hello

This assumes that gtk is installed (brew install gtk+). Also for easiness, they recommend to use pkg-config to get the entire list of paths to compile something that uses gtk.

The problem is that pkg-config complains about "xcv-shm blah blah blah" and it does not work.

The answer from here is to set PKG_CONFIG_PATH appropriately. Apparently is a miss configuration of gtk + x11 + brew.

$ pkg-config --cflags gtk+-2.0
Package xcb-shm was not found in the pkg-config search path.
Perhaps you should add the directory containing `xcb-shm.pc'
to the PKG_CONFIG_PATH environment variable
Package 'xcb-shm', required by 'cairo', not found
PKG_CONFIG_PATH should be set so it reads from Xquartz path so we need to add it to ~/.profile.
$ echo "export PKG_CONFIG_PATH=/opt/X11/lib/pkgconfig" >> ~/.profile

Now it works :)

$ pkg-config --cflags gtk+-2.0
-D_REENTRANT -I/opt/X11/include/cairo -I/opt/X11/include/pixman-1 -I/opt/X11/include/libpng15 -I/opt/X11/include -I/opt/X11/include/libpng15 -I/opt/X11/include -I/opt/X11/include/freetype2 -I/opt/X11/include -I/opt/X11/include/freetype2 -I/opt/X11/include -I/usr/local/Cellar/gtk+/2.24.22/include/gtk-2.0 -I/usr/local/Cellar/gtk+/2.24.22/lib/gtk-2.0/include -I/usr/local/Cellar/pango/1.36.1/include/pango-1.0 -I/usr/local/Cellar/atk/2.10.0/include/atk-1.0 -I/usr/local/Cellar/gdk-pixbuf/2.30.1/include/gdk-pixbuf-2.0 -I/usr/local/Cellar/pango/1.36.1/include/pango-1.0 -I/usr/local/Cellar/harfbuzz/0.9.25/include/harfbuzz -I/usr/local/Cellar/pango/1.36.1/include/pango-1.0 -I/usr/local/Cellar/glib/2.38.2/include/glib-2.0 -I/usr/local/Cellar/glib/2.38.2/lib/glib-2.0/include -I/usr/local/opt/gettext/include 


2013/12/30

LLDB from the command line

Before IDEs and all current eye-candy stuff, everything was done like this:
// Compile a sample.cpp program with debug symbols
$ clang++ -g sample.cpp

// Star the debugger
$ lldb

// Create a target to start the debug session
$ target create a.out

// Setup your breakpoints
# breakpoing set --file sample.cpp --line 7
# breakpoint list
$ b sample.cpp:7


// Run the target
$ run a.out

// Step in
$ s

// Print the stack trace
$ st

// From now do as usual...

// More Commands
http://lldb.llvm.org/lldb-gdb.html



2013/11/10

clang-format

I've been wanting to use clang-format since a while already. It turns out that installation instructions are kind outdated. I had to read various commits in the clang repository to realize clang-format command it was moved from clang to llvm repository.

2014/08/06 Update: Use prebuilds!

Now is even simpler, just download the prebuilds for your system, decompress and use them!
# Download
$ curl -O http://llvm.org/releases/3.4.2/clang+llvm-3.4.2-x86_64-apple-darwin10.9.xz
# Decompress
$ tar xvfJ clang+llvm-3.4.2-x86_64-apple-darwin10.9.xz 
# Locate clang-format
$ ./clang+llvm-3.4.2-x86_64-apple-darwin10.9/bin/clang-format --help
Just one thing. I couldn't find the git hook python script available. Still, it is in the source and it does not need to be compiled, just copy th
# Download only (not the entire llvm project) the repository that contains the hook script
$ svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
# Voila!
$ find . name git-clang-format
# Now just copy it somewhere into your $PATH

Old approach: Build llvm


We need to compile LLVM! I wish brew provides something like --with-tools or something like --with-clang-format. For now we have to do the entire thing by ourselves. Some instructions were taken from Clang's getting started page:

Getting LLVM + Clang

$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
$ cd llvm/tools
$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
$ cd ../..
$ cd llvm/tools/clang/tools
$ svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
$ cd ../../../..
$ cd llvm/projects
$ svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
$ cd ../..

Building LLVM + Clang

$ ./llvm/configure
$ make
In my case, make didn't succeed, it takes forever and it fails somewhere after building clang-format but that is ok. clang-format was built and I wasn't planning to install llvm/clang from source either, I am fine with Xcode/brew stuff :p

Installing clang-format

If it is not clear where makeput all compiled stuff we can always use find:
$ find . -name "clang-format"
./Release+Asserts/bin/clang-format
./tools/clang/tools/clang-format
We need to copy clang-format command from above location to somewhere in our PATH or make an alias. Also we want to install git-clang-format and maybe other scripts.
# copy clang-format command to your $PATH
$ cp ./Release+Asserts/bin/clang-format /somewhere/in/your/PATH

# install (copy) git-clang-format subcommand to your $PATH
$ cd ./tools/clang/tools/clang-format
$ cp git-clang-format ~/.bin

Using clang-format command

Now, lets say we are inside a directory which contains c/cpp/objc sources which we want to reformat. We simply create a .clang-format file which should be of the form:
Key: Value
Key: Value
Key: Value
Key: Value
And then we would run clang-format file.c Some commands to know more about the command and keys available:
# dump all configuration keys
clang-format -dump-config 
clang-format -dump-config  style=webkit

# help
clang-format --help
clang-format --help-list-hidden

# format a file (it will read .clang-format file if available)
clang-format filename.c

# format a file with a explicit style
clang-format -style=google filename.c
Check clang's official style documentation page for more info.

Using it with git

Since we installed git-clang-format file to our PATH, if we are in a git repository, we can do:
git clang-format
And it will reformat all staged code, pretty awesome!

Are you wondering where did clang-format subcommand come from?! Answer: custom git subcommands are simply executables in the PATH and its name should have the "git-" prefix and should not have extension.

Hope this info is helpful to somebody :)



2013/11/09

インターネット接続 制限あり、ウィンドウズタブレットでの件

新しい無線ルーター買って電波が強くなった筈だから楽しみだったのに ウィンドウズタブレットのインターネット接続が「制限あり」??!

いろいろ調べたところアダプターのせいらしい、ドライバーを最新にすべきだそうだ。したけど直らない。

また別のサイトの情報によるとアダプターを無効にしてからまた有効にすると直ることがある。試してみたら実際に直っていた!でも一時的だけ、ちょっとするとまた「制限あり」になった。

「問題のトラブルシューティング」をクリックすると同じく一時的に直る。よく見ると問題解決の後に「アダプターのリセット」というステップがあるからおそらくアダプターを無効にしてから有効にすると同じかと思う。

そこで、このブログの情報を見つけて解決しました!アダプターの設定を変更するのだった!!hiro25hiro07様に感謝感謝!

念のためここに転載。

ネットワークアダプタの設定を変更します。

  1. デバイスマネージャーを開きます。
  2. [ネットワーク アダプター]をダブルクリックします。
  3. [Broadcom 802.11abgn Wireless SDIO Adapter]をダブルクリックします。
  4. プロパティーが表示されますので、[詳細設定]タブをクリックします。
  5. 表示された[詳細設定]タブから   以下の項目の設定変更を行ってください。
    • [20/40 Coexistance]の[Auto]を[Enable]に変更します。
    • [40MHz Intolerant]の[Disabled]を[Enable]に変更します。
    • [802.11n Preamble]の[Auto]を[Mixed Mode]に変更します。
    • [Afterburner]の[Disabled]を[Enable]に変更します。
    • [Bandwidth Capability]の[11a:20/40;11bg:20MHz]を[11a/b/g:20/40MHz]に変更します。
    • 以上で、操作は終了です。


あと、やっぱりドライバーのアップデートした方が良さそうだ、 Acerうんち全然アップデートしないからSony様からパクりました。 とりあえず、 DriverIdenfier.comからv5.93.98.4ダウンロードできた。 93.97.113でもだめでしたし、その一個前もだめだったし。
他のメーカーはちゃんとアップデートバージョンでしているのに、Acerはだしていない。。。ひどい。

参考



2013/10/22

Tar

I wish this was a tar tutorial, however there are plenty of them already. Maybe some people find it useful too, specially when downloading, opening tar balls... :)
A ".tar" file is a collection of files within a single file in an uncompressed form. If the file is a ".tar.gz" ( usually called tarball) or ".tgz" file then it is a collection of files in a compressed form.
To compress a file you could create the tar file with the z option. Or alternatively you could create the file with any other tool and then use gzip to compress it.

Some Tar Options

  • c : create a new archive
  • d : delete from the archive
  • r : append files to the end of the archive
  • t : list contents
  • u : update (append files if newer)
  • x : extract
  • f : file?
  • v : verbose
  • z : gzip

Uncomprezing files:

# target file is a zipped tar ball
$ tar -zxvf file.tar.gz
# target file is simply a tar ball
$ tar -xvf file.tar

Listing contents of the file

$ tar -tvf myfile.tar

Compressing files

# tar contents of folder foo in foo.tar
$ tar -cvvf foo.tar foo/
That is all, maybe I add more options as needed.



2013/07/30

Installing Emacs from the source

This VM I am in is a bit old and somewhow apt-get is not pulling the latest packages... so I need it to get it manually.
As many other open source software built with make: Get a release, from http://ftp.jaist.ac.jp/pub/GNU/emacs/ for example, then compile and install.
$ wget http://ftp.jaist.ac.jp/pub/GNU/emacs/emacs-24.3.tar.gz
$ tar -xzvf emacs-24.3.tar.gz
$ cd emacs-24.3
$ less INSTALL; # Just take a glance of the install notes
$ ./configure; # Check the output is not something weird
$ make; # No errors should appear here
$ sudo make install; # Gets moved to somewhere in the PATH
If in the way perl complains about LANG, etc variables:
 perl: warning: Setting locale failed.
 perl: warning: Please check that your locale settings:
  LANGUAGE = (unset),
  LC_ALL = (unset),
  LANG = "en_US.utf8"
    are supported and installed on your system.
 perl: warning: Falling back to the standard locale ("C").
Follow instructions: Perl warning Setting locale failed in Debian
$ export LANGUAGE=en_US.UTF-8
$ export LANG=en_US.UTF-8
$ export LC_ALL=en_US.UTF-8
$ sudo /usr/sbin/locale-gen en_US.UTF-8
$ sudo /usr/sbin/dpkg-reconfigure locales
# now choose the appropriate language from the list to generate
Finally re-run from the last step, install in this case:
$ sudo make install


2013/07/23

SQL stuff

I am just a beginner in SQL, so I write some trivial stuff here. Lets say I have some datum in my table of logs:
SELECT *, stime - time AS delay FROM logs;
+------+------+-------+-------+
| usid | time | stime | delay |
+------+------+-------+-------+
|    1 |   10 |    10 |     0 |
|    1 |   10 |    12 |     2 |
|    1 |   15 |    17 |     2 |
|    1 |   13 |    15 |     2 |
|    1 |   18 |    21 |     3 |
|    1 |   19 |    22 |     3 |
|    1 |   20 |    25 |     5 |
|    1 |   21 |    26 |     5 |
|    1 |   22 |    26 |     4 |
|    1 |   23 |    26 |     3 |
+------+------+-------+-------+
Where:
  • usid is some random id
  • time is record time in the client side
  • stime is record time in the server side
  • delay is simply the diff of server time and client side


Some exercises:

Count the number of records with a particular delay:
SELECT stime - time AS delay,
       COUNT(*) FROM logs
GROUP BY stime - time;
+-------+----------+
| delay | count(*) |
+-------+----------+
|     0 |        1 |
|     2 |        3 |
|     3 |        3 |
|     4 |        1 |
|     5 |        2 |
+-------+----------+
Too much detail (too granulated), so we want to group 2 and 3 delay into 2, 4 and 5 into 4, etc. To make sure I am doing the right calculations, here is the delay and rounded delay:
SELECT *,
       stime - time AS delay,
       FLOOR((stime - time) / 2) * 2 AS rounded_delay
FROM   logs;
+------+------+-------+-------+---------------+
| stid | time | ctime | delay | rounded_delay |
+------+------+-------+-------+---------------+
|    1 |   10 |    10 |     0 |             0 |
|    1 |   10 |    12 |     2 |             2 |
|    1 |   15 |    17 |     2 |             2 |
|    1 |   13 |    15 |     2 |             2 |
|    1 |   18 |    21 |     3 |             2 |
|    1 |   19 |    22 |     3 |             2 |
|    1 |   20 |    25 |     5 |             4 |
|    1 |   21 |    26 |     5 |             4 |
|    1 |   22 |    26 |     4 |             4 |
|    1 |   23 |    26 |     3 |             2 |
+------+------+-------+-------+---------------+
So now group by the rounded delay (named just "delay" here)
SELECT FLOOR((stime - time) / 2) * 2 AS delay,
       COUNT(*) FROM logs
GROUP BY FLOOR((stime - time) / 2) * 2;
+-------+----------+
| delay | count(*) |
+-------+----------+
|     0 |        1 |
|     2 |        6 |
|     4 |        3 |
+-------+----------+
Add a percentage, I know I have 10 rows in my table so I can do this:
SELECT *,
       c.cnt / 10 AS percentage
FROM (
      SELECT FLOOR((stime - time) / 2) * 2 AS delay,
             COUNT(*) AS cnt
      FROM   logs
      GROUP BY FLOOR((stime - time) / 2) * 2
) c;
+-------+-----+------------+
| delay | cnt | percentage |
+-------+-----+------------+
|     0 |   1 |     0.1000 |
|     2 |   6 |     0.6000 |
|     4 |   3 |     0.3000 |
+-------+-----+------------+
Although, probably is better not to hard-code the count:
SELECT *,
       c.cnt / ( SELECT COUNT(*) FROM logs) AS percentage
FROM (
       SELECT FLOOR((stime - time) / 2) * 2 AS delay,
              COUNT(*) AS cnt
       FROM   logs
       GROUP BY FLOOR((stime - time) / 2) * 2
) c;
+-------+-----+------------+
| delay | cnt | percentage |
+-------+-----+------------+
|     0 |   1 |     0.1000 |
|     2 |   6 |     0.6000 |
|     4 |   3 |     0.3000 |
+-------+-----+------------+
There should be much better ways (better performance) of doing this... I am glad to receive some comments :)


2013/07/22

Converting from to unix time

I write this because I always forget the right formats, options...

BSD Date - Mac OSX

The f option is for input format. The j option is to not try to set the time. The last argument is optional, is the output format and it requires an x as a prefix.
  • Convert to unix time
    $ date -jf "%Y-%m-%d %H:%M:%S %Z" "2013-07-19 00:00:01 JST" "+%s"
    1374159601
    
  • Convert from unix time
    $ date -jf "%s" 1374159601 "+%Y-%m-%d %H:%M:%S %Z"
    2013-07-19 00:00:01 JST
    
    Also:
    $ date -jf "%s" 1374159601
    Fri Jul 19 00:00:01 JST 2013
    


GNU Date - Linux, etc

The -d is for the input date. Format is recognized automatically. The last parameter, same as BSD Date, is the output format (optional). It must be prepended by a +.
  • Convert to unix time
    $ date -d "2013-07-19 00:00:00 JST" "+%s"
    1374159600
    
  • Convert from unix time
    $ date -d @1374159600 "+%Y-%m-%d %H:%M:%S %Z"
    2013-07-19 00:00:00 JST
    
    Also :
    $ date -d @1374159600
    Fri Jul 19 00:00:00 JST 2013
    


2013/03/02

Gollum

Wikis with Gollum

Gollum is a simple wiki system built on top of Git that powers GitHub Wikis. Super easy to starting working in your wiki.

Installation

gem install gollum redcarpet rdiscount
gollum --help

Usage

git clone https://github.com/allending/Kiwi.git
cd Kiwi.wiki/
gollum
Alternatively
git clone https://github.com/allending/Kiwi.git
gollum --page-file-dir Kiwi.wiki/ TestWiki

Editing changes

As documented, changes done directly in the source should be committed to trigger gollum to reflect them

Coda

If coda is your editor then below markdown mode might become handy: Markdown.mode by bobthecow - Github


2012/04/23

Installing GLEW in MacOS X

The old way

The easy way is at the bottom of the post :)
  1. Download the sources from SourceForge:
  2. http://glew.sourceforge.net/

  3. Unzip/Untar the file (Some browsers will do this automatically)

  4. Before compiling ...
  5. Usually you would run `make` but the shell script will fail to find/guess "$system" variable so we need to set it manually (as of in version 1.7.0 [08-26-11]). So open the makefile with some editor and change system to be `darwin` as shown in the image.
  6. Compile, Install and Clean
  7. make
    sudo make install
    make clean
    
    Some harmless warnings appear but ... let them be.

  8. We are done!
  9. Glew's headers are in /usr/include/GL and the dynamic and static libraries are in /usr/lib/ as usual :)

The easy way

  1. Use homebrew and save you all these little hazels ... :)
    brew install glew
    

Links

  1. Installing GLEW in Mac OS X (Leopard) - Julian Villegas
  2. GLEW on Mac OS - 175 CS Forum


2012/03/21

CoreImage and UIKit coordinates

Recently I found a very nice CoreImage tutorial for iOS: Easy face detection with core animation in iOS5 and after downloading the source I found that this quite popular tutorial was teaching something wrong, coordinates system conversions!.

I can't remember how many bugs/problems I had because of not converting the coordinates well or using the incorrect coordinate system when I was at the uni. So I decided to write this little post so my great audience (approx. 6 viewers per day) can benefit from it :)

CoreImage coordinates are different from UIKit

CoreImage Coordinate system


(From CoreImage Programming Guide)


Even-though is not very clear in the image, each image processed has its own coordinate space and its origin in at the left bottom corner of the image. Each images's coordinate systems is device independent.

UIKit Coordinate System


(From View Programming Guide for iOS)


UIViews's frame's origin is at the top left corner and its coordinates are in their superview coordinate space. They are not independent.

Converting coordinates


We should convert CoreImage coordinates to UIKit coordinates system, not the other way around, because chances are that most of your code will be in UIKit coordinates and because other iOS devs will expect {0,0} to be at the top left corner, be nice and don't change everything just because of CoreImage. :)

This is easily done with an affine transform:
Where ui and ci subindexes mean UIKit and CoreImage coordinates respectively and h is the height of the image in regard.

We could do this manually but happily there are a bunch of functions for this task like: CGAffineTransformMakeScale, CGAffineTransformTranslate, CGPointApplyAffineTransform and even CGRectApplyAffineTransform!. Thanks to Apple for making our life easier.

The code


// Create the image and detector
CIImage* image = [CIImage imageWithCGImage:imageView.image.CGImage];
CIDetector* detector = [CIDetector detectorOfType:CIDetectorTypeFace 
                                          context:... options:...];

// CoreImage coordinate system origin is at the bottom left corner
// and UIKit is at the top left corner. So we need to translate
// features positions before drawing them to screen. In order to do
// so we make an affine transform
CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
transform = CGAffineTransformTranslate(transform,
                                    0, -imageView.bounds.size.height);

// Get features from the image
NSArray* features = [detector featuresInImage:image];
for(CIFaceFeature* faceFeature in features) {

  // Get the face rect: Convert CoreImage to UIKit coordinates
  const CGRect faceRect = CGRectApplyAffineTransform(faceFeature.bounds, transform);

  // create a UIView using the bounds of the face
  UIView* faceView = [[UIView alloc] initWithFrame:faceRect];

  ...

  if(faceFeature.hasLeftEyePosition) {
    
    // Get the left eye position: Convert CoreImage to UIKit coordinates
    const CGPoint leftEyePos = CGPointApplyAffineTransform(faceFeature.leftEyePosition, transform);
    ...

  }

  ...
}


You can download the sample from here and see the result is pretty much the same as the original tutorial. Only this time we didn't scramble with the coordinate system :)

In case, you didn't notice, the original example changes the whole window coordinate system causing its origin to be at the bottom left (like Cocoa in the Mac) hence the imageView appears at the bottom.




2012/03/02

Another twilight theme for Xcode

I just created my ...


err ...


actually just tweaked Twilight theme a bit and named it "Twilight Console" It resembles Twilight but it uses font Monaco size 10 and the most important part (at least to me) is the console is also customized:


If you play with the console very often (gdb, llvm debugger, etc) you might like this theme.

Download TwilightConsole.dvtcolortheme or get if from Github :)




2012/02/08

Shake animation using CAKeyFrameAnimation

Animation that shakes a toolbar (UIToolbar or any generic UIView object)

I put this here so I have a quick and simple example to refer to in the future :)

- (void)shakeToolbar
{
    static BOOL performingAnimation = NO;
    if (!performingAnimation) {
        performingAnimation = YES;

        // Make an image view to animate
        // Probably not necessary when animation only "position"
        // property, but if animating its size, transform or some
        // property that will need its subviews to layout is more
        // efficient to do it like this.
        UIGraphicsBeginImageContext(toolbar.frame.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        [self.view.layer renderInContext:context];
        UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        UIImageView *imageToAnimate;
        imageToAnimate = [[UIImageView alloc] initWithImage:img];
        imageToAnimate.frame = toolbar.frame;
        
        // Replace the toolbar with the image view temporarily
        [toolbar.superview addSubview:imageToAnimate];
        toolbar.hidden = YES;
        [imageToAnimate release];

        // Build the animation
        CGPoint pos = toolbar.layer.position;
        CGMutablePathRef shakePath = CGPathCreateMutable();
        CGPathMoveToPoint(shakePath, NULL, pos.x, pos.y);
        CGPathAddLineToPoint(shakePath, NULL, pos.x - 5, pos.y);
        CGPathAddLineToPoint(shakePath, NULL, pos.x + 4, pos.y);
        CGPathAddLineToPoint(shakePath, NULL, pos.x - 3, pos.y);
        CGPathAddLineToPoint(shakePath, NULL, pos.x + 2, pos.y);
        CGPathAddLineToPoint(shakePath, NULL, pos.x - 1, pos.y);
        CGPathCloseSubpath(shakePath);
        const float durationOfShake = 0.5;
        CAKeyframeAnimation *shakeAni;
        shakeAni = [CAKeyframeAnimation animationWithKeyPath:
                                                        @"position"];
        shakeAni.path = shakePath;
        shakeAni.duration = durationOfShake;
        CFRelease(shakePath);

        // Perform the animation
        [imageToAnimate.layer addAnimation:shakeAni 
                                    forKey:@"shakeAnimation"];

        // Restore the toolbar to its original state when finished
        // (Probably is better to do this in the delegate method ... )
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 
                                      durationOfShake * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            toolbar.hidden = NO;
            [imageToAnimate removeFromSuperview];
            performingAnimation = NO;
        });
    }
}


2012/01/30

Customized Blogger search box

I write this here so I have a place to refer so when some good day I decide to change current I don't have to write this again :)

The implementation is far from optimal but I couldn't find a better option than polling until the search box is loaded to fully customize it. Some properties are overwritten by defaults and CSS seems to be not enough. If somebody know how to do this in a cleaner/better way, I want to hear it ( read : write a comment please :) )

The CSS code that will make the search field look nicer and hides the search button:
/* customization of search box - nacho4d (css)*/
.gsc-search-box{
}
table.gsc-search-box td{
 border: 0px;
}
input.gsc-input { /* This is the real search field*/
background-image:url('http://web.me.com/nacho4d/toolbar_find24.png');
background-repeat:no-repeat;
background-position:0% 50%;

border: 1px solid gray;
-webkit-border-radius: 5px ;
-moz-border-radius: 5px ;
border-radius: 5px ;

-moz-box-shadow: inset 0 5px 15px rgba(0,0,0,.15);
-webkit-box-shadow: inset 0 5px 15px rgba(0,0,0,.15);
box-shadow: inset 0 5px 15px rgba(0,0,0,.15);

font-size: 1.2em;
color: gray;
padding-left:30px;
padding-right:7px;
height: 24px;
}
input.gsc-input:focus { 
-moz-box-shadow: inset 0 3px 25px rgba(0,0,0,.0);
-webkit-box-shadow: inset 0 3px 25px rgba(0,0,0,0);
box-shadow: inset 0 3px 25px rgba(0,0,0,0);
color:black;
}
input.gsc-search-button { /* this is the search button */
display:none;
}
/* end of customization of search box - nacho4d (css)*/
Remember to put this somewhere inside <style> tag :)

The js code that will poll looking for the search field (which is loaded dynamically) and set a couple of attributes to do the final touch.
<!-- Start of customization of search box - nacho4d (js) -->
  <script type='text/javascript'>
function fixSearchField() {
  var searchFields = document.getElementsByTagName('input');
  for (var i = 0; i < searchFields.length; i++) {
    var searchField = searchFields[i];
    if (searchField.getAttribute('class', 0) == ' gsc-input'){
      // found it!
      searchField.style.paddingLeft = '30px';
      searchField.style.width = '120px';
      searchField.setAttribute('placeholder', 'Search ...');
      return;
    }
  }
  setTimeout('fixSearchField()', 1000);
}
fixSearchField();
</script>

<!-- End of customization of search box - nacho4d (js) -->

Remember to put this somewhere after </style> :)

I guess this would be much easier if I were hosting my own blog ... just saying.


2012/01/27

scrollViewDidEndScrolling ?

Last time I tried this I think it was in iOS2.x, 3.x ... so instead of looking for an old code I decided to implement this again. I want to know when the text view did end scrolling. I mean when the text end moving (regardless regular dragging or drag + deceleration).


First I created my regular UITextView, set the delegate and implemented the delegate methods:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    if (scrollView.isDecelerating) {
    NSLog(@" ... restarting");
    } else {
    NSLog(@"Scroll will begin");
    }
}

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(CGPoint *)targetContentOffset
{
    NSLog(@"will end dragging: velocity: %f", velocity.y);
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (decelerate) {
    } else {
        NSLog(@"Scroll did end (Dragging)");
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    NSLog(@"Scroll did end (Decelerating)");
}

So if I ...

scroll without deceleration I get:

Scroll will begin
will end dragging: velocity: 0.000000
Scroll did end (Dragging)


scroll with deceleration I get:

Scroll will begin
will end dragging: velocity: 0.321089
Scroll did end (Decelerating)


start scrolling with deceleration and while its decelerating do another scrolling without deceleration I get:

Scroll will begin
will end dragging: velocity: 1.094134
... restarting
will end dragging: velocity: 0.000000
Scroll did end (Dragging)


start scrolling with desceleration and while its decelerating do another scrolling with deceleration I get:

Scroll will begin
will end dragging: velocity: 1.995404
... restarting
will end dragging: velocity: 0.442658
Scroll did end (Decelerating)


Everything goes as expected :)


Why do I need scrollViewWillEndDragging:withVelocity:targetContentOffset: ?. This is my little finding: If that method is **not** implement and then I ...

start scrolling with deceleration and while its decelerating do another scrolling without deceleration I get :

Scroll will begin
will end dragging: velocity: 1.094134
... restarting
will end dragging: velocity: 0.000000
Scroll did end (Dragging)
Scroll did end (Decelerating)

Huh?? The textview ended dragging and just after decelerating? Did I find a bug?
So, in order to get notified only once when the text did end scrolling I need to implement scrollViewWillEndDragging:withVelocity:targetContentOffset: ?? ??
I hope I am not missing something.


In the mean time I uploaded a sample project that show the issue here.


2012/01/24

Installing Node.js for the third time

I think this is the third time I want to use node.js in a different computer and I **always** get stuck in the same place.
I know there are several "How do I install node.js" tutorials, blogs, etc.
Here is what it worked for me:

  • In theory you install node using brew: brew install node (or brew upgrade node to upgrade current node installation) and then npm : curl http://npmjs.org/install.sh | sh.
    curl https://npmjs.org/install.sh | sh

  • But in practice, At least me, I always get permission errors, link errors, it looks pretty bad. It is because I need to set adjust my permissions first : sudo chown -R $USER /usr/local.

  • Then, If you got: "Error: The linking step did not complete successfully." finish node installation with brew link node.

  • Now installing npm should work flawless too: curl http://npmjs.org/install.sh | sh

Hope it helps... :)

Other References


2012/01/22

Adding Linkedin Badge to Blogger

I write this here so If I ever decide to change the template of this blog I have a reference to go back and set this again :)

Basically I simply replaced :
<a class='profile-link' expr:href='data:userUrl' rel='author'><data:viewProfileMsg/></a>

with Linkedin's badge. Something like this :)
 <b:if cond='data:aboutme != ""'><dd class='profile-textblock'><data:aboutme/></dd></b:if>
 </dl>
   <a href='http://jp.linkedin.com/pub/guillermo-ignacio-enriquez-gutierrez/31/b53/173'><img id='linkedinImg' border='0' src='http://www.linkedin.com/img/webpromo/btn_myprofile_160x33.png'/></a>
   <!-- <a class='profile-link' expr:href='data:userUrl' rel='author'><data:viewProfileMsg/></a> -->
 </b:if>

optionally, remove the border and shadow of img tag. (Put this somewhere before ]]></b:skin>)
#linkedinImg{
-webkit-box-shadow: none; 
-moz-box-shadow: none; 
box-shadow: none;
border: 0px;
}

In my opinion this looks much better than Google+ :)




2012/01/14

Catching Keyboard Events in iOS


Some notes before starting ...

Things explained here are NOT possible using public APIs so this definitely violates AppStore's rules. However, if you want to take your chances and implement this for the AppStore or perhaps for Jailbroken iPhones ... keep on reading :) I think this time it is harder to get caught since this doesn't need to link against private frameworks or add private headers, etc.

The question is: How?

The short answer

The trick is in accessing GSEventKey struct memory directly and check certain bytes to know the keycode and flags of the key pressed. Below code is almost self explanatory and should be put in your UIApplication subclass.

#define GSEVENT_TYPE 2
#define GSEVENT_FLAGS 12
#define GSEVENTKEY_KEYCODE 15
#define GSEVENT_TYPE_KEYUP 11

NSString *const GSEventKeyUpNotification = @"GSEventKeyUpHackNotification";

- (void)sendEvent:(UIEvent *)event
{
    [super sendEvent:event];

    if ([event respondsToSelector:@selector(_gsEvent)]) {

        // Key events come in form of UIInternalEvents.
        // They contain a GSEvent object which contains 
        // a GSEventRecord among other things

        int *eventMem;
        eventMem = (int *)[event performSelector:@selector(_gsEvent)];
        if (eventMem) {

            // So far we got a GSEvent :)
            
            int eventType = eventMem[GSEVENT_TYPE];
            if (eventType == GSEVENT_TYPE_KEYUP) {
                
                // Now we got a GSEventKey!
                
                // Read flags from GSEvent
                int eventFlags = eventMem[GSEVENT_FLAGS];
                if (eventFlags) { 

                    // This example post notifications only when 
                    // pressed key has Shift, Ctrl, Cmd or Alt flags

                    // Read keycode from GSEventKey
                    int tmp = eventMem[GSEVENTKEY_KEYCODE];
                    UniChar *keycode = (UniChar *)&tmp;

                    // Post notification
                    NSDictionary *inf;
                    inf = [[NSDictionary alloc] initWithObjectsAndKeys:
                      [NSNumber numberWithShort:keycode[0]],
                      @"keycode",
                      [NSNumber numberWithInt:eventFlags], 
                      @"eventFlags",
                      nil];
                    [[NSNotificationCenter defaultCenter] 
                        postNotificationName:GSEventKeyUpNotification 
                                      object:nil
                                    userInfo:userInfo];
                }
            }
        }
    }
}


If you are asking yourself "Where all those #defines come from?", "Application subclass?, I don't have such a thing in code" then please read the long answer, I hope you find if helpful :)

The long answer:

UIEvents are simple wrappers of GSEventRefs, which contain a GSEventRecord struct in it. Usually we only treat UIEvents representing touch events because the UIApplication will not dispatch other events to our views or objects we create. These are UIInternalEvents and can represent accelerometer events, volume events, keyboard events, etc.

  1. In order to intercept all events our application receives we need to override sendEvent: method in our UIApplication subclass.
  2. We need to access the GSEvent and check it is a key event and then check its flags (Shift, Cmd, Ctrl, Alt). Its easy as that, the problem is we don't know how to get the type and flags of GSEvent, it is a private API :(

- GSEvent objects -
So I did the homework and according to Kenny TM in here and here, GSEvents looks like:
typedef struct __GSEvent {
    CFRuntimeBase _base;
    GSEventRecord record;
} GSEvent;
typedef struct __GSEvent* GSEventRef;
typedef struct GSEventRecord {
    GSEventType type; // 0x8 //2
    GSEventSubType subtype;    // 0xC //3
    CGPoint location;     // 0x10 //4
    CGPoint windowLocation;    // 0x18 //6
    int windowContextId;    // 0x20 //8
    uint64_t timestamp;    // 0x24, from mach_absolute_time //9
    GSWindowRef window;    // 0x2C //
    GSEventFlags flags;    // 0x30 //12
    unsigned senderPID;    // 0x34 //13
    CFIndex infoSize; // 0x38 //14
} GSEventRecord;
typedef struct GSEventKey {
 GSEvent _super;
 UniChar keycode, characterIgnoringModifier, character; // 0x38, 0x3A, 0x3C
 short characterSet;  // 0x3E
 Boolean isKeyRepeating; // 0x40
} GSEventKey;
Headers seems to be a bit old (iOS3~4) but things haven't changed so much. What is for sure is that keycode is right next to infoSize. (Isn't this the fun of private APIs?).
Everything we have to do now is to count bytes from the start of the memory of GSEvent
int *eventMem;
eventMem = (int *)[event performSelector:@selector(_gsEvent)];
GSEventType is at 2
GSEventFlags at 12 and
Unichar keycode at index 15.
I do some checks in the way but that is basically all. :)

Yes, Apple might change GSEvent at anytime so if you are a challenger and would like to submit this to the AppStore, at least do do this conditionally:
// I am lazy to do the proper check here in the post :)
[super sendEvent:event];
if ([[[UIDevice currentDevice] systemVersion] intValue] == 5) {
    ...
}

If you use it or tried to, it would be awesome you drop a line in the comments. (^-^)/
I still have not completed a sample for this little hack but in the mean you can check this this gist out where you can find some keycodes and masks.

References


2011/12/16

Share buttons

Added buttons: Finally added tweet, like, share, burp and fart buttons (LOL) to this humble blog in blogger. So much info around there but not all of them are up to date, it was hard to find the correct information.
Got some info from here, here, here and here put the code inside my blog in the footer :)
Which one was the easiest ?
The winner is LinkedIn besides it looks great :) but GooglePlus was almost as easy as the winner.

Which one was the most difficult ... ?
Facebook, Ohh how I hate Facebook!

Twitter is OK :)
<div class='post-footer'>

 <!-- Tweeter -->
 <div style='float:left;padding:4px;'>
   <a class='twitter-share-button' data-count='none' data-lang='en' data-via='nacho4d' expr:data-text='data:post.title' expr:data-url='data:post.url' href='http://twitter.com/share' rel='me'/>
   <b:if cond='data:post.isFirstPost'><script src='http://platform.twitter.com/widgets.js' type='text/javascript'/></b:if>
 </div>
 <!-- Google plus -->
 <div style='float:left;padding:4px;'>
   <g:plusone annotation='none' expr:href='data:post.url' size='medium'/>
 </div>
 <!-- LinkedIn -->
 <div style='float:left;padding:4px;'>
    <b:if cond='data:post.isFirstPost'><script src='http://platform.linkedin.com/in.js' type='text/javascript'/></b:if>
    <script expr:data-url='data:post.url' type='in/share'/>
 </div>
 <!-- Facebook -->
 <div style='float:left;padding:5px;'>
   <a expr:share_url='data:post.url' name='fb_share' rel='nofollow' type='share'/>  
   <b:if cond='data:post.isFirstPost'><script src='http://static.ak.fbcdn.net/connect.php/js/FB.Share' type='text/javascript'/></b:if>
 </div>
 <br/>
 <br/>

Any kind of comments or criticism is welcomed here :)


2011/12/08

CATimingFunction with bezier path


CoreAnimation is awesome! specially because it lets you define a timing function for you animation. But, somehow I always find myself googling for a interactive bezier curve creator site or something that lets me draw the curve.

Really, I don't know how many times I've done the same search and sometimes I can't find the page I used in the past.
So this time I wrote a simple but interactive HTML (using the canvas) that helps me define a bezier path I can use to create a custom timing function for CoreAnimation:
Here is the source:
$ git clone git@github.com:nacho4d/BezierJS.git




2011/08/02

Versions in OSX 10.7 : Half tutorial, half just notes

Foreword
Last week I spent some days implementing one of the new features in MacOSX 10.7 Lion: Versions and autosave.
It was not so straight forward, APIs are too new that there is no samples yet. Documentation is not enough for newbies like me. (hehe)

I thought that watching Apple's session 107 of WWDC 2011 was going to be enough but it turns out that the video/pdfs dont show all the code you need. Besides I couldn't find the sample code specifically for that session!. TextEdit autosave implementation is just too simple, not very educational in this regard.

I think my case is not trivial. Why? Because I am using a NSWindow subclass with NSBorderlessWindowMask and I have to craft close/minimize/maximize buttons, handle window resizing by my own. I even have to add the autosave button by my own and I still don't get the "--Edited" or "--Locked" string right next to the versions button (NSWindowDocumentVersionsButton)

So here are my notes:
(I assume the app is a document-based cocoa application)

First:
The easy part, override +[NSDocument autosaveInPlace] which will enable versions by default
//MyDocument.h
+ (BOOL)autosavesInPlace{
 return YES;
}
Or override +[NSDocument preservesVersions] directly.

Now, without much effort you will get something like this:

Second:

Still easy, implement the following NSWindowDelegate methods. If you are using a subclass of NSWindowController that is a good place, if not then the NSDocument subclass should be fine :)

To customize the size of the window in the version browser:
//Bug? : In NSBorderlessWindowMask windows below method is called but has no effect!
- (NSSize)window:(NSWindow *)aWindow willResizeForVersionBrowserWithMaxPreferredSize:(NSSize)maxPreferredSize maxAllowedSize:(NSSize)maxAllowedSize{
    //Create a custom size for the window entering version browser
    //This is just an example of a size you might use. This is quite big
    float ratio = maxPreferredSize.height/maxPreferredSize.width;
    NSSize winSize = [aWindow frame].size;
    winSize.height = winSize.width * ratio;
    return winSize;
}

To customize the window when entering/exiting version browser
- (void)windowWillEnterVersionBrowser:(NSNotification *)notification
{

    //Suggested by the docs:
    //disable UI elements that will have no effect in version browser.
    //Simplify the UI, as well

    //Example a textView:
    MyWindow *win = (MyWindow *)[notification object];
    [win hideTitlebarAndStatusBar];     //method of MyWindow : simply the window
    [win setUserIntaractionEnabled:YES];//method of MyWindow : disable UI
    [myTextView setEditable:NO];        //disable UI
}

- (void)windowDidEnterVersionBrowser:(NSNotification *)notification
{
    //If needed, do your thing here
}
- (void)windowWillExitVersionBrowser:(NSNotification *)notification
{
    //If needed, do your thing here too
}

- (void)windowDidExitVersionBrowser:(NSNotification *)notification
{
    //Suggested by the docs
    //Set the window to its original settings

    MyWindow *win = (MyWindow *)[notification object];
    [win showTitlebarAndStatusBar];     //method of MyWindow : restore the window
    [win setUserInteractionEnabled:YES];//method of MyWindow : restore UI
    [myTextView setEditable:YES];       //restore UI
}

Third
In fact this step is easy too but not very well documented, I believe.

In normal cases (When using regular windows with non NSBorderLessWindowMask) doing step 1 and 2 is enough. Cocoa will coordinate buttons in the window and resized to not to work while in the version browser.

In case of NSBorderLessWindowMask windows we need to do more.
As suggested by Apple docs UI/input should be disabled and in the window should be simplified to show only relevant information.

Something that is not clear in the docs is that above methods are only called for the current document (The document in the left side of the version browser).
So in order to disable UI in windows of past versions's documents (the documents in the right side of the browser) we need other APIs:

-[NSDocument isInViewingMode] will return YES for all the documents in the right side of the browser. NO for the current document
And -[NSDocument windowForSheet] will return the windows for all these documents.

So something like this should work:
- (NSWindow *)windowForSheet{
    MyWindow *win = (MyWindow *)[super windowForSheet];
    MyDocument *doc = (MyDocument *)[[win windowController] document];
    if ([self isInViewingMode]) {
        //disable UI temporarily
        [win hideTitlebarAndStatusBar];
        [win setUserInteractionEnabled:NO];
     [doc->myTextView setEditable:NO];
    }else{
        [win showTitlebarAndStatusBar];
        [win setUserInteractionEnabled:YES];
        [doc->myTextView setEditable:YES];
    }
    return win;
}

However, in version browser, each document is created in a different thread, so if you are handling big documents it should be much more efficient to above check in the same a method that run in the same thread. (-[NSDocument windowForSheet] is called in current document thread)

So, we better write above content inside windowControllerDidLoadNib: to avoid thread changing. :)

BTW. If you wan't to debug your app's version browser set flag NSDocumentRevisionsDebugMode to YES. Each window/document in the version browser is loaded in one different thread so without this flag is difficult to debug


Fourth:
These are not mandatory but recommended to implement.
Enabling writing/saving asynchronously might improve dramatically application responsiveness, specially when working with big documents.

- (void)autosaveWithImplicitCancellability:(BOOL)autosavingIsImplicitlyCancellable completionHandler:(void (^)(NSError *errorOrNil))completionHandler;
- (BOOL)canAsynchronouslyWriteToURL:(NSURL *)url ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation;
- (void)continueActivityUsingBlock:(void (^)(void))block;
- (void)continueAsynchronousWorkOnMainThreadUsingBlock:(void (^)(void))block;
- (NSDocument *)duplicateAndReturnError:(NSError **)outError;
etc


Window restoration:
I wish Apple showed this part too in their examples so my life would have been easier but NO! - they like me to suffer! (Well not really...)

Implement these NSWindowDelegate methods too to save/restore some info into/from the coded window.

- (void)window:(NSWindow *)window willEncodeRestorableState:(NSCoder *)state
{
     //any additional info to save 
     //Example:
     [state encodeObject:myObj forKey:@"myObject"];
}
- (void)window:(NSWindow *)window didDecodeRestorableState:(NSCoder *)state
{
     //any additional info to restore
     //Example:
     MyObject *myObj = [state decodeObjectForKey:@"myObject"];
}

Similarly you can override below methods of NSWindow
I am saving the state of the title bar because that is not done by default by Cocoa
- (void)restoreStateWithCoder:(NSCoder *)coder
{
    [super restoreStateWithCoder:coder];
    titleBarHidden = [super decodeBoolForKey:@"titleBarHidden"];
}
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    [super encodeRestorableStateWithCoder:coder];
    [coder encodeBool:titleBarHidden forKey:@"titleBarHidden"];
}

Basically that is all.
More info can be found in the following links and surely everywhere very soon as Lion and these features becomes more and more popular.

References


2011/07/26

Custom Window Widgets:

This is tricky and didn't really think it would work because all the info found was more than 3 years old. But it did!
I could get a window with custom widgets (Close/Miminize/Maximize and theorically fullscreen buttons), :) . I hope someday I know photoshop as much as objc and make my own cool buttons, for now I have to play with iCal's buttons.



Normal Cocoa NSWindowButtons


Customized NSWindowButtons

The left picture shows the normal cocoa NSWindowButtons, right picture on the right shows darker and yellowish buttons, not very nice on the gray titlebar but ... Is because I don't know photoshop! (涙) But with great potential huh?! (笑)

Introduction:

In cocoa you get the buttons of a window :
NSButton *button = [window standardWindowButton:NSWindowZoomButton];

But button is not really of kind NSButton is in fact an instance of _NSThemeWidget. Furthermore, it does not use a normal NSButtonCell but it has its own _NSThemeWidgetCell. Furthermore, the close button is a subclass of them: _NSThemeCloseWidget and _NSThemeCloseWidget because it has a dirty state of the document

In this post I show how to customize the images of these private classes because setImage: does nothing :(

How this works
I tried to make a new class and pose it as an _NSThemeWidgetCell but posing is being deprecated and is not possible anymore, at least not that I know.

Crayson told me that I should better try the method swizzling approach. This was a huge hint!.
So using a couple of objective-c runtime functions I added a method dynamically to _NSThemeWidgetCell class.

Then it was very easy to exchange methods : the one newly added alt_drawWithFrame:inView: with the other that does the drawing as usual drawWithFrame:inView:.

This part the code and the whole source + the images I borrowed from Lion's iCal can be downloaded from github :)

void drawWithFrameInView(id self, SEL _cmd, NSRect frame, id view)
{   
    NSLog(@"hacking drawWithFrameInView ...");
 
    NSString *imageName = @"titlebarcontrols_regularwin";

    //Get button ID
    int buttonID = (int)[self buttonID];
    NSLog(@"%d", buttonID);
    switch (buttonID)
    {
        case 127: // Close button
            imageName = [imageName stringByAppendingFormat:@"_close"];
            break;
        case 128: // Minimize button
            imageName = [imageName stringByAppendingFormat:@"_minimize"];
            break;
        case 129: // Zoom button
            imageName = [imageName stringByAppendingFormat:@"_zoom" ];
            break;
        case 130: // Toolbar button
            imageName = [imageName stringByAppendingFormat:@"_toolbar_button" ];
            break;
    }

    //Get System preferences: Window style: (Aqua or graphite)
    NSString * const kAppleAquaColorVariant = @"AppleAquaColorVariant";
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults addSuiteNamed:NSGlobalDomain]; 
    NSNumber *color = [userDefaults objectForKey:kAppleAquaColorVariant];
    if ([color intValue] == 6) {//graphite is 6 
        imageName = [imageName stringByAppendingFormat:@"_graphite"];
    }else{//defaults to aqua, (aqua is 1)
        imageName = [imageName stringByAppendingFormat:@"_colorsryg"];
    }

    //Get button state
    if ([self respondsToSelector:@selector(getState:)]) {
        int state = (int)[self getState:view];
        //NSLog(@"state %d", state);
        switch (state) {
            //Known states
            //active = 0
            //activenokey = not used?
            //disabled = not used?
            //inactive = 3
            //pressed = 2
            //rollover = 1
            case 0: 
                imageName = [imageName stringByAppendingFormat:@"_active"];
                break;
            case 1:
                imageName = [imageName stringByAppendingFormat:@"_rollover"];
                break;
            case 2:
                imageName = [imageName stringByAppendingFormat:@"_pressed"];
                break;
            case 3:
                imageName = [imageName stringByAppendingFormat:@"_inactive"];
                break;
            case 4:
                break;//disabled? activenokey?
            case 5:
                break;//disabled? activenokey?
     default:
                break;
        }

        NSImage *img = [NSImage imageNamed:imageName];
        if (img){
            [img dissolveToPoint:NSMakePoint(frame.origin.x, frame.origin.y + frame.size.height) fraction:1.0];
        }else{
            [(NSButtonCell*)self alt_drawWithFrame:frame inView:view];//original implementation 
        }
    }
}

And the part of code that does the objective-c runtime magic:

@implementation TestAppDelegate
@synthesize window;
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{

    Class class = NSClassFromString(@"_NSThemeWidgetCell");
    SEL new_selector = @selector(alt_drawWithFrame:inView:);
    SEL orig_selector = @selector(drawWithFrame:inView:);

    //Add a new method dinamically because _NSThemeWidgetCell is a private class
    BOOL success = class_addMethod(class, new_selector, 
                (IMP)drawWithFrameInView, 
                "v@:{CGRect={CGPoint=dd}{CGSize=dd}}@");
    if (success) {
        //Get the methods to exchange
        Method originalMethod = class_getInstanceMethod(class, orig_selector);
        Method newMethod = class_getInstanceMethod(class, new_selector);

        // If both are found, swizzle them
        if ((originalMethod != nil) && (newMethod != nil)){
            method_exchangeImplementations(originalMethod, newMethod);
        }
    }

//TEST:a new method should appear "alt_drawWithFrame:inView:" in the console
//uint methodCount = 0;
//class = NSClassFromString(@"UIWebDocumentView");
//Method *mlist = class_copyMethodList(class, &methodCount);
//for (int i = 0; i < methodCount; ++i){
// NSLog(@"%@", NSStringFromSelector(method_getName(mlist[i])));
//}

//TEST: "hacking drawWithFrameInView ..." should appear in the console
//NSButton *but = [window standardWindowButton:NSWindowZoomButton];
//[[but cell] drawWithFrame:NSZeroRect inView:nil];
}
References and useful Links


2011/07/16

Instrospection in Objective-C
Sometimes public APIs in cocoa/cocoa-touch frameworks is simply not enough or maybe a private API could save you some work.

So, this is not something new: If you read Objective-c runtime reference you will find really handy and hacky functions there.
These are some snippets:

List up methods of a class
uint methodCount = 0;
Class class = NSClassFromString(@"UIWebDocumentView");
Method *mlist = class_copyMethodList(class, &methodCount);
for (int i = 0; i < methodCount; ++i){
    NSLog(@"%@", NSStringFromSelector(method_getName(mlist[i])));
}
List up protocols conformed by a class
Class class = [UITextView class];
Protocol **p1 = class_copyProtocolList(class, NULL);
for (int i = 0; p1[i]; i++) {
    printf(@"%s\n", protocol_getName(p1[i]));
}
free(p1);
List up ivars of a class
Class class = [UITextView class];
uint ivarsNum = 0;
Ivar *ivars = class_copyIvarList(class, &ivarsNum);
for (int i = 0; i < ivarsNum; i++) {
    printf(@"%s\n", ivar_getName(ivars[i]));
}
Introspect arguments of a method
Class class = [UITextView class];
SEL selector = @selector(keyboardInput:shouldInsertText:isMarkedText:);
Method method = class_getInstanceMethod(class, selector);
char *arg = method_copyArgumentType(method, 0);
printf(@"_%s_\n", arg);
free(arg);

Here you will get: @ for objects, i for integers, f for floats. That is all you get.

Using GDB In Xcode set a symbolic break point to:
-[UITextView keyboardInput:shouldInsertText:isMarkedText:]
or in gdb type:
b -[UITextView keyboardInput:shouldInsertText:isMarkedText:]
so the debugger will stop at that method. When stopped is possible to show the registers values hence is possible to inspect the arguments passed :) This is a more complete list of how to call the registers in different architectures. Since the iOS Simulator is in i386 (after prolog) I can inspect this particular method doing:
(gdb) po *(id*)($ebp + 8)
<MyTextView: 0x5911270; baseClass = UITextView; frame = (80 70; 240 323); text = 'Lorem ipsum dolor sit er ...'; clipsToBounds = YES; autoresize = RM+BM; layer = <CALayer: 0x5c0c7d0>; contentOffset: {0, 0}>

(gdb) p *(SEL*)($ebp + 12)
$1 = (SEL) 0xbd19

(gdb) po *(id*)($ebp + 16)
<UIWebDocumentView: 0xa02f000; frame = (0 0; 240 457); text = 'Lorem ipsum dolor sit er ...'; opaque = NO; userInteractionEnabled = NO; layer = <UIWebLayer: 0x5c35070>>

(gdb) po *(id*)($ebp + 20)
t

(gdb) p *(id*)($ebp + 24)
$2 = (id) 0x0
and finally to get the selector name from a SEL in gdb
(gdb) p (char*)$1
$1 = 0xbd19 "keyboardInput:shouldInsertText:isMarkedText:"

I found this super useful because now I can get the list of method of any class and dig in. Yippeee!

For example I wanted to see if I can customize some shortcuts in the iOS when using a hardware keyboard. But it turns out that the UITextView is not the one who controls that. UITextView seems to be a mere client of UIWebDocumentView which is the one who handles text input and also keyboard events. So overriding private methods of UITextView is just not enough. This is not as simple as I thought to I will save this for another post :)

Links


2011/06/17

NSWindow private methods

So, this week I tried Lion almost for the first time, is getting really cool :)

My motivation to do this is because I want to make my non-standard window enter fullscreen (although now I now this is not the way of doing it) it was interesting. So in OSX 10.6 and earlier NSWindow has: performZoom:, performMiniaturize:, performClose:, etc. So I thought there should be something like:performFullscreen: No?

I dug into 10.7 SDK documentation hoping to find something. Unfortunately no, there seems to be no new things in NSWindow?, at least not that I have noticed. Weird... Maybe I am not looking at the correct docs?

I just thought of this:
#import <objc/runtime.h>

unsigned int methodCount = 0;
Method *mlist = class_copyMethodList([NSWindow class], &methodCount);
for (int i = 0; i < methodCount; ++i){
    NSLog(@"%@", NSStringFromSelector(method_getName(mlist[i])));
}
which will print a list of all methods implemented by NSWindow and it worked! I got the whole list. Including the private methods :)

These Objective-C runtime functions must be the Swiss knife of cocoa-hackers. I still have to try this in 10.7 but This is definitely a good start.

PS: Off-course there was no performFullscreen: method. Later I realized that toggleFullScreen: will do the job :)


2011/05/08

Bezier Paths : making rectangles with rounded corners

Learning at school Bezier paths was fun for me because is when I finally got to know where all those curves come from. I like the maths, and there are a lot of them behind Bezier paths ;) .

Once the theory is known is not complicated to imagine how a path would look like just by knowing its control points position. But, off-course a normal human like me can only make an approximation inside of his/her head. In real life, you don't approximated paths, specially if you are the kind of person who care about small details like me. So, I decided to do a small research and find out the exact position the control points should have in order to approximate an arc or circle or a rounded rectangle.

My choices were: 1. get a computer graphics book or go to wikipedia, remember the maths and then get a pencil and paper and try to solve it mathematically. 2. Trial and error approach. Even though I like maths I like even more programming so decided to go for number 2 and program test my results in javascript(and put the results here)


In order to make a rounded top-left corner I need to...

First trial:

In first place, I thought: I need a cubic bezier path with one control point in the top-left corner and the other at the end of the curve. This is what I got:

Canvas not supported.

That curve starts at point P0 and ends at P1 and use a couple of control points pc0 and pc1. I obtained a nice curve ... nothing new. However the corner I have just drawn is not exactly overlapping the circle in the picture. It's actually outside.

Second trial:

Having the control points in the middle makes sense as well :
Canvas not supported.

This also looks OK. But Why now it looks like the corner was cut or cropped. It seems logical to think that control points should be at the middle like in this case.

Third Trial:

What about quadratic bezier? This seems to be fine but since we have a circle in there we notice this is not correct too.

Canvas not supported.

Fourth Trial:

So I google it and found approximation of a circle using cubic bezier curve There is a paper that has the maths I decided to skip in first place ... In page 3 Dr. Murtaza found the value of kappa: 0.55... which is the (approximated) distance of control point 1 and 2 should have from start and end point respectively. Control points should be placed as follows:

Canvas not supported.

So, if we want to have a rounded rectangle with corner radius r we have to place pc0 and pc1at (0,k)and (k,0) where k is kappa = 0.552228474...

Here we have an almost perfect rounded corner! ;)

I have implemented this in javascript with the canvas element and all the graphics here were rendered using that function. And also I have made an extension for NSBezierPath class so now I can have paths like:

Here are the sources:
NSBezierPath+Extensions.h
NSBezierPath+Extensions.m

And BezierPaths:
Canvas+BezierPaths.js

References:
Mathworks - Approximation of circle using cubic bezier
Wikipedia - Bezier Paths
MDC Docs - Drawing shapes
And maybe this too:Cocoa Dev Central - Intro to Quartz