summaryrefslogtreecommitdiff
path: root/vcl/unx/gtk3/gtk3gtkinst.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/gtk3/gtk3gtkinst.cxx')
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx1572
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, &gtkmin, &gtkmax);
+ 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, &gtkstep, &gtkpage);
+ 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: */