diff --git a/meson_options.txt b/meson_options.txt index 3736f108..e5730961 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -25,3 +25,10 @@ option( value: false, description: 'enable -fsanitize=address compile/link flag', ) + +option( + 'config-debug', + type: 'feature', + value: 'auto', + description: 'enable CONFIG_DEBUG, some unittests need this flag', +) diff --git a/src/TestConfig.h.in b/src/TestConfig.h.in index 43bc2e03..aa7ed2b4 100644 --- a/src/TestConfig.h.in +++ b/src/TestConfig.h.in @@ -1,6 +1,7 @@ #ifndef IPTUX_TEST_CONFIG_H #define IPTUX_TEST_CONFIG_H +#include "config.h" #mesondefine CURRENT_SOURCE_PATH #endif // IPTUX_TEST_CONFIG_H diff --git a/src/config.h.in b/src/config.h.in index 12155525..2be99395 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -19,6 +19,7 @@ #define PHOTO_PATH "/iptux/photo" #mesondefine SYSTEM_DARWIN +#mesondefine CONFIG_DEBUG #if defined(__APPLE__) || defined(__CYGWIN__) #define O_LARGEFILE 0 diff --git a/src/iptux/ApplicationTest.cpp b/src/iptux/ApplicationTest.cpp index afe55621..c2eb4e9b 100644 --- a/src/iptux/ApplicationTest.cpp +++ b/src/iptux/ApplicationTest.cpp @@ -1,3 +1,4 @@ +#include "TestConfig.h" #include "UiHelper.h" #include "gtest/gtest.h" @@ -13,6 +14,7 @@ void do_action(Application* app, const string& name) { g_action_activate(g_action_map_lookup_action(m, name.c_str()), NULL); } +#if CONFIG_DEBUG TEST(Application, Constructor) { _ForTestToggleOpenUrl(false); Application* app = CreateApplication(); @@ -26,3 +28,4 @@ TEST(Application, Constructor) { app->_ForTestProcessEvents(); DestroyApplication(app); } +#endif diff --git a/src/iptux/DataSettingsTest.cpp b/src/iptux/DataSettingsTest.cpp index 8c9d3b3e..994fa838 100644 --- a/src/iptux/DataSettingsTest.cpp +++ b/src/iptux/DataSettingsTest.cpp @@ -1,3 +1,4 @@ +#include "TestConfig.h" #include "UiHelper.h" #include "gtest/gtest.h" @@ -15,6 +16,7 @@ TEST(DataSettings, Constructor) { DestroyApplication(app); } +#if CONFIG_DEBUG TEST(DataSettings, Constructor2) { pop_disable(); Application* app = CreateApplication(); @@ -23,3 +25,4 @@ TEST(DataSettings, Constructor2) { gtk_entry_set_text(port_entry, "abc"); ASSERT_FALSE(ds.Save()); } +#endif diff --git a/src/iptux/DialogBase.cpp b/src/iptux/DialogBase.cpp index 45d5153d..8dd881dc 100644 --- a/src/iptux/DialogBase.cpp +++ b/src/iptux/DialogBase.cpp @@ -115,6 +115,25 @@ void DialogBase::ScrollHistoryTextview() { gtk_text_buffer_delete_mark(buffer, mark); } +typedef struct _GetImageCbkCtx { + int idx; + GtkEventBox* res; +} GetImageCbkCtx; + +static void GetImageCbk(GtkWidget* widget, GetImageCbkCtx* ctx) { + if (GTK_IS_EVENT_BOX(widget) && ctx->idx-- == 0) { + ctx->res = GTK_EVENT_BOX(widget); + } +} + +GtkEventBox* DialogBase::chatHistoryGetImageEventBox(int idx) { + GetImageCbkCtx ctx = {idx, nullptr}; + + gtk_container_foreach(GTK_CONTAINER(chat_history_widget), + (GtkCallback)GetImageCbk, &ctx); + return ctx.res; +} + /** * 窗口打开情况下,新消息来到以后的接口 */ @@ -818,14 +837,12 @@ void DialogBase::afterWindowCreated() { m_imagePopupMenu = GTK_MENU(gtk_menu_new()); GtkWidget* menu_item = gtk_menu_item_new_with_label(_("Save Image")); + gtk_actionable_set_action_name(GTK_ACTIONABLE(menu_item), "win.save_image"); gtk_menu_shell_append(GTK_MENU_SHELL(m_imagePopupMenu), menu_item); - g_signal_connect_swapped(menu_item, "activate", - G_CALLBACK(DialogBase::OnSaveImage), this); menu_item = gtk_menu_item_new_with_label(_("Copy Image")); + gtk_actionable_set_action_name(GTK_ACTIONABLE(menu_item), "win.copy_image"); gtk_menu_shell_append(GTK_MENU_SHELL(m_imagePopupMenu), menu_item); - g_signal_connect_swapped(menu_item, "activate", - G_CALLBACK(DialogBase::OnCopyImage), this); gtk_menu_attach_to_widget(m_imagePopupMenu, GTK_WIDGET(getWindow()), NULL); } @@ -880,7 +897,7 @@ void DialogBase::OnChatHistoryInsertChildAnchor(DialogBase* self, gtk_widget_show_all(event_box); } -void DialogBase::OnSaveImage(DialogBase* self) { +void DialogBase::onSaveImage(void*, void*, DialogBase* self) { GtkImage* image = self->m_activeImage; g_return_if_fail(!!image); @@ -899,7 +916,7 @@ void DialogBase::OnSaveImage(DialogBase* self) { TRUE); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "image.png"); - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + if (igtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { char* save_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); GError* error = NULL; @@ -920,7 +937,7 @@ void DialogBase::OnSaveImage(DialogBase* self) { gtk_widget_destroy(dialog); } -void DialogBase::OnCopyImage(DialogBase* self) { +void DialogBase::onCopyImage(void*, void*, DialogBase* self) { GtkImage* image = self->m_activeImage; g_return_if_fail(!!image); diff --git a/src/iptux/DialogBase.h b/src/iptux/DialogBase.h index e424882c..2adbb3e0 100644 --- a/src/iptux/DialogBase.h +++ b/src/iptux/DialogBase.h @@ -30,6 +30,7 @@ class DialogBase : public SessionAbstract, public sigc::trackable { virtual GtkWindow* getWindow() = 0; void ClearHistoryTextView(); + GtkEventBox* chatHistoryGetImageEventBox(int idx); protected: void InitSublayerGeneral(); @@ -91,8 +92,8 @@ class DialogBase : public SessionAbstract, public sigc::trackable { const GtkTextIter* location, GtkTextChildAnchor* anchor, GtkTextBuffer* buffer); - static void OnSaveImage(DialogBase* self); - static void OnCopyImage(DialogBase* self); + static void onSaveImage(void*, void*, DialogBase* self); + static void onCopyImage(void*, void*, DialogBase* self); protected: Application* app; diff --git a/src/iptux/DialogPeer.cpp b/src/iptux/DialogPeer.cpp index 34978eda..a989690b 100644 --- a/src/iptux/DialogPeer.cpp +++ b/src/iptux/DialogPeer.cpp @@ -96,6 +96,8 @@ void DialogPeer::init() { G_ACTION_CALLBACK(onRequestSharedResources)), makeActionEntry("send_message", G_ACTION_CALLBACK(onSendMessage)), makeActionEntry("paste", G_ACTION_CALLBACK(onPaste)), + makeActionEntry("save_image", G_ACTION_CALLBACK(onSaveImage)), + makeActionEntry("copy_image", G_ACTION_CALLBACK(onCopyImage)), }; g_action_map_add_action_entries(G_ACTION_MAP(window), win_entries, G_N_ELEMENTS(win_entries), this); diff --git a/src/iptux/DialogPeerTest.cpp b/src/iptux/DialogPeerTest.cpp index c338ebcc..f91d9fbb 100644 --- a/src/iptux/DialogPeerTest.cpp +++ b/src/iptux/DialogPeerTest.cpp @@ -52,5 +52,11 @@ TEST(DialogPeer, Constructor) { ChipData(MessageContentType::PICTURE, testDataPath("iptux.png"))); grpinf->addMsgPara(msg); + GtkEventBox* eb = dlgpr->chatHistoryGetImageEventBox(0); + ASSERT_NE(eb, nullptr); + GtkImage* image = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(eb))); + ASSERT_NE(image, nullptr); + gtk_widget_grab_focus(GTK_WIDGET(eb)); + DestroyApplication(app); } diff --git a/src/iptux/UiHelper.cpp b/src/iptux/UiHelper.cpp index 5c011bcb..9ed6d834 100644 --- a/src/iptux/UiHelper.cpp +++ b/src/iptux/UiHelper.cpp @@ -16,8 +16,17 @@ using namespace std; namespace iptux { -static atomic_bool open_url_enabled(true); +#if CONFIG_DEBUG static bool pop_disabled = false; +static atomic_bool open_url_enabled(true); +static gint igtk_dialog_run_return_val = 0; +#else +enum { + igtk_dialog_run_return_val = 0, + pop_disabled = 0, + open_url_enabled = 1, +}; +#endif void iptux_open_path(const char* path) { g_return_if_fail(!!path); @@ -42,10 +51,6 @@ void iptux_open_path(const char* path) { g_free(uri); } -void _ForTestToggleOpenUrl(bool enable) { - open_url_enabled = enable; -} - /** * 打开URL. * @param url url @@ -156,10 +161,6 @@ GSList* selection_data_get_path(GtkSelectionData* data) { return filelist; } -void pop_disable() { - pop_disabled = true; -} - /** * 弹出消息提示. * @param parent parent window @@ -399,4 +400,24 @@ string igtk_text_buffer_get_text(GtkTextBuffer* buffer) { return res; } +gint igtk_dialog_run(GtkDialog* dialog) { + if (igtk_dialog_run_return_val) { + return igtk_dialog_run_return_val; + } + return gtk_dialog_run(dialog); +} + +#if CONFIG_DEBUG +void pop_disable() { + pop_disabled = true; +} +void _ForTestToggleOpenUrl(bool enable) { + open_url_enabled = enable; +} + +void setIgtkDialogRunReturnVal(gint val) { + igtk_dialog_run_return_val = val; +} +#endif + } // namespace iptux diff --git a/src/iptux/UiHelper.h b/src/iptux/UiHelper.h index c2771ce9..6eafe6ce 100644 --- a/src/iptux/UiHelper.h +++ b/src/iptux/UiHelper.h @@ -38,17 +38,12 @@ GSList* selection_data_get_path(GtkSelectionData* data); */ GtkImage* igtk_image_new_with_size(const char* filename, int width, int height); std::string igtk_text_buffer_get_text(GtkTextBuffer* buffer); +gint igtk_dialog_run(GtkDialog* dialog); -/** - * @brief only used for test, after call this, pop_info, pop_warning, - * and iptux_open_url will only print log - */ -void pop_disable(); void pop_info(GtkWidget* parent, const gchar* format, ...) G_GNUC_PRINTF(2, 3); void pop_warning(GtkWidget* parent, const gchar* format, ...) G_GNUC_PRINTF(2, 3); void iptux_open_url(const char* url); -void _ForTestToggleOpenUrl(bool enable); std::string ipv4_get_lan_name(in_addr ipv4); @@ -107,5 +102,15 @@ std::string TimeToStr(time_t t); /* only used for test */ std::string TimeToStr_(time_t t, time_t now); +#if CONFIG_DEBUG +/** + * @brief only used for test, after call this, pop_info, pop_warning, + * and iptux_open_url will only print log + */ +void pop_disable(); +void _ForTestToggleOpenUrl(bool enable); +void setIgtkDialogRunReturnVal(gint val); +#endif + } // namespace iptux #endif // IPTUX_UIHELPER_H diff --git a/src/meson.build b/src/meson.build index 281f4d18..842a116c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -32,6 +32,16 @@ else conf_data.set('SYSTEM_DARWIN', 0) endif +config_debug = get_option('config-debug') +if config_debug.enabled() + config_debug_val = 1 +elif config_debug.disabled() + config_debug_val = 0 +else + config_debug_val = get_option('debug').to_int() +endif +conf_data.set('CONFIG_DEBUG', config_debug_val) + configure_file( input: 'config.h.in', output: 'config.h',