/* * This file part of StarDict - A international dictionary for GNOME. * http://stardict.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #ifdef _WIN32 # include #endif #include "stardict.h" #include "desktop.hpp" #include "conf.h" #include "utils.h" #include "iskeyspressed.hpp" #include "floatwin.h" FloatWin::FloatWin() { timeout = 0; now_window_width = 0; now_window_height = 0; button_box_once_shown = false; ismoving = false; menu = NULL; } void FloatWin::End() { if (timeout) g_source_remove(timeout); if (menu) gtk_widget_destroy(menu); if (FloatWindow) gtk_widget_destroy(FloatWindow); } void FloatWin::Create() { FloatWindow = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_set_events(FloatWindow, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK); g_signal_connect (G_OBJECT (FloatWindow), "button_press_event", G_CALLBACK (vButtonPressCallback), this); g_signal_connect (G_OBJECT (FloatWindow), "button_release_event", G_CALLBACK (vButtonReleaseCallback), this); g_signal_connect (G_OBJECT (FloatWindow), "motion_notify_event", G_CALLBACK (vMotionNotifyCallback), this); g_signal_connect (G_OBJECT (FloatWindow), "enter_notify_event", G_CALLBACK (vEnterNotifyCallback), this); g_signal_connect (G_OBJECT (FloatWindow), "leave_notify_event", G_CALLBACK (vLeaveNotifyCallback), this); int transparent=conf->get_int_at("floating_window/transparent"); if (transparent != 0) gtk_window_set_opacity(GTK_WINDOW(FloatWindow), (100-transparent)/100.0); GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(FloatWindow)); gint screen_width = gdk_screen_get_width(screen); gint screen_height = gdk_screen_get_height(screen); int max_window_width= conf->get_int_at("floating_window/max_window_width"); int max_window_height= conf->get_int_at("floating_window/max_window_height"); if (max_window_width < MIN_MAX_FLOATWIN_WIDTH || max_window_width > screen_width) conf->set_int_at("floating_window/max_window_width", DEFAULT_MAX_FLOATWIN_WIDTH); if (max_window_height < MIN_MAX_FLOATWIN_HEIGHT || max_window_height > screen_height) conf->set_int_at("floating_window/max_window_height", DEFAULT_MAX_FLOATWIN_HEIGHT); int lock_x= conf->get_int_at("floating_window/lock_x"); int lock_y= conf->get_int_at("floating_window/lock_y"); max_window_width= conf->get_int_at("floating_window/max_window_width"); max_window_height= conf->get_int_at("floating_window/max_window_height"); if (lock_x<0) lock_x=0; else if (lock_x > (screen_width - max_window_width)) lock_x = screen_width - max_window_width; if (lock_y<0) lock_y=0; else if (lock_y > (screen_height - max_window_height)) lock_y = screen_height - max_window_height; gtk_window_move(GTK_WINDOW(FloatWindow),lock_x,lock_y); GtkWidget *frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_OUT); gtk_container_add(GTK_CONTAINER(FloatWindow),frame); GtkWidget *vbox; vbox = gtk_vbox_new(false,0); gtk_container_set_border_width (GTK_CONTAINER (vbox), FLOATWIN_BORDER_WIDTH); gtk_container_add(GTK_CONTAINER(frame),vbox); button_hbox = gtk_hbox_new(false,0); gtk_box_pack_start(GTK_BOX(vbox),button_hbox,false,false,0); GtkWidget *button; button= gtk_button_new(); gtk_container_add(GTK_CONTAINER(button),gtk_image_new_from_stock(GTK_STOCK_FIND,GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_query_click), this); g_signal_connect(G_OBJECT(button),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_start(GTK_BOX(button_hbox),button,false,false,0); gtk_widget_set_tooltip_text(button,_("Query in the main window")); button= gtk_button_new(); gtk_container_add(GTK_CONTAINER(button),gtk_image_new_from_stock(GTK_STOCK_SAVE,GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_save_click), this); g_signal_connect(G_OBJECT(button),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_start(GTK_BOX(button_hbox),button,false,false,0); gtk_widget_set_tooltip_text(button,_("Save to file")); PronounceWordButton= gtk_button_new(); gtk_container_add(GTK_CONTAINER(PronounceWordButton),gtk_image_new_from_stock(GTK_STOCK_EXECUTE,GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (PronounceWordButton), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(PronounceWordButton),"clicked", G_CALLBACK(on_play_click), this); g_signal_connect(G_OBJECT(PronounceWordButton),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_start(GTK_BOX(button_hbox),PronounceWordButton,false,false,0); gtk_widget_set_tooltip_text(PronounceWordButton,_("Pronounce the word")); gtk_widget_set_sensitive(PronounceWordButton, false); StopButton= gtk_button_new(); gtk_container_add(GTK_CONTAINER(StopButton),gtk_image_new_from_stock(GTK_STOCK_STOP,GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (StopButton), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(StopButton),"clicked", G_CALLBACK(on_stop_click), this); g_signal_connect(G_OBJECT(StopButton),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_start(GTK_BOX(button_hbox),StopButton,false,false,0); gtk_widget_set_tooltip_text(StopButton, _("Stop selection-scanning")); gtk_widget_set_sensitive(gpAppFrame->oFloatWin.StopButton, conf->get_bool_at("dictionary/scan_selection")); #ifndef CONFIG_GPE button= gtk_button_new(); gtk_container_add(GTK_CONTAINER(button),gtk_image_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_help_click), this); g_signal_connect(G_OBJECT(button),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_start(GTK_BOX(button_hbox),button,false,false,0); gtk_widget_set_tooltip_text(button,_("Help")); button= gtk_button_new(); gtk_container_add(GTK_CONTAINER(button),gtk_image_new_from_stock(GTK_STOCK_QUIT,GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_quit_click), this); g_signal_connect(G_OBJECT(button),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_start(GTK_BOX(button_hbox),button,false,false,0); gtk_widget_set_tooltip_text(button,_("Quit")); #endif button = gtk_button_new(); if (conf->get_bool_at("floating_window/lock")) lock_image= gtk_image_new_from_stock(GTK_STOCK_GOTO_LAST,GTK_ICON_SIZE_MENU); else lock_image= gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD,GTK_ICON_SIZE_MENU); gtk_container_add(GTK_CONTAINER(button),lock_image); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(vLockCallback),this); g_signal_connect(G_OBJECT(button),"enter_notify_event", G_CALLBACK(stardict_on_enter_notify), NULL); gtk_box_pack_end(GTK_BOX(button_hbox),button,false,false,0); gtk_widget_set_tooltip_text(button,_("Lock floating window")); view.reset(new ArticleView(GTK_BOX(vbox), true)); gtk_widget_show_all(frame); gtk_widget_hide(button_hbox); //show all will show hbox's children,now hide hbox only. if (conf->get_bool_at("floating_window/use_custom_bg")) { GdkColor color; color.red = conf->get_int_at("floating_window/bg_red"); color.green = conf->get_int_at("floating_window/bg_green"); color.blue = conf->get_int_at("floating_window/bg_blue"); set_bg(&color); } } void FloatWin::set_bg(const GdkColor *color) { gtk_widget_modify_bg(FloatWindow, GTK_STATE_NORMAL, color); view->modify_bg(GTK_STATE_NORMAL, color); } void FloatWin::ShowText(gchar ***Word, gchar ****WordData, const gchar *sOriginWord) { QueryingWord = sOriginWord; found_result = FLOAT_WIN_FOUND; view->begin_update(); view->clear(); std::string mark = ""; gchar *m_str = g_markup_escape_text(sOriginWord, -1); mark += m_str; g_free(m_str); mark += ""; view->append_pango_text(mark.c_str()); int j,k; for (size_t i=0; iscan_dictmask.size(); i++) { if (Word[i]) { view->AppendNewline(); view->SetDictIndex(gpAppFrame->scan_dictmask[i]); if (gpAppFrame->scan_dictmask[i].type == InstantDictType_LOCAL) view->AppendHeader(gpAppFrame->oLibs.dict_name(gpAppFrame->scan_dictmask[i].index).c_str()); else if (gpAppFrame->scan_dictmask[i].type == InstantDictType_VIRTUAL) view->AppendHeader(gpAppFrame->oStarDictPlugins->VirtualDictPlugins.dict_name(gpAppFrame->scan_dictmask[i].index)); else if (gpAppFrame->scan_dictmask[i].type == InstantDictType_NET) view->AppendHeader(gpAppFrame->oStarDictPlugins->NetDictPlugins.dict_name(gpAppFrame->scan_dictmask[i].index)); j=0; do { if (j==0) { if (strcmp(Word[i][j], sOriginWord)) view->AppendWord(Word[i][j]); } else { view->AppendNewline(); view->AppendWord(Word[i][j]); } view->AppendData(WordData[i][j][0], Word[i][j], sOriginWord); k=1; while (WordData[i][j][k]) { view->AppendNewline(); view->AppendDataSeparate(); view->AppendData(WordData[i][j][k], Word[i][j], sOriginWord); k++; } j++; } while (Word[i][j]); } } view->end_update(); gboolean pronounced = false; readwordtype = gpAppFrame->oReadWord.canRead(sOriginWord); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == sOriginWord) pronounced = true; else PronounceWord = sOriginWord; } else { for (size_t i=0;i< gpAppFrame->scan_dictmask.size(); i++) { if (Word[i] && strcmp(Word[i][0], sOriginWord)) { readwordtype = gpAppFrame->oReadWord.canRead(Word[i][0]); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == Word[i][0]) pronounced = true; else PronounceWord = Word[i][0]; } break; } } } gtk_widget_set_sensitive(PronounceWordButton, readwordtype != READWORD_CANNOT); Popup(true); if ((readwordtype != READWORD_CANNOT) && (!pronounced) && conf->get_bool_at("floating_window/pronounce_when_popup")) gpAppFrame->oReadWord.read(PronounceWord.c_str(), readwordtype); } void FloatWin::ShowText(NetDictResponse *resp) { view->begin_update(); bool do_append; if (found_result == FLOAT_WIN_FOUND || found_result == FLOAT_WIN_NET_FOUND) { do_append = true; view->goto_end(); } else { do_append = false; view->clear(); view->goto_begin(); } if (resp->data) { found_result = FLOAT_WIN_NET_FOUND; if (!do_append) { std::string mark = ""; gchar *m_str = g_markup_escape_text(resp->word, -1); mark += m_str; g_free(m_str); mark += ""; view->append_pango_text(mark.c_str()); } InstantDictIndex dict_index; dict_index.type = InstantDictType_UNKNOWN; view->SetDictIndex(dict_index); view->AppendNewline(); view->AppendHeader(resp->bookname); view->AppendWord(resp->word); view->AppendData(resp->data, resp->word, resp->word); } else { if (do_append) { view->end_update(); return; } found_result = FLOAT_WIN_NET_NOT_FOUND; if (!conf->get_bool_at("floating_window/show_if_not_found")) { view->end_update(); return; } gchar *text; text = g_markup_printf_escaped("%s\n%s", resp->word, _("")); view->set_pango_text(text); g_free(text); } view->end_update(); gboolean pronounced = false; readwordtype = gpAppFrame->oReadWord.canRead(resp->word); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == resp->word) pronounced = true; else PronounceWord = resp->word; } gtk_widget_set_sensitive(PronounceWordButton, readwordtype != READWORD_CANNOT); Popup(true); if ((readwordtype != READWORD_CANNOT) && (!pronounced) && conf->get_bool_at("floating_window/pronounce_when_popup")) gpAppFrame->oReadWord.read(PronounceWord.c_str(), readwordtype); } void FloatWin::ShowText(const struct STARDICT::LookupResponse::DictResponse *dict_response) { view->begin_update(); bool do_append; if (found_result == FLOAT_WIN_FOUND || found_result == FLOAT_WIN_NET_FOUND) { do_append = true; view->goto_end(); } else { do_append = false; view->clear(); view->goto_begin(); } if (dict_response->dict_result_list.empty()) { if (do_append) { view->end_update(); return; } found_result = FLOAT_WIN_NET_NOT_FOUND; if (!conf->get_bool_at("floating_window/show_if_not_found")) { view->end_update(); return; } gchar *text; text = g_markup_printf_escaped("%s\n%s", dict_response->oword, _("")); view->set_pango_text(text); g_free(text); } else { found_result = FLOAT_WIN_NET_FOUND; if (!do_append) { std::string mark = ""; gchar *m_str = g_markup_escape_text(dict_response->oword, -1); mark += m_str; g_free(m_str); mark += ""; view->append_pango_text(mark.c_str()); } InstantDictIndex dict_index; dict_index.type = InstantDictType_UNKNOWN; view->SetDictIndex(dict_index); for (std::list::const_iterator i = dict_response->dict_result_list.begin(); i != dict_response->dict_result_list.end(); ++i) { view->AppendNewline(); view->AppendHeader((*i)->bookname); for (std::list::iterator j = (*i)->word_result_list.begin(); j != (*i)->word_result_list.end(); ++j) { if (j == (*i)->word_result_list.begin()) { if (strcmp((*j)->word, dict_response->oword)) { view->AppendWord((*j)->word); } } else { view->AppendNewline(); view->AppendWord((*j)->word); } std::list::iterator k = (*j)->datalist.begin(); view->AppendData(*k, (*j)->word, dict_response->oword); for (++k; k != (*j)->datalist.end(); ++k) { view->AppendNewline(); view->AppendDataSeparate(); view->AppendData(*k, (*j)->word, dict_response->oword); } } } } view->end_update(); gboolean pronounced = false; readwordtype = gpAppFrame->oReadWord.canRead(dict_response->oword); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == dict_response->oword) pronounced = true; else PronounceWord = dict_response->oword; } else { for (std::list::const_iterator i = dict_response->dict_result_list.begin(); i != dict_response->dict_result_list.end(); ++i) { std::list::iterator j = (*i)->word_result_list.begin(); if (j != (*i)->word_result_list.end() && strcmp((*j)->word, dict_response->oword)) { readwordtype = gpAppFrame->oReadWord.canRead((*j)->word); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == (*j)->word) pronounced = true; else PronounceWord = (*j)->word; } break; } } } gtk_widget_set_sensitive(PronounceWordButton, readwordtype != READWORD_CANNOT); Popup(true); if ((readwordtype != READWORD_CANNOT) && (!pronounced) && conf->get_bool_at("floating_window/pronounce_when_popup")) gpAppFrame->oReadWord.read(PronounceWord.c_str(), readwordtype); } void FloatWin::ShowText(gchar ****ppppWord, gchar *****pppppWordData, const gchar ** ppOriginWord, gint count, const gchar *sOriginWord) { QueryingWord = sOriginWord; found_result = FLOAT_WIN_FUZZY_FOUND; view->begin_update(); view->clear(); view->goto_begin(); std::string mark; gchar *m_str; mark = _("Fuzzy query"); mark += " "; m_str = g_markup_escape_text(sOriginWord,-1); mark += m_str; g_free(m_str); mark += " "; mark += _("has succeeded.\n"); if (count ==1) mark+= _("Found 1 word:\n"); else { m_str=g_strdup_printf(_("Found %d words:\n"),count); mark += m_str; g_free(m_str); } int j; for (j=0; j"; m_str = g_markup_escape_text(ppOriginWord[j], -1); mark += m_str; g_free(m_str); mark += " "; } mark += ""; m_str = g_markup_escape_text(ppOriginWord[count-1],-1); mark += m_str; g_free(m_str); mark += ""; view->append_pango_text(mark.c_str()); int m,n; for (j=0; j"; m_str = g_markup_escape_text(ppOriginWord[j],-1); mark += m_str; g_free(m_str); mark += ""; view->append_pango_text(mark.c_str()); for (size_t i=0; iscan_dictmask.size(); i++) { if (ppppWord[j][i]) { view->AppendNewline(); view->SetDictIndex(gpAppFrame->scan_dictmask[i]); if (gpAppFrame->scan_dictmask[i].type == InstantDictType_LOCAL) view->AppendHeader(gpAppFrame->oLibs.dict_name(gpAppFrame->scan_dictmask[i].index).c_str()); else if (gpAppFrame->scan_dictmask[i].type == InstantDictType_VIRTUAL) view->AppendHeader(gpAppFrame->oStarDictPlugins->VirtualDictPlugins.dict_name(gpAppFrame->scan_dictmask[i].index)); else if (gpAppFrame->scan_dictmask[i].type == InstantDictType_NET) view->AppendHeader(gpAppFrame->oStarDictPlugins->NetDictPlugins.dict_name(gpAppFrame->scan_dictmask[i].index)); m=0; do { if (m==0) { if (strcmp(ppppWord[j][i][m], ppOriginWord[j])) view->AppendWord(ppppWord[j][i][m]); } else { view->AppendNewline(); view->AppendWord(ppppWord[j][i][m]); } view->AppendData(pppppWordData[j][i][m][0], ppppWord[j][i][m], sOriginWord); n=1; while (pppppWordData[j][i][m][n]) { view->AppendNewline(); view->AppendDataSeparate(); view->AppendData(pppppWordData[j][i][m][n], ppppWord[j][i][m], sOriginWord); n++; } m++; } while (ppppWord[j][i][m]); } } } view->end_update(); readwordtype = gpAppFrame->oReadWord.canRead(sOriginWord); if (readwordtype != READWORD_CANNOT) PronounceWord = sOriginWord; gtk_widget_set_sensitive(PronounceWordButton, readwordtype != READWORD_CANNOT); Popup(false); /*bool pronounce_when_popup= conf->get_bool_at("floating_window/pronounce_when_popup"); if (canRead && pronounce_when_popup) gpAppFrame->oReadWord.read(PronounceWord.c_str());*/ } void FloatWin::ShowNotFound(const char* sWord,const char* sReason, gboolean fuzzy) { QueryingWord = sWord; if (fuzzy) found_result = FLOAT_WIN_FUZZY_NOT_FOUND; else found_result = FLOAT_WIN_NOT_FOUND; bool enable_netdict = conf->get_bool_at("network/enable_netdict"); if (enable_netdict) return; bool have_netdict = false; for (size_t iLib=0; iLib< gpAppFrame->scan_dictmask.size(); iLib++) { if (gpAppFrame->scan_dictmask[iLib].type == InstantDictType_NET) { have_netdict = true; break; } } if (have_netdict) return; if (!conf->get_bool_at("floating_window/show_if_not_found")) return; gchar *text; text = g_markup_printf_escaped("%s\n%s", sWord, sReason); view->set_pango_text(text); g_free(text); gboolean pronounced = false; readwordtype = gpAppFrame->oReadWord.canRead(sWord); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == sWord) pronounced = true; else PronounceWord = sWord; } gtk_widget_set_sensitive(PronounceWordButton, readwordtype != READWORD_CANNOT); if (fuzzy) Popup(false); else Popup(true); if ((readwordtype != READWORD_CANNOT) && (!pronounced) && conf->get_bool_at("floating_window/pronounce_when_popup")) gpAppFrame->oReadWord.read(PronounceWord.c_str(), readwordtype); } void FloatWin::ShowPangoTips(const char *sWord, const char *text) { QueryingWord = sWord; found_result = FLOAT_WIN_FOUND; view->set_pango_text(text); gboolean pronounced = false; readwordtype = gpAppFrame->oReadWord.canRead(sWord); if (readwordtype != READWORD_CANNOT) { if (PronounceWord == sWord) pronounced = true; else PronounceWord = sWord; } gtk_widget_set_sensitive(PronounceWordButton, readwordtype != READWORD_CANNOT); Popup(true); } void FloatWin::Popup(gboolean updatePosition) { ismoving = true; GtkRequisition requisition; gtk_widget_size_request(view->widget(), &requisition); int max_window_width=conf->get_int_at("floating_window/max_window_width"); if (requisition.width > max_window_width) { // it is not really max window width setting. gtk_widget_set_size_request(view->widget(), max_window_width, -1); gtk_label_set_line_wrap(GTK_LABEL(view->widget()), true); gtk_widget_size_request(view->widget(), &requisition); //update requisition } gint window_width,window_height; window_width = 2*(FLOATWIN_BORDER_WIDTH+2) + requisition.width; // 2 is the frame 's width.or get it by gtk function? i am lazy,hoho int max_window_height= conf->get_int_at("floating_window/max_window_height"); if (requisition.height > max_window_height) { static gint vscrollbar_width = 0; if (!vscrollbar_width) { if (view->vscroll_bar()) { GtkRequisition vscrollbar_requisition; gtk_widget_size_request(view->vscroll_bar(), &vscrollbar_requisition); vscrollbar_width = vscrollbar_requisition.width; vscrollbar_width += view->scroll_space(); } } view->set_size(requisition.width + vscrollbar_width, max_window_height); window_height = 2*(FLOATWIN_BORDER_WIDTH+2) + max_window_height; window_width += vscrollbar_width; } else { view->set_size(requisition.width, requisition.height); window_height = 2*(FLOATWIN_BORDER_WIDTH+2) + requisition.height; } gboolean button_hbox_visible = GTK_WIDGET_VISIBLE(button_hbox); if (button_hbox_visible) { window_height += (button_hbox->allocation).height; if (window_width < (button_hbox->allocation).width + 2*(FLOATWIN_BORDER_WIDTH+2)) window_width = (button_hbox->allocation).width + 2*(FLOATWIN_BORDER_WIDTH+2); } if (conf->get_bool_at("floating_window/lock")) { gtk_window_resize(GTK_WINDOW(FloatWindow),window_width,window_height); now_window_width = window_width; now_window_height = window_height; // need to make window 's resize relate to other corner? Show(); } else { gint iCurrentX,iCurrentY; GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(FloatWindow)); if ((!GTK_WIDGET_VISIBLE(FloatWindow)) || updatePosition) { button_box_once_shown = false; GdkDisplay *display = gdk_screen_get_display(screen); gdk_display_get_pointer(display, NULL, &iCurrentX, &iCurrentY, NULL); bool pressed = gpAppFrame->unlock_keys->is_pressed(); if (pressed) { popup_pointer_x = iCurrentX; popup_pointer_y = iCurrentY; } else { // popup by middle click on the notification area icon, //so never hiden the floating window even mouse didn't moved as in FloatWin::vTimeOutCallback(). popup_pointer_x = -1; popup_pointer_y = -1; } iCurrentX += FLOATWIN_OFFSET_X; iCurrentY += FLOATWIN_OFFSET_Y; } else { gtk_window_get_position(GTK_WINDOW(FloatWindow),&iCurrentX,&iCurrentY); } gint screen_width = gdk_screen_get_width(screen); gint screen_height = gdk_screen_get_height(screen); if (iCurrentX + window_width > screen_width) iCurrentX = screen_width - window_width; if (iCurrentY + window_height > screen_height) iCurrentY = screen_height - window_height; // don't use gdk_window_resize,it make the window can't be smaller latter! /*if (FloatWindow->window) { gdk_window_move_resize(FloatWindow->window, iCurrentX, iCurrentY, window_width, window_height); } else { gtk_window_move(GTK_WINDOW(FloatWindow),iCurrentX,iCurrentY); gtk_window_resize(GTK_WINDOW(FloatWindow),window_width,window_height); }*/ //note: must do resize before move should be better,as the vTimeOutCallback() may hide it. gtk_window_resize(GTK_WINDOW(FloatWindow),window_width,window_height); gtk_window_move(GTK_WINDOW(FloatWindow),iCurrentX,iCurrentY); //gtk_decorated_window_move_resize_window(GTK_WINDOW(FloatWindow), iCurrentX, iCurrentY, window_width, window_height); now_window_width = window_width; now_window_height = window_height; Show(); } ismoving = false; } void FloatWin::Show() { gtk_widget_show(FloatWindow); #ifdef _WIN32 gtk_window_present(GTK_WINDOW(FloatWindow)); #endif if (!timeout) timeout = g_timeout_add(FLOAT_TIMEOUT,vTimeOutCallback,this); } void FloatWin::Hide() { if (timeout) { g_source_remove(timeout); timeout = 0; } button_box_once_shown = false; PronounceWord.clear(); gtk_widget_hide(FloatWindow); } gint FloatWin::vTimeOutCallback(gpointer data) { FloatWin *oFloatWin = static_cast(data); bool lock= conf->get_bool_at("floating_window/lock"); if(!lock && !oFloatWin->ismoving && GTK_WIDGET_VISIBLE(oFloatWin->FloatWindow)) { GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(oFloatWin->FloatWindow)); GdkDisplay *display = gdk_screen_get_display(screen); gint iCurrentX,iCurrentY; gdk_display_get_pointer(display, NULL, &iCurrentX, &iCurrentY, NULL); bool only_scan_while_modifier_key= conf->get_bool_at("dictionary/only_scan_while_modifier_key"); bool hide_floatwin_when_modifier_key_released= conf->get_bool_at("dictionary/hide_floatwin_when_modifier_key_released"); if (only_scan_while_modifier_key && hide_floatwin_when_modifier_key_released) { if (iCurrentX == oFloatWin->popup_pointer_x && iCurrentY==oFloatWin->popup_pointer_y) { bool released = !gpAppFrame->unlock_keys->is_pressed(); if (released) { oFloatWin->Hide(); gpAppFrame->oSelection.LastClipWord.clear(); //so press modifier key again will pop up the floatwin. return true; } } } int distance; gint window_x,window_y,window_width,window_height; gtk_window_get_position(GTK_WINDOW(oFloatWin->FloatWindow),&window_x,&window_y); //notice: gtk_window_get_size() is not really uptodate,don't use it! see "gtk reference". //gtk_window_get_size(GTK_WINDOW(oFloatWin->FloatWindow),&window_width,&window_height); window_width = oFloatWin->now_window_width; window_height = oFloatWin->now_window_height; if (iCurrentX < window_x) { distance = (iCurrentX-window_x)*(iCurrentX-window_x); if (iCurrentY < window_y) distance += (iCurrentY-window_y)*(iCurrentY-window_y); else if (iCurrentY > window_y+window_height) distance += (iCurrentY-window_y-window_height)*(iCurrentY-window_y-window_height); } else if (iCurrentX > window_x+window_width) { distance = (iCurrentX-window_x-window_width)*(iCurrentX-window_x-window_width); if (iCurrentY < window_y) distance += (iCurrentY-window_y)*(iCurrentY-window_y); else if ( iCurrentY > window_y+window_height ) distance += (iCurrentY-window_y-window_height)*(iCurrentY-window_y-window_height); } else { if (iCurrentY < window_y) distance = (window_y - iCurrentY)*(window_y - iCurrentY); else if (iCurrentY > window_y+window_height) distance = (iCurrentY-window_y-window_height)*(iCurrentY-window_y-window_height); else distance = 0; //in the floating window. } if (distance > DISAPPEAR_DISTANCE){ oFloatWin->Hide(); } } // to be hidden return true; } gboolean FloatWin::vEnterNotifyCallback (GtkWidget *widget, GdkEventCrossing *event, FloatWin *oFloatWin) { /*g_print("enter "); switch (event->detail) { case GDK_NOTIFY_ANCESTOR: g_print("GDK_NOTIFY_ANCESTOR\n"); break; case GDK_NOTIFY_VIRTUAL: g_print("GDK_NOTIFY_VIRTUAL\n"); break; case GDK_NOTIFY_NONLINEAR: g_print("GDK_NOTIFY_NONLINEAR\n"); break; case GDK_NOTIFY_NONLINEAR_VIRTUAL: g_print("GDK_NOTIFY_NONLINEAR_VIRTUAL\n"); break; case GDK_NOTIFY_UNKNOWN: g_print("GDK_NOTIFY_UNKNOWN\n"); break; case GDK_NOTIFY_INFERIOR: g_print("GDK_NOTIFY_INFERIOR\n"); break; }*/ #ifdef _WIN32 if ((event->detail==GDK_NOTIFY_ANCESTOR) || (event->detail==GDK_NOTIFY_NONLINEAR) || (event->detail==GDK_NOTIFY_NONLINEAR_VIRTUAL)) { #else if ((event->detail==GDK_NOTIFY_NONLINEAR) || (event->detail==GDK_NOTIFY_NONLINEAR_VIRTUAL)) { #endif if (!GTK_WIDGET_VISIBLE(oFloatWin->button_hbox)) { gtk_widget_show(oFloatWin->button_hbox); if (!oFloatWin->button_box_once_shown) { oFloatWin->button_box_once_shown = true; gint iCurrentX,iCurrentY; gtk_window_get_position(GTK_WINDOW(oFloatWin->FloatWindow),&iCurrentX,&iCurrentY); GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(oFloatWin->FloatWindow)); gint screen_width = gdk_screen_get_width(screen); gint screen_height = gdk_screen_get_height(screen); GtkRequisition requisition; gtk_widget_size_request(oFloatWin->button_hbox,&requisition); oFloatWin->now_window_height += requisition.height; requisition.width += 2*(FLOATWIN_BORDER_WIDTH+2); if (requisition.width > oFloatWin->now_window_width) oFloatWin->now_window_width = requisition.width; gboolean changed=false; if (iCurrentX < 0) { iCurrentX = 0; changed = true; } else { if (iCurrentX + oFloatWin->now_window_width > screen_width) { iCurrentX = screen_width - oFloatWin->now_window_width; changed = true; } } if (iCurrentY < 0) { iCurrentY = 0; changed = true; } else { if (iCurrentY + oFloatWin->now_window_height > screen_height) { iCurrentY = screen_height - oFloatWin->now_window_height; changed = true; } } if (changed) gtk_window_move(GTK_WINDOW(oFloatWin->FloatWindow),iCurrentX,iCurrentY); } } } return true; } gboolean FloatWin::vLeaveNotifyCallback (GtkWidget *widget, GdkEventCrossing *event, FloatWin *oFloatWin) { /*g_print("leave "); switch (event->detail) { case GDK_NOTIFY_ANCESTOR: g_print("GDK_NOTIFY_ANCESTOR\n"); break; case GDK_NOTIFY_VIRTUAL: g_print("GDK_NOTIFY_VIRTUAL\n"); break; case GDK_NOTIFY_NONLINEAR: g_print("GDK_NOTIFY_NONLINEAR\n"); break; case GDK_NOTIFY_NONLINEAR_VIRTUAL: g_print("GDK_NOTIFY_NONLINEAR_VIRTUAL\n"); break; case GDK_NOTIFY_UNKNOWN: g_print("GDK_NOTIFY_UNKNOWN\n"); break; case GDK_NOTIFY_INFERIOR: g_print("GDK_NOTIFY_INFERIOR\n"); break; }*/ #ifdef _WIN32 if (((event->detail==GDK_NOTIFY_ANCESTOR) || (event->detail==GDK_NOTIFY_NONLINEAR) || (event->detail==GDK_NOTIFY_NONLINEAR_VIRTUAL))&&(!oFloatWin->ismoving)) { #else if (((event->detail==GDK_NOTIFY_NONLINEAR) || (event->detail==GDK_NOTIFY_NONLINEAR_VIRTUAL))&&(!oFloatWin->ismoving)) { #endif gtk_widget_hide(oFloatWin->button_hbox); } return true; } void FloatWin::on_menu_copy_activate(GtkWidget * widget, FloatWin *oFloatWin) { GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text(clipboard, oFloatWin->view->get_text().c_str(), -1); } void FloatWin::on_menu_save_activate(GtkWidget * widget, FloatWin *oFloatWin) { oFloatWin->on_save_click(widget, oFloatWin); } void FloatWin::on_menu_query_activate(GtkWidget * widget, FloatWin *oFloatWin) { oFloatWin->on_query_click(widget, oFloatWin); } void FloatWin::on_menu_play_activate(GtkWidget * widget, FloatWin *oFloatWin) { oFloatWin->on_play_click(widget, oFloatWin); } void FloatWin::on_menu_fuzzyquery_activate(GtkWidget * widget, FloatWin *oFloatWin) { gpAppFrame->LookupWithFuzzyToFloatWin(oFloatWin->QueryingWord.c_str()); } gboolean FloatWin::vButtonPressCallback (GtkWidget * widget, GdkEventButton * event , FloatWin *oFloatWin) { if (event->type == GDK_BUTTON_PRESS) { if (event->button == 1) { gtk_window_get_position(GTK_WINDOW(widget),&(oFloatWin->press_window_x),&(oFloatWin->press_window_y)); oFloatWin->press_x_root = (gint)(event->x_root); oFloatWin->press_y_root = (gint)(event->y_root); oFloatWin->ismoving = true; } else if (event->button == 3) { if (oFloatWin->menu) gtk_widget_destroy(oFloatWin->menu); oFloatWin->menu = gtk_menu_new(); GtkWidget *menuitem; menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Copy")); GtkWidget *image; image = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(on_menu_copy_activate), oFloatWin); gtk_menu_shell_append(GTK_MENU_SHELL(oFloatWin->menu), menuitem); menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Save")); image = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(on_menu_save_activate), oFloatWin); gtk_menu_shell_append(GTK_MENU_SHELL(oFloatWin->menu), menuitem); menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Query")); image = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(on_menu_query_activate), oFloatWin); gtk_menu_shell_append(GTK_MENU_SHELL(oFloatWin->menu), menuitem); if (GTK_WIDGET_SENSITIVE(oFloatWin->PronounceWordButton)) { menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Play")); image = gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(on_menu_play_activate), oFloatWin); gtk_menu_shell_append(GTK_MENU_SHELL(oFloatWin->menu), menuitem); } if ((oFloatWin->found_result != FLOAT_WIN_FUZZY_FOUND) && (oFloatWin->found_result != FLOAT_WIN_FUZZY_NOT_FOUND)) { menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Fuzzy Query")); image = gtk_image_new_from_stock(GTK_STOCK_FIND_AND_REPLACE, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(on_menu_fuzzyquery_activate), oFloatWin); gtk_menu_shell_append(GTK_MENU_SHELL(oFloatWin->menu), menuitem); } gtk_widget_show_all(oFloatWin->menu); gtk_menu_popup(GTK_MENU(oFloatWin->menu), NULL, NULL, NULL, NULL, event->button, event->time); play_sound_on_event("menushow"); } } else if (event->type == GDK_2BUTTON_PRESS) { if (oFloatWin->found_result == FLOAT_WIN_NOT_FOUND) gpAppFrame->LookupWithFuzzyToFloatWin(oFloatWin->QueryingWord.c_str()); else oFloatWin->Hide(); } return true; } gboolean FloatWin::vButtonReleaseCallback (GtkWidget * widget, GdkEventButton * event , FloatWin *oFloatWin) { if (event->button == 1) { oFloatWin->ismoving = false; } else if (event->button==3) { //gpAppFrame->oAppCore->Popup(); } return true; } gboolean FloatWin::vMotionNotifyCallback (GtkWidget * widget, GdkEventMotion * event , FloatWin *oFloatWin) { if (event->state & GDK_BUTTON1_MASK) { gint x,y; x = oFloatWin->press_window_x + (gint)(event->x_root) - oFloatWin->press_x_root; y = oFloatWin->press_window_y + (gint)(event->y_root) - oFloatWin->press_y_root; if (x<0) x = 0; if (y<0) y = 0; gtk_window_move(GTK_WINDOW(oFloatWin->FloatWindow), x, y); } return true; } void FloatWin::on_query_click(GtkWidget *widget, FloatWin *oFloatWin) { play_sound_on_event("buttonactive"); if (!conf->get_bool_at("floating_window/lock")) oFloatWin->Hide(); gpAppFrame->Query(oFloatWin->QueryingWord.c_str()); gpAppFrame->oDockLet->maximize_from_tray(); } void FloatWin::on_save_click(GtkWidget *widget, FloatWin *oFloatWin) { if (conf->get_bool_at("dictionary/only_export_word")) { FILE *fp = fopen(conf->get_string_at("dictionary/export_file").c_str(), "a+"); if(fp) { fputs(oFloatWin->QueryingWord.c_str(),fp); fputs("\n",fp); fclose(fp); } } else { FILE *fp = fopen(conf->get_string_at("dictionary/export_file").c_str(), "a+"); if(fp) { fputs(oFloatWin->view->get_text().c_str(),fp); fputs("\n\n",fp); fclose(fp); } } play_sound_on_event("buttonactive"); } void FloatWin::on_play_click(GtkWidget *widget, FloatWin *oFloatWin) { gpAppFrame->oReadWord.read(oFloatWin->PronounceWord.c_str(), oFloatWin->readwordtype); } void FloatWin::on_stop_click(GtkWidget *widget, FloatWin *oFloatWin) { play_sound_on_event("buttonactive"); conf->set_bool_at("dictionary/scan_selection", false); } #ifndef CONFIG_GPE void FloatWin::on_help_click(GtkWidget *widget, FloatWin *oFloatWin) { play_sound_on_event("buttonactive"); if (!conf->get_bool_at("floating_window/lock")) oFloatWin->Hide(); show_help("stardict-scan-selection"); } void FloatWin::on_quit_click(GtkWidget *widget, FloatWin *oFloatWin) { play_sound_on_event("buttonactive"); gpAppFrame->Quit(); } #endif void FloatWin::vLockCallback(GtkWidget *widget, FloatWin *oFloatWin) { play_sound_on_event("buttonactive"); conf->set_bool_at("floating_window/lock", !conf->get_bool_at("floating_window/lock")); }