#ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef USE_GNOME_APPLET #include #include #endif #include //GdkWindowのルートウィンドウを使うため。 #include #include #if (( __GLIBC_MINOR__ == 2 ) || ( __GLIBC_MINOR__ == 3)) && ( __GLIBC__ == 2 ) #include #define DO_AHO_HACK #endif #include "xim.h" #include "kkconv.h" #include "gtkdispatch.h" #include "code.xpm" #include "on.xpm" #include "off.xpm" //コード表 class CodeTable : WidgetIf{ public: CodeTable(); void clicked(GtkWidget *); void show(); private: void proc_click(int,int ); void init_window(); void update_labels(); GtkWidget *top_win; GtkWidget *buttons[16][8]; GtkWidget *labels[16][8]; GtkWidget *button_right; GtkWidget *button_left; GtkWidget *code_label; GtkWidget *cancel_button; int base_code; int page_index; }; static int jis_page_table[]={//0xe,半角カナは扱わない。 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, 0x70,0x71,0x72,0x73,0x74,0}; #define MAX_PAGE 76 // どこかにフォーカスが合っているかどうかを示すインジケータ // ツールバーの右端についている。 class Indicator{ public: Indicator(); GtkWidget *get_win(); void expose(); void draw_stat(); private: void updatePix(); GtkWidget *win; GdkPixmap *pix; GdkPixmap *on,*off; }; #define STAT_NONE 0 #define STAT_ON 1 #define STAT_OFF 2 struct DragState{ int wx,wy; int px,py; bool mIsOnDrag; }; class ToolBar : public WidgetIf{ public: ToolBar(KKConv *conv); void set_mode(int); void show(); void hide(); bool is_visible(); int get_mode(void); virtual void clicked(GtkWidget *); virtual void activate(GtkWidget *w,gpointer p); virtual void destroy(GtkWidget *w); virtual void button_press(GtkWidget *,int x,int y,int b); virtual void button_release(GtkWidget *,int x,int y,int b); virtual void motion(GtkWidget *,int x,int y,int b); private: void create(); void add_icon_to_button(GtkWidget *,char **xpm); void add_input_mode(GtkWidget *,char *,int mode); void init_mode_menu(); void init_buttons(); void trim_position(); GtkWidget *create_top_window(); GtkWidget *m_win; GtkWidget *m_hbox; GtkWidget *m_opt_menu; // button GtkWidget *kk_setting_button; GtkWidget *code_table_button; KKConv *mConv; DragState mDs; bool mIsVisible; int curmode; bool mIsInit; }; // なんかニュースなどを出す。 class IssueDialog : public WidgetIf{ public: IssueDialog(char *); void show(); virtual void clicked(GtkWidget *); private: GtkWidget *top; GtkWidget *button; }; //グローバル変数 static ToolBar *tool_bar; static Indicator *indicator; static CodeTable *code_table; static std::list issue_queue; class ui_impl { public: ui_impl(); void update_input_mode(int s); void acquire(XimIC *); void release(XimIC *); void change_menu(int s);//ユーザインターフェースによる変更 private: int m_stat; }; static ui_impl *user_if; void init_toolkit(int *argc,char ***argv) { #ifdef USE_GNOME_APPLET if (!( g_option_mask & OPT_TOOLBAR)) { applet_widget_init(PACKAGE, VERSION , 1,*argv,0,0,0); return ; } #endif gtk_init(argc,argv); } void init_status_indicator() { indicator = new Indicator(); } void init_ui(KKConv *conv) { tool_bar = new ToolBar(conv); code_table = new CodeTable(); user_if = new ui_impl(); indicator->draw_stat(); } /*glibc-2.2と組み合わせたgtkのバグ?をよけるためのコード glibcのmb系の関数にバグかgtkの使い間違いか 2001/3/16*/ bool isValidEUC(char *str) { #ifdef DO_AHO_HACK int res; size_t inlen,outlen; char buf[16]; char *obuf=buf; iconv_t ic = iconv_open("EUC-JP","EUC-JP"); inlen = strlen(str); outlen = 16; res = iconv(ic,&str,&inlen,&obuf,&outlen); iconv_close(ic); if ( res == -1 ){ return false; } #endif return true; } void show_issue(char *msg) { IssueDialog *is = new IssueDialog(msg); issue_queue.push_back(is); if (issue_queue.size() == 1) { is->show(); } } void ui_update_ic_stat() { indicator->draw_stat(); } void ui_update_input_mode(int s) { user_if->update_input_mode(s); } void ui_impl::update_input_mode(int s) { m_stat = s; tool_bar->set_mode(s); } void ui_impl::change_menu(int s) { XimIC *ic = XimIC::get_current_ic(); if (ic) { ic->changeMode(s); } } ui_impl::ui_impl() { m_stat = 0; } ToolBar::ToolBar(KKConv *conv) { mDs.mIsOnDrag = false; mIsInit = false; init_status_indicator(); mConv = conv; create(); mIsVisible = 1; } void ToolBar::create() { m_win = create_top_window(); gtk_window_set_title(GTK_WINDOW (m_win), PACKAGE); m_hbox = gtk_hbox_new(FALSE,0); init_mode_menu(); init_buttons(); //レイアウトする gtk_box_pack_start(GTK_BOX(m_hbox),m_opt_menu,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(m_hbox),kk_setting_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(m_hbox),code_table_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(m_hbox),indicator->get_win(),FALSE,FALSE,2); gtk_widget_set_events (m_win, GDK_BUTTON_PRESS_MASK| GDK_BUTTON_RELEASE_MASK| GDK_POINTER_MOTION_MASK); #ifdef USE_WITHDRAWN if ( g_option_mask & OPT_WITHDRAWN ){ XWMHints wmhints; gtk_widget_realize(m_win); wmhints.initial_state = WithdrawnState; wmhints.flags = StateHint; XSetWMHints(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(m_win->window), &wmhints); } #endif if (!(g_option_mask & OPT_TOOLBAR)) { #ifdef USE_GNOME_APPLET applet_widget_add (APPLET_WIDGET (m_win), m_hbox); #else gtk_container_add(GTK_CONTAINER(m_win),m_hbox); #endif } else { gtk_container_add(GTK_CONTAINER(m_win),m_hbox); } gtk_widget_show(m_hbox); gtk_widget_show(m_win); //絵を貼る、 char **p; p = getKKIcon(); if (p) { add_icon_to_button(kk_setting_button,p); } // コード表のボタン add_icon_to_button(code_table_button,code_xpm); add_widget_watch(m_win,WIDGET_DESTROY,this); add_widget_watch(m_win,WIDGET_BUTTON_PRESS,this); add_widget_watch(m_win,WIDGET_BUTTON_RELEASE,this); add_widget_watch(m_win,WIDGET_MOTION,this); indicator->expose(); mIsInit = true; } GtkWidget *ToolBar::create_top_window() { if ( g_option_mask & OPT_POPUP ){ return gtk_window_new(GTK_WINDOW_POPUP); } #ifdef USE_GNOME_APPLET if (!(g_option_mask & OPT_TOOLBAR)){ GtkWidget *top = applet_widget_new(PACKAGE); return top; } #endif return gtk_window_new(GTK_WINDOW_TOPLEVEL); } void ToolBar::show() { if (!mIsInit) { create(); } gtk_widget_show(m_win); mIsVisible = 1; } void ToolBar::hide() { mIsVisible = 0; if ( !mIsInit ){ return ; } gtk_widget_hide(m_win); } bool ToolBar::is_visible() { return mIsVisible; } int ToolBar::get_mode() { return curmode; } void ToolBar::set_mode(int s) { curmode = s; if (mIsInit) { gtk_option_menu_set_history(GTK_OPTION_MENU(m_opt_menu),s); gtk_widget_draw(m_opt_menu,NULL); } } void ToolBar::add_icon_to_button(GtkWidget *button,char **xpm) { GtkStyle *style; GdkBitmap *mask; GtkWidget *icon_win; GdkPixmap *icon; style = gtk_widget_get_style(m_win); icon = gdk_pixmap_create_from_xpm_d(m_win->window,&mask, &style->bg[GTK_STATE_NORMAL], (gchar **)xpm); icon_win = gtk_pixmap_new( icon, mask ); gtk_widget_show(icon_win); add_widget_watch(button,WIDGET_CLICK,this); gtk_container_add(GTK_CONTAINER(button),icon_win); } void ToolBar::add_input_mode(GtkWidget *menu,char *name,int mode) { GtkWidget *menu_item; menu_item = gtk_menu_item_new_with_label(name); gtk_menu_append(GTK_MENU (menu), menu_item); add_widget_watch(menu_item,WIDGET_ACTIVATE,this,(void *)mode); gtk_widget_show(menu_item); } //入力モードのメニューの初期化 void ToolBar::init_mode_menu() { GtkWidget *menu; menu = gtk_menu_new(); char *name; int i=0; while ((name = mConv->getModeName(i))) { add_input_mode(menu,name,i); i++; } m_opt_menu = gtk_option_menu_new(); gtk_option_menu_set_menu(GTK_OPTION_MENU(m_opt_menu),menu); gtk_widget_show(m_opt_menu); } void ToolBar::init_buttons() { //ボタン kk_setting_button = gtk_button_new(); gtk_widget_set_usize(GTK_WIDGET(kk_setting_button),28,36); gtk_widget_show(kk_setting_button); code_table_button = gtk_button_new(); gtk_widget_set_usize(GTK_WIDGET(code_table_button),28,36); gtk_widget_show(code_table_button); } void ToolBar::clicked(GtkWidget *w) { if ( w == kk_setting_button ){ onPushIcon(); }else if ( w == code_table_button ){ code_table->show(); } } void ToolBar::destroy(GtkWidget *w) { // 強制クローズ #ifdef USE_GNOME_APPLET if (!(g_option_mask & OPT_TOOLBAR)){ applet_widget_gtk_main_quit(); return ; } #endif gtk_main_quit(); } void ToolBar::activate(GtkWidget *w,gpointer p) { int pos = (int)p; gtk_widget_draw(w, NULL); user_if->change_menu(pos); } #ifdef USE_WITHDRAWN void ToolBar::button_press(GtkWidget *w,int x,int y,int b) { if ( !(g_option_mask & OPT_WITHDRAWN) ){ if ( b != 1 || w != m_win){ return ; } int wx,wy; gdk_window_get_root_origin(w->window,&wx,&wy); mDs.mIsOnDrag=true; mDs.px = x; mDs.py = y; mDs.wx = wx; mDs.wy = wy; gtk_grab_add(m_win); } } void ToolBar::button_release(GtkWidget *w,int x,int y,int b) { if ( !(g_option_mask & OPT_WITHDRAWN) ){ if ( b != 1 || w != m_win){ return ; } gtk_grab_remove(m_win); trim_position(); gdk_window_raise(m_win->window); mDs.mIsOnDrag=false; } } void ToolBar::motion(GtkWidget *w,int x,int y,int b) { if ( !(g_option_mask & OPT_WITHDRAWN) ){ if ( !mDs.mIsOnDrag ){ return ; } int dx,dy; dx = x - mDs.px; dy = y - mDs.py; mDs.wx += dx; mDs.wy += dy; gtk_widget_set_uposition(w,mDs.wx,mDs.wy); } } #else // USE_WITHDRAWN void ToolBar::button_press(GtkWidget *w,int x,int y,int b) { if ( b != 1 || w != m_win){ return ; } int wx,wy; gdk_window_get_root_origin(w->window,&wx,&wy); mDs.mIsOnDrag=true; mDs.px = x; mDs.py = y; mDs.wx = wx; mDs.wy = wy; gtk_grab_add(m_win); } void ToolBar::button_release(GtkWidget *w,int x,int y,int b) { if ( b != 1 || w != m_win){ return ; } gtk_grab_remove(m_win); trim_position(); gdk_window_raise(m_win->window); mDs.mIsOnDrag=false; } void ToolBar::motion(GtkWidget *w,int x,int y,int b) { if ( !mDs.mIsOnDrag ){ return ; } int dx,dy; dx = x - mDs.px; dy = y - mDs.py; mDs.wx += dx; mDs.wy += dy; gtk_widget_set_uposition(w,mDs.wx,mDs.wy); } #endif // USE_WITHDRAWN void ToolBar::trim_position() { int x,y,w,h,d; gdk_window_get_geometry(m_win->window,&x,&y,&w,&h,&d); gdk_window_get_root_origin(m_win->window,&x,&y); if ( x < 0 ){ x = 0; } if ( y < 0 ){ y = 0; } if ( x + w > scr_width ){ x = scr_width -w; } if ( y + h > scr_height ){ y = scr_height -h; } gtk_widget_set_uposition(m_win,x,y); } // why? this doesn't use WidgetIf gint indicator_expose(GtkWidget *w,GdkEventExpose *e) { indicator->expose(); return FALSE; } Indicator::Indicator() { win = gtk_drawing_area_new(); gtk_widget_set_usize(GTK_WIDGET(win),16,36); gtk_widget_show(win); gtk_signal_connect(GTK_OBJECT(win),"expose_event", (GtkSignalFunc)indicator_expose,NULL); GdkBitmap *mask; GtkStyle *style; style = gtk_widget_get_style(win); pix = gdk_pixmap_new(GDK_ROOT_PARENT(),16,36,-1); on = gdk_pixmap_create_from_xpm_d(GDK_ROOT_PARENT(),&mask, &style->bg[GTK_STATE_NORMAL], (gchar **)on_xpm); off = gdk_pixmap_create_from_xpm_d(GDK_ROOT_PARENT(),&mask, &style->bg[GTK_STATE_NORMAL], (gchar **)off_xpm); } GtkWidget *Indicator::get_win() { return win; } void Indicator::draw_stat() { char *m = "OFF"; if (XimIC::isAnyActive()){ m = "ON"; } updatePix(); } void Indicator::updatePix() { GdkPixmap *p; if (XimIC::isAnyActive()){ p = on; } else { p = off; } if (tool_bar->is_visible()) { gdk_draw_pixmap(pix, win->style->fg_gc[GTK_WIDGET_STATE (win)], p,0,0,0,0,12,32); expose(); } } void Indicator::expose() { gdk_draw_pixmap(win->window, win->style->fg_gc[GTK_WIDGET_STATE (win)], pix,0,0,0,0,12,32); } IssueDialog::IssueDialog(char *msg) { GtkWidget *l,*v; top = gtk_window_new(GTK_WINDOW_TOPLEVEL); v = gtk_vbox_new(FALSE,0); l = gtk_label_new(msg); button = gtk_button_new_with_label("OK"); gtk_box_pack_end(GTK_BOX(v),button,FALSE,FALSE,0); gtk_box_pack_start(GTK_BOX(v),l,TRUE,TRUE,0); gtk_container_add(GTK_CONTAINER(top),v); gtk_widget_show(l); gtk_widget_show(button); gtk_widget_show(v); add_widget_watch(button,WIDGET_CLICK,this); } void IssueDialog::show() { gtk_widget_show(top); } void IssueDialog::clicked(GtkWidget *w) { gtk_widget_destroy(top); gtk_widget_destroy(button); remove_widget_watch(button); issue_queue.pop_front();// XXX leak if ( issue_queue.size()){ (*issue_queue.begin())->show(); } delete this; } CodeTable::CodeTable() { page_index = 1; base_code = jis_page_table[page_index]; init_window(); update_labels(); } void CodeTable::init_window() { GtkWidget *table; //コード表のtoplevel Window top_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); table = gtk_table_new(13, 18, TRUE); gtk_container_add (GTK_CONTAINER (top_win), table); //コード表の文字があるボタン int x,y; for ( y = 0 ; y < 8 ; y++){ for ( x = 0 ; x < 16 ; x++){ buttons[x][y] = gtk_button_new(); labels[x][y] = gtk_label_new(" "); gtk_container_add(GTK_CONTAINER(buttons[x][y]),labels[x][y]); gtk_table_attach_defaults(GTK_TABLE(table), buttons[x][y],x+1,x+2,y+2,y+3); gtk_widget_show(labels[x][y]); gtk_widget_show(buttons[x][y]); add_widget_watch(buttons[x][y],WIDGET_CLICK,this); } } // インデックス GtkWidget *label; char buf[2]; buf[1] = 0; for ( x = 0 ; x < 16 ; x++){ buf[0] = ("0123456789ABCDEF")[x]; label = gtk_label_new(buf); gtk_table_attach_defaults(GTK_TABLE(table),label,x+1,x+2,1,2); gtk_widget_show(label); } for ( x = 0 ; x < 8 ; x++){ buf[0] = ("01234567")[x]; label = gtk_label_new(buf); gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,x+2,x+3); gtk_widget_show(label); } //いまの文字コードを書くラベル code_label = gtk_label_new(""); gtk_table_attach_defaults(GTK_TABLE(table),code_label,0,2,0,1); gtk_widget_show(code_label); button_right = gtk_button_new_with_label(">>"); button_left = gtk_button_new_with_label("<<"); cancel_button = gtk_button_new_with_label("閉じる"); gtk_table_attach_defaults(GTK_TABLE(table),button_left,2,4,11,12); gtk_table_attach_defaults(GTK_TABLE(table),button_right,5,7,11,12); gtk_table_attach_defaults(GTK_TABLE(table),cancel_button,8,10,11,12); gtk_widget_show(button_right); gtk_widget_show(button_left); gtk_widget_show(cancel_button); gtk_widget_show(table); add_widget_watch(button_left,WIDGET_CLICK,this); add_widget_watch(button_right,WIDGET_CLICK,this); add_widget_watch(cancel_button,WIDGET_CLICK,this); } void CodeTable::update_labels() { int x,y,c; unsigned char buf[5]; for ( y = 0 ; y < 8; y++){ for ( x = 0 ; x < 16; x++){ c = base_code *256 + x+y*16; buf[0] = ((c >> 8) & 255)|0x80; buf[1] = (c & 255)|0x80; buf[2] = 0; //字が定義してないところを指定すると再描画がされないようだ。 //0文字列をsetしてごまかしている。本当は変更時に今迄のを //消すべき? gtk_label_set(GTK_LABEL(labels[x][y]),(char *)&buf[2]); if ( isValidEUC((char *)buf)){ gtk_label_set(GTK_LABEL(labels[x][y]),(char *)buf); } } } sprintf((char *)buf,"%x00",base_code); gtk_label_set(GTK_LABEL(code_label),(char *)buf); } void CodeTable::show() { gtk_widget_show(top_win); } void CodeTable::clicked(GtkWidget *w) { if ( w == button_right ){ page_index ++; if ( page_index >MAX_PAGE){ page_index = 0; } } if ( w == button_left ){ page_index --; if ( page_index < 0 ){ page_index = MAX_PAGE; } } base_code = jis_page_table[page_index]; update_labels(); int x,y; for ( x = 0 ; x < 16 ; x ++){ for ( y = 0 ; y < 8 ; y ++){ if ( w == buttons[x][y]){ proc_click(x,y); } } } if ( w == cancel_button ){ gtk_widget_hide(top_win); } } void CodeTable::proc_click(int x,int y) { cchar c; jstring_t s; XimIC *ic = XimIC::get_current_ic(); if ( ic ){ c = x + y*16 +base_code*256; s.push_back(c); ic->extra_input(&s); //ここで強制イベントを付ける } } /* * Local variables: * c-indent-level: 4 * c-basic-offset: 4 * End: */