========================================================================== Writing new XScreenSaver modules XScreenSaverの新しいモジュールの書き方 ========================================================================== Any program that can be made to render on an X window created by another process can be used as a screen saver. Just get the window ID out of $XSCREENSAVER_WINDOW, draw on that, and you're done. 他のプロセスで作成されたXウィンドウにレンダリングさせることができるプログラムであれば、スクリーンセーバーとして使用することができます。 $XSCREENSAVER_WINDOWからウィンドウIDを取り出し、その上に描画すれば完了です。 In theory, you can write a screen saver in any language you like. In practice, however, languages other than C or C++ tend not to allow you to draw to windows that they did not create themselves. Unfortunately, this means that if you want to write a screen saver, you must write it in C. 理論的には、好きな言語でスクリーンセーバーを書くことができます。 しかし、実際には、CやC++以外の言語では、自分で作成したものではないウィンドウへの描画はできない傾向にあります。 残念ながら、これではスクリーンセーバーを書こうと思ったら、C言語で書かなければならないことになる。 Given that you're going to be writing in C, you might as well take advantage of the various utility functions that I have written to make that easier. Writing a new screen saver in C using the frameworks included with xscreensaver simplifies things enormously. C言語で書くことを考えると、それを容易にするために私が書いた様々なユーティリティ関数を利用した方が良いでしょう。 xscreensaverに含まれるフレームワークを使用してC言語で新しいスクリーンセーバーを書くと、非常に簡単になります。 Generally, the best way to learn how to do something is to find a similar program, and play around with it until you understand it. Another approach is to not worry about understanding it, but to just hack it out. Either way, your best bet is probably to start with one of the existing xscreensaver demos, included in the "hacks/" directory, rename the file, and edit it until it does what you want. 一般に、何かのやり方を学ぶには、似たようなプログラムを見つけて、理解できるまでいじくり回すのが一番です。 もう一つの方法は、理解することを気にせず、ただハックすることです。 いずれにせよ、あなたの最善の方法は、おそらく "hacks/" ディレクトリに含まれる既存の xscreensaver デモのうちの 1 つから始めて、ファイル名を変更し、あなたが望むようになるまでそれを編集することでしょう。 The "Greynetic" and "Deluxe" hacks are probably good ones to start with, since they are so very simple. For OpenGL programs, "DangerBall" is a good example. "Greynetic" と "Deluxe" のハックは、非常にシンプルなので、おそらく手始めとしては良いものでしょう。 OpenGLのプログラムでは、"DangerBall "が良い例です。 ========================================================================== Requirements for inclusion with the XScreenSaver collection XScreenSaverコレクションに収録されるための条件 ========================================================================== If you come up with anything, send it to me! If it's good, I'd love to include it in the xscreensaver distribution. However, there are a few requirements for me to distribute it: もし何か思いついたら、私に送ってください。 もしそれが良いものであれば、xscreensaverの配布物に含めたいと思います。 ただし、配布するためにはいくつか条件があります。 - Write in portable ANSI C. No C++. No nonstandard libraries. - ポータブルなANSI Cで書く。C++は使わない。非標準のライブラリは使わない。 - Write a .man page describing all command-line options. - すべてのコマンドラインオプションを記述した .man ページを作成する。 - Write an .xml file describing the graphical configuration dialog box. - グラフィカルな設定ダイアログボックスを記述した .xml ファイルを作成します。 - Include a BSD-like copyright/license notice at the top of each source file (preferably, just use the one from "screenhack.h", and include your name and the current year). The GNU GPL is not compatible with the rest of XScreenSaver. - 各ソースファイルの先頭に BSD 風の著作権/ライセンス表示を入れてください (できれば "screenhack.h" のものをそのまま使い、あなたの名前と現在の年号を含めてください)。GNU GPL は XScreenSaver の他の部分と互換性がありません。 - No clocks! Just as time travellers always try to kill Hitler on their first trip, everyone seems to think that their first screen saver should be a clock of some kind. Nobody needs to know what time it is with such frequency. Fight The Tyranny Of The Clock. - 時計はダメ! タイムトラベラーが最初の旅行で必ずヒトラーを殺そうとするように、誰もが最初のスクリーンセーバーは何らかの時計であるべきだと考えているようです。 誰もそんな頻度で時刻を知る必要はないのです。 時計の支配と戦おう。 ========================================================================== The XScreenSaver API ========================================================================== - Start with #include "screenhack.h" - Define 2 global variables: - 2つのグローバル変数を定義: yoursavername_defaults -- Default values for the resources you use. 使用するリソースのデフォルト値 yoursavername_options -- The command-line options you accept. 受け入れるコマンドラインオプション。 - Define 5 functions: - 5つの関数を定義: yoursavername_init -- Return an object holding your global state. グローバルな状態を保持するオブジェクトを返します。 yoursavername_draw -- Draw a single frame, quickly. 1フレームを高速に描画。 yoursavername_free -- Free everything you've allocated. 割り当てたものをすべて解放する。 yoursavername_reshape -- Called when the window is resized. ウィンドウのサイズが変更されたときに呼び出されます。 yoursavername_event -- Called when a keyboard or mouse event happens. キーボードやマウスのイベントが発生したときに呼び出されます。 The "event" function will only be called when running in a window (not as a screen saver). "event"関数は、(スクリーンセーバーとしてではなく) ウィンドウ内で実行されているときのみ呼び出されます。 The "reshape" event will be called when the window size changes, or (as a screen saver) when the display size changes as a result of a RANDR event (e.g., plugging in a new monitor). "reshape"イベントは、ウィンドウサイズが変わったとき、あるいは (スクリーンセーバーとして) RANDR イベントの結果 (例えば、新しいモニタを接続したとき) ディスプレイサイズが変わったときに呼び出されます。 It's ok for both the "event" and "resize" functions to do nothing. "event"と"resize"の両機能は何もしなくても大丈夫です。 - All other functions should be static. - それ以外の機能は静的(static)であるべきです。 - The last line of the file should be XSCREENSAVER_MODULE ("YourSaverName", yoursavername) - ファイルの最後の行は、XSCREENSAVER_MODULE ("YourSaverName", yoursavername) でなければなりません。 - Finally, edit the Makefile to add a rule for your program. Just cut-and-paste one of the existing rules. - 最後に、Makefileを編集して、あなたのプログラム用のルールを追加します。既存のルールの一つをカットアンドペーストするだけです。 Your "draw" must not run for more than a fraction of a second withoutreturning. This means "don't call usleep()". Everything has to be a state machine. あなたの "draw "は、1秒の何分の一かを超えて実行され、返されることがあってはなりません。 つまり、「usleep()を呼び出してはいけない」。 全てがステートマシンでなければならない。 You may not store global state in global variables, or in function-local static variables. All of your runtime state must be encapsulated in the "state" object created by your "init" function. If you use global or static variables, your screen saver will not work properly on macOS. グローバル変数や関数ローカルの静的変数にグローバルな状態を格納することはできません。 すべての実行時状態は、"init"関数で作成した "state"オブジェクトにカプセル化する必要があります。 グローバル変数や静的変数を使用すると、スクリーンセーバーがmacOSで正しく動作しなくなります。 Do not call XSync() or XFlush(). If you think you need to do that, it probably means that you are you are relying on the speed of the graphics card for timing, which probably means that your "draw" function is taking too long. XSync()やXFlush()を呼び出さないようにしてください。 もし、そうする必要があると思うなら、それはおそらく、タイミングをグラフィックカードの速度に頼っているということであり、それはおそらく、「描画」関数があまりにも長くかかっているということです。 ========================================================================== The xlockmore API ========================================================================== Some of the display modes that come with xscreensaver were ported fromxlock, and so, for historical reasons, they follow a slightly differentprogramming convention. For newly-written Xlib programs, you'd bebetter off following the pattern used in hacks like "Deluxe" than inhacks like "Flag". The xlockmore ones are the ones that begin with "#ifdef STANDALONE" and #include "xlockmore.h". xscreensaverに付属するいくつかの表示モードはxlockから移植されたもので、歴史的な理由から、それらはわずかに異なるプログラミングの慣習に従っています。 新しく書かれたXlibプログラムでは、"Flag "のようなハックよりも、"Deluxe "のようなハックで使われるパターンに従った方が良いでしょう。 xlockmoreのものは、"#ifdef STANDALONE" と #include "xlockmore.h" で始まっているものです。 But, all OpenGL screen savers have to follow the xlockmore API. しかし、すべてのOpenGLスクリーンセーバーは、xlockmore APIに従わなければなりません。 The xlockmore API is similar to the XScreenSaver API, in that you define(roughly) the same set of functions, but the naming conventions areslightly different. Instead of "hackname_init", it's "init_hackname",and it should be preceeded with the pseudo-declaration ENTRYPOINT. xlockmore API は、XScreenSaver API と似ていて、(だいたい)同じような関数群を定義しますが、命名規則が少し異なります。 "hackname_init" の代わりに "init_hackname" で、その前に ENTRYPOINT という擬似宣言が必要です。 One annoying mis-feature of the xlockmore API is that it *requires* youto make use of global variables for two things: first, for each of yourcommand line options; and second, for an array that holds your globalstate objects. These are the only exceptions to the "never use globalvariables" rule. xlockmore APIの厄介な誤りの1つは、グローバル変数の使用を2つ要求されることです。1つはコマンドラインオプション、もう1つはglobalstateオブジェクトを保持するための配列です。 これらは、「グローバル変数を使用しない」というルールの唯一の例外です。 There are a few important differences between the original xlockmore API and XScreenSaver's implementation: オリジナルのxlockmore APIとXScreenSaverの実装には、いくつかの重要な違いがあります。 - XScreenSaver does not use refresh_hackname or change_hackname. - XScreenSaverは、refresh_hackname または change_hacknameを使用しません。 - XScreenSaver provides two additional hooks not present in xlockmore: reshape_hackname, and hackname_handle_event. These are respectively equivalent to hackname_reshape and hackname_event in the XScreenSaver API. - XScreenSaverは、xlockmoreにはない2つの追加フック: reshape_hacknameとhackname_handle_eventを提供します。これらはそれぞれ XScreenSaver API の hackname_reshape と hackname_event に相当するものです。 - Under Xlib, MI_CLEARWINDOW doesn't clear the window immediately. Instead, due to double buffering on macOS/iOS/Android, it waits until after init_hackname or draw_hackname returns before clearing. Make sure not to issue any Xlib drawing calls immediately after a call to MI_CLEARWINDOW, as these will be erased. To clear the window immediately, just use XClearWindow. - Xlibでは、MI_CLEARWINDOW はウィンドウをすぐにクリアしません。代わりに、macOS/iOS/Androidのダブルバッファリングのため、 init_hackname または draw_hackname が戻るまで待ってからクリアします。MI_CLEARWINDOWを呼び出した直後にXlibの描画コールを発行しないように注意してください。ウィンドウを直ちに消去するには、XClearWindowを使用してください。 ========================================================================== Programming Tips ========================================================================== - Your screen saver should look reasonable at 20-30 frames per second. That is, do not assume that your "draw" function will be called more than 20 times a second. Even if you return a smaller requested delay than that, you might not get it. Likewise, if your "draw" function takes longer than 1/20th of a second to run, your screen saver may be consuming too much CPU. - スクリーンセーバーは、1秒間に20~30フレームで合理的に見えるはずです。つまり、"draw"関数が1秒間に20回以上呼ばれることを想定しないでください。 それよりも小さい要求遅延を返したとしても、それが得られないかもしれません。 同様に、"draw"関数の実行に1/20秒以上かかる場合、スクリーンセーバーはCPUを過剰に消費している可能性があります。 - Don't make assumptions about the depth of the display, or whether it is colormapped. You must allocate all your colors explicitly: do not assume you can construct an RGB value and use that as a pixel value directly. In particular, you can't make assumptions about whether pixels are RGB, RGBA, ARGB, ABGR, or even whether they are 32, 24, 16 or 8 bits. Use the utility routines provided by "utils/colors.h" to simplify color allocation. - ディスプレイの深度や、カラーマップされているかどうかを仮定してはいけません。 すべての色を明示的に割り当てる必要があります。RGB値を構築し、それを直接ピクセル値として使用できると仮定してはいけません。 特に、ピクセルが RGB、RGBA、ARGB、ABGR、あるいは 32 ビット、24 ビット、16 ビット、8 ビットであるかどうかを仮定することはできません。 色の割り当てを簡単にするために、"utils/colors.h "で提供されるユーティリティルーチンを使用します。 - It is better to eliminate flicker by double-buffering to a Pixmap than by erasing and re-drawing objects. Do not use drawing tricks involving XOR. - オブジェクトを消して再描画するよりも、Pixmapにダブルバッファリングすることでフリッカを解消する方がよいでしょう。XORを含む描画トリックは使用しないでください。 - If you use double-buffering, have a resource to turn it off. (MacOS, iOS and Android have double-buffering built in, so you'd end up triple-buffering.) - ダブルバッファリングを使用する場合は、それをオフにするリソースを用意する。(MacOS、iOS、Androidはダブルバッファリングを内蔵しているので、結局トリプルバッファリングになってしまう) - Understand the differences between Pixmaps and XImages, and keep in mind which operations are happening in client memory and which are in server memory, and which cause latency due to server round-trips. Sometimes using the Shared Memory extension can be helpful, but probably not as often as you might think. - Pixmap と XImages の違いを理解し、どの操作がクライアントのメモリで行われ、どの操作がサーバのメモリで行われ、サーバのラウンドトリップによるレイテンシが発生するのかを覚えておいてください。Shared Memoryエクステンションを使用すると便利なことがありますが、おそらくあなたが思うほど頻繁には使用しないでしょう。 - On modern machines, OpenGL will always run faster than Xlib. It's also more portable. Consider writing in OpenGL whenever possible. - 最近のマシンでは、OpenGL は Xlib よりも常に高速に動作します。また、よりポータブルです。 可能な限り、OpenGLで書くことを検討してください。 - Free any memory you allocate. While screen savers under X11 have their memory freed automatically when their process is killed by the XScreenSaver daemon, under iOS and Android screen savers exist in long-lived processes where no such cleanup takes place. Consider Valgrind or gcc -fsanitize=leak to find memory leaks. - 割り当てたメモリはすべて解放してください。X11 のスクリーンセーバーは XScreenSaver デーモンによってプロセスが終了すると自動的にメモリが解放されますが、 iOS や Android ではスクリーンセーバーは長寿命のプロセスの中に存在し、そのようなクリーンアップが行われません。メモリリークを見つけるには、Valgrind や gcc -fsanitize=leak を検討してください。 - Again, don't use global variables. If you are doing your developent under X11, test your saver from the command line with the "-pair" argument. If that crashes, you're using global variables! - 繰り返しになりますが、グローバル変数は使わないでください。 X11 で開発をしている場合、コマンドラインから "-pair" 引数でセーバーをテストしてください。 これでクラッシュするようなら、グローバル変数を使っていることになります! ========================================================================== macOS, iOS and Android ========================================================================== Though XScreenSaver started its life as an X11 program, it also now runs on macOS, iOS and Android, due to a maniacal collection of compatibility shims. If you do your development on an X11 system, and follow the usual XScreenSaver APIs, you shouldn't need to do anything special for it to also work on macOS and on phones. XScreenSaverはX11のプログラムとして誕生しましたが、マニアックな互換性シムのコレクションによって、今ではmacOS、iOS、Androidでも動作するようになりました。 もしあなたがX11システム上で開発を行い、通常のXScreenSaverのAPIに従うならば、macOSや携帯電話でも動作させるために特別なことをする必要はないはずです。 See the READMEs in the OSX/ and android/ directories for instructions on compiling for those platforms. OSX/およびandroid/ディレクトリにあるREADMEを参照し、これらのプラットフォーム用にコンパイルする方法を説明します。 To check that an X11 saver will fit well on a mobile device, test it with -geometry 640x1136 and 640x960. That's a good first step, anyway. X11セーバーがモバイルデバイスにうまくフィットするかどうかを確認するには、-geometry 640x1136と640x960でテストしてください。 これはとにかく良い最初のステップです。 ========================================================================== Theory behind the ifdefs ========================================================================== HAVE_ macros indicate that an API is available. USE_ macros indicate that a feature is requested. Some notable ones: HAVE_GL The OpenGL 1.3 API is available, natively or through emulation. HAVE_GLES The OpenGLES 1.x API is available. HAVE_COCOA The Cocoa API is available, meaning compiling for macOS or iOS. HAVE_IPHONE Compiling for iOS, including iPad. HAVE_ANDROID Compiling for Android. HAVE_MOBILE iOS or Android, typically used for things related to rotation or screen size that apply to all phones and tablets. HAVE_JWXYZ Compiling on a system where the X11 API is emulated (macOS, iOS or Android). HAVE_JWZGLES Compiling on a system where the OpenGL 1.3 API is emulated (iOS, Android, possibly Linux). HAVE_GLSL Compiling against a library that supports the GL Shading Language. Note that using GLSL also requires a runtime check to see which version of GLSL the *running* system supports. HAVE_EGL OpenGL interfaces with native windows via EGL instead of GLX. ==========================================================================