diff options
Diffstat (limited to 'vcl/unx/gtk3/gtk3gtkinst.cxx')
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 1572 |
1 files changed, 1571 insertions, 1 deletions
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 5497a3d7de4b..0acaed180b20 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -25,8 +25,14 @@ #include <comphelper/processfactory.hxx> #include <comphelper/sequence.hxx> #include <cppuhelper/compbase.hxx> +#include <comphelper/string.hxx> #include <cppuhelper/implbase.hxx> #include <cppuhelper/supportsservice.hxx> +#include <rtl/bootstrap.hxx> +#include <tools/fract.hxx> +#include <tools/stream.hxx> +#include <vcl/pngwrite.hxx> +#include <vcl/weld.hxx> using namespace com::sun::star; using namespace com::sun::star::uno; @@ -130,7 +136,7 @@ std::vector<css::datatransfer::DataFlavor> GtkTransferable::getTransferDataFlavo } aFlavor.MimeType = OUString(pFinalName, - rtl_str_getLength(pFinalName), + strlen(pFinalName), RTL_TEXTENCODING_UTF8); m_aMimeTypeToAtom[aFlavor.MimeType] = targets[i]; @@ -1148,4 +1154,1568 @@ OpenGLContext* GtkInstance::CreateOpenGLContext() return new GtkOpenGLContext; } +class GtkInstanceBuilder; + +namespace +{ + OString get_help_id(const GtkWidget *pWidget) + { + void* pData = g_object_get_data(G_OBJECT(pWidget), "helpid"); + const gchar* pStr = static_cast<const gchar*>(pData); + return OString(pStr, pStr ? strlen(pStr) : 0); + } +} + +class GtkInstanceWidget : public virtual weld::Widget +{ +protected: + GtkWidget* m_pWidget; +private: + bool m_bTakeOwnership; + +public: + GtkInstanceWidget(GtkWidget* pWidget, bool bTakeOwnership) + : m_pWidget(pWidget) + , m_bTakeOwnership(bTakeOwnership) + { + } + + virtual void set_sensitive(bool sensitive) override + { + gtk_widget_set_sensitive(m_pWidget, sensitive); + } + + virtual bool get_sensitive() const override + { + return gtk_widget_get_sensitive(m_pWidget); + } + + virtual void set_visible(bool visible) override + { + gtk_widget_set_visible(m_pWidget, visible); + } + + virtual bool get_visible() const override + { + return gtk_widget_get_visible(m_pWidget); + } + + virtual void grab_focus() override + { + gtk_widget_grab_focus(m_pWidget); + } + + virtual bool has_focus() const override + { + return gtk_widget_has_focus(m_pWidget); + } + + virtual void show() override + { + gtk_widget_show(m_pWidget); + } + + virtual void hide() override + { + gtk_widget_hide(m_pWidget); + } + + virtual void set_size_request(int nWidth, int nHeight) override + { + gtk_widget_set_size_request(m_pWidget, nWidth, nHeight); + } + + virtual Size get_preferred_size() const override + { + GtkRequisition size; + gtk_widget_get_preferred_size(m_pWidget, nullptr, &size); + return Size(size.width, size.height); + } + + virtual float approximate_char_width() const override + { + PangoContext* pContext = gtk_widget_get_pango_context(m_pWidget); + PangoFontMetrics* pMetrics = pango_context_get_metrics(pContext, + pango_context_get_font_description(pContext), + pango_context_get_language(pContext)); + float nCharWidth = pango_font_metrics_get_approximate_char_width(pMetrics); + float nDigitWidth = pango_font_metrics_get_approximate_digit_width(pMetrics); + pango_font_metrics_unref(pMetrics); + + return std::max(nCharWidth, nDigitWidth) / PANGO_SCALE; + } + + virtual Size get_pixel_size(const OUString& rText) const override + { + OString aStr(OUStringToOString(rText, RTL_TEXTENCODING_UTF8)); + PangoLayout* pLayout = gtk_widget_create_pango_layout(m_pWidget, aStr.getStr()); + gint nWidth, nHeight; + pango_layout_get_pixel_size(pLayout, &nWidth, &nHeight); + g_object_unref(pLayout); + return Size(nWidth, nHeight); + } + + virtual weld::Widget* weld_parent() const override + { + GtkWidget* pParent = gtk_widget_get_parent(m_pWidget); + return pParent ? new GtkInstanceWidget(pParent, false) : nullptr; + } + + virtual OString get_buildable_name() const override + { + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(m_pWidget)); + return OString(pStr, pStr ? strlen(pStr) : 0); + } + + virtual OString get_help_id() const override + { + OString sRet = ::get_help_id(m_pWidget); + if (sRet.isEmpty()) + sRet = OString("null"); + return sRet; + } + + GtkWidget* getWidget() + { + return m_pWidget; + } + + GtkWindow* getWindow() + { + return GTK_WINDOW(gtk_widget_get_toplevel(m_pWidget)); + } + + virtual ~GtkInstanceWidget() override + { + if (m_bTakeOwnership) + gtk_widget_destroy(m_pWidget); + } +}; + +class GtkInstanceContainer : public GtkInstanceWidget, public virtual weld::Container +{ +private: + GtkContainer* m_pContainer; +public: + GtkInstanceContainer(GtkContainer* pContainer, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pContainer), bTakeOwnership) + , m_pContainer(pContainer) + { + (void)m_pContainer; + } +}; + +class GtkInstanceWindow : public GtkInstanceContainer, public virtual weld::Window +{ +private: + GtkWindow* m_pWindow; + + static void help_pressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer widget) + { + GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget); + pThis->help(); + } +protected: + void help(); +public: + GtkInstanceWindow(GtkWindow* pWindow, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pWindow), bTakeOwnership) + , m_pWindow(pWindow) + { + //hook up F1 to show help + GtkAccelGroup *pGroup = gtk_accel_group_new(); + GClosure* closure = g_cclosure_new(G_CALLBACK(help_pressed), this, nullptr); + gtk_accel_group_connect(pGroup, GDK_KEY_F1, static_cast<GdkModifierType>(0), GTK_ACCEL_LOCKED, closure); + gtk_window_add_accel_group(pWindow, pGroup); + } + + virtual void set_title(const OUString& rTitle) override + { + gtk_window_set_title(m_pWindow, OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual OUString get_title() const override + { + const gchar* pStr = gtk_window_get_title(m_pWindow); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } +}; + +class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog +{ +private: + GtkDialog* m_pDialog; + gulong m_nCloseSignalId; + + static void signalClose(GtkWidget *, gpointer widget) + { + GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget); + pThis->response(RET_CANCEL); + } +public: + GtkInstanceDialog(GtkDialog* pDialog, bool bTakeOwnership) + : GtkInstanceWindow(GTK_WINDOW(pDialog), bTakeOwnership) + , m_pDialog(pDialog) + , m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this)) + { + } + + virtual int run() override + { + int ret; + while (true) + { + ret = gtk_dialog_run(m_pDialog); + if (ret == GTK_RESPONSE_HELP) + { + help(); + continue; + } + else if (ret == GTK_RESPONSE_OK) + ret = RET_OK; + else if (ret == GTK_RESPONSE_CANCEL) + ret = RET_CANCEL; + break; + } + hide(); + return ret; + } + + virtual void response(int nResponse) override + { + if (nResponse == RET_OK) + nResponse = GTK_RESPONSE_OK; + else if (nResponse == RET_CANCEL) + nResponse = GTK_RESPONSE_CANCEL; + else if (nResponse == RET_HELP) + nResponse = GTK_RESPONSE_HELP; + gtk_dialog_response(m_pDialog, nResponse); + } + + virtual ~GtkInstanceDialog() override + { + g_signal_handler_disconnect(m_pDialog, m_nCloseSignalId); + } +}; + +class GtkInstanceMessageDialog : public GtkInstanceDialog, public virtual weld::MessageDialog +{ +private: + GtkMessageDialog* m_pMessageDialog; +public: + GtkInstanceMessageDialog(GtkMessageDialog* pMessageDialog, bool bTakeOwnership) + : GtkInstanceDialog(GTK_DIALOG(pMessageDialog), bTakeOwnership) + , m_pMessageDialog(pMessageDialog) + { + } + + virtual void set_primary_text(const OUString& rText) override + { + g_object_set(G_OBJECT(m_pMessageDialog), "text", + OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(), + nullptr); + } + + virtual OUString get_primary_text() const override + { + gchar* pText = nullptr; + g_object_get(G_OBJECT(m_pMessageDialog), "text", &pText, nullptr); + return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + } + + virtual void set_secondary_text(const OUString& rText) override + { + g_object_set(G_OBJECT(m_pMessageDialog), "secondary-text", + OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(), + nullptr); + } + + virtual OUString get_secondary_text() const override + { + gchar* pText = nullptr; + g_object_get(G_OBJECT(m_pMessageDialog), "secondary-text", &pText, nullptr); + return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + } +}; + +static OString MapToGtkAccelerator(const OUString &rStr) +{ + return OUStringToOString(rStr.replaceFirst("~", "_"), RTL_TEXTENCODING_UTF8); +} + +class GtkInstanceFrame : public GtkInstanceContainer, public virtual weld::Frame +{ +private: + GtkFrame* m_pFrame; +public: + GtkInstanceFrame(GtkFrame* pFrame, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pFrame), bTakeOwnership) + , m_pFrame(pFrame) + { + } + + virtual void set_label(const OUString& rText) override + { + gtk_label_set_label(GTK_LABEL(gtk_frame_get_label_widget(m_pFrame)), MapToGtkAccelerator(rText).getStr()); + } + + virtual OUString get_label() const override + { + const gchar* pStr = gtk_frame_get_label(m_pFrame); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } +}; + +class GtkInstanceNotebook : public GtkInstanceContainer, public virtual weld::Notebook +{ +private: + GtkNotebook* m_pNotebook; + gulong m_nSignalId; + mutable std::vector<std::unique_ptr<GtkInstanceContainer>> m_aPages; + + static void signalSwitchPage(GtkNotebook*, GtkWidget*, guint nNewPage, gpointer widget) + { + GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget); + pThis->signal_switch_page(nNewPage); + } + + void signal_switch_page(guint nNewPage) + { + bool bAllow = m_aLeavePageHdl.Call(get_current_page_ident()); + if (!bAllow) + { + g_signal_stop_emission_by_name(m_pNotebook, "switch-page"); + OString sNewIdent(get_page_ident(nNewPage)); + m_aEnterPageHdl.Call(sNewIdent); + } + } + + OString get_page_ident(guint nPage) const + { + const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook, gtk_notebook_get_nth_page(m_pNotebook, nPage)); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget)); + return OString(pStr, pStr ? strlen(pStr) : 0); + } + + gint get_page_number(const OString& rIdent) const + { + gint nPages = gtk_notebook_get_n_pages(m_pNotebook); + for (gint i = 0; i < nPages; ++i) + { + const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook, gtk_notebook_get_nth_page(m_pNotebook, i)); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget)); + if (strcmp(pStr, rIdent.getStr()) == 0) + return i; + } + return -1; + } + +public: + GtkInstanceNotebook(GtkNotebook* pNotebook, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pNotebook), bTakeOwnership) + , m_pNotebook(pNotebook) + , m_nSignalId(g_signal_connect(pNotebook, "switch-page", G_CALLBACK(signalSwitchPage), this)) + { + } + + virtual int get_current_page() const override + { + return gtk_notebook_get_current_page(m_pNotebook); + } + + virtual OString get_current_page_ident() const override + { + return get_page_ident(get_current_page()); + } + + virtual weld::Container* get_page(const OString& rIdent) const override + { + int nPage = get_page_number(rIdent); + if (nPage < 0) + return nullptr; + GtkContainer* pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pNotebook, nPage)); + unsigned int nPageIndex = static_cast<unsigned int>(nPage); + if (m_aPages.size() < nPageIndex + 1) + m_aPages.resize(nPageIndex + 1); + if (!m_aPages[nPageIndex]) + m_aPages[nPageIndex].reset(new GtkInstanceContainer(pChild, false)); + return m_aPages[nPageIndex].get(); + } + + virtual void set_current_page(int nPage) override + { + gtk_notebook_set_current_page(m_pNotebook, nPage); + } + + virtual void set_current_page(const OString& rIdent) override + { + gint nPage = get_page_number(rIdent); + set_current_page(nPage); + } + + virtual int get_n_pages() const override + { + return gtk_notebook_get_n_pages(m_pNotebook); + } + + virtual ~GtkInstanceNotebook() override + { + g_signal_handler_disconnect(m_pNotebook, m_nSignalId); + } +}; + +class GtkInstanceButton : public GtkInstanceContainer, public virtual weld::Button +{ +private: + GtkButton* m_pButton; + gulong m_nSignalId; + + static void signalClicked(GtkButton*, gpointer widget) + { + GtkInstanceButton* pThis = static_cast<GtkInstanceButton*>(widget); + pThis->signal_clicked(); + } +public: + GtkInstanceButton(GtkButton* pButton, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pButton), bTakeOwnership) + , m_pButton(pButton) + , m_nSignalId(g_signal_connect(pButton, "clicked", G_CALLBACK(signalClicked), this)) + { + } + + virtual void set_label(const OUString& rText) override + { + gtk_button_set_label(m_pButton, MapToGtkAccelerator(rText).getStr()); + } + + virtual OUString get_label() const override + { + const gchar* pStr = gtk_button_get_label(m_pButton); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } + + virtual ~GtkInstanceButton() override + { + g_signal_handler_disconnect(m_pButton, m_nSignalId); + } +}; + +class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton +{ +private: + GtkToggleButton* m_pToggleButton; + gulong m_nSignalId; + + static void signalToggled(GtkToggleButton*, gpointer widget) + { + GtkInstanceToggleButton* pThis = static_cast<GtkInstanceToggleButton*>(widget); + pThis->signal_toggled(); + } +public: + GtkInstanceToggleButton(GtkToggleButton* pButton, bool bTakeOwnership) + : GtkInstanceButton(GTK_BUTTON(pButton), bTakeOwnership) + , m_pToggleButton(pButton) + , m_nSignalId(g_signal_connect(m_pToggleButton, "toggled", G_CALLBACK(signalToggled), this)) + { + } + + virtual void set_active(bool active) override + { + gtk_toggle_button_set_active(m_pToggleButton, active); + } + + virtual bool get_active() const override + { + return gtk_toggle_button_get_active(m_pToggleButton); + } + + virtual void set_inconsistent(bool inconsistent) override + { + gtk_toggle_button_set_inconsistent(m_pToggleButton, inconsistent); + } + + virtual bool get_inconsistent() const override + { + return gtk_toggle_button_get_inconsistent(m_pToggleButton); + } + + virtual ~GtkInstanceToggleButton() override + { + g_signal_handler_disconnect(m_pToggleButton, m_nSignalId); + } +}; + +class GtkInstanceRadioButton : public GtkInstanceToggleButton, public virtual weld::RadioButton +{ +public: + GtkInstanceRadioButton(GtkRadioButton* pButton, bool bTakeOwnership) + : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pButton), bTakeOwnership) + { + } +}; + +class GtkInstanceCheckButton : public GtkInstanceToggleButton, public virtual weld::CheckButton +{ +public: + GtkInstanceCheckButton(GtkCheckButton* pButton, bool bTakeOwnership) + : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pButton), bTakeOwnership) + { + } +}; + +class GtkInstanceEntry : public GtkInstanceWidget, public virtual weld::Entry +{ +private: + GtkEntry* m_pEntry; + gulong m_nChangedSignalId; + gulong m_nInsertTextSignalId; + + static void signalChanged(GtkEntry*, gpointer widget) + { + GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget); + pThis->signal_changed(); + } + + static void signalInsertText(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength, + gint* position, gpointer widget) + { + GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget); + pThis->signal_insert_text(pEntry, pNewText, nNewTextLength, position); + } + + void signal_insert_text(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength, gint* position) + { + if (!m_aInsertTextHdl.IsSet()) + return; + OUString sText(pNewText, nNewTextLength, RTL_TEXTENCODING_UTF8); + const bool bContinue = m_aInsertTextHdl.Call(sText); + if (bContinue && !sText.isEmpty()) + { + OString sFinalText(OUStringToOString(sText, RTL_TEXTENCODING_UTF8)); + g_signal_handlers_block_by_func(pEntry, gpointer(signalInsertText), this); + gtk_editable_insert_text(GTK_EDITABLE(pEntry), sFinalText.getStr(), sFinalText.getLength(), position); + g_signal_handlers_unblock_by_func(pEntry, gpointer(signalInsertText), this); + } + g_signal_stop_emission_by_name(pEntry, "insert-text"); + } +public: + GtkInstanceEntry(GtkEntry* pEntry, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pEntry), bTakeOwnership) + , m_pEntry(pEntry) + , m_nChangedSignalId(g_signal_connect(pEntry, "changed", G_CALLBACK(signalChanged), this)) + , m_nInsertTextSignalId(g_signal_connect(pEntry, "insert-text", G_CALLBACK(signalInsertText), this)) + { + } + + virtual void set_text(const OUString& rText) override + { + gtk_entry_set_text(m_pEntry, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual OUString get_text() const override + { + const gchar* pText = gtk_entry_get_text(m_pEntry); + OUString sRet(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + return sRet; + } + + virtual void set_width_chars(int nChars) override + { + gtk_entry_set_width_chars(m_pEntry, nChars); + } + + virtual ~GtkInstanceEntry() override + { + g_signal_handler_disconnect(m_pEntry, m_nInsertTextSignalId); + g_signal_handler_disconnect(m_pEntry, m_nChangedSignalId); + } +}; + +namespace +{ + struct Search + { + OString str; + int index = -1; + Search(const OUString& rText) + : str(OUStringToOString(rText, RTL_TEXTENCODING_UTF8)) + , index(-1) + { + } + }; + + gboolean foreach_find(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data) + { + Search* search = static_cast<Search*>(data); + gchar *pStr = nullptr; + gtk_tree_model_get(model, iter, 0, &pStr, -1); + bool found = strcmp(pStr, search->str.getStr()) == 0; + if (found) + search->index = gtk_tree_path_get_indices(path)[0]; + g_free(pStr); + return found; + } +} + +class GtkInstanceTreeView : public GtkInstanceContainer, public virtual weld::TreeView +{ +private: + GtkTreeView* m_pTreeView; + GtkListStore* m_pListStore; + gulong m_nChangedSignalId; + gulong m_nRowActivatedSignalId; + + static void signalChanged(GtkTreeView*, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->signal_changed(); + } + + static void signalRowActivated(GtkTreeView*, gpointer widget) + { + GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget); + pThis->signal_row_activated(); + } +public: + GtkInstanceTreeView(GtkTreeView* pTreeView, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pTreeView), bTakeOwnership) + , m_pTreeView(pTreeView) + , m_pListStore(GTK_LIST_STORE(gtk_tree_view_get_model(m_pTreeView))) + , m_nChangedSignalId(g_signal_connect(gtk_tree_view_get_selection(pTreeView), "changed", + G_CALLBACK(signalChanged), this)) + , m_nRowActivatedSignalId(g_signal_connect(pTreeView, "row-activated", G_CALLBACK(signalRowActivated), this)) + { + } + + virtual void append(const OUString& rText) override + { + insert(rText, -1); + } + + virtual void insert(const OUString& rText, int pos) override + { + GtkTreeIter iter; + gtk_list_store_insert(m_pListStore, &iter, pos); + gtk_list_store_set(m_pListStore, &iter, 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(), -1); + } + + virtual void remove(int pos) override + { + GtkTreeIter iter; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos); + gtk_list_store_remove(m_pListStore, &iter); + } + + virtual int find(const OUString& rText) const override + { + Search aSearch(rText); + gtk_tree_model_foreach(GTK_TREE_MODEL(m_pListStore), foreach_find, &aSearch); + return aSearch.index; + } + + void move_before(int pos, int before) + { + if (pos == before) + return; + + GtkTreeIter iter; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos); + + GtkTreeIter position; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &position, nullptr, before); + + gtk_list_store_move_before(m_pListStore, &iter, &position); + } + + virtual void set_top_entry(int pos) override + { + move_before(pos, 0); + } + + virtual void clear() override + { + gtk_list_store_clear(m_pListStore); + } + + virtual int n_children() const override + { + return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pListStore), nullptr); + } + + virtual void select(int pos) override + { + if (pos != -1) + { + GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1); + gtk_tree_selection_select_path(gtk_tree_view_get_selection(m_pTreeView), path); + gtk_tree_path_free(path); + } + else + { + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(m_pTreeView)); + } + } + + virtual OUString get_selected() override + { + OUString sRet; + GtkTreeIter iter; + GtkTreeModel* pModel; + if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), &pModel, &iter)) + { + gchar *pStr = nullptr; + gtk_tree_model_get(pModel, &iter, 0, &pStr, -1); + sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + g_free(pStr); + } + return sRet; + } + + virtual OUString get(int pos) override + { + GtkTreeIter iter; + gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos); + gchar *pStr = nullptr; + gtk_tree_model_get(GTK_TREE_MODEL(m_pListStore), &iter, 0, &pStr, -1); + OUString sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + g_free(pStr); + return sRet; + } + + virtual int get_selected_index() override + { + int nRet = -1; + GtkTreeIter iter; + GtkTreeModel* pModel; + if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), &pModel, &iter)) + { + GtkTreePath* path = gtk_tree_model_get_path(pModel, &iter); + nRet = gtk_tree_path_get_indices(path)[0]; + gtk_tree_path_free(path); + } + return nRet; + } + + virtual void freeze() override + { + g_object_ref(m_pListStore); + gtk_tree_view_set_model(m_pTreeView, nullptr); + } + + virtual void thaw() override + { + gtk_tree_view_set_model(m_pTreeView, GTK_TREE_MODEL(m_pListStore)); + g_object_unref(m_pListStore); + } + + virtual int get_height_rows(int nRows) const override + { + GtkTreeViewColumn* pColumn = gtk_tree_view_get_column(m_pTreeView, 0); + GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)); + GtkCellRenderer* pRenderer = GTK_CELL_RENDERER(g_list_nth_data(pRenderers, 0)); + gint nRowHeight; + gtk_cell_renderer_get_preferred_height(pRenderer, GTK_WIDGET(m_pTreeView), nullptr, &nRowHeight); + g_list_free(pRenderers); + + gint nVerticalSeparator; + gtk_widget_style_get(GTK_WIDGET(m_pTreeView), "vertical-separator", &nVerticalSeparator, nullptr); + + return (nRowHeight * nRows) + (nVerticalSeparator * (nRows + 1)); + } + + virtual ~GtkInstanceTreeView() override + { + g_signal_handler_disconnect(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId); + g_signal_handler_disconnect(m_pTreeView, m_nRowActivatedSignalId); + } +}; + + +class GtkInstanceSpinButton : public GtkInstanceEntry, public virtual weld::SpinButton +{ +private: + GtkSpinButton* m_pButton; + gulong m_nValueChangedSignalId; + gulong m_nOutputSignalId; + + static void signalValueChanged(GtkSpinButton*, gpointer widget) + { + GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget); + pThis->signal_value_changed(); + } + + static gboolean signalOutput(GtkSpinButton*, gpointer widget) + { + GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget); + return pThis->signal_output(); + } + + double toGtk(int nValue) const + { + return static_cast<double>(nValue) / Power10(get_digits()); + } + + int fromGtk(double fValue) const + { + return FRound(fValue * Power10(get_digits())); + } + +public: + GtkInstanceSpinButton(GtkSpinButton* pButton, bool bTakeOwnership) + : GtkInstanceEntry(GTK_ENTRY(pButton), bTakeOwnership) + , m_pButton(pButton) + , m_nValueChangedSignalId(g_signal_connect(pButton, "value-changed", G_CALLBACK(signalValueChanged), this)) + , m_nOutputSignalId(g_signal_connect(pButton, "output", G_CALLBACK(signalOutput), this)) + { + } + + virtual int get_value() const override + { + return fromGtk(gtk_spin_button_get_value(m_pButton)); + } + + virtual void set_value(int value) override + { + gtk_spin_button_set_value(m_pButton, toGtk(value)); + } + + virtual void set_range(int min, int max) override + { + gtk_spin_button_set_range(m_pButton, toGtk(min), toGtk(max)); + } + + virtual void get_range(int& min, int& max) const override + { + double gtkmin, gtkmax; + gtk_spin_button_get_range(m_pButton, >kmin, >kmax); + min = fromGtk(gtkmin); + max = fromGtk(gtkmax); + } + + virtual void set_increments(int step, int page) override + { + gtk_spin_button_set_increments(m_pButton, toGtk(step), toGtk(page)); + } + + virtual void get_increments(int& step, int& page) const override + { + double gtkstep, gtkpage; + gtk_spin_button_get_increments(m_pButton, >kstep, >kpage); + step = fromGtk(gtkstep); + page = fromGtk(gtkpage); + } + + virtual void set_digits(unsigned int digits) override + { + gtk_spin_button_set_digits(m_pButton, digits); + } + + virtual unsigned int get_digits() const override + { + return gtk_spin_button_get_digits(m_pButton); + } + + virtual ~GtkInstanceSpinButton() override + { + g_signal_handler_disconnect(m_pButton, m_nOutputSignalId); + g_signal_handler_disconnect(m_pButton, m_nValueChangedSignalId); + } +}; + +class GtkInstanceLabel : public GtkInstanceWidget, public virtual weld::Label +{ +private: + GtkLabel* m_pLabel; +public: + GtkInstanceLabel(GtkLabel* pLabel, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pLabel), bTakeOwnership) + , m_pLabel(pLabel) + { + } + + virtual void set_label(const OUString& rText) override + { + gtk_label_set_label(m_pLabel, MapToGtkAccelerator(rText).getStr()); + } +}; + +class GtkInstanceTextView : public GtkInstanceContainer, public virtual weld::TextView +{ +private: + GtkTextView* m_pTextView; +public: + GtkInstanceTextView(GtkTextView* pTextView, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pTextView), bTakeOwnership) + , m_pTextView(pTextView) + { + } + + virtual void set_text(const OUString& rText) override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + OString sText(OUStringToOString(rText, RTL_TEXTENCODING_UTF8)); + gtk_text_buffer_set_text(pBuffer, sText.getStr(), sText.getLength()); + } + + virtual OUString get_text() const override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + GtkTextIter start, end; + gtk_text_buffer_get_bounds(pBuffer, &start, &end); + char* pStr = gtk_text_buffer_get_text(pBuffer, &start, &end, true); + OUString sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + g_free(pStr); + return sRet; + } + + virtual Selection get_selection() const override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + GtkTextIter start, end; + gtk_text_buffer_get_selection_bounds(pBuffer, &start, &end); + return Selection(gtk_text_iter_get_offset(&start), gtk_text_iter_get_offset(&end)); + } + + virtual void set_selection(const Selection& rSelection) override + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(m_pTextView); + GtkTextIter start, end; + gtk_text_buffer_get_iter_at_offset(pBuffer, &start, rSelection.Min()); + gtk_text_buffer_get_iter_at_offset(pBuffer, &end, rSelection.Max()); + gtk_text_buffer_select_range(pBuffer, &start, &end); + GtkTextMark* mark = gtk_text_buffer_create_mark(pBuffer, "scroll", &end, true); + gtk_text_view_scroll_mark_onscreen(m_pTextView, mark); + } + +}; + +class GtkInstanceDrawingArea : public GtkInstanceWidget, public virtual weld::DrawingArea +{ +private: + GtkDrawingArea* m_pDrawingArea; + ScopedVclPtrInstance<VirtualDevice> m_xDevice; + std::vector<unsigned char> m_aBuffer; + cairo_surface_t* m_pSurface; + gulong m_nDrawSignalId; + gulong m_nSizeAllocateSignalId; + static gboolean signalDraw(GtkWidget*, cairo_t* cr, gpointer widget) + { + GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget); + pThis->signal_draw(cr); + return false; + } + static void signalSizeAllocate(GtkWidget*, GdkRectangle* allocation, gpointer widget) + { + GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget); + pThis->signal_size_allocate(allocation->width, allocation->height); + } + void signal_size_allocate(guint nWidth, guint nHeight) + { + if (m_pSurface) + cairo_surface_destroy(m_pSurface); + + const int nScale = gtk_widget_get_scale_factor(GTK_WIDGET(m_pDrawingArea)); + const int nStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nWidth * nScale); + m_aBuffer.resize(nHeight * nScale * nStride); + m_xDevice->SetOutputSizePixelScaleOffsetAndBuffer(Size(nWidth, nHeight), Fraction(1.0), Point(), + m_aBuffer.data()); + m_pSurface = cairo_image_surface_create_for_data(m_aBuffer.data(), CAIRO_FORMAT_ARGB32, + nWidth * nScale, nHeight * nScale, nStride); +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0) + cairo_surface_set_device_scale(m_pSurface, nScale, nScale); +#endif + m_aSizeAllocateHdl.Call(Size(nWidth, nHeight)); + } + void signal_draw(cairo_t* cr) + { + m_aDrawHdl.Call(*m_xDevice); + cairo_surface_mark_dirty(m_pSurface); + + cairo_set_source_surface(cr, m_pSurface, 0, 0); + cairo_paint(cr); + } +public: + GtkInstanceDrawingArea(GtkDrawingArea* pDrawingArea, bool bTakeOwnership) + : GtkInstanceWidget(GTK_WIDGET(pDrawingArea), bTakeOwnership) + , m_pDrawingArea(pDrawingArea) + , m_xDevice(nullptr, Size(1, 1), DeviceFormat::DEFAULT) + , m_pSurface(nullptr) + , m_nDrawSignalId(g_signal_connect(pDrawingArea, "draw", G_CALLBACK(signalDraw), this)) + , m_nSizeAllocateSignalId(g_signal_connect(pDrawingArea, "size_allocate", G_CALLBACK(signalSizeAllocate), this)) + { + } + + virtual void queue_draw() override + { + gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea)); + } + + virtual ~GtkInstanceDrawingArea() override + { + if (m_pSurface) + cairo_surface_destroy(m_pSurface); + g_signal_handler_disconnect(m_pDrawingArea, m_nSizeAllocateSignalId); + g_signal_handler_disconnect(m_pDrawingArea, m_nDrawSignalId); + } +}; + +namespace +{ + gint sort_func(GtkTreeModel* pModel, GtkTreeIter* a, GtkTreeIter* b, gpointer data) + { + comphelper::string::NaturalStringSorter* pSorter = static_cast<comphelper::string::NaturalStringSorter*>(data); + gchar* pName1; + gchar* pName2; + gtk_tree_model_get(pModel, a, 0, &pName1, -1); + gtk_tree_model_get(pModel, b, 0, &pName2, -1); + gint ret = pSorter->compare(OUString(pName1, strlen(pName1), RTL_TEXTENCODING_UTF8), + OUString(pName2, strlen(pName2), RTL_TEXTENCODING_UTF8)); + g_free(pName1); + g_free(pName2); + return ret; + } +} + +class GtkInstanceComboBoxText : public GtkInstanceContainer, public virtual weld::ComboBoxText +{ +private: + GtkComboBoxText* m_pComboBoxText; + std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter; + gulong m_nSignalId; + + static void signalChanged(GtkComboBox*, gpointer widget) + { + GtkInstanceComboBoxText* pThis = static_cast<GtkInstanceComboBoxText*>(widget); + pThis->signal_changed(); + } + + OUString get(int pos, int col) const + { + OUString sRet; + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + GtkTreeIter iter; + if (gtk_tree_model_iter_nth_child(pModel, &iter, nullptr, pos)) + { + gchar* pStr; + gtk_tree_model_get(pModel, &iter, col, &pStr, -1); + sRet = OUString(pStr, strlen(pStr), RTL_TEXTENCODING_UTF8); + g_free(pStr); + } + return sRet; + } + +public: + GtkInstanceComboBoxText(GtkComboBoxText* pComboBoxText, bool bTakeOwnership) + : GtkInstanceContainer(GTK_CONTAINER(pComboBoxText), bTakeOwnership) + , m_pComboBoxText(pComboBoxText) + , m_nSignalId(g_signal_connect(pComboBoxText, "changed", G_CALLBACK(signalChanged), this)) + { + } + + virtual int get_active() const override + { + return gtk_combo_box_get_active(GTK_COMBO_BOX(m_pComboBoxText)); + } + + virtual OUString get_active_id() const override + { + const gchar* pText = gtk_combo_box_get_active_id(GTK_COMBO_BOX(m_pComboBoxText)); + return OUString(pText, strlen(pText), RTL_TEXTENCODING_UTF8); + } + + virtual void set_active_id(const OUString& rStr) override + { + OString aId(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8)); + gtk_combo_box_set_active_id(GTK_COMBO_BOX(m_pComboBoxText), aId.getStr()); + } + + virtual void set_active(int pos) override + { + gtk_combo_box_set_active(GTK_COMBO_BOX(m_pComboBoxText), pos); + } + + virtual OUString get_active_text() const override + { + gchar* pText = gtk_combo_box_text_get_active_text(m_pComboBoxText); + OUString sRet(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8); + g_free(pText); + return sRet; + } + + virtual OUString get_text(int pos) const override + { + return get(pos, 0); + } + + virtual OUString get_id(int pos) const override + { + gint id_column = gtk_combo_box_get_id_column(GTK_COMBO_BOX(m_pComboBoxText)); + return get(pos, id_column); + } + + virtual void append_text(const OUString& rStr) override + { + gtk_combo_box_text_append_text(m_pComboBoxText, OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual void insert_text(int pos, const OUString& rStr) override + { + gtk_combo_box_text_insert_text(m_pComboBoxText, pos, OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual void append(const OUString& rId, const OUString& rStr) override + { + gtk_combo_box_text_append(m_pComboBoxText, + OUStringToOString(rId, RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual void insert(int pos, const OUString& rId, const OUString& rStr) override + { + gtk_combo_box_text_insert(m_pComboBoxText, pos, + OUStringToOString(rId, RTL_TEXTENCODING_UTF8).getStr(), + OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + } + + virtual int get_count() const override + { + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + return gtk_tree_model_iter_n_children(pModel, nullptr); + } + + virtual int find_text(const OUString& rStr) const override + { + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + GtkTreeIter iter; + if (!gtk_tree_model_get_iter_first(pModel, &iter)) + return -1; + + OString aStr(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr()); + int nRet = 0; + do + { + gchar* pStr; + gtk_tree_model_get(pModel, &iter, 0, &pStr, -1); + const bool bEqual = strcmp(pStr, aStr.getStr()) == 0; + g_free(pStr); + if (bEqual) + return nRet; + ++nRet; + } while (gtk_tree_model_iter_next(pModel, &iter)); + + return -1; + } + + virtual void clear() override + { + GtkTreeModel *pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + gtk_list_store_clear(GTK_LIST_STORE(pModel)); + } + + virtual void make_sorted() override + { + m_xSorter.reset(new comphelper::string::NaturalStringSorter( + ::comphelper::getProcessComponentContext(), + Application::GetSettings().GetLanguageTag().getLocale())); + GtkTreeModel* pModel = gtk_combo_box_get_model(GTK_COMBO_BOX(m_pComboBoxText)); + GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(pModel); + gtk_tree_sortable_set_sort_func(pSortable, 0, sort_func, m_xSorter.get(), nullptr); + gtk_tree_sortable_set_sort_column_id(pSortable, 0, GTK_SORT_ASCENDING); + } + + virtual ~GtkInstanceComboBoxText() override + { + g_signal_handler_disconnect(m_pComboBoxText, m_nSignalId); + } +}; + +namespace +{ + gboolean signalTooltipQuery(GtkWidget* pWidget, gint /*x*/, gint /*y*/, + gboolean /*keyboard_mode*/, GtkTooltip *tooltip) + { + const ImplSVData* pSVData = ImplGetSVData(); + if (pSVData->maHelpData.mbBalloonHelp) + { + AtkObject* pAtkObject = gtk_widget_get_accessible(pWidget); + const char* pDesc = pAtkObject ? atk_object_get_description(pAtkObject) : nullptr; + if (pDesc) + { + gtk_tooltip_set_text(tooltip, pDesc); + return true; + } + } + + const char* pDesc = gtk_widget_get_tooltip_text(pWidget); + if (pDesc) + { + gtk_tooltip_set_text(tooltip, pDesc); + return true; + } + + return false; + } + + void postprocess(gpointer data, gpointer user_data) + { + GObject* pObject = static_cast<GObject*>(data); + if (!GTK_IS_WIDGET(pObject)) + return; + OString* pHelpRoot = static_cast<OString*>(user_data); + //fixup icons + //wanted: better way to do this, e.g. make gtk use gio for + //loading from a filename and provide gio protocol handler + //for our image in a zip urls + // + //unpack the images and keep them as dirs and just + //add the paths to the gtk icon theme dir + if (GTK_IS_IMAGE(pObject)) + { + GtkImage* pImage = GTK_IMAGE(pObject); + const gchar* icon_name; + gtk_image_get_icon_name(pImage, &icon_name, nullptr); + GtkIconSize size; + g_object_get(pImage, "icon-size", &size, nullptr); + if (icon_name) + { + OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8); + + SvMemoryStream aMemStm; + BitmapEx aBitmap(aIconName); + vcl::PNGWriter aWriter(aBitmap); + aWriter.Write(aMemStm); + + GdkPixbufLoader *pixbuf_loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(pixbuf_loader, static_cast<const guchar*>(aMemStm.GetData()), + aMemStm.Seek(STREAM_SEEK_TO_END), nullptr); + gdk_pixbuf_loader_close(pixbuf_loader, nullptr); + GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(pixbuf_loader); + + gtk_image_set_from_pixbuf(pImage, pixbuf); + g_object_unref(pixbuf_loader); + } + } + //set helpids + GtkWidget* pWidget = GTK_WIDGET(pObject); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget)); + size_t nLen = pStr ? strlen(pStr) : 0; + if (!nLen) + return; + OString sHelpId = *pHelpRoot + OString(pStr, nLen); + gchar *helpid = g_strdup(sHelpId.getStr()); + g_object_set_data_full(pObject, "helpid", helpid, g_free); + //hook up for extended help + const ImplSVData* pSVData = ImplGetSVData(); + if (pSVData->maHelpData.mbBalloonHelp) + { + AtkObject* pAtkObject = gtk_widget_get_accessible(pWidget); + if (pAtkObject && atk_object_get_description(pAtkObject)) + { + gtk_widget_set_has_tooltip(pWidget, true); + g_signal_connect(pObject, "query-tooltip", G_CALLBACK(signalTooltipQuery), nullptr); + } + } + } + + void destroy_toplevels(gpointer data, gpointer /*user_data*/) + { + GObject* pObject = static_cast<GObject*>(data); + if (!GTK_IS_WINDOW(pObject)) + return; + gtk_widget_destroy(GTK_WIDGET(pObject)); + } +} + +class GtkInstanceBuilder : public weld::Builder +{ +private: + OUString m_sHelpRoot; + GtkBuilder* m_pBuilder; + GSList* m_pObjectList; + GtkWidget* m_pParentWidget; +public: + GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile) + : weld::Builder(rUIFile) + , m_sHelpRoot(rUIFile) + , m_pParentWidget(pParent) + { + OUString aUri(rUIRoot + rUIFile); + OUString aPath; + osl::FileBase::getSystemPathFromFileURL(aUri, aPath); + m_pBuilder = gtk_builder_new_from_file(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8).getStr()); + + sal_Int32 nIdx = m_sHelpRoot.lastIndexOf('.'); + if (nIdx != -1) + m_sHelpRoot = m_sHelpRoot.copy(0, nIdx); + m_sHelpRoot = m_sHelpRoot + OUString('/'); + + m_pObjectList = gtk_builder_get_objects(m_pBuilder); + OString aUtf8HelpRoot(OUStringToOString(m_sHelpRoot, RTL_TEXTENCODING_UTF8)); + g_slist_foreach(m_pObjectList, postprocess, &aUtf8HelpRoot); + } + + virtual ~GtkInstanceBuilder() override + { + g_slist_foreach(m_pObjectList, destroy_toplevels, nullptr); + g_slist_free(m_pObjectList); + g_object_unref(m_pBuilder); + } + + //ideally we would have/use weld::Container add and explicitly + //call add when we want to do this, but in the vcl impl the + //parent has to be set when the child is created, so for the + //gtk impl emulate this by doing this implicitly at weld time + void auto_add_parentless_widgets_to_container(GtkWidget* pWidget) + { + if (gtk_widget_get_toplevel(pWidget) == pWidget) + gtk_container_add(GTK_CONTAINER(m_pParentWidget), pWidget); + } + + virtual weld::MessageDialog* weld_message_dialog(const OString &id, bool bTakeOwnership) override + { + GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pMessageDialog) + return nullptr; + gtk_window_set_transient_for(GTK_WINDOW(pMessageDialog), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))); + return new GtkInstanceMessageDialog(pMessageDialog, bTakeOwnership); + } + + virtual weld::Dialog* weld_dialog(const OString &id, bool bTakeOwnership) override + { + GtkDialog* pDialog = GTK_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pDialog) + return nullptr; + gtk_window_set_transient_for(GTK_WINDOW(pDialog), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))); + return new GtkInstanceDialog(pDialog, bTakeOwnership); + } + + virtual weld::Window* weld_window(const OString &id, bool bTakeOwnership) override + { + GtkWindow* pWindow = GTK_WINDOW(gtk_builder_get_object(m_pBuilder, id.getStr())); + return pWindow ? new GtkInstanceWindow(pWindow, bTakeOwnership) : nullptr; + } + + virtual weld::Widget* weld_widget(const OString &id, bool bTakeOwnership) override + { + GtkWidget* pWidget = GTK_WIDGET(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pWidget) + return nullptr; + auto_add_parentless_widgets_to_container(pWidget); + return new GtkInstanceWidget(pWidget, bTakeOwnership); + } + + virtual weld::Container* weld_container(const OString &id, bool bTakeOwnership) override + { + GtkContainer* pContainer = GTK_CONTAINER(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pContainer) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pContainer)); + return new GtkInstanceContainer(pContainer, bTakeOwnership); + } + + virtual weld::Frame* weld_frame(const OString &id, bool bTakeOwnership) override + { + GtkFrame* pFrame = GTK_FRAME(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pFrame) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pFrame)); + return new GtkInstanceFrame(pFrame, bTakeOwnership); + } + + virtual weld::Notebook* weld_notebook(const OString &id, bool bTakeOwnership) override + { + GtkNotebook* pNotebook = GTK_NOTEBOOK(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pNotebook) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pNotebook)); + return new GtkInstanceNotebook(pNotebook, bTakeOwnership); + } + + virtual weld::Button* weld_button(const OString &id, bool bTakeOwnership) override + { + GtkButton* pButton = GTK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pButton)); + return new GtkInstanceButton(pButton, bTakeOwnership); + } + + virtual weld::RadioButton* weld_radio_button(const OString &id, bool bTakeOwnership) override + { + GtkRadioButton* pRadioButton = GTK_RADIO_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pRadioButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pRadioButton)); + return new GtkInstanceRadioButton(pRadioButton, bTakeOwnership); + } + + virtual weld::CheckButton* weld_check_button(const OString &id, bool bTakeOwnership) override + { + GtkCheckButton* pCheckButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pCheckButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pCheckButton)); + return new GtkInstanceCheckButton(pCheckButton, bTakeOwnership); + } + + virtual weld::Entry* weld_entry(const OString &id, bool bTakeOwnership) override + { + GtkEntry* pEntry = GTK_ENTRY(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pEntry) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pEntry)); + return new GtkInstanceEntry(pEntry, bTakeOwnership); + } + + virtual weld::SpinButton* weld_spin_button(const OString &id, bool bTakeOwnership) override + { + GtkSpinButton* pSpinButton = GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pSpinButton) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pSpinButton)); + return new GtkInstanceSpinButton(pSpinButton, bTakeOwnership); + } + + virtual weld::ComboBoxText* weld_combo_box_text(const OString &id, bool bTakeOwnership) override + { + GtkComboBoxText* pComboBoxText = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pComboBoxText) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pComboBoxText)); + return new GtkInstanceComboBoxText(pComboBoxText, bTakeOwnership); + } + + virtual weld::TreeView* weld_tree_view(const OString &id, bool bTakeOwnership) override + { + GtkTreeView* pTreeView = GTK_TREE_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pTreeView) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pTreeView)); + return new GtkInstanceTreeView(pTreeView, bTakeOwnership); + } + + virtual weld::Label* weld_label(const OString &id, bool bTakeOwnership) override + { + GtkLabel* pLabel = GTK_LABEL(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pLabel) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pLabel)); + return new GtkInstanceLabel(pLabel, bTakeOwnership); + } + + virtual weld::TextView* weld_text_view(const OString &id, bool bTakeOwnership) override + { + GtkTextView* pTextView = GTK_TEXT_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pTextView) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pTextView)); + return new GtkInstanceTextView(pTextView, bTakeOwnership); + } + + virtual weld::DrawingArea* weld_drawing_area(const OString &id, bool bTakeOwnership) override + { + GtkDrawingArea* pDrawingArea = GTK_DRAWING_AREA(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pDrawingArea) + return nullptr; + auto_add_parentless_widgets_to_container(GTK_WIDGET(pDrawingArea)); + return new GtkInstanceDrawingArea(pDrawingArea, bTakeOwnership); + } +}; + +void GtkInstanceWindow::help() +{ + //show help for widget with keyboard focus + GtkWidget* pWidget = gtk_window_get_focus(m_pWindow); + if (!pWidget) + pWidget = GTK_WIDGET(m_pWindow); + OString sHelpId = ::get_help_id(pWidget); + while (sHelpId.isEmpty()) + { + pWidget = gtk_widget_get_parent(pWidget); + if (!pWidget) + break; + sHelpId = ::get_help_id(pWidget); + } + std::unique_ptr<weld::Widget> xTemp(pWidget != m_pWidget ? new GtkInstanceWidget(pWidget, false) : nullptr); + weld::Widget* pSource = xTemp ? xTemp.get() : this; + bool bRunNormalHelpRequest = true; + if (m_aHelpRequestHdl.IsSet()) + bRunNormalHelpRequest = m_aHelpRequestHdl.Call(*pSource); + Help* pHelp = bRunNormalHelpRequest ? Application::GetHelp() : nullptr; + if (pHelp) + pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), pSource); +} + +weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile) +{ + GtkInstanceWidget* pParentWidget = dynamic_cast<GtkInstanceWidget*>(pParent); + GtkWidget* pBuilderParent = pParentWidget ? pParentWidget->getWidget() : nullptr; + return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile); +} + +GtkMessageType VclToGtk(VclMessageType eType) +{ + GtkMessageType eRet(GTK_MESSAGE_INFO); + switch (eType) + { + case VclMessageType::Info: + eRet = GTK_MESSAGE_INFO; + break; + case VclMessageType::Warning: + eRet = GTK_MESSAGE_WARNING; + break; + case VclMessageType::Question: + eRet = GTK_MESSAGE_QUESTION; + break; + case VclMessageType::Error: + eRet = GTK_MESSAGE_ERROR; + break; + } + return eRet; +} + +GtkButtonsType VclToGtk(VclButtonsType eType) +{ + GtkButtonsType eRet(GTK_BUTTONS_NONE); + switch (eType) + { + case VclButtonsType::NONE: + eRet = GTK_BUTTONS_NONE; + break; + case VclButtonsType::Ok: + eRet = GTK_BUTTONS_OK; + break; + case VclButtonsType::Close: + eRet = GTK_BUTTONS_CLOSE; + break; + case VclButtonsType::Cancel: + eRet = GTK_BUTTONS_CANCEL; + break; + case VclButtonsType::YesNo: + eRet = GTK_BUTTONS_YES_NO; + break; + case VclButtonsType::OkCancel: + eRet = GTK_BUTTONS_OK_CANCEL; + break; + } + return eRet; +} + +weld::MessageDialog* GtkInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString &rPrimaryMessage) +{ + GtkInstanceWidget* pParentInstance = dynamic_cast<GtkInstanceWidget*>(pParent); + GtkWindow* pParentWindow = pParentInstance ? pParentInstance->getWindow() : nullptr; + GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL, + VclToGtk(eMessageType), VclToGtk(eButtonsType), "%s", + OUStringToOString(rPrimaryMessage, RTL_TEXTENCODING_UTF8).getStr())); + return new GtkInstanceMessageDialog(pMessageDialog, true); +} + +weld::Window* GtkSalFrame::GetFrameWeld() const +{ + if (!m_xFrameWeld) + m_xFrameWeld.reset(new GtkInstanceWindow(GTK_WINDOW(getWindow()), false)); + return m_xFrameWeld.get(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |