+Thu December 24 2009 Shyouzou Sugitani <shy@users.sourceforge.jp>
+ * バージョン4.0(jump off into never-never land)リリース.
+ * locale/ja.poを更新した.
+ * ユーザー設定からヘルパーを削除した.
+ それに合わせてdoc/saori.txtを修正した.
+ * れたす(lettuce.dll)互換モジュールを削除した.
+ (要望があればGStreamerを使用して再度実装する.)
+ * 音声ファイルの再生にはGStreamerを使用するようにした.
+ \_v[]タグとMCIAudio, MCIAudioR互換モジュールを変更した.
+ MCIAudioRはループ演奏に対応した.
+ READMEの「必要なもの」にGStreamer Python bindingsを追加した.
+
+Fri December 4 2009 Shyouzou Sugitani <shy@users.sourceforge.jp>
+ * Webブラウザの呼び出しにはPythonのwebbrowerモジュールを
+ 使用するようにした.(ユーザー設定からWebブラウザを削除した.)
+
Sun November 29 2009 Shyouzou Sugitani <shy@users.sourceforge.jp>
* バージョン3.9.9aリリース.
* CommunicateWindowクラス(とそれを継承しているクラス)を修正.
Ver.4.0の変更点
-------------------
--
+- ユーザー設定からヘルパーを削除しました.
+ 音声ファイルの再生にはGStreamerを使用するようにしました.
+ GStreamer Python bindingsが必要です.
+- れたす(lettuce.dll)互換モジュールを削除しました.
+ 要望があれば再度GStreamerを使用して実装し直したものを追加します.
+- ユーザー設定からWebブラウザを削除しました.
+ 使用している環境のデフォルトブラウザを呼び出します.
+- 「きのこ」の'ontop'の処理が確実に行なわれるように修正しました.
+- 「猫どりふ」の見切れをゴースト同様に透明部分も含めたサーフェスの1/3が
+ 画面外に出ると発動するよう変更しました.
+- ユーザー設定の項目を減らしました.
+ SHIORIイベントの発生を抑制する項目(PREFS_EVENT_KILL_LIST)と
+ マウスボタンの機能を設定する項目(PREFS_MOUSE_BUTTON1, PREFS_MOUSE_BUTTON3)を
+ 削除しました.
+ また, メニューから個々のゴーストについてサーフェス倍率とスクリプトの
+ 再生スピードを設定する項目を削除しました.(全ゴーストが同じ設定になります.)
+- 画面の上下方向の有効範囲(タスクバー等を除いた範囲)をユーザーが指定する
+ ための設定値を削除しました. ウインドウマネージャから情報を得て自動的に
+ 処理します.
+- sourceforge.jpにGitリポジトリを作成し, ソースコードの管理をGitに移行しました.
+ 今後CVSのリポジトリは更新されません.
+- バルーンを出す際にバルーンがフォーカスを奪わないようにするための設定を
+ 削除しました.
+ バルーンを出す際にバルーンがフォーカスを奪わないようにしつつ, バルーンの
+ ウインドウを前面に持ってくる方法が見付からなかったためです.
+ この辺りの処理はウインドウマネージャ次第で変わってしまい, 確実な方法が
+ 無いので, ninix-ayaでは何もしないことにしました.
+- サーフェスのツールチップ表示を実装しました.(SSP互換)
+- surfaces.txtの文字コード指定に対応しました.(SSP互換)
+- _niseshiori.so(暗号化辞書の解読用C言語モジュール)を削除しました.
+ ninix-aya本体にはC言語モジュールが無くなりました.
+- 透過ウインドウ処理にGTK+2.10の新機能を使用するように変更しました.
+ このバージョンから正式にサポートされた機能になります.
+- ゴーストのサーフェスをマウスドラッグするボタンを左ボタン(1番)に変更しました.
+- ゴーストのサーフェス移動後の位置の再計算のタイミングを移動直後にしました.
+- osuwari.dll互換SAORIモジュールosuwari.pyを追加しました.
+- OnBallonCloseイベントのサポートを追加しました.
+- OnMouseEnterAll, OnMouseLeaveAll, OnMouseEnter, OnMouseLeave イベントの
+ サポートを追加しました.
+- SERIKOによるサーフェスの書き換えを抑制するオプションを追加しました.
+ (サーフェスの書き換えが起きないだけで内部でSERIKOは動作しています.)
+- YAYAローダー(yaya.py)を追加しました.(動作確認がまだ出来ていません.)
+- メニューコンテキストの配置がSSPに近付くよう変更しました.
+- PNAファイルの処理にNumpyの機能を使い高速化しました.
+- アニメーションの処理を変更し, CPU負荷とコマ飛びを低減しました.
Ver.3.9の変更点
-------------------
Shift_JIS以外の文字コードを使用している「美坂」使用ゴーストを動作させるのに
必要です。バージョン 1.0 での動作を確認しています。
+- GStreamer Python bindings (http://gstreamer.freedesktop.org/src/gst-python/)
+ 音声ファイルの再生に使用しています。 バージョン 0.10.17 での動作を確認して
+ います。
+
インストール
------------
各種OS用パッケージを使用する場合は ninix-aya 開発プロジェクト
設定
----
-é\9f³å£°ã\83\95ã\82¡ã\82¤ã\83«å\86\8dç\94\9fã\81«ã\81¯å\88¥é\80\94対å¿\9cã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\81\8cå¿\85è¦\81ã\81§ã\81\99.
-メニューから設定を選び「ヘルパー」を設定して下さい.
+é\9f³å£°ã\83\95ã\82¡ã\82¤ã\83«å\86\8dç\94\9fã\81¯GStreamerã\81\8cã\81\9dã\81®ã\83\95ã\82¡ã\82¤ã\83«å½¢å¼\8fã\81®å\86\8dç\94\9fã\81«å¯¾å¿\9cã\81\97ã\81¦ã\81\84ã\82\8cã\81°
+設定は必要ありません.
それ以外のモジュールは特に設定の必要はありません.
-設定例(「パターン : コマンド」)
-\.(mp3)$ : mpg123 -q %s
-\.(wav)$ : aplay -q %s
-\.(mid)$ : timidity -idq %s
-\.(ogg)$ : ogg123 -q %s
現在、以下の互換モジュールが収録されています。
りゅう氏が開発されている「花柚」と互換のモジュールです。
ゴーストの過去一週間の起動時間をグラフ表示します。
-lettuce.py
-----------
-七瀬いーうぃ氏が開発されている「れたす」と互換のモジュールです。
-Ogg Vorbis形式の音声を再生する機能を提供します。
-
wmove.py
--------
tmizu氏が開発されている「wmove.dll」と互換のモジュールです。
http://members.jcom.home.ne.jp/umeici/saoricollect.html
umeici氏提供の総合リンク集です。
-TiMidity++
-http://www.goice.co.jp/member/mo/timidity/index-jp.html
-http://timidity.sourceforge.jp/
-Tuuka Toivonen氏によるTiMidityの開発・公開は終了しました。
-現在は、出雲正尚氏らによってTiMidity++が公開されています。
-
-vorbis-tools
-http://www.vorbis.com/
-http://www.vorbis.com/download_unix.psp
-Ogg Vorbis公式サイトのダウンロードページです。
-ogg123が収録されています。
-
さくらのにえ
http://nie.counterghost.net/
cr.set_source_pixbuf(self.balloon_pixbuf, 0, 0)
cr.paint_with_alpha(self.__alpha_channel)
- def set_markup(self, index, text):
+ def set_markup(self, index, text): # FIXME: escape & -> &
tags_ = ('sup', 'sub', 's', 'u')
count_ = {}
for tag_ in tags_:
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# lettuce.py - a LETTUCE compatible Saori module for ninix
-# Copyright (C) 2002-2009 by Shyouzou Sugitani <shy@users.sourceforge.jp>
-# Copyright (C) 2002, 2003 by MATSUMURA Namihiko <nie@counterghost.net>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License (version 2) as
-# published by the Free Software Foundation. It is distributed in the
-# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-# PURPOSE. See the GNU General Public License for more details.
-#
-
-import os
-import sys
-import signal
-import socket
-
-from ninix.dll import SAORI
-
-
-class Saori(SAORI):
-
- module_name = 'LETTUCE'
- dll_name = 'lettuce.dll'
-
- def __init__(self):
- SAORI.__init__(self)
- self.files = {}
- self.sstpport = None
- self.__sakura = None
-
- def need_ghost_backdoor(self, sakura):
- self.__sakura = sakura
-
- def load(self, dir=os.curdir):
- self.dir = dir
- result = 0
- if self.loaded:
- result = 2
- elif self.__sakura is not None:
- signal.signal(signal.SIGCHLD, self.signal_handler)
- self.loaded = 1
- result = 1
- return result
-
- def finalize(self):
- #for name in self.files:
- # pid = self.files[name]['pid']
- # if pid:
- # os.kill(pid, 9)
- # os.waitpid(pid, 0)
- self.files = {}
- return 1
-
- def signal_handler(self, signum, frame):
- for name in self.files:
- pid = self.files[name]['pid']
- if not pid:
- continue
- result = os.waitpid(pid, os.WNOHANG)
- if result:
- if os.WIFSTOPPED(result[1]):
- self.files[name]['status'] = 'pause'
- else:
- self.files[name]['pid'] = None
- self.files[name]['status'] = 'stop'
- ### send SSTP message ###
- if os.WIFEXITED(result[1]) and self.sstpport:
- address = ('', int(self.sstpport))
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- s.connect(address)
- except socket.error:
- sys.stderr.write(
- '%s: cannot connect to the SSTP server\n' % \
- self.module_name)
- return
- s.send(
- ''.join(('SEND SSTP/1.1\r\n'
- 'Sender: %s\r\n' % self.module_name,
- 'Event: OnApplicationOperationFinish\r\n',
- 'Reference0: %s\r\n' % self.dll_name,
- 'Reference1: play.finished\r\n',
- 'Reference2: %s\r\n' % name,
- 'Charset: ASCII\r\n\r\n')))
- s.recv(1024)
- s.close()
-
- def request(self, req):
- req_type, argument = self.evaluate_request(req)
- if not req_type:
- return 'SAORI/1.0 400 Bad Request\r\n\r\n'
- elif req_type == 'GET Version':
- return 'SAORI/1.0 200 OK\r\n\r\n'
- elif req_type == 'EXECUTE':
- if not argument:
- return 'SAORI/1.0 400 Bad Request\r\n\r\n'
- command = argument[0]
- result = 0
- if command == 'set.hwnd':
- if len(argument) < 2:
- return 'SAORI/1.0 400 Bad Request\r\n\r\n'
- else:
- self.sstpport = argument[1]
- result = 1
- elif command == 'play':
- if len(argument) < 2:
- return 'SAORI/1.0 400 Bad Request\r\n\r\n'
- else:
- name = argument[1].replace('\\', '/').lower() ## FIXME: Shiori -> filename
- filepath = os.path.join(self.dir,
- ''.join(('./', name, 'ogg')))
- if name in self.files:
- pid = self.files[name]['pid']
- if pid and self.files[name]['status'] == 'play':
- try:
- os.kill(-pid, 9)
- os.waitpid(pid, 0)
- except:
- pass
- self.files[name]['pid'] = 0
- else:
- self.files[name] = {}
- if filepath:
- pid = os.fork()
- self.files[name]['pid'] = pid
- if pid == 0:
- os.setsid()
- if os.path.isfile(filepath):
- for regex, command in self.prefs.get_helpers_regex():
- if regex.search(filepath):
- self.execute_command(command, filepath)
- os._exit(0)
- self.files[name]['status'] = 'play'
- result = 1
- elif command == 'play.ex':
- pass # FIXME
- elif command == 'stop':
- if len(argument) < 2:
- for name in self.files:
- pid = self.files[name]['pid']
- if pid:
- try:
- os.kill(-pid, 9)
- os.waitpid(pid, 0)
- except:
- pass
- self.files[name]['pid'] = 0
- result = 1
- else:
- name = argument[1].replace('\\', '/').lower()
- if name in self.files:
- pid = self.files[name]['pid']
- if pid:
- try:
- os.kill(-pid, 9)
- os.waitpid(pid, 0)
- except:
- pass
- self.files[name]['pid'] = 0
- result = 1
- elif command == 'pause':
- pass # FIXME
- elif command == 'set.loop':
- pass # FIXME
- elif command == 'reset.loop':
- pass # FIXME
- return 'SAORI/1.0 200 OK\r\nResult: %s\r\n\r\n' % result
- else:
- return 'SAORI/1.0 400 Bad Request\r\n\r\n'
-
- def execute_command(self, command, arg):
- if '%s' not in command:
- sys.stderr.write('cannot execute command (%s missing)\n')
- return
- os.system(command.replace('%s', arg, 1))
#
import os
-import sys
import signal
+import pygst
+pygst.require("0.10")
+import gst
+
from ninix.dll import SAORI
def __init__(self):
SAORI.__init__(self)
- self.pid = 0
+ self.player = gst.element_factory_make("playbin", "player")
+ fakesink = gst.element_factory_make("fakesink", "fakesink")
+ self.player.set_property("video-sink", fakesink)
+ bus = self.player.get_bus()
+ bus.add_signal_watch()
+ bus.connect("message", self.on_message)
self.filepath = None
self.__sakura = None
- self.pause = 0
+ self.state = 0 # 0/1/2 - stop/playing/paused
def need_ghost_backdoor(self, sakura):
self.__sakura = sakura
return 0
def finalize(self):
- if self.pid != 0:
- try:
- os.kill(-self.pid, 9)
- os.waitpid(self.pid, 0)
- except:
- pass
- self.pid = 0
+ self.player.set_state(gst.STATE_NULL)
+ self.player = None
self.filepath = None
return 1
def execute(self, argv):
argc = len(argv)
if argc == 1:
+ assert self.player is not None
if argv[0] == 'stop':
- ##self.filepath = None
- if self.pid != 0:
- try:
- os.kill(-self.pid, 9)
- os.waitpid(self.pid, 0)
- except:
- pass
- self.pid = 0
+ self.player.set_state(gst.STATE_NULL)
elif argv[0] == 'play':
- if self.pid != 0:
- status = os.waitpid(-self.pid, os.WNOHANG)
- if os.WIFEXITED(status) or os.WIFSIGNALED(status):
- self.pid = 0
- elif self.pause:
- os.kill(-self.pid, signal.SIGCONT)
- self.pause = 0
- return 'SAORI/1.0 204 No Content\r\n\r\n'
- else:
- os.kill(-self.pid, signal.SIGSTOP)
- self.pause = 1
- return 'SAORI/1.0 204 No Content\r\n\r\n'
+ if self.state == 2:
+ self.state = 1
+ self.player.set_state(gst.STATE_PLAYING)
+ return 'SAORI/1.0 204 No Content\r\n\r\n'
+ elif self.state == 1:
+ self.state = 2
+ self.player.set_state(gst.STATE_PAUSED)
+ return 'SAORI/1.0 204 No Content\r\n\r\n'
if os.path.isfile(self.filepath):
- self.pid = os.fork()
- if self.pid == 0:
- os.setsid()
- for regex, command in self.prefs.get_helpers_regex():
- if regex.search(self.filepath):
- self.execute_command(command, self.filepath)
- os._exit(0)
+ self.player.set_property("uri", "file://" + self.filepath)
+ self.player.set_state(gst.STATE_PLAYING)
elif argc == 2:
if argv[0] == 'load':
- if self.pid != 0:
- try:
- os.kill(-self.pid, 9)
- os.waitpid(self.pid, 0)
- except:
- pass
- self.pid = 0
+ self.player.set_state(gst.STATE_NULL)
filename = argv[1].replace('\\', '/').lower()
if os.path.isabs(filename):
return 'SAORI/1.0 400 Bad Request\r\n\r\n'
filename)
return 'SAORI/1.0 204 No Content\r\n\r\n'
- def execute_command(self, command, arg):
- if '%s' not in command:
- sys.stderr.write('cannot execute command (%s missing)\n')
- return
- os.system(command.replace('%s', arg, 1))
+ def on_message(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ self.player.set_state(gst.STATE_NULL)
+ self.state = 0
+ elif t == gst.MESSAGE_ERROR:
+ self.player.set_state(gst.STATE_NULL)
+ err, debug = message.parse_error()
+ print "Error: %s" % err, debug
+ self.state = 0
# PURPOSE. See the GNU General Public License for more details.
#
-# TODO:
-# - loop 演奏.
-
import os
-import sys
import signal
+import pygst
+pygst.require("0.10")
+import gst
+
from ninix.dll import SAORI
def __init__(self):
SAORI.__init__(self)
- self.pid = 0
+ self.player = gst.element_factory_make("playbin", "player")
+ fakesink = gst.element_factory_make("fakesink", "fakesink")
+ self.player.set_property("video-sink", fakesink)
+ bus = self.player.get_bus()
+ bus.add_signal_watch()
+ bus.connect("message", self.on_message)
self.filepath = None
- self.pause = 0
+ self.state = 0 # 0/1/2 - stop/playing/paused
+ self.loop = False
def finalize(self):
- if self.pid != 0:
- try:
- os.kill(-self.pid, 9)
- os.waitpid(self.pid, 0)
- except:
- pass
- self.pid = 0
+ self.player.set_state(gst.STATE_NULL)
+ self.player = None
self.filepath = None
return 1
def execute(self, argv):
argc = len(argv)
if argc == 1:
+ assert self.player is not None
if argv[0] == 'stop':
- ##self.filepath = None
- if self.pid != 0:
- try:
- os.kill(-self.pid, 9)
- os.waitpid(self.pid, 0)
- except:
- pass
- self.pid = 0
- elif argv[0] == 'play':
- if self.pid != 0:
- status = os.waitpid(-self.pid, os.WNOHANG)
- if os.WIFEXITED(status) or os.WIFSIGNALED(status):
- self.pid = 0
- elif self.pause:
- os.kill(-self.pid, signal.SIGCONT)
- self.pause = 0
- return 'SAORI/1.0 204 No Content\r\n\r\n'
- else:
- os.kill(-self.pid, signal.SIGSTOP)
- self.pause = 1
- return 'SAORI/1.0 204 No Content\r\n\r\n'
+ self.player.set_state(gst.STATE_NULL)
+ elif argv[0] in ['play', 'loop']:
+ if argv[0] == 'loop':
+ self.loop = True
+ if self.state == 2:
+ self.state = 1
+ self.player.set_state(gst.STATE_PLAYING)
+ return 'SAORI/1.0 204 No Content\r\n\r\n'
+ elif self.state == 1:
+ self.state = 2
+ self.player.set_state(gst.STATE_PAUSED)
+ return 'SAORI/1.0 204 No Content\r\n\r\n'
if os.path.isfile(self.filepath):
- self.pid = os.fork()
- if self.pid == 0:
- os.setsid()
- for regex, command in self.prefs.get_helpers_regex():
- if regex.search(self.filepath):
- self.execute_command(command, self.filepath)
- os._exit(0)
+ self.player.set_property("uri", "file://" + self.filepath)
+ self.player.set_state(gst.STATE_PLAYING)
elif argc == 2:
if argv[0] == 'load':
- if self.pid != 0:
- try:
- os.kill(-self.pid, 9)
- os.waitpid(self.pid, 0)
- except:
- pass
- self.pid = 0
+ self.player.set_state(gst.STATE_NULL)
filename = argv[1].replace('\\', '/')
if not os.path.isabs(filename): # XXX
filename = filename.lower()
self.filepath = os.path.join(self.dir, filename)
return 'SAORI/1.0 204 No Content\r\n\r\n'
- def execute_command(self, command, arg):
- if '%s' not in command:
- sys.stderr.write('cannot execute command (%s missing)\n')
- return
- os.system(command.replace('%s', arg, 1))
+ def on_message(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ if self.loop:
+ self.player.set_state(gst.STATE_PLAYING)
+ self.state = 1
+ else:
+ self.player.set_state(gst.STATE_NULL)
+ self.state = 0
+ elif t == gst.MESSAGE_ERROR:
+ self.player.set_state(gst.STATE_NULL)
+ err, debug = message.parse_error()
+ print "Error: %s" % err, debug
+ self.state = 0
+ self.loop = False
import os
import re
import sys
-import urllib
import time
+import urllib
+import webbrowser
from xml.dom import pulldom
button.set_relief(gtk.RELIEF_NONE)
self.url['HP'] = [None, button.get_child()]
vbox2.pack_start(button, False, True, 0)
- button.connect('clicked',
- lambda b, w=self: w.launch_browser(self.url['HP'][0]))
+ button.connect(
+ 'clicked', lambda b: webbrowser.open(self.url['HP'][0]))
button.show()
button = gtk.Button('')
button.set_relief(gtk.RELIEF_NONE)
self.url['Public'] = [None, button.get_child()]
vbox2.pack_start(button, False, True, 0)
button.connect(
- 'clicked',
- lambda b, w=self: w.launch_browser(self.url['Public'][0]))
+ 'clicked', lambda b: webbrowser.open(self.url['Public'][0]))
button.show()
vbox.pack_start(hbox, False, True, 0)
hbox.show()
self.info = textview
return vbox
- def launch_browser(self, url):
- command = self.ngm.app.prefs.get('browser')
- if '%s' not in command:
- sys.stderr.write('cannot execute command (%s missing)\n')
- return
- os.system(' '.join((command.replace('%s', url, 1), '&')))
-
def update_info_area(self):
info_list = [(_('Author:'), 'Author'),
(_('ArchiveTime:'), 'ArchiveTime'),
(''.join(('7 (', _('Slow'), ')')), 8)]
# default settings
-DEFAULT_BROWSER = "firefox %s"
DEFAULT_BALLOON_FONTS = 'Sans'
def get_default_surface_scale():
class PreferenceDialog:
- PREFS_HELPER_PATTERN = 'helper_%d_pattern'
- PREFS_HELPER_COMMAND = 'helper_%d_command'
-
PREFS_TYPE = {'sakura_name': None,
'sakura_surface': int,
'default_balloon': None,
'script_speed': int,
'surface_scale': int,
'balloon_scalling': int,
- 'browser': None,
- 'helper_%d_pattern': None,
- 'helper_%d_command': None,
'balloon_fonts': None,
'allowembryo': int,
'check_collision': int,
self.notebook.show()
for name, constructor in [
(_('Font'), self.make_page_fonts),
- (_('Browser'), self.make_page_browser),
- (_('Helper'), self.make_page_helper),
(_('Surface&Balloon'), self.make_page_surface_n_balloon),
(_('Misc'), self.make_page_misc),
(_('Debug'), self.make_page_debug),
button.connect('clicked', self.cancel)
box.add(button)
button.show()
- self.rule_editor = RuleEditor(self.window)
def load(self):
self.__prefs = load_prefs()
def reset(self): ### FIXME ###
self.set_balloon_fonts(self.get('balloon_fonts', DEFAULT_BALLOON_FONTS))
- self.set_browser(self.get('browser', DEFAULT_BROWSER))
- helper_list = []
- while 1:
- pattern = self.__prefs.get(self.PREFS_HELPER_PATTERN % len(helper_list)) ## FIXME
- command = self.__prefs.get(self.PREFS_HELPER_COMMAND % len(helper_list)) ## FIXME
- if not pattern or not command:
- break
- helper_list.append((pattern, command))
- self.set_helpers(helper_list)
name = self.get('default_balloon')
if self.app.find_balloon_by_name(name) is not None:
self.set_default_balloon(name)
self.__prefs['sakura_surface'] = self.__saved_prefs['sakura_surface'] = surface
self.__prefs.save()
- def get_helpers_regex(self):
- helpers_regex = []
- for pattern, command in self.get_helpers():
- try:
- regex = re.compile(pattern)
- except re.error:
- continue
- helpers_regex.append((regex, command))
- return helpers_regex
-
def edit_preferences(self):
self.show()
def update(self): ## FIXME
self.__prefs['allowembryo'] = str(1 if self.allowembryo_button.get_active() else 0)
self.__prefs['balloon_fonts'] = self.fontsel.get_font_name()
- self.__prefs['browser'] = self.browser.get_text()
- lstore = self.helpers.get_model()
- listiter = lstore.get_iter_first()
- i = 0 ## FIXME
- while listiter:
- self.__prefs[self.PREFS_HELPER_PATTERN % i] = lstore.get_value(listiter, 0)
- self.__prefs[self.PREFS_HELPER_COMMAND % i] = lstore.get_value(listiter, 1)
- i += 1
- listiter = lstore.iter_next(listiter)
name = None
selected = self.balloon_treeview.get_selection().get_selected()
if selected:
page.show()
return page
- def make_page_browser(self):
- page = gtk.VBox(spacing=5)
- page.set_border_width(5)
- # browser
- frame = gtk.Frame(unicode(_('Browser'), 'utf-8'))
- frame.set_size_request(480, -1)
- page.pack_start(frame)
- frame.show()
- box = gtk.VBox(spacing=2)
- box.set_border_width(5)
- frame.add(box)
- box.show()
- self.browser = gtk.Entry()
- box.pack_start(self.browser, False)
- self.browser.show()
- # help messages
- frame = gtk.Frame()
- frame.set_size_request(480, -1)
- page.pack_start(frame, False)
- frame.show()
- box = gtk.VBox(spacing=2)
- box.set_border_width(5)
- frame.add(box)
- box.show()
- label = gtk.Label(unicode(_('- %s in this command line will be replaced with the URL'), 'utf-8'))
- label.set_alignment(0, -1)
- box.pack_start(label, False)
- label.show()
- label = gtk.Label(unicode(_('- trailing & is not required.(automagically added)'), 'utf-8'))
- label.set_alignment(0, -1)
- box.pack_start(label, False)
- label.show()
- page.show()
- return page
-
- def make_page_helper(self):
- page = gtk.VBox(spacing=5)
- page.set_border_width(5)
- frame = gtk.Frame(unicode(_('Application'), 'utf-8'))
- frame.set_size_request(480, -1)
- page.pack_start(frame)
- frame.show()
- box = gtk.VBox(spacing=5)
- box.set_border_width(5)
- frame.add(box)
- box.show()
- swin = gtk.ScrolledWindow()
- swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- box.pack_start(swin)
- swin.show()
- lstore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
- self.helpers = gtk.TreeView(lstore)
- column = gtk.TreeViewColumn('Pattern', gtk.CellRendererText(), text=0)
- self.helpers.append_column(column)
- column = gtk.TreeViewColumn('Command', gtk.CellRendererText(), text=1)
- self.helpers.append_column(column)
- swin.add(self.helpers)
- self.helpers.show()
- bbox = gtk.HButtonBox()
- bbox.set_spacing(10)
- bbox.set_layout(gtk.BUTTONBOX_EDGE)
- bbox.set_border_width(5)
- box.pack_start(bbox, False)
- bbox.show()
- button = gtk.Button('New')
- button.connect('clicked', self.rule_new)
- bbox.pack_start(button)
- button.show()
- button = gtk.Button('Edit')
- button.connect('clicked', self.rule_edit)
- bbox.pack_start(button)
- button.show()
- button = gtk.Button('Delete')
- button.connect('clicked', self.rule_delete)
- bbox.pack_start(button)
- button.show()
- button = gtk.Button('Up')
- button.connect('clicked', self.rule_up)
- bbox.pack_start(button)
- button.show()
- button = gtk.Button('Down')
- button.connect('clicked', self.rule_down)
- bbox.pack_start(button)
- button.show()
- frame = gtk.Frame()
- frame.set_size_request(480, -1)
- page.pack_start(frame, False)
- frame.show()
- box = gtk.VBox(spacing=2)
- box.set_border_width(5)
- frame.add(box)
- box.show()
- label = gtk.Label(unicode(_('- %s in this command line will be replaced with the filename'), 'utf-8'))
- label.set_alignment(0, -1)
- box.pack_start(label, False)
- label.show()
- label = gtk.Label(unicode(_('- trailing & is not required.(automagically added)'), 'utf-8'))
- label.set_alignment(0, -1)
- box.pack_start(label, False)
- label.show()
- page.show()
- return page
-
def make_page_surface_n_balloon(self):
page = gtk.VBox(spacing=5)
page.set_border_width(5)
button.show()
return page
- def rule_new(self, widget):
- self.rule_editor.set_pattern('')
- self.rule_editor.set_command('')
- if self.rule_editor.run('New rule...'):
- pattern = self.rule_editor.get_pattern()
- command = self.rule_editor.get_command()
- lstore = self.helpers.get_model()
- listiter = lstore.append()
- lstore.set(listiter, 0, pattern, 1, command)
-
- def rule_edit(self, widget):
- selection = self.helpers.get_selection()
- lstore, listiter = selection.get_selected()
- if not listiter:
- return
- pattern = lstore.get_value(listiter, 0)
- command = lstore.get_value(listiter, 1)
- self.rule_editor.set_pattern(pattern)
- self.rule_editor.set_command(command)
- if self.rule_editor.run('Edit rule...'):
- pattern = self.rule_editor.get_pattern()
- command = self.rule_editor.get_command()
- lstore.set(listiter, 0, pattern, 1, command)
-
- def rule_delete(self, widget):
- selection = self.helpers.get_selection()
- lstore, listiter = selection.get_selected()
- if not listiter:
- return
- lstore.remove(listiter)
-
- def rule_up(self, widget):
- selection = self.helpers.get_selection()
- lstore, listiter = selection.get_selected()
- if not listiter:
- return
- path = lstore.get_path(listiter)
- if path[0] == 0:
- return
- listiter_ = lstore.get_iter(path[0] - 1)
- if listiter_:
- lstore.swap(listiter_, listiter)
-
- def rule_down(self, widget):
- selection = self.helpers.get_selection()
- lstore, listiter = selection.get_selected()
- if not listiter:
- return
- listiter_ = lstore.iter_next(listiter)
- if listiter_:
- lstore.swap(listiter_, listiter)
-
def notify(self): ## FIXME
for sakura in self.app.get_working_ghost():
sakura.reset_balloon_fonts() ## FIXME
def set_balloon_fonts(self, name):
self.fontsel.set_font_name(name)
- def set_browser(self, command):
- self.browser.set_text(command)
-
- def set_helpers(self, helper_list):
- lstore = self.helpers.get_model()
- lstore.clear()
- for pattern, command in helper_list:
- listiter = lstore.append()
- lstore.set(listiter, 0, pattern, 1, command)
-
- def get_helpers(self):
- helper_list = []
- while 1:
- pattern = self.__prefs.get(self.PREFS_HELPER_PATTERN % len(helper_list))
- command = self.__prefs.get(self.PREFS_HELPER_COMMAND % len(helper_list))
- if not pattern or not command:
- break
- helper_list.append((pattern, command))
- return helper_list
-
def set_balloon_scalling(self, flag):
self.balloon_scalling_button.set_active(True if flag else False)
def set_seriko_inactive(self, flag):
self.seriko_inactive_button.set_active(True if flag else False)
-
-
-class RuleEditor:
-
- def __init__(self, master=None):
- self.dialog = gtk.Dialog()
- self.dialog.connect('delete_event', self.cancel)
- self.dialog.set_modal(True)
- self.dialog.set_position(gtk.WIN_POS_CENTER)
- if master is not None:
- self.dialog.set_transient_for(master)
- # entries
- table = gtk.Table(2, 2)
- table.set_row_spacings(5)
- table.set_col_spacings(5)
- table.set_border_width(10)
- self.dialog.vbox.pack_start(table)
- label = gtk.Label('Pattern')
- table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)
- self.pattern_entry = gtk.Entry()
- self.pattern_entry.set_size_request(300, -1)
- self.pattern_entry.connect('changed', self.changed)
- table.attach(self.pattern_entry, 1, 2, 0, 1)
- label = gtk.Label('Command')
- table.attach(label, 0, 1, 1, 2, xoptions=gtk.FILL)
- self.command_entry = gtk.Entry()
- self.command_entry.set_size_request(300, -1)
- self.command_entry.connect('changed', self.changed)
- table.attach(self.command_entry, 1, 2, 1, 2)
- self.dialog.vbox.show_all()
- # buttons
- self.ok_button = gtk.Button('OK')
- self.ok_button.connect('clicked', self.ok)
- self.dialog.action_area.pack_start(self.ok_button)
- button = gtk.Button('Cancel')
- button.connect('clicked', self.cancel)
- self.dialog.action_area.pack_start(button)
- self.dialog.action_area.show_all()
-
- def set_pattern(self, text):
- self.pattern_entry.set_text(text)
-
- def get_pattern(self):
- return self.pattern_entry.get_text()
-
- def set_command(self, text):
- self.command_entry.set_text(text)
-
- def get_command(self):
- return self.command_entry.get_text()
-
- def changed(self, widget, event=None):
- if self.pattern_entry.get_text() and \
- self.command_entry.get_text():
- self.ok_button.set_sensitive(True)
- else:
- self.ok_button.set_sensitive(False)
-
- def run(self, title):
- self.dialog.set_title(title)
- self.dialog.show()
- gtk.main()
- return self.done
-
- def hide(self):
- self.dialog.hide()
- gtk.main_quit()
-
- def ok(self, widget, event=None):
- self.done = 1
- self.hide()
- return True
-
- def cancel(self, widget, event=None):
- self.done = 0
- self.hide()
- return True
# PURPOSE. See the GNU General Public License for more details.
#
+import codecs
import os
+import random
import re
-import socket
import select
+import socket
import sys
import time
-import random
-import codecs
+import webbrowser
import StringIO
if 'DISPLAY' in os.environ:
import gtk ## FIXME
import gobject
+import pygst
+pygst.require("0.10")
+import gst
+
import ninix.surface
import ninix.balloon
import ninix.dll
name = (shiori_dll, shiori_name)
self.shiori = self.__dll.request(name)
self.updateman = ninix.update.NetworkUpdate(self)
+ self.audio_player = gst.element_factory_make("playbin", "player")
+ fakesink = gst.element_factory_make("fakesink", "fakesink")
+ self.audio_player.set_property("video-sink", fakesink)
char = 2
while self.desc.get('char%d.seriko.defaultsurface' % char) is not None:
char += 1
def is_anchor(self, link_id):
return 1 if len(link_id) == 2 and link_id[0] == 'anchor' else 0
- def launch_browser(self, url): ## FIXME
- command = self.prefs.get('browser')
- self.execute_command(command, url)
-
def execute_command(self, command, arg): ## FIXME
if '%s' not in command:
sys.stderr.write('cannot execute command (%s missing)\n')
if self.is_anchor(link_id):
self.notify_event('OnAnchorSelect', link_id[1])
elif self.is_URL(link_id):
- self.launch_browser(link_id)
+ webbrowser.open(link_id)
self.reset_script(1)
self.stand_by(0)
elif self.sstp_entry_db:
def notify_site_selection(self, event, args):
title, url = args
if self.is_URL(url):
- self.launch_browser(url)
+ webbrowser.open(url)
self.enqueue_event('OnRecommandedSiteChoice', title, url)
def notify_surface_click(self, button, click, side, x, y):
self.hide_all()
self.surface.finalize()
self.balloon.finalize()
+ self.audio_player.set_state(gst.STATE_NULL)
+ self.audio_player = None
def process_script(self):
now = time.time()
def __yen_j(self, args):
jump_id = args[0]
if self.is_URL(jump_id):
- self.launch_browser(jump_id)
+ webbrowser.open(jump_id)
elif self.sstp_entry_db:
self.start_script(self.sstp_entry_db.get(jump_id, r'\e'))
filename = filename.lower()
path = os.path.join(self.get_prefix(), 'ghost/master', filename)
if os.path.isfile(path):
- for regex, command in self.prefs.get_helpers_regex():
- if regex.search(path):
- self.execute_command(command, path)
- break
+ self.audio_player.set_state(gst.STATE_NULL)
+ self.audio_player.set_property("uri", "file://" + path)
+ self.audio_player.set_state(gst.STATE_PLAYING)
def __yen_exclamation(self, args): ## FIXME
if not args:
if args[0] == 'raise' and argc >= 2:
self.notify_event(*args[1:10])
elif args[0:2] == ['open', 'browser'] and argc > 2:
- self.launch_browser(args[2])
+ webbrowser.open(args[2])
elif args[0:2] == ['open', 'communicatebox']:
if not self.passivemode:
self.balloon.open_communicatebox()
# PURPOSE. See the GNU General Public License for more details.
#
-NUMBER = '3.9.9a'
-CODENAME = '"I see no more YASAGURE here."'
+NUMBER = '4.0'
+CODENAME = 'jump off into never-never land'
VERSION = '%s (%s)' % (NUMBER, CODENAME)
VERSION_INFO = (''.join((r'\h\s[0]\w8ninix-aya %s\n' % VERSION,
msgstr ""
"Project-Id-Version: ninix-aya 4.0\n"
"POT-Creation-Date: Tue Sep 23 18:01:59 2003\n"
-"PO-Revision-Date: 2009-07-08 20:34+JST\n"
+"PO-Revision-Date: 2009-12-24 02:48+JST\n"
"Last-Translator: Shyouzou Sugitani <shy@users.sourcefoge.jp>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
msgid "Katochan(_K)"
msgstr "落下物(_K)"
-#: lib/ninix/ngm.py:276
+#: lib/ninix/ngm.py:277
msgid "Search for"
msgstr "検索文字を入力して下さい"
-#: lib/ninix/ngm.py:282
+#: lib/ninix/ngm.py:283
msgid "OK"
msgstr "OK"
-#: lib/ninix/ngm.py:285
+#: lib/ninix/ngm.py:286
msgid "Cancel"
msgstr "キャンセル"
-#: lib/ninix/ngm.py:342
+#: lib/ninix/ngm.py:343
msgid "_File"
msgstr "ファイル(_F)"
-#: lib/ninix/ngm.py:343
+#: lib/ninix/ngm.py:344
msgid "_View"
msgstr "表示(_V)"
-#: lib/ninix/ngm.py:344
+#: lib/ninix/ngm.py:345
msgid "_Archive"
msgstr "アーカイブ(_A)"
-#: lib/ninix/ngm.py:345
+#: lib/ninix/ngm.py:346
msgid "_Help"
msgstr "ヘルプ(_H)"
-#: lib/ninix/ngm.py:347
+#: lib/ninix/ngm.py:348
msgid "Search(_F)"
msgstr "検索(_F)"
-#: lib/ninix/ngm.py:351
+#: lib/ninix/ngm.py:352
msgid "Search Forward(_S)"
msgstr "次を検索(_S)"
-#: lib/ninix/ngm.py:355
+#: lib/ninix/ngm.py:356
msgid "Settings(_O)"
msgstr "設定(_O)"
-#: lib/ninix/ngm.py:359
+#: lib/ninix/ngm.py:360
msgid "DB Network Update(_N)"
msgstr "DB ネットワーク更新(_N)"
-#: lib/ninix/ngm.py:363
+#: lib/ninix/ngm.py:364
msgid "Close(_X)"
msgstr "終了(_X)"
-#: lib/ninix/ngm.py:367
+#: lib/ninix/ngm.py:368
msgid "Mask(_M)"
msgstr "表示マスク(_M)"
-#: lib/ninix/ngm.py:371
+#: lib/ninix/ngm.py:372
msgid "Reset to Default(_Y)"
msgstr "デフォルトに戻す(_Y)"
-#: lib/ninix/ngm.py:375
+#: lib/ninix/ngm.py:376
msgid "Show All(_Z)"
msgstr "すべて表示(_Z)"
-#: lib/ninix/ngm.py:391
+#: lib/ninix/ngm.py:392
msgid "Ghost Manager"
msgstr "ゴーストマネージャ"
-#: lib/ninix/ngm.py:425
+#: lib/ninix/ngm.py:426
msgid "Previous"
msgstr "前ヘ"
-#: lib/ninix/ngm.py:430
+#: lib/ninix/ngm.py:431
msgid "Next"
msgstr "次ヘ"
-#: lib/ninix/ngm.py:519
+#: lib/ninix/ngm.py:520
msgid "Install"
msgstr "Install"
-#: lib/ninix/ngm.py:524
+#: lib/ninix/ngm.py:525
msgid "Update"
msgstr "Update"
-#: lib/ninix/ngm.py:567
+#: lib/ninix/ngm.py:560
msgid "Author:"
msgstr "作者:"
-#: lib/ninix/ngm.py:568
+#: lib/ninix/ngm.py:561
msgid "ArchiveTime:"
msgstr "最終更新時刻:"
-#: lib/ninix/ngm.py:569
+#: lib/ninix/ngm.py:562
msgid "ArchiveSize:"
msgstr "アーカイブサイズ:"
-#: lib/ninix/ngm.py:570
+#: lib/ninix/ngm.py:563
msgid "NetworkUpdateTime:"
msgstr "ネットワーク更新時刻:"
-#: lib/ninix/ngm.py:571
+#: lib/ninix/ngm.py:564
msgid "Version:"
msgstr "バージョン:"
-#: lib/ninix/ngm.py:572
+#: lib/ninix/ngm.py:565
msgid "AIName:"
msgstr "使用偽AI:"
-#: lib/ninix/ngm.py:579 lib/ninix/ngm.py:583
+#: lib/ninix/ngm.py:572 lib/ninix/ngm.py:576
msgid "SurfaceList:"
msgstr "使用サーフィス:"
-#: lib/ninix/ngm.py:593
+#: lib/ninix/ngm.py:586
msgid " Web Page"
msgstr "公開ページ"
msgid "Slow"
msgstr "遅い"
-#: lib/ninix/prefs.py:148
+#: lib/ninix/prefs.py:141
msgid "Font"
msgstr "フォント"
-#: lib/ninix/prefs.py:149 lib/ninix/prefs.py:314
-msgid "Browser"
-msgstr "ブラウザ"
-
-#: lib/ninix/prefs.py:150
-msgid "Helper"
-msgstr "ヘルパー"
-
-#: lib/ninix/prefs.py:151
+#: lib/ninix/prefs.py:142
msgid "Surface&Balloon"
msgstr "サーフェス&バルーン"
-#: lib/ninix/prefs.py:152
+#: lib/ninix/prefs.py:143
msgid "Misc"
msgstr "色々"
-#: lib/ninix/prefs.py:153
+#: lib/ninix/prefs.py:144
msgid "Debug"
msgstr "デバッグ"
-#: lib/ninix/prefs.py:300
+#: lib/ninix/prefs.py:262
msgid "Font(s) for balloons"
msgstr "バルーンフォント"
-#: lib/ninix/prefs.py:334
-msgid "- %s in this command line will be replaced with the URL"
-msgstr "・コマンド中の %s は URL に置き換えられます"
-
-#: lib/ninix/prefs.py:338 lib/ninix/prefs.py:406
-msgid "- trailing & is not required.(automagically added)"
-msgstr "・末尾に & を付ける必要はありません (自動的に付加されます)"
-
-#: lib/ninix/prefs.py:348
-msgid "Application"
-msgstr "アプリケーション"
-
-#: lib/ninix/prefs.py:402
-msgid "- %s in this command line will be replaced with the filename"
-msgstr "・コマンド中の %s はファイル名に置き換えられます"
-
-#: lib/ninix/prefs.py:417
+#: lib/ninix/prefs.py:276
msgid "Surface Scaling"
msgstr "サーフェス倍率"
-#: lib/ninix/prefs.py:428 lib/ninix/prefs.py:546
+#: lib/ninix/prefs.py:287 lib/ninix/prefs.py:405
msgid "Default Setting"
msgstr "デフォルト設定"
-#: lib/ninix/prefs.py:436
+#: lib/ninix/prefs.py:295
msgid "Scale Balloon"
msgstr "バルーンもいっしょ"
-#: lib/ninix/prefs.py:440
+#: lib/ninix/prefs.py:299
msgid "Default Balloon"
msgstr "デフォルトのバルーン"
-#: lib/ninix/prefs.py:460
+#: lib/ninix/prefs.py:319
msgid "Balloon Name"
msgstr "バルーン名"
-#: lib/ninix/prefs.py:466
+#: lib/ninix/prefs.py:325
msgid "Always Use This Balloon"
msgstr "常にこのバルーンを使う"
-#: lib/ninix/prefs.py:470
+#: lib/ninix/prefs.py:329
msgid "Translucency"
msgstr "透過処理"
-#: lib/ninix/prefs.py:478
+#: lib/ninix/prefs.py:337
msgid "Use PNA file"
msgstr "PNAファイルを使用する"
-#: lib/ninix/prefs.py:485
+#: lib/ninix/prefs.py:344
msgid "Surfaces' alpha channel"
msgstr "サーフェスの透過率"
-#: lib/ninix/prefs.py:495
+#: lib/ninix/prefs.py:354
msgid "Balloons' alpha channel"
msgstr "バルーンの透過率"
-#: lib/ninix/prefs.py:502
+#: lib/ninix/prefs.py:361
msgid "Animation"
msgstr "アニメーション"
-#: lib/ninix/prefs.py:513
+#: lib/ninix/prefs.py:372
msgid "Quality"
msgstr "品質"
-#: lib/ninix/prefs.py:521
+#: lib/ninix/prefs.py:380
msgid "SERIKO INACTIVE"
msgstr "アニメーション抑制"
-#: lib/ninix/prefs.py:531
+#: lib/ninix/prefs.py:390
msgid "SSTP Setting"
msgstr "SSTP 設定"
-#: lib/ninix/prefs.py:535
+#: lib/ninix/prefs.py:394
msgid "Allowembryo"
msgstr "IfGhostに一致するゴーストがいない場合に他のゴーストで再生(SEND/1.4)"
-#: lib/ninix/prefs.py:539
+#: lib/ninix/prefs.py:398
msgid "Script Wait"
msgstr "表示ウェイト"
-#: lib/ninix/prefs.py:554
+#: lib/ninix/prefs.py:413
msgid "Raise & Lower"
msgstr "Raise & Lower"
-#: lib/ninix/prefs.py:562
+#: lib/ninix/prefs.py:421
msgid "Sink after Talk"
msgstr "喋り終わると裏へ沈む"
-#: lib/ninix/prefs.py:566
+#: lib/ninix/prefs.py:425
msgid "Raise before Talk"
msgstr "喋る時手前に出てくる"
-#: lib/ninix/prefs.py:576
+#: lib/ninix/prefs.py:435
msgid "Surface Debugging"
msgstr "サーフェスのデバッグ"
-#: lib/ninix/prefs.py:580
+#: lib/ninix/prefs.py:439
msgid "Display Collision Area"
msgstr "当たり判定領域を表示する"
-#: lib/ninix/sakura.py:289
+#: lib/ninix/sakura.py:297
msgid "Network Update has begun."
msgstr "ネットワーク更新を開始しました。"
-#: lib/ninix/sakura.py:293
+#: lib/ninix/sakura.py:301
msgid "Network Update completed successfully."
msgstr "ネットワーク更新に成功しました。"
-#: lib/ninix/sakura.py:297
+#: lib/ninix/sakura.py:305
msgid "Network Update failed."
msgstr "ネットワーク更新に失敗しました。"
-#: lib/ninix/sakura.py:433
+#: lib/ninix/sakura.py:437
msgid "Sakura&Unyuu"
msgstr "さくら&うにゅう"
-#: lib/ninix/sakura.py:438
+#: lib/ninix/sakura.py:442
msgid "User"
msgstr "ユーザーさん"
-#: lib/ninix/sakura.py:442 lib/ninix/sakura.py:446
+#: lib/ninix/sakura.py:446 lib/ninix/sakura.py:450
msgid "Sakura"
msgstr "さくら"
-#: lib/ninix/sakura.py:450
+#: lib/ninix/sakura.py:454
msgid "Unyuu"
msgstr "うにゅう"
-#: lib/ninix/sakura.py:455
+#: lib/ninix/sakura.py:459
msgid "Tomoyo"
msgstr "知世"
-#: lib/ninix/sakura.py:757
+#: lib/ninix/sakura.py:761
msgid "Own Balloon"
msgstr "専用バルーン"
-#: lib/ninix/sakura.py:948
+#: lib/ninix/sakura.py:952
msgid "Master"
msgstr "マスター"
-#: lib/ninix/sakura.py:1757
+#: lib/ninix/sakura.py:1762
msgid "I'm afraid I don't have Network Update yet."
msgstr "ネットワーク更新、\\w4まだ無いの。"
-#: lib/ninix/sakura.py:1782
+#: lib/ninix/sakura.py:1787
msgid "Vanish"
msgstr "消滅指示"
-#: lib/ninix/sakura.py:1789
+#: lib/ninix/sakura.py:1794
msgid "Yes"
msgstr "はい"
-#: lib/ninix/sakura.py:1793
+#: lib/ninix/sakura.py:1798
msgid "No"
msgstr "いいえ"