最終目標は、このプログラムに手を入れることではなく、できるだけ早期にMotif上に移植する ことです。画面回り以外は、特別に何も書き換えなくても動作します。ある程度の細工は必要です が、まあソースに手を加える必要はまずありません。
しかし、ウィンドウ回りはそのままでは絶対に動かないので、大幅な変更が必要です。今回の移 植は、Xウィンドウという点でベースは同じだったので、本当はそれほど難しい仕事ではなかった のです。難しかったのは、プログラムのDirtyさだったのです。
全てのウィンドウがこんな感じで書かれていたので、移植に対する最初の問題は、この訳の分か らない膨大なリストをどう処理するかでした。
答は簡単なのです。画面の生成部分は「廃棄処分」にしました。残ったのは、関数名と大域変数 くらいでした。ちゃんとした仕様書がなかったので、各関数の機能だけを理解し、ウィンドウのデ ザインはMotifの豊富なカスタマイズ機能をフルに発揮し、Cプログラムをゴチャゴチャ書くので はなく、可能な限りXのリソース機能を使いました。要するに、Xが持っているデータベース機能 を存分に利用し、可能な限りさぼりました。
困ったことは、元のプログラムが、何事もさぼらず、訳の分からぬことを書いているので、それ を外す作業、そして正しく外せたかの確認作業が中心でした。
リスト13−2 修正版(Motif版) |
1 void rgb_info_init( ) 2 { 3 int i, line = 0; 4 Dimension width, height; 5 char name[80]; 6 Arg args[10]; 7 Widget basepanel, subpanel, board, rowcol; 8 Widget canvas, frame, draw; 9 static ButtonData data[] = { 10 { NULL, rgb_info_before_plane, }, 11 { NULL, rgb_info_next_plane, }, 12 { &rgb_info_quit_button, (XtCallbackProc)rgb_info_quit, }, 13 }; 14 15 rgb_info_frame = CreateShellDefaultDecorations( "rgb_info", APP_CLASS_NAME ); 16 basepanel = MakeRowColumn( "basepanel", rgb_info_frame ); 17 18 board = MakeBulletinBoard( "board", basepanel ); 19 image_set = MakeDrawingArea( "image", board ); 20 21 subpanel = MakeRowColumn( "subpanel", basepanel ); 22 23 sprintf( name, "line%d", ++line ); 24 rowcol = MakeRowColumn( name, subpanel ); 25 26 MakeLabelGadget( "label", rowcol ); 27 rgb_info_disp1 = MakeLabel( "label1", rowcol ); 28 rgb_info_disp2 = MakeLabel( "label2", rowcol ); 29 30 sprintf( name, "line%d", ++line ); 31 rowcol = MakeRowColumn( name, subpanel ); 32 33 MakeLabelGadget( "label", rowcol ); 34 for ( i = 0; i < XtNumber( rgb_info_disp3 ); ++i ) { 35 sprintf( name, "label%d", i + 1 ); 36 rgb_info_disp3[i] = MakeLabel( name, rowcol ); 37 } 38 39 sprintf( name, "line%d", ++line ); 40 rowcol = MakeRowColumn( name, subpanel ); 41 42 MakeLabelGadget( "label", rowcol ); 43 for ( i = 0; i < XtNumber( rgb_info_disp3 ); ++i ) { 44 sprintf( name, "label%d", i + 1 ); 45 rgb_info_disp4[i] = MakeLabel( name, rowcol ); 46 } 47 48 sprintf( name, "line%d", ++line ); 49 rowcol = MakeRowColumn( name, subpanel ); 50 51 rgb_info_plane = MakeLabel( "label1", rowcol ); 52 MakeLabel( "label2", rowcol ); 53 rgb_info_num = MakeLabel( "label3", rowcol ); 54 55 sprintf( name, "line%d", ++line ); 56 rowcol = MakeRowColumn( name, subpanel ); 57 58 canvas = XtCreateManagedWidget( "canvas", xmFormWidgetClass, rowcol, NULL, 0 ); 59 frame = XtCreateManagedWidget( "frame", xmFrameWidgetClass, canvas, NULL, 0 ); 60 draw = XtCreateManagedWidget( "draw", xmDrawingAreaWidgetClass, frame, NULL, 0 ); 61 rgb_info_scroll = MakeScrollBar( "scroll", rowcol ); 62 63 rgb_info_canvas = alloc_canvas( canvas, frame, draw, rgb_info_scroll, NULL ); 64 65 XtAddCallback( rgb_info_scroll, XmNvalueChangedCallback, scrolled, NULL ); 66 XtAddCallback( rgb_info_scroll, XmNincrementCallback, scrolled, NULL ); 67 XtAddCallback( rgb_info_scroll, XmNdecrementCallback, scrolled, NULL ); 68 XtAddCallback( rgb_info_scroll, XmNpageIncrementCallback, scrolled, NULL ); 69 XtAddCallback( rgb_info_scroll, XmNpageDecrementCallback, scrolled, NULL ); 70 XtAddCallback( rgb_info_scroll, XmNtoTopCallback, scrolled, NULL ); 71 XtAddCallback( rgb_info_scroll, XmNtoBottomCallback, scrolled, NULL ); 72 XtAddCallback( rgb_info_scroll, XmNdragCallback, scrolled, NULL ); 73 74 MakeFormPushButton( "form", subpanel, data, XtNumber( data ) ); 75 76 XtRealizeWidget( rgb_info_frame ); 77 78 rgb_info_color = pixelcolortable; 79 i = 0; 80 XtSetArg( args[i], XmNwidth, &width ); ++i; 81 XtSetArg( args[i], XmNheight, &height ); ++i; 82 XtGetValues( my_canvas_paint_window( rgb_info_canvas ), args, i ); 83 rgb_info_pixmap = XCreatePixmap( motif_display, my_canvas_paint_winid( rgb_info_canvas ), 84 width, height, DefaultDepth( motif_display, 0 ) ); 85 rgb_info_xwin = (Xv_Window)my_canvas_paint_window( rgb_info_canvas ); 86 rgb_info_gc = XCreateGC( motif_display, my_canvas_paint_winid( rgb_info_canvas ), 0, 0 ); 87 XSetFont( motif_display, rgb_info_gc, XLoadFont( motif_display, "fixed" ) ); 88 XSetForeground( motif_display, rgb_info_gc, 0xffffffff ); 89 XSetBackground( motif_display, rgb_info_gc, 0 ); 90 backing_store_canvas( rgb_info_canvas ); 91 92 make_colorbox( image_set ); 93 } |
意味不明の計算と、マクロになっていた多数の文字列に相当する部分は、リソースファイルとし て実現しました。このファイルは、
rgb_info*.line1.orientation: HORIZONTAL rgb_info*.line1.label.labelString: 色のような行がいっぱい並んだテキストファイルです。":"の左側で「どのデータ」かを指定し、右 側に「その値」を書きます。1行目のように、予約語や数値を書いている行もあります。2行目の ように左側がlabelStringのところは、右側には文字列を指定します。この文字列は、ウィンドウ 上の指定位置にそのまま表示されます。漢字で書けば、そのまま漢字で表示されます。
このファイルはテキストファイルなので、エディタで簡単に修正できます。line1なんていう名 前(正確にはウィジェットインスタンス名)を使わず、もっと意味のあるものにしたかったのです が、移植なので、プログラムの意味を理解して作業をしている訳ではなし、とりあえず識別できる ようにと、こんな安直な名前にしておきました。まあ、今後の開発をする人が正式の名前にしてく れるといいのですが、さてどうなるのでしょう。
関数化できる部分をもっと関数化するとか、いっそのこと全面的に書き換えてしまうとかすれば もっとすっきりします。でも、このソフト、表示以外の部分にもいっぱい病根があったので、ユー ザインターフェイスだけ良くしてもアンバランスになってしまうので、このレベルの書き換えで止 めておきました。何事も「バランス」が重要ですからね。
リスト中の、属性名が STRING(S) に続く属性値として文字列が一杯あるソフトでしたので、複 数言語に対応するとなると、オリジナルのままを踏襲すると、日本語版は日本語のヘッダーファイ ルを、英語版は英語のヘッダーファイルをインクルードした状態でコンパイルし、それぞれ別のも のとして実行形式を作らねばならなかったのです。
ところが、Motifへの移植に際して、きちんとサボったため、ソースについての詳しい知識がまっ たく無くても簡単に変更できるように変身したのです。
ウィンドウ上に表示される日本語文字列に対応するリソースファイルの漢字部分
rgb_info*.line1.label.labelString: 色を
rgb_info*.line1.label.labelString: Colorのように書き換えてしまえば、海外でも使えるソフトになってしまいます。じつに簡単なんです。 文字列長が変化しても、ある程度はMotifが自動調整してくれます。
このファイルについてのドキュメントは書きましたが、英語化の説明は全然しなかったのです。 しかし、お客さま自身でちょこちょこっと英語に書き換えて英語化のテストをしていました。
これも、「廃棄処分」と「さぼり」の効果ですが、お客の側で簡単に英語化できるようなものに してしまったのは「経営上の誤りか」と悩んでおります。