conky

メインPCにLinuxを入れてえーっと 半年くらい?
ウインドウマネージャはOpenBoxで タスクバーがわりにlxpanel あとステータスの表示にconkeyを使ってます。

アナログ時計が欲しくなったので今日はconkyからluaを呼び出してcairoで時計を描いてみることにします。
(意外に日本語のチュートリアルがないので、誰かの助けになれば… ということで書いてみよう。

もう↑のスクリーンショットには作成済みの時計が見えてますが、これからアレの作り方を書いてみることにします

conky

設定の再読込

An easy way to force Conky to reload your ~/.conkyrc: "killall -SIGUSR1 conky". Saves you the trouble of having to kill and then restart. You can now also do the same with SIGHUP.

なんかこれでもうまくいかないこともあったのでそういう時はkillしてconkyを再起動

HelloWorld

conky.lua

 function conky_string_func()
         return "Hello"
 end

とかしておく

以下を.conkyrcのTEXTより上に書く

 lua_load conky.lua

TEXTより下に

 ${lua_parse string_func}

とする

Helloと出た!

lua_parseはluaの設定ファイルの書式を解釈するはずだからフォントの色とかも変えられそう。
他にもlua_barとかlua_gaugeとかあるね。
しかし今回の目的はアナログ時計の表示なのだ スルー

luaとcairo

luaからcairoが使えます。
書き放題!

 require 'cairo'
 function conky_string_func()
          return "Hello"
 end
 
 cs, cr = nil
 function conky_cairo_test()
         if conky_window == nil then return end
         if cs == nil or cairo_xlib_surface_get_width(cs) ~= conky_window.width or cairo_xlib_surface_get_height(cs) ~= conky_window.height then
            if cs then cairo_surface_destroy(cs) end
            cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
         end
         if cr then cairo_destroy(cr) end
         cr = cairo_create(cs)
         cairo_move_to(cr, 0, 0)
         cairo_line_to(cr, 100,100)
         cairo_set_source_rgb(cr, 1, 0.2, 0.2);
         cairo_set_line_width(cr, 10.0)
         cairo_stroke(cr)
         cairo_destroy(cr)
         cr = nil
 end

このconky_cairo_test関数が毎度よばれるらしい

.conkyrcのTEXTよりも前に

 lua_load conky.lua
 lua_draw_hook_pre cairo_test

とかすると反映される。

なんか動かないときはconkyのオプションを利用する

 conky -d

で起動するとエラーを詳細に表示してくれる。

今回使ったlua_draw_hook_preはレイアウトは無視して背景を描くものなんだけど、ある範囲を確保して絵を書くにはどうすればいいんだろう?

ちょっと調べたけどわかんない まぁいいや
TEXT以下は改行をたくさん入れればスペースが確保できるし

luaの注意

基本JSっぽい ブロックの書き方が{}ではなくて endで終わる事、 文字の結合が..演算子であることくらいを気にすればいいのかな?

うぎゃコメントが // ではなくて --なのか

luaで時間を扱う
 function conky_string_func()
         local ts = os.date('*t')
         return ts['hour']%13 .. ':' .. ts['min'] .. ':' .. ts['sec'];
 end

os.dateが優秀だね これで材料は揃った

読むべきリファレンス

もうこれだけあればやりたいことは全部できる

時計の作成

つってももう材料があるのであとは sin,cosが使えれば出来上がりだね

 require 'cairo'
 function conky_string_func()
	 return os.date('%m/%d %H:%M');
 end
 
 cs, cr = nil
 function conky_cairo_test()
	 if conky_window == nil then return end
	 if cs == nil or cairo_xlib_surface_get_width(cs) ~= conky_window.width or cairo_xlib_surface_get_height(cs) ~= conky_window.height then
	    if cs then cairo_surface_destroy(cs) end
	    cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
	 end
	 if cr then cairo_destroy(cr) end
 
	 cr = cairo_create(cs)
 
	 cairo_set_line_width(cr, 3.0)
	 cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1);
	 local r = math.min(conky_window.width, conky_window.height);
	 cairo_arc(cr, r/2, r/2, r/2 * 0.8, 0, 2 * math.pi)
	 cairo_stroke(cr);	 
 
	 local ts = os.date('*t');
	 local i,tr
	 cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
	 for i = 0,11 do
	     tr = math.pi * 2 * i / 12;
	     cairo_move_to(cr, r/2 + 0.7*r/2*math.cos(tr), r/2 + 0.7*r/2*math.sin(tr));
	     cairo_line_to(cr, r/2 + 0.9*r/2*math.cos(tr), r/2 + 0.9*r/2*math.sin(tr));
	     cairo_stroke(cr);	 
	 end
	 
	 -- hour
	 tr = math.pi*2*(ts['hour']*60 + ts['min'])/(60*12) - math.pi/2
	 cairo_set_source_rgb(cr, 1, 1, 0.2);
	 cairo_move_to(cr, r/2, r/2);
	 cairo_line_to(cr, r/2 + 0.6*r/2*math.cos(tr), r/2 + 0.6*r/2*math.sin(tr));
	 cairo_stroke(cr);	 
 
	 -- min
	 cairo_set_source_rgb(cr, 0.2, 1, 0.2);
	 cairo_move_to(cr, r/2, r/2);
	 cairo_line_to(cr, r/2 + 0.8*r/2*math.cos(math.pi*2*ts['min']/60 - math.pi/2), r/2 + 0.8*r/2*math.sin(math.pi*2*ts['min']/60 - math.pi/2));
	 cairo_stroke(cr);	 
 
	 -- sec
	 cairo_set_source_rgba(cr, 0.5, 0.5, 1, 0.8);
	 cairo_move_to(cr, r/2, r/2);
	 cairo_line_to(cr, r/2 + r/2*math.cos(math.pi*2*ts['sec']/60 - math.pi/2), r/2 + r/2*math.sin(math.pi*2*ts['sec']/60 - math.pi/2));
	 cairo_stroke(cr);	 
 
	 cairo_destroy(cr)
	 cr = nil
 end

でーきた!