#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef USE_GNOME_APPLET
#include <gnome.h>
#include <applet-widget.h>
#endif
#include <gtk/gtk.h>
//GdkWindowのルートウィンドウを使うため。
#include <gdk/gdkx.h>
#include <stdlib.h>
#if (( __GLIBC_MINOR__ == 2 ) || ( __GLIBC_MINOR__ == 3)) && ( __GLIBC__ == 2 )
#include <iconv.h>
#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 <IssueDialog *> 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:
*/
syntax highlighted by Code2HTML, v. 0.9.1