Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 113, column 13
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name gtk3gtkinst.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/gtk-3.0 -isystem /usr/include/pango-1.0 -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/harfbuzz -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/fribidi -isystem /usr/include/libxml2 -isystem /usr/include/cairo -isystem /usr/include/pixman-1 -isystem /usr/include/gdk-pixbuf-2.0 -isystem /usr/include/gio-unix-2.0 -isystem /usr/include/atk-1.0 -isystem /usr/include/at-spi2-atk/2.0 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/at-spi-2.0 -isystem /usr/include/gtk-3.0/unix-print -isystem /usr/include/gstreamer-1.0 -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/orc-0.4 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCLPLUG_GTK_IMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/vcl/unx -I /home/maarten/src/libreoffice/core/vcl/unx/gtk3 -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -Wno-deprecated-declarations -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx

/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10#include <sal/config.h>
11
12#include <deque>
13#include <stack>
14#include <string.h>
15#include <osl/process.h>
16#include <unx/gtk/gtkdata.hxx>
17#include <unx/gtk/gtkinst.hxx>
18#include <unx/salobj.h>
19#include <unx/gtk/gtkgdi.hxx>
20#include <unx/gtk/gtkframe.hxx>
21#include <unx/gtk/gtkobject.hxx>
22#include <unx/gtk/atkbridge.hxx>
23#include <unx/gtk/gtkprn.hxx>
24#include <unx/gtk/gtksalmenu.hxx>
25#include <headless/svpvd.hxx>
26#include <headless/svpbmp.hxx>
27#include <vcl/inputtypes.hxx>
28#include <vcl/transfer.hxx>
29#include <unx/genpspgraphics.h>
30#include <rtl/strbuf.hxx>
31#include <sal/log.hxx>
32#include <rtl/uri.hxx>
33
34#include <vcl/settings.hxx>
35
36#include <dlfcn.h>
37#include <fcntl.h>
38#include <unistd.h>
39
40#include <unx/gtk/gtkprintwrapper.hxx>
41
42#include "a11y/atkwrapper.hxx"
43#include <com/sun/star/lang/IllegalArgumentException.hpp>
44#include <com/sun/star/lang/XMultiServiceFactory.hpp>
45#include <com/sun/star/lang/XServiceInfo.hpp>
46#include <com/sun/star/lang/XSingleServiceFactory.hpp>
47#include <com/sun/star/lang/XInitialization.hpp>
48#include <com/sun/star/datatransfer/XTransferable.hpp>
49#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
50#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
51#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
52#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
53#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
54#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp>
55#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
56#include <comphelper/lok.hxx>
57#include <comphelper/processfactory.hxx>
58#include <comphelper/sequence.hxx>
59#include <cppuhelper/compbase.hxx>
60#include <comphelper/string.hxx>
61#include <cppuhelper/implbase.hxx>
62#include <cppuhelper/supportsservice.hxx>
63#include <officecfg/Office/Common.hxx>
64#include <rtl/bootstrap.hxx>
65#include <o3tl/unreachable.hxx>
66#include <svl/zforlist.hxx>
67#include <svl/zformat.hxx>
68#include <tools/helpers.hxx>
69#include <tools/fract.hxx>
70#include <tools/stream.hxx>
71#include <unotools/resmgr.hxx>
72#include <unx/gstsink.hxx>
73#include <vcl/ImageTree.hxx>
74#include <vcl/abstdlg.hxx>
75#include <vcl/event.hxx>
76#include <vcl/i18nhelp.hxx>
77#include <vcl/quickselectionengine.hxx>
78#include <vcl/mnemonic.hxx>
79#include <vcl/pngwrite.hxx>
80#include <vcl/stdtext.hxx>
81#include <vcl/syswin.hxx>
82#include <vcl/virdev.hxx>
83#include <vcl/weld.hxx>
84#include <vcl/wrkwin.hxx>
85#include <strings.hrc>
86#include <window.h>
87#include <numeric>
88
89#include <boost/property_tree/ptree.hpp>
90
91using namespace com::sun::star;
92using namespace com::sun::star::uno;
93using namespace com::sun::star::lang;
94
95extern "C"
96{
97 #define GET_YIELD_MUTEX()static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance
->GetYieldMutex())
static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
98 static void GdkThreadsEnter()
99 {
100 GtkYieldMutex *pYieldMutex = GET_YIELD_MUTEX()static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance
->GetYieldMutex())
;
101 pYieldMutex->ThreadsEnter();
102 }
103 static void GdkThreadsLeave()
104 {
105 GtkYieldMutex *pYieldMutex = GET_YIELD_MUTEX()static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance
->GetYieldMutex())
;
106 pYieldMutex->ThreadsLeave();
107 }
108
109 VCLPLUG_GTK_PUBLIC__attribute__ ((visibility("default"))) SalInstance* create_SalInstance()
110 {
111 SAL_INFO(do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "create vcl plugin instance with gtk version " <<
gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
112 "vcl.gtk",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "create vcl plugin instance with gtk version " <<
gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
113 "create vcl plugin instance with gtk version " << gtk_major_versiondo { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "create vcl plugin instance with gtk version " <<
gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
114 << " " << gtk_minor_version << " " << gtk_micro_version)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "create vcl plugin instance with gtk version " <<
gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), (
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "create vcl plugin instance with gtk version "
<< gtk_get_major_version () << " " << gtk_get_minor_version
() << " " << gtk_get_micro_version ()), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"create vcl plugin instance with gtk version " << gtk_get_major_version
() << " " << gtk_get_minor_version () << " "
<< gtk_get_micro_version (); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "114" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
115
116 if (gtk_major_versiongtk_get_major_version () == 3 && gtk_minor_versiongtk_get_minor_version () < 18)
117 {
118 g_warning("require gtk >= 3.18 for theme expectations");
119 return nullptr;
120 }
121
122 // for gtk2 it is always built with X support, so this is always called
123 // for gtk3 it is normally built with X and Wayland support, if
124 // X is supported GDK_WINDOWING_X11 is defined and this is always
125 // called, regardless of if we're running under X or Wayland.
126 // We can't use (DLSYM_GDK_IS_X11_DISPLAY(pDisplay)) to only do it under
127 // X, because we need to do it earlier than we have a display
128#if defined(GDK_WINDOWING_X11)
129 /* #i92121# workaround deadlocks in the X11 implementation
130 */
131 static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
132 /* #i90094#
133 from now on we know that an X connection will be
134 established, so protect X against itself
135 */
136 if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
137 XInitThreads();
138#endif
139
140 // init gdk thread protection
141 bool const sup = g_thread_supported()(1);
142 // extracted from the 'if' to avoid Clang -Wunreachable-code
143 if ( !sup )
144 g_thread_init( nullptr );
145
146 gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
147 SAL_INFO("vcl.gtk", "Hooked gdk threads locks")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Hooked gdk threads locks"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "147" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Hooked gdk threads locks"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Hooked gdk threads locks"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "147" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Hooked gdk threads locks") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "147" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Hooked gdk threads locks"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"Hooked gdk threads locks"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "147" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
148
149 auto pYieldMutex = std::make_unique<GtkYieldMutex>();
150
151 gdk_threads_init();
152
153 GtkInstance* pInstance = new GtkInstance( std::move(pYieldMutex) );
154 SAL_INFO("vcl.gtk", "creating GtkInstance " << pInstance)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "creating GtkInstance "
<< pInstance) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "154" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "creating GtkInstance " << pInstance
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "creating GtkInstance " << pInstance; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "154" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "creating GtkInstance " << pInstance) == 1)
{ ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "154" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "creating GtkInstance " << pInstance
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "creating GtkInstance " << pInstance; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "154" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
155
156 // Create SalData, this does not leak
157 new GtkSalData( pInstance );
158
159 return pInstance;
160 }
161}
162
163static VclInputFlags categorizeEvent(const GdkEvent *pEvent)
164{
165 VclInputFlags nType = VclInputFlags::NONE;
166 switch( pEvent->type )
167 {
168 case GDK_MOTION_NOTIFY:
169 case GDK_BUTTON_PRESS:
170 case GDK_2BUTTON_PRESS:
171 case GDK_3BUTTON_PRESS:
172 case GDK_BUTTON_RELEASE:
173 case GDK_ENTER_NOTIFY:
174 case GDK_LEAVE_NOTIFY:
175 case GDK_SCROLL:
176 nType = VclInputFlags::MOUSE;
177 break;
178 case GDK_KEY_PRESS:
179 // case GDK_KEY_RELEASE: //similar to the X11SalInstance one
180 nType = VclInputFlags::KEYBOARD;
181 break;
182 case GDK_EXPOSE:
183 nType = VclInputFlags::PAINT;
184 break;
185 default:
186 nType = VclInputFlags::OTHER;
187 break;
188 }
189 return nType;
190}
191
192GtkInstance::GtkInstance( std::unique_ptr<SalYieldMutex> pMutex )
193 : SvpSalInstance( std::move(pMutex) )
194 , m_pTimer(nullptr)
195 , bNeedsInit(true)
196 , m_pLastCairoFontOptions(nullptr)
197{
198}
199
200//We want to defer initializing gtk until we are after uno has been
201//bootstrapped so we can ask the config what the UI language is so that we can
202//force that in as $LANGUAGE to get gtk to render widgets RTL if we have a RTL
203//UI in a LTR locale
204void GtkInstance::AfterAppInit()
205{
206 EnsureInit();
207}
208
209void GtkInstance::EnsureInit()
210{
211 if (!bNeedsInit)
212 return;
213 // initialize SalData
214 GtkSalData *pSalData = GetGtkSalData();
215 pSalData->Init();
216 GtkSalData::initNWF();
217
218 InitAtkBridge();
219
220 ImplSVData* pSVData = ImplGetSVData();
221#ifdef GTK_TOOLKIT_NAME
222 pSVData->maAppData.mxToolkitName = OUString(GTK_TOOLKIT_NAME);
223#else
224 pSVData->maAppData.mxToolkitName = OUString("gtk3");
225#endif
226
227 bNeedsInit = false;
228}
229
230GtkInstance::~GtkInstance()
231{
232 assert( nullptr == m_pTimer )(static_cast <bool> (nullptr == m_pTimer) ? void (0) : __assert_fail
("nullptr == m_pTimer", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 232, __extension__ __PRETTY_FUNCTION__))
;
233 DeInitAtkBridge();
234 ResetLastSeenCairoFontOptions(nullptr);
235}
236
237SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle )
238{
239 EnsureInit();
240 return new GtkSalFrame( pParent, nStyle );
241}
242
243SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, SalFrameStyleFlags )
244{
245 EnsureInit();
246 return new GtkSalFrame( pParentData );
247}
248
249SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow )
250{
251 EnsureInit();
252 //FIXME: Missing CreateObject functionality ...
253 if (pWindowData && pWindowData->bClipUsingNativeWidget)
254 return new GtkSalObjectWidgetClip(static_cast<GtkSalFrame*>(pParent), bShow);
255 return new GtkSalObject(static_cast<GtkSalFrame*>(pParent), bShow);
256}
257
258extern "C"
259{
260 typedef void*(* getDefaultFnc)();
261 typedef void(* addItemFnc)(void *, const char *);
262}
263
264void GtkInstance::AddToRecentDocumentList(const OUString& rFileUrl, const OUString&, const OUString&)
265{
266 EnsureInit();
267 OString sGtkURL;
268 rtl_TextEncoding aSystemEnc = osl_getThreadTextEncoding();
269 if ((aSystemEnc == RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))) || !rFileUrl.startsWith( "file://" ))
270 sGtkURL = OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
271 else
272 {
273 //Non-utf8 locales are a bad idea if trying to work with non-ascii filenames
274 //Decode %XX components
275 OUString sDecodedUri = rtl::Uri::decode(rFileUrl.copy(7), rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
276 //Convert back to system locale encoding
277 OString sSystemUrl = OUStringToOString(sDecodedUri, aSystemEnc);
278 //Encode to an escaped ASCII-encoded URI
279 gchar *g_uri = g_filename_to_uri(sSystemUrl.getStr(), nullptr, nullptr);
280 sGtkURL = OString(g_uri);
281 g_free(g_uri);
282 }
283 GtkRecentManager *manager = gtk_recent_manager_get_default ();
284 gtk_recent_manager_add_item (manager, sGtkURL.getStr());
285}
286
287SalInfoPrinter* GtkInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
288 ImplJobSetup* pSetupData )
289{
290 EnsureInit();
291 mbPrinterInit = true;
292 // create and initialize SalInfoPrinter
293 PspSalInfoPrinter* pPrinter = new GtkSalInfoPrinter;
294 configurePspInfoPrinter(pPrinter, pQueueInfo, pSetupData);
295 return pPrinter;
296}
297
298std::unique_ptr<SalPrinter> GtkInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
299{
300 EnsureInit();
301 mbPrinterInit = true;
302 return std::unique_ptr<SalPrinter>(new GtkSalPrinter( pInfoPrinter ));
303}
304
305/*
306 * These methods always occur in pairs
307 * A ThreadsEnter is followed by a ThreadsLeave
308 * We need to queue up the recursive lock count
309 * for each pair, so we can accurately restore
310 * it later.
311 */
312thread_local std::stack<sal_uInt32> GtkYieldMutex::yieldCounts;
313
314void GtkYieldMutex::ThreadsEnter()
315{
316 acquire();
317 if (!yieldCounts.empty()) {
318 auto n = yieldCounts.top();
319 yieldCounts.pop();
320 assert(n > 0)(static_cast <bool> (n > 0) ? void (0) : __assert_fail
("n > 0", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 320, __extension__ __PRETTY_FUNCTION__))
;
321 n--;
322 if (n > 0)
323 acquire(n);
324 }
325}
326
327void GtkYieldMutex::ThreadsLeave()
328{
329 assert(m_nCount != 0)(static_cast <bool> (m_nCount != 0) ? void (0) : __assert_fail
("m_nCount != 0", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 329, __extension__ __PRETTY_FUNCTION__))
;
330 yieldCounts.push(m_nCount);
331 release(true);
332}
333
334std::unique_ptr<SalVirtualDevice> GtkInstance::CreateVirtualDevice( SalGraphics *pG,
335 long &nDX, long &nDY,
336 DeviceFormat eFormat,
337 const SystemGraphicsData* pGd )
338{
339 EnsureInit();
340 SvpSalGraphics *pSvpSalGraphics = dynamic_cast<SvpSalGraphics*>(pG);
341 assert(pSvpSalGraphics)(static_cast <bool> (pSvpSalGraphics) ? void (0) : __assert_fail
("pSvpSalGraphics", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 341, __extension__ __PRETTY_FUNCTION__))
;
342 // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget
343 cairo_surface_t* pPreExistingTarget = pGd ? static_cast<cairo_surface_t*>(pGd->pSurface) : nullptr;
344 std::unique_ptr<SalVirtualDevice> pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget));
345 pNew->SetSize( nDX, nDY );
346 return pNew;
347}
348
349std::shared_ptr<SalBitmap> GtkInstance::CreateSalBitmap()
350{
351 EnsureInit();
352 return SvpSalInstance::CreateSalBitmap();
353}
354
355std::unique_ptr<SalMenu> GtkInstance::CreateMenu( bool bMenuBar, Menu* pVCLMenu )
356{
357 EnsureInit();
358 GtkSalMenu* pSalMenu = new GtkSalMenu( bMenuBar );
359 pSalMenu->SetMenu( pVCLMenu );
360 return std::unique_ptr<SalMenu>(pSalMenu);
361}
362
363std::unique_ptr<SalMenuItem> GtkInstance::CreateMenuItem( const SalItemParams & rItemData )
364{
365 EnsureInit();
366 return std::unique_ptr<SalMenuItem>(new GtkSalMenuItem( &rItemData ));
367}
368
369SalTimer* GtkInstance::CreateSalTimer()
370{
371 EnsureInit();
372 assert( nullptr == m_pTimer )(static_cast <bool> (nullptr == m_pTimer) ? void (0) : __assert_fail
("nullptr == m_pTimer", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 372, __extension__ __PRETTY_FUNCTION__))
;
373 if ( nullptr == m_pTimer )
374 m_pTimer = new GtkSalTimer();
375 return m_pTimer;
376}
377
378void GtkInstance::RemoveTimer ()
379{
380 EnsureInit();
381 m_pTimer = nullptr;
382}
383
384bool GtkInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
385{
386 EnsureInit();
387 return GetGtkSalData()->Yield( bWait, bHandleAllCurrentEvents );
388}
389
390bool GtkInstance::IsTimerExpired()
391{
392 EnsureInit();
393 return (m_pTimer && m_pTimer->Expired());
394}
395
396bool GtkInstance::AnyInput( VclInputFlags nType )
397{
398 EnsureInit();
399 if( (nType & VclInputFlags::TIMER) && IsTimerExpired() )
400 return true;
401 if (!gdk_events_pending())
402 return false;
403
404 if (nType == VCL_INPUT_ANY(VclInputFlags::MOUSE | VclInputFlags::KEYBOARD | VclInputFlags
::PAINT | VclInputFlags::TIMER | VclInputFlags::OTHER | VclInputFlags
::APPEVENT)
)
405 return true;
406
407 bool bRet = false;
408 std::deque<GdkEvent*> aEvents;
409 GdkEvent *pEvent = nullptr;
410 while ((pEvent = gdk_event_get()))
411 {
412 aEvents.push_back(pEvent);
413 VclInputFlags nEventType = categorizeEvent(pEvent);
414 if ( (nEventType & nType) || ( nEventType == VclInputFlags::NONE && (nType & VclInputFlags::OTHER) ) )
415 {
416 bRet = true;
417 }
418 }
419
420 while (!aEvents.empty())
421 {
422 pEvent = aEvents.front();
423 gdk_event_put(pEvent);
424 gdk_event_free(pEvent);
425 aEvents.pop_front();
426 }
427 return bRet;
428}
429
430std::unique_ptr<GenPspGraphics> GtkInstance::CreatePrintGraphics()
431{
432 EnsureInit();
433 return std::make_unique<GenPspGraphics>();
434}
435
436std::shared_ptr<vcl::unx::GtkPrintWrapper> const &
437GtkInstance::getPrintWrapper() const
438{
439 if (!m_xPrintWrapper)
440 m_xPrintWrapper = std::make_shared<vcl::unx::GtkPrintWrapper>();
441 return m_xPrintWrapper;
442}
443
444const cairo_font_options_t* GtkInstance::GetCairoFontOptions()
445{
446 const cairo_font_options_t* pCairoFontOptions = gdk_screen_get_font_options(gdk_screen_get_default());
447 if (!m_pLastCairoFontOptions && pCairoFontOptions)
448 m_pLastCairoFontOptions = cairo_font_options_copy(pCairoFontOptions);
449 return pCairoFontOptions;
450}
451
452const cairo_font_options_t* GtkInstance::GetLastSeenCairoFontOptions() const
453{
454 return m_pLastCairoFontOptions;
455}
456
457void GtkInstance::ResetLastSeenCairoFontOptions(const cairo_font_options_t* pCairoFontOptions)
458{
459 if (m_pLastCairoFontOptions)
460 cairo_font_options_destroy(m_pLastCairoFontOptions);
461 if (pCairoFontOptions)
462 m_pLastCairoFontOptions = cairo_font_options_copy(pCairoFontOptions);
463 else
464 m_pLastCairoFontOptions = nullptr;
465}
466
467
468namespace
469{
470 struct TypeEntry
471 {
472 const char* pNativeType; // string corresponding to nAtom for the case of nAtom being uninitialized
473 const char* pType; // Mime encoding on our side
474 };
475
476 const TypeEntry aConversionTab[] =
477 {
478 { "ISO10646-1", "text/plain;charset=utf-16" },
479 { "UTF8_STRING", "text/plain;charset=utf-8" },
480 { "UTF-8", "text/plain;charset=utf-8" },
481 { "text/plain;charset=UTF-8", "text/plain;charset=utf-8" },
482 // ISO encodings
483 { "ISO8859-2", "text/plain;charset=iso8859-2" },
484 { "ISO8859-3", "text/plain;charset=iso8859-3" },
485 { "ISO8859-4", "text/plain;charset=iso8859-4" },
486 { "ISO8859-5", "text/plain;charset=iso8859-5" },
487 { "ISO8859-6", "text/plain;charset=iso8859-6" },
488 { "ISO8859-7", "text/plain;charset=iso8859-7" },
489 { "ISO8859-8", "text/plain;charset=iso8859-8" },
490 { "ISO8859-9", "text/plain;charset=iso8859-9" },
491 { "ISO8859-10", "text/plain;charset=iso8859-10" },
492 { "ISO8859-13", "text/plain;charset=iso8859-13" },
493 { "ISO8859-14", "text/plain;charset=iso8859-14" },
494 { "ISO8859-15", "text/plain;charset=iso8859-15" },
495 // asian encodings
496 { "JISX0201.1976-0", "text/plain;charset=jisx0201.1976-0" },
497 { "JISX0208.1983-0", "text/plain;charset=jisx0208.1983-0" },
498 { "JISX0208.1990-0", "text/plain;charset=jisx0208.1990-0" },
499 { "JISX0212.1990-0", "text/plain;charset=jisx0212.1990-0" },
500 { "GB2312.1980-0", "text/plain;charset=gb2312.1980-0" },
501 { "KSC5601.1992-0", "text/plain;charset=ksc5601.1992-0" },
502 // eastern european encodings
503 { "KOI8-R", "text/plain;charset=koi8-r" },
504 { "KOI8-U", "text/plain;charset=koi8-u" },
505 // String (== iso8859-1)
506 { "STRING", "text/plain;charset=iso8859-1" },
507 // special for compound text
508 { "COMPOUND_TEXT", "text/plain;charset=compound_text" },
509
510 // PIXMAP
511 { "PIXMAP", "image/bmp" }
512 };
513
514 class DataFlavorEq
515 {
516 private:
517 const css::datatransfer::DataFlavor& m_rData;
518 public:
519 explicit DataFlavorEq(const css::datatransfer::DataFlavor& rData) : m_rData(rData) {}
520 bool operator() (const css::datatransfer::DataFlavor& rData) const
521 {
522 return rData.MimeType == m_rData.MimeType &&
523 rData.DataType == m_rData.DataType;
524 }
525 };
526}
527
528std::vector<css::datatransfer::DataFlavor> GtkTransferable::getTransferDataFlavorsAsVector(GdkAtom *targets, gint n_targets)
529{
530 std::vector<css::datatransfer::DataFlavor> aVector;
531
532 bool bHaveText = false, bHaveUTF16 = false;
533
534 for (gint i = 0; i < n_targets; ++i)
535 {
536 gchar* pName = gdk_atom_name(targets[i]);
537 const char* pFinalName = pName;
538 css::datatransfer::DataFlavor aFlavor;
539
540 // omit text/plain;charset=unicode since it is not well defined
541 if (rtl_str_compare(pName, "text/plain;charset=unicode") == 0)
542 {
543 g_free(pName);
544 continue;
545 }
546
547 for (size_t j = 0; j < SAL_N_ELEMENTS(aConversionTab)(sizeof(sal_n_array_size(aConversionTab))); ++j)
548 {
549 if (rtl_str_compare(pName, aConversionTab[j].pNativeType) == 0)
550 {
551 pFinalName = aConversionTab[j].pType;
552 break;
553 }
554 }
555
556 // There are more non-MIME-types reported that are not translated by
557 // aConversionTab, like "SAVE_TARGETS", "INTEGER", "ATOM"; just filter
558 // them out for now before they confuse this code's clients:
559 if (rtl_str_indexOfChar(pFinalName, '/') == -1)
560 {
561 g_free(pName);
562 continue;
563 }
564
565 aFlavor.MimeType = OUString(pFinalName,
566 strlen(pFinalName),
567 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
568
569 m_aMimeTypeToAtom[aFlavor.MimeType] = targets[i];
570
571 aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
572
573 sal_Int32 nIndex(0);
574 if (aFlavor.MimeType.getToken(0, ';', nIndex) == "text/plain")
575 {
576 bHaveText = true;
577 OUString aToken(aFlavor.MimeType.getToken(0, ';', nIndex));
578 if (aToken == "charset=utf-16")
579 {
580 bHaveUTF16 = true;
581 aFlavor.DataType = cppu::UnoType<OUString>::get();
582 }
583 }
584 aVector.push_back(aFlavor);
585 g_free(pName);
586 }
587
588 //If we have text, but no UTF-16 format which is basically the only
589 //text-format LibreOffice supports for cnp then claim we do and we
590 //will convert on demand
591 if (bHaveText && !bHaveUTF16)
592 {
593 css::datatransfer::DataFlavor aFlavor;
594 aFlavor.MimeType = "text/plain;charset=utf-16";
595 aFlavor.DataType = cppu::UnoType<OUString>::get();
596 aVector.push_back(aFlavor);
597 }
598
599 return aVector;
600}
601
602
603css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL GtkTransferable::getTransferDataFlavors()
604{
605 return comphelper::containerToSequence(getTransferDataFlavorsAsVector());
606}
607
608sal_Bool SAL_CALL GtkTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor)
609{
610 const std::vector<css::datatransfer::DataFlavor> aAll =
611 getTransferDataFlavorsAsVector();
612
613 return std::any_of(aAll.begin(), aAll.end(), DataFlavorEq(rFlavor));
614}
615
616namespace {
617
618class GtkClipboardTransferable : public GtkTransferable
619{
620private:
621 GdkAtom m_nSelection;
622public:
623
624 explicit GtkClipboardTransferable(GdkAtom nSelection)
625 : m_nSelection(nSelection)
626 {
627 }
628
629 /*
630 * XTransferable
631 */
632
633 virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override
634 {
635 GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
636 if (rFlavor.MimeType == "text/plain;charset=utf-16")
637 {
638 OUString aStr;
639 gchar *pText = gtk_clipboard_wait_for_text(clipboard);
640 if (pText)
641 aStr = OUString(pText, strlen(pText), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
642 g_free(pText);
643 css::uno::Any aRet;
644 aRet <<= aStr.replaceAll("\r\n", "\n");
645 return aRet;
646 }
647
648 auto it = m_aMimeTypeToAtom.find(rFlavor.MimeType);
649 if (it == m_aMimeTypeToAtom.end())
650 return css::uno::Any();
651
652 css::uno::Any aRet;
653 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
654 it->second);
655 if (!data)
656 {
657 return css::uno::Any();
658 }
659 gint length;
660 const guchar *rawdata = gtk_selection_data_get_data_with_length(data,
661 &length);
662 Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(rawdata), length);
663 gtk_selection_data_free(data);
664 aRet <<= aSeq;
665 return aRet;
666 }
667
668 std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector()
669 override
670 {
671 std::vector<css::datatransfer::DataFlavor> aVector;
672
673 GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
674
675 GdkAtom *targets;
676 gint n_targets;
677 if (gtk_clipboard_wait_for_targets(clipboard, &targets, &n_targets))
678 {
679 aVector = GtkTransferable::getTransferDataFlavorsAsVector(targets, n_targets);
680 g_free(targets);
681 }
682
683 return aVector;
684 }
685};
686
687class VclGtkClipboard :
688 public cppu::WeakComponentImplHelper<
689 datatransfer::clipboard::XSystemClipboard,
690 datatransfer::clipboard::XFlushableClipboard,
691 XServiceInfo>
692{
693 GdkAtom m_nSelection;
694 osl::Mutex m_aMutex;
695 gulong m_nOwnerChangedSignalId;
696 Reference<css::datatransfer::XTransferable> m_aContents;
697 Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
698 std::vector< Reference<css::datatransfer::clipboard::XClipboardListener> > m_aListeners;
699 std::vector<GtkTargetEntry> m_aGtkTargets;
700 VclToGtkHelper m_aConversionHelper;
701
702public:
703
704 explicit VclGtkClipboard(GdkAtom nSelection);
705 virtual ~VclGtkClipboard() override;
706
707 /*
708 * XServiceInfo
709 */
710
711 virtual OUString SAL_CALL getImplementationName() override;
712 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
713 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
714
715 /*
716 * XClipboard
717 */
718
719 virtual Reference< css::datatransfer::XTransferable > SAL_CALL getContents() override;
720
721 virtual void SAL_CALL setContents(
722 const Reference< css::datatransfer::XTransferable >& xTrans,
723 const Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner ) override;
724
725 virtual OUString SAL_CALL getName() override;
726
727 /*
728 * XClipboardEx
729 */
730
731 virtual sal_Int8 SAL_CALL getRenderingCapabilities() override;
732
733 /*
734 * XFlushableClipboard
735 */
736 virtual void SAL_CALL flushClipboard() override;
737
738 /*
739 * XClipboardNotifier
740 */
741 virtual void SAL_CALL addClipboardListener(
742 const Reference< css::datatransfer::clipboard::XClipboardListener >& listener ) override;
743
744 virtual void SAL_CALL removeClipboardListener(
745 const Reference< css::datatransfer::clipboard::XClipboardListener >& listener ) override;
746
747 void ClipboardGet(GtkSelectionData *selection_data, guint info);
748 void ClipboardClear();
749 void OwnerPossiblyChanged(GtkClipboard *clipboard);
750};
751
752}
753
754OUString VclGtkClipboard::getImplementationName()
755{
756 return "com.sun.star.datatransfer.VclGtkClipboard";
757}
758
759Sequence< OUString > VclGtkClipboard::getSupportedServiceNames()
760{
761 Sequence<OUString> aRet { "com.sun.star.datatransfer.clipboard.SystemClipboard" };
762 return aRet;
763}
764
765sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName )
766{
767 return cppu::supportsService(this, ServiceName);
768}
769
770Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents()
771{
772 if (!m_aContents.is())
773 {
774 //tdf#93887 This is the system clipboard/selection. We fetch it when we are not
775 //the owner of the clipboard and have not already fetched it.
776 m_aContents = new GtkClipboardTransferable(m_nSelection);
777 }
778
779 return m_aContents;
780}
781
782void VclGtkClipboard::ClipboardGet(GtkSelectionData *selection_data, guint info)
783{
784 if (!m_aContents.is())
785 return;
786 // tdf#129809 take a reference in case m_aContents is replaced during this
787 // call
788 Reference<datatransfer::XTransferable> xCurrentContents(m_aContents);
789 m_aConversionHelper.setSelectionData(xCurrentContents, selection_data, info);
790}
791
792namespace
793{
794 const OString& getPID()
795 {
796 static OString sPID;
797 if (!sPID.getLength())
798 {
799 oslProcessIdentifier aProcessId = 0;
800 oslProcessInfo info;
801 info.Size = sizeof (oslProcessInfo);
802 if (osl_getProcessInfo(nullptr, osl_Process_IDENTIFIER0x0001, &info) == osl_Process_E_None)
803 aProcessId = info.Ident;
804 sPID = OString::number(aProcessId);
805 }
806 return sPID;
807 }
808}
809
810namespace
811{
812 void ClipboardGetFunc(GtkClipboard* /*clipboard*/, GtkSelectionData *selection_data,
813 guint info,
814 gpointer user_data_or_owner)
815 {
816 VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data_or_owner);
817 pThis->ClipboardGet(selection_data, info);
818 }
819
820 void ClipboardClearFunc(GtkClipboard* /*clipboard*/, gpointer user_data_or_owner)
821 {
822 VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data_or_owner);
823 pThis->ClipboardClear();
824 }
825
826 void handle_owner_change(GtkClipboard *clipboard, GdkEvent* /*event*/, gpointer user_data)
827 {
828 VclGtkClipboard* pThis = static_cast<VclGtkClipboard*>(user_data);
829 pThis->OwnerPossiblyChanged(clipboard);
830 }
831}
832
833void VclGtkClipboard::OwnerPossiblyChanged(GtkClipboard* clipboard)
834{
835 if (!m_aContents.is())
836 return;
837
838 //if gdk_display_supports_selection_notification is not supported, e.g. like
839 //right now under wayland, then you only get owner-changed notifications at
840 //opportune times when the selection might have changed. So here
841 //we see if the selection supports a dummy selection type identifying
842 //our pid, in which case it's us.
843 bool bSelf = false;
844
845 //disconnect and reconnect after gtk_clipboard_wait_for_targets to
846 //avoid possible recursion
847 g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
848
849 OString sTunnel = "application/x-libreoffice-internal-id-" + getPID();
850 GdkAtom *targets;
851 gint n_targets;
852 if (gtk_clipboard_wait_for_targets(clipboard, &targets, &n_targets))
853 {
854 for (gint i = 0; i < n_targets && !bSelf; ++i)
855 {
856 gchar* pName = gdk_atom_name(targets[i]);
857 if (strcmp(pName, sTunnel.getStr()) == 0)
858 {
859 bSelf = true;
860 }
861 g_free(pName);
862 }
863
864 g_free(targets);
865 }
866
867 m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",g_signal_connect_data ((clipboard), ("owner-change"), (((GCallback
) (handle_owner_change))), (this), __null, (GConnectFlags) 0)
868 G_CALLBACK(handle_owner_change), this)g_signal_connect_data ((clipboard), ("owner-change"), (((GCallback
) (handle_owner_change))), (this), __null, (GConnectFlags) 0)
;
869
870 if (!bSelf)
871 {
872 //null out m_aContents to return control to the system-one which
873 //will be retrieved if getContents is called again
874 setContents(Reference<css::datatransfer::XTransferable>(),
875 Reference<css::datatransfer::clipboard::XClipboardOwner>());
876 }
877}
878
879void VclGtkClipboard::ClipboardClear()
880{
881 for (auto &a : m_aGtkTargets)
882 g_free(a.target);
883 m_aGtkTargets.clear();
884}
885
886GtkTargetEntry VclToGtkHelper::makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor)
887{
888 GtkTargetEntry aEntry;
889 aEntry.target =
890 g_strdup(OUStringToOString(rFlavor.MimeType, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
891 aEntry.flags = 0;
892 auto it = std::find_if(aInfoToFlavor.begin(), aInfoToFlavor.end(),
893 DataFlavorEq(rFlavor));
894 if (it != aInfoToFlavor.end())
895 aEntry.info = std::distance(aInfoToFlavor.begin(), it);
896 else
897 {
898 aEntry.info = aInfoToFlavor.size();
899 aInfoToFlavor.push_back(rFlavor);
900 }
901 return aEntry;
902}
903
904void VclToGtkHelper::setSelectionData(const Reference<css::datatransfer::XTransferable> &rTrans,
905 GtkSelectionData *selection_data, guint info)
906{
907 GdkAtom type(gdk_atom_intern(OUStringToOString(aInfoToFlavor[info].MimeType,
908 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
909 false));
910
911 css::datatransfer::DataFlavor aFlavor(aInfoToFlavor[info]);
912 if (aFlavor.MimeType == "UTF8_STRING" || aFlavor.MimeType == "STRING")
913 aFlavor.MimeType = "text/plain;charset=utf-8";
914
915 Sequence<sal_Int8> aData;
916 Any aValue;
917
918 try
919 {
920 aValue = rTrans->getTransferData(aFlavor);
921 }
922 catch (...)
923 {
924 }
925
926 if (aValue.getValueTypeClass() == TypeClass_STRING)
927 {
928 OUString aString;
929 aValue >>= aString;
930 aData = Sequence< sal_Int8 >( reinterpret_cast<sal_Int8 const *>(aString.getStr()), aString.getLength() * sizeof( sal_Unicode ) );
931 }
932 else if (aValue.getValueType() == cppu::UnoType<Sequence< sal_Int8 >>::get())
933 {
934 aValue >>= aData;
935 }
936 else if (aFlavor.MimeType == "text/plain;charset=utf-8")
937 {
938 //didn't have utf-8, try utf-16 and convert
939 aFlavor.MimeType = "text/plain;charset=utf-16";
940 aFlavor.DataType = cppu::UnoType<OUString>::get();
941 try
942 {
943 aValue = rTrans->getTransferData(aFlavor);
944 }
945 catch (...)
946 {
947 }
948 OUString aString;
949 aValue >>= aString;
950 OString aUTF8String(OUStringToOString(aString, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
951 gtk_selection_data_set(selection_data, type, 8,
952 reinterpret_cast<const guchar *>(aUTF8String.getStr()),
953 aUTF8String.getLength());
954 return;
955 }
956
957 gtk_selection_data_set(selection_data, type, 8,
958 reinterpret_cast<const guchar *>(aData.getArray()),
959 aData.getLength());
960}
961
962VclGtkClipboard::VclGtkClipboard(GdkAtom nSelection)
963 : cppu::WeakComponentImplHelper<datatransfer::clipboard::XSystemClipboard,
964 datatransfer::clipboard::XFlushableClipboard, XServiceInfo>
965 (m_aMutex)
966 , m_nSelection(nSelection)
967{
968 GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
969 m_nOwnerChangedSignalId = g_signal_connect(clipboard, "owner-change",g_signal_connect_data ((clipboard), ("owner-change"), (((GCallback
) (handle_owner_change))), (this), __null, (GConnectFlags) 0)
970 G_CALLBACK(handle_owner_change), this)g_signal_connect_data ((clipboard), ("owner-change"), (((GCallback
) (handle_owner_change))), (this), __null, (GConnectFlags) 0)
;
971}
972
973void VclGtkClipboard::flushClipboard()
974{
975 SolarMutexGuard aGuard;
976
977 if (GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))) != m_nSelection)
978 return;
979
980 GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
981 gtk_clipboard_store(clipboard);
982}
983
984VclGtkClipboard::~VclGtkClipboard()
985{
986 GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
987 g_signal_handler_disconnect(clipboard, m_nOwnerChangedSignalId);
988 if (!m_aGtkTargets.empty())
989 {
990 gtk_clipboard_clear(clipboard);
991 ClipboardClear();
992 }
993 assert(m_aGtkTargets.empty())(static_cast <bool> (m_aGtkTargets.empty()) ? void (0) :
__assert_fail ("m_aGtkTargets.empty()", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 993, __extension__ __PRETTY_FUNCTION__))
;
994}
995
996std::vector<GtkTargetEntry> VclToGtkHelper::FormatsToGtk(const css::uno::Sequence<css::datatransfer::DataFlavor> &rFormats)
997{
998 std::vector<GtkTargetEntry> aGtkTargets;
999
1000 bool bHaveText(false), bHaveUTF8(false);
1001 for (const css::datatransfer::DataFlavor& rFlavor : rFormats)
1002 {
1003 sal_Int32 nIndex(0);
1004 if (rFlavor.MimeType.getToken(0, ';', nIndex) == "text/plain")
1005 {
1006 bHaveText = true;
1007 OUString aToken(rFlavor.MimeType.getToken(0, ';', nIndex));
1008 if (aToken == "charset=utf-8")
1009 {
1010 bHaveUTF8 = true;
1011 }
1012 }
1013 GtkTargetEntry aEntry(makeGtkTargetEntry(rFlavor));
1014 aGtkTargets.push_back(aEntry);
1015 }
1016
1017 if (bHaveText)
1018 {
1019 css::datatransfer::DataFlavor aFlavor;
1020 aFlavor.DataType = cppu::UnoType<Sequence< sal_Int8 >>::get();
1021 if (!bHaveUTF8)
1022 {
1023 aFlavor.MimeType = "text/plain;charset=utf-8";
1024 aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
1025 }
1026 aFlavor.MimeType = "UTF8_STRING";
1027 aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
1028 aFlavor.MimeType = "STRING";
1029 aGtkTargets.push_back(makeGtkTargetEntry(aFlavor));
1030 }
1031
1032 return aGtkTargets;
1033}
1034
1035void VclGtkClipboard::setContents(
1036 const Reference< css::datatransfer::XTransferable >& xTrans,
1037 const Reference< css::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
1038{
1039 css::uno::Sequence<css::datatransfer::DataFlavor> aFormats;
1040 if (xTrans.is())
1041 {
1042 aFormats = xTrans->getTransferDataFlavors();
1043 }
1044
1045 osl::ClearableMutexGuard aGuard( m_aMutex );
1046 Reference< datatransfer::clipboard::XClipboardOwner > xOldOwner( m_aOwner );
1047 Reference< datatransfer::XTransferable > xOldContents( m_aContents );
1048 m_aContents = xTrans;
1049 m_aOwner = xClipboardOwner;
1050
1051 std::vector< Reference< datatransfer::clipboard::XClipboardListener > > aListeners( m_aListeners );
1052 datatransfer::clipboard::ClipboardEvent aEv;
1053
1054 GtkClipboard* clipboard = gtk_clipboard_get(m_nSelection);
1055 if (!m_aGtkTargets.empty())
1056 {
1057 gtk_clipboard_clear(clipboard);
1058 ClipboardClear();
1059 }
1060 assert(m_aGtkTargets.empty())(static_cast <bool> (m_aGtkTargets.empty()) ? void (0) :
__assert_fail ("m_aGtkTargets.empty()", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 1060, __extension__ __PRETTY_FUNCTION__))
;
1061 if (m_aContents.is())
1062 {
1063 std::vector<GtkTargetEntry> aGtkTargets(m_aConversionHelper.FormatsToGtk(aFormats));
1064 if (!aGtkTargets.empty())
1065 {
1066 GtkTargetEntry aEntry;
1067 OString sTunnel = "application/x-libreoffice-internal-id-" + getPID();
1068 aEntry.target = g_strdup(sTunnel.getStr());
1069 aEntry.flags = 0;
1070 aEntry.info = 0;
1071 aGtkTargets.push_back(aEntry);
1072
1073 gtk_clipboard_set_with_data(clipboard, aGtkTargets.data(), aGtkTargets.size(),
1074 ClipboardGetFunc, ClipboardClearFunc, this);
1075 gtk_clipboard_set_can_store(clipboard, aGtkTargets.data(), aGtkTargets.size());
1076 }
1077
1078 m_aGtkTargets = aGtkTargets;
1079 }
1080
1081 aEv.Contents = getContents();
1082
1083 aGuard.clear();
1084
1085 if (xOldOwner.is() && xOldOwner != xClipboardOwner)
1086 xOldOwner->lostOwnership( this, xOldContents );
1087 for (auto const& listener : aListeners)
1088 {
1089 listener->changedContents( aEv );
1090 }
1091}
1092
1093OUString VclGtkClipboard::getName()
1094{
1095 return (m_nSelection == GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69)))) ? OUString("CLIPBOARD") : OUString("PRIMARY");
1096}
1097
1098sal_Int8 VclGtkClipboard::getRenderingCapabilities()
1099{
1100 return 0;
1101}
1102
1103void VclGtkClipboard::addClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
1104{
1105 osl::ClearableMutexGuard aGuard( m_aMutex );
1106
1107 m_aListeners.push_back( listener );
1108}
1109
1110void VclGtkClipboard::removeClipboardListener( const Reference< datatransfer::clipboard::XClipboardListener >& listener )
1111{
1112 osl::ClearableMutexGuard aGuard( m_aMutex );
1113
1114 m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener), m_aListeners.end());
1115}
1116
1117Reference< XInterface > GtkInstance::CreateClipboard(const Sequence< Any >& arguments)
1118{
1119 OUString sel;
1120 if (!arguments.hasElements()) {
1121 sel = "CLIPBOARD";
1122 } else if (arguments.getLength() != 1 || !(arguments[0] >>= sel)) {
1123 throw css::lang::IllegalArgumentException(
1124 "bad GtkInstance::CreateClipboard arguments",
1125 css::uno::Reference<css::uno::XInterface>(), -1);
1126 }
1127
1128 GdkAtom nSelection = (sel == "CLIPBOARD") ? GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))) : GDK_SELECTION_PRIMARY((GdkAtom)((gpointer) (gulong) (1)));
1129
1130 auto it = m_aClipboards.find(nSelection);
1131 if (it != m_aClipboards.end())
1132 return it->second;
1133
1134 Reference<XInterface> xClipboard(static_cast<cppu::OWeakObject *>(new VclGtkClipboard(nSelection)));
1135 m_aClipboards[nSelection] = xClipboard;
1136
1137 return xClipboard;
1138}
1139
1140GtkDropTarget::GtkDropTarget()
1141 : WeakComponentImplHelper(m_aMutex)
1142 , m_pFrame(nullptr)
1143 , m_pFormatConversionRequest(nullptr)
1144 , m_bActive(false)
1145 , m_bInDrag(false)
1146 , m_nDefaultActions(0)
1147{
1148}
1149
1150OUString SAL_CALL GtkDropTarget::getImplementationName()
1151{
1152 return "com.sun.star.datatransfer.dnd.VclGtkDropTarget";
1153}
1154
1155sal_Bool SAL_CALL GtkDropTarget::supportsService(OUString const & ServiceName)
1156{
1157 return cppu::supportsService(this, ServiceName);
1158}
1159
1160css::uno::Sequence<OUString> SAL_CALL GtkDropTarget::getSupportedServiceNames()
1161{
1162 Sequence<OUString> aRet { "com.sun.star.datatransfer.dnd.GtkDropTarget" };
1163 return aRet;
1164}
1165
1166GtkDropTarget::~GtkDropTarget()
1167{
1168 if (m_pFrame)
1169 m_pFrame->deregisterDropTarget(this);
1170}
1171
1172void GtkDropTarget::deinitialize()
1173{
1174 m_pFrame = nullptr;
1175 m_bActive = false;
1176}
1177
1178void GtkDropTarget::initialize(const Sequence<Any>& rArguments)
1179{
1180 if (rArguments.getLength() < 2)
1181 {
1182 throw RuntimeException("DropTarget::initialize: Cannot install window event handler",
1183 static_cast<OWeakObject*>(this));
1184 }
1185
1186 sal_IntPtr nFrame = 0;
1187 rArguments.getConstArray()[1] >>= nFrame;
1188
1189 if (!nFrame)
1190 {
1191 throw RuntimeException("DropTarget::initialize: missing SalFrame",
1192 static_cast<OWeakObject*>(this));
1193 }
1194
1195 m_pFrame = reinterpret_cast<GtkSalFrame*>(nFrame);
1196 m_pFrame->registerDropTarget(this);
1197 m_bActive = true;
1198}
1199
1200void GtkDropTarget::addDropTargetListener( const Reference< css::datatransfer::dnd::XDropTargetListener >& xListener)
1201{
1202 ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
1203
1204 m_aListeners.push_back( xListener );
1205}
1206
1207void GtkDropTarget::removeDropTargetListener( const Reference< css::datatransfer::dnd::XDropTargetListener >& xListener)
1208{
1209 ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
1210
1211 m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), m_aListeners.end());
1212}
1213
1214void GtkDropTarget::fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde)
1215{
1216 osl::ClearableGuard<osl::Mutex> aGuard( m_aMutex );
1217 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1218 aGuard.clear();
1219
1220 for (auto const& listener : aListeners)
1221 {
1222 listener->drop( dtde );
1223 }
1224}
1225
1226void GtkDropTarget::fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde)
1227{
1228 osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
1229 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1230 aGuard.clear();
1231
1232 for (auto const& listener : aListeners)
1233 {
1234 listener->dragEnter( dtde );
1235 }
1236}
1237
1238void GtkDropTarget::fire_dragOver(const css::datatransfer::dnd::DropTargetDragEvent& dtde)
1239{
1240 osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
1241 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1242 aGuard.clear();
1243
1244 for (auto const& listener : aListeners)
1245 {
1246 listener->dragOver( dtde );
1247 }
1248}
1249
1250void GtkDropTarget::fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte)
1251{
1252 osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
1253 std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(m_aListeners);
1254 aGuard.clear();
1255
1256 for (auto const& listener : aListeners)
1257 {
1258 listener->dragExit( dte );
1259 }
1260}
1261
1262sal_Bool GtkDropTarget::isActive()
1263{
1264 return m_bActive;
1265}
1266
1267void GtkDropTarget::setActive(sal_Bool bActive)
1268{
1269 m_bActive = bActive;
1270}
1271
1272sal_Int8 GtkDropTarget::getDefaultActions()
1273{
1274 return m_nDefaultActions;
1275}
1276
1277void GtkDropTarget::setDefaultActions(sal_Int8 nDefaultActions)
1278{
1279 m_nDefaultActions = nDefaultActions;
1280}
1281
1282Reference< XInterface > GtkInstance::CreateDropTarget()
1283{
1284 return Reference<XInterface>(static_cast<cppu::OWeakObject*>(new GtkDropTarget));
1285}
1286
1287GtkDragSource::~GtkDragSource()
1288{
1289 if (m_pFrame)
1290 m_pFrame->deregisterDragSource(this);
1291
1292 if (GtkDragSource::g_ActiveDragSource == this)
1293 {
1294 SAL_WARN( "vcl.gtk", "dragEnd should have been called on GtkDragSource before dtor")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "dragEnd should have been called on GtkDragSource before dtor"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1294" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "dragEnd should have been called on GtkDragSource before dtor"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "dragEnd should have been called on GtkDragSource before dtor"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1294" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "dragEnd should have been called on GtkDragSource before dtor"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1294" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "dragEnd should have been called on GtkDragSource before dtor"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "dragEnd should have been called on GtkDragSource before dtor"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1294" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1295 GtkDragSource::g_ActiveDragSource = nullptr;
1296 }
1297}
1298
1299void GtkDragSource::deinitialize()
1300{
1301 m_pFrame = nullptr;
1302}
1303
1304sal_Bool GtkDragSource::isDragImageSupported()
1305{
1306 return true;
1307}
1308
1309sal_Int32 GtkDragSource::getDefaultCursor( sal_Int8 )
1310{
1311 return 0;
1312}
1313
1314void GtkDragSource::initialize(const css::uno::Sequence<css::uno::Any >& rArguments)
1315{
1316 if (rArguments.getLength() < 2)
1317 {
1318 throw RuntimeException("DragSource::initialize: Cannot install window event handler",
1319 static_cast<OWeakObject*>(this));
1320 }
1321
1322 sal_IntPtr nFrame = 0;
1323 rArguments.getConstArray()[1] >>= nFrame;
1324
1325 if (!nFrame)
1326 {
1327 throw RuntimeException("DragSource::initialize: missing SalFrame",
1328 static_cast<OWeakObject*>(this));
1329 }
1330
1331 m_pFrame = reinterpret_cast<GtkSalFrame*>(nFrame);
1332 m_pFrame->registerDragSource(this);
1333}
1334
1335OUString SAL_CALL GtkDragSource::getImplementationName()
1336{
1337 return "com.sun.star.datatransfer.dnd.VclGtkDragSource";
1338}
1339
1340sal_Bool SAL_CALL GtkDragSource::supportsService(OUString const & ServiceName)
1341{
1342 return cppu::supportsService(this, ServiceName);
1343}
1344
1345css::uno::Sequence<OUString> SAL_CALL GtkDragSource::getSupportedServiceNames()
1346{
1347 Sequence<OUString> aRet { "com.sun.star.datatransfer.dnd.GtkDragSource" };
1348 return aRet;
1349}
1350
1351Reference< XInterface > GtkInstance::CreateDragSource()
1352{
1353 return Reference< XInterface >( static_cast<cppu::OWeakObject *>(new GtkDragSource()) );
1354}
1355
1356namespace {
1357
1358class GtkOpenGLContext : public OpenGLContext
1359{
1360 GLWindow m_aGLWin;
1361 GtkWidget *m_pGLArea;
1362 GdkGLContext *m_pContext;
1363 guint m_nAreaFrameBuffer;
1364 guint m_nFrameBuffer;
1365 guint m_nRenderBuffer;
1366 guint m_nDepthBuffer;
1367 guint m_nFrameScratchBuffer;
1368 guint m_nRenderScratchBuffer;
1369 guint m_nDepthScratchBuffer;
1370
1371public:
1372 GtkOpenGLContext()
1373 : OpenGLContext()
1374 , m_pGLArea(nullptr)
1375 , m_pContext(nullptr)
1376 , m_nAreaFrameBuffer(0)
1377 , m_nFrameBuffer(0)
1378 , m_nRenderBuffer(0)
1379 , m_nDepthBuffer(0)
1380 , m_nFrameScratchBuffer(0)
1381 , m_nRenderScratchBuffer(0)
1382 , m_nDepthScratchBuffer(0)
1383 {
1384 }
1385
1386 virtual void initWindow() override
1387 {
1388 if( !m_pChildWindow )
1389 {
1390 SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext);
1391 m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
1392 }
1393
1394 if (m_pChildWindow)
1395 {
1396 InitChildWindow(m_pChildWindow.get());
1397 }
1398 }
1399
1400private:
1401 virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
1402 virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
1403
1404 static void signalDestroy(GtkWidget*, gpointer context)
1405 {
1406 GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(context);
1407 pThis->m_pGLArea = nullptr;
1408 }
1409
1410 static gboolean signalRender(GtkGLArea*, GdkGLContext*, gpointer window)
1411 {
1412 GtkOpenGLContext* pThis = static_cast<GtkOpenGLContext*>(window);
1413
1414 int scale = gtk_widget_get_scale_factor(pThis->m_pGLArea);
1415 int width = pThis->m_aGLWin.Width * scale;
1416 int height = pThis->m_aGLWin.Height * scale;
1417
1418 glDrawBufferepoxy_glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT0x8CE0);
1419
1420 glBindFramebufferepoxy_glBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, pThis->m_nAreaFrameBuffer);
1421 glReadBufferepoxy_glReadBuffer(GL_COLOR_ATTACHMENT0_EXT0x8CE0);
1422
1423 glBlitFramebufferepoxy_glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
1424 GL_COLOR_BUFFER_BIT0x00004000 | GL_DEPTH_BUFFER_BIT0x00000100, GL_NEAREST0x2600);
1425
1426 gdk_gl_context_make_current(pThis->m_pContext);
1427 return true;
1428 }
1429
1430 virtual void adjustToNewSize() override
1431 {
1432 if (!m_pGLArea)
1433 return;
1434
1435 int scale = gtk_widget_get_scale_factor(m_pGLArea);
1436 int width = m_aGLWin.Width * scale;
1437 int height = m_aGLWin.Height * scale;
1438
1439 // seen in tdf#124729 width/height of 0 leading to GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
1440 int allocwidth = std::max(width, 1);
1441 int allocheight = std::max(height, 1);
1442
1443 gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
);
1444 if (GError *pError = gtk_gl_area_get_error(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
))
1445 {
1446 SAL_WARN("vcl.gtk", "gtk gl area error: " << pError->message)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "gtk gl area error: "
<< pError->message) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1446" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "gtk gl area error: " << pError
->message), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "gtk gl area error: " << pError
->message; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1446" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "gtk gl area error: " << pError->message
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1446" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "gtk gl area error: " << pError
->message), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "gtk gl area error: " << pError
->message; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1446" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1447 return;
1448 }
1449
1450 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nRenderBuffer);
1451 glRenderbufferStorageepoxy_glRenderbufferStorage(GL_RENDERBUFFER0x8D41, GL_RGB80x8051, allocwidth, allocheight);
1452 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nDepthBuffer);
1453 glRenderbufferStorageepoxy_glRenderbufferStorage(GL_RENDERBUFFER0x8D41, GL_DEPTH_COMPONENT240x81A6, allocwidth, allocheight);
1454 glBindFramebufferEXTepoxy_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT0x8D40, m_nAreaFrameBuffer);
1455
1456 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
1457 GL_RENDERBUFFER_EXT0x8D41, m_nRenderBuffer);
1458 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_DEPTH_ATTACHMENT_EXT0x8D00,
1459 GL_RENDERBUFFER_EXT0x8D41, m_nDepthBuffer);
1460
1461 gdk_gl_context_make_current(m_pContext);
1462 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nRenderBuffer);
1463 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nDepthBuffer);
1464 glBindFramebufferEXTepoxy_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT0x8D40, m_nFrameBuffer);
1465
1466 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
1467 GL_RENDERBUFFER_EXT0x8D41, m_nRenderBuffer);
1468 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_DEPTH_ATTACHMENT_EXT0x8D00,
1469 GL_RENDERBUFFER_EXT0x8D41, m_nDepthBuffer);
1470 glViewportepoxy_glViewport(0, 0, width, height);
1471
1472 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nRenderScratchBuffer);
1473 glRenderbufferStorageepoxy_glRenderbufferStorage(GL_RENDERBUFFER0x8D41, GL_RGB80x8051, allocwidth, allocheight);
1474 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nDepthScratchBuffer);
1475 glRenderbufferStorageepoxy_glRenderbufferStorage(GL_RENDERBUFFER0x8D41, GL_DEPTH_COMPONENT240x81A6, allocwidth, allocheight);
1476 glBindFramebufferEXTepoxy_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT0x8D40, m_nFrameScratchBuffer);
1477
1478 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
1479 GL_RENDERBUFFER_EXT0x8D41, m_nRenderScratchBuffer);
1480 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_DEPTH_ATTACHMENT_EXT0x8D00,
1481 GL_RENDERBUFFER_EXT0x8D41, m_nDepthScratchBuffer);
1482
1483 glViewportepoxy_glViewport(0, 0, width, height);
1484 }
1485
1486 virtual bool ImplInit() override
1487 {
1488 const SystemEnvData* pEnvData = m_pChildWindow->GetSystemData();
1489 GtkWidget *pParent = static_cast<GtkWidget*>(pEnvData->pWidget);
1490 m_pGLArea = gtk_gl_area_new();
1491 g_signal_connect(G_OBJECT(m_pGLArea), "destroy", G_CALLBACK(signalDestroy), this)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((m_pGLArea)), (((GType) ((20) << (2
))))))))), ("destroy"), (((GCallback) (signalDestroy))), (this
), __null, (GConnectFlags) 0)
;
1492 g_signal_connect(G_OBJECT(m_pGLArea), "render", G_CALLBACK(signalRender), this)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((m_pGLArea)), (((GType) ((20) << (2
))))))))), ("render"), (((GCallback) (signalRender))), (this)
, __null, (GConnectFlags) 0)
;
1493 gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
, true);
1494 gtk_gl_area_set_auto_render(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
, false);
1495 gtk_widget_set_hexpand(m_pGLArea, true);
1496 gtk_widget_set_vexpand(m_pGLArea, true);
1497 gtk_container_add(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, m_pGLArea);
1498 gtk_widget_show_all(pParent);
1499
1500 gtk_gl_area_make_current(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
);
1501 if (GError *pError = gtk_gl_area_get_error(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
))
1502 {
1503 SAL_WARN("vcl.gtk", "gtk gl area error: " << pError->message)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "gtk gl area error: "
<< pError->message) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1503" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "gtk gl area error: " << pError
->message), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "gtk gl area error: " << pError
->message; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1503" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "gtk gl area error: " << pError->message
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1503" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "gtk gl area error: " << pError
->message), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "gtk gl area error: " << pError
->message; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "1503" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1504 return false;
1505 }
1506
1507 gtk_gl_area_attach_buffers(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
);
1508 glGenFramebuffersEXTepoxy_glGenFramebuffersEXT(1, &m_nAreaFrameBuffer);
1509
1510 GdkWindow *pWindow = gtk_widget_get_window(pParent);
1511 m_pContext = gdk_window_create_gl_context(pWindow, nullptr);
1512 if (!m_pContext)
1513 return false;
1514
1515 if (!gdk_gl_context_realize(m_pContext, nullptr))
1516 return false;
1517
1518 gdk_gl_context_make_current(m_pContext);
1519 glGenFramebuffersEXTepoxy_glGenFramebuffersEXT(1, &m_nFrameBuffer);
1520 glGenRenderbuffersEXTepoxy_glGenRenderbuffersEXT(1, &m_nRenderBuffer);
1521 glGenRenderbuffersEXTepoxy_glGenRenderbuffersEXT(1, &m_nDepthBuffer);
1522 glGenFramebuffersEXTepoxy_glGenFramebuffersEXT(1, &m_nFrameScratchBuffer);
1523 glGenRenderbuffersEXTepoxy_glGenRenderbuffersEXT(1, &m_nRenderScratchBuffer);
1524 glGenRenderbuffersEXTepoxy_glGenRenderbuffersEXT(1, &m_nDepthScratchBuffer);
1525
1526 bool bRet = InitGL();
1527 InitGLDebugging();
1528 return bRet;
1529 }
1530
1531 virtual void restoreDefaultFramebuffer() override
1532 {
1533 OpenGLContext::restoreDefaultFramebuffer();
1534 glBindFramebufferEXTepoxy_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT0x8D40, m_nFrameScratchBuffer);
1535 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
1536 GL_RENDERBUFFER_EXT0x8D41, m_nRenderScratchBuffer);
1537 }
1538
1539 virtual void makeCurrent() override
1540 {
1541 if (isCurrent())
1542 return;
1543
1544 clearCurrent();
1545
1546 if (m_pGLArea)
1547 {
1548 int scale = gtk_widget_get_scale_factor(m_pGLArea);
1549 int width = m_aGLWin.Width * scale;
1550 int height = m_aGLWin.Height * scale;
1551
1552 gdk_gl_context_make_current(m_pContext);
1553
1554 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nRenderScratchBuffer);
1555 glBindRenderbufferepoxy_glBindRenderbuffer(GL_RENDERBUFFER0x8D41, m_nDepthScratchBuffer);
1556 glBindFramebufferEXTepoxy_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT0x8D40, m_nFrameScratchBuffer);
1557 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
1558 GL_RENDERBUFFER_EXT0x8D41, m_nRenderScratchBuffer);
1559 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT0x8D40, GL_DEPTH_ATTACHMENT_EXT0x8D00,
1560 GL_RENDERBUFFER_EXT0x8D41, m_nDepthScratchBuffer);
1561 glViewportepoxy_glViewport(0, 0, width, height);
1562 }
1563
1564 registerAsCurrent();
1565 }
1566
1567 virtual void destroyCurrentContext() override
1568 {
1569 gdk_gl_context_clear_current();
1570 }
1571
1572 virtual bool isCurrent() override
1573 {
1574 return m_pGLArea && gdk_gl_context_get_current() == m_pContext;
1575 }
1576
1577 virtual void sync() override
1578 {
1579 }
1580
1581 virtual void resetCurrent() override
1582 {
1583 clearCurrent();
1584 gdk_gl_context_clear_current();
1585 }
1586
1587 virtual void swapBuffers() override
1588 {
1589 int scale = gtk_widget_get_scale_factor(m_pGLArea);
1590 int width = m_aGLWin.Width * scale;
1591 int height = m_aGLWin.Height * scale;
1592
1593 glBindFramebufferepoxy_glBindFramebuffer(GL_DRAW_FRAMEBUFFER0x8CA9, m_nFrameBuffer);
1594 glDrawBufferepoxy_glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT0x8CE0);
1595
1596 glBindFramebufferepoxy_glBindFramebuffer(GL_READ_FRAMEBUFFER0x8CA8, m_nFrameScratchBuffer);
1597 glReadBufferepoxy_glReadBuffer(GL_COLOR_ATTACHMENT0_EXT0x8CE0);
1598
1599 glBlitFramebufferepoxy_glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
1600 GL_COLOR_BUFFER_BIT0x00004000 | GL_DEPTH_BUFFER_BIT0x00000100, GL_NEAREST0x2600);
1601
1602 glBindFramebufferepoxy_glBindFramebuffer(GL_DRAW_FRAMEBUFFER0x8CA9, m_nFrameScratchBuffer);
1603 glDrawBufferepoxy_glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT0x8CE0);
1604
1605 gtk_gl_area_queue_render(GTK_GL_AREA(m_pGLArea)((((GtkGLArea*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pGLArea)), ((gtk_gl_area_get_type ()))))))
);
1606 BuffersSwapped();
1607 }
1608
1609 virtual ~GtkOpenGLContext() override
1610 {
1611 if (m_pContext)
1612 {
1613 g_clear_object(&m_pContext)do { static_assert (sizeof *((&m_pContext)) == sizeof (gpointer
), "Expression evaluates to false"); union { char *in; gpointer
*out; } _pp; gpointer _p; GDestroyNotify _destroy = (GDestroyNotify
) (g_object_unref); _pp.in = (char *) ((&m_pContext)); _p
= *_pp.out; if (_p) { *_pp.out = __null; _destroy (_p); } } while
(0)
;
1614 }
1615 }
1616};
1617
1618}
1619
1620OpenGLContext* GtkInstance::CreateOpenGLContext()
1621{
1622 return new GtkOpenGLContext;
1623}
1624
1625// tdf#123800 avoid requiring wayland at runtime just because it existed at buildtime
1626bool DLSYM_GDK_IS_WAYLAND_DISPLAY(GdkDisplay* pDisplay)
1627{
1628 static auto get_type = reinterpret_cast<GType (*) (void)>(dlsym(nullptr, "gdk_wayland_display_get_type"));
1629 if (!get_type)
1630 return false;
1631 return G_TYPE_CHECK_INSTANCE_TYPE(pDisplay, get_type())((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
pDisplay); GType __t = (get_type()); gboolean __r; if (!__inst
) __r = (0); else if (__inst->g_class && __inst->
g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a
(__inst, __t); __r; })))
;
1632}
1633
1634bool DLSYM_GDK_IS_X11_DISPLAY(GdkDisplay* pDisplay)
1635{
1636 static auto get_type = reinterpret_cast<GType (*) (void)>(dlsym(nullptr, "gdk_x11_display_get_type"));
1637 if (!get_type)
1638 return false;
1639 return G_TYPE_CHECK_INSTANCE_TYPE(pDisplay, get_type())((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
pDisplay); GType __t = (get_type()); gboolean __r; if (!__inst
) __r = (0); else if (__inst->g_class && __inst->
g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a
(__inst, __t); __r; })))
;
1640}
1641
1642namespace
1643{
1644
1645class GtkInstanceBuilder;
1646
1647 void set_help_id(const GtkWidget *pWidget, const OString& rHelpId)
1648 {
1649 gchar *helpid = g_strdup(rHelpId.getStr());
1650 g_object_set_data_full(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "g-lo-helpid", helpid, g_free);
1651 }
1652
1653 OString get_help_id(const GtkWidget *pWidget)
1654 {
1655 void* pData = g_object_get_data(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "g-lo-helpid");
1656 const gchar* pStr = static_cast<const gchar*>(pData);
1657 return OString(pStr, pStr ? strlen(pStr) : 0);
1658 }
1659
1660 KeyEvent GtkToVcl(const GdkEventKey& rEvent)
1661 {
1662 sal_uInt16 nKeyCode = GtkSalFrame::GetKeyCode(rEvent.keyval);
1663 if (nKeyCode == 0)
1664 {
1665 guint updated_keyval = GtkSalFrame::GetKeyValFor(gdk_keymap_get_default(), rEvent.hardware_keycode, rEvent.group);
1666 nKeyCode = GtkSalFrame::GetKeyCode(updated_keyval);
1667 }
1668 nKeyCode |= GtkSalFrame::GetKeyModCode(rEvent.state);
1669 return KeyEvent(gdk_keyval_to_unicode(rEvent.keyval), nKeyCode, 0);
1670 }
1671}
1672
1673static MouseEventModifiers ImplGetMouseButtonMode(sal_uInt16 nButton, sal_uInt16 nCode)
1674{
1675 MouseEventModifiers nMode = MouseEventModifiers::NONE;
1676 if ( nButton == MOUSE_LEFT(sal_uInt16(0x0001)) )
1677 nMode |= MouseEventModifiers::SIMPLECLICK;
1678 if ( (nButton == MOUSE_LEFT(sal_uInt16(0x0001))) && !(nCode & (MOUSE_MIDDLE(sal_uInt16(0x0002)) | MOUSE_RIGHT(sal_uInt16(0x0004)))) )
1679 nMode |= MouseEventModifiers::SELECT;
1680 if ( (nButton == MOUSE_LEFT(sal_uInt16(0x0001))) && (nCode & KEY_MOD1) &&
1681 !(nCode & (MOUSE_MIDDLE(sal_uInt16(0x0002)) | MOUSE_RIGHT(sal_uInt16(0x0004)) | KEY_SHIFT)) )
1682 nMode |= MouseEventModifiers::MULTISELECT;
1683 if ( (nButton == MOUSE_LEFT(sal_uInt16(0x0001))) && (nCode & KEY_SHIFT) &&
1684 !(nCode & (MOUSE_MIDDLE(sal_uInt16(0x0002)) | MOUSE_RIGHT(sal_uInt16(0x0004)) | KEY_MOD1)) )
1685 nMode |= MouseEventModifiers::RANGESELECT;
1686 return nMode;
1687}
1688
1689static MouseEventModifiers ImplGetMouseMoveMode(sal_uInt16 nCode)
1690{
1691 MouseEventModifiers nMode = MouseEventModifiers::NONE;
1692 if ( !nCode )
1693 nMode |= MouseEventModifiers::SIMPLEMOVE;
1694 if ( (nCode & MOUSE_LEFT(sal_uInt16(0x0001))) && !(nCode & KEY_MOD1) )
1695 nMode |= MouseEventModifiers::DRAGMOVE;
1696 if ( (nCode & MOUSE_LEFT(sal_uInt16(0x0001))) && (nCode & KEY_MOD1) )
1697 nMode |= MouseEventModifiers::DRAGCOPY;
1698 return nMode;
1699}
1700
1701namespace
1702{
1703 bool SwapForRTL(GtkWidget* pWidget)
1704 {
1705 GtkTextDirection eDir = gtk_widget_get_direction(pWidget);
1706 if (eDir == GTK_TEXT_DIR_RTL)
1707 return true;
1708 if (eDir == GTK_TEXT_DIR_LTR)
1709 return false;
1710 return AllSettings::GetLayoutRTL();
1711 }
1712
1713 void replaceWidget(GtkWidget* pWidget, GtkWidget* pReplacement)
1714 {
1715 // remove the widget and replace it with pReplacement
1716 GtkWidget* pParent = gtk_widget_get_parent(pWidget);
1717
1718 // if pWidget was un-parented then don't bother
1719 if (!pParent)
1720 return;
1721
1722 g_object_ref(pWidget);
1723
1724 gint nTopAttach(0), nLeftAttach(0), nHeight(1), nWidth(1);
1725 if (GTK_IS_GRID(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_grid_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1726 {
1727 gtk_container_child_get(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pWidget,
1728 "left-attach", &nTopAttach,
1729 "top-attach", &nLeftAttach,
1730 "width", &nWidth,
1731 "height", &nHeight,
1732 nullptr);
1733 }
1734
1735 gboolean bExpand(false), bFill(false);
1736 GtkPackType ePackType(GTK_PACK_START);
1737 guint nPadding(0);
1738 gint nPosition(0);
1739 if (GTK_IS_BOX(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_box_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1740 {
1741 gtk_container_child_get(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pWidget,
1742 "expand", &bExpand,
1743 "fill", &bFill,
1744 "pack-type", &ePackType,
1745 "padding", &nPadding,
1746 "position", &nPosition,
1747 nullptr);
1748 }
1749
1750 gtk_container_remove(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pWidget);
1751
1752 gtk_widget_set_visible(pReplacement, gtk_widget_get_visible(pWidget));
1753 gtk_widget_set_no_show_all(pReplacement, gtk_widget_get_no_show_all(pWidget));
1754
1755 int nReqWidth, nReqHeight;
1756 gtk_widget_get_size_request(pWidget, &nReqWidth, &nReqHeight);
1757 gtk_widget_set_size_request(pReplacement, nReqWidth, nReqHeight);
1758
1759 static GQuark quark_size_groups = g_quark_from_static_string("gtk-widget-size-groups");
1760 GSList* pSizeGroups = static_cast<GSList*>(g_object_get_qdata(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, quark_size_groups));
1761 while (pSizeGroups)
1762 {
1763 GtkSizeGroup *pSizeGroup = static_cast<GtkSizeGroup*>(pSizeGroups->data);
1764 pSizeGroups = pSizeGroups->next;
1765 gtk_size_group_remove_widget(pSizeGroup, pWidget);
1766 gtk_size_group_add_widget(pSizeGroup, pReplacement);
1767 }
1768
1769 // tdf#135368 change the mnemonic to point to our replacement
1770 GList* pLabels = gtk_widget_list_mnemonic_labels(pWidget);
1771 for (GList* pLabel = g_list_first(pLabels); pLabel; pLabel = g_list_next(pLabel)((pLabel) ? (((GList *)(pLabel))->next) : __null))
1772 {
1773 GtkWidget* pLabelWidget = static_cast<GtkWidget*>(pLabel->data);
1774 if (!GTK_IS_LABEL(pLabelWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pLabelWidget)); GType __t = ((gtk_label_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1775 continue;
1776 gtk_label_set_mnemonic_widget(GTK_LABEL(pLabelWidget)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pLabelWidget)), ((gtk_label_get_type ()))))))
, pReplacement);
1777 }
1778 g_list_free(pLabels);
1779
1780 gtk_container_add(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pReplacement);
1781
1782 if (GTK_IS_GRID(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_grid_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1783 {
1784 gtk_container_child_set(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pReplacement,
1785 "left-attach", nTopAttach,
1786 "top-attach", nLeftAttach,
1787 "width", nWidth,
1788 "height", nHeight,
1789 nullptr);
1790 }
1791
1792 if (GTK_IS_BOX(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_box_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1793 {
1794 gtk_container_child_set(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pReplacement,
1795 "expand", bExpand,
1796 "fill", bFill,
1797 "pack-type", ePackType,
1798 "padding", nPadding,
1799 "position", nPosition,
1800 nullptr);
1801 }
1802
1803 if (gtk_widget_get_hexpand_set(pWidget))
1804 gtk_widget_set_hexpand(pReplacement, gtk_widget_get_hexpand(pWidget));
1805
1806 if (gtk_widget_get_vexpand_set(pWidget))
1807 gtk_widget_set_vexpand(pReplacement, gtk_widget_get_vexpand(pWidget));
1808
1809 gtk_widget_set_halign(pReplacement, gtk_widget_get_halign(pWidget));
1810 gtk_widget_set_valign(pReplacement, gtk_widget_get_valign(pWidget));
1811
1812 g_object_unref(pWidget);
1813 }
1814
1815 void insertAsParent(GtkWidget* pWidget, GtkWidget* pReplacement)
1816 {
1817 g_object_ref(pWidget);
1818
1819 replaceWidget(pWidget, pReplacement);
1820
1821 gtk_container_add(GTK_CONTAINER(pReplacement)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pReplacement)), ((gtk_container_get_type ()))))))
, pWidget);
1822
1823 g_object_unref(pWidget);
1824 }
1825
1826 GtkWidget* ensureEventWidget(GtkWidget* pWidget)
1827 {
1828 if (!pWidget)
1829 return nullptr;
1830
1831 GtkWidget* pMouseEventBox;
1832 // not every widget has a GdkWindow and can get any event, so if we
1833 // want an event it doesn't have, insert a GtkEventBox so we can get
1834 // those
1835 if (gtk_widget_get_has_window(pWidget))
1836 pMouseEventBox = pWidget;
1837 else
1838 {
1839 // remove the widget and replace it with an eventbox and put the old
1840 // widget into it
1841 pMouseEventBox = gtk_event_box_new();
1842 gtk_event_box_set_above_child(GTK_EVENT_BOX(pMouseEventBox)((((GtkEventBox*) g_type_check_instance_cast ((GTypeInstance*
) ((pMouseEventBox)), ((gtk_event_box_get_type ()))))))
, false);
1843 gtk_event_box_set_visible_window(GTK_EVENT_BOX(pMouseEventBox)((((GtkEventBox*) g_type_check_instance_cast ((GTypeInstance*
) ((pMouseEventBox)), ((gtk_event_box_get_type ()))))))
, false);
1844 insertAsParent(pWidget, pMouseEventBox);
1845 }
1846
1847 return pMouseEventBox;
1848 }
1849}
1850
1851namespace {
1852
1853GdkDragAction VclToGdk(sal_Int8 dragOperation)
1854{
1855 GdkDragAction eRet(static_cast<GdkDragAction>(0));
1856 if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY)
1857 eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_COPY);
1858 if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE)
1859 eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_MOVE);
1860 if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK)
1861 eRet = static_cast<GdkDragAction>(eRet | GDK_ACTION_LINK);
1862 return eRet;
1863}
1864
1865class GtkInstanceWidget : public virtual weld::Widget
1866{
1867protected:
1868 GtkWidget* m_pWidget;
1869 GtkWidget* m_pMouseEventBox;
1870 GtkInstanceBuilder* m_pBuilder;
1871
1872 DECL_LINK(async_signal_focus_in, void*, void)static void LinkStubasync_signal_focus_in(void *, void*); void
async_signal_focus_in(void*)
;
1873 DECL_LINK(async_signal_focus_out, void*, void)static void LinkStubasync_signal_focus_out(void *, void*); void
async_signal_focus_out(void*)
;
1874 DECL_LINK(async_drag_cancel, void*, void)static void LinkStubasync_drag_cancel(void *, void*); void async_drag_cancel
(void*)
;
1875
1876 void launch_signal_focus_in()
1877 {
1878 // in e.g. function wizard RefEdits we want to select all when we get focus
1879 // but there are pending gtk handlers which change selection after our handler
1880 // post our focus in event to happen after those finish
1881 if (m_pFocusInEvent)
1882 Application::RemoveUserEvent(m_pFocusInEvent);
1883 m_pFocusInEvent = Application::PostUserEvent(LINK(this, GtkInstanceWidget, async_signal_focus_in)::tools::detail::makeLink( ::tools::detail::castTo<GtkInstanceWidget
*>(this), &GtkInstanceWidget::LinkStubasync_signal_focus_in
)
);
1884 }
1885
1886 static gboolean signalFocusIn(GtkWidget*, GdkEvent*, gpointer widget)
1887 {
1888 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
1889 pThis->launch_signal_focus_in();
1890 return false;
1891 }
1892
1893 void signal_focus_in()
1894 {
1895 m_aFocusInHdl.Call(*this);
1896 }
1897
1898 static gboolean signalMnemonicActivate(GtkWidget*, gboolean, gpointer widget)
1899 {
1900 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
1901 SolarMutexGuard aGuard;
1902 return pThis->signal_mnemonic_activate();
1903 }
1904
1905 bool signal_mnemonic_activate()
1906 {
1907 return m_aMnemonicActivateHdl.Call(*this);
1908 }
1909
1910 void launch_signal_focus_out()
1911 {
1912 // tdf#127262 because focus in is async, focus out must not appear out
1913 // of sequence to focus in
1914 if (m_pFocusOutEvent)
1915 Application::RemoveUserEvent(m_pFocusOutEvent);
1916 m_pFocusOutEvent = Application::PostUserEvent(LINK(this, GtkInstanceWidget, async_signal_focus_out)::tools::detail::makeLink( ::tools::detail::castTo<GtkInstanceWidget
*>(this), &GtkInstanceWidget::LinkStubasync_signal_focus_out
)
);
1917 }
1918
1919 static gboolean signalFocusOut(GtkWidget*, GdkEvent*, gpointer widget)
1920 {
1921 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
1922 SolarMutexGuard aGuard;
1923 pThis->launch_signal_focus_out();
1924 return false;
1925 }
1926
1927 void launch_drag_cancel(GdkDragContext* context)
1928 {
1929 // post our drag cancel to happen at the next available event cycle
1930 if (m_pDragCancelEvent)
1931 return;
1932 g_object_ref(context);
1933 m_pDragCancelEvent = Application::PostUserEvent(LINK(this, GtkInstanceWidget, async_drag_cancel)::tools::detail::makeLink( ::tools::detail::castTo<GtkInstanceWidget
*>(this), &GtkInstanceWidget::LinkStubasync_drag_cancel
)
, context);
1934 }
1935
1936 void signal_focus_out()
1937 {
1938 m_aFocusOutHdl.Call(*this);
1939 }
1940
1941 virtual void ensureMouseEventWidget()
1942 {
1943 if (!m_pMouseEventBox)
1944 m_pMouseEventBox = ::ensureEventWidget(m_pWidget);
1945 }
1946
1947 void ensureButtonPressSignal()
1948 {
1949 if (!m_nButtonPressSignalId)
1950 {
1951 ensureMouseEventWidget();
1952 m_nButtonPressSignalId = g_signal_connect(m_pMouseEventBox, "button-press-event", G_CALLBACK(signalButton), this)g_signal_connect_data ((m_pMouseEventBox), ("button-press-event"
), (((GCallback) (signalButton))), (this), __null, (GConnectFlags
) 0)
;
1953 }
1954 }
1955
1956 static gboolean signalPopupMenu(GtkWidget* pWidget, gpointer widget)
1957 {
1958 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
1959 SolarMutexGuard aGuard;
1960 //center it when we don't know where else to use
1961 Point aPos(gtk_widget_get_allocated_width(pWidget) / 2,
1962 gtk_widget_get_allocated_height(pWidget) / 2);
1963 CommandEvent aCEvt(aPos, CommandEventId::ContextMenu, false);
1964 return pThis->signal_popup_menu(aCEvt);
1965 }
1966
1967 bool SwapForRTL() const
1968 {
1969 return ::SwapForRTL(m_pWidget);
1970 }
1971
1972 void do_enable_drag_source(const rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants)
1973 {
1974 css::uno::Reference<css::datatransfer::XTransferable> xTrans(rHelper.get());
1975 css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> xListener(rHelper.get());
1976
1977 ensure_drag_source();
1978
1979 auto aFormats = xTrans->getTransferDataFlavors();
1980 std::vector<GtkTargetEntry> aGtkTargets(m_xDragSource->FormatsToGtk(aFormats));
1981
1982 m_eDragAction = VclToGdk(eDNDConstants);
1983 drag_source_set(aGtkTargets, m_eDragAction);
1984
1985 for (auto &a : aGtkTargets)
1986 g_free(a.target);
1987
1988 m_xDragSource->set_datatransfer(xTrans, xListener);
1989 }
1990
1991 void localizeDecimalSeparator()
1992 {
1993 // tdf#128867 if localize decimal separator is active we will always
1994 // need to be able to change the output of the decimal key press
1995 if (!m_nKeyPressSignalId && Application::GetSettings().GetMiscSettings().GetEnableLocalizedDecimalSep())
1996 m_nKeyPressSignalId = g_signal_connect(m_pWidget, "key-press-event", G_CALLBACK(signalKey), this)g_signal_connect_data ((m_pWidget), ("key-press-event"), (((GCallback
) (signalKey))), (this), __null, (GConnectFlags) 0)
;
1997 }
1998
1999 void ensure_drag_begin_end()
2000 {
2001 if (!m_nDragBeginSignalId)
2002 {
2003 // using "after" due to https://gitlab.gnome.org/GNOME/pygobject/issues/251
2004 m_nDragBeginSignalId = g_signal_connect_after(m_pWidget, "drag-begin", G_CALLBACK(signalDragBegin), this)g_signal_connect_data ((m_pWidget), ("drag-begin"), (((GCallback
) (signalDragBegin))), (this), __null, G_CONNECT_AFTER)
;
2005 }
2006 if (!m_nDragEndSignalId)
2007 m_nDragEndSignalId = g_signal_connect(m_pWidget, "drag-end", G_CALLBACK(signalDragEnd), this)g_signal_connect_data ((m_pWidget), ("drag-end"), (((GCallback
) (signalDragEnd))), (this), __null, (GConnectFlags) 0)
;
2008 }
2009
2010private:
2011 bool m_bTakeOwnership;
2012 bool m_bDraggedOver;
2013 sal_uInt16 m_nLastMouseButton;
2014 sal_uInt16 m_nLastMouseClicks;
2015 int m_nPressedButton;
2016 int m_nPressStartX;
2017 int m_nPressStartY;
2018 ImplSVEvent* m_pFocusInEvent;
2019 ImplSVEvent* m_pFocusOutEvent;
2020 ImplSVEvent* m_pDragCancelEvent;
2021 GtkCssProvider* m_pBgCssProvider;
2022 GdkDragAction m_eDragAction;
2023 gulong m_nFocusInSignalId;
2024 gulong m_nMnemonicActivateSignalId;
2025 gulong m_nFocusOutSignalId;
2026 gulong m_nKeyPressSignalId;
2027 gulong m_nKeyReleaseSignalId;
2028 gulong m_nSizeAllocateSignalId;
2029 gulong m_nButtonPressSignalId;
2030 gulong m_nMotionSignalId;
2031 gulong m_nLeaveSignalId;
2032 gulong m_nEnterSignalId;
2033 gulong m_nButtonReleaseSignalId;
2034 gulong m_nDragMotionSignalId;
2035 gulong m_nDragDropSignalId;
2036 gulong m_nDragDropReceivedSignalId;
2037 gulong m_nDragLeaveSignalId;
2038 gulong m_nDragBeginSignalId;
2039 gulong m_nDragEndSignalId;
2040 gulong m_nDragFailedSignalId;
2041 gulong m_nDragDataDeleteignalId;
2042 gulong m_nDragGetSignalId;
2043
2044 rtl::Reference<GtkDropTarget> m_xDropTarget;
2045 rtl::Reference<GtkDragSource> m_xDragSource;
2046
2047 static void signalSizeAllocate(GtkWidget*, GdkRectangle* allocation, gpointer widget)
2048 {
2049 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2050 SolarMutexGuard aGuard;
2051 pThis->signal_size_allocate(allocation->width, allocation->height);
2052 }
2053
2054 static gboolean signalKey(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
2055 {
2056 // #i1820# use locale specific decimal separator
2057 if (pEvent->keyval == GDK_KEY_KP_Decimal0xffae && Application::GetSettings().GetMiscSettings().GetEnableLocalizedDecimalSep())
2058 {
2059 OUString aSep(Application::GetSettings().GetLocaleDataWrapper().getNumDecimalSep());
2060 pEvent->keyval = aSep[0];
2061 }
2062
2063 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2064 return pThis->signal_key(pEvent);
2065 }
2066
2067 virtual bool signal_popup_menu(const CommandEvent&)
2068 {
2069 return false;
2070 }
2071
2072 static gboolean signalButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
2073 {
2074 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2075 SolarMutexGuard aGuard;
2076 return pThis->signal_button(pEvent);
2077 }
2078
2079 bool signal_button(GdkEventButton* pEvent)
2080 {
2081 m_nPressedButton = -1;
2082
2083 Point aPos(pEvent->x, pEvent->y);
2084 if (SwapForRTL())
2085 aPos.setX(gtk_widget_get_allocated_width(m_pWidget) - 1 - aPos.X());
2086
2087 if (gdk_event_triggers_context_menu(reinterpret_cast<GdkEvent*>(pEvent)) && pEvent->type == GDK_BUTTON_PRESS)
2088 {
2089 //if handled for context menu, stop processing
2090 CommandEvent aCEvt(aPos, CommandEventId::ContextMenu, true);
2091 if (signal_popup_menu(aCEvt))
2092 return true;
2093 }
2094
2095 if (!m_aMousePressHdl.IsSet() && !m_aMouseReleaseHdl.IsSet())
2096 return false;
2097
2098 SalEvent nEventType = SalEvent::NONE;
2099 switch (pEvent->type)
2100 {
2101 case GDK_BUTTON_PRESS:
2102 if (GdkEvent* pPeekEvent = gdk_event_peek())
2103 {
2104 bool bSkip = pPeekEvent->type == GDK_2BUTTON_PRESS ||
2105 pPeekEvent->type == GDK_3BUTTON_PRESS;
2106 gdk_event_free(pPeekEvent);
2107 if (bSkip)
2108 {
2109 return false;
2110 }
2111 }
2112 nEventType = SalEvent::MouseButtonDown;
2113 m_nLastMouseClicks = 1;
2114 break;
2115 case GDK_2BUTTON_PRESS:
2116 m_nLastMouseClicks = 2;
2117 nEventType = SalEvent::MouseButtonDown;
2118 break;
2119 case GDK_3BUTTON_PRESS:
2120 m_nLastMouseClicks = 3;
2121 nEventType = SalEvent::MouseButtonDown;
2122 break;
2123 case GDK_BUTTON_RELEASE:
2124 nEventType = SalEvent::MouseButtonUp;
2125 break;
2126 default:
2127 return false;
2128 }
2129
2130 switch (pEvent->button)
2131 {
2132 case 1:
2133 m_nLastMouseButton = MOUSE_LEFT(sal_uInt16(0x0001));
2134 break;
2135 case 2:
2136 m_nLastMouseButton = MOUSE_MIDDLE(sal_uInt16(0x0002));
2137 break;
2138 case 3:
2139 m_nLastMouseButton = MOUSE_RIGHT(sal_uInt16(0x0004));
2140 break;
2141 default:
2142 return false;
2143 }
2144
2145 /* Save press to possibly begin a drag */
2146 if (pEvent->type != GDK_BUTTON_RELEASE)
2147 {
2148 m_nPressedButton = pEvent->button;
2149 m_nPressStartX = pEvent->x;
2150 m_nPressStartY = pEvent->y;
2151 }
2152
2153 sal_uInt32 nModCode = GtkSalFrame::GetMouseModCode(pEvent->state);
2154 // strip out which buttons are involved from the nModCode and replace with m_nLastMouseButton
2155 sal_uInt16 nCode = m_nLastMouseButton | (nModCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2));
2156 MouseEvent aMEvt(aPos, m_nLastMouseClicks, ImplGetMouseButtonMode(m_nLastMouseButton, nModCode), nCode, nCode);
2157
2158 if (nEventType == SalEvent::MouseButtonDown)
2159 {
2160 if (!m_aMousePressHdl.IsSet())
2161 return false;
2162 return m_aMousePressHdl.Call(aMEvt);
2163 }
2164
2165 if (!m_aMouseReleaseHdl.IsSet())
2166 return false;
2167 return m_aMouseReleaseHdl.Call(aMEvt);
2168 }
2169
2170 static gboolean signalMotion(GtkWidget*, GdkEventMotion* pEvent, gpointer widget)
2171 {
2172 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2173 SolarMutexGuard aGuard;
2174 return pThis->signal_motion(pEvent);
2175 }
2176
2177 bool signal_motion(const GdkEventMotion* pEvent)
2178 {
2179 GtkTargetList* pDragData = (m_eDragAction != 0 && m_nPressedButton != -1 && m_xDragSource.is()) ? gtk_drag_source_get_target_list(m_pWidget) : nullptr;
2180 bool bUnsetDragIcon(false);
2181 if (pDragData && gtk_drag_check_threshold(m_pWidget, m_nPressStartX, m_nPressStartY, pEvent->x, pEvent->y) && !do_signal_drag_begin(bUnsetDragIcon))
2182 {
2183 GdkDragContext* pContext = gtk_drag_begin_with_coordinates(m_pWidget,
2184 pDragData,
2185 m_eDragAction,
2186 m_nPressedButton,
2187 const_cast<GdkEvent*>(reinterpret_cast<const GdkEvent*>(pEvent)),
2188 m_nPressStartX, m_nPressStartY);
2189
2190 if (pContext && bUnsetDragIcon)
2191 {
2192 cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
2193 gtk_drag_set_icon_surface(pContext, surface);
2194 }
2195
2196 m_nPressedButton = -1;
2197 return false;
2198 }
2199
2200 if (!m_aMouseMotionHdl.IsSet())
2201 return false;
2202
2203 Point aPos(pEvent->x, pEvent->y);
2204 if (SwapForRTL())
2205 aPos.setX(gtk_widget_get_allocated_width(m_pWidget) - 1 - aPos.X());
2206 sal_uInt32 nModCode = GtkSalFrame::GetMouseModCode(pEvent->state);
2207 MouseEvent aMEvt(aPos, 0, ImplGetMouseMoveMode(nModCode), nModCode, nModCode);
2208
2209 m_aMouseMotionHdl.Call(aMEvt);
2210 return true;
2211 }
2212
2213 static gboolean signalCrossing(GtkWidget*, GdkEventCrossing* pEvent, gpointer widget)
2214 {
2215 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2216 SolarMutexGuard aGuard;
2217 return pThis->signal_crossing(pEvent);
2218 }
2219
2220 bool signal_crossing(const GdkEventCrossing* pEvent)
2221 {
2222 if (!m_aMouseMotionHdl.IsSet())
2223 return false;
2224
2225 Point aPos(pEvent->x, pEvent->y);
2226 if (SwapForRTL())
2227 aPos.setX(gtk_widget_get_allocated_width(m_pWidget) - 1 - aPos.X());
2228 sal_uInt32 nModCode = GtkSalFrame::GetMouseModCode(pEvent->state);
2229 MouseEventModifiers eModifiers = ImplGetMouseMoveMode(nModCode);
2230 eModifiers = eModifiers | (pEvent->type == GDK_ENTER_NOTIFY ? MouseEventModifiers::ENTERWINDOW : MouseEventModifiers::LEAVEWINDOW);
2231 MouseEvent aMEvt(aPos, 0, eModifiers, nModCode, nModCode);
2232
2233 m_aMouseMotionHdl.Call(aMEvt);
2234 return true;
2235 }
2236
2237 virtual void drag_started()
2238 {
2239 }
2240
2241 static gboolean signalDragMotion(GtkWidget *pWidget, GdkDragContext *context, gint x, gint y, guint time, gpointer widget)
2242 {
2243 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2244 if (!pThis->m_bDraggedOver)
2245 {
2246 pThis->m_bDraggedOver = true;
2247 pThis->drag_started();
2248 }
2249 return pThis->m_xDropTarget->signalDragMotion(pWidget, context, x, y, time);
2250 }
2251
2252 static gboolean signalDragDrop(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, guint time, gpointer widget)
2253 {
2254 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2255 return pThis->m_xDropTarget->signalDragDrop(pWidget, context, x, y, time);
2256 }
2257
2258 static void signalDragDropReceived(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, GtkSelectionData* data, guint ttype, guint time, gpointer widget)
2259 {
2260 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2261 pThis->m_xDropTarget->signalDragDropReceived(pWidget, context, x, y, data, ttype, time);
2262 }
2263
2264 virtual void drag_ended()
2265 {
2266 }
2267
2268 static void signalDragLeave(GtkWidget *pWidget, GdkDragContext *context, guint time, gpointer widget)
2269 {
2270 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2271 pThis->m_xDropTarget->signalDragLeave(pWidget, context, time);
2272 if (pThis->m_bDraggedOver)
2273 {
2274 pThis->m_bDraggedOver = false;
2275 pThis->drag_ended();
2276 }
2277 }
2278
2279 static void signalDragBegin(GtkWidget*, GdkDragContext* context, gpointer widget)
2280 {
2281 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2282 pThis->signal_drag_begin(context);
2283 }
2284
2285 void ensure_drag_source()
2286 {
2287 if (!m_xDragSource)
2288 {
2289 m_xDragSource.set(new GtkDragSource);
2290
2291 m_nDragFailedSignalId = g_signal_connect(m_pWidget, "drag-failed", G_CALLBACK(signalDragFailed), this)g_signal_connect_data ((m_pWidget), ("drag-failed"), (((GCallback
) (signalDragFailed))), (this), __null, (GConnectFlags) 0)
;
2292 m_nDragDataDeleteignalId = g_signal_connect(m_pWidget, "drag-data-delete", G_CALLBACK(signalDragDelete), this)g_signal_connect_data ((m_pWidget), ("drag-data-delete"), (((
GCallback) (signalDragDelete))), (this), __null, (GConnectFlags
) 0)
;
2293 m_nDragGetSignalId = g_signal_connect(m_pWidget, "drag-data-get", G_CALLBACK(signalDragDataGet), this)g_signal_connect_data ((m_pWidget), ("drag-data-get"), (((GCallback
) (signalDragDataGet))), (this), __null, (GConnectFlags) 0)
;
2294
2295 ensure_drag_begin_end();
2296 }
2297 }
2298
2299 virtual bool do_signal_drag_begin(bool& rUnsetDragIcon)
2300 {
2301 rUnsetDragIcon = false;
2302 return false;
2303 }
2304
2305 void signal_drag_begin(GdkDragContext* context)
2306 {
2307 bool bUnsetDragIcon(false);
2308 if (do_signal_drag_begin(bUnsetDragIcon))
2309 {
2310 launch_drag_cancel(context);
2311 return;
2312 }
2313 if (bUnsetDragIcon)
2314 {
2315 cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
2316 gtk_drag_set_icon_surface(context, surface);
2317 }
2318 if (!m_xDragSource)
2319 return;
2320 m_xDragSource->setActiveDragSource();
2321 }
2322
2323 virtual void do_signal_drag_end()
2324 {
2325 }
2326
2327 static void signalDragEnd(GtkWidget* /*widget*/, GdkDragContext* context, gpointer widget)
2328 {
2329 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2330 pThis->do_signal_drag_end();
2331 if (pThis->m_xDragSource.is())
2332 pThis->m_xDragSource->dragEnd(context);
2333 }
2334
2335 static gboolean signalDragFailed(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkDragResult /*result*/, gpointer widget)
2336 {
2337 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2338 pThis->m_xDragSource->dragFailed();
2339 return false;
2340 }
2341
2342 static void signalDragDelete(GtkWidget* /*widget*/, GdkDragContext* /*context*/, gpointer widget)
2343 {
2344 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2345 pThis->m_xDragSource->dragDelete();
2346 }
2347
2348 static void signalDragDataGet(GtkWidget* /*widget*/, GdkDragContext* /*context*/, GtkSelectionData *data, guint info,
2349 guint /*time*/, gpointer widget)
2350 {
2351 GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
2352 pThis->m_xDragSource->dragDataGet(data, info);
2353 }
2354
2355 virtual void drag_source_set(const std::vector<GtkTargetEntry>& rGtkTargets, GdkDragAction eDragAction)
2356 {
2357 gtk_drag_source_set(m_pWidget, GDK_BUTTON1_MASK, rGtkTargets.data(), rGtkTargets.size(), eDragAction);
2358 }
2359
2360 void do_set_background(const Color& rColor)
2361 {
2362 const bool bRemoveColor = rColor == COL_AUTO;
2363 if (bRemoveColor && !m_pBgCssProvider)
2364 return;
2365 GtkStyleContext *pWidgetContext = gtk_widget_get_style_context(GTK_WIDGET(m_pWidget)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWidget)), ((gtk_widget_get_type ()))))))
);
2366 if (m_pBgCssProvider)
2367 {
2368 gtk_style_context_remove_provider(pWidgetContext, GTK_STYLE_PROVIDER(m_pBgCssProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pBgCssProvider)), ((gtk_style_provider_get_type ()))))
))
);
2369 m_pBgCssProvider = nullptr;
2370 }
2371 if (bRemoveColor)
2372 return;
2373 OUString sColor = rColor.AsRGBHexString();
2374 m_pBgCssProvider = gtk_css_provider_new();
2375 OUString aBuffer = "* { background-color: #" + sColor + "; }";
2376 OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
2377 gtk_css_provider_load_from_data(m_pBgCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
2378 gtk_style_context_add_provider(pWidgetContext, GTK_STYLE_PROVIDER(m_pBgCssProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pBgCssProvider)), ((gtk_style_provider_get_type ()))))
))
,
2379 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
2380 }
2381
2382public:
2383 GtkInstanceWidget(GtkWidget* pWidget, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
2384 : m_pWidget(pWidget)
2385 , m_pMouseEventBox(nullptr)
2386 , m_pBuilder(pBuilder)
2387 , m_bTakeOwnership(bTakeOwnership)
2388 , m_bDraggedOver(false)
2389 , m_nLastMouseButton(0)
2390 , m_nLastMouseClicks(0)
2391 , m_nPressedButton(-1)
2392 , m_nPressStartX(-1)
2393 , m_nPressStartY(-1)
2394 , m_pFocusInEvent(nullptr)
2395 , m_pFocusOutEvent(nullptr)
2396 , m_pDragCancelEvent(nullptr)
2397 , m_pBgCssProvider(nullptr)
2398 , m_eDragAction(GdkDragAction(0))
2399 , m_nFocusInSignalId(0)
2400 , m_nMnemonicActivateSignalId(0)
2401 , m_nFocusOutSignalId(0)
2402 , m_nKeyPressSignalId(0)
2403 , m_nKeyReleaseSignalId(0)
2404 , m_nSizeAllocateSignalId(0)
2405 , m_nButtonPressSignalId(0)
2406 , m_nMotionSignalId(0)
2407 , m_nLeaveSignalId(0)
2408 , m_nEnterSignalId(0)
2409 , m_nButtonReleaseSignalId(0)
2410 , m_nDragMotionSignalId(0)
2411 , m_nDragDropSignalId(0)
2412 , m_nDragDropReceivedSignalId(0)
2413 , m_nDragLeaveSignalId(0)
2414 , m_nDragBeginSignalId(0)
2415 , m_nDragEndSignalId(0)
2416 , m_nDragFailedSignalId(0)
2417 , m_nDragDataDeleteignalId(0)
2418 , m_nDragGetSignalId(0)
2419 {
2420 if (!bTakeOwnership)
2421 g_object_ref(m_pWidget);
2422
2423 localizeDecimalSeparator();
2424 }
2425
2426 virtual void connect_key_press(const Link<const KeyEvent&, bool>& rLink) override
2427 {
2428 if (!m_nKeyPressSignalId)
2429 m_nKeyPressSignalId = g_signal_connect(m_pWidget, "key-press-event", G_CALLBACK(signalKey), this)g_signal_connect_data ((m_pWidget), ("key-press-event"), (((GCallback
) (signalKey))), (this), __null, (GConnectFlags) 0)
;
2430 weld::Widget::connect_key_press(rLink);
2431 }
2432
2433 virtual void connect_key_release(const Link<const KeyEvent&, bool>& rLink) override
2434 {
2435 if (!m_nKeyReleaseSignalId)
2436 m_nKeyReleaseSignalId = g_signal_connect(m_pWidget, "key-release-event", G_CALLBACK(signalKey), this)g_signal_connect_data ((m_pWidget), ("key-release-event"), ((
(GCallback) (signalKey))), (this), __null, (GConnectFlags) 0)
;
2437 weld::Widget::connect_key_release(rLink);
2438 }
2439
2440 virtual void connect_mouse_press(const Link<const MouseEvent&, bool>& rLink) override
2441 {
2442 ensureButtonPressSignal();
2443 weld::Widget::connect_mouse_press(rLink);
2444 }
2445
2446 virtual void connect_mouse_move(const Link<const MouseEvent&, bool>& rLink) override
2447 {
2448 ensureMouseEventWidget();
2449 if (!m_nMotionSignalId)
2450 m_nMotionSignalId = g_signal_connect(m_pMouseEventBox, "motion-notify-event", G_CALLBACK(signalMotion), this)g_signal_connect_data ((m_pMouseEventBox), ("motion-notify-event"
), (((GCallback) (signalMotion))), (this), __null, (GConnectFlags
) 0)
;
2451 if (!m_nLeaveSignalId)
2452 m_nLeaveSignalId = g_signal_connect(m_pMouseEventBox, "leave-notify-event", G_CALLBACK(signalCrossing), this)g_signal_connect_data ((m_pMouseEventBox), ("leave-notify-event"
), (((GCallback) (signalCrossing))), (this), __null, (GConnectFlags
) 0)
;
2453 if (!m_nEnterSignalId)
2454 m_nEnterSignalId = g_signal_connect(m_pMouseEventBox, "enter-notify-event", G_CALLBACK(signalCrossing), this)g_signal_connect_data ((m_pMouseEventBox), ("enter-notify-event"
), (((GCallback) (signalCrossing))), (this), __null, (GConnectFlags
) 0)
;
2455 weld::Widget::connect_mouse_move(rLink);
2456 }
2457
2458 virtual void connect_mouse_release(const Link<const MouseEvent&, bool>& rLink) override
2459 {
2460 ensureMouseEventWidget();
2461 if (!m_nButtonReleaseSignalId)
2462 m_nButtonReleaseSignalId = g_signal_connect(m_pMouseEventBox, "button-release-event", G_CALLBACK(signalButton), this)g_signal_connect_data ((m_pMouseEventBox), ("button-release-event"
), (((GCallback) (signalButton))), (this), __null, (GConnectFlags
) 0)
;
2463 weld::Widget::connect_mouse_release(rLink);
2464 }
2465
2466 virtual void set_sensitive(bool sensitive) override
2467 {
2468 gtk_widget_set_sensitive(m_pWidget, sensitive);
2469 }
2470
2471 virtual bool get_sensitive() const override
2472 {
2473 return gtk_widget_get_sensitive(m_pWidget);
2474 }
2475
2476 virtual bool get_visible() const override
2477 {
2478 return gtk_widget_get_visible(m_pWidget);
2479 }
2480
2481 virtual bool is_visible() const override
2482 {
2483 return gtk_widget_is_visible(m_pWidget);
2484 }
2485
2486 virtual void set_can_focus(bool bCanFocus) override
2487 {
2488 gtk_widget_set_can_focus(m_pWidget, bCanFocus);
2489 }
2490
2491 virtual void grab_focus() override
2492 {
2493 disable_notify_events();
2494 gtk_widget_grab_focus(m_pWidget);
2495 enable_notify_events();
2496 }
2497
2498 virtual bool has_focus() const override
2499 {
2500 return gtk_widget_has_focus(m_pWidget);
2501 }
2502
2503 virtual bool is_active() const override
2504 {
2505 GtkWindow* pTopLevel = GTK_WINDOW(gtk_widget_get_toplevel(m_pWidget))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(m_pWidget))), ((gtk_window_get_type (
)))))))
;
2506 return pTopLevel && gtk_window_is_active(pTopLevel) && has_focus();
2507 }
2508
2509 virtual void set_has_default(bool has_default) override
2510 {
2511 g_object_set(G_OBJECT(m_pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pWidget)), (((GType) ((20) << (2))))))))
, "has-default", has_default, nullptr);
2512 }
2513
2514 virtual bool get_has_default() const override
2515 {
2516 gboolean has_default(false);
2517 g_object_get(G_OBJECT(m_pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pWidget)), (((GType) ((20) << (2))))))))
, "has-default", &has_default, nullptr);
2518 return has_default;
2519 }
2520
2521 virtual void show() override
2522 {
2523 gtk_widget_show(m_pWidget);
2524 }
2525
2526 virtual void hide() override
2527 {
2528 gtk_widget_hide(m_pWidget);
2529 }
2530
2531 virtual void set_size_request(int nWidth, int nHeight) override
2532 {
2533 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
2534 if (GTK_IS_VIEWPORT(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_viewport_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2535 pParent = gtk_widget_get_parent(pParent);
2536 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2537 {
2538 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
, nWidth);
2539 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
, nHeight);
2540 }
2541 gtk_widget_set_size_request(m_pWidget, nWidth, nHeight);
2542 }
2543
2544 virtual Size get_size_request() const override
2545 {
2546 int nWidth, nHeight;
2547 gtk_widget_get_size_request(m_pWidget, &nWidth, &nHeight);
2548 return Size(nWidth, nHeight);
2549 }
2550
2551 virtual Size get_preferred_size() const override
2552 {
2553 GtkRequisition size;
2554 gtk_widget_get_preferred_size(m_pWidget, nullptr, &size);
2555 return Size(size.width, size.height);
2556 }
2557
2558 virtual float get_approximate_digit_width() const override
2559 {
2560 PangoContext* pContext = gtk_widget_get_pango_context(m_pWidget);
2561 PangoFontMetrics* pMetrics = pango_context_get_metrics(pContext,
2562 pango_context_get_font_description(pContext),
2563 pango_context_get_language(pContext));
2564 float nDigitWidth = pango_font_metrics_get_approximate_digit_width(pMetrics);
2565 pango_font_metrics_unref(pMetrics);
2566
2567 return nDigitWidth / PANGO_SCALE1024;
2568 }
2569
2570 virtual int get_text_height() const override
2571 {
2572 PangoContext* pContext = gtk_widget_get_pango_context(m_pWidget);
2573 PangoFontMetrics* pMetrics = pango_context_get_metrics(pContext,
2574 pango_context_get_font_description(pContext),
2575 pango_context_get_language(pContext));
2576 int nLineHeight = pango_font_metrics_get_ascent(pMetrics) + pango_font_metrics_get_descent(pMetrics);
2577 pango_font_metrics_unref(pMetrics);
2578 return nLineHeight / PANGO_SCALE1024;
2579 }
2580
2581 virtual Size get_pixel_size(const OUString& rText) const override
2582 {
2583 OString aStr(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
2584 PangoLayout* pLayout = gtk_widget_create_pango_layout(m_pWidget, aStr.getStr());
2585 gint nWidth, nHeight;
2586 pango_layout_get_pixel_size(pLayout, &nWidth, &nHeight);
2587 g_object_unref(pLayout);
2588 return Size(nWidth, nHeight);
2589 }
2590
2591 virtual vcl::Font get_font() override
2592 {
2593 PangoContext* pContext = gtk_widget_get_pango_context(m_pWidget);
2594 return pango_to_vcl(pango_context_get_font_description(pContext),
2595 Application::GetSettings().GetUILanguageTag().getLocale());
2596 }
2597
2598 virtual void set_grid_left_attach(int nAttach) override
2599 {
2600 GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_widget_get_parent(m_pWidget))), ((gtk_container_get_type
()))))))
;
2601 gtk_container_child_set(pParent, m_pWidget, "left-attach", nAttach, nullptr);
2602 }
2603
2604 virtual int get_grid_left_attach() const override
2605 {
2606 GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_widget_get_parent(m_pWidget))), ((gtk_container_get_type
()))))))
;
2607 gint nAttach(0);
2608 gtk_container_child_get(pParent, m_pWidget, "left-attach", &nAttach, nullptr);
2609 return nAttach;
2610 }
2611
2612 virtual void set_grid_width(int nCols) override
2613 {
2614 GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_widget_get_parent(m_pWidget))), ((gtk_container_get_type
()))))))
;
2615 gtk_container_child_set(pParent, m_pWidget, "width", nCols, nullptr);
2616 }
2617
2618 virtual void set_grid_top_attach(int nAttach) override
2619 {
2620 GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_widget_get_parent(m_pWidget))), ((gtk_container_get_type
()))))))
;
2621 gtk_container_child_set(pParent, m_pWidget, "top-attach", nAttach, nullptr);
2622 }
2623
2624 virtual int get_grid_top_attach() const override
2625 {
2626 GtkContainer* pParent = GTK_CONTAINER(gtk_widget_get_parent(m_pWidget))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_widget_get_parent(m_pWidget))), ((gtk_container_get_type
()))))))
;
2627 gint nAttach(0);
2628 gtk_container_child_get(pParent, m_pWidget, "top-attach", &nAttach, nullptr);
2629 return nAttach;
2630 }
2631
2632 virtual void set_hexpand(bool bExpand) override
2633 {
2634 gtk_widget_set_hexpand(m_pWidget, bExpand);
2635 }
2636
2637 virtual bool get_hexpand() const override
2638 {
2639 return gtk_widget_get_hexpand(m_pWidget);
2640 }
2641
2642 virtual void set_vexpand(bool bExpand) override
2643 {
2644 gtk_widget_set_vexpand(m_pWidget, bExpand);
2645 }
2646
2647 virtual bool get_vexpand() const override
2648 {
2649 return gtk_widget_get_vexpand(m_pWidget);
2650 }
2651
2652 virtual void set_secondary(bool bSecondary) override
2653 {
2654 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
2655 if (pParent && GTK_IS_BUTTON_BOX(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_button_box_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2656 gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(pParent)((((GtkButtonBox*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_button_box_get_type ()))))))
, m_pWidget, bSecondary);
2657 }
2658
2659 virtual void set_margin_top(int nMargin) override
2660 {
2661 gtk_widget_set_margin_top(m_pWidget, nMargin);
2662 }
2663
2664 virtual void set_margin_bottom(int nMargin) override
2665 {
2666 gtk_widget_set_margin_bottom(m_pWidget, nMargin);
2667 }
2668
2669 virtual void set_margin_left(int nMargin) override
2670 {
2671 gtk_widget_set_margin_left(m_pWidget, nMargin);
2672 }
2673
2674 virtual void set_margin_right(int nMargin) override
2675 {
2676 gtk_widget_set_margin_right(m_pWidget, nMargin);
2677 }
2678
2679 virtual int get_margin_top() const override
2680 {
2681 return gtk_widget_get_margin_top(m_pWidget);
2682 }
2683
2684 virtual int get_margin_bottom() const override
2685 {
2686 return gtk_widget_get_margin_bottom(m_pWidget);
2687 }
2688
2689 virtual int get_margin_left() const override
2690 {
2691 return gtk_widget_get_margin_left(m_pWidget);
2692 }
2693
2694 virtual int get_margin_right() const override
2695 {
2696 return gtk_widget_get_margin_right(m_pWidget);
2697 }
2698
2699 virtual void set_accessible_name(const OUString& rName) override
2700 {
2701 AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
2702 if (!pAtkObject)
2703 return;
2704 atk_object_set_name(pAtkObject, OUStringToOString(rName, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
2705 }
2706
2707 virtual OUString get_accessible_name() const override
2708 {
2709 AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
2710 const char* pStr = pAtkObject ? atk_object_get_name(pAtkObject) : nullptr;
2711 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
2712 }
2713
2714 virtual OUString get_accessible_description() const override
2715 {
2716 AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
2717 const char* pStr = pAtkObject ? atk_object_get_description(pAtkObject) : nullptr;
2718 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
2719 }
2720
2721 virtual void set_accessible_relation_labeled_by(weld::Widget* pLabel) override
2722 {
2723 AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
2724 if (!pAtkObject)
2725 return;
2726 AtkObject *pAtkLabel = pLabel ? gtk_widget_get_accessible(dynamic_cast<GtkInstanceWidget&>(*pLabel).getWidget()) : nullptr;
2727 AtkRelationSet *pRelationSet = atk_object_ref_relation_set(pAtkObject);
2728 AtkRelation *pRelation = atk_relation_set_get_relation_by_type(pRelationSet, ATK_RELATION_LABELLED_BY);
2729 if (pRelation)
2730 atk_relation_set_remove(pRelationSet, pRelation);
2731 if (pAtkLabel)
2732 {
2733 AtkObject *obj_array[1];
2734 obj_array[0] = pAtkLabel;
2735 pRelation = atk_relation_new(obj_array, 1, ATK_RELATION_LABELLED_BY);
2736 atk_relation_set_add(pRelationSet, pRelation);
2737 }
2738 g_object_unref(pRelationSet);
2739 }
2740
2741 virtual void set_accessible_relation_label_for(weld::Widget* pLabeled) override
2742 {
2743 AtkObject* pAtkObject = gtk_widget_get_accessible(m_pWidget);
2744 if (!pAtkObject)
2745 return;
2746 AtkObject *pAtkLabeled = pLabeled ? gtk_widget_get_accessible(dynamic_cast<GtkInstanceWidget&>(*pLabeled).getWidget()) : nullptr;
2747 AtkRelationSet *pRelationSet = atk_object_ref_relation_set(pAtkObject);
2748 AtkRelation *pRelation = atk_relation_set_get_relation_by_type(pRelationSet, ATK_RELATION_LABEL_FOR);
2749 if (pRelation)
2750 atk_relation_set_remove(pRelationSet, pRelation);
2751 if (pAtkLabeled)
2752 {
2753 AtkObject *obj_array[1];
2754 obj_array[0] = pAtkLabeled;
2755 pRelation = atk_relation_new(obj_array, 1, ATK_RELATION_LABEL_FOR);
2756 atk_relation_set_add(pRelationSet, pRelation);
2757 }
2758 g_object_unref(pRelationSet);
2759 }
2760
2761 virtual bool get_extents_relative_to(const weld::Widget& rRelative, int& x, int &y, int& width, int &height) const override
2762 {
2763 //for toplevel windows this is sadly futile under wayland, so we can't tell where a dialog is in order to allow
2764 //the document underneath to auto-scroll to place content in a visible location
2765 bool ret = gtk_widget_translate_coordinates(m_pWidget,
2766 dynamic_cast<const GtkInstanceWidget&>(rRelative).getWidget(),
2767 0, 0, &x, &y);
2768 width = gtk_widget_get_allocated_width(m_pWidget);
2769 height = gtk_widget_get_allocated_height(m_pWidget);
2770 return ret;
2771 }
2772
2773 virtual void set_tooltip_text(const OUString& rTip) override
2774 {
2775 gtk_widget_set_tooltip_text(m_pWidget, OUStringToOString(rTip, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
2776 }
2777
2778 virtual OUString get_tooltip_text() const override
2779 {
2780 const gchar* pStr = gtk_widget_get_tooltip_text(m_pWidget);
2781 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
2782 }
2783
2784 virtual std::unique_ptr<weld::Container> weld_parent() const override;
2785
2786 virtual OString get_buildable_name() const override
2787 {
2788 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(m_pWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pWidget)), ((gtk_buildable_get_type ()))))))
);
2789 return OString(pStr, pStr ? strlen(pStr) : 0);
2790 }
2791
2792 virtual void set_help_id(const OString& rHelpId) override
2793 {
2794 ::set_help_id(m_pWidget, rHelpId);
2795 }
2796
2797 virtual OString get_help_id() const override
2798 {
2799 OString sRet = ::get_help_id(m_pWidget);
2800 if (sRet.isEmpty())
2801 sRet = OString("null");
2802 return sRet;
2803 }
2804
2805 GtkWidget* getWidget() const
2806 {
2807 return m_pWidget;
2808 }
2809
2810 GtkWindow* getWindow()
2811 {
2812 return GTK_WINDOW(gtk_widget_get_toplevel(m_pWidget))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(m_pWidget))), ((gtk_window_get_type (
)))))))
;
2813 }
2814
2815 virtual void connect_focus_in(const Link<Widget&, void>& rLink) override
2816 {
2817 if (!m_nFocusInSignalId)
2818 m_nFocusInSignalId = g_signal_connect(m_pWidget, "focus-in-event", G_CALLBACK(signalFocusIn), this)g_signal_connect_data ((m_pWidget), ("focus-in-event"), (((GCallback
) (signalFocusIn))), (this), __null, (GConnectFlags) 0)
;
2819 weld::Widget::connect_focus_in(rLink);
2820 }
2821
2822 virtual void connect_mnemonic_activate(const Link<Widget&, bool>& rLink) override
2823 {
2824 if (!m_nMnemonicActivateSignalId)
2825 m_nMnemonicActivateSignalId = g_signal_connect(m_pWidget, "mnemonic-activate", G_CALLBACK(signalMnemonicActivate), this)g_signal_connect_data ((m_pWidget), ("mnemonic-activate"), ((
(GCallback) (signalMnemonicActivate))), (this), __null, (GConnectFlags
) 0)
;
2826 weld::Widget::connect_mnemonic_activate(rLink);
2827 }
2828
2829 virtual void connect_focus_out(const Link<Widget&, void>& rLink) override
2830 {
2831 if (!m_nFocusOutSignalId)
2832 m_nFocusOutSignalId = g_signal_connect(m_pWidget, "focus-out-event", G_CALLBACK(signalFocusOut), this)g_signal_connect_data ((m_pWidget), ("focus-out-event"), (((GCallback
) (signalFocusOut))), (this), __null, (GConnectFlags) 0)
;
2833 weld::Widget::connect_focus_out(rLink);
2834 }
2835
2836 virtual void connect_size_allocate(const Link<const Size&, void>& rLink) override
2837 {
2838 m_nSizeAllocateSignalId = g_signal_connect(m_pWidget, "size_allocate", G_CALLBACK(signalSizeAllocate), this)g_signal_connect_data ((m_pWidget), ("size_allocate"), (((GCallback
) (signalSizeAllocate))), (this), __null, (GConnectFlags) 0)
;
2839 weld::Widget::connect_size_allocate(rLink);
2840 }
2841
2842 virtual void signal_size_allocate(guint nWidth, guint nHeight)
2843 {
2844 m_aSizeAllocateHdl.Call(Size(nWidth, nHeight));
2845 }
2846
2847 bool signal_key(const GdkEventKey* pEvent)
2848 {
2849 if (pEvent->type == GDK_KEY_PRESS && m_aKeyPressHdl.IsSet())
2850 {
2851 SolarMutexGuard aGuard;
2852 return m_aKeyPressHdl.Call(GtkToVcl(*pEvent));
2853 }
2854 if (pEvent->type == GDK_KEY_RELEASE && m_aKeyReleaseHdl.IsSet())
2855 {
2856 SolarMutexGuard aGuard;
2857 return m_aKeyReleaseHdl.Call(GtkToVcl(*pEvent));
2858 }
2859 return false;
2860 }
2861
2862 virtual void grab_add() override
2863 {
2864 gtk_grab_add(m_pWidget);
2865 }
2866
2867 virtual bool has_grab() const override
2868 {
2869 return gtk_widget_has_grab(m_pWidget);
2870 }
2871
2872 virtual void grab_remove() override
2873 {
2874 gtk_grab_remove(m_pWidget);
2875 }
2876
2877 virtual bool get_direction() const override
2878 {
2879 return gtk_widget_get_direction(m_pWidget) == GTK_TEXT_DIR_RTL;
2880 }
2881
2882 virtual void set_direction(bool bRTL) override
2883 {
2884 gtk_widget_set_direction(m_pWidget, bRTL ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
2885 }
2886
2887 virtual void freeze() override
2888 {
2889 gtk_widget_freeze_child_notify(m_pWidget);
2890 g_object_freeze_notify(G_OBJECT(m_pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pWidget)), (((GType) ((20) << (2))))))))
);
2891 }
2892
2893 virtual void thaw() override
2894 {
2895 g_object_thaw_notify(G_OBJECT(m_pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pWidget)), (((GType) ((20) << (2))))))))
);
2896 gtk_widget_thaw_child_notify(m_pWidget);
2897 }
2898
2899 virtual css::uno::Reference<css::datatransfer::dnd::XDropTarget> get_drop_target() override
2900 {
2901 if (!m_xDropTarget)
2902 {
2903 m_xDropTarget.set(new GtkDropTarget);
2904 if (!gtk_drag_dest_get_track_motion(m_pWidget))
2905 {
2906 gtk_drag_dest_set(m_pWidget, GtkDestDefaults(0), nullptr, 0, GdkDragAction(0));
2907 gtk_drag_dest_set_track_motion(m_pWidget, true);
2908 }
2909 m_nDragMotionSignalId = g_signal_connect(m_pWidget, "drag-motion", G_CALLBACK(signalDragMotion), this)g_signal_connect_data ((m_pWidget), ("drag-motion"), (((GCallback
) (signalDragMotion))), (this), __null, (GConnectFlags) 0)
;
2910 m_nDragDropSignalId = g_signal_connect(m_pWidget, "drag-drop", G_CALLBACK(signalDragDrop), this)g_signal_connect_data ((m_pWidget), ("drag-drop"), (((GCallback
) (signalDragDrop))), (this), __null, (GConnectFlags) 0)
;
2911 m_nDragDropReceivedSignalId = g_signal_connect(m_pWidget, "drag-data-received", G_CALLBACK(signalDragDropReceived), this)g_signal_connect_data ((m_pWidget), ("drag-data-received"), (
((GCallback) (signalDragDropReceived))), (this), __null, (GConnectFlags
) 0)
;
2912 m_nDragLeaveSignalId = g_signal_connect(m_pWidget, "drag-leave", G_CALLBACK(signalDragLeave), this)g_signal_connect_data ((m_pWidget), ("drag-leave"), (((GCallback
) (signalDragLeave))), (this), __null, (GConnectFlags) 0)
;
2913 }
2914 return m_xDropTarget.get();
2915 }
2916
2917 virtual void connect_get_property_tree(const Link<tools::JsonWriter&, void>& /*rLink*/) override
2918 {
2919 //not implemented for the gtk variant
2920 }
2921
2922 virtual void set_stack_background() override
2923 {
2924 do_set_background(Application::GetSettings().GetStyleSettings().GetWindowColor());
2925 }
2926
2927 virtual void set_title_background() override
2928 {
2929 do_set_background(Application::GetSettings().GetStyleSettings().GetShadowColor());
2930 }
2931
2932 virtual void set_highlight_background() override
2933 {
2934 do_set_background(Application::GetSettings().GetStyleSettings().GetHighlightColor());
2935 }
2936
2937 virtual void set_background(const Color& rColor) override
2938 {
2939 do_set_background(rColor);
2940 }
2941
2942 virtual void set_toolbar_background() override
2943 {
2944 // no-op
2945 }
2946
2947 virtual ~GtkInstanceWidget() override
2948 {
2949 if (m_pFocusInEvent)
2950 Application::RemoveUserEvent(m_pFocusInEvent);
2951 if (m_pFocusOutEvent)
2952 Application::RemoveUserEvent(m_pFocusOutEvent);
2953 if (m_pDragCancelEvent)
2954 Application::RemoveUserEvent(m_pDragCancelEvent);
2955 if (m_nDragMotionSignalId)
2956 g_signal_handler_disconnect(m_pWidget, m_nDragMotionSignalId);
2957 if (m_nDragDropSignalId)
2958 g_signal_handler_disconnect(m_pWidget, m_nDragDropSignalId);
2959 if (m_nDragDropReceivedSignalId)
2960 g_signal_handler_disconnect(m_pWidget, m_nDragDropReceivedSignalId);
2961 if (m_nDragLeaveSignalId)
2962 g_signal_handler_disconnect(m_pWidget, m_nDragLeaveSignalId);
2963 if (m_nDragEndSignalId)
2964 g_signal_handler_disconnect(m_pWidget, m_nDragEndSignalId);
2965 if (m_nDragBeginSignalId)
2966 g_signal_handler_disconnect(m_pWidget, m_nDragBeginSignalId);
2967 if (m_nDragFailedSignalId)
2968 g_signal_handler_disconnect(m_pWidget, m_nDragFailedSignalId);
2969 if (m_nDragDataDeleteignalId)
2970 g_signal_handler_disconnect(m_pWidget, m_nDragDataDeleteignalId);
2971 if (m_nDragGetSignalId)
2972 g_signal_handler_disconnect(m_pWidget, m_nDragGetSignalId);
2973 if (m_nKeyPressSignalId)
2974 g_signal_handler_disconnect(m_pWidget, m_nKeyPressSignalId);
2975 if (m_nKeyReleaseSignalId)
2976 g_signal_handler_disconnect(m_pWidget, m_nKeyReleaseSignalId);
2977 if (m_nButtonPressSignalId)
2978 g_signal_handler_disconnect(m_pMouseEventBox, m_nButtonPressSignalId);
2979 if (m_nMotionSignalId)
2980 g_signal_handler_disconnect(m_pMouseEventBox, m_nMotionSignalId);
2981 if (m_nLeaveSignalId)
2982 g_signal_handler_disconnect(m_pMouseEventBox, m_nLeaveSignalId);
2983 if (m_nEnterSignalId)
2984 g_signal_handler_disconnect(m_pMouseEventBox, m_nEnterSignalId);
2985 if (m_nButtonReleaseSignalId)
2986 g_signal_handler_disconnect(m_pMouseEventBox, m_nButtonReleaseSignalId);
2987 if (m_nFocusInSignalId)
2988 g_signal_handler_disconnect(m_pWidget, m_nFocusInSignalId);
2989 if (m_nMnemonicActivateSignalId)
2990 g_signal_handler_disconnect(m_pWidget, m_nMnemonicActivateSignalId);
2991 if (m_nFocusOutSignalId)
2992 g_signal_handler_disconnect(m_pWidget, m_nFocusOutSignalId);
2993 if (m_nSizeAllocateSignalId)
2994 g_signal_handler_disconnect(m_pWidget, m_nSizeAllocateSignalId);
2995
2996 do_set_background(COL_AUTO);
2997
2998 if (m_pMouseEventBox && m_pMouseEventBox != m_pWidget)
2999 {
3000 // put things back they way we found them
3001 GtkWidget* pParent = gtk_widget_get_parent(m_pMouseEventBox);
3002
3003 g_object_ref(m_pWidget);
3004 gtk_container_remove(GTK_CONTAINER(m_pMouseEventBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMouseEventBox)), ((gtk_container_get_type ()))))))
, m_pWidget);
3005
3006 gtk_widget_destroy(m_pMouseEventBox);
3007
3008 gtk_container_add(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, m_pWidget);
3009 g_object_unref(m_pWidget);
3010 }
3011
3012 if (m_bTakeOwnership)
3013 gtk_widget_destroy(m_pWidget);
3014 else
3015 g_object_unref(m_pWidget);
3016 }
3017
3018 virtual void disable_notify_events()
3019 {
3020 if (m_nFocusInSignalId)
3021 g_signal_handler_block(m_pWidget, m_nFocusInSignalId);
3022 if (m_nMnemonicActivateSignalId)
3023 g_signal_handler_block(m_pWidget, m_nMnemonicActivateSignalId);
3024 if (m_nFocusOutSignalId)
3025 g_signal_handler_block(m_pWidget, m_nFocusOutSignalId);
3026 if (m_nSizeAllocateSignalId)
3027 g_signal_handler_block(m_pWidget, m_nSizeAllocateSignalId);
3028 }
3029
3030 virtual void enable_notify_events()
3031 {
3032 if (m_nSizeAllocateSignalId)
3033 g_signal_handler_unblock(m_pWidget, m_nSizeAllocateSignalId);
3034 if (m_nFocusOutSignalId)
3035 g_signal_handler_unblock(m_pWidget, m_nFocusOutSignalId);
3036 if (m_nMnemonicActivateSignalId)
3037 g_signal_handler_unblock(m_pWidget, m_nMnemonicActivateSignalId);
3038 if (m_nFocusInSignalId)
3039 g_signal_handler_unblock(m_pWidget, m_nFocusInSignalId);
3040 }
3041
3042 virtual void help_hierarchy_foreach(const std::function<bool(const OString&)>& func) override;
3043
3044 virtual OUString strip_mnemonic(const OUString &rLabel) const override
3045 {
3046 return rLabel.replaceFirst("_", "");
3047 }
3048
3049 virtual VclPtr<VirtualDevice> create_virtual_device() const override
3050 {
3051 // create with no separate alpha layer like everything sane does
3052 auto xRet = VclPtr<VirtualDevice>::Create();
3053 xRet->SetBackground(COL_TRANSPARENT);
3054 return xRet;
3055 }
3056
3057 virtual void draw(OutputDevice& rOutput, const tools::Rectangle& rRect) override
3058 {
3059 // detect if we have to manually setup its size
3060 bool bAlreadyRealized = gtk_widget_get_realized(m_pWidget);
3061 // has to be visible for draw to work
3062 bool bAlreadyVisible = gtk_widget_get_visible(m_pWidget);
3063 // has to be mapped for draw to work
3064 bool bAlreadyMapped = gtk_widget_get_mapped(m_pWidget);
3065
3066 if (!bAlreadyRealized)
3067 gtk_widget_realize(m_pWidget);
3068 if (!bAlreadyVisible)
3069 gtk_widget_show(m_pWidget);
3070 if (!bAlreadyMapped)
3071 gtk_widget_map(m_pWidget);
3072
3073 assert(gtk_widget_is_drawable(m_pWidget))(static_cast <bool> (gtk_widget_is_drawable(m_pWidget))
? void (0) : __assert_fail ("gtk_widget_is_drawable(m_pWidget)"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3073, __extension__ __PRETTY_FUNCTION__))
; // all that should result in this holding
3074
3075 // turn off animations, otherwise we get a frame of an animation sequence
3076 gboolean bAnimations;
3077 GtkSettings* pSettings = gtk_widget_get_settings(m_pWidget);
3078 g_object_get(pSettings, "gtk-enable-animations", &bAnimations, nullptr);
3079 if (bAnimations)
3080 g_object_set(pSettings, "gtk-enable-animations", false, nullptr);
3081
3082 Size aSize(rRect.GetSize());
3083
3084 GtkAllocation aOrigAllocation;
3085 gtk_widget_get_allocation(m_pWidget, &aOrigAllocation);
3086
3087 GtkAllocation aNewAllocation {aOrigAllocation.x,
3088 aOrigAllocation.y,
3089 static_cast<int>(aSize.Width()),
3090 static_cast<int>(aSize.Height()) };
3091 gtk_widget_size_allocate(m_pWidget, &aNewAllocation);
3092
3093 if (GTK_IS_CONTAINER(m_pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pWidget)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
3094 gtk_container_resize_children(GTK_CONTAINER(m_pWidget)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pWidget)), ((gtk_container_get_type ()))))))
);
3095
3096 VclPtr<VirtualDevice> xOutput(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
3097 xOutput->SetOutputSizePixel(aSize);
3098 xOutput->DrawOutDev(Point(), aSize, rRect.TopLeft(), aSize, rOutput);
3099
3100 cairo_surface_t* pSurface = get_underlying_cairo_surface(*xOutput);
3101 cairo_t* cr = cairo_create(pSurface);
3102
3103 gtk_widget_draw(m_pWidget, cr);
3104
3105 cairo_destroy(cr);
3106
3107 gtk_widget_set_allocation(m_pWidget, &aOrigAllocation);
3108 gtk_widget_size_allocate(m_pWidget, &aOrigAllocation);
3109
3110 rOutput.DrawOutDev(rRect.TopLeft(), aSize, Point(), aSize, *xOutput);
3111
3112 if (bAnimations)
3113 g_object_set(pSettings, "gtk-enable-animations", true, nullptr);
3114
3115 if (!bAlreadyMapped)
3116 gtk_widget_unmap(m_pWidget);
3117 if (!bAlreadyVisible)
3118 gtk_widget_hide(m_pWidget);
3119 if (!bAlreadyRealized)
3120 gtk_widget_unrealize(m_pWidget);
3121 }
3122};
3123
3124}
3125
3126IMPL_LINK_NOARG(GtkInstanceWidget, async_signal_focus_in, void*, void)void GtkInstanceWidget::LinkStubasync_signal_focus_in(void * instance
, void* data) { return static_cast<GtkInstanceWidget *>
(instance)->async_signal_focus_in(data); } void GtkInstanceWidget
::async_signal_focus_in(__attribute__ ((unused)) void*)
3127{
3128 m_pFocusInEvent = nullptr;
3129 signal_focus_in();
3130}
3131
3132IMPL_LINK_NOARG(GtkInstanceWidget, async_signal_focus_out, void*, void)void GtkInstanceWidget::LinkStubasync_signal_focus_out(void *
instance, void* data) { return static_cast<GtkInstanceWidget
*>(instance)->async_signal_focus_out(data); } void GtkInstanceWidget
::async_signal_focus_out(__attribute__ ((unused)) void*)
3133{
3134 m_pFocusOutEvent = nullptr;
3135 signal_focus_out();
3136}
3137
3138IMPL_LINK(GtkInstanceWidget, async_drag_cancel, void*, arg, void)void GtkInstanceWidget::LinkStubasync_drag_cancel(void * instance
, void* data) { return static_cast<GtkInstanceWidget *>
(instance)->async_drag_cancel(data); } void GtkInstanceWidget
::async_drag_cancel(void* arg)
3139{
3140 m_pDragCancelEvent = nullptr;
3141 GdkDragContext* context = static_cast<GdkDragContext*>(arg);
3142
3143 // tdf#132477 simply calling gtk_drag_cancel on the treeview dnd under X
3144 // doesn't seem to work as hoped for (though under wayland all is well).
3145 // Under X the next (allowed) drag effort doesn't work to drop anything,
3146 // but a then repeated attempt does.
3147 // emitting cancel to get gtk to cancel the drag for us does work as hoped for.
3148 g_signal_emit_by_name(context, "cancel", 0, GDK_DRAG_CANCEL_USER_CANCELLED);
3149
3150 g_object_unref(context);
3151}
3152
3153namespace
3154{
3155 OString MapToGtkAccelerator(const OUString &rStr)
3156 {
3157 return OUStringToOString(rStr.replaceFirst("~", "_"), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3158 }
3159
3160 OUString get_label(GtkLabel* pLabel)
3161 {
3162 const gchar* pStr = gtk_label_get_label(pLabel);
3163 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3164 }
3165
3166 void set_label(GtkLabel* pLabel, const OUString& rText)
3167 {
3168 gtk_label_set_label(pLabel, MapToGtkAccelerator(rText).getStr());
3169 }
3170
3171 OUString get_label(GtkButton* pButton)
3172 {
3173 const gchar* pStr = gtk_button_get_label(pButton);
3174 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3175 }
3176
3177 void set_label(GtkButton* pButton, const OUString& rText)
3178 {
3179 gtk_button_set_label(pButton, MapToGtkAccelerator(rText).getStr());
3180 }
3181
3182 OUString get_title(GtkWindow* pWindow)
3183 {
3184 const gchar* pStr = gtk_window_get_title(pWindow);
3185 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3186 }
3187
3188 void set_title(GtkWindow* pWindow, const OUString& rTitle)
3189 {
3190 gtk_window_set_title(pWindow, OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
3191 }
3192
3193 OUString get_primary_text(GtkMessageDialog* pMessageDialog)
3194 {
3195 gchar* pText = nullptr;
3196 g_object_get(G_OBJECT(pMessageDialog)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pMessageDialog)), (((GType) ((20) << (2))))))))
, "text", &pText, nullptr);
3197 return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3198 }
3199
3200 void set_primary_text(GtkMessageDialog* pMessageDialog, const OUString& rText)
3201 {
3202 g_object_set(G_OBJECT(pMessageDialog)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pMessageDialog)), (((GType) ((20) << (2))))))))
, "text",
3203 OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
3204 nullptr);
3205 }
3206
3207 void set_secondary_text(GtkMessageDialog* pMessageDialog, const OUString& rText)
3208 {
3209 g_object_set(G_OBJECT(pMessageDialog)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pMessageDialog)), (((GType) ((20) << (2))))))))
, "secondary-text",
3210 OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
3211 nullptr);
3212 }
3213
3214 OUString get_secondary_text(GtkMessageDialog* pMessageDialog)
3215 {
3216 gchar* pText = nullptr;
3217 g_object_get(G_OBJECT(pMessageDialog)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pMessageDialog)), (((GType) ((20) << (2))))))))
, "secondary-text", &pText, nullptr);
3218 return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3219 }
3220}
3221
3222namespace
3223{
3224 GdkPixbuf* load_icon_from_stream(SvMemoryStream& rStream, const OString& image_type)
3225 {
3226 // if we know the image type, it's a little faster to hand the type over and skip the type
3227 // detection.
3228 GdkPixbufLoader *pixbuf_loader = gdk_pixbuf_loader_new_with_type(image_type.getStr(), nullptr);
3229 gdk_pixbuf_loader_write(pixbuf_loader, static_cast<const guchar*>(rStream.GetData()),
3230 rStream.TellEnd(), nullptr);
3231 gdk_pixbuf_loader_close(pixbuf_loader, nullptr);
3232 GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(pixbuf_loader);
3233 if (pixbuf)
3234 g_object_ref(pixbuf);
3235 g_object_unref(pixbuf_loader);
3236 return pixbuf;
3237 }
3238
3239 GdkPixbuf* load_icon_by_name_theme_lang(const OUString& rIconName, const OUString& rIconTheme, const OUString& rUILang)
3240 {
3241 auto xMemStm = ImageTree::get().getImageStream(rIconName, rIconTheme, rUILang);
3242 if (!xMemStm)
3243 return nullptr;
3244 OUString sImageType = rIconName.copy(rIconName.lastIndexOf('.')+1).toAsciiLowerCase();
3245 return load_icon_from_stream(*xMemStm, sImageType.toUtf8());
3246 }
3247}
3248
3249GdkPixbuf* load_icon_by_name(const OUString& rIconName)
3250{
3251 OUString sIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme();
3252 OUString sUILang = Application::GetSettings().GetUILanguageTag().getBcp47();
3253 return load_icon_by_name_theme_lang(rIconName, sIconTheme, sUILang);
3254}
3255
3256namespace
3257{
3258 GdkPixbuf* getPixbuf(const css::uno::Reference<css::graphic::XGraphic>& rImage)
3259 {
3260 Image aImage(rImage);
3261
3262 OUString sStock(aImage.GetStock());
3263 if (!sStock.isEmpty())
3264 return load_icon_by_name(sStock);
3265
3266 std::unique_ptr<SvMemoryStream> xMemStm(new SvMemoryStream);
3267
3268 css::uno::Sequence<css::beans::PropertyValue> aFilterData(1);
3269 aFilterData[0].Name = "Compression";
3270 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed.
3271 aFilterData[0].Value <<= sal_Int32(1);
3272
3273 vcl::PNGWriter aWriter(aImage.GetBitmapEx(), &aFilterData);
3274 aWriter.Write(*xMemStm);
3275
3276 return load_icon_from_stream(*xMemStm, "png");
3277 }
3278
3279 GdkPixbuf* getPixbuf(const VirtualDevice& rDevice)
3280 {
3281 Size aSize(rDevice.GetOutputSizePixel());
3282 cairo_surface_t* orig_surface = get_underlying_cairo_surface(rDevice);
3283 double m_fXScale, m_fYScale;
3284 dl_cairo_surface_get_device_scale(orig_surface, &m_fXScale, &m_fYScale);
3285
3286 cairo_surface_t* surface;
3287 if (m_fXScale != 1.0 || m_fYScale != -1)
3288 {
3289 surface = cairo_surface_create_similar_image(orig_surface,
3290 CAIRO_FORMAT_ARGB32,
3291 aSize.Width(),
3292 aSize.Height());
3293 cairo_t* cr = cairo_create(surface);
3294 cairo_set_source_surface(cr, orig_surface, 0, 0);
3295 cairo_paint(cr);
3296 cairo_destroy(cr);
3297 }
3298 else
3299 surface = orig_surface;
3300
3301 GdkPixbuf* pRet = gdk_pixbuf_get_from_surface(surface, 0, 0, aSize.Width(), aSize.Height());
3302
3303 if (surface != orig_surface)
3304 cairo_surface_destroy(surface);
3305
3306 return pRet;
3307 }
3308
3309 GdkPixbuf* getPixbuf(const OUString& rIconName)
3310 {
3311 if (rIconName.isEmpty())
3312 return nullptr;
3313
3314 GdkPixbuf* pixbuf = nullptr;
3315
3316 if (rIconName.lastIndexOf('.') != rIconName.getLength() - 4)
3317 {
3318 assert((rIconName== "dialog-warning" || rIconName== "dialog-error" || rIconName== "dialog-information") &&(static_cast <bool> ((rIconName== "dialog-warning" || rIconName
== "dialog-error" || rIconName== "dialog-information") &&
"unknown stock image") ? void (0) : __assert_fail ("(rIconName== \"dialog-warning\" || rIconName== \"dialog-error\" || rIconName== \"dialog-information\") && \"unknown stock image\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3319, __extension__ __PRETTY_FUNCTION__))
3319 "unknown stock image")(static_cast <bool> ((rIconName== "dialog-warning" || rIconName
== "dialog-error" || rIconName== "dialog-information") &&
"unknown stock image") ? void (0) : __assert_fail ("(rIconName== \"dialog-warning\" || rIconName== \"dialog-error\" || rIconName== \"dialog-information\") && \"unknown stock image\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3319, __extension__ __PRETTY_FUNCTION__))
;
3320
3321 GError *error = nullptr;
3322 GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
3323 pixbuf = gtk_icon_theme_load_icon(icon_theme, OUStringToOString(rIconName, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
3324 16, GTK_ICON_LOOKUP_USE_BUILTIN, &error);
3325 }
3326 else
3327 {
3328 const AllSettings& rSettings = Application::GetSettings();
3329 pixbuf = load_icon_by_name_theme_lang(rIconName,
3330 rSettings.GetStyleSettings().DetermineIconTheme(),
3331 rSettings.GetUILanguageTag().getBcp47());
3332 }
3333
3334 return pixbuf;
3335 }
3336
3337 GtkWidget* image_new_from_virtual_device(const VirtualDevice& rImageSurface)
3338 {
3339 GtkWidget* pImage = nullptr;
3340 if (gtk_check_version(3, 20, 0) == nullptr)
3341 {
3342 cairo_surface_t* surface = get_underlying_cairo_surface(rImageSurface);
3343
3344 Size aSize(rImageSurface.GetOutputSizePixel());
3345 cairo_surface_t* target = cairo_surface_create_similar(surface,
3346 cairo_surface_get_content(surface),
3347 aSize.Width(),
3348 aSize.Height());
3349
3350 cairo_t* cr = cairo_create(target);
3351 cairo_set_source_surface(cr, surface, 0, 0);
3352 cairo_paint(cr);
3353 cairo_destroy(cr);
3354 pImage = gtk_image_new_from_surface(target);
3355 cairo_surface_destroy(target);
3356 }
3357 else
3358 {
3359 GdkPixbuf* pixbuf = getPixbuf(rImageSurface);
3360 pImage = gtk_image_new_from_pixbuf(pixbuf);
3361 g_object_unref(pixbuf);
3362 }
3363 return pImage;
3364 }
3365
3366class MenuHelper
3367{
3368protected:
3369 GtkMenu* m_pMenu;
3370 bool m_bTakeOwnership;
3371 std::map<OString, GtkMenuItem*> m_aMap;
3372private:
3373
3374 static void collect(GtkWidget* pItem, gpointer widget)
3375 {
3376 GtkMenuItem* pMenuItem = GTK_MENU_ITEM(pItem)((((GtkMenuItem*) g_type_check_instance_cast ((GTypeInstance*
) ((pItem)), ((gtk_menu_item_get_type ()))))))
;
3377 if (GtkWidget* pSubMenu = gtk_menu_item_get_submenu(pMenuItem))
3378 gtk_container_foreach(GTK_CONTAINER(pSubMenu)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pSubMenu)), ((gtk_container_get_type ()))))))
, collect, widget);
3379 MenuHelper* pThis = static_cast<MenuHelper*>(widget);
3380 pThis->add_to_map(pMenuItem);
3381 }
3382
3383 static void signalActivate(GtkMenuItem* pItem, gpointer widget)
3384 {
3385 MenuHelper* pThis = static_cast<MenuHelper*>(widget);
3386 SolarMutexGuard aGuard;
3387 pThis->signal_activate(pItem);
3388 }
3389
3390 virtual void signal_activate(GtkMenuItem* pItem) = 0;
3391
3392public:
3393 MenuHelper(GtkMenu* pMenu, bool bTakeOwnership)
3394 : m_pMenu(pMenu)
3395 , m_bTakeOwnership(bTakeOwnership)
3396 {
3397 if (!m_pMenu)
3398 return;
3399 gtk_container_foreach(GTK_CONTAINER(m_pMenu)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenu)), ((gtk_container_get_type ()))))))
, collect, this);
3400 }
3401
3402 void add_to_map(GtkMenuItem* pMenuItem)
3403 {
3404 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pMenuItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pMenuItem)), ((gtk_buildable_get_type ()))))))
);
3405 OString id(pStr, pStr ? strlen(pStr) : 0);
3406 m_aMap[id] = pMenuItem;
3407 g_signal_connect(pMenuItem, "activate", G_CALLBACK(signalActivate), this)g_signal_connect_data ((pMenuItem), ("activate"), (((GCallback
) (signalActivate))), (this), __null, (GConnectFlags) 0)
;
3408 }
3409
3410 void remove_from_map(GtkMenuItem* pMenuItem)
3411 {
3412 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pMenuItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pMenuItem)), ((gtk_buildable_get_type ()))))))
);
3413 OString id(pStr, pStr ? strlen(pStr) : 0);
3414 auto iter = m_aMap.find(id);
3415 g_signal_handlers_disconnect_by_data(pMenuItem, this)g_signal_handlers_disconnect_matched ((pMenuItem), G_SIGNAL_MATCH_DATA
, 0, 0, __null, __null, (this))
;
3416 m_aMap.erase(iter);
3417 }
3418
3419 void disable_item_notify_events()
3420 {
3421 for (auto& a : m_aMap)
3422 g_signal_handlers_block_by_func(a.second, reinterpret_cast<void*>(signalActivate), this)g_signal_handlers_block_matched ((a.second), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<void*>(signalActivate)), (this))
;
3423 }
3424
3425 void enable_item_notify_events()
3426 {
3427 for (auto& a : m_aMap)
3428 g_signal_handlers_unblock_by_func(a.second, reinterpret_cast<void*>(signalActivate), this)g_signal_handlers_unblock_matched ((a.second), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<void*>(signalActivate)), (this))
;
3429 }
3430
3431 void insert_item(int pos, const OUString& rId, const OUString& rStr,
3432 const OUString* pIconName, const VirtualDevice* pImageSurface,
3433 TriState eCheckRadioFalse)
3434 {
3435 GtkWidget* pImage = nullptr;
3436 if (pIconName && !pIconName->isEmpty())
3437 {
3438 GdkPixbuf* pixbuf = load_icon_by_name(*pIconName);
3439 if (!pixbuf)
3440 {
3441 pImage = gtk_image_new_from_pixbuf(pixbuf);
3442 g_object_unref(pixbuf);
3443 }
3444 }
3445 else if (pImageSurface)
3446 pImage = image_new_from_virtual_device(*pImageSurface);
3447
3448 GtkWidget *pItem;
3449 if (pImage)
3450 {
3451 GtkWidget *pBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
3452 GtkWidget *pLabel = gtk_label_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr());
3453 pItem = eCheckRadioFalse != TRISTATE_INDET ? gtk_check_menu_item_new() : gtk_menu_item_new();
3454 gtk_container_add(GTK_CONTAINER(pBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pBox)), ((gtk_container_get_type ()))))))
, pImage);
3455 gtk_container_add(GTK_CONTAINER(pBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pBox)), ((gtk_container_get_type ()))))))
, pLabel);
3456 gtk_container_add(GTK_CONTAINER(pItem)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_container_get_type ()))))))
, pBox);
3457 gtk_widget_show_all(pItem);
3458 }
3459 else
3460 {
3461 pItem = eCheckRadioFalse != TRISTATE_INDET ? gtk_check_menu_item_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr())
3462 : gtk_menu_item_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr());
3463 }
3464
3465 if (eCheckRadioFalse == TRISTATE_FALSE)
3466 gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(pItem)((((GtkCheckMenuItem*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_check_menu_item_get_type ()))))))
, true);
3467
3468 gtk_buildable_set_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
, OUStringToOString(rId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
3469 gtk_menu_shell_append(GTK_MENU_SHELL(m_pMenu)((((GtkMenuShell*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenu)), ((gtk_menu_shell_get_type ()))))))
, pItem);
3470 gtk_widget_show(pItem);
3471 add_to_map(GTK_MENU_ITEM(pItem)((((GtkMenuItem*) g_type_check_instance_cast ((GTypeInstance*
) ((pItem)), ((gtk_menu_item_get_type ()))))))
);
3472 if (pos != -1)
3473 gtk_menu_reorder_child(m_pMenu, pItem, pos);
3474 }
3475
3476 void insert_separator(int pos, const OUString& rId)
3477 {
3478 GtkWidget* pItem = gtk_separator_menu_item_new();
3479 gtk_buildable_set_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
, OUStringToOString(rId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
3480 gtk_menu_shell_append(GTK_MENU_SHELL(m_pMenu)((((GtkMenuShell*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenu)), ((gtk_menu_shell_get_type ()))))))
, pItem);
3481 gtk_widget_show(pItem);
3482 add_to_map(GTK_MENU_ITEM(pItem)((((GtkMenuItem*) g_type_check_instance_cast ((GTypeInstance*
) ((pItem)), ((gtk_menu_item_get_type ()))))))
);
3483 if (pos != -1)
3484 gtk_menu_reorder_child(m_pMenu, pItem, pos);
3485 }
3486
3487 void remove_item(const OString& rIdent)
3488 {
3489 GtkMenuItem* pMenuItem = m_aMap[rIdent];
3490 remove_from_map(pMenuItem);
3491 gtk_widget_destroy(GTK_WIDGET(pMenuItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenuItem)), ((gtk_widget_get_type ()))))))
);
3492 }
3493
3494 void set_item_sensitive(const OString& rIdent, bool bSensitive)
3495 {
3496 gtk_widget_set_sensitive(GTK_WIDGET(m_aMap[rIdent])((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap[rIdent])), ((gtk_widget_get_type ()))))))
, bSensitive);
3497 }
3498
3499 void set_item_active(const OString& rIdent, bool bActive)
3500 {
3501 disable_item_notify_events();
3502 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(m_aMap[rIdent])((((GtkCheckMenuItem*) g_type_check_instance_cast ((GTypeInstance
*) ((m_aMap[rIdent])), ((gtk_check_menu_item_get_type ())))))
)
, bActive);
3503 enable_item_notify_events();
3504 }
3505
3506 bool get_item_active(const OString& rIdent) const
3507 {
3508 return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(m_aMap.find(rIdent)->second)((((GtkCheckMenuItem*) g_type_check_instance_cast ((GTypeInstance
*) ((m_aMap.find(rIdent)->second)), ((gtk_check_menu_item_get_type
()))))))
);
3509 }
3510
3511 void set_item_label(const OString& rIdent, const OUString& rText)
3512 {
3513 gtk_menu_item_set_label(m_aMap[rIdent], MapToGtkAccelerator(rText).getStr());
3514 }
3515
3516 OUString get_item_label(const OString& rIdent) const
3517 {
3518 const gchar* pText = gtk_menu_item_get_label(m_aMap.find(rIdent)->second);
3519 return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3520 }
3521
3522 void set_item_help_id(const OString& rIdent, const OString& rHelpId)
3523 {
3524 set_help_id(GTK_WIDGET(m_aMap[rIdent])((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap[rIdent])), ((gtk_widget_get_type ()))))))
, rHelpId);
3525 }
3526
3527 OString get_item_help_id(const OString& rIdent) const
3528 {
3529 return get_help_id(GTK_WIDGET(m_aMap.find(rIdent)->second)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap.find(rIdent)->second)), ((gtk_widget_get_type ()))
))))
);
3530 }
3531
3532 void set_item_visible(const OString& rIdent, bool bShow)
3533 {
3534 GtkWidget* pWidget = GTK_WIDGET(m_aMap[rIdent])((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap[rIdent])), ((gtk_widget_get_type ()))))))
;
3535 if (bShow)
3536 gtk_widget_show(pWidget);
3537 else
3538 gtk_widget_hide(pWidget);
3539 }
3540
3541 void clear_items()
3542 {
3543 for (const auto& a : m_aMap)
3544 {
3545 GtkMenuItem* pMenuItem = a.second;
3546 g_signal_handlers_disconnect_by_data(pMenuItem, this)g_signal_handlers_disconnect_matched ((pMenuItem), G_SIGNAL_MATCH_DATA
, 0, 0, __null, __null, (this))
;
3547 gtk_widget_destroy(GTK_WIDGET(pMenuItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenuItem)), ((gtk_widget_get_type ()))))))
);
3548 }
3549 m_aMap.clear();
3550 }
3551
3552 GtkMenu* getMenu() const
3553 {
3554 return m_pMenu;
3555 }
3556
3557 virtual ~MenuHelper()
3558 {
3559 for (auto& a : m_aMap)
3560 g_signal_handlers_disconnect_by_data(a.second, this)g_signal_handlers_disconnect_matched ((a.second), G_SIGNAL_MATCH_DATA
, 0, 0, __null, __null, (this))
;
3561 if (m_bTakeOwnership)
3562 gtk_widget_destroy(GTK_WIDGET(m_pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenu)), ((gtk_widget_get_type ()))))))
);
3563 }
3564};
3565
3566class GtkInstanceSizeGroup : public weld::SizeGroup
3567{
3568private:
3569 GtkSizeGroup* m_pGroup;
3570public:
3571 GtkInstanceSizeGroup()
3572 : m_pGroup(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL))
3573 {
3574 }
3575 virtual void add_widget(weld::Widget* pWidget) override
3576 {
3577 GtkInstanceWidget* pVclWidget = dynamic_cast<GtkInstanceWidget*>(pWidget);
3578 assert(pVclWidget)(static_cast <bool> (pVclWidget) ? void (0) : __assert_fail
("pVclWidget", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3578, __extension__ __PRETTY_FUNCTION__))
;
3579 gtk_size_group_add_widget(m_pGroup, pVclWidget->getWidget());
3580 }
3581 virtual void set_mode(VclSizeGroupMode eVclMode) override
3582 {
3583 GtkSizeGroupMode eGtkMode(GTK_SIZE_GROUP_NONE);
3584 switch (eVclMode)
3585 {
3586 case VclSizeGroupMode::NONE:
3587 eGtkMode = GTK_SIZE_GROUP_NONE;
3588 break;
3589 case VclSizeGroupMode::Horizontal:
3590 eGtkMode = GTK_SIZE_GROUP_HORIZONTAL;
3591 break;
3592 case VclSizeGroupMode::Vertical:
3593 eGtkMode = GTK_SIZE_GROUP_VERTICAL;
3594 break;
3595 case VclSizeGroupMode::Both:
3596 eGtkMode = GTK_SIZE_GROUP_BOTH;
3597 break;
3598 }
3599 gtk_size_group_set_mode(m_pGroup, eGtkMode);
3600 }
3601 virtual ~GtkInstanceSizeGroup() override
3602 {
3603 g_object_unref(m_pGroup);
3604 }
3605};
3606
3607class ChildFrame : public WorkWindow
3608{
3609private:
3610 Idle maLayoutIdle;
3611
3612 DECL_LINK(ImplHandleLayoutTimerHdl, Timer*, void)static void LinkStubImplHandleLayoutTimerHdl(void *, Timer*);
void ImplHandleLayoutTimerHdl(Timer*)
;
3613public:
3614 ChildFrame(vcl::Window* pParent, WinBits nStyle)
3615 : WorkWindow(pParent, nStyle)
3616 {
3617 maLayoutIdle.SetPriority(TaskPriority::RESIZE);
3618 maLayoutIdle.SetInvokeHandler( LINK( this, ChildFrame, ImplHandleLayoutTimerHdl )::tools::detail::makeLink( ::tools::detail::castTo<ChildFrame
*>(this), &ChildFrame::LinkStubImplHandleLayoutTimerHdl
)
);
3619 maLayoutIdle.SetDebugName( "ChildFrame maLayoutIdle" );
3620 }
3621
3622 virtual void dispose() override
3623 {
3624 maLayoutIdle.Stop();
3625 WorkWindow::dispose();
3626 }
3627
3628 virtual void queue_resize(StateChangedType eReason = StateChangedType::Layout) override
3629 {
3630 WorkWindow::queue_resize(eReason);
3631 if (maLayoutIdle.IsActive())
3632 return;
3633 maLayoutIdle.Start();
3634 }
3635
3636 virtual void Resize() override
3637 {
3638 WorkWindow::Resize();
3639 queue_resize();
3640 }
3641};
3642
3643IMPL_LINK_NOARG(ChildFrame, ImplHandleLayoutTimerHdl, Timer*, void)void ChildFrame::LinkStubImplHandleLayoutTimerHdl(void * instance
, Timer* data) { return static_cast<ChildFrame *>(instance
)->ImplHandleLayoutTimerHdl(data); } void ChildFrame::ImplHandleLayoutTimerHdl
(__attribute__ ((unused)) Timer*)
3644{
3645 if (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild))
3646 pChild->SetPosSizePixel(Point(0, 0), GetSizePixel());
3647}
3648
3649class GtkInstanceContainer : public GtkInstanceWidget, public virtual weld::Container
3650{
3651private:
3652 GtkContainer* m_pContainer;
3653
3654 static void implResetDefault(GtkWidget *pWidget, gpointer user_data)
3655 {
3656 if (GTK_IS_BUTTON(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_button_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
3657 g_object_set(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "has-default", false, nullptr);
3658 if (GTK_IS_CONTAINER(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
3659 gtk_container_forall(GTK_CONTAINER(pWidget)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_container_get_type ()))))))
, implResetDefault, user_data);
3660 }
3661
3662public:
3663 GtkInstanceContainer(GtkContainer* pContainer, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
3664 : GtkInstanceWidget(GTK_WIDGET(pContainer)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pContainer)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
3665 , m_pContainer(pContainer)
3666 {
3667 }
3668
3669 GtkContainer* getContainer() { return m_pContainer; }
3670
3671 virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) override
3672 {
3673 GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pWidget);
3674 assert(pGtkWidget)(static_cast <bool> (pGtkWidget) ? void (0) : __assert_fail
("pGtkWidget", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3674, __extension__ __PRETTY_FUNCTION__))
;
3675 GtkWidget* pChild = pGtkWidget->getWidget();
3676 g_object_ref(pChild);
3677 gtk_container_remove(getContainer(), pChild);
3678
3679 GtkInstanceContainer* pNewGtkParent = dynamic_cast<GtkInstanceContainer*>(pNewParent);
3680 assert(!pNewParent || pNewGtkParent)(static_cast <bool> (!pNewParent || pNewGtkParent) ? void
(0) : __assert_fail ("!pNewParent || pNewGtkParent", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3680, __extension__ __PRETTY_FUNCTION__))
;
3681 if (pNewGtkParent)
3682 gtk_container_add(pNewGtkParent->getContainer(), pChild);
3683 g_object_unref(pChild);
3684 }
3685
3686 virtual void recursively_unset_default_buttons() override
3687 {
3688 implResetDefault(GTK_WIDGET(m_pContainer)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pContainer)), ((gtk_widget_get_type ()))))))
, nullptr);
3689 }
3690
3691 virtual css::uno::Reference<css::awt::XWindow> CreateChildFrame() override
3692 {
3693 // This will cause a GtkSalFrame to be created. With WB_SYSTEMCHILDWINDOW set it
3694 // will create a toplevel GtkEventBox window
3695 auto xEmbedWindow = VclPtr<ChildFrame>::Create(ImplGetDefaultWindow(), WB_SYSTEMCHILDWINDOW | WB_DIALOGCONTROL | WB_CHILDDLGCTRL);
3696 SalFrame* pFrame = xEmbedWindow->ImplGetFrame();
3697 GtkSalFrame* pGtkFrame = dynamic_cast<GtkSalFrame*>(pFrame);
3698 assert(pGtkFrame)(static_cast <bool> (pGtkFrame) ? void (0) : __assert_fail
("pGtkFrame", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3698, __extension__ __PRETTY_FUNCTION__))
;
3699
3700 // relocate that toplevel GtkEventBox into this widget
3701 GtkWidget* pWindow = pGtkFrame->getWindow();
3702
3703 GtkWidget* pParent = gtk_widget_get_parent(pWindow);
3704
3705 g_object_ref(pWindow);
3706 gtk_container_remove(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pWindow);
3707 gtk_container_add(m_pContainer, pWindow);
3708 gtk_container_child_set(m_pContainer, pWindow, "expand", true, "fill", true, nullptr);
3709 gtk_widget_set_hexpand(pWindow, true);
3710 gtk_widget_set_vexpand(pWindow, true);
3711 gtk_widget_realize(pWindow);
3712 gtk_widget_set_can_focus(pWindow, true);
3713 g_object_unref(pWindow);
3714
3715 // NoActivate otherwise Show grab focus to this widget
3716 xEmbedWindow->Show(true, ShowFlags::NoActivate);
3717 css::uno::Reference<css::awt::XWindow> xWindow(xEmbedWindow->GetComponentInterface(), css::uno::UNO_QUERY);
3718 return xWindow;
3719 }
3720};
3721
3722}
3723
3724std::unique_ptr<weld::Container> GtkInstanceWidget::weld_parent() const
3725{
3726 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
3727 if (!pParent)
3728 return nullptr;
3729 return std::make_unique<GtkInstanceContainer>(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, m_pBuilder, false);
3730}
3731
3732namespace {
3733
3734struct ButtonOrder
3735{
3736 const char * m_aType;
3737 int m_nPriority;
3738};
3739
3740int getButtonPriority(const OString &rType)
3741{
3742 static const size_t N_TYPES = 7;
3743 static const ButtonOrder aDiscardCancelSave[N_TYPES] =
3744 {
3745 { "/discard", 0 },
3746 { "/cancel", 1 },
3747 { "/no", 2 },
3748 { "/open", 3 },
3749 { "/save", 3 },
3750 { "/yes", 3 },
3751 { "/ok", 3 }
3752 };
3753
3754 static const ButtonOrder aSaveDiscardCancel[N_TYPES] =
3755 {
3756 { "/open", 0 },
3757 { "/save", 0 },
3758 { "/yes", 0 },
3759 { "/ok", 0 },
3760 { "/discard", 1 },
3761 { "/no", 1 },
3762 { "/cancel", 2 }
3763 };
3764
3765 const ButtonOrder* pOrder = &aDiscardCancelSave[0];
3766
3767 const OUString &rEnv = Application::GetDesktopEnvironment();
3768
3769 if (rEnv.equalsIgnoreAsciiCase("windows") ||
3770 rEnv.equalsIgnoreAsciiCase("tde") ||
3771 rEnv.startsWithIgnoreAsciiCase("kde"))
3772 {
3773 pOrder = &aSaveDiscardCancel[0];
3774 }
3775
3776 for (size_t i = 0; i < N_TYPES; ++i, ++pOrder)
3777 {
3778 if (rType.endsWith(pOrder->m_aType))
3779 return pOrder->m_nPriority;
3780 }
3781
3782 return -1;
3783}
3784
3785bool sortButtons(const GtkWidget* pA, const GtkWidget* pB)
3786{
3787 //order within groups according to platform rules
3788 return getButtonPriority(::get_help_id(pA)) < getButtonPriority(::get_help_id(pB));
3789}
3790
3791void sort_native_button_order(GtkBox* pContainer)
3792{
3793 std::vector<GtkWidget*> aChildren;
3794 GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pContainer)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pContainer)), ((gtk_container_get_type ()))))))
);
3795 for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild)((pChild) ? (((GList *)(pChild))->next) : __null))
3796 aChildren.push_back(static_cast<GtkWidget*>(pChild->data));
3797 g_list_free(pChildren);
3798
3799 //sort child order within parent so that we match the platform button order
3800 std::stable_sort(aChildren.begin(), aChildren.end(), sortButtons);
3801
3802 for (size_t pos = 0; pos < aChildren.size(); ++pos)
3803 gtk_box_reorder_child(pContainer, aChildren[pos], pos);
3804}
3805
3806class GtkInstanceBox : public GtkInstanceContainer, public virtual weld::Box
3807{
3808private:
3809 GtkBox* m_pBox;
3810
3811public:
3812 GtkInstanceBox(GtkBox* pBox, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
3813 : GtkInstanceContainer(GTK_CONTAINER(pBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pBox)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
3814 , m_pBox(pBox)
3815 {
3816 }
3817
3818 virtual void reorder_child(weld::Widget* pWidget, int nNewPosition) override
3819 {
3820 GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pWidget);
3821 assert(pGtkWidget)(static_cast <bool> (pGtkWidget) ? void (0) : __assert_fail
("pGtkWidget", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3821, __extension__ __PRETTY_FUNCTION__))
;
3822 GtkWidget* pChild = pGtkWidget->getWidget();
3823 gtk_box_reorder_child(m_pBox, pChild, nNewPosition);
3824 }
3825
3826 virtual void sort_native_button_order() override
3827 {
3828 ::sort_native_button_order(m_pBox);
3829 }
3830};
3831
3832 void set_cursor(GtkWidget* pWidget, const char *pName)
3833 {
3834 if (!gtk_widget_get_realized(pWidget))
3835 gtk_widget_realize(pWidget);
3836 GdkDisplay *pDisplay = gtk_widget_get_display(pWidget);
3837 GdkCursor *pCursor = pName ? gdk_cursor_new_from_name(pDisplay, pName) : nullptr;
3838 gdk_window_set_cursor(gtk_widget_get_window(pWidget), pCursor);
3839 gdk_display_flush(pDisplay);
3840 if (pCursor)
3841 g_object_unref(pCursor);
3842 }
3843}
3844
3845namespace
3846{
3847 Point get_csd_offset(GtkWidget* pTopLevel)
3848 {
3849 // try and omit drawing CSD under wayland
3850 GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pTopLevel)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pTopLevel)), ((gtk_container_get_type ()))))))
);
3851 GList* pChild = g_list_first(pChildren);
3852
3853 int x, y;
3854 gtk_widget_translate_coordinates(GTK_WIDGET(pChild->data)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pChild->data)), ((gtk_widget_get_type ()))))))
,
3855 GTK_WIDGET(pTopLevel)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pTopLevel)), ((gtk_widget_get_type ()))))))
,
3856 0, 0, &x, &y);
3857
3858 int innerborder = gtk_container_get_border_width(GTK_CONTAINER(pChild->data)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pChild->data)), ((gtk_container_get_type ()))))))
);
3859 g_list_free(pChildren);
3860
3861 int outerborder = gtk_container_get_border_width(GTK_CONTAINER(pTopLevel)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pTopLevel)), ((gtk_container_get_type ()))))))
);
3862 int totalborder = outerborder + innerborder;
3863 x -= totalborder;
3864 y -= totalborder;
3865
3866 return Point(x, y);
3867 }
3868
3869 void do_collect_screenshot_data(GtkWidget* pItem, gpointer data)
3870 {
3871 GtkWidget* pTopLevel = gtk_widget_get_toplevel(pItem);
3872
3873 int x, y;
3874 gtk_widget_translate_coordinates(pItem, pTopLevel, 0, 0, &x, &y);
3875
3876 Point aOffset = get_csd_offset(pTopLevel);
3877
3878 GtkAllocation alloc;
3879 gtk_widget_get_allocation(pItem, &alloc);
3880
3881 const basegfx::B2IPoint aCurrentTopLeft(x - aOffset.X(), y - aOffset.Y());
3882 const basegfx::B2IRange aCurrentRange(aCurrentTopLeft, aCurrentTopLeft + basegfx::B2IPoint(alloc.width, alloc.height));
3883
3884 if (!aCurrentRange.isEmpty())
3885 {
3886 weld::ScreenShotCollection* pCollection = static_cast<weld::ScreenShotCollection*>(data);
3887 pCollection->emplace_back(::get_help_id(pItem), aCurrentRange);
3888 }
3889
3890 if (GTK_IS_CONTAINER(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
3891 gtk_container_forall(GTK_CONTAINER(pItem)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_container_get_type ()))))))
, do_collect_screenshot_data, data);
3892 }
3893
3894 tools::Rectangle get_monitor_workarea(GtkWidget* pWindow)
3895 {
3896 GdkScreen* pScreen = gtk_widget_get_screen(pWindow);
3897 gint nMonitor = gdk_screen_get_monitor_at_window(pScreen, gtk_widget_get_window(pWindow));
3898 GdkRectangle aRect;
3899 gdk_screen_get_monitor_workarea(pScreen, nMonitor, &aRect);
3900 return tools::Rectangle(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height);
3901 }
3902
3903
3904class GtkInstanceWindow : public GtkInstanceContainer, public virtual weld::Window
3905{
3906private:
3907 GtkWindow* m_pWindow;
3908 rtl::Reference<SalGtkXWindow> m_xWindow; //uno api
3909 gulong m_nToplevelFocusChangedSignalId;
3910
3911 static gboolean help_pressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer widget)
3912 {
3913 GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget);
3914 pThis->help();
3915 return true;
3916 }
3917
3918 static void signalToplevelFocusChanged(GtkWindow*, GParamSpec*, gpointer widget)
3919 {
3920 GtkInstanceWindow* pThis = static_cast<GtkInstanceWindow*>(widget);
3921 pThis->signal_toplevel_focus_changed();
3922 }
3923
3924protected:
3925 void help();
3926public:
3927 GtkInstanceWindow(GtkWindow* pWindow, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
3928 : GtkInstanceContainer(GTK_CONTAINER(pWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pWindow)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
3929 , m_pWindow(pWindow)
3930 , m_nToplevelFocusChangedSignalId(0)
3931 {
3932 const bool bIsFrameWeld = pBuilder == nullptr;
3933 if (!bIsFrameWeld)
3934 {
3935 //hook up F1 to show help
3936 GtkAccelGroup *pGroup = gtk_accel_group_new();
3937 GClosure* closure = g_cclosure_new(G_CALLBACK(help_pressed)((GCallback) (help_pressed)), this, nullptr);
3938 gtk_accel_group_connect(pGroup, GDK_KEY_F10xffbe, static_cast<GdkModifierType>(0), GTK_ACCEL_LOCKED, closure);
3939 gtk_window_add_accel_group(pWindow, pGroup);
3940 }
3941 }
3942
3943 virtual void set_title(const OUString& rTitle) override
3944 {
3945 ::set_title(m_pWindow, rTitle);
3946 }
3947
3948 virtual OUString get_title() const override
3949 {
3950 return ::get_title(m_pWindow);
3951 }
3952
3953 virtual css::uno::Reference<css::awt::XWindow> GetXWindow() override
3954 {
3955 if (!m_xWindow.is())
3956 m_xWindow.set(new SalGtkXWindow(this, m_pWidget));
3957 return css::uno::Reference<css::awt::XWindow>(m_xWindow.get());
3958 }
3959
3960 virtual void set_busy_cursor(bool bBusy) override
3961 {
3962 set_cursor(m_pWidget, bBusy ? "progress" : nullptr);
3963 }
3964
3965 virtual void set_modal(bool bModal) override
3966 {
3967 gtk_window_set_modal(m_pWindow, bModal);
3968 }
3969
3970 virtual bool get_modal() const override
3971 {
3972 return gtk_window_get_modal(m_pWindow);
3973 }
3974
3975 virtual void resize_to_request() override
3976 {
3977 gtk_window_resize(m_pWindow, 1, 1);
3978 }
3979
3980 virtual void window_move(int x, int y) override
3981 {
3982 gtk_window_move(m_pWindow, x, y);
3983 }
3984
3985 virtual SystemEnvData get_system_data() const override
3986 {
3987 assert(false && "nothing should call this impl, yet anyway, if ever")(static_cast <bool> (false && "nothing should call this impl, yet anyway, if ever"
) ? void (0) : __assert_fail ("false && \"nothing should call this impl, yet anyway, if ever\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 3987, __extension__ __PRETTY_FUNCTION__))
;
3988 return SystemEnvData();
3989 }
3990
3991 virtual Size get_size() const override
3992 {
3993 int current_width, current_height;
3994 gtk_window_get_size(m_pWindow, &current_width, &current_height);
3995 return Size(current_width, current_height);
3996 }
3997
3998 virtual Point get_position() const override
3999 {
4000 int current_x, current_y;
4001 gtk_window_get_position(m_pWindow, &current_x, &current_y);
4002 return Point(current_x, current_y);
4003 }
4004
4005 virtual tools::Rectangle get_monitor_workarea() const override
4006 {
4007 return ::get_monitor_workarea(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4008 }
4009
4010 virtual void set_centered_on_parent(bool bTrackGeometryRequests) override
4011 {
4012 if (bTrackGeometryRequests)
4013 gtk_window_set_position(m_pWindow, GTK_WIN_POS_CENTER_ALWAYS);
4014 else
4015 gtk_window_set_position(m_pWindow, GTK_WIN_POS_CENTER_ON_PARENT);
4016 }
4017
4018 virtual bool get_resizable() const override
4019 {
4020 return gtk_window_get_resizable(m_pWindow);
4021 }
4022
4023 virtual bool has_toplevel_focus() const override
4024 {
4025 return gtk_window_has_toplevel_focus(m_pWindow);
4026 }
4027
4028 virtual void present() override
4029 {
4030 gtk_window_present(m_pWindow);
4031 }
4032
4033 virtual void set_window_state(const OString& rStr) override
4034 {
4035 WindowStateData aData;
4036 ImplWindowStateFromStr( aData, rStr );
4037
4038 auto nMask = aData.GetMask();
4039 auto nState = aData.GetState() & WindowStateState::SystemMask;
4040
4041 if (nMask & WindowStateMask::Width && nMask & WindowStateMask::Height)
4042 {
4043 gtk_window_set_default_size(m_pWindow, aData.GetWidth(), aData.GetHeight());
4044 }
4045 if (nMask & WindowStateMask::State)
4046 {
4047 if (nState & WindowStateState::Maximized)
4048 gtk_window_maximize(m_pWindow);
4049 else
4050 gtk_window_unmaximize(m_pWindow);
4051 }
4052 }
4053
4054 virtual OString get_window_state(WindowStateMask nMask) const override
4055 {
4056 bool bPositioningAllowed = true;
4057#if defined(GDK_WINDOWING_WAYLAND)
4058 // drop x/y when under wayland
4059 GdkDisplay *pDisplay = gtk_widget_get_display(m_pWidget);
4060 bPositioningAllowed = !DLSYM_GDK_IS_WAYLAND_DISPLAY(pDisplay);
4061#endif
4062
4063 WindowStateData aData;
4064 WindowStateMask nAvailable = WindowStateMask::State |
4065 WindowStateMask::Width | WindowStateMask::Height;
4066 if (bPositioningAllowed)
4067 nAvailable |= WindowStateMask::X | WindowStateMask::Y;
4068 aData.SetMask(nMask & nAvailable);
4069
4070 if (nMask & WindowStateMask::State)
4071 {
4072 WindowStateState nState = WindowStateState::Normal;
4073 if (gtk_window_is_maximized(m_pWindow))
4074 nState |= WindowStateState::Maximized;
4075 aData.SetState(nState);
4076 }
4077
4078 if (bPositioningAllowed && (nMask & (WindowStateMask::X | WindowStateMask::Y)))
4079 {
4080 auto aPos = get_position();
4081 aData.SetX(aPos.X());
4082 aData.SetY(aPos.Y());
4083 }
4084
4085 if (nMask & (WindowStateMask::Width | WindowStateMask::Height))
4086 {
4087 auto aSize = get_size();
4088 aData.SetWidth(aSize.Width());
4089 aData.SetHeight(aSize.Height());
4090 }
4091
4092 return aData.ToStr();
4093 }
4094
4095 virtual void connect_toplevel_focus_changed(const Link<weld::Widget&, void>& rLink) override
4096 {
4097 assert(!m_nToplevelFocusChangedSignalId)(static_cast <bool> (!m_nToplevelFocusChangedSignalId) ?
void (0) : __assert_fail ("!m_nToplevelFocusChangedSignalId"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 4097, __extension__ __PRETTY_FUNCTION__))
;
4098 m_nToplevelFocusChangedSignalId = g_signal_connect(m_pWindow, "notify::has-toplevel-focus", G_CALLBACK(signalToplevelFocusChanged), this)g_signal_connect_data ((m_pWindow), ("notify::has-toplevel-focus"
), (((GCallback) (signalToplevelFocusChanged))), (this), __null
, (GConnectFlags) 0)
;
4099 weld::Window::connect_toplevel_focus_changed(rLink);
4100 }
4101
4102 virtual void disable_notify_events() override
4103 {
4104 if (m_nToplevelFocusChangedSignalId)
4105 g_signal_handler_block(m_pWidget, m_nToplevelFocusChangedSignalId);
4106 GtkInstanceContainer::disable_notify_events();
4107 }
4108
4109 virtual void enable_notify_events() override
4110 {
4111 GtkInstanceContainer::enable_notify_events();
4112 if (m_nToplevelFocusChangedSignalId)
4113 g_signal_handler_unblock(m_pWidget, m_nToplevelFocusChangedSignalId);
4114 }
4115
4116 virtual VclPtr<VirtualDevice> screenshot() override
4117 {
4118 // detect if we have to manually setup its size
4119 bool bAlreadyRealized = gtk_widget_get_realized(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4120 // has to be visible for draw to work
4121 bool bAlreadyVisible = gtk_widget_get_visible(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4122 if (!bAlreadyVisible)
4123 {
4124 if (GTK_IS_DIALOG(m_pWindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pWindow)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4125 sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pWindow)))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_dialog_get_action_area
(((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*)
((m_pWindow)), ((gtk_dialog_get_type ()))))))))), ((gtk_box_get_type
()))))))
);
4126 gtk_widget_show(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4127 }
4128
4129 if (!bAlreadyRealized)
4130 {
4131 GtkAllocation allocation;
4132 gtk_widget_realize(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4133 gtk_widget_get_allocation(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
, &allocation);
4134 gtk_widget_size_allocate(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
, &allocation);
4135 }
4136
4137 VclPtr<VirtualDevice> xOutput(VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT));
4138 xOutput->SetOutputSizePixel(get_size());
4139 cairo_surface_t* pSurface = get_underlying_cairo_surface(*xOutput);
4140 cairo_t* cr = cairo_create(pSurface);
4141
4142 Point aOffset = get_csd_offset(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4143
4144 cairo_translate(cr, -aOffset.X(), -aOffset.Y());
4145
4146 gtk_widget_draw(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
, cr);
4147
4148 cairo_destroy(cr);
4149
4150 if (!bAlreadyVisible)
4151 gtk_widget_hide(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4152 if (!bAlreadyRealized)
4153 gtk_widget_unrealize(GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
);
4154
4155 return xOutput;
4156 }
4157
4158 virtual weld::ScreenShotCollection collect_screenshot_data() override
4159 {
4160 weld::ScreenShotCollection aRet;
4161
4162 gtk_container_foreach(GTK_CONTAINER(m_pWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pWindow)), ((gtk_container_get_type ()))))))
, do_collect_screenshot_data, &aRet);
4163
4164 return aRet;
4165 }
4166
4167 virtual ~GtkInstanceWindow() override
4168 {
4169 if (m_nToplevelFocusChangedSignalId)
4170 g_signal_handler_disconnect(m_pWindow, m_nToplevelFocusChangedSignalId);
4171 if (m_xWindow.is())
4172 m_xWindow->clear();
4173 }
4174};
4175
4176class GtkInstanceDialog;
4177
4178struct DialogRunner
4179{
4180 GtkWindow* m_pDialog;
4181 GtkInstanceDialog *m_pInstance;
4182 gint m_nResponseId;
4183 GMainLoop *m_pLoop;
4184 VclPtr<vcl::Window> m_xFrameWindow;
4185 int m_nModalDepth;
4186
4187 DialogRunner(GtkWindow* pDialog, GtkInstanceDialog* pInstance)
4188 : m_pDialog(pDialog)
4189 , m_pInstance(pInstance)
4190 , m_nResponseId(GTK_RESPONSE_NONE)
4191 , m_pLoop(nullptr)
4192 , m_nModalDepth(0)
4193 {
4194 GtkWindow* pParent = gtk_window_get_transient_for(m_pDialog);
4195 GtkSalFrame* pFrame = pParent ? GtkSalFrame::getFromWindow(GTK_WIDGET(pParent)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pParent)), ((gtk_widget_get_type ()))))))
) : nullptr;
4196 m_xFrameWindow = pFrame ? pFrame->GetWindow() : nullptr;
4197 }
4198
4199 bool loop_is_running() const
4200 {
4201 return m_pLoop && g_main_loop_is_running(m_pLoop);
4202 }
4203
4204 void loop_quit()
4205 {
4206 if (g_main_loop_is_running(m_pLoop))
4207 g_main_loop_quit(m_pLoop);
4208 }
4209
4210 static void signal_response(GtkDialog*, gint nResponseId, gpointer data);
4211 static void signal_cancel(GtkAssistant*, gpointer data);
4212
4213 static gboolean signal_delete(GtkDialog* pDialog, GdkEventAny*, gpointer data)
4214 {
4215 DialogRunner* pThis = static_cast<DialogRunner*>(data);
4216 if (GTK_IS_ASSISTANT(pThis->m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pThis->m_pDialog)); GType __t = ((gtk_assistant_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
4217 {
4218 // An assistant isn't a dialog, but we want to treat it like one
4219 signal_response(pDialog, GTK_RESPONSE_DELETE_EVENT, data);
4220 }
4221 else
4222 pThis->loop_quit();
4223 return true; /* Do not destroy */
4224 }
4225
4226 static void signal_destroy(GtkDialog*, gpointer data)
4227 {
4228 DialogRunner* pThis = static_cast<DialogRunner*>(data);
4229 pThis->loop_quit();
4230 }
4231
4232 void inc_modal_count()
4233 {
4234 if (m_xFrameWindow)
4235 {
4236 m_xFrameWindow->IncModalCount();
4237 if (m_nModalDepth == 0)
4238 m_xFrameWindow->ImplGetFrame()->NotifyModalHierarchy(true);
4239 ++m_nModalDepth;
4240 }
4241 }
4242
4243 void dec_modal_count()
4244 {
4245 if (m_xFrameWindow)
4246 {
4247 m_xFrameWindow->DecModalCount();
4248 --m_nModalDepth;
4249 if (m_nModalDepth == 0)
4250 m_xFrameWindow->ImplGetFrame()->NotifyModalHierarchy(false);
4251 }
4252 }
4253
4254 // same as gtk_dialog_run except that unmap doesn't auto-respond
4255 // so we can hide the dialog and restore it without a response getting
4256 // triggered
4257 gint run()
4258 {
4259 g_object_ref(m_pDialog);
4260
4261 inc_modal_count();
4262
4263 bool bWasModal = gtk_window_get_modal(m_pDialog);
4264 if (!bWasModal)
4265 gtk_window_set_modal(m_pDialog, true);
4266
4267 if (!gtk_widget_get_visible(GTK_WIDGET(m_pDialog)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_widget_get_type ()))))))
))
4268 gtk_widget_show(GTK_WIDGET(m_pDialog)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_widget_get_type ()))))))
);
4269
4270 gulong nSignalResponseId = GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
? g_signal_connect(m_pDialog, "response", G_CALLBACK(signal_response), this)g_signal_connect_data ((m_pDialog), ("response"), (((GCallback
) (signal_response))), (this), __null, (GConnectFlags) 0)
: 0;
4271 gulong nSignalCancelId = GTK_IS_ASSISTANT(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signal_cancel), this)g_signal_connect_data ((m_pDialog), ("cancel"), (((GCallback)
(signal_cancel))), (this), __null, (GConnectFlags) 0)
: 0;
4272 gulong nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signal_delete), this)g_signal_connect_data ((m_pDialog), ("delete-event"), (((GCallback
) (signal_delete))), (this), __null, (GConnectFlags) 0)
;
4273 gulong nSignalDestroyId = g_signal_connect(m_pDialog, "destroy", G_CALLBACK(signal_destroy), this)g_signal_connect_data ((m_pDialog), ("destroy"), (((GCallback
) (signal_destroy))), (this), __null, (GConnectFlags) 0)
;
4274
4275 m_pLoop = g_main_loop_new(nullptr, false);
4276 m_nResponseId = GTK_RESPONSE_NONE;
4277
4278 gdk_threads_leave();
4279 g_main_loop_run(m_pLoop);
4280 gdk_threads_enter();
4281
4282 g_main_loop_unref(m_pLoop);
4283
4284 m_pLoop = nullptr;
4285
4286 if (!bWasModal)
4287 gtk_window_set_modal(m_pDialog, false);
4288
4289 if (nSignalResponseId)
4290 g_signal_handler_disconnect(m_pDialog, nSignalResponseId);
4291 if (nSignalCancelId)
4292 g_signal_handler_disconnect(m_pDialog, nSignalCancelId);
4293 g_signal_handler_disconnect(m_pDialog, nSignalDeleteId);
4294 g_signal_handler_disconnect(m_pDialog, nSignalDestroyId);
4295
4296 dec_modal_count();
4297
4298 g_object_unref(m_pDialog);
4299
4300 return m_nResponseId;
4301 }
4302
4303 ~DialogRunner()
4304 {
4305 if (m_xFrameWindow && m_nModalDepth)
4306 {
4307 // if, like the calc validation dialog does, the modality was
4308 // toggled off during execution ensure that on cleanup the parent
4309 // is left in the state it was found
4310 while (m_nModalDepth++ < 0)
4311 m_xFrameWindow->IncModalCount();
4312 }
4313 }
4314};
4315
4316}
4317
4318typedef std::set<GtkWidget*> winset;
4319
4320namespace
4321{
4322 void hideUnless(GtkContainer *pTop, const winset& rVisibleWidgets,
4323 std::vector<GtkWidget*> &rWasVisibleWidgets)
4324 {
4325 GList* pChildren = gtk_container_get_children(pTop);
4326 for (GList* pEntry = g_list_first(pChildren); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
4327 {
4328 GtkWidget* pChild = static_cast<GtkWidget*>(pEntry->data);
4329 if (!gtk_widget_get_visible(pChild))
4330 continue;
4331 if (rVisibleWidgets.find(pChild) == rVisibleWidgets.end())
4332 {
4333 g_object_ref(pChild);
4334 rWasVisibleWidgets.emplace_back(pChild);
4335 gtk_widget_hide(pChild);
4336 }
4337 else if (GTK_IS_CONTAINER(pChild)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pChild)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4338 {
4339 hideUnless(GTK_CONTAINER(pChild)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pChild)), ((gtk_container_get_type ()))))))
, rVisibleWidgets, rWasVisibleWidgets);
4340 }
4341 }
4342 g_list_free(pChildren);
4343 }
4344
4345class GtkInstanceButton;
4346
4347class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog
4348{
4349private:
4350 GtkWindow* m_pDialog;
4351 DialogRunner m_aDialogRun;
4352 std::shared_ptr<weld::DialogController> m_xDialogController;
4353 // Used to keep ourself alive during a runAsync(when doing runAsync without a DialogController)
4354 std::shared_ptr<weld::Dialog> m_xRunAsyncSelf;
4355 std::function<void(sal_Int32)> m_aFunc;
4356 gulong m_nCloseSignalId;
4357 gulong m_nResponseSignalId;
4358 gulong m_nCancelSignalId;
4359 gulong m_nSignalDeleteId;
4360
4361 // for calc ref dialog that shrink to range selection widgets and resize back
4362 GtkWidget* m_pRefEdit;
4363 std::vector<GtkWidget*> m_aHiddenWidgets; // vector of hidden Controls
4364 int m_nOldEditWidth; // Original width of the input field
4365 int m_nOldEditWidthReq; // Original width request of the input field
4366 int m_nOldBorderWidth; // border width for expanded dialog
4367
4368 void signal_close()
4369 {
4370 close(true);
4371 }
4372
4373 static void signalClose(GtkWidget*, gpointer widget)
4374 {
4375 GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
4376 pThis->signal_close();
4377 }
4378
4379 static void signalAsyncResponse(GtkWidget*, gint ret, gpointer widget)
4380 {
4381 GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
4382 pThis->asyncresponse(ret);
4383 }
4384
4385 static void signalAsyncCancel(GtkAssistant*, gpointer widget)
4386 {
4387 GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
4388 // make esc in an assistant act as if cancel button was pressed
4389 pThis->close(false);
4390 }
4391
4392 static gboolean signalAsyncDelete(GtkWidget* pDialog, GdkEventAny*, gpointer widget)
4393 {
4394 GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
4395 if (GTK_IS_ASSISTANT(pThis->m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pThis->m_pDialog)); GType __t = ((gtk_assistant_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
4396 {
4397 // An assistant isn't a dialog, but we want to treat it like one
4398 signalAsyncResponse(pDialog, GTK_RESPONSE_DELETE_EVENT, widget);
4399 }
4400 return true; /* Do not destroy */
4401 }
4402
4403 static int GtkToVcl(int ret)
4404 {
4405 if (ret == GTK_RESPONSE_OK)
4406 ret = RET_OK;
4407 else if (ret == GTK_RESPONSE_CANCEL)
4408 ret = RET_CANCEL;
4409 else if (ret == GTK_RESPONSE_DELETE_EVENT)
4410 ret = RET_CANCEL;
4411 else if (ret == GTK_RESPONSE_CLOSE)
4412 ret = RET_CLOSE;
4413 else if (ret == GTK_RESPONSE_YES)
4414 ret = RET_YES;
4415 else if (ret == GTK_RESPONSE_NO)
4416 ret = RET_NO;
4417 else if (ret == GTK_RESPONSE_HELP)
4418 ret = RET_HELP;
4419 return ret;
4420 }
4421
4422 static int VclToGtk(int nResponse)
4423 {
4424 if (nResponse == RET_OK)
4425 return GTK_RESPONSE_OK;
4426 else if (nResponse == RET_CANCEL)
4427 return GTK_RESPONSE_CANCEL;
4428 else if (nResponse == RET_CLOSE)
4429 return GTK_RESPONSE_CLOSE;
4430 else if (nResponse == RET_YES)
4431 return GTK_RESPONSE_YES;
4432 else if (nResponse == RET_NO)
4433 return GTK_RESPONSE_NO;
4434 else if (nResponse == RET_HELP)
4435 return GTK_RESPONSE_HELP;
4436 return nResponse;
4437 }
4438
4439 void asyncresponse(gint ret);
4440
4441 static void signalActivate(GtkMenuItem*, gpointer data)
4442 {
4443 bool* pActivate = static_cast<bool*>(data);
4444 *pActivate = true;
4445 }
4446
4447 bool signal_screenshot_popup_menu(const GdkEventButton* pEvent)
4448 {
4449 GtkWidget *pMenu = gtk_menu_new();
4450
4451 GtkWidget* pMenuItem = gtk_menu_item_new_with_mnemonic(MapToGtkAccelerator(VclResId(SV_BUTTONTEXT_SCREENSHOTreinterpret_cast<char const *>("SV_BUTTONTEXT_SCREENSHOT"
"\004" u8"~Screenshot")
)).getStr());
4452 gtk_menu_shell_append(GTK_MENU_SHELL(pMenu)((((GtkMenuShell*) g_type_check_instance_cast ((GTypeInstance
*) ((pMenu)), ((gtk_menu_shell_get_type ()))))))
, pMenuItem);
4453 bool bActivate(false);
4454 g_signal_connect(pMenuItem, "activate", G_CALLBACK(signalActivate), &bActivate)g_signal_connect_data ((pMenuItem), ("activate"), (((GCallback
) (signalActivate))), (&bActivate), __null, (GConnectFlags
) 0)
;
4455 gtk_widget_show(pMenuItem);
4456
4457 int button, event_time;
4458 if (pEvent
1.1
'pEvent' is null
1.1
'pEvent' is null
1.1
'pEvent' is null
1.1
'pEvent' is null
)
2
Taking false branch
4459 {
4460 button = pEvent->button;
4461 event_time = pEvent->time;
4462 }
4463 else
4464 {
4465 button = 0;
4466 event_time = gtk_get_current_event_time();
4467 }
4468
4469 gtk_menu_attach_to_widget(GTK_MENU(pMenu)((((GtkMenu*) g_type_check_instance_cast ((GTypeInstance*) ((
pMenu)), ((gtk_menu_get_type ()))))))
, GTK_WIDGET(m_pDialog)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_widget_get_type ()))))))
, nullptr);
4470
4471 GMainLoop* pLoop = g_main_loop_new(nullptr, true);
4472 gulong nSignalId = g_signal_connect_swapped(G_OBJECT(pMenu), "deactivate", G_CALLBACK(g_main_loop_quit), pLoop)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((pMenu)), (((GType) ((20) << (2))))
))))), ("deactivate"), (((GCallback) (g_main_loop_quit))), (pLoop
), __null, G_CONNECT_SWAPPED)
;
4473
4474 gtk_menu_popup(GTK_MENU(pMenu)((((GtkMenu*) g_type_check_instance_cast ((GTypeInstance*) ((
pMenu)), ((gtk_menu_get_type ()))))))
, nullptr, nullptr, nullptr, nullptr, button, event_time);
4475
4476 if (g_main_loop_is_running(pLoop))
3
Assuming the condition is false
4
Taking false branch
4477 {
4478 gdk_threads_leave();
4479 g_main_loop_run(pLoop);
4480 gdk_threads_enter();
4481 }
4482
4483 g_main_loop_unref(pLoop);
4484 g_signal_handler_disconnect(pMenu, nSignalId);
4485 gtk_menu_detach(GTK_MENU(pMenu)((((GtkMenu*) g_type_check_instance_cast ((GTypeInstance*) ((
pMenu)), ((gtk_menu_get_type ()))))))
);
4486
4487 if (bActivate)
5
Assuming 'bActivate' is true
6
Taking true branch
4488 {
4489 // open screenshot annotation dialog
4490 VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
4491 VclPtr<AbstractScreenshotAnnotationDlg> xTmp = pFact->CreateScreenshotAnnotationDlg(*this);
4492 ScopedVclPtr<AbstractScreenshotAnnotationDlg> xDialog(xTmp);
7
Calling constructor for 'ScopedVclPtr<AbstractScreenshotAnnotationDlg>'
14
Returning from constructor for 'ScopedVclPtr<AbstractScreenshotAnnotationDlg>'
4493 xDialog->Execute();
4494 }
15
Calling '~ScopedVclPtr'
28
Returning from '~ScopedVclPtr'
29
Calling implicit destructor for 'VclPtr<AbstractScreenshotAnnotationDlg>'
30
Calling '~Reference'
4495
4496 return false;
4497 }
4498
4499 static gboolean signalScreenshotPopupMenu(GtkWidget*, gpointer widget)
4500 {
4501 GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
4502 return pThis->signal_screenshot_popup_menu(nullptr);
1
Calling 'GtkInstanceDialog::signal_screenshot_popup_menu'
4503 }
4504
4505 static gboolean signalScreenshotButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
4506 {
4507 GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
4508 SolarMutexGuard aGuard;
4509 return pThis->signal_screenshot_button(pEvent);
4510 }
4511
4512 bool signal_screenshot_button(GdkEventButton* pEvent)
4513 {
4514 if (gdk_event_triggers_context_menu(reinterpret_cast<GdkEvent*>(pEvent)) && pEvent->type == GDK_BUTTON_PRESS)
4515 {
4516 //if handled for context menu, stop processing
4517 return signal_screenshot_popup_menu(pEvent);
4518 }
4519 return false;
4520 }
4521
4522public:
4523 GtkInstanceDialog(GtkWindow* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
4524 : GtkInstanceWindow(pDialog, pBuilder, bTakeOwnership)
4525 , m_pDialog(pDialog)
4526 , m_aDialogRun(pDialog, this)
4527 , m_nResponseSignalId(0)
4528 , m_nCancelSignalId(0)
4529 , m_nSignalDeleteId(0)
4530 , m_pRefEdit(nullptr)
4531 , m_nOldEditWidth(0)
4532 , m_nOldEditWidthReq(0)
4533 , m_nOldBorderWidth(0)
4534 {
4535 if (GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
|| GTK_IS_ASSISTANT(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4536 m_nCloseSignalId = g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this)g_signal_connect_data ((m_pDialog), ("close"), (((GCallback) (
signalClose))), (this), __null, (GConnectFlags) 0)
;
4537 else
4538 m_nCloseSignalId = 0;
4539 const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get());
4540 if (bScreenshotMode)
4541 {
4542 g_signal_connect(m_pDialog, "popup-menu", G_CALLBACK(signalScreenshotPopupMenu), this)g_signal_connect_data ((m_pDialog), ("popup-menu"), (((GCallback
) (signalScreenshotPopupMenu))), (this), __null, (GConnectFlags
) 0)
;
4543 g_signal_connect(m_pDialog, "button-press-event", G_CALLBACK(signalScreenshotButton), this)g_signal_connect_data ((m_pDialog), ("button-press-event"), (
((GCallback) (signalScreenshotButton))), (this), __null, (GConnectFlags
) 0)
;
4544 }
4545 }
4546
4547 virtual bool runAsync(std::shared_ptr<weld::DialogController> rDialogController, const std::function<void(sal_Int32)>& func) override
4548 {
4549 assert(!m_nResponseSignalId && !m_nCancelSignalId && !m_nSignalDeleteId)(static_cast <bool> (!m_nResponseSignalId && !m_nCancelSignalId
&& !m_nSignalDeleteId) ? void (0) : __assert_fail ("!m_nResponseSignalId && !m_nCancelSignalId && !m_nSignalDeleteId"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 4549, __extension__ __PRETTY_FUNCTION__))
;
4550
4551 m_xDialogController = rDialogController;
4552 m_aFunc = func;
4553
4554 if (get_modal())
4555 m_aDialogRun.inc_modal_count();
4556 show();
4557
4558 m_nResponseSignalId = GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
? g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this)g_signal_connect_data ((m_pDialog), ("response"), (((GCallback
) (signalAsyncResponse))), (this), __null, (GConnectFlags) 0)
: 0;
4559 m_nCancelSignalId = GTK_IS_ASSISTANT(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signalAsyncCancel), this)g_signal_connect_data ((m_pDialog), ("cancel"), (((GCallback)
(signalAsyncCancel))), (this), __null, (GConnectFlags) 0)
: 0;
4560 m_nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signalAsyncDelete), this)g_signal_connect_data ((m_pDialog), ("delete-event"), (((GCallback
) (signalAsyncDelete))), (this), __null, (GConnectFlags) 0)
;
4561
4562 return true;
4563 }
4564
4565 virtual bool runAsync(std::shared_ptr<Dialog> const & rxSelf, const std::function<void(sal_Int32)>& func) override
4566 {
4567 assert( rxSelf.get() == this )(static_cast <bool> (rxSelf.get() == this) ? void (0) :
__assert_fail ("rxSelf.get() == this", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 4567, __extension__ __PRETTY_FUNCTION__))
;
4568 assert(!m_nResponseSignalId && !m_nCancelSignalId && !m_nSignalDeleteId)(static_cast <bool> (!m_nResponseSignalId && !m_nCancelSignalId
&& !m_nSignalDeleteId) ? void (0) : __assert_fail ("!m_nResponseSignalId && !m_nCancelSignalId && !m_nSignalDeleteId"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 4568, __extension__ __PRETTY_FUNCTION__))
;
4569
4570 // In order to store a shared_ptr to ourself, we have to have been constructed by make_shared,
4571 // which is that rxSelf enforces.
4572 m_xRunAsyncSelf = rxSelf;
4573 m_aFunc = func;
4574
4575 if (get_modal())
4576 m_aDialogRun.inc_modal_count();
4577 show();
4578
4579 m_nResponseSignalId = GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
? g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this)g_signal_connect_data ((m_pDialog), ("response"), (((GCallback
) (signalAsyncResponse))), (this), __null, (GConnectFlags) 0)
: 0;
4580 m_nCancelSignalId = GTK_IS_ASSISTANT(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signalAsyncCancel), this)g_signal_connect_data ((m_pDialog), ("cancel"), (((GCallback)
(signalAsyncCancel))), (this), __null, (GConnectFlags) 0)
: 0;
4581 m_nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signalAsyncDelete), this)g_signal_connect_data ((m_pDialog), ("delete-event"), (((GCallback
) (signalAsyncDelete))), (this), __null, (GConnectFlags) 0)
;
4582
4583 return true;
4584 }
4585
4586 GtkInstanceButton* has_click_handler(int nResponse);
4587
4588 virtual int run() override;
4589
4590 virtual void show() override
4591 {
4592 if (gtk_widget_get_visible(m_pWidget))
4593 return;
4594 if (GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4595 sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_dialog_get_action_area
(((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*)
((m_pDialog)), ((gtk_dialog_get_type ()))))))))), ((gtk_box_get_type
()))))))
);
4596 GtkInstanceWindow::show();
4597 }
4598
4599 virtual void set_modal(bool bModal) override
4600 {
4601 if (get_modal() == bModal)
4602 return;
4603 GtkInstanceWindow::set_modal(bModal);
4604 /* if change the dialog modality while its running, then also change the parent LibreOffice window
4605 modal count, we typically expect the dialog modality to be restored to its original state
4606
4607 This change modality while running case is for...
4608
4609 a) the calc/chart dialogs which put up an extra range chooser
4610 dialog, hides the original, the user can select a range of cells and
4611 on completion the original dialog is restored
4612
4613 b) the validity dialog in calc
4614 */
4615 // tdf#135567 we know we are running in the sync case if loop_is_running is true
4616 // but for the async case we instead check for m_xDialogController which is set in
4617 // runAsync and cleared in asyncresponse
4618 if (m_aDialogRun.loop_is_running() || m_xDialogController)
4619 {
4620 if (bModal)
4621 m_aDialogRun.inc_modal_count();
4622 else
4623 m_aDialogRun.dec_modal_count();
4624 }
4625 }
4626
4627 virtual void response(int nResponse) override;
4628
4629 virtual void add_button(const OUString& rText, int nResponse, const OString& rHelpId) override
4630 {
4631 GtkWidget* pWidget = gtk_dialog_add_button(GTK_DIALOG(m_pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_dialog_get_type ()))))))
, MapToGtkAccelerator(rText).getStr(), VclToGtk(nResponse));
4632 if (!rHelpId.isEmpty())
4633 ::set_help_id(pWidget, rHelpId);
4634 }
4635
4636 virtual void set_default_response(int nResponse) override
4637 {
4638 gtk_dialog_set_default_response(GTK_DIALOG(m_pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_dialog_get_type ()))))))
, VclToGtk(nResponse));
4639 }
4640
4641 virtual GtkButton* get_widget_for_response(int nGtkResponse)
4642 {
4643 return GTK_BUTTON(gtk_dialog_get_widget_for_response(GTK_DIALOG(m_pDialog), nGtkResponse))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_dialog_get_widget_for_response(((((GtkDialog*) g_type_check_instance_cast
((GTypeInstance*) ((m_pDialog)), ((gtk_dialog_get_type ())))
))), nGtkResponse))), ((gtk_button_get_type ()))))))
;
4644 }
4645
4646 virtual weld::Button* weld_widget_for_response(int nVclResponse) override;
4647
4648 virtual Container* weld_content_area() override
4649 {
4650 return new GtkInstanceContainer(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(m_pDialog)))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_dialog_get_content_area(((((GtkDialog*) g_type_check_instance_cast
((GTypeInstance*) ((m_pDialog)), ((gtk_dialog_get_type ())))
)))))), ((gtk_container_get_type ()))))))
, m_pBuilder, false);
4651 }
4652
4653 virtual void collapse(weld::Widget* pEdit, weld::Widget* pButton) override
4654 {
4655 GtkInstanceWidget* pVclEdit = dynamic_cast<GtkInstanceWidget*>(pEdit);
4656 assert(pVclEdit)(static_cast <bool> (pVclEdit) ? void (0) : __assert_fail
("pVclEdit", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 4656, __extension__ __PRETTY_FUNCTION__))
;
4657 GtkInstanceWidget* pVclButton = dynamic_cast<GtkInstanceWidget*>(pButton);
4658
4659 GtkWidget* pRefEdit = pVclEdit->getWidget();
4660 GtkWidget* pRefBtn = pVclButton ? pVclButton->getWidget() : nullptr;
4661
4662 m_nOldEditWidth = gtk_widget_get_allocated_width(pRefEdit);
4663
4664 gtk_widget_get_size_request(pRefEdit, &m_nOldEditWidthReq, nullptr);
4665
4666 //We want just pRefBtn and pRefEdit to be shown
4667 //mark widgets we want to be visible, starting with pRefEdit
4668 //and all its direct parents.
4669 winset aVisibleWidgets;
4670 GtkWidget *pContentArea = gtk_dialog_get_content_area(GTK_DIALOG(m_pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_dialog_get_type ()))))))
);
4671 for (GtkWidget *pCandidate = pRefEdit;
4672 pCandidate && pCandidate != pContentArea && gtk_widget_get_visible(pCandidate);
4673 pCandidate = gtk_widget_get_parent(pCandidate))
4674 {
4675 aVisibleWidgets.insert(pCandidate);
4676 }
4677 //same again with pRefBtn, except stop if there's a
4678 //shared parent in the existing widgets
4679 for (GtkWidget *pCandidate = pRefBtn;
4680 pCandidate && pCandidate != pContentArea && gtk_widget_get_visible(pCandidate);
4681 pCandidate = gtk_widget_get_parent(pCandidate))
4682 {
4683 if (aVisibleWidgets.insert(pCandidate).second)
4684 break;
4685 }
4686
4687 //hide everything except the aVisibleWidgets
4688 hideUnless(GTK_CONTAINER(pContentArea)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pContentArea)), ((gtk_container_get_type ()))))))
, aVisibleWidgets, m_aHiddenWidgets);
4689
4690 gtk_widget_set_size_request(pRefEdit, m_nOldEditWidth, -1);
4691 m_nOldBorderWidth = gtk_container_get_border_width(GTK_CONTAINER(m_pDialog)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pDialog)), ((gtk_container_get_type ()))))))
);
4692 gtk_container_set_border_width(GTK_CONTAINER(m_pDialog)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pDialog)), ((gtk_container_get_type ()))))))
, 0);
4693 if (GtkWidget* pActionArea = gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_dialog_get_type ()))))))
))
4694 gtk_widget_hide(pActionArea);
4695
4696 // calc's insert->function is springing back to its original size if the ref-button
4697 // is used to shrink the dialog down and then the user clicks in the calc area to do
4698 // the selection
4699#if defined(GDK_WINDOWING_WAYLAND)
4700 bool bWorkaroundSizeSpringingBack = DLSYM_GDK_IS_WAYLAND_DISPLAY(gtk_widget_get_display(m_pWidget));
4701 if (bWorkaroundSizeSpringingBack)
4702 gtk_widget_unmap(GTK_WIDGET(m_pDialog)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_widget_get_type ()))))))
);
4703#endif
4704
4705 resize_to_request();
4706
4707#if defined(GDK_WINDOWING_WAYLAND)
4708 if (bWorkaroundSizeSpringingBack)
4709 gtk_widget_map(GTK_WIDGET(m_pDialog)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_widget_get_type ()))))))
);
4710#endif
4711
4712 m_pRefEdit = pRefEdit;
4713 }
4714
4715 virtual void undo_collapse() override
4716 {
4717 // All others: Show();
4718 for (GtkWidget* pWindow : m_aHiddenWidgets)
4719 {
4720 gtk_widget_show(pWindow);
4721 g_object_unref(pWindow);
4722 }
4723 m_aHiddenWidgets.clear();
4724
4725 gtk_widget_set_size_request(m_pRefEdit, m_nOldEditWidthReq, -1);
4726 m_pRefEdit = nullptr;
4727 gtk_container_set_border_width(GTK_CONTAINER(m_pDialog)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pDialog)), ((gtk_container_get_type ()))))))
, m_nOldBorderWidth);
4728 if (GtkWidget* pActionArea = gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_dialog_get_type ()))))))
))
4729 gtk_widget_show(pActionArea);
4730 resize_to_request();
4731 present();
4732 }
4733
4734 void close(bool bCloseSignal);
4735
4736 virtual void SetInstallLOKNotifierHdl(const Link<void*, vcl::ILibreOfficeKitNotifier*>&) override
4737 {
4738 //not implemented for the gtk variant
4739 }
4740
4741 virtual ~GtkInstanceDialog() override
4742 {
4743 if (!m_aHiddenWidgets.empty())
4744 {
4745 for (GtkWidget* pWindow : m_aHiddenWidgets)
4746 g_object_unref(pWindow);
4747 m_aHiddenWidgets.clear();
4748 }
4749
4750 if (m_nCloseSignalId)
4751 g_signal_handler_disconnect(m_pDialog, m_nCloseSignalId);
4752 assert(!m_nResponseSignalId && !m_nCancelSignalId && !m_nSignalDeleteId)(static_cast <bool> (!m_nResponseSignalId && !m_nCancelSignalId
&& !m_nSignalDeleteId) ? void (0) : __assert_fail ("!m_nResponseSignalId && !m_nCancelSignalId && !m_nSignalDeleteId"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 4752, __extension__ __PRETTY_FUNCTION__))
;
4753 }
4754};
4755
4756}
4757
4758void DialogRunner::signal_response(GtkDialog*, gint nResponseId, gpointer data)
4759{
4760 DialogRunner* pThis = static_cast<DialogRunner*>(data);
4761
4762 // make GTK_RESPONSE_DELETE_EVENT act as if cancel button was pressed
4763 if (nResponseId == GTK_RESPONSE_DELETE_EVENT)
4764 {
4765 pThis->m_pInstance->close(false);
4766 return;
4767 }
4768
4769 pThis->m_nResponseId = nResponseId;
4770 pThis->loop_quit();
4771}
4772
4773void DialogRunner::signal_cancel(GtkAssistant*, gpointer data)
4774{
4775 DialogRunner* pThis = static_cast<DialogRunner*>(data);
4776
4777 // make esc in an assistant act as if cancel button was pressed
4778 pThis->m_pInstance->close(false);
4779}
4780
4781namespace {
4782
4783class GtkInstanceMessageDialog : public GtkInstanceDialog, public virtual weld::MessageDialog
4784{
4785private:
4786 GtkMessageDialog* m_pMessageDialog;
4787public:
4788 GtkInstanceMessageDialog(GtkMessageDialog* pMessageDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
4789 : GtkInstanceDialog(GTK_WINDOW(pMessageDialog)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pMessageDialog)), ((gtk_window_get_type ()))))))
, pBuilder, bTakeOwnership)
4790 , m_pMessageDialog(pMessageDialog)
4791 {
4792 }
4793
4794 virtual void set_primary_text(const OUString& rText) override
4795 {
4796 ::set_primary_text(m_pMessageDialog, rText);
4797 }
4798
4799 virtual OUString get_primary_text() const override
4800 {
4801 return ::get_primary_text(m_pMessageDialog);
4802 }
4803
4804 virtual void set_secondary_text(const OUString& rText) override
4805 {
4806 ::set_secondary_text(m_pMessageDialog, rText);
4807 }
4808
4809 virtual OUString get_secondary_text() const override
4810 {
4811 return ::get_secondary_text(m_pMessageDialog);
4812 }
4813
4814 virtual Container* weld_message_area() override
4815 {
4816 return new GtkInstanceContainer(GTK_CONTAINER(gtk_message_dialog_get_message_area(m_pMessageDialog))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_message_dialog_get_message_area(m_pMessageDialog))),
((gtk_container_get_type ()))))))
, m_pBuilder, false);
4817 }
4818};
4819
4820class GtkInstanceAssistant : public GtkInstanceDialog, public virtual weld::Assistant
4821{
4822private:
4823 GtkAssistant* m_pAssistant;
4824 GtkWidget* m_pSidebar;
4825 GtkWidget* m_pSidebarEventBox;
4826 GtkButtonBox* m_pButtonBox;
4827 GtkButton* m_pHelp;
4828 GtkButton* m_pBack;
4829 GtkButton* m_pNext;
4830 GtkButton* m_pFinish;
4831 GtkButton* m_pCancel;
4832 gulong m_nButtonPressSignalId;
4833 std::vector<std::unique_ptr<GtkInstanceContainer>> m_aPages;
4834 std::map<OString, bool> m_aNotClickable;
4835
4836 int find_page(const OString& rIdent) const
4837 {
4838 int nPages = gtk_assistant_get_n_pages(m_pAssistant);
4839 for (int i = 0; i < nPages; ++i)
4840 {
4841 GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, i);
4842 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pPage)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pPage)), ((gtk_buildable_get_type ()))))))
);
4843 if (g_strcmp0(pStr, rIdent.getStr()) == 0)
4844 return i;
4845 }
4846 return -1;
4847 }
4848
4849 static void wrap_sidebar_label(GtkWidget *pWidget, gpointer /*user_data*/)
4850 {
4851 if (GTK_IS_LABEL(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_label_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4852 {
4853 gtk_label_set_line_wrap(GTK_LABEL(pWidget)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_label_get_type ()))))))
, true);
4854 gtk_label_set_width_chars(GTK_LABEL(pWidget)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_label_get_type ()))))))
, 22);
4855 gtk_label_set_max_width_chars(GTK_LABEL(pWidget)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_label_get_type ()))))))
, 22);
4856 }
4857 }
4858
4859 static void find_sidebar(GtkWidget *pWidget, gpointer user_data)
4860 {
4861 if (g_strcmp0(gtk_buildable_get_name(GTK_BUILDABLE(pWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_buildable_get_type ()))))))
), "sidebar") == 0)
4862 {
4863 GtkWidget **ppSidebar = static_cast<GtkWidget**>(user_data);
4864 *ppSidebar = pWidget;
4865 }
4866 if (GTK_IS_CONTAINER(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
4867 gtk_container_forall(GTK_CONTAINER(pWidget)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_container_get_type ()))))))
, find_sidebar, user_data);
4868 }
4869
4870 static void signalHelpClicked(GtkButton*, gpointer widget)
4871 {
4872 GtkInstanceAssistant* pThis = static_cast<GtkInstanceAssistant*>(widget);
4873 pThis->signal_help_clicked();
4874 }
4875
4876 void signal_help_clicked()
4877 {
4878 help();
4879 }
4880
4881 static gboolean signalButton(GtkWidget*, GdkEventButton* pEvent, gpointer widget)
4882 {
4883 GtkInstanceAssistant* pThis = static_cast<GtkInstanceAssistant*>(widget);
4884 SolarMutexGuard aGuard;
4885 return pThis->signal_button(pEvent);
4886 }
4887
4888 bool signal_button(const GdkEventButton* pEvent)
4889 {
4890 int nNewCurrentPage = -1;
4891
4892 GtkAllocation allocation;
4893
4894 int nPageIndex = 0;
4895 GList* pChildren = gtk_container_get_children(GTK_CONTAINER(m_pSidebar)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pSidebar)), ((gtk_container_get_type ()))))))
);
4896 for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild)((pChild) ? (((GList *)(pChild))->next) : __null))
4897 {
4898 GtkWidget* pWidget = static_cast<GtkWidget*>(pChild->data);
4899 if (!gtk_widget_get_visible(pWidget))
4900 continue;
4901
4902 gtk_widget_get_allocation(pWidget, &allocation);
4903
4904 gint dest_x1, dest_y1;
4905 gtk_widget_translate_coordinates(pWidget,
4906 m_pSidebarEventBox,
4907 0,
4908 0,
4909 &dest_x1,
4910 &dest_y1);
4911
4912 gint dest_x2, dest_y2;
4913 gtk_widget_translate_coordinates(pWidget,
4914 m_pSidebarEventBox,
4915 allocation.width,
4916 allocation.height,
4917 &dest_x2,
4918 &dest_y2);
4919
4920
4921 if (pEvent->x >= dest_x1 && pEvent->x <= dest_x2 && pEvent->y >= dest_y1 && pEvent->y <= dest_y2)
4922 {
4923 nNewCurrentPage = nPageIndex;
4924 break;
4925 }
4926
4927 ++nPageIndex;
4928 }
4929 g_list_free(pChildren);
4930
4931 if (nNewCurrentPage != -1 && nNewCurrentPage != get_current_page())
4932 {
4933 OString sIdent = get_page_ident(nNewCurrentPage);
4934 if (!m_aNotClickable[sIdent] && !signal_jump_page(sIdent))
4935 set_current_page(nNewCurrentPage);
4936 }
4937
4938 return false;
4939 }
4940
4941public:
4942 GtkInstanceAssistant(GtkAssistant* pAssistant, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
4943 : GtkInstanceDialog(GTK_WINDOW(pAssistant)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pAssistant)), ((gtk_window_get_type ()))))))
, pBuilder, bTakeOwnership)
4944 , m_pAssistant(pAssistant)
4945 , m_pSidebar(nullptr)
4946 {
4947 m_pButtonBox = GTK_BUTTON_BOX(gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL))((((GtkButtonBox*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL))), ((gtk_button_box_get_type
()))))))
;
4948 gtk_button_box_set_layout(m_pButtonBox, GTK_BUTTONBOX_END);
4949 gtk_box_set_spacing(GTK_BOX(m_pButtonBox)((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButtonBox
)), ((gtk_box_get_type ()))))))
, 6);
4950
4951 m_pBack = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText(StandardButtonType::Back)).getStr()))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText
(StandardButtonType::Back)).getStr()))), ((gtk_button_get_type
()))))))
;
4952 gtk_widget_set_can_default(GTK_WIDGET(m_pBack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pBack)), ((gtk_widget_get_type ()))))))
, true);
4953 gtk_buildable_set_name(GTK_BUILDABLE(m_pBack)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pBack)), ((gtk_buildable_get_type ()))))))
, "previous");
4954 gtk_box_pack_end(GTK_BOX(m_pButtonBox)((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButtonBox
)), ((gtk_box_get_type ()))))))
, GTK_WIDGET(m_pBack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pBack)), ((gtk_widget_get_type ()))))))
, false, false, 0);
4955
4956 m_pNext = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText(StandardButtonType::Next)).getStr()))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText
(StandardButtonType::Next)).getStr()))), ((gtk_button_get_type
()))))))
;
4957 gtk_widget_set_can_default(GTK_WIDGET(m_pNext)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNext)), ((gtk_widget_get_type ()))))))
, true);
4958 gtk_buildable_set_name(GTK_BUILDABLE(m_pNext)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pNext)), ((gtk_buildable_get_type ()))))))
, "next");
4959 gtk_box_pack_end(GTK_BOX(m_pButtonBox)((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButtonBox
)), ((gtk_box_get_type ()))))))
, GTK_WIDGET(m_pNext)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNext)), ((gtk_widget_get_type ()))))))
, false, false, 0);
4960
4961 m_pCancel = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText(StandardButtonType::Cancel)).getStr()))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText
(StandardButtonType::Cancel)).getStr()))), ((gtk_button_get_type
()))))))
;
4962 gtk_widget_set_can_default(GTK_WIDGET(m_pCancel)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pCancel)), ((gtk_widget_get_type ()))))))
, true);
4963 gtk_box_pack_end(GTK_BOX(m_pButtonBox)((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButtonBox
)), ((gtk_box_get_type ()))))))
, GTK_WIDGET(m_pCancel)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pCancel)), ((gtk_widget_get_type ()))))))
, false, false, 0);
4964
4965 m_pFinish = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText(StandardButtonType::Finish)).getStr()))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText
(StandardButtonType::Finish)).getStr()))), ((gtk_button_get_type
()))))))
;
4966 gtk_widget_set_can_default(GTK_WIDGET(m_pFinish)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pFinish)), ((gtk_widget_get_type ()))))))
, true);
4967 gtk_buildable_set_name(GTK_BUILDABLE(m_pFinish)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pFinish)), ((gtk_buildable_get_type ()))))))
, "finish");
4968 gtk_box_pack_end(GTK_BOX(m_pButtonBox)((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButtonBox
)), ((gtk_box_get_type ()))))))
, GTK_WIDGET(m_pFinish)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pFinish)), ((gtk_widget_get_type ()))))))
, false, false, 0);
4969
4970 m_pHelp = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText(StandardButtonType::Help)).getStr()))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_button_new_with_mnemonic(MapToGtkAccelerator(GetStandardText
(StandardButtonType::Help)).getStr()))), ((gtk_button_get_type
()))))))
;
4971 gtk_widget_set_can_default(GTK_WIDGET(m_pHelp)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pHelp)), ((gtk_widget_get_type ()))))))
, true);
4972 g_signal_connect(m_pHelp, "clicked", G_CALLBACK(signalHelpClicked), this)g_signal_connect_data ((m_pHelp), ("clicked"), (((GCallback) (
signalHelpClicked))), (this), __null, (GConnectFlags) 0)
;
4973 gtk_box_pack_end(GTK_BOX(m_pButtonBox)((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButtonBox
)), ((gtk_box_get_type ()))))))
, GTK_WIDGET(m_pHelp)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pHelp)), ((gtk_widget_get_type ()))))))
, false, false, 0);
4974
4975 gtk_assistant_add_action_widget(pAssistant, GTK_WIDGET(m_pButtonBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButtonBox)), ((gtk_widget_get_type ()))))))
);
4976 gtk_button_box_set_child_secondary(m_pButtonBox, GTK_WIDGET(m_pHelp)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pHelp)), ((gtk_widget_get_type ()))))))
, true);
4977 gtk_widget_set_hexpand(GTK_WIDGET(m_pButtonBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButtonBox)), ((gtk_widget_get_type ()))))))
, true);
4978
4979 GtkWidget* pParent = gtk_widget_get_parent(GTK_WIDGET(m_pButtonBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButtonBox)), ((gtk_widget_get_type ()))))))
);
4980 gtk_container_child_set(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, GTK_WIDGET(m_pButtonBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButtonBox)), ((gtk_widget_get_type ()))))))
, "expand", true, "fill", true, nullptr);
4981 gtk_widget_set_halign(pParent, GTK_ALIGN_FILL);
4982
4983 // Hide the built-in ones early so we get a nice optimal size for the width without
4984 // including the unused contents
4985 GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
);
4986 for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild)((pChild) ? (((GList *)(pChild))->next) : __null))
4987 {
4988 GtkWidget* pWidget = static_cast<GtkWidget*>(pChild->data);
4989 gtk_widget_hide(pWidget);
4990 }
4991 g_list_free(pChildren);
4992
4993 gtk_widget_show_all(GTK_WIDGET(m_pButtonBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButtonBox)), ((gtk_widget_get_type ()))))))
);
4994
4995 find_sidebar(GTK_WIDGET(m_pAssistant)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pAssistant)), ((gtk_widget_get_type ()))))))
, &m_pSidebar);
4996
4997 m_pSidebarEventBox = ::ensureEventWidget(m_pSidebar);
4998 m_nButtonPressSignalId = m_pSidebarEventBox ? g_signal_connect(m_pSidebarEventBox, "button-press-event", G_CALLBACK(signalButton), this)g_signal_connect_data ((m_pSidebarEventBox), ("button-press-event"
), (((GCallback) (signalButton))), (this), __null, (GConnectFlags
) 0)
: 0;
4999 }
5000
5001 virtual int get_current_page() const override
5002 {
5003 return gtk_assistant_get_current_page(m_pAssistant);
5004 }
5005
5006 virtual int get_n_pages() const override
5007 {
5008 return gtk_assistant_get_n_pages(m_pAssistant);
5009 }
5010
5011 virtual OString get_page_ident(int nPage) const override
5012 {
5013 const GtkWidget* pWidget = gtk_assistant_get_nth_page(m_pAssistant, nPage);
5014 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_buildable_get_type ()))))))
);
5015 return OString(pStr, pStr ? strlen(pStr) : 0);
5016 }
5017
5018 virtual OString get_current_page_ident() const override
5019 {
5020 return get_page_ident(get_current_page());
5021 }
5022
5023 virtual void set_current_page(int nPage) override
5024 {
5025 OString sDialogTitle(gtk_window_get_title(GTK_WINDOW(m_pAssistant)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pAssistant)), ((gtk_window_get_type ()))))))
));
5026
5027 gtk_assistant_set_current_page(m_pAssistant, nPage);
5028
5029 // if the page doesn't have a title, then the dialog will now have no
5030 // title, so restore the original title as a fallback
5031 GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nPage);
5032 if (!gtk_assistant_get_page_title(m_pAssistant, pPage))
5033 gtk_window_set_title(GTK_WINDOW(m_pAssistant)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pAssistant)), ((gtk_window_get_type ()))))))
, sDialogTitle.getStr());
5034 }
5035
5036 virtual void set_current_page(const OString& rIdent) override
5037 {
5038 int nPage = find_page(rIdent);
5039 if (nPage == -1)
5040 return;
5041 set_current_page(nPage);
5042 }
5043
5044 virtual void set_page_title(const OString& rIdent, const OUString& rTitle) override
5045 {
5046 int nIndex = find_page(rIdent);
5047 if (nIndex == -1)
5048 return;
5049 GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nIndex);
5050 gtk_assistant_set_page_title(m_pAssistant, pPage,
5051 OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
5052 gtk_container_forall(GTK_CONTAINER(m_pSidebar)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pSidebar)), ((gtk_container_get_type ()))))))
, wrap_sidebar_label, nullptr);
5053 }
5054
5055 virtual OUString get_page_title(const OString& rIdent) const override
5056 {
5057 int nIndex = find_page(rIdent);
5058 if (nIndex == -1)
5059 return OUString();
5060 GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nIndex);
5061 const gchar* pStr = gtk_assistant_get_page_title(m_pAssistant, pPage);
5062 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
5063 }
5064
5065 virtual void set_page_sensitive(const OString& rIdent, bool bSensitive) override
5066 {
5067 m_aNotClickable[rIdent] = !bSensitive;
5068 }
5069
5070 virtual void set_page_index(const OString& rIdent, int nNewIndex) override
5071 {
5072 int nOldIndex = find_page(rIdent);
5073 if (nOldIndex == -1)
5074 return;
5075
5076 if (nOldIndex == nNewIndex)
5077 return;
5078
5079 GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nOldIndex);
5080
5081 g_object_ref(pPage);
5082 OString sTitle(gtk_assistant_get_page_title(m_pAssistant, pPage));
5083 gtk_assistant_remove_page(m_pAssistant, nOldIndex);
5084 gtk_assistant_insert_page(m_pAssistant, pPage, nNewIndex);
5085 gtk_assistant_set_page_type(m_pAssistant, pPage, GTK_ASSISTANT_PAGE_CUSTOM);
5086 gtk_assistant_set_page_title(m_pAssistant, pPage, sTitle.getStr());
5087 gtk_container_forall(GTK_CONTAINER(m_pSidebar)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pSidebar)), ((gtk_container_get_type ()))))))
, wrap_sidebar_label, nullptr);
5088 g_object_unref(pPage);
5089 }
5090
5091 virtual weld::Container* append_page(const OString& rIdent) override
5092 {
5093 disable_notify_events();
5094
5095 GtkWidget *pChild = gtk_grid_new();
5096 gtk_buildable_set_name(GTK_BUILDABLE(pChild)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pChild)), ((gtk_buildable_get_type ()))))))
, rIdent.getStr());
5097 gtk_assistant_append_page(m_pAssistant, pChild);
5098 gtk_assistant_set_page_type(m_pAssistant, pChild, GTK_ASSISTANT_PAGE_CUSTOM);
5099 gtk_widget_show(pChild);
5100
5101 enable_notify_events();
5102
5103 m_aPages.emplace_back(new GtkInstanceContainer(GTK_CONTAINER(pChild)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pChild)), ((gtk_container_get_type ()))))))
, m_pBuilder, false));
5104
5105 return m_aPages.back().get();
5106 }
5107
5108 virtual void set_page_side_help_id(const OString& rHelpId) override
5109 {
5110 if (!m_pSidebar)
5111 return;
5112 ::set_help_id(m_pSidebar, rHelpId);
5113 }
5114
5115 virtual GtkButton* get_widget_for_response(int nGtkResponse) override
5116 {
5117 GtkButton* pButton = nullptr;
5118 if (nGtkResponse == GTK_RESPONSE_YES)
5119 pButton = m_pNext;
5120 else if (nGtkResponse == GTK_RESPONSE_NO)
5121 pButton = m_pBack;
5122 else if (nGtkResponse == GTK_RESPONSE_OK)
5123 pButton = m_pFinish;
5124 else if (nGtkResponse == GTK_RESPONSE_CANCEL)
5125 pButton = m_pCancel;
5126 else if (nGtkResponse == GTK_RESPONSE_HELP)
5127 pButton = m_pHelp;
5128 return pButton;
5129 }
5130
5131 virtual ~GtkInstanceAssistant() override
5132 {
5133 if (m_nButtonPressSignalId)
5134 g_signal_handler_disconnect(m_pSidebarEventBox, m_nButtonPressSignalId);
5135 }
5136};
5137
5138class GtkInstanceFrame : public GtkInstanceContainer, public virtual weld::Frame
5139{
5140private:
5141 GtkFrame* m_pFrame;
5142public:
5143 GtkInstanceFrame(GtkFrame* pFrame, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
5144 : GtkInstanceContainer(GTK_CONTAINER(pFrame)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pFrame)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
5145 , m_pFrame(pFrame)
5146 {
5147 }
5148
5149 virtual void set_label(const OUString& rText) override
5150 {
5151 gtk_label_set_label(GTK_LABEL(gtk_frame_get_label_widget(m_pFrame))((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_frame_get_label_widget(m_pFrame))), ((gtk_label_get_type
()))))))
, rText.replaceFirst("~", "").toUtf8().getStr());
5152 }
5153
5154 virtual OUString get_label() const override
5155 {
5156 const gchar* pStr = gtk_frame_get_label(m_pFrame);
5157 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
5158 }
5159
5160 virtual std::unique_ptr<weld::Label> weld_label_widget() const override;
5161};
5162
5163class GtkInstancePaned : public GtkInstanceContainer, public virtual weld::Paned
5164{
5165private:
5166 GtkPaned* m_pPaned;
5167public:
5168 GtkInstancePaned(GtkPaned* pPaned, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
5169 : GtkInstanceContainer(GTK_CONTAINER(pPaned)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pPaned)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
5170 , m_pPaned(pPaned)
5171 {
5172 }
5173
5174 virtual void set_position(int nPos) override
5175 {
5176 gtk_paned_set_position(m_pPaned, nPos);
5177 }
5178
5179 virtual int get_position() const override
5180 {
5181 return gtk_paned_get_position(m_pPaned);
5182 }
5183};
5184
5185}
5186
5187static GType crippled_viewport_get_type();
5188
5189#define CRIPPLED_TYPE_VIEWPORT(crippled_viewport_get_type ()) (crippled_viewport_get_type ())
5190#define CRIPPLED_VIEWPORT(obj)((((CrippledViewport*) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((crippled_viewport_get_type ()))))))
(G_TYPE_CHECK_INSTANCE_CAST ((obj), CRIPPLED_TYPE_VIEWPORT, CrippledViewport)(((CrippledViewport*) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((crippled_viewport_get_type ())))))
)
5191#ifndef NDEBUG
5192# define CRIPPLED_IS_VIEWPORT(obj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((crippled_viewport_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), CRIPPLED_TYPE_VIEWPORT)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((crippled_viewport_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))
)
5193#endif
5194
5195namespace {
5196
5197struct CrippledViewport
5198{
5199 GtkViewport viewport;
5200
5201 GtkAdjustment *hadjustment;
5202 GtkAdjustment *vadjustment;
5203};
5204
5205}
5206
5207enum
5208{
5209 PROP_0,
5210 PROP_HADJUSTMENT,
5211 PROP_VADJUSTMENT,
5212 PROP_HSCROLL_POLICY,
5213 PROP_VSCROLL_POLICY,
5214 PROP_SHADOW_TYPE
5215};
5216
5217static void viewport_set_adjustment(CrippledViewport *viewport,
5218 GtkOrientation orientation,
5219 GtkAdjustment *adjustment)
5220{
5221 if (!adjustment)
5222 adjustment = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
5223
5224 if (orientation == GTK_ORIENTATION_HORIZONTAL)
5225 {
5226 if (viewport->hadjustment)
5227 g_object_unref(viewport->hadjustment);
5228 viewport->hadjustment = adjustment;
5229 }
5230 else
5231 {
5232 if (viewport->vadjustment)
5233 g_object_unref(viewport->vadjustment);
5234 viewport->vadjustment = adjustment;
5235 }
5236
5237 g_object_ref_sink(adjustment);
5238}
5239
5240static void
5241crippled_viewport_set_property(GObject* object,
5242 guint prop_id,
5243 const GValue* value,
5244 GParamSpec* /*pspec*/)
5245{
5246 CrippledViewport *viewport = CRIPPLED_VIEWPORT(object)((((CrippledViewport*) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((crippled_viewport_get_type ()))))))
;
5247
5248 switch (prop_id)
5249 {
5250 case PROP_HADJUSTMENT:
5251 viewport_set_adjustment(viewport, GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT(g_value_get_object(value))((((GtkAdjustment*) g_type_check_instance_cast ((GTypeInstance
*) ((g_value_get_object(value))), ((gtk_adjustment_get_type (
)))))))
);
5252 break;
5253 case PROP_VADJUSTMENT:
5254 viewport_set_adjustment(viewport, GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(g_value_get_object(value))((((GtkAdjustment*) g_type_check_instance_cast ((GTypeInstance
*) ((g_value_get_object(value))), ((gtk_adjustment_get_type (
)))))))
);
5255 break;
5256 case PROP_HSCROLL_POLICY:
5257 case PROP_VSCROLL_POLICY:
5258 break;
5259 default:
5260 SAL_WARN( "vcl.gtk", "unknown property\n")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unknown property\n")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5260" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown property\n"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"unknown property\n"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5260" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unknown property\n") == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5260" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown property\n"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"unknown property\n"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5260" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5261 break;
5262 }
5263}
5264
5265static void
5266crippled_viewport_get_property(GObject* object,
5267 guint prop_id,
5268 GValue* value,
5269 GParamSpec* /*pspec*/)
5270{
5271 CrippledViewport *viewport = CRIPPLED_VIEWPORT(object)((((CrippledViewport*) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((crippled_viewport_get_type ()))))))
;
5272
5273 switch (prop_id)
5274 {
5275 case PROP_HADJUSTMENT:
5276 g_value_set_object(value, viewport->hadjustment);
5277 break;
5278 case PROP_VADJUSTMENT:
5279 g_value_set_object(value, viewport->vadjustment);
5280 break;
5281 case PROP_HSCROLL_POLICY:
5282 g_value_set_enum(value, GTK_SCROLL_MINIMUM);
5283 break;
5284 case PROP_VSCROLL_POLICY:
5285 g_value_set_enum(value, GTK_SCROLL_MINIMUM);
5286 break;
5287 default:
5288 SAL_WARN( "vcl.gtk", "unknown property\n")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gtk")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "unknown property\n")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"
), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5288" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown property\n"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"unknown property\n"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5288" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "unknown property\n") == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5288" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "unknown property\n"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"unknown property\n"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gtk"), ("/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
":" "5288" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5289 break;
5290 }
5291}
5292
5293static void crippled_viewport_class_init(GtkViewportClass *klass)
5294{
5295 GObjectClass* o_class = G_OBJECT_CLASS(klass)((((GObjectClass*) g_type_check_class_cast ((GTypeClass*) ((klass
)), (((GType) ((20) << (2))))))))
;
5296
5297 /* GObject signals */
5298 o_class->set_property = crippled_viewport_set_property;
5299 o_class->get_property = crippled_viewport_get_property;
5300
5301 /* Properties */
5302 g_object_class_override_property(o_class, PROP_HADJUSTMENT, "hadjustment");
5303 g_object_class_override_property(o_class, PROP_VADJUSTMENT, "vadjustment");
5304 g_object_class_override_property(o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
5305 g_object_class_override_property(o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
5306}
5307
5308GType crippled_viewport_get_type()
5309{
5310 static GType type = 0;
5311
5312 if (!type)
5313 {
5314 static const GTypeInfo tinfo =
5315 {
5316 sizeof (GtkViewportClass),
5317 nullptr, /* base init */
5318 nullptr, /* base finalize */
5319 reinterpret_cast<GClassInitFunc>(crippled_viewport_class_init), /* class init */
5320 nullptr, /* class finalize */
5321 nullptr, /* class data */
5322 sizeof (CrippledViewport), /* instance size */
5323 0, /* nb preallocs */
5324 nullptr, /* instance init */
5325 nullptr /* value table */
5326 };
5327
5328 type = g_type_register_static( GTK_TYPE_VIEWPORT(gtk_viewport_get_type ()), "CrippledViewport",
5329 &tinfo, GTypeFlags(0));
5330 }
5331
5332 return type;
5333}
5334
5335#define CUSTOM_TYPE_CELL_RENDERER_SURFACE(custom_cell_renderer_surface_get_type()) (custom_cell_renderer_surface_get_type())
5336#define CUSTOM_CELL_RENDERER_SURFACE(obj)((((CustomCellRendererSurface*) g_type_check_instance_cast ((
GTypeInstance*) ((obj)), ((custom_cell_renderer_surface_get_type
()))))))
(G_TYPE_CHECK_INSTANCE_CAST((obj), CUSTOM_TYPE_CELL_RENDERER_SURFACE, CustomCellRendererSurface)(((CustomCellRendererSurface*) g_type_check_instance_cast ((GTypeInstance
*) ((obj)), ((custom_cell_renderer_surface_get_type())))))
)
5337#define CUSTOM_IS_CELL_RENDERER_SURFACE(obj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((custom_cell_renderer_surface_get_type()
)); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), CUSTOM_TYPE_CELL_RENDERER_SURFACE)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(obj)); GType __t = ((custom_cell_renderer_surface_get_type()
)); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))
)
5338
5339namespace {
5340
5341 struct CustomCellRendererSurface
5342 {
5343 GtkCellRendererText parent;
5344 VclPtr<VirtualDevice> device;
5345 gchar *id;
5346 gpointer instance;
5347 };
5348
5349 struct CustomCellRendererSurfaceClass
5350 {
5351 GtkCellRendererTextClass parent_class;
5352 };
5353
5354 enum
5355 {
5356 PROP_ID = 10000,
5357 PROP_INSTANCE_TREE_VIEW = 10001
5358 };
5359}
5360
5361static gpointer custom_cell_renderer_surface_parent_class;
5362
5363static GType custom_cell_renderer_surface_get_type();
5364static void custom_cell_renderer_surface_class_init(CustomCellRendererSurfaceClass *klass);
5365
5366GType custom_cell_renderer_surface_get_type()
5367{
5368 static GType type = 0;
5369
5370 if (!type)
5371 {
5372 static const GTypeInfo tinfo =
5373 {
5374 sizeof (CustomCellRendererSurfaceClass),
5375 nullptr, /* base init */
5376 nullptr, /* base finalize */
5377 reinterpret_cast<GClassInitFunc>(custom_cell_renderer_surface_class_init), /* class init */
5378 nullptr, /* class finalize */
5379 nullptr, /* class data */
5380 sizeof (CustomCellRendererSurface), /* instance size */
5381 0, /* nb preallocs */
5382 nullptr, /* instance init */
5383 nullptr /* value table */
5384 };
5385
5386 // inherit from GtkCellRendererText so we can set the "text" property and get a11y support for that
5387 type = g_type_register_static(GTK_TYPE_CELL_RENDERER_TEXT(gtk_cell_renderer_text_get_type ()), "CustomCellRendererSurface",
5388 &tinfo, GTypeFlags(0));
5389 }
5390
5391 return type;
5392}
5393
5394static void custom_cell_renderer_surface_get_property(GObject *object,
5395 guint param_id,
5396 GValue *value,
5397 GParamSpec *pspec)
5398{
5399 CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(object)((((CustomCellRendererSurface*) g_type_check_instance_cast ((
GTypeInstance*) ((object)), ((custom_cell_renderer_surface_get_type
()))))))
;
5400
5401 switch (param_id)
5402 {
5403 case PROP_ID:
5404 g_value_set_string(value, cellsurface->id);
5405 break;
5406 case PROP_INSTANCE_TREE_VIEW:
5407 g_value_set_pointer(value, cellsurface->instance);
5408 break;
5409 default:
5410 G_OBJECT_CLASS(custom_cell_renderer_surface_parent_class)((((GObjectClass*) g_type_check_class_cast ((GTypeClass*) ((custom_cell_renderer_surface_parent_class
)), (((GType) ((20) << (2))))))))
->get_property(object, param_id, value, pspec);
5411 break;
5412 }
5413}
5414
5415static void custom_cell_renderer_surface_set_property(GObject *object,
5416 guint param_id,
5417 const GValue *value,
5418 GParamSpec *pspec)
5419{
5420 CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(object)((((CustomCellRendererSurface*) g_type_check_instance_cast ((
GTypeInstance*) ((object)), ((custom_cell_renderer_surface_get_type
()))))))
;
5421
5422 switch (param_id)
5423 {
5424 case PROP_ID:
5425 g_free(cellsurface->id);
5426 cellsurface->id = g_value_dup_string(value);
5427 break;
5428 case PROP_INSTANCE_TREE_VIEW:
5429 cellsurface->instance = g_value_get_pointer(value);
5430 break;
5431 default:
5432 G_OBJECT_CLASS(custom_cell_renderer_surface_parent_class)((((GObjectClass*) g_type_check_class_cast ((GTypeClass*) ((custom_cell_renderer_surface_parent_class
)), (((GType) ((20) << (2))))))))
->set_property(object, param_id, value, pspec);
5433 break;
5434 }
5435}
5436
5437static bool custom_cell_renderer_surface_get_preferred_size(GtkCellRenderer *cell,
5438 GtkOrientation orientation,
5439 gint *minimum_size,
5440 gint *natural_size);
5441
5442static void custom_cell_renderer_surface_render(GtkCellRenderer* cell,
5443 cairo_t* cr,
5444 GtkWidget* widget,
5445 const GdkRectangle* background_area,
5446 const GdkRectangle* cell_area,
5447 GtkCellRendererState flags);
5448
5449static void custom_cell_renderer_surface_finalize(GObject *object)
5450{
5451 CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(object)((((CustomCellRendererSurface*) g_type_check_instance_cast ((
GTypeInstance*) ((object)), ((custom_cell_renderer_surface_get_type
()))))))
;
5452
5453 g_free(cellsurface->id);
5454 cellsurface->device.disposeAndClear();
5455
5456 G_OBJECT_CLASS(custom_cell_renderer_surface_parent_class)((((GObjectClass*) g_type_check_class_cast ((GTypeClass*) ((custom_cell_renderer_surface_parent_class
)), (((GType) ((20) << (2))))))))
->finalize(object);
5457}
5458
5459static void custom_cell_renderer_surface_get_preferred_width(GtkCellRenderer *cell,
5460 GtkWidget *widget,
5461 gint *minimum_size,
5462 gint *natural_size)
5463{
5464 if (!custom_cell_renderer_surface_get_preferred_size(cell, GTK_ORIENTATION_HORIZONTAL,
5465 minimum_size, natural_size))
5466 {
5467 // fallback to parent if we're empty
5468 GTK_CELL_RENDERER_CLASS(custom_cell_renderer_surface_parent_class)((((GtkCellRendererClass*) g_type_check_class_cast ((GTypeClass
*) ((custom_cell_renderer_surface_parent_class)), ((gtk_cell_renderer_get_type
()))))))
->get_preferred_width(cell,
5469 widget, minimum_size, natural_size);
5470 }
5471}
5472
5473static void custom_cell_renderer_surface_get_preferred_height(GtkCellRenderer *cell,
5474 GtkWidget *widget,
5475 gint *minimum_size,
5476 gint *natural_size)
5477{
5478 if (!custom_cell_renderer_surface_get_preferred_size(cell, GTK_ORIENTATION_VERTICAL,
5479 minimum_size, natural_size))
5480 {
5481 // fallback to parent if we're empty
5482 GTK_CELL_RENDERER_CLASS(custom_cell_renderer_surface_parent_class)((((GtkCellRendererClass*) g_type_check_class_cast ((GTypeClass
*) ((custom_cell_renderer_surface_parent_class)), ((gtk_cell_renderer_get_type
()))))))
->get_preferred_height(cell,
5483 widget, minimum_size, natural_size);
5484 }
5485
5486}
5487
5488static void custom_cell_renderer_surface_get_preferred_height_for_width(GtkCellRenderer *cell,
5489 GtkWidget *widget,
5490 gint /*width*/,
5491 gint *minimum_height,
5492 gint *natural_height)
5493{
5494 gtk_cell_renderer_get_preferred_height(cell, widget, minimum_height, natural_height);
5495}
5496
5497static void custom_cell_renderer_surface_get_preferred_width_for_height(GtkCellRenderer *cell,
5498 GtkWidget *widget,
5499 gint /*height*/,
5500 gint *minimum_width,
5501 gint *natural_width)
5502{
5503 gtk_cell_renderer_get_preferred_width(cell, widget, minimum_width, natural_width);
5504}
5505
5506void custom_cell_renderer_surface_class_init(CustomCellRendererSurfaceClass *klass)
5507{
5508 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass)((((GtkCellRendererClass*) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((gtk_cell_renderer_get_type ()))))))
;
5509 GObjectClass *object_class = G_OBJECT_CLASS(klass)((((GObjectClass*) g_type_check_class_cast ((GTypeClass*) ((klass
)), (((GType) ((20) << (2))))))))
;
5510
5511 /* Hook up functions to set and get our custom cell renderer properties */
5512 object_class->get_property = custom_cell_renderer_surface_get_property;
5513 object_class->set_property = custom_cell_renderer_surface_set_property;
5514
5515 custom_cell_renderer_surface_parent_class = g_type_class_peek_parent(klass);
5516 object_class->finalize = custom_cell_renderer_surface_finalize;
5517
5518 cell_class->get_preferred_width = custom_cell_renderer_surface_get_preferred_width;
5519 cell_class->get_preferred_height = custom_cell_renderer_surface_get_preferred_height;
5520 cell_class->get_preferred_width_for_height = custom_cell_renderer_surface_get_preferred_width_for_height;
5521 cell_class->get_preferred_height_for_width = custom_cell_renderer_surface_get_preferred_height_for_width;
5522
5523 cell_class->render = custom_cell_renderer_surface_render;
5524
5525 g_object_class_install_property(object_class,
5526 PROP_ID,
5527 g_param_spec_string("id",
5528 "ID",
5529 "The ID of the custom data",
5530 nullptr,
5531 G_PARAM_READWRITE));
5532
5533 g_object_class_install_property(object_class,
5534 PROP_INSTANCE_TREE_VIEW,
5535 g_param_spec_pointer("instance",
5536 "Instance",
5537 "The GtkInstanceTreeView",
5538 G_PARAM_READWRITE));
5539
5540 gtk_cell_renderer_class_set_accessible_type(cell_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE(gtk_text_cell_accessible_get_type ()));
5541}
5542
5543static GtkCellRenderer* custom_cell_renderer_surface_new()
5544{
5545 return GTK_CELL_RENDERER(g_object_new(CUSTOM_TYPE_CELL_RENDERER_SURFACE, nullptr))((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((g_object_new((custom_cell_renderer_surface_get_type()), nullptr
))), ((gtk_cell_renderer_get_type ()))))))
;
5546}
5547
5548static VclPolicyType GtkToVcl(GtkPolicyType eType)
5549{
5550 VclPolicyType eRet(VclPolicyType::NEVER);
5551 switch (eType)
5552 {
5553 case GTK_POLICY_ALWAYS:
5554 eRet = VclPolicyType::ALWAYS;
5555 break;
5556 case GTK_POLICY_AUTOMATIC:
5557 eRet = VclPolicyType::AUTOMATIC;
5558 break;
5559 case GTK_POLICY_EXTERNAL:
5560 case GTK_POLICY_NEVER:
5561 eRet = VclPolicyType::NEVER;
5562 break;
5563 }
5564 return eRet;
5565}
5566
5567static GtkPolicyType VclToGtk(VclPolicyType eType)
5568{
5569 GtkPolicyType eRet(GTK_POLICY_ALWAYS);
5570 switch (eType)
5571 {
5572 case VclPolicyType::ALWAYS:
5573 eRet = GTK_POLICY_ALWAYS;
5574 break;
5575 case VclPolicyType::AUTOMATIC:
5576 eRet = GTK_POLICY_AUTOMATIC;
5577 break;
5578 case VclPolicyType::NEVER:
5579 eRet = GTK_POLICY_NEVER;
5580 break;
5581 }
5582 return eRet;
5583}
5584
5585static GtkMessageType VclToGtk(VclMessageType eType)
5586{
5587 GtkMessageType eRet(GTK_MESSAGE_INFO);
5588 switch (eType)
5589 {
5590 case VclMessageType::Info:
5591 eRet = GTK_MESSAGE_INFO;
5592 break;
5593 case VclMessageType::Warning:
5594 eRet = GTK_MESSAGE_WARNING;
5595 break;
5596 case VclMessageType::Question:
5597 eRet = GTK_MESSAGE_QUESTION;
5598 break;
5599 case VclMessageType::Error:
5600 eRet = GTK_MESSAGE_ERROR;
5601 break;
5602 case VclMessageType::Other:
5603 eRet = GTK_MESSAGE_OTHER;
5604 break;
5605 }
5606 return eRet;
5607}
5608
5609static GtkButtonsType VclToGtk(VclButtonsType eType)
5610{
5611 GtkButtonsType eRet(GTK_BUTTONS_NONE);
5612 switch (eType)
5613 {
5614 case VclButtonsType::NONE:
5615 eRet = GTK_BUTTONS_NONE;
5616 break;
5617 case VclButtonsType::Ok:
5618 eRet = GTK_BUTTONS_OK;
5619 break;
5620 case VclButtonsType::Close:
5621 eRet = GTK_BUTTONS_CLOSE;
5622 break;
5623 case VclButtonsType::Cancel:
5624 eRet = GTK_BUTTONS_CANCEL;
5625 break;
5626 case VclButtonsType::YesNo:
5627 eRet = GTK_BUTTONS_YES_NO;
5628 break;
5629 case VclButtonsType::OkCancel:
5630 eRet = GTK_BUTTONS_OK_CANCEL;
5631 break;
5632 }
5633 return eRet;
5634}
5635
5636static GtkSelectionMode VclToGtk(SelectionMode eType)
5637{
5638 GtkSelectionMode eRet(GTK_SELECTION_NONE);
5639 switch (eType)
5640 {
5641 case SelectionMode::NONE:
5642 eRet = GTK_SELECTION_NONE;
5643 break;
5644 case SelectionMode::Single:
5645 eRet = GTK_SELECTION_SINGLE;
5646 break;
5647 case SelectionMode::Range:
5648 eRet = GTK_SELECTION_BROWSE;
5649 break;
5650 case SelectionMode::Multiple:
5651 eRet = GTK_SELECTION_MULTIPLE;
5652 break;
5653 }
5654 return eRet;
5655}
5656
5657namespace {
5658
5659class GtkInstanceScrolledWindow final : public GtkInstanceContainer, public virtual weld::ScrolledWindow
5660{
5661private:
5662 GtkScrolledWindow* m_pScrolledWindow;
5663 GtkWidget *m_pOrigViewport;
5664 GtkAdjustment* m_pVAdjustment;
5665 GtkAdjustment* m_pHAdjustment;
5666 gulong m_nVAdjustChangedSignalId;
5667 gulong m_nHAdjustChangedSignalId;
5668
5669 static void signalVAdjustValueChanged(GtkAdjustment*, gpointer widget)
5670 {
5671 GtkInstanceScrolledWindow* pThis = static_cast<GtkInstanceScrolledWindow*>(widget);
5672 SolarMutexGuard aGuard;
5673 pThis->signal_vadjustment_changed();
5674 }
5675
5676 static void signalHAdjustValueChanged(GtkAdjustment*, gpointer widget)
5677 {
5678 GtkInstanceScrolledWindow* pThis = static_cast<GtkInstanceScrolledWindow*>(widget);
5679 SolarMutexGuard aGuard;
5680 pThis->signal_hadjustment_changed();
5681 }
5682
5683public:
5684 GtkInstanceScrolledWindow(GtkScrolledWindow* pScrolledWindow, GtkInstanceBuilder* pBuilder, bool bTakeOwnership, bool bUserManagedScrolling)
5685 : GtkInstanceContainer(GTK_CONTAINER(pScrolledWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pScrolledWindow)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
5686 , m_pScrolledWindow(pScrolledWindow)
5687 , m_pOrigViewport(nullptr)
5688 , m_pVAdjustment(gtk_scrolled_window_get_vadjustment(m_pScrolledWindow))
5689 , m_pHAdjustment(gtk_scrolled_window_get_hadjustment(m_pScrolledWindow))
5690 , m_nVAdjustChangedSignalId(g_signal_connect(m_pVAdjustment, "value-changed", G_CALLBACK(signalVAdjustValueChanged), this)g_signal_connect_data ((m_pVAdjustment), ("value-changed"), (
((GCallback) (signalVAdjustValueChanged))), (this), __null, (
GConnectFlags) 0)
)
5691 , m_nHAdjustChangedSignalId(g_signal_connect(m_pHAdjustment, "value-changed", G_CALLBACK(signalHAdjustValueChanged), this)g_signal_connect_data ((m_pHAdjustment), ("value-changed"), (
((GCallback) (signalHAdjustValueChanged))), (this), __null, (
GConnectFlags) 0)
)
5692 {
5693 if (bUserManagedScrolling)
5694 set_user_managed_scrolling();
5695 }
5696
5697 void set_user_managed_scrolling()
5698 {
5699 disable_notify_events();
5700 //remove the original viewport and replace it with our bodged one which
5701 //doesn't do any scrolling and expects its child to figure it out somehow
5702 assert(!m_pOrigViewport)(static_cast <bool> (!m_pOrigViewport) ? void (0) : __assert_fail
("!m_pOrigViewport", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 5702, __extension__ __PRETTY_FUNCTION__))
;
5703 GtkWidget *pViewport = gtk_bin_get_child(GTK_BIN(m_pScrolledWindow)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((m_pScrolledWindow
)), ((gtk_bin_get_type ()))))))
);
5704 assert(GTK_IS_VIEWPORT(pViewport))(static_cast <bool> ((((__extension__ ({ GTypeInstance *
__inst = (GTypeInstance*) ((pViewport)); GType __t = ((gtk_viewport_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ? void (0) : __assert_fail ("GTK_IS_VIEWPORT(pViewport)"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 5704, __extension__ __PRETTY_FUNCTION__))
;
5705 GtkWidget *pChild = gtk_bin_get_child(GTK_BIN(pViewport)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((pViewport
)), ((gtk_bin_get_type ()))))))
);
5706 g_object_ref(pChild);
5707 gtk_container_remove(GTK_CONTAINER(pViewport)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pViewport)), ((gtk_container_get_type ()))))))
, pChild);
5708 g_object_ref(pViewport);
5709 gtk_container_remove(GTK_CONTAINER(m_pScrolledWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pScrolledWindow)), ((gtk_container_get_type ()))))))
, pViewport);
5710 GtkWidget* pNewViewport = GTK_WIDGET(g_object_new(crippled_viewport_get_type(), nullptr))((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(g_object_new(crippled_viewport_get_type(), nullptr))), ((gtk_widget_get_type
()))))))
;
5711 gtk_widget_show(pNewViewport);
5712 gtk_container_add(GTK_CONTAINER(m_pScrolledWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pScrolledWindow)), ((gtk_container_get_type ()))))))
, pNewViewport);
5713 gtk_container_add(GTK_CONTAINER(pNewViewport)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pNewViewport)), ((gtk_container_get_type ()))))))
, pChild);
5714 g_object_unref(pChild);
5715 m_pOrigViewport = pViewport;
5716 enable_notify_events();
5717 }
5718
5719 virtual void hadjustment_configure(int value, int lower, int upper,
5720 int step_increment, int page_increment,
5721 int page_size) override
5722 {
5723 disable_notify_events();
5724 if (SwapForRTL())
5725 value = upper - (value - lower + page_size);
5726 gtk_adjustment_configure(m_pHAdjustment, value, lower, upper, step_increment, page_increment, page_size);
5727 enable_notify_events();
5728 }
5729
5730 virtual int hadjustment_get_value() const override
5731 {
5732 int value = gtk_adjustment_get_value(m_pHAdjustment);
5733
5734 if (SwapForRTL())
5735 {
5736 int upper = gtk_adjustment_get_upper(m_pHAdjustment);
5737 int lower = gtk_adjustment_get_lower(m_pHAdjustment);
5738 int page_size = gtk_adjustment_get_page_size(m_pHAdjustment);
5739 value = lower + (upper - value - page_size);
5740 }
5741
5742 return value;
5743 }
5744
5745 virtual void hadjustment_set_value(int value) override
5746 {
5747 disable_notify_events();
5748
5749 if (SwapForRTL())
5750 {
5751 int upper = gtk_adjustment_get_upper(m_pHAdjustment);
5752 int lower = gtk_adjustment_get_lower(m_pHAdjustment);
5753 int page_size = gtk_adjustment_get_page_size(m_pHAdjustment);
5754 value = upper - (value - lower + page_size);
5755 }
5756
5757 gtk_adjustment_set_value(m_pHAdjustment, value);
5758 enable_notify_events();
5759 }
5760
5761 virtual int hadjustment_get_upper() const override
5762 {
5763 return gtk_adjustment_get_upper(m_pHAdjustment);
5764 }
5765
5766 virtual void hadjustment_set_upper(int upper) override
5767 {
5768 disable_notify_events();
5769 gtk_adjustment_set_upper(m_pHAdjustment, upper);
5770 enable_notify_events();
5771 }
5772
5773 virtual int hadjustment_get_page_size() const override
5774 {
5775 return gtk_adjustment_get_page_size(m_pHAdjustment);
5776 }
5777
5778 virtual void hadjustment_set_page_size(int size) override
5779 {
5780 gtk_adjustment_set_page_size(m_pHAdjustment, size);
5781 }
5782
5783 virtual void hadjustment_set_page_increment(int size) override
5784 {
5785 gtk_adjustment_set_page_increment(m_pHAdjustment, size);
5786 }
5787
5788 virtual void hadjustment_set_step_increment(int size) override
5789 {
5790 gtk_adjustment_set_step_increment(m_pHAdjustment, size);
5791 }
5792
5793 virtual void set_hpolicy(VclPolicyType eHPolicy) override
5794 {
5795 GtkPolicyType eGtkVPolicy;
5796 gtk_scrolled_window_get_policy(m_pScrolledWindow, nullptr, &eGtkVPolicy);
5797 gtk_scrolled_window_set_policy(m_pScrolledWindow, eGtkVPolicy, VclToGtk(eHPolicy));
5798 }
5799
5800 virtual VclPolicyType get_hpolicy() const override
5801 {
5802 GtkPolicyType eGtkHPolicy;
5803 gtk_scrolled_window_get_policy(m_pScrolledWindow, &eGtkHPolicy, nullptr);
5804 return GtkToVcl(eGtkHPolicy);
5805 }
5806
5807 virtual int get_hscroll_height() const override
5808 {
5809 if (gtk_scrolled_window_get_overlay_scrolling(m_pScrolledWindow))
5810 return 0;
5811 return gtk_widget_get_allocated_height(gtk_scrolled_window_get_hscrollbar(m_pScrolledWindow));
5812 }
5813
5814 virtual void vadjustment_configure(int value, int lower, int upper,
5815 int step_increment, int page_increment,
5816 int page_size) override
5817 {
5818 disable_notify_events();
5819 gtk_adjustment_configure(m_pVAdjustment, value, lower, upper, step_increment, page_increment, page_size);
5820 enable_notify_events();
5821 }
5822
5823 virtual int vadjustment_get_value() const override
5824 {
5825 return gtk_adjustment_get_value(m_pVAdjustment);
5826 }
5827
5828 virtual void vadjustment_set_value(int value) override
5829 {
5830 disable_notify_events();
5831 gtk_adjustment_set_value(m_pVAdjustment, value);
5832 enable_notify_events();
5833 }
5834
5835 virtual int vadjustment_get_upper() const override
5836 {
5837 return gtk_adjustment_get_upper(m_pVAdjustment);
5838 }
5839
5840 virtual void vadjustment_set_upper(int upper) override
5841 {
5842 disable_notify_events();
5843 gtk_adjustment_set_upper(m_pVAdjustment, upper);
5844 enable_notify_events();
5845 }
5846
5847 virtual int vadjustment_get_lower() const override
5848 {
5849 return gtk_adjustment_get_lower(m_pVAdjustment);
5850 }
5851
5852 virtual void vadjustment_set_lower(int lower) override
5853 {
5854 disable_notify_events();
5855 gtk_adjustment_set_lower(m_pVAdjustment, lower);
5856 enable_notify_events();
5857 }
5858
5859 virtual int vadjustment_get_page_size() const override
5860 {
5861 return gtk_adjustment_get_page_size(m_pVAdjustment);
5862 }
5863
5864 virtual void vadjustment_set_page_size(int size) override
5865 {
5866 gtk_adjustment_set_page_size(m_pVAdjustment, size);
5867 }
5868
5869 virtual void vadjustment_set_page_increment(int size) override
5870 {
5871 gtk_adjustment_set_page_increment(m_pVAdjustment, size);
5872 }
5873
5874 virtual void vadjustment_set_step_increment(int size) override
5875 {
5876 gtk_adjustment_set_step_increment(m_pVAdjustment, size);
5877 }
5878
5879 virtual void set_vpolicy(VclPolicyType eVPolicy) override
5880 {
5881 GtkPolicyType eGtkHPolicy;
5882 gtk_scrolled_window_get_policy(m_pScrolledWindow, &eGtkHPolicy, nullptr);
5883 gtk_scrolled_window_set_policy(m_pScrolledWindow, eGtkHPolicy, VclToGtk(eVPolicy));
5884 }
5885
5886 virtual VclPolicyType get_vpolicy() const override
5887 {
5888 GtkPolicyType eGtkVPolicy;
5889 gtk_scrolled_window_get_policy(m_pScrolledWindow, nullptr, &eGtkVPolicy);
5890 return GtkToVcl(eGtkVPolicy);
5891 }
5892
5893 virtual int get_vscroll_width() const override
5894 {
5895 if (gtk_scrolled_window_get_overlay_scrolling(m_pScrolledWindow))
5896 return 0;
5897 return gtk_widget_get_allocated_width(gtk_scrolled_window_get_vscrollbar(m_pScrolledWindow));
5898 }
5899
5900 virtual void disable_notify_events() override
5901 {
5902 g_signal_handler_block(m_pVAdjustment, m_nVAdjustChangedSignalId);
5903 g_signal_handler_block(m_pHAdjustment, m_nHAdjustChangedSignalId);
5904 GtkInstanceContainer::disable_notify_events();
5905 }
5906
5907 virtual void enable_notify_events() override
5908 {
5909 GtkInstanceContainer::enable_notify_events();
5910 g_signal_handler_unblock(m_pVAdjustment, m_nVAdjustChangedSignalId);
5911 g_signal_handler_unblock(m_pHAdjustment, m_nHAdjustChangedSignalId);
5912 }
5913
5914 virtual ~GtkInstanceScrolledWindow() override
5915 {
5916 // we use GtkInstanceContainer::[disable|enable]_notify_events later on
5917 // to avoid touching these removed handlers
5918 g_signal_handler_disconnect(m_pVAdjustment, m_nVAdjustChangedSignalId);
5919 g_signal_handler_disconnect(m_pHAdjustment, m_nHAdjustChangedSignalId);
5920
5921 //put it back the way it was
5922 if (!m_pOrigViewport)
5923 return;
5924
5925 GtkInstanceContainer::disable_notify_events();
5926
5927 // force in new adjustment to drop the built-in handlers on value-changed
5928 // which are getting called eventually by the gtk_container_add call
5929 // and which access the scrolled window indicators which, in the case
5930 // of user-managed scrolling windows in toolbar popups during popdown
5931 // are nullptr causing crashes when the scrolling windows is not at its
5932 // initial 0,0 position
5933 GtkAdjustment *pVAdjustment = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
5934 gtk_scrolled_window_set_vadjustment(m_pScrolledWindow, pVAdjustment);
5935 GtkAdjustment *pHAdjustment = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
5936 gtk_scrolled_window_set_hadjustment(m_pScrolledWindow, pHAdjustment);
5937
5938 GtkWidget *pViewport = gtk_bin_get_child(GTK_BIN(m_pScrolledWindow)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((m_pScrolledWindow
)), ((gtk_bin_get_type ()))))))
);
5939 assert(CRIPPLED_IS_VIEWPORT(pViewport))(static_cast <bool> ((((__extension__ ({ GTypeInstance *
__inst = (GTypeInstance*) ((pViewport)); GType __t = ((crippled_viewport_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ? void (0) : __assert_fail ("CRIPPLED_IS_VIEWPORT(pViewport)"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 5939, __extension__ __PRETTY_FUNCTION__))
;
5940 GtkWidget *pChild = gtk_bin_get_child(GTK_BIN(pViewport)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((pViewport
)), ((gtk_bin_get_type ()))))))
);
5941 g_object_ref(pChild);
5942 gtk_container_remove(GTK_CONTAINER(pViewport)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pViewport)), ((gtk_container_get_type ()))))))
, pChild);
5943 g_object_ref(pViewport);
5944 gtk_container_remove(GTK_CONTAINER(m_pScrolledWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pScrolledWindow)), ((gtk_container_get_type ()))))))
, pViewport);
5945
5946 gtk_container_add(GTK_CONTAINER(m_pScrolledWindow)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pScrolledWindow)), ((gtk_container_get_type ()))))))
, m_pOrigViewport);
5947 g_object_unref(m_pOrigViewport);
5948 gtk_container_add(GTK_CONTAINER(m_pOrigViewport)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pOrigViewport)), ((gtk_container_get_type ()))))))
, pChild);
5949 g_object_unref(pChild);
5950 gtk_widget_destroy(pViewport);
5951 g_object_unref(pViewport);
5952 m_pOrigViewport = nullptr;
5953 GtkInstanceContainer::enable_notify_events();
5954 }
5955};
5956
5957class GtkInstanceNotebook : public GtkInstanceContainer, public virtual weld::Notebook
5958{
5959private:
5960 GtkNotebook* m_pNotebook;
5961 GtkBox* m_pOverFlowBox;
5962 GtkNotebook* m_pOverFlowNotebook;
5963 gulong m_nSwitchPageSignalId;
5964 gulong m_nOverFlowSwitchPageSignalId;
5965 gulong m_nSizeAllocateSignalId;
5966 gulong m_nFocusSignalId;
5967 gulong m_nChangeCurrentPageId;
5968 guint m_nLaunchSplitTimeoutId;
5969 bool m_bOverFlowBoxActive;
5970 bool m_bOverFlowBoxIsStart;
5971 bool m_bInternalPageChange;
5972 int m_nStartTabCount;
5973 int m_nEndTabCount;
5974 mutable std::vector<std::unique_ptr<GtkInstanceContainer>> m_aPages;
5975
5976 static void signalSwitchPage(GtkNotebook*, GtkWidget*, guint nNewPage, gpointer widget)
5977 {
5978 GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget);
5979 SolarMutexGuard aGuard;
5980 pThis->signal_switch_page(nNewPage);
5981 }
5982
5983 static gboolean launch_overflow_switch_page(GtkInstanceNotebook* pThis)
5984 {
5985 SolarMutexGuard aGuard;
5986 pThis->signal_overflow_switch_page();
5987 return false;
5988 }
5989
5990 static void signalOverFlowSwitchPage(GtkNotebook*, GtkWidget*, guint, gpointer widget)
5991 {
5992 g_timeout_add_full(G_PRIORITY_HIGH_IDLE100, 0, reinterpret_cast<GSourceFunc>(launch_overflow_switch_page), widget, nullptr);
5993 }
5994
5995 void signal_switch_page(int nNewPage)
5996 {
5997 if (m_bOverFlowBoxIsStart)
5998 {
5999 auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
6000 // add count of overflow pages, minus the extra tab
6001 nNewPage += nOverFlowLen;
6002 }
6003
6004 bool bAllow = m_bInternalPageChange || !m_aLeavePageHdl.IsSet() || m_aLeavePageHdl.Call(get_current_page_ident());
6005 if (!bAllow)
6006 {
6007 g_signal_stop_emission_by_name(m_pNotebook, "switch-page");
6008 return;
6009 }
6010 if (m_bOverFlowBoxActive)
6011 gtk_notebook_set_current_page(m_pOverFlowNotebook, gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1);
6012 OString sNewIdent(get_page_ident(nNewPage));
6013 if (!m_bInternalPageChange)
6014 m_aEnterPageHdl.Call(sNewIdent);
6015 }
6016
6017 void unsplit_notebooks()
6018 {
6019 int nOverFlowPages = gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1;
6020 int nMainPages = gtk_notebook_get_n_pages(m_pNotebook);
6021 int nPageIndex = 0;
6022 if (!m_bOverFlowBoxIsStart)
6023 nPageIndex += nMainPages;
6024
6025 // take the overflow pages, and put them back at the end of the normal one
6026 int i = nMainPages;
6027 while (nOverFlowPages)
6028 {
6029 OString sIdent(get_page_ident(m_pOverFlowNotebook, 0));
6030 OUString sLabel(get_tab_label_text(m_pOverFlowNotebook, 0));
6031 remove_page(m_pOverFlowNotebook, sIdent);
6032
6033 GtkWidget* pPage = m_aPages[nPageIndex]->getWidget();
6034 insert_page(m_pNotebook, sIdent, sLabel, pPage, -1);
6035
6036 GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook,
6037 gtk_notebook_get_nth_page(m_pNotebook, i));
6038 gtk_widget_set_hexpand(pTabWidget, true);
6039 --nOverFlowPages;
6040 ++i;
6041 ++nPageIndex;
6042 }
6043
6044 // remove the dangling placeholder tab page
6045 remove_page(m_pOverFlowNotebook, "useless");
6046 }
6047
6048 // a tab has been selected on the overflow notebook
6049 void signal_overflow_switch_page()
6050 {
6051 int nNewPage = gtk_notebook_get_current_page(m_pOverFlowNotebook);
6052 int nOverFlowPages = gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1;
6053 if (nNewPage == nOverFlowPages)
6054 {
6055 // the useless tab which is there because there has to be an active tab
6056 return;
6057 }
6058
6059 // check if we are allowed leave before attempting to resplit the notebooks
6060 bool bAllow = !m_aLeavePageHdl.IsSet() || m_aLeavePageHdl.Call(get_current_page_ident());
6061 if (!bAllow)
6062 return;
6063
6064 disable_notify_events();
6065
6066 // take the overflow pages, and put them back at the end of the normal one
6067 unsplit_notebooks();
6068
6069 // now redo the split, the pages will be split the other way around this time
6070 std::swap(m_nStartTabCount, m_nEndTabCount);
6071 split_notebooks();
6072
6073 gtk_notebook_set_current_page(m_pNotebook, nNewPage);
6074
6075 enable_notify_events();
6076
6077 // trigger main notebook switch-page callback
6078 OString sNewIdent(get_page_ident(m_pNotebook, nNewPage));
6079 m_aEnterPageHdl.Call(sNewIdent);
6080 }
6081
6082 static OString get_page_ident(GtkNotebook *pNotebook, guint nPage)
6083 {
6084 const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(pNotebook, gtk_notebook_get_nth_page(pNotebook, nPage));
6085 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pTabWidget)), ((gtk_buildable_get_type ()))))))
);
6086 return OString(pStr, pStr ? strlen(pStr) : 0);
6087 }
6088
6089 static gint get_page_number(GtkNotebook *pNotebook, const OString& rIdent)
6090 {
6091 gint nPages = gtk_notebook_get_n_pages(pNotebook);
6092 for (gint i = 0; i < nPages; ++i)
6093 {
6094 const GtkWidget* pTabWidget = gtk_notebook_get_tab_label(pNotebook, gtk_notebook_get_nth_page(pNotebook, i));
6095 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pTabWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pTabWidget)), ((gtk_buildable_get_type ()))))))
);
6096 if (pStr && strcmp(pStr, rIdent.getStr()) == 0)
6097 return i;
6098 }
6099 return -1;
6100 }
6101
6102 int remove_page(GtkNotebook *pNotebook, const OString& rIdent)
6103 {
6104 disable_notify_events();
6105 int nPageNumber = get_page_number(pNotebook, rIdent);
6106 gtk_notebook_remove_page(pNotebook, nPageNumber);
6107 enable_notify_events();
6108 return nPageNumber;
6109 }
6110
6111 static OUString get_tab_label_text(GtkNotebook *pNotebook, guint nPage)
6112 {
6113 const gchar* pStr = gtk_notebook_get_tab_label_text(pNotebook, gtk_notebook_get_nth_page(pNotebook, nPage));
6114 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
6115 }
6116
6117 static void set_tab_label_text(GtkNotebook *pNotebook, guint nPage, const OUString& rText)
6118 {
6119 OString sUtf8(rText.toUtf8());
6120
6121 GtkWidget* pPage = gtk_notebook_get_nth_page(pNotebook, nPage);
6122
6123 // tdf#128241 if there's already a label here, reuse it so the buildable
6124 // name remains the same, gtk_notebook_set_tab_label_text will replace
6125 // the label widget with a new one
6126 GtkWidget* pTabWidget = gtk_notebook_get_tab_label(pNotebook, pPage);
6127 if (pTabWidget && GTK_IS_LABEL(pTabWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pTabWidget)); GType __t = ((gtk_label_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
6128 {
6129 gtk_label_set_label(GTK_LABEL(pTabWidget)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pTabWidget)), ((gtk_label_get_type ()))))))
, sUtf8.getStr());
6130 return;
6131 }
6132
6133 gtk_notebook_set_tab_label_text(pNotebook, pPage, sUtf8.getStr());
6134 }
6135
6136 void append_useless_page(GtkNotebook *pNotebook)
6137 {
6138 disable_notify_events();
6139
6140 GtkWidget *pTabWidget = gtk_fixed_new();
6141 gtk_buildable_set_name(GTK_BUILDABLE(pTabWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pTabWidget)), ((gtk_buildable_get_type ()))))))
, "useless");
6142
6143 GtkWidget *pChild = gtk_grid_new();
6144 gtk_notebook_append_page(pNotebook, pChild, pTabWidget);
6145 gtk_widget_show(pChild);
6146 gtk_widget_show(pTabWidget);
6147
6148 enable_notify_events();
6149 }
6150
6151 void insert_page(GtkNotebook *pNotebook, const OString& rIdent, const OUString& rLabel, GtkWidget *pChild, int nPos)
6152 {
6153 disable_notify_events();
6154
6155 GtkWidget *pTabWidget = gtk_label_new_with_mnemonic(MapToGtkAccelerator(rLabel).getStr());
6156 gtk_buildable_set_name(GTK_BUILDABLE(pTabWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pTabWidget)), ((gtk_buildable_get_type ()))))))
, rIdent.getStr());
6157
6158 gtk_notebook_insert_page(pNotebook, pChild, pTabWidget, nPos);
6159 gtk_widget_show(pChild);
6160 gtk_widget_show(pTabWidget);
6161
6162 if (nPos != -1)
6163 {
6164 unsigned int nPageIndex = static_cast<unsigned int>(nPos);
6165 if (nPageIndex < m_aPages.size())
6166 m_aPages.insert(m_aPages.begin() + nPageIndex, nullptr);
6167 }
6168
6169 enable_notify_events();
6170 }
6171
6172 void make_overflow_boxes()
6173 {
6174 m_pOverFlowBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_box_new
(GTK_ORIENTATION_VERTICAL, 0))), ((gtk_box_get_type ()))))))
;
6175 GtkWidget* pParent = gtk_widget_get_parent(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6176 gtk_container_add(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, GTK_WIDGET(m_pOverFlowBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowBox)), ((gtk_widget_get_type ()))))))
);
6177 gtk_box_pack_start(m_pOverFlowBox, GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
, false, false, 0);
6178 g_object_ref(m_pNotebook);
6179 gtk_container_remove(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6180 gtk_box_pack_start(m_pOverFlowBox, GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
, true, true, 0);
6181 g_object_unref(m_pNotebook);
6182 gtk_widget_show(GTK_WIDGET(m_pOverFlowBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowBox)), ((gtk_widget_get_type ()))))))
);
6183 }
6184
6185 void split_notebooks()
6186 {
6187 // get the original preferred size for the notebook, the sane width
6188 // expected here depends on the notebooks all initially having
6189 // scrollable tabs enabled
6190 GtkAllocation alloc;
6191 gtk_widget_get_allocation(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
, &alloc);
6192
6193 // toggle the direction of the split since the last time
6194 m_bOverFlowBoxIsStart = !m_bOverFlowBoxIsStart;
6195 if (!m_pOverFlowBox)
6196 make_overflow_boxes();
6197
6198 // don't scroll the tabs anymore
6199 gtk_notebook_set_scrollable(m_pNotebook, false);
6200
6201 gtk_widget_freeze_child_notify(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6202 gtk_widget_freeze_child_notify(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6203
6204 gtk_widget_show(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6205
6206 gint nPages;
6207
6208 GtkRequisition size1, size2;
6209
6210 if (!m_nStartTabCount && !m_nEndTabCount)
6211 {
6212 nPages = gtk_notebook_get_n_pages(m_pNotebook);
6213
6214 std::vector<int> aLabelWidths;
6215 //move tabs to the overflow notebook
6216 for (int i = 0; i < nPages; ++i)
6217 {
6218 OUString sLabel(get_tab_label_text(m_pNotebook, i));
6219 aLabelWidths.push_back(get_pixel_size(sLabel).Width());
6220 }
6221 int row_width = std::accumulate(aLabelWidths.begin(), aLabelWidths.end(), 0) / 2;
6222 int count = 0;
6223 for (int i = 0; i < nPages; ++i)
6224 {
6225 count += aLabelWidths[i];
6226 if (count >= row_width)
6227 {
6228 m_nStartTabCount = i;
6229 break;
6230 }
6231 }
6232
6233 m_nEndTabCount = nPages - m_nStartTabCount;
6234 }
6235
6236 //move the tabs to the overflow notebook
6237 int i = 0;
6238 int nOverFlowPages = m_nStartTabCount;
6239 while (nOverFlowPages)
6240 {
6241 OString sIdent(get_page_ident(m_pNotebook, 0));
6242 OUString sLabel(get_tab_label_text(m_pNotebook, 0));
6243 remove_page(m_pNotebook, sIdent);
6244 insert_page(m_pOverFlowNotebook, sIdent, sLabel, gtk_grid_new(), -1);
6245 GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pOverFlowNotebook,
6246 gtk_notebook_get_nth_page(m_pOverFlowNotebook, i));
6247 gtk_widget_set_hexpand(pTabWidget, true);
6248
6249 --nOverFlowPages;
6250 ++i;
6251 }
6252
6253 for (i = 0; i < m_nEndTabCount; ++i)
6254 {
6255 GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook,
6256 gtk_notebook_get_nth_page(m_pNotebook, i));
6257 gtk_widget_set_hexpand(pTabWidget, true);
6258 }
6259
6260 // have to have some tab as the active tab of the overflow notebook
6261 append_useless_page(m_pOverFlowNotebook);
6262 gtk_notebook_set_current_page(m_pOverFlowNotebook, gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1);
6263 if (gtk_widget_has_focus(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
))
6264 gtk_widget_grab_focus(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6265
6266 // add this temporarily to the normal notebook to measure how wide
6267 // the row would be if switched to the other notebook
6268 append_useless_page(m_pNotebook);
6269
6270 gtk_widget_get_preferred_size(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
, nullptr, &size1);
6271 gtk_widget_get_preferred_size(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
, nullptr, &size2);
6272
6273 auto nWidth = std::max(size1.width, size2.width);
6274 gtk_widget_set_size_request(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
, nWidth, alloc.height);
6275 gtk_widget_set_size_request(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
, nWidth, -1);
6276
6277 // remove it once we've measured it
6278 remove_page(m_pNotebook, "useless");
6279
6280 gtk_widget_thaw_child_notify(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6281 gtk_widget_thaw_child_notify(GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6282
6283 m_bOverFlowBoxActive = true;
6284 }
6285
6286 static gboolean launch_split_notebooks(GtkInstanceNotebook* pThis)
6287 {
6288 int nCurrentPage = pThis->get_current_page();
6289 pThis->split_notebooks();
6290 pThis->set_current_page(nCurrentPage);
6291 pThis->m_nLaunchSplitTimeoutId = 0;
6292 return false;
6293 }
6294
6295 // tdf#120371
6296 // https://developer.gnome.org/hig-book/unstable/controls-notebooks.html.en#controls-too-many-tabs
6297 // if no of tabs > 6, but only if the notebook would auto-scroll, then split the tabs over
6298 // two notebooks. Checking for the auto-scroll allows themes like Ambience under Ubuntu 16.04 to keep
6299 // tabs in a single row when they would fit
6300 void signal_notebook_size_allocate()
6301 {
6302 if (m_bOverFlowBoxActive || m_nLaunchSplitTimeoutId)
6303 return;
6304 disable_notify_events();
6305 gint nPages = gtk_notebook_get_n_pages(m_pNotebook);
6306 if (nPages > 6 && gtk_notebook_get_tab_pos(m_pNotebook) == GTK_POS_TOP)
6307 {
6308 for (gint i = 0; i < nPages; ++i)
6309 {
6310 GtkWidget* pTabWidget = gtk_notebook_get_tab_label(m_pNotebook, gtk_notebook_get_nth_page(m_pNotebook, i));
6311 if (!gtk_widget_get_child_visible(pTabWidget))
6312 {
6313 m_nLaunchSplitTimeoutId = g_timeout_add_full(G_PRIORITY_HIGH_IDLE100, 0, reinterpret_cast<GSourceFunc>(launch_split_notebooks), this, nullptr);
6314 break;
6315 }
6316 }
6317 }
6318 enable_notify_events();
6319 }
6320
6321 static void signalSizeAllocate(GtkWidget*, GdkRectangle*, gpointer widget)
6322 {
6323 GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget);
6324 pThis->signal_notebook_size_allocate();
6325 }
6326
6327 bool signal_focus(GtkDirectionType direction)
6328 {
6329 if (!m_bOverFlowBoxActive)
6330 return false;
6331
6332 int nPage = gtk_notebook_get_current_page(m_pNotebook);
6333 if (direction == GTK_DIR_LEFT && nPage == 0)
6334 {
6335 auto nOverFlowLen = gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1;
6336 gtk_notebook_set_current_page(m_pOverFlowNotebook, nOverFlowLen - 1);
6337 return true;
6338 }
6339 else if (direction == GTK_DIR_RIGHT && nPage == gtk_notebook_get_n_pages(m_pNotebook) - 1)
6340 {
6341 gtk_notebook_set_current_page(m_pOverFlowNotebook, 0);
6342 return true;
6343 }
6344
6345 return false;
6346 }
6347
6348 static gboolean signalFocus(GtkNotebook* notebook, GtkDirectionType direction, gpointer widget)
6349 {
6350 // if the notebook widget itself has focus
6351 if (gtk_widget_is_focus(GTK_WIDGET(notebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(notebook)), ((gtk_widget_get_type ()))))))
))
6352 {
6353 GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget);
6354 return pThis->signal_focus(direction);
6355 }
6356 return false;
6357 }
6358
6359 // ctrl + page_up/ page_down
6360 bool signal_change_current_page(gint arg1)
6361 {
6362 bool bHandled = signal_focus(arg1 < 0 ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
6363 if (bHandled)
6364 g_signal_stop_emission_by_name(m_pNotebook, "change-current-page");
6365 return false;
6366 }
6367
6368 static gboolean signalChangeCurrentPage(GtkNotebook*, gint arg1, gpointer widget)
6369 {
6370 if (arg1 == 0)
6371 return true;
6372 GtkInstanceNotebook* pThis = static_cast<GtkInstanceNotebook*>(widget);
6373 return pThis->signal_change_current_page(arg1);
6374 }
6375
6376public:
6377 GtkInstanceNotebook(GtkNotebook* pNotebook, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
6378 : GtkInstanceContainer(GTK_CONTAINER(pNotebook)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pNotebook)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
6379 , m_pNotebook(pNotebook)
6380 , m_pOverFlowBox(nullptr)
6381 , m_pOverFlowNotebook(GTK_NOTEBOOK(gtk_notebook_new())((((GtkNotebook*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_notebook_new())), ((gtk_notebook_get_type ()))))))
)
6382 , m_nSwitchPageSignalId(g_signal_connect(pNotebook, "switch-page", G_CALLBACK(signalSwitchPage), this)g_signal_connect_data ((pNotebook), ("switch-page"), (((GCallback
) (signalSwitchPage))), (this), __null, (GConnectFlags) 0)
)
6383 , m_nOverFlowSwitchPageSignalId(g_signal_connect(m_pOverFlowNotebook, "switch-page", G_CALLBACK(signalOverFlowSwitchPage), this)g_signal_connect_data ((m_pOverFlowNotebook), ("switch-page")
, (((GCallback) (signalOverFlowSwitchPage))), (this), __null,
(GConnectFlags) 0)
)
6384 , m_nFocusSignalId(g_signal_connect(pNotebook, "focus", G_CALLBACK(signalFocus), this)g_signal_connect_data ((pNotebook), ("focus"), (((GCallback) (
signalFocus))), (this), __null, (GConnectFlags) 0)
)
6385 , m_nChangeCurrentPageId(g_signal_connect(pNotebook, "change-current-page", G_CALLBACK(signalChangeCurrentPage), this)g_signal_connect_data ((pNotebook), ("change-current-page"), (
((GCallback) (signalChangeCurrentPage))), (this), __null, (GConnectFlags
) 0)
)
6386 , m_nLaunchSplitTimeoutId(0)
6387 , m_bOverFlowBoxActive(false)
6388 , m_bOverFlowBoxIsStart(false)
6389 , m_bInternalPageChange(false)
6390 , m_nStartTabCount(0)
6391 , m_nEndTabCount(0)
6392 {
6393 gtk_widget_add_events(GTK_WIDGET(pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pNotebook)), ((gtk_widget_get_type ()))))))
, GDK_SCROLL_MASK);
6394 if (get_n_pages() > 6)
6395 m_nSizeAllocateSignalId = g_signal_connect_after(pNotebook, "size-allocate", G_CALLBACK(signalSizeAllocate), this)g_signal_connect_data ((pNotebook), ("size-allocate"), (((GCallback
) (signalSizeAllocate))), (this), __null, G_CONNECT_AFTER)
;
6396 else
6397 m_nSizeAllocateSignalId = 0;
6398 gtk_notebook_set_show_border(m_pOverFlowNotebook, false);
6399
6400 // tdf#122623 it's nigh impossible to have a GtkNotebook without an active (checked) tab, so try and theme
6401 // the unwanted tab into invisibility
6402 GtkStyleContext *pNotebookContext = gtk_widget_get_style_context(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6403 GtkCssProvider *pProvider = gtk_css_provider_new();
6404 static const gchar data[] = "header.top > tabs > tab:checked { box-shadow: none; padding: 0 0 0 0; margin: 0 0 0 0; border-image: none; border-image-width: 0 0 0 0; background-image: none; background-color: transparent; border-radius: 0 0 0 0; border-width: 0 0 0 0; border-style: none; border-color: transparent; opacity: 0; min-height: 0; min-width: 0; }";
6405 static const gchar olddata[] = "tab.top:active { box-shadow: none; padding: 0 0 0 0; margin: 0 0 0 0; border-image: none; border-image-width: 0 0 0 0; background-image: none; background-color: transparent; border-radius: 0 0 0 0; border-width: 0 0 0 0; border-style: none; border-color: transparent; opacity: 0; }";
6406 gtk_css_provider_load_from_data(pProvider, gtk_check_version(3, 20, 0) == nullptr ? data : olddata, -1, nullptr);
6407 gtk_style_context_add_provider(pNotebookContext, GTK_STYLE_PROVIDER(pProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((pProvider)), ((gtk_style_provider_get_type ()))))))
,
6408 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
6409 }
6410
6411 virtual int get_current_page() const override
6412 {
6413 int nPage = gtk_notebook_get_current_page(m_pNotebook);
6414 if (nPage == -1)
6415 return nPage;
6416 if (m_bOverFlowBoxIsStart)
6417 {
6418 auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
6419 // add count of overflow pages, minus the extra tab
6420 nPage += nOverFlowLen;
6421 }
6422 return nPage;
6423 }
6424
6425 virtual OString get_page_ident(int nPage) const override
6426 {
6427 auto nMainLen = gtk_notebook_get_n_pages(m_pNotebook);
6428 auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
6429 if (m_bOverFlowBoxIsStart)
6430 {
6431 if (nPage < nOverFlowLen)
6432 return get_page_ident(m_pOverFlowNotebook, nPage);
6433 nPage -= nOverFlowLen;
6434 return get_page_ident(m_pNotebook, nPage);
6435 }
6436 else
6437 {
6438 if (nPage < nMainLen)
6439 return get_page_ident(m_pNotebook, nPage);
6440 nPage -= nMainLen;
6441 return get_page_ident(m_pOverFlowNotebook, nPage);
6442 }
6443 }
6444
6445 virtual OString get_current_page_ident() const override
6446 {
6447 const int nPage = get_current_page();
6448 return nPage != -1 ? get_page_ident(nPage) : OString();
6449 }
6450
6451 virtual int get_page_index(const OString& rIdent) const override
6452 {
6453 auto nMainIndex = get_page_number(m_pNotebook, rIdent);
6454 auto nOverFlowIndex = get_page_number(m_pOverFlowNotebook, rIdent);
6455
6456 if (nMainIndex == -1 && nOverFlowIndex == -1)
6457 return -1;
6458
6459 if (m_bOverFlowBoxIsStart)
6460 {
6461 if (nOverFlowIndex != -1)
6462 return nOverFlowIndex;
6463 else
6464 {
6465 auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
6466 return nMainIndex + nOverFlowLen;
6467 }
6468 }
6469 else
6470 {
6471 if (nMainIndex != -1)
6472 return nMainIndex;
6473 else
6474 {
6475 auto nMainLen = gtk_notebook_get_n_pages(m_pNotebook);
6476 return nOverFlowIndex + nMainLen;
6477 }
6478 }
6479 }
6480
6481 virtual weld::Container* get_page(const OString& rIdent) const override
6482 {
6483 int nPage = get_page_index(rIdent);
6484 if (nPage < 0)
6485 return nullptr;
6486
6487 GtkContainer* pChild;
6488 if (m_bOverFlowBoxIsStart)
6489 {
6490 auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
6491 if (nPage < nOverFlowLen)
6492 pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage))),
((gtk_container_get_type ()))))))
;
6493 else
6494 {
6495 nPage -= nOverFlowLen;
6496 pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pNotebook, nPage))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_notebook_get_nth_page(m_pNotebook, nPage))), ((gtk_container_get_type
()))))))
;
6497 }
6498 }
6499 else
6500 {
6501 auto nMainLen = gtk_notebook_get_n_pages(m_pNotebook);
6502 if (nPage < nMainLen)
6503 pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pNotebook, nPage))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_notebook_get_nth_page(m_pNotebook, nPage))), ((gtk_container_get_type
()))))))
;
6504 else
6505 {
6506 nPage -= nMainLen;
6507 pChild = GTK_CONTAINER(gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_notebook_get_nth_page(m_pOverFlowNotebook, nPage))),
((gtk_container_get_type ()))))))
;
6508 }
6509 }
6510
6511 unsigned int nPageIndex = static_cast<unsigned int>(nPage);
6512 if (m_aPages.size() < nPageIndex + 1)
6513 m_aPages.resize(nPageIndex + 1);
6514 if (!m_aPages[nPageIndex])
6515 m_aPages[nPageIndex].reset(new GtkInstanceContainer(pChild, m_pBuilder, false));
6516 return m_aPages[nPageIndex].get();
6517 }
6518
6519 virtual void set_current_page(int nPage) override
6520 {
6521 // normally we'd call disable_notify_events/enable_notify_events here,
6522 // but the notebook is complicated by the need to support the
6523 // double-decker hackery so for simplicity just flag that the page
6524 // change is not a directly user-triggered one
6525 bool bInternalPageChange = m_bInternalPageChange;
6526 m_bInternalPageChange = true;
6527
6528 if (m_bOverFlowBoxIsStart)
6529 {
6530 auto nOverFlowLen = m_bOverFlowBoxActive ? gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1 : 0;
6531 if (nPage < nOverFlowLen)
6532 gtk_notebook_set_current_page(m_pOverFlowNotebook, nPage);
6533 else
6534 {
6535 nPage -= nOverFlowLen;
6536 gtk_notebook_set_current_page(m_pNotebook, nPage);
6537 }
6538 }
6539 else
6540 {
6541 auto nMainLen = gtk_notebook_get_n_pages(m_pNotebook);
6542 if (nPage < nMainLen)
6543 gtk_notebook_set_current_page(m_pNotebook, nPage);
6544 else
6545 {
6546 nPage -= nMainLen;
6547 gtk_notebook_set_current_page(m_pOverFlowNotebook, nPage);
6548 }
6549 }
6550
6551 m_bInternalPageChange = bInternalPageChange;
6552 }
6553
6554 virtual void set_current_page(const OString& rIdent) override
6555 {
6556 gint nPage = get_page_index(rIdent);
6557 set_current_page(nPage);
6558 }
6559
6560 virtual int get_n_pages() const override
6561 {
6562 int nLen = gtk_notebook_get_n_pages(m_pNotebook);
6563 if (m_bOverFlowBoxActive)
6564 nLen += gtk_notebook_get_n_pages(m_pOverFlowNotebook) - 1;
6565 return nLen;
6566 }
6567
6568 virtual OUString get_tab_label_text(const OString& rIdent) const override
6569 {
6570 gint nPageNum = get_page_number(m_pNotebook, rIdent);
6571 if (nPageNum != -1)
6572 return get_tab_label_text(m_pNotebook, nPageNum);
6573 nPageNum = get_page_number(m_pOverFlowNotebook, rIdent);
6574 if (nPageNum != -1)
6575 return get_tab_label_text(m_pOverFlowNotebook, nPageNum);
6576 return OUString();
6577 }
6578
6579 virtual void set_tab_label_text(const OString& rIdent, const OUString& rText) override
6580 {
6581 gint nPageNum = get_page_number(m_pNotebook, rIdent);
6582 if (nPageNum != -1)
6583 {
6584 set_tab_label_text(m_pNotebook, nPageNum, rText);
6585 return;
6586 }
6587 nPageNum = get_page_number(m_pOverFlowNotebook, rIdent);
6588 if (nPageNum != -1)
6589 {
6590 set_tab_label_text(m_pOverFlowNotebook, nPageNum, rText);
6591 }
6592 }
6593
6594 virtual void disable_notify_events() override
6595 {
6596 g_signal_handler_block(m_pNotebook, m_nSwitchPageSignalId);
6597 g_signal_handler_block(m_pNotebook, m_nFocusSignalId);
6598 g_signal_handler_block(m_pNotebook, m_nChangeCurrentPageId);
6599 g_signal_handler_block(m_pOverFlowNotebook, m_nOverFlowSwitchPageSignalId);
6600 gtk_widget_freeze_child_notify(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6601 GtkInstanceContainer::disable_notify_events();
6602 }
6603
6604 virtual void enable_notify_events() override
6605 {
6606 GtkInstanceContainer::enable_notify_events();
6607 gtk_widget_thaw_child_notify(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6608 g_signal_handler_unblock(m_pOverFlowNotebook, m_nOverFlowSwitchPageSignalId);
6609 g_signal_handler_unblock(m_pNotebook, m_nSwitchPageSignalId);
6610 g_signal_handler_unblock(m_pNotebook, m_nFocusSignalId);
6611 g_signal_handler_unblock(m_pNotebook, m_nChangeCurrentPageId);
6612 }
6613
6614 void reset_split_data()
6615 {
6616 // reset overflow and allow it to be recalculated if necessary
6617 gtk_widget_hide(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6618 m_bOverFlowBoxActive = false;
6619 m_nStartTabCount = 0;
6620 m_nEndTabCount = 0;
6621 }
6622
6623 virtual void remove_page(const OString& rIdent) override
6624 {
6625 if (m_bOverFlowBoxActive)
6626 {
6627 unsplit_notebooks();
6628 reset_split_data();
6629 }
6630
6631 unsigned int nPageIndex = remove_page(m_pNotebook, rIdent);
6632 if (nPageIndex < m_aPages.size())
6633 m_aPages.erase(m_aPages.begin() + nPageIndex);
6634 }
6635
6636 virtual void insert_page(const OString& rIdent, const OUString& rLabel, int nPos) override
6637 {
6638 if (m_bOverFlowBoxActive)
6639 {
6640 unsplit_notebooks();
6641 reset_split_data();
6642 }
6643
6644 // reset overflow and allow it to be recalculated if necessary
6645 gtk_widget_hide(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6646 m_bOverFlowBoxActive = false;
6647
6648 insert_page(m_pNotebook, rIdent, rLabel, gtk_grid_new(), nPos);
6649 }
6650
6651 virtual ~GtkInstanceNotebook() override
6652 {
6653 if (m_nLaunchSplitTimeoutId)
6654 g_source_remove(m_nLaunchSplitTimeoutId);
6655 if (m_nSizeAllocateSignalId)
6656 g_signal_handler_disconnect(m_pNotebook, m_nSizeAllocateSignalId);
6657 g_signal_handler_disconnect(m_pNotebook, m_nSwitchPageSignalId);
6658 g_signal_handler_disconnect(m_pNotebook, m_nFocusSignalId);
6659 g_signal_handler_disconnect(m_pNotebook, m_nChangeCurrentPageId);
6660 g_signal_handler_disconnect(m_pOverFlowNotebook, m_nOverFlowSwitchPageSignalId);
6661 gtk_widget_destroy(GTK_WIDGET(m_pOverFlowNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowNotebook)), ((gtk_widget_get_type ()))))))
);
6662 if (m_pOverFlowBox)
6663 {
6664 // put it back to how we found it initially
6665 GtkWidget* pParent = gtk_widget_get_parent(GTK_WIDGET(m_pOverFlowBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowBox)), ((gtk_widget_get_type ()))))))
);
6666 g_object_ref(m_pNotebook);
6667 gtk_container_remove(GTK_CONTAINER(m_pOverFlowBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pOverFlowBox)), ((gtk_container_get_type ()))))))
, GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6668 gtk_container_add(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, GTK_WIDGET(m_pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pNotebook)), ((gtk_widget_get_type ()))))))
);
6669 g_object_unref(m_pNotebook);
6670
6671 gtk_widget_destroy(GTK_WIDGET(m_pOverFlowBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverFlowBox)), ((gtk_widget_get_type ()))))))
);
6672 }
6673 }
6674};
6675
6676class GtkInstanceButton : public GtkInstanceContainer, public virtual weld::Button
6677{
6678private:
6679 GtkButton* m_pButton;
6680 gulong m_nSignalId;
6681
6682 static void signalClicked(GtkButton*, gpointer widget)
6683 {
6684 GtkInstanceButton* pThis = static_cast<GtkInstanceButton*>(widget);
6685 SolarMutexGuard aGuard;
6686 pThis->signal_clicked();
6687 }
6688
6689 virtual void ensureMouseEventWidget() override
6690 {
6691 // The GtkButton is sufficient to get mouse events without an intermediate GtkEventBox
6692 if (!m_pMouseEventBox)
6693 m_pMouseEventBox = m_pWidget;
6694 }
6695
6696public:
6697 GtkInstanceButton(GtkButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
6698 : GtkInstanceContainer(GTK_CONTAINER(pButton)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pButton)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
6699 , m_pButton(pButton)
6700 , m_nSignalId(g_signal_connect(pButton, "clicked", G_CALLBACK(signalClicked), this)g_signal_connect_data ((pButton), ("clicked"), (((GCallback) (
signalClicked))), (this), __null, (GConnectFlags) 0)
)
6701 {
6702 g_object_set_data(G_OBJECT(m_pButton)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pButton)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceButton", this);
6703 }
6704
6705 virtual void set_label(const OUString& rText) override
6706 {
6707 ::set_label(m_pButton, rText);
6708 }
6709
6710 virtual void set_image(VirtualDevice* pDevice) override
6711 {
6712 gtk_button_set_always_show_image(m_pButton, true);
6713 gtk_button_set_image_position(m_pButton, GTK_POS_LEFT);
6714 if (pDevice)
6715 gtk_button_set_image(m_pButton, image_new_from_virtual_device(*pDevice));
6716 else
6717 gtk_button_set_image(m_pButton, nullptr);
6718 }
6719
6720 virtual void set_from_icon_name(const OUString& rIconName) override
6721 {
6722 GdkPixbuf* pixbuf = load_icon_by_name(rIconName);
6723 if (!pixbuf)
6724 gtk_button_set_image(m_pButton, nullptr);
6725 else
6726 {
6727 gtk_button_set_image(m_pButton, gtk_image_new_from_pixbuf(pixbuf));
6728 g_object_unref(pixbuf);
6729 }
6730 }
6731
6732 virtual void set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage) override
6733 {
6734 GdkPixbuf* pixbuf = getPixbuf(rImage);
6735 if (!pixbuf)
6736 gtk_button_set_image(m_pButton, nullptr);
6737 else
6738 {
6739 gtk_button_set_image(m_pButton, gtk_image_new_from_pixbuf(pixbuf));
6740 g_object_unref(pixbuf);
6741 }
6742 }
6743
6744 virtual OUString get_label() const override
6745 {
6746 return ::get_label(m_pButton);
6747 }
6748
6749 virtual void set_label_line_wrap(bool wrap) override
6750 {
6751 GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pButton)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((m_pButton
)), ((gtk_bin_get_type ()))))))
);
6752 gtk_label_set_line_wrap(GTK_LABEL(pChild)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pChild)), ((gtk_label_get_type ()))))))
, wrap);
6753 }
6754
6755 // allow us to block buttons with click handlers making dialogs return a response
6756 bool has_click_handler() const
6757 {
6758 return m_aClickHdl.IsSet();
6759 }
6760
6761 void clear_click_handler()
6762 {
6763 m_aClickHdl = Link<Button&, void>();
6764 }
6765
6766 virtual void disable_notify_events() override
6767 {
6768 g_signal_handler_block(m_pButton, m_nSignalId);
6769 GtkInstanceContainer::disable_notify_events();
6770 }
6771
6772 virtual void enable_notify_events() override
6773 {
6774 GtkInstanceContainer::enable_notify_events();
6775 g_signal_handler_unblock(m_pButton, m_nSignalId);
6776 }
6777
6778 virtual ~GtkInstanceButton() override
6779 {
6780 g_object_steal_data(G_OBJECT(m_pButton)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pButton)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceButton");
6781 g_signal_handler_disconnect(m_pButton, m_nSignalId);
6782 }
6783};
6784
6785}
6786
6787void GtkInstanceDialog::asyncresponse(gint ret)
6788{
6789 if (ret == GTK_RESPONSE_HELP)
6790 {
6791 help();
6792 return;
6793 }
6794
6795 GtkInstanceButton* pClickHandler = has_click_handler(ret);
6796 if (pClickHandler)
6797 {
6798 // make GTK_RESPONSE_DELETE_EVENT act as if cancel button was pressed
6799 if (ret == GTK_RESPONSE_DELETE_EVENT)
6800 close(false);
6801 return;
6802 }
6803
6804 if (get_modal())
6805 m_aDialogRun.dec_modal_count();
6806 hide();
6807
6808 // move the self pointer, otherwise it might be de-allocated by time we try to reset it
6809 auto xRunAsyncSelf = std::move(m_xRunAsyncSelf);
6810 auto xDialogController = std::move(m_xDialogController);
6811 auto aFunc = std::move(m_aFunc);
6812
6813 auto nResponseSignalId = m_nResponseSignalId;
6814 auto nCancelSignalId = m_nCancelSignalId;
6815 auto nSignalDeleteId = m_nSignalDeleteId;
6816 m_nResponseSignalId = 0;
6817 m_nCancelSignalId = 0;
6818 m_nSignalDeleteId = 0;
6819
6820 aFunc(GtkToVcl(ret));
6821
6822 if (nResponseSignalId)
6823 g_signal_handler_disconnect(m_pDialog, nResponseSignalId);
6824 if (nCancelSignalId)
6825 g_signal_handler_disconnect(m_pDialog, nCancelSignalId);
6826 if (nSignalDeleteId)
6827 g_signal_handler_disconnect(m_pDialog, nSignalDeleteId);
6828
6829 xDialogController.reset();
6830 xRunAsyncSelf.reset();
6831}
6832
6833int GtkInstanceDialog::run()
6834{
6835 if (GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
6836 sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_dialog_get_action_area
(((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*)
((m_pDialog)), ((gtk_dialog_get_type ()))))))))), ((gtk_box_get_type
()))))))
);
6837 int ret;
6838 while (true)
6839 {
6840 ret = m_aDialogRun.run();
6841 if (ret == GTK_RESPONSE_HELP)
6842 {
6843 help();
6844 continue;
6845 }
6846 else if (has_click_handler(ret))
6847 continue;
6848 break;
6849 }
6850 hide();
6851 return GtkToVcl(ret);
6852}
6853
6854weld::Button* GtkInstanceDialog::weld_widget_for_response(int nVclResponse)
6855{
6856 GtkButton* pButton = get_widget_for_response(VclToGtk(nVclResponse));
6857 if (!pButton)
6858 return nullptr;
6859 return new GtkInstanceButton(pButton, m_pBuilder, false);
6860}
6861
6862void GtkInstanceDialog::response(int nResponse)
6863{
6864 int nGtkResponse = VclToGtk(nResponse);
6865 //unblock this response now when activated through code
6866 if (GtkButton* pWidget = get_widget_for_response(nGtkResponse))
6867 {
6868 void* pData = g_object_get_data(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceButton");
6869 GtkInstanceButton* pButton = static_cast<GtkInstanceButton*>(pData);
6870 if (pButton)
6871 pButton->clear_click_handler();
6872 }
6873 if (GTK_IS_DIALOG(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
6874 gtk_dialog_response(GTK_DIALOG(m_pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDialog)), ((gtk_dialog_get_type ()))))))
, nGtkResponse);
6875 else if (GTK_IS_ASSISTANT(m_pDialog)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pDialog)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
6876 {
6877 if (!m_aDialogRun.loop_is_running())
6878 asyncresponse(nGtkResponse);
6879 else
6880 {
6881 m_aDialogRun.m_nResponseId = nGtkResponse;
6882 m_aDialogRun.loop_quit();
6883 }
6884 }
6885}
6886
6887void GtkInstanceDialog::close(bool bCloseSignal)
6888{
6889 GtkInstanceButton* pClickHandler = has_click_handler(GTK_RESPONSE_CANCEL);
6890 if (pClickHandler)
6891 {
6892 if (bCloseSignal)
6893 g_signal_stop_emission_by_name(m_pDialog, "close");
6894 // make esc (bCloseSignal == true) or window-delete (bCloseSignal == false)
6895 // act as if cancel button was pressed
6896 pClickHandler->clicked();
6897 return;
6898 }
6899 response(RET_CANCEL);
6900}
6901
6902GtkInstanceButton* GtkInstanceDialog::has_click_handler(int nResponse)
6903{
6904 GtkInstanceButton* pButton = nullptr;
6905 // e.g. map GTK_RESPONSE_DELETE_EVENT to GTK_RESPONSE_CANCEL
6906 nResponse = VclToGtk(GtkToVcl(nResponse));
6907 if (GtkButton* pWidget = get_widget_for_response(nResponse))
6908 {
6909 void* pData = g_object_get_data(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceButton");
6910 pButton = static_cast<GtkInstanceButton*>(pData);
6911 if (pButton && !pButton->has_click_handler())
6912 pButton = nullptr;
6913 }
6914 return pButton;
6915}
6916
6917namespace {
6918
6919class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton
6920{
6921private:
6922 GtkToggleButton* m_pToggleButton;
6923 gulong m_nSignalId;
6924
6925 static void signalToggled(GtkToggleButton*, gpointer widget)
6926 {
6927 GtkInstanceToggleButton* pThis = static_cast<GtkInstanceToggleButton*>(widget);
6928 SolarMutexGuard aGuard;
6929 pThis->signal_toggled();
6930 }
6931public:
6932 GtkInstanceToggleButton(GtkToggleButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
6933 : GtkInstanceButton(GTK_BUTTON(pButton)((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_button_get_type ()))))))
, pBuilder, bTakeOwnership)
6934 , m_pToggleButton(pButton)
6935 , m_nSignalId(g_signal_connect(m_pToggleButton, "toggled", G_CALLBACK(signalToggled), this)g_signal_connect_data ((m_pToggleButton), ("toggled"), (((GCallback
) (signalToggled))), (this), __null, (GConnectFlags) 0)
)
6936 {
6937 }
6938
6939 virtual void set_active(bool active) override
6940 {
6941 disable_notify_events();
6942 gtk_toggle_button_set_inconsistent(m_pToggleButton, false);
6943 gtk_toggle_button_set_active(m_pToggleButton, active);
6944 enable_notify_events();
6945 }
6946
6947 virtual bool get_active() const override
6948 {
6949 return gtk_toggle_button_get_active(m_pToggleButton);
6950 }
6951
6952 virtual void set_inconsistent(bool inconsistent) override
6953 {
6954 gtk_toggle_button_set_inconsistent(m_pToggleButton, inconsistent);
6955 }
6956
6957 virtual bool get_inconsistent() const override
6958 {
6959 return gtk_toggle_button_get_inconsistent(m_pToggleButton);
6960 }
6961
6962 virtual void disable_notify_events() override
6963 {
6964 g_signal_handler_block(m_pToggleButton, m_nSignalId);
6965 GtkInstanceButton::disable_notify_events();
6966 }
6967
6968 virtual void enable_notify_events() override
6969 {
6970 GtkInstanceButton::enable_notify_events();
6971 g_signal_handler_unblock(m_pToggleButton, m_nSignalId);
6972 }
6973
6974 virtual ~GtkInstanceToggleButton() override
6975 {
6976 g_signal_handler_disconnect(m_pToggleButton, m_nSignalId);
6977 }
6978};
6979
6980void do_grab(GtkWidget* pWidget)
6981{
6982 GdkDisplay *pDisplay = gtk_widget_get_display(pWidget);
6983#if GTK_CHECK_VERSION(3, 20, 0)((3) > (3) || ((3) == (3) && (24) > (20)) || ((
3) == (3) && (24) == (20) && (23) >= (0)))
6984 if (gtk_check_version(3, 20, 0) == nullptr)
6985 {
6986 GdkSeat* pSeat = gdk_display_get_default_seat(pDisplay);
6987 gdk_seat_grab(pSeat, gtk_widget_get_window(pWidget),
6988 GDK_SEAT_CAPABILITY_ALL, true, nullptr, nullptr, nullptr, nullptr);
6989 return;
6990 }
6991#endif
6992 //else older gtk3
6993 GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(pDisplay);
6994 GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
6995 GdkWindow* pWindow = gtk_widget_get_window(pWidget);
6996 guint32 nCurrentTime = gtk_get_current_event_time();
6997 gdk_device_grab(pPointer, pWindow, GDK_OWNERSHIP_NONE, true, GDK_ALL_EVENTS_MASK, nullptr, nCurrentTime);
6998 if (GdkDevice* pKeyboard = gdk_device_get_associated_device(pPointer))
6999 gdk_device_grab(pKeyboard, pWindow, GDK_OWNERSHIP_NONE, true, GDK_ALL_EVENTS_MASK, nullptr, nCurrentTime);
7000}
7001
7002void do_ungrab(GtkWidget* pWidget)
7003{
7004 GdkDisplay *pDisplay = gtk_widget_get_display(pWidget);
7005#if GTK_CHECK_VERSION(3, 20, 0)((3) > (3) || ((3) == (3) && (24) > (20)) || ((
3) == (3) && (24) == (20) && (23) >= (0)))
7006 if (gtk_check_version(3, 20, 0) == nullptr)
7007 {
7008 GdkSeat* pSeat = gdk_display_get_default_seat(pDisplay);
7009 gdk_seat_ungrab(pSeat);
7010 return;
7011 }
7012#endif
7013 //else older gtk3
7014 GdkDeviceManager* pDeviceManager = gdk_display_get_device_manager(pDisplay);
7015 GdkDevice* pPointer = gdk_device_manager_get_client_pointer(pDeviceManager);
7016 guint32 nCurrentTime = gtk_get_current_event_time();
7017 gdk_device_ungrab(pPointer, nCurrentTime);
7018 if (GdkDevice* pKeyboard = gdk_device_get_associated_device(pPointer))
7019 gdk_device_ungrab(pKeyboard, nCurrentTime);
7020}
7021
7022GtkPositionType show_menu_older_gtk(GtkWidget* pMenuButton, GtkWindow* pMenu)
7023{
7024 //place the toplevel just below its launcher button
7025 GtkWidget* pToplevel = gtk_widget_get_toplevel(pMenuButton);
7026 gint x, y, absx, absy;
7027 gtk_widget_translate_coordinates(pMenuButton, pToplevel, 0, 0, &x, &y);
7028 GdkWindow *pWindow = gtk_widget_get_window(pToplevel);
7029 gdk_window_get_position(pWindow, &absx, &absy);
7030
7031 x += absx;
7032 y += absy;
7033
7034 gint nButtonHeight = gtk_widget_get_allocated_height(pMenuButton);
7035 y += nButtonHeight;
7036
7037 gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
), pMenu);
7038 gtk_window_set_transient_for(pMenu, GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
);
7039
7040 gint nMenuWidth, nMenuHeight;
7041 gtk_widget_get_size_request(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
, &nMenuWidth, &nMenuHeight);
7042
7043 if (nMenuWidth == -1 || nMenuHeight == -1)
7044 {
7045 GtkRequisition req;
7046 gtk_widget_get_preferred_size(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
, nullptr, &req);
7047 if (nMenuWidth == -1)
7048 nMenuWidth = req.width;
7049 if (nMenuHeight == -1)
7050 nMenuHeight = req.height;
7051 }
7052
7053 bool bSwapForRTL = SwapForRTL(pMenuButton);
7054 if (bSwapForRTL)
7055 {
7056 gint nButtonWidth = gtk_widget_get_allocated_width(pMenuButton);
7057 x += nButtonWidth;
7058 x -= nMenuWidth;
7059 }
7060
7061 tools::Rectangle aWorkArea(::get_monitor_workarea(pMenuButton));
7062
7063 // shrink it a little, I find it reassuring to see a little margin with a
7064 // long menu to know the menu is fully on screen
7065 aWorkArea.AdjustTop(8);
7066 aWorkArea.AdjustBottom(-8);
7067 gint endx = x + nMenuWidth;
7068 if (endx > aWorkArea.Right())
7069 x -= endx - aWorkArea.Right();
7070 if (x < 0)
7071 x = 0;
7072
7073 GtkPositionType ePosUsed = GTK_POS_BOTTOM;
7074
7075 gint endy = y + nMenuHeight;
7076 gint nMissingBelow = endy - aWorkArea.Bottom();
7077 if (nMissingBelow > 0)
7078 {
7079 gint nNewY = y - (nButtonHeight + nMenuHeight);
7080 if (nNewY < aWorkArea.Top())
7081 {
7082 gint nMissingAbove = aWorkArea.Top() - nNewY;
7083 if (nMissingBelow <= nMissingAbove)
7084 nMenuHeight -= nMissingBelow;
7085 else
7086 {
7087 nMenuHeight -= nMissingAbove;
7088 y = aWorkArea.Top();
7089 ePosUsed = GTK_POS_TOP;
7090 }
7091 gtk_widget_set_size_request(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
, nMenuWidth, nMenuHeight);
7092 }
7093 else
7094 {
7095 y = nNewY;
7096 ePosUsed = GTK_POS_TOP;
7097 }
7098 }
7099
7100 gtk_window_move(pMenu, x, y);
7101
7102 return ePosUsed;
7103}
7104
7105bool show_menu_newer_gtk(GtkWidget* pComboBox, GtkWindow* pMenu)
7106{
7107 static auto window_move_to_rect = reinterpret_cast<void (*) (GdkWindow*, const GdkRectangle*, GdkGravity,
7108 GdkGravity, GdkAnchorHints, gint, gint)>(
7109 dlsym(nullptr, "gdk_window_move_to_rect"));
7110 if (!window_move_to_rect)
7111 return false;
7112
7113#if defined(GDK_WINDOWING_X11)
7114 // under wayland gdk_window_move_to_rect works great for me, but in my current
7115 // gtk 3.24 under X it leaves part of long menus outside the work area
7116 GdkDisplay *pDisplay = gtk_widget_get_display(pComboBox);
7117 if (DLSYM_GDK_IS_X11_DISPLAY(pDisplay))
7118 return false;
7119#endif
7120
7121 //place the toplevel just below its launcher button
7122 GtkWidget* pToplevel = gtk_widget_get_toplevel(pComboBox);
7123 gint x, y;
7124 gtk_widget_translate_coordinates(pComboBox, pToplevel, 0, 0, &x, &y);
7125
7126 gtk_widget_realize(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
);
7127 gtk_window_group_add_window(gtk_window_get_group(GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
), pMenu);
7128 gtk_window_set_transient_for(pMenu, GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
);
7129
7130 gint nComboWidth = gtk_widget_get_allocated_width(pComboBox);
7131 gint nComboHeight = gtk_widget_get_allocated_height(pComboBox);
7132
7133 bool bSwapForRTL = SwapForRTL(GTK_WIDGET(pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pComboBox)), ((gtk_widget_get_type ()))))))
);
7134
7135 GdkGravity rect_anchor = !bSwapForRTL ? GDK_GRAVITY_SOUTH_WEST : GDK_GRAVITY_SOUTH_EAST;
7136 GdkGravity menu_anchor = !bSwapForRTL ? GDK_GRAVITY_NORTH_WEST : GDK_GRAVITY_NORTH_EAST;
7137 GdkRectangle rect {x, y, nComboWidth, nComboHeight };
7138 GdkWindow* toplevel = gtk_widget_get_window(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
);
7139
7140 window_move_to_rect(toplevel, &rect, rect_anchor, menu_anchor,
7141 static_cast<GdkAnchorHints>(GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_RESIZE_Y |
7142 GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_RESIZE_X),
7143 0, 0);
7144
7145 return true;
7146}
7147
7148GtkPositionType show_menu(GtkWidget* pMenuButton, GtkWindow* pMenu)
7149{
7150 // we only use ePosUsed in the replacement-for-X-popover case of a
7151 // MenuButton, so we only need it when show_menu_older_gtk is used
7152 GtkPositionType ePosUsed = GTK_POS_BOTTOM;
7153
7154 // tdf#120764 It isn't allowed under wayland to have two visible popups that share
7155 // the same top level parent. The problem is that since gtk 3.24 tooltips are also
7156 // implemented as popups, which means that we cannot show any popup if there is a
7157 // visible tooltip.
7158 GtkWidget* pParent = gtk_widget_get_toplevel(pMenuButton);
7159 GtkSalFrame* pFrame = pParent ? GtkSalFrame::getFromWindow(pParent) : nullptr;
7160 if (pFrame)
7161 {
7162 // hide any current tooltip
7163 pFrame->HideTooltip();
7164 // don't allow any more to appear until menu is dismissed
7165 pFrame->BlockTooltip();
7166 }
7167
7168 // try with gdk_window_move_to_rect, but if that's not available, try without
7169 if (!show_menu_newer_gtk(pMenuButton, pMenu))
7170 ePosUsed = show_menu_older_gtk(pMenuButton, pMenu);
7171 gtk_widget_show_all(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
);
7172 gtk_widget_grab_focus(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
);
7173 do_grab(GTK_WIDGET(pMenu)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenu)), ((gtk_widget_get_type ()))))))
);
7174
7175 return ePosUsed;
7176}
7177
7178class GtkInstanceMenuButton : public GtkInstanceToggleButton, public MenuHelper, public virtual weld::MenuButton
7179{
7180private:
7181 GtkMenuButton* m_pMenuButton;
7182 GtkBox* m_pBox;
7183 GtkImage* m_pImage;
7184 GtkWidget* m_pLabel;
7185 //popover cannot escape dialog under X so stick up own window instead
7186 GtkWindow* m_pMenuHack;
7187 //when doing so, if it's a toolbar menubutton align the menu to the full toolitem
7188 GtkWidget* m_pMenuHackAlign;
7189 GtkWidget* m_pPopover;
7190 gulong m_nSignalId;
7191
7192 static void signalToggled(GtkWidget*, gpointer widget)
7193 {
7194 GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget);
7195 SolarMutexGuard aGuard;
7196 pThis->toggle_menu();
7197 }
7198
7199 void toggle_menu()
7200 {
7201 if (!m_pMenuHack)
7202 return;
7203 if (!get_active())
7204 {
7205 do_ungrab(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
);
7206
7207 gtk_widget_hide(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
);
7208 //put contents back from where the came from
7209 GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pMenuHack)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((m_pMenuHack
)), ((gtk_bin_get_type ()))))))
);
7210 g_object_ref(pChild);
7211 gtk_container_remove(GTK_CONTAINER(m_pMenuHack)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuHack)), ((gtk_container_get_type ()))))))
, pChild);
7212 gtk_container_add(GTK_CONTAINER(m_pPopover)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pPopover)), ((gtk_container_get_type ()))))))
, pChild);
7213 g_object_unref(pChild);
7214
7215 // so gdk_window_move_to_rect will work again the next time
7216 gtk_widget_unrealize(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
);
7217
7218 gtk_widget_set_size_request(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
, -1, -1);
7219
7220 // undo show_menu tooltip blocking
7221 GtkWidget* pParent = gtk_widget_get_toplevel(GTK_WIDGET(m_pMenuButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuButton)), ((gtk_widget_get_type ()))))))
);
7222 GtkSalFrame* pFrame = pParent ? GtkSalFrame::getFromWindow(pParent) : nullptr;
7223 if (pFrame)
7224 pFrame->UnblockTooltip();
7225 }
7226 else
7227 {
7228 //set border width
7229 gtk_container_set_border_width(GTK_CONTAINER(m_pMenuHack)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuHack)), ((gtk_container_get_type ()))))))
, gtk_container_get_border_width(GTK_CONTAINER(m_pPopover)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pPopover)), ((gtk_container_get_type ()))))))
));
7230
7231 //steal popover contents and smuggle into toplevel display window
7232 GtkWidget* pChild = gtk_bin_get_child(GTK_BIN(m_pPopover)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((m_pPopover
)), ((gtk_bin_get_type ()))))))
);
7233 g_object_ref(pChild);
7234 gtk_container_remove(GTK_CONTAINER(m_pPopover)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pPopover)), ((gtk_container_get_type ()))))))
, pChild);
7235 gtk_container_add(GTK_CONTAINER(m_pMenuHack)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuHack)), ((gtk_container_get_type ()))))))
, pChild);
7236 g_object_unref(pChild);
7237
7238 GtkPositionType ePosUsed = show_menu(m_pMenuHackAlign ? m_pMenuHackAlign : GTK_WIDGET(m_pMenuButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuButton)), ((gtk_widget_get_type ()))))))
, m_pMenuHack);
7239 // tdf#132540 keep the placeholder popover on this same side as the replacement menu
7240 gtk_popover_set_position(gtk_menu_button_get_popover(m_pMenuButton), ePosUsed);
7241 }
7242 }
7243
7244 static void signalGrabBroken(GtkWidget*, GdkEventGrabBroken *pEvent, gpointer widget)
7245 {
7246 GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget);
7247 pThis->grab_broken(pEvent);
7248 }
7249
7250 void grab_broken(const GdkEventGrabBroken *event)
7251 {
7252 if (event->grab_window == nullptr)
7253 {
7254 set_active(false);
7255 }
7256 else
7257 {
7258 //try and regrab, so when we lose the grab to the menu of the color palette
7259 //combobox we regain it so the color palette doesn't itself disappear on next
7260 //click on the color palette combobox
7261 do_grab(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
);
7262 }
7263 }
7264
7265 static gboolean signalButtonRelease(GtkWidget* pWidget, GdkEventButton* pEvent, gpointer widget)
7266 {
7267 GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget);
7268 return pThis->button_release(pWidget, pEvent);
7269 }
7270
7271 bool button_release(GtkWidget* pWidget, GdkEventButton* pEvent)
7272 {
7273 //we want to pop down if the button was released outside our popup
7274 gdouble x = pEvent->x_root;
7275 gdouble y = pEvent->y_root;
7276 gint xoffset, yoffset;
7277 gdk_window_get_root_origin(gtk_widget_get_window(pWidget), &xoffset, &yoffset);
7278
7279 GtkAllocation alloc;
7280 gtk_widget_get_allocation(pWidget, &alloc);
7281 xoffset += alloc.x;
7282 yoffset += alloc.y;
7283
7284 gtk_widget_get_allocation(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
, &alloc);
7285 gint x1 = alloc.x + xoffset;
7286 gint y1 = alloc.y + yoffset;
7287 gint x2 = x1 + alloc.width;
7288 gint y2 = y1 + alloc.height;
7289
7290 if (x > x1 && x < x2 && y > y1 && y < y2)
7291 return false;
7292
7293 set_active(false);
7294
7295 return false;
7296 }
7297
7298 static gboolean keyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
7299 {
7300 GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget);
7301 return pThis->key_press(pEvent);
7302 }
7303
7304 bool key_press(const GdkEventKey* pEvent)
7305 {
7306 if (pEvent->keyval == GDK_KEY_Escape0xff1b)
7307 {
7308 set_active(false);
7309 return true;
7310 }
7311 return false;
7312 }
7313
7314 void ensure_image_widget()
7315 {
7316 if (!m_pImage)
7317 {
7318 m_pImage = GTK_IMAGE(gtk_image_new())((((GtkImage*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_image_new())), ((gtk_image_get_type ()))))))
;
7319 gtk_box_pack_start(m_pBox, GTK_WIDGET(m_pImage)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pImage)), ((gtk_widget_get_type ()))))))
, false, false, 0);
7320 gtk_box_reorder_child(m_pBox, GTK_WIDGET(m_pImage)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pImage)), ((gtk_widget_get_type ()))))))
, 0);
7321 gtk_widget_show(GTK_WIDGET(m_pImage)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pImage)), ((gtk_widget_get_type ()))))))
);
7322 }
7323 }
7324
7325public:
7326 GtkInstanceMenuButton(GtkMenuButton* pMenuButton, GtkWidget* pMenuAlign, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
7327 : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pMenuButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pMenuButton)), ((gtk_toggle_button_get_type ()))))))
, pBuilder, bTakeOwnership)
7328 , MenuHelper(gtk_menu_button_get_popup(pMenuButton), false)
7329 , m_pMenuButton(pMenuButton)
7330 , m_pImage(nullptr)
7331 , m_pMenuHack(nullptr)
7332 , m_pMenuHackAlign(pMenuAlign)
7333 , m_pPopover(nullptr)
7334 , m_nSignalId(0)
7335 {
7336 m_pLabel = gtk_bin_get_child(GTK_BIN(m_pMenuButton)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((m_pMenuButton
)), ((gtk_bin_get_type ()))))))
);
7337 //do it "manually" so we can have the dropdown image in GtkMenuButtons shown
7338 //on the right at the same time as this image is shown on the left
7339 g_object_ref(m_pLabel);
7340 gtk_container_remove(GTK_CONTAINER(m_pMenuButton)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuButton)), ((gtk_container_get_type ()))))))
, m_pLabel);
7341
7342 gint nImageSpacing(2);
7343 GtkStyleContext *pContext = gtk_widget_get_style_context(GTK_WIDGET(m_pMenuButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuButton)), ((gtk_widget_get_type ()))))))
);
7344 gtk_style_context_get_style(pContext, "image-spacing", &nImageSpacing, nullptr);
7345 m_pBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, nImageSpacing))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_box_new
(GTK_ORIENTATION_HORIZONTAL, nImageSpacing))), ((gtk_box_get_type
()))))))
;
7346
7347 gtk_box_pack_start(m_pBox, m_pLabel, true, true, 0);
7348 g_object_unref(m_pLabel);
7349
7350 if (gtk_toggle_button_get_mode(GTK_TOGGLE_BUTTON(m_pMenuButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuButton)), ((gtk_toggle_button_get_type ()))))))
))
7351 gtk_box_pack_end(m_pBox, gtk_image_new_from_icon_name("pan-down-symbolic", GTK_ICON_SIZE_BUTTON), false, false, 0);
7352
7353 gtk_container_add(GTK_CONTAINER(m_pMenuButton)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuButton)), ((gtk_container_get_type ()))))))
, GTK_WIDGET(m_pBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pBox)), ((gtk_widget_get_type ()))))))
);
7354 gtk_widget_show_all(GTK_WIDGET(m_pBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pBox)), ((gtk_widget_get_type ()))))))
);
7355 }
7356
7357 virtual void set_size_request(int nWidth, int nHeight) override
7358 {
7359 // tweak the label to get a narrower size to stick
7360 if (GTK_IS_LABEL(m_pLabel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pLabel)); GType __t = ((gtk_label_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7361 gtk_label_set_ellipsize(GTK_LABEL(m_pLabel)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pLabel)), ((gtk_label_get_type ()))))))
, PANGO_ELLIPSIZE_MIDDLE);
7362 gtk_widget_set_size_request(m_pWidget, nWidth, nHeight);
7363 }
7364
7365 virtual void set_label(const OUString& rText) override
7366 {
7367 ::set_label(GTK_LABEL(m_pLabel)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pLabel)), ((gtk_label_get_type ()))))))
, rText);
7368 }
7369
7370 virtual OUString get_label() const override
7371 {
7372 return ::get_label(GTK_LABEL(m_pLabel)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pLabel)), ((gtk_label_get_type ()))))))
);
7373 }
7374
7375 virtual void set_image(VirtualDevice* pDevice) override
7376 {
7377 ensure_image_widget();
7378 if (pDevice)
7379 {
7380 if (gtk_check_version(3, 20, 0) == nullptr)
7381 gtk_image_set_from_surface(m_pImage, get_underlying_cairo_surface(*pDevice));
7382 else
7383 {
7384 GdkPixbuf* pixbuf = getPixbuf(*pDevice);
7385 gtk_image_set_from_pixbuf(m_pImage, pixbuf);
7386 g_object_unref(pixbuf);
7387 }
7388 }
7389 else
7390 gtk_image_set_from_surface(m_pImage, nullptr);
7391 }
7392
7393 virtual void set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage) override
7394 {
7395 ensure_image_widget();
7396 GdkPixbuf* pixbuf = getPixbuf(rImage);
7397 if (pixbuf)
7398 {
7399 gtk_image_set_from_pixbuf(m_pImage, pixbuf);
7400 g_object_unref(pixbuf);
7401 }
7402 else
7403 gtk_image_set_from_surface(m_pImage, nullptr);
7404 }
7405
7406 virtual void insert_item(int pos, const OUString& rId, const OUString& rStr,
7407 const OUString* pIconName, VirtualDevice* pImageSurface, TriState eCheckRadioFalse) override
7408 {
7409 MenuHelper::insert_item(pos, rId, rStr, pIconName, pImageSurface, eCheckRadioFalse);
7410 }
7411
7412 virtual void insert_separator(int pos, const OUString& rId) override
7413 {
7414 MenuHelper::insert_separator(pos, rId);
7415 }
7416
7417 virtual void remove_item(const OString& rId) override
7418 {
7419 MenuHelper::remove_item(rId);
7420 }
7421
7422 virtual void clear() override
7423 {
7424 clear_items();
7425 }
7426
7427 virtual void set_item_active(const OString& rIdent, bool bActive) override
7428 {
7429 MenuHelper::set_item_active(rIdent, bActive);
7430 }
7431
7432 virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) override
7433 {
7434 MenuHelper::set_item_sensitive(rIdent, bSensitive);
7435 }
7436
7437 virtual void set_item_label(const OString& rIdent, const OUString& rLabel) override
7438 {
7439 MenuHelper::set_item_label(rIdent, rLabel);
7440 }
7441
7442 virtual OUString get_item_label(const OString& rIdent) const override
7443 {
7444 return MenuHelper::get_item_label(rIdent);
7445 }
7446
7447 virtual void set_item_visible(const OString& rIdent, bool bVisible) override
7448 {
7449 MenuHelper::set_item_visible(rIdent, bVisible);
7450 }
7451
7452 virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override
7453 {
7454 MenuHelper::set_item_help_id(rIdent, rHelpId);
7455 }
7456
7457 virtual OString get_item_help_id(const OString& rIdent) const override
7458 {
7459 return MenuHelper::get_item_help_id(rIdent);
7460 }
7461
7462 virtual void signal_activate(GtkMenuItem* pItem) override
7463 {
7464 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
);
7465 signal_selected(OString(pStr, pStr ? strlen(pStr) : 0));
7466 }
7467
7468 virtual void set_popover(weld::Widget* pPopover) override
7469 {
7470 GtkInstanceWidget* pPopoverWidget = dynamic_cast<GtkInstanceWidget*>(pPopover);
7471 m_pPopover = pPopoverWidget ? pPopoverWidget->getWidget() : nullptr;
7472
7473#if defined(GDK_WINDOWING_X11)
7474 if (!m_pMenuHack)
7475 {
7476 //under wayland a Popover will work to "escape" the parent dialog, not
7477 //so under X, so come up with this hack to use a raw GtkWindow
7478 GdkDisplay *pDisplay = gtk_widget_get_display(m_pWidget);
7479 if (DLSYM_GDK_IS_X11_DISPLAY(pDisplay))
7480 {
7481 m_pMenuHack = GTK_WINDOW(gtk_window_new(GTK_WINDOW_POPUP))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_window_new(GTK_WINDOW_POPUP))), ((gtk_window_get_type ()
))))))
;
7482 gtk_window_set_type_hint(m_pMenuHack, GDK_WINDOW_TYPE_HINT_COMBO);
7483 gtk_window_set_modal(m_pMenuHack, true);
7484 gtk_window_set_resizable(m_pMenuHack, false);
7485 m_nSignalId = g_signal_connect(GTK_TOGGLE_BUTTON(m_pMenuButton), "toggled", G_CALLBACK(signalToggled), this)g_signal_connect_data ((((((GtkToggleButton*) g_type_check_instance_cast
((GTypeInstance*) ((m_pMenuButton)), ((gtk_toggle_button_get_type
()))))))), ("toggled"), (((GCallback) (signalToggled))), (this
), __null, (GConnectFlags) 0)
;
7486 g_signal_connect(m_pMenuHack, "grab-broken-event", G_CALLBACK(signalGrabBroken), this)g_signal_connect_data ((m_pMenuHack), ("grab-broken-event"), (
((GCallback) (signalGrabBroken))), (this), __null, (GConnectFlags
) 0)
;
7487 g_signal_connect(m_pMenuHack, "button-release-event", G_CALLBACK(signalButtonRelease), this)g_signal_connect_data ((m_pMenuHack), ("button-release-event"
), (((GCallback) (signalButtonRelease))), (this), __null, (GConnectFlags
) 0)
;
7488 g_signal_connect(m_pMenuHack, "key-press-event", G_CALLBACK(keyPress), this)g_signal_connect_data ((m_pMenuHack), ("key-press-event"), ((
(GCallback) (keyPress))), (this), __null, (GConnectFlags) 0)
;
7489 }
7490 }
7491#endif
7492
7493 if (m_pMenuHack)
7494 {
7495 GtkWidget* pPlaceHolder = gtk_popover_new(GTK_WIDGET(m_pMenuButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuButton)), ((gtk_widget_get_type ()))))))
);
7496 gtk_popover_set_transitions_enabled(GTK_POPOVER(pPlaceHolder)((((GtkPopover*) g_type_check_instance_cast ((GTypeInstance*)
((pPlaceHolder)), ((gtk_popover_get_type ()))))))
, false);
7497
7498 // tdf#132540 theme the unwanted popover into invisibility
7499 GtkStyleContext *pPopoverContext = gtk_widget_get_style_context(pPlaceHolder);
7500 GtkCssProvider *pProvider = gtk_css_provider_new();
7501 static const gchar data[] = "popover { box-shadow: none; padding: 0 0 0 0; margin: 0 0 0 0; border-image: none; border-image-width: 0 0 0 0; background-image: none; background-color: transparent; border-radius: 0 0 0 0; border-width: 0 0 0 0; border-style: none; border-color: transparent; opacity: 0; min-height: 0; min-width: 0; }";
7502 gtk_css_provider_load_from_data(pProvider, data, -1, nullptr);
7503 gtk_style_context_add_provider(pPopoverContext, GTK_STYLE_PROVIDER(pProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((pProvider)), ((gtk_style_provider_get_type ()))))))
,
7504 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
7505
7506 gtk_menu_button_set_popover(m_pMenuButton, pPlaceHolder);
7507 }
7508 else
7509 {
7510 gtk_menu_button_set_popover(m_pMenuButton, m_pPopover);
7511 if (m_pPopover)
7512 gtk_widget_show_all(m_pPopover);
7513 }
7514 }
7515
7516 void set_menu(weld::Menu* pMenu);
7517
7518 virtual ~GtkInstanceMenuButton() override
7519 {
7520 if (m_pMenuHack)
7521 {
7522 g_signal_handler_disconnect(m_pMenuButton, m_nSignalId);
7523 gtk_menu_button_set_popover(m_pMenuButton, nullptr);
7524 gtk_widget_destroy(GTK_WIDGET(m_pMenuHack)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuHack)), ((gtk_widget_get_type ()))))))
);
7525 }
7526 }
7527};
7528
7529class GtkInstanceMenu : public MenuHelper, public virtual weld::Menu
7530{
7531protected:
7532 std::vector<GtkMenuItem*> m_aExtraItems;
7533 OString m_sActivated;
7534 MenuHelper* m_pTopLevelMenuHelper;
7535
7536private:
7537 virtual void signal_activate(GtkMenuItem* pItem) override
7538 {
7539 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
);
7540 m_sActivated = OString(pStr, pStr ? strlen(pStr) : 0);
7541 weld::Menu::signal_activate(m_sActivated);
7542 }
7543
7544 void clear_extras()
7545 {
7546 if (m_aExtraItems.empty())
7547 return;
7548 if (m_pTopLevelMenuHelper)
7549 {
7550 for (auto a : m_aExtraItems)
7551 m_pTopLevelMenuHelper->remove_from_map(a);
7552 }
7553 m_aExtraItems.clear();
7554 }
7555
7556public:
7557 GtkInstanceMenu(GtkMenu* pMenu, bool bTakeOwnership)
7558 : MenuHelper(pMenu, bTakeOwnership)
7559 , m_pTopLevelMenuHelper(nullptr)
7560 {
7561 g_object_set_data(G_OBJECT(m_pMenu)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pMenu)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceMenu", this);
7562 // tdf#122527 if we're welding a submenu of a menu of a MenuButton,
7563 // then find that MenuButton parent so that when adding items to this
7564 // menu we can inform the MenuButton of their addition
7565 GtkMenu* pTopLevelMenu = pMenu;
7566 while (true)
7567 {
7568 GtkWidget* pAttached = gtk_menu_get_attach_widget(pTopLevelMenu);
7569 if (!pAttached || !GTK_IS_MENU_ITEM(pAttached)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pAttached)); GType __t = ((gtk_menu_item_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7570 break;
7571 GtkWidget* pParent = gtk_widget_get_parent(pAttached);
7572 if (!pParent || !GTK_IS_MENU(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_menu_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7573 break;
7574 pTopLevelMenu = GTK_MENU(pParent)((((GtkMenu*) g_type_check_instance_cast ((GTypeInstance*) ((
pParent)), ((gtk_menu_get_type ()))))))
;
7575 }
7576 if (pTopLevelMenu == pMenu)
7577 return;
7578
7579 // maybe the toplevel is a menubutton
7580 GtkWidget* pAttached = gtk_menu_get_attach_widget(pTopLevelMenu);
7581 if (pAttached && GTK_IS_MENU_BUTTON(pAttached)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pAttached)); GType __t = ((gtk_menu_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7582 {
7583 void* pData = g_object_get_data(G_OBJECT(pAttached)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pAttached)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceButton");
7584 m_pTopLevelMenuHelper = dynamic_cast<GtkInstanceMenuButton*>(static_cast<GtkInstanceButton*>(pData));
7585 }
7586 // or maybe a menu
7587 if (!m_pTopLevelMenuHelper)
7588 {
7589 void* pData = g_object_get_data(G_OBJECT(pTopLevelMenu)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pTopLevelMenu)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceMenu");
7590 m_pTopLevelMenuHelper = static_cast<GtkInstanceMenu*>(pData);
7591 }
7592 }
7593
7594 virtual OString popup_at_rect(weld::Widget* pParent, const tools::Rectangle &rRect) override
7595 {
7596 m_sActivated.clear();
7597
7598 GtkInstanceWidget* pGtkWidget = dynamic_cast<GtkInstanceWidget*>(pParent);
7599 assert(pGtkWidget)(static_cast <bool> (pGtkWidget) ? void (0) : __assert_fail
("pGtkWidget", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 7599, __extension__ __PRETTY_FUNCTION__))
;
7600
7601 GtkWidget* pWidget = pGtkWidget->getWidget();
7602 gtk_menu_attach_to_widget(m_pMenu, pWidget, nullptr);
7603
7604 //run in a sub main loop because we need to keep vcl PopupMenu alive to use
7605 //it during DispatchCommand, returning now to the outer loop causes the
7606 //launching PopupMenu to be destroyed, instead run the subloop here
7607 //until the gtk menu is destroyed
7608 GMainLoop* pLoop = g_main_loop_new(nullptr, true);
7609 gulong nSignalId = g_signal_connect_swapped(G_OBJECT(m_pMenu), "deactivate", G_CALLBACK(g_main_loop_quit), pLoop)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((m_pMenu)), (((GType) ((20) << (2))
))))))), ("deactivate"), (((GCallback) (g_main_loop_quit))), (
pLoop), __null, G_CONNECT_SWAPPED)
;
7610
7611#if GTK_CHECK_VERSION(3,22,0)((3) > (3) || ((3) == (3) && (24) > (22)) || ((
3) == (3) && (24) == (22) && (23) >= (0)))
7612 if (gtk_check_version(3, 22, 0) == nullptr)
7613 {
7614 GdkRectangle aRect{static_cast<int>(rRect.Left()), static_cast<int>(rRect.Top()),
7615 static_cast<int>(rRect.GetWidth()), static_cast<int>(rRect.GetHeight())};
7616 if (SwapForRTL(pWidget))
7617 aRect.x = gtk_widget_get_allocated_width(pWidget) - aRect.width - 1 - aRect.x;
7618
7619 // Send a keyboard event through gtk_main_do_event to toggle any active tooltip offs
7620 // before trying to launch the menu
7621 // https://gitlab.gnome.org/GNOME/gtk/issues/1785
7622 GdkEvent *pKeyEvent = GtkSalFrame::makeFakeKeyPress(pWidget);
7623 gtk_main_do_event(pKeyEvent);
7624
7625 GdkEvent *pTriggerEvent = gtk_get_current_event();
7626 if (!pTriggerEvent)
7627 pTriggerEvent = pKeyEvent;
7628
7629 gtk_menu_popup_at_rect(m_pMenu, gtk_widget_get_window(pWidget), &aRect, GDK_GRAVITY_NORTH_WEST, GDK_GRAVITY_NORTH_WEST, pTriggerEvent);
7630
7631 gdk_event_free(pKeyEvent);
7632 }
7633 else
7634#else
7635 (void) rRect;
7636#endif
7637 {
7638 guint nButton;
7639 guint32 nTime;
7640
7641 //typically there is an event, and we can then distinguish if this was
7642 //launched from the keyboard (gets auto-mnemoniced) or the mouse (which
7643 //doesn't)
7644 GdkEvent *pEvent = gtk_get_current_event();
7645 if (pEvent)
7646 {
7647 gdk_event_get_button(pEvent, &nButton);
7648 nTime = gdk_event_get_time(pEvent);
7649 }
7650 else
7651 {
7652 nButton = 0;
7653 nTime = GtkSalFrame::GetLastInputEventTime();
7654 }
7655
7656 gtk_menu_popup(m_pMenu, nullptr, nullptr, nullptr, nullptr, nButton, nTime);
7657 }
7658
7659 if (g_main_loop_is_running(pLoop))
7660 {
7661 gdk_threads_leave();
7662 g_main_loop_run(pLoop);
7663 gdk_threads_enter();
7664 }
7665 g_main_loop_unref(pLoop);
7666 g_signal_handler_disconnect(m_pMenu, nSignalId);
7667 gtk_menu_detach(m_pMenu);
7668
7669 return m_sActivated;
7670 }
7671
7672 virtual void set_sensitive(const OString& rIdent, bool bSensitive) override
7673 {
7674 set_item_sensitive(rIdent, bSensitive);
7675 }
7676
7677 virtual void set_active(const OString& rIdent, bool bActive) override
7678 {
7679 set_item_active(rIdent, bActive);
7680 }
7681
7682 virtual bool get_active(const OString& rIdent) const override
7683 {
7684 return get_item_active(rIdent);
7685 }
7686
7687 virtual void set_visible(const OString& rIdent, bool bShow) override
7688 {
7689 set_item_visible(rIdent, bShow);
7690 }
7691
7692 virtual void set_label(const OString& rIdent, const OUString& rLabel) override
7693 {
7694 set_item_label(rIdent, rLabel);
7695 }
7696
7697 virtual OUString get_label(const OString& rIdent) const override
7698 {
7699 return get_item_label(rIdent);
7700 }
7701
7702 virtual void insert_separator(int pos, const OUString& rId) override
7703 {
7704 MenuHelper::insert_separator(pos, rId);
7705 }
7706
7707 virtual void clear() override
7708 {
7709 clear_extras();
7710 clear_items();
7711 }
7712
7713 virtual void insert(int pos, const OUString& rId, const OUString& rStr,
7714 const OUString* pIconName, VirtualDevice* pImageSurface,
7715 TriState eCheckRadioFalse) override
7716 {
7717 GtkWidget* pImage = nullptr;
7718 if (pIconName)
7719 {
7720 if (GdkPixbuf* pixbuf = load_icon_by_name(*pIconName))
7721 {
7722 pImage = gtk_image_new_from_pixbuf(pixbuf);
7723 g_object_unref(pixbuf);
7724 }
7725 }
7726 else if (pImageSurface)
7727 {
7728 pImage = image_new_from_virtual_device(*pImageSurface);
7729 }
7730
7731 GtkWidget *pItem;
7732 if (pImage)
7733 {
7734 GtkWidget *pBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
7735 GtkWidget *pLabel = gtk_label_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr());
7736 pItem = eCheckRadioFalse != TRISTATE_INDET ? gtk_check_menu_item_new() : gtk_menu_item_new();
7737 gtk_container_add(GTK_CONTAINER(pBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pBox)), ((gtk_container_get_type ()))))))
, pImage);
7738 gtk_container_add(GTK_CONTAINER(pBox)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pBox)), ((gtk_container_get_type ()))))))
, pLabel);
7739 gtk_container_add(GTK_CONTAINER(pItem)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_container_get_type ()))))))
, pBox);
7740 gtk_widget_show_all(pItem);
7741 }
7742 else
7743 {
7744 pItem = eCheckRadioFalse != TRISTATE_INDET ? gtk_check_menu_item_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr())
7745 : gtk_menu_item_new_with_mnemonic(MapToGtkAccelerator(rStr).getStr());
7746 }
7747
7748 if (eCheckRadioFalse == TRISTATE_FALSE)
7749 gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(pItem)((((GtkCheckMenuItem*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_check_menu_item_get_type ()))))))
, true);
7750
7751 gtk_buildable_set_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
, OUStringToOString(rId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
7752 gtk_menu_shell_append(GTK_MENU_SHELL(m_pMenu)((((GtkMenuShell*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenu)), ((gtk_menu_shell_get_type ()))))))
, pItem);
7753 gtk_widget_show(pItem);
7754 GtkMenuItem* pMenuItem = GTK_MENU_ITEM(pItem)((((GtkMenuItem*) g_type_check_instance_cast ((GTypeInstance*
) ((pItem)), ((gtk_menu_item_get_type ()))))))
;
7755 m_aExtraItems.push_back(pMenuItem);
7756 add_to_map(pMenuItem);
7757 if (m_pTopLevelMenuHelper)
7758 m_pTopLevelMenuHelper->add_to_map(pMenuItem);
7759 if (pos != -1)
7760 gtk_menu_reorder_child(m_pMenu, pItem, pos);
7761 }
7762
7763 virtual int n_children() const override
7764 {
7765 GList* pChildren = gtk_container_get_children(GTK_CONTAINER(m_pMenu)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenu)), ((gtk_container_get_type ()))))))
);
7766 int nLen = g_list_length(pChildren);
7767 g_list_free(pChildren);
7768 return nLen;
7769 }
7770
7771 void remove(const OString& rIdent) override
7772 {
7773 if (!m_aExtraItems.empty())
7774 {
7775 GtkMenuItem* pMenuItem = m_aMap[rIdent];
7776 auto iter = std::find(m_aExtraItems.begin(), m_aExtraItems.end(), pMenuItem);
7777 if (iter != m_aExtraItems.end())
7778 {
7779 m_pTopLevelMenuHelper->remove_from_map(pMenuItem);
7780 m_aExtraItems.erase(iter);
7781 }
7782 }
7783 MenuHelper::remove_item(rIdent);
7784 }
7785
7786 virtual ~GtkInstanceMenu() override
7787 {
7788 clear_extras();
7789 g_object_steal_data(G_OBJECT(m_pMenu)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pMenu)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceMenu");
7790 }
7791};
7792
7793 vcl::ImageType GtkToVcl(GtkIconSize eSize)
7794 {
7795 vcl::ImageType eRet;
7796 switch (eSize)
7797 {
7798 case GTK_ICON_SIZE_MENU:
7799 case GTK_ICON_SIZE_SMALL_TOOLBAR:
7800 case GTK_ICON_SIZE_BUTTON:
7801 eRet = vcl::ImageType::Size16;
7802 break;
7803 case GTK_ICON_SIZE_LARGE_TOOLBAR:
7804 eRet = vcl::ImageType::Size26;
7805 break;
7806 case GTK_ICON_SIZE_DND:
7807 case GTK_ICON_SIZE_DIALOG:
7808 eRet = vcl::ImageType::Size32;
7809 break;
7810 default:
7811 case GTK_ICON_SIZE_INVALID:
7812 eRet = vcl::ImageType::Small;
7813 break;
7814 }
7815 return eRet;
7816 }
7817
7818 GtkIconSize VclToGtk(vcl::ImageType eSize)
7819 {
7820 GtkIconSize eRet;
7821 switch (eSize)
7822 {
7823 case vcl::ImageType::Size16:
7824 eRet = GTK_ICON_SIZE_SMALL_TOOLBAR;
7825 break;
7826 case vcl::ImageType::Size26:
7827 eRet = GTK_ICON_SIZE_LARGE_TOOLBAR;
7828 break;
7829 case vcl::ImageType::Size32:
7830 eRet = GTK_ICON_SIZE_DIALOG;
7831 break;
7832 default:
7833 O3TL_UNREACHABLEdo { (static_cast <bool> (false) ? void (0) : __assert_fail
("false", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 7833, __extension__ __PRETTY_FUNCTION__)); __builtin_unreachable
(); } while (false)
;
7834 }
7835 return eRet;
7836 }
7837}
7838
7839void GtkInstanceMenuButton::set_menu(weld::Menu* pMenu)
7840{
7841 GtkInstanceMenu* pPopoverWidget = dynamic_cast<GtkInstanceMenu*>(pMenu);
7842 m_pPopover = nullptr;
7843 GtkWidget* pMenuWidget = GTK_WIDGET(pPopoverWidget ? pPopoverWidget->getMenu() : nullptr)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pPopoverWidget ? pPopoverWidget->getMenu() : nullptr)), (
(gtk_widget_get_type ()))))))
;
7844 gtk_menu_button_set_popup(m_pMenuButton, pMenuWidget);
7845}
7846
7847namespace {
7848
7849class GtkInstanceToolbar : public GtkInstanceWidget, public virtual weld::Toolbar
7850{
7851private:
7852 GtkToolbar* m_pToolbar;
7853 GtkCssProvider *m_pMenuButtonProvider;
7854
7855 std::map<OString, GtkToolItem*> m_aMap;
7856 std::map<OString, std::unique_ptr<GtkInstanceMenuButton>> m_aMenuButtonMap;
7857
7858 // at the time of writing there is no gtk_menu_tool_button_set_popover available
7859 // though there will be in the future
7860 // https://gitlab.gnome.org/GNOME/gtk/commit/03e30431a8af9a947a0c4ccab545f24da16bfe17?w=1
7861 static void find_menu_button(GtkWidget *pWidget, gpointer user_data)
7862 {
7863 if (g_strcmp0(gtk_widget_get_name(pWidget), "GtkMenuButton") == 0)
7864 {
7865 GtkWidget **ppToggleButton = static_cast<GtkWidget**>(user_data);
7866 *ppToggleButton = pWidget;
7867 }
7868 else if (GTK_IS_CONTAINER(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7869 gtk_container_forall(GTK_CONTAINER(pWidget)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_container_get_type ()))))))
, find_menu_button, user_data);
7870 }
7871
7872 static void find_menupeer_button(GtkWidget *pWidget, gpointer user_data)
7873 {
7874 if (g_strcmp0(gtk_widget_get_name(pWidget), "GtkButton") == 0)
7875 {
7876 GtkWidget **ppButton = static_cast<GtkWidget**>(user_data);
7877 *ppButton = pWidget;
7878 }
7879 else if (GTK_IS_CONTAINER(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7880 gtk_container_forall(GTK_CONTAINER(pWidget)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_container_get_type ()))))))
, find_menupeer_button, user_data);
7881 }
7882
7883 static void collect(GtkWidget* pItem, gpointer widget)
7884 {
7885 if (GTK_IS_TOOL_ITEM(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_item_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7886 {
7887 GtkToolItem* pToolItem = GTK_TOOL_ITEM(pItem)((((GtkToolItem*) g_type_check_instance_cast ((GTypeInstance*
) ((pItem)), ((gtk_tool_item_get_type ()))))))
;
7888 GtkInstanceToolbar* pThis = static_cast<GtkInstanceToolbar*>(widget);
7889
7890 GtkMenuButton* pMenuButton = nullptr;
7891 if (GTK_IS_MENU_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_menu_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7892 find_menu_button(pItem, &pMenuButton);
7893
7894 pThis->add_to_map(pToolItem, pMenuButton);
7895 }
7896 }
7897
7898 void add_to_map(GtkToolItem* pToolItem, GtkMenuButton* pMenuButton)
7899 {
7900 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pToolItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pToolItem)), ((gtk_buildable_get_type ()))))))
);
7901 OString id(pStr, pStr ? strlen(pStr) : 0);
7902 m_aMap[id] = pToolItem;
7903 if (pMenuButton)
7904 {
7905 m_aMenuButtonMap[id] = std::make_unique<GtkInstanceMenuButton>(pMenuButton, GTK_WIDGET(pToolItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pToolItem)), ((gtk_widget_get_type ()))))))
, m_pBuilder, false);
7906 // so that, e.g. with focus initially in writer main document then
7907 // after clicking the heading menu in the writer navigator focus is
7908 // left in the main document and not in the toolbar
7909 gtk_button_set_focus_on_click(GTK_BUTTON(pMenuButton)((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenuButton)), ((gtk_button_get_type ()))))))
, false);
7910 g_signal_connect(pMenuButton, "toggled", G_CALLBACK(signalItemToggled), this)g_signal_connect_data ((pMenuButton), ("toggled"), (((GCallback
) (signalItemToggled))), (this), __null, (GConnectFlags) 0)
;
7911
7912 if (pMenuButton)
7913 {
7914 // by default the GtkMenuButton down arrow button is as wide as
7915 // a normal button and LibreOffice's original ones are very
7916 // narrow, that assumption is fairly baked into the toolbar and
7917 // sidebar designs, try and minimize the width of the dropdown
7918 // zone.
7919 GtkStyleContext *pButtonContext = gtk_widget_get_style_context(GTK_WIDGET(pMenuButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pMenuButton)), ((gtk_widget_get_type ()))))))
);
7920
7921 if (!m_pMenuButtonProvider)
7922 {
7923 m_pMenuButtonProvider = gtk_css_provider_new();
7924 static const gchar data[] = "* { "
7925 "padding: 0;"
7926 "margin-left: 0px;"
7927 "margin-right: 0px;"
7928 "min-width: 4px;"
7929 "}";
7930 const gchar olddata[] = "* { "
7931 "padding: 0;"
7932 "margin-left: 0px;"
7933 "margin-right: 0px;"
7934 "}";
7935 gtk_css_provider_load_from_data(m_pMenuButtonProvider, gtk_check_version(3, 20, 0) == nullptr ? data : olddata, -1, nullptr);
7936 }
7937
7938 gtk_style_context_add_provider(pButtonContext,
7939 GTK_STYLE_PROVIDER(m_pMenuButtonProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pMenuButtonProvider)), ((gtk_style_provider_get_type (
)))))))
,
7940 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
7941 }
7942
7943 }
7944 if (!GTK_IS_TOOL_BUTTON(pToolItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pToolItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
7945 return;
7946 g_signal_connect(pToolItem, "clicked", G_CALLBACK(signalItemClicked), this)g_signal_connect_data ((pToolItem), ("clicked"), (((GCallback
) (signalItemClicked))), (this), __null, (GConnectFlags) 0)
;
7947 }
7948
7949 static void signalItemClicked(GtkToolButton* pItem, gpointer widget)
7950 {
7951 GtkInstanceToolbar* pThis = static_cast<GtkInstanceToolbar*>(widget);
7952 SolarMutexGuard aGuard;
7953 pThis->signal_item_clicked(pItem);
7954 }
7955
7956 void signal_item_clicked(GtkToolButton* pItem)
7957 {
7958 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
);
7959 signal_clicked(OString(pStr, pStr ? strlen(pStr) : 0));
7960 }
7961
7962 static void signalItemToggled(GtkToggleButton* pItem, gpointer widget)
7963 {
7964 GtkInstanceToolbar* pThis = static_cast<GtkInstanceToolbar*>(widget);
7965 SolarMutexGuard aGuard;
7966 pThis->signal_item_toggled(pItem);
7967 }
7968
7969 void signal_item_toggled(GtkToggleButton* pItem)
7970 {
7971 for (auto& a : m_aMenuButtonMap)
7972 {
7973 if (a.second->getWidget() == GTK_WIDGET(pItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pItem)), ((gtk_widget_get_type ()))))))
)
7974 {
7975 signal_toggle_menu(a.first);
7976 break;
7977 }
7978 }
7979 }
7980
7981 static void set_item_image(GtkToolButton* pItem, const css::uno::Reference<css::graphic::XGraphic>& rIcon)
7982 {
7983 GtkWidget* pImage = nullptr;
7984
7985 if (GdkPixbuf* pixbuf = getPixbuf(rIcon))
7986 {
7987 pImage = gtk_image_new_from_pixbuf(pixbuf);
7988 g_object_unref(pixbuf);
7989 gtk_widget_show(pImage);
7990 }
7991
7992 gtk_tool_button_set_icon_widget(pItem, pImage);
7993 }
7994
7995 void set_item_image(GtkToolButton* pItem, const VirtualDevice* pDevice)
7996 {
7997 GtkWidget* pImage = nullptr;
7998
7999 if (pDevice)
8000 {
8001 pImage = image_new_from_virtual_device(*pDevice);
8002 gtk_widget_show(pImage);
8003 }
8004
8005 gtk_tool_button_set_icon_widget(pItem, pImage);
8006 gtk_widget_queue_draw(GTK_WIDGET(m_pToolbar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pToolbar)), ((gtk_widget_get_type ()))))))
);
8007 }
8008
8009public:
8010 GtkInstanceToolbar(GtkToolbar* pToolbar, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8011 : GtkInstanceWidget(GTK_WIDGET(pToolbar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pToolbar)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8012 , m_pToolbar(pToolbar)
8013 , m_pMenuButtonProvider(nullptr)
8014 {
8015 gtk_container_foreach(GTK_CONTAINER(pToolbar)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pToolbar)), ((gtk_container_get_type ()))))))
, collect, this);
8016 }
8017
8018 void disable_item_notify_events()
8019 {
8020 for (auto& a : m_aMap)
8021 {
8022 g_signal_handlers_block_by_func(a.second, reinterpret_cast<void*>(signalItemClicked), this)g_signal_handlers_block_matched ((a.second), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<void*>(signalItemClicked)), (this))
;
8023 }
8024 }
8025
8026 void enable_item_notify_events()
8027 {
8028 for (auto& a : m_aMap)
8029 {
8030 g_signal_handlers_unblock_by_func(a.second, reinterpret_cast<void*>(signalItemClicked), this)g_signal_handlers_unblock_matched ((a.second), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<void*>(signalItemClicked)), (this))
;
8031 }
8032 }
8033
8034 virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) override
8035 {
8036 disable_item_notify_events();
8037 gtk_widget_set_sensitive(GTK_WIDGET(m_aMap[rIdent])((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap[rIdent])), ((gtk_widget_get_type ()))))))
, bSensitive);
8038 enable_item_notify_events();
8039 }
8040
8041 virtual bool get_item_sensitive(const OString& rIdent) const override
8042 {
8043 return gtk_widget_get_sensitive(GTK_WIDGET(m_aMap.find(rIdent)->second)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap.find(rIdent)->second)), ((gtk_widget_get_type ()))
))))
);
8044 }
8045
8046 virtual void set_item_visible(const OString& rIdent, bool bVisible) override
8047 {
8048 disable_item_notify_events();
8049 gtk_widget_set_visible(GTK_WIDGET(m_aMap[rIdent])((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap[rIdent])), ((gtk_widget_get_type ()))))))
, bVisible);
8050 enable_item_notify_events();
8051 }
8052
8053 virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override
8054 {
8055 ::set_help_id(GTK_WIDGET(m_aMap[rIdent])((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap[rIdent])), ((gtk_widget_get_type ()))))))
, rHelpId);
8056 }
8057
8058 virtual bool get_item_visible(const OString& rIdent) const override
8059 {
8060 return gtk_widget_get_visible(GTK_WIDGET(m_aMap.find(rIdent)->second)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_aMap.find(rIdent)->second)), ((gtk_widget_get_type ()))
))))
);
8061 }
8062
8063 virtual void set_item_active(const OString& rIdent, bool bActive) override
8064 {
8065 disable_item_notify_events();
8066
8067 GtkToolItem* pToolButton = m_aMap.find(rIdent)->second;
8068
8069 assert(GTK_IS_TOGGLE_TOOL_BUTTON(pToolButton) || GTK_IS_MENU_TOOL_BUTTON(pToolButton) || !bActive)(static_cast <bool> ((((__extension__ ({ GTypeInstance *
__inst = (GTypeInstance*) ((pToolButton)); GType __t = ((gtk_toggle_tool_button_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))) || (((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pToolButton)); GType __t = ((gtk_menu_tool_button_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))) || !bActive) ? void (0) : __assert_fail ("GTK_IS_TOGGLE_TOOL_BUTTON(pToolButton) || GTK_IS_MENU_TOOL_BUTTON(pToolButton) || !bActive"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 8069, __extension__ __PRETTY_FUNCTION__))
;
8070 if (GTK_IS_MENU_TOOL_BUTTON(pToolButton)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pToolButton)); GType __t = ((gtk_menu_tool_button_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
8071 {
8072 GtkButton* pButton = nullptr;
8073 // there is no GtkMenuToggleToolButton so abuse the CHECKED state of the GtkMenuToolButton button
8074 // to emulate one
8075 find_menupeer_button(GTK_WIDGET(pToolButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pToolButton)), ((gtk_widget_get_type ()))))))
, &pButton);
8076 if (pButton)
8077 {
8078 auto eState = gtk_widget_get_state_flags(GTK_WIDGET(pButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_widget_get_type ()))))))
) & ~GTK_STATE_FLAG_CHECKED;
8079 if (bActive)
8080 eState |= GTK_STATE_FLAG_CHECKED;
8081 gtk_widget_set_state_flags(GTK_WIDGET(pButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_widget_get_type ()))))))
, static_cast<GtkStateFlags>(eState), true);
8082 }
8083 }
8084 else if (GTK_IS_TOGGLE_TOOL_BUTTON(pToolButton)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pToolButton)); GType __t = ((gtk_toggle_tool_button_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
8085 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(pToolButton)((((GtkToggleToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pToolButton)), ((gtk_toggle_tool_button_get_type ())))))
)
, bActive);
8086
8087 enable_item_notify_events();
8088 }
8089
8090 virtual bool get_item_active(const OString& rIdent) const override
8091 {
8092 GtkToolItem* pToolButton = m_aMap.find(rIdent)->second;
8093
8094 assert(GTK_IS_TOGGLE_TOOL_BUTTON(pToolButton) || GTK_IS_MENU_TOOL_BUTTON(pToolButton))(static_cast <bool> ((((__extension__ ({ GTypeInstance *
__inst = (GTypeInstance*) ((pToolButton)); GType __t = ((gtk_toggle_tool_button_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))) || (((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((pToolButton)); GType __t = ((gtk_menu_tool_button_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))) ? void (0) : __assert_fail ("GTK_IS_TOGGLE_TOOL_BUTTON(pToolButton) || GTK_IS_MENU_TOOL_BUTTON(pToolButton)"
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 8094, __extension__ __PRETTY_FUNCTION__))
;
8095 if (GTK_IS_MENU_TOOL_BUTTON(pToolButton)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pToolButton)); GType __t = ((gtk_menu_tool_button_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
8096 {
8097 GtkButton* pButton = nullptr;
8098 // there is no GtkMenuToggleToolButton so abuse the CHECKED state of the GtkMenuToolButton button
8099 // to emulate one
8100 find_menupeer_button(GTK_WIDGET(pToolButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pToolButton)), ((gtk_widget_get_type ()))))))
, &pButton);
8101 if (pButton)
8102 {
8103 return gtk_widget_get_state_flags(GTK_WIDGET(pButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_widget_get_type ()))))))
) & GTK_STATE_FLAG_CHECKED;
8104 }
8105 }
8106 else if (GTK_IS_TOGGLE_TOOL_BUTTON(pToolButton)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pToolButton)); GType __t = ((gtk_toggle_tool_button_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
8107 return gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(pToolButton)((((GtkToggleToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pToolButton)), ((gtk_toggle_tool_button_get_type ())))))
)
);
8108
8109 return false;
8110 }
8111
8112 virtual void set_menu_item_active(const OString& rIdent, bool bActive) override
8113 {
8114 disable_item_notify_events();
8115
8116 auto aFind = m_aMenuButtonMap.find(rIdent);
8117 assert (aFind != m_aMenuButtonMap.end())(static_cast <bool> (aFind != m_aMenuButtonMap.end()) ?
void (0) : __assert_fail ("aFind != m_aMenuButtonMap.end()",
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 8117, __extension__ __PRETTY_FUNCTION__))
;
8118 aFind->second->set_active(bActive);
8119
8120 enable_item_notify_events();
8121 }
8122
8123 virtual bool get_menu_item_active(const OString& rIdent) const override
8124 {
8125 auto aFind = m_aMenuButtonMap.find(rIdent);
8126 assert (aFind != m_aMenuButtonMap.end())(static_cast <bool> (aFind != m_aMenuButtonMap.end()) ?
void (0) : __assert_fail ("aFind != m_aMenuButtonMap.end()",
"/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 8126, __extension__ __PRETTY_FUNCTION__))
;
8127 return aFind->second->get_active();
8128 }
8129
8130 virtual void insert_separator(int pos, const OUString& rId) override
8131 {
8132 GtkToolItem* pItem = gtk_separator_tool_item_new();
8133 gtk_buildable_set_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
, OUStringToOString(rId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
8134 gtk_toolbar_insert(m_pToolbar, pItem, pos);
8135 gtk_widget_show(GTK_WIDGET(pItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pItem)), ((gtk_widget_get_type ()))))))
);
8136 }
8137
8138 virtual void set_item_popover(const OString& rIdent, weld::Widget* pPopover) override
8139 {
8140 m_aMenuButtonMap[rIdent]->set_popover(pPopover);
8141 }
8142
8143 virtual void set_item_menu(const OString& rIdent, weld::Menu* pMenu) override
8144 {
8145 m_aMenuButtonMap[rIdent]->set_menu(pMenu);
8146 }
8147
8148 virtual int get_n_items() const override
8149 {
8150 return gtk_toolbar_get_n_items(m_pToolbar);
8151 }
8152
8153 virtual OString get_item_ident(int nIndex) const override
8154 {
8155 GtkToolItem* pItem = gtk_toolbar_get_nth_item(m_pToolbar, nIndex);
8156 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
);
8157 return OString(pStr, pStr ? strlen(pStr) : 0);
8158 }
8159
8160 virtual void set_item_ident(int nIndex, const OString& rIdent) override
8161 {
8162 GtkToolItem* pItem = gtk_toolbar_get_nth_item(m_pToolbar, nIndex);
8163 gtk_buildable_set_name(GTK_BUILDABLE(pItem)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_buildable_get_type ()))))))
, rIdent.getStr());
8164 }
8165
8166 virtual void set_item_label(int nIndex, const OUString& rLabel) override
8167 {
8168 GtkToolItem* pItem = gtk_toolbar_get_nth_item(m_pToolbar, nIndex);
8169 if (!GTK_IS_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
8170 return;
8171 gtk_tool_button_set_label(GTK_TOOL_BUTTON(pItem)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_tool_button_get_type ()))))))
, MapToGtkAccelerator(rLabel).getStr());
8172 }
8173
8174 virtual void set_item_label(const OString& rIdent, const OUString& rLabel) override
8175 {
8176 GtkToolItem* pItem = m_aMap[rIdent];
8177 if (!pItem || !GTK_IS_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
8178 return;
8179 gtk_tool_button_set_label(GTK_TOOL_BUTTON(pItem)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_tool_button_get_type ()))))))
, MapToGtkAccelerator(rLabel).getStr());
8180 }
8181
8182 OUString get_item_label(const OString& rIdent) const override
8183 {
8184 const gchar* pText = gtk_tool_button_get_label(GTK_TOOL_BUTTON(m_aMap.find(rIdent)->second)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_aMap.find(rIdent)->second)), ((gtk_tool_button_get_type
()))))))
);
8185 return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
8186 }
8187
8188 virtual void set_item_icon_name(const OString& rIdent, const OUString& rIconName) override
8189 {
8190 GtkToolItem* pItem = m_aMap[rIdent];
8191 if (!pItem || !GTK_IS_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
8192 return;
8193
8194 GtkWidget* pImage = nullptr;
8195
8196 if (GdkPixbuf* pixbuf = getPixbuf(rIconName))
8197 {
8198 pImage = gtk_image_new_from_pixbuf(pixbuf);
8199 g_object_unref(pixbuf);
8200 gtk_widget_show(pImage);
8201 }
8202
8203 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(pItem)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_tool_button_get_type ()))))))
, pImage);
8204 }
8205
8206 virtual void set_item_image(const OString& rIdent, const css::uno::Reference<css::graphic::XGraphic>& rIcon) override
8207 {
8208 GtkToolItem* pItem = m_aMap[rIdent];
8209 if (!pItem || !GTK_IS_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
8210 return;
8211 set_item_image(GTK_TOOL_BUTTON(pItem)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_tool_button_get_type ()))))))
, rIcon);
8212 }
8213
8214 virtual void set_item_image(const OString& rIdent, VirtualDevice* pDevice) override
8215 {
8216 GtkToolItem* pItem = m_aMap[rIdent];
8217 if (!pItem || !GTK_IS_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
8218 return;
8219 set_item_image(GTK_TOOL_BUTTON(pItem)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_tool_button_get_type ()))))))
, pDevice);
8220 }
8221
8222 virtual void set_item_image(int nIndex, const css::uno::Reference<css::graphic::XGraphic>& rIcon) override
8223 {
8224 GtkToolItem* pItem = gtk_toolbar_get_nth_item(m_pToolbar, nIndex);
8225 if (!GTK_IS_TOOL_BUTTON(pItem)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pItem)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
8226 return;
8227 set_item_image(GTK_TOOL_BUTTON(pItem)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pItem)), ((gtk_tool_button_get_type ()))))))
, rIcon);
8228 }
8229
8230 virtual void set_item_tooltip_text(int nIndex, const OUString& rTip) override
8231 {
8232 GtkToolItem* pItem = gtk_toolbar_get_nth_item(m_pToolbar, nIndex);
8233 gtk_widget_set_tooltip_text(GTK_WIDGET(pItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pItem)), ((gtk_widget_get_type ()))))))
, OUStringToOString(rTip, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
8234 }
8235
8236 virtual void set_item_tooltip_text(const OString& rIdent, const OUString& rTip) override
8237 {
8238 GtkToolItem* pItem = m_aMap[rIdent];
8239 gtk_widget_set_tooltip_text(GTK_WIDGET(pItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pItem)), ((gtk_widget_get_type ()))))))
, OUStringToOString(rTip, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
8240 }
8241
8242 virtual OUString get_item_tooltip_text(const OString& rIdent) const override
8243 {
8244 GtkToolItem* pItem = m_aMap.find(rIdent)->second;
8245 const gchar* pStr = gtk_widget_get_tooltip_text(GTK_WIDGET(pItem)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pItem)), ((gtk_widget_get_type ()))))))
);
8246 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
8247 }
8248
8249 virtual vcl::ImageType get_icon_size() const override
8250 {
8251 return GtkToVcl(gtk_toolbar_get_icon_size(m_pToolbar));
8252 }
8253
8254 virtual void set_icon_size(vcl::ImageType eType) override
8255 {
8256 return gtk_toolbar_set_icon_size(m_pToolbar, VclToGtk(eType));
8257 }
8258
8259 virtual sal_uInt16 get_modifier_state() const override
8260 {
8261 GdkKeymap* pKeymap = gdk_keymap_get_default();
8262 guint nState = gdk_keymap_get_modifier_state(pKeymap);
8263 return GtkSalFrame::GetKeyModCode(nState);
8264 }
8265
8266 int get_drop_index(const Point& rPoint) const override
8267 {
8268 return gtk_toolbar_get_drop_index(m_pToolbar, rPoint.X(), rPoint.Y());
8269 }
8270
8271 virtual ~GtkInstanceToolbar() override
8272 {
8273 for (auto& a : m_aMap)
8274 g_signal_handlers_disconnect_by_data(a.second, this)g_signal_handlers_disconnect_matched ((a.second), G_SIGNAL_MATCH_DATA
, 0, 0, __null, __null, (this))
;
8275 }
8276};
8277
8278class GtkInstanceLinkButton : public GtkInstanceContainer, public virtual weld::LinkButton
8279{
8280private:
8281 GtkLinkButton* m_pButton;
8282 gulong m_nSignalId;
8283
8284 static bool signalActivateLink(GtkButton*, gpointer widget)
8285 {
8286 GtkInstanceLinkButton* pThis = static_cast<GtkInstanceLinkButton*>(widget);
8287 SolarMutexGuard aGuard;
8288 return pThis->signal_activate_link();
8289 }
8290
8291public:
8292 GtkInstanceLinkButton(GtkLinkButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8293 : GtkInstanceContainer(GTK_CONTAINER(pButton)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pButton)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
8294 , m_pButton(pButton)
8295 , m_nSignalId(g_signal_connect(pButton, "activate-link", G_CALLBACK(signalActivateLink), this)g_signal_connect_data ((pButton), ("activate-link"), (((GCallback
) (signalActivateLink))), (this), __null, (GConnectFlags) 0)
)
8296 {
8297 }
8298
8299 virtual void set_label(const OUString& rText) override
8300 {
8301 ::set_label(GTK_BUTTON(m_pButton)((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButton)), ((gtk_button_get_type ()))))))
, rText);
8302 }
8303
8304 virtual OUString get_label() const override
8305 {
8306 return ::get_label(GTK_BUTTON(m_pButton)((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButton)), ((gtk_button_get_type ()))))))
);
8307 }
8308
8309 virtual void set_uri(const OUString& rText) override
8310 {
8311 gtk_link_button_set_uri(m_pButton, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
8312 }
8313
8314 virtual OUString get_uri() const override
8315 {
8316 const gchar* pStr = gtk_link_button_get_uri(m_pButton);
8317 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
8318 }
8319
8320 virtual void disable_notify_events() override
8321 {
8322 g_signal_handler_block(m_pButton, m_nSignalId);
8323 GtkInstanceContainer::disable_notify_events();
8324 }
8325
8326 virtual void enable_notify_events() override
8327 {
8328 GtkInstanceContainer::enable_notify_events();
8329 g_signal_handler_unblock(m_pButton, m_nSignalId);
8330 }
8331
8332 virtual ~GtkInstanceLinkButton() override
8333 {
8334 g_signal_handler_disconnect(m_pButton, m_nSignalId);
8335 }
8336};
8337
8338class GtkInstanceRadioButton : public GtkInstanceToggleButton, public virtual weld::RadioButton
8339{
8340public:
8341 GtkInstanceRadioButton(GtkRadioButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8342 : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pButton)), ((gtk_toggle_button_get_type ()))))))
, pBuilder, bTakeOwnership)
8343 {
8344 }
8345};
8346
8347class GtkInstanceCheckButton : public GtkInstanceToggleButton, public virtual weld::CheckButton
8348{
8349public:
8350 GtkInstanceCheckButton(GtkCheckButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8351 : GtkInstanceToggleButton(GTK_TOGGLE_BUTTON(pButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pButton)), ((gtk_toggle_button_get_type ()))))))
, pBuilder, bTakeOwnership)
8352 {
8353 }
8354};
8355
8356class GtkInstanceScale : public GtkInstanceWidget, public virtual weld::Scale
8357{
8358private:
8359 GtkScale* m_pScale;
8360 gulong m_nValueChangedSignalId;
8361
8362 static void signalValueChanged(GtkScale*, gpointer widget)
8363 {
8364 GtkInstanceScale* pThis = static_cast<GtkInstanceScale*>(widget);
8365 SolarMutexGuard aGuard;
8366 pThis->signal_value_changed();
8367 }
8368
8369public:
8370 GtkInstanceScale(GtkScale* pScale, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8371 : GtkInstanceWidget(GTK_WIDGET(pScale)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pScale)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8372 , m_pScale(pScale)
8373 , m_nValueChangedSignalId(g_signal_connect(m_pScale, "value-changed", G_CALLBACK(signalValueChanged), this)g_signal_connect_data ((m_pScale), ("value-changed"), (((GCallback
) (signalValueChanged))), (this), __null, (GConnectFlags) 0)
)
8374 {
8375 }
8376
8377 virtual void disable_notify_events() override
8378 {
8379 g_signal_handler_block(m_pScale, m_nValueChangedSignalId);
8380 GtkInstanceWidget::disable_notify_events();
8381 }
8382
8383 virtual void enable_notify_events() override
8384 {
8385 GtkInstanceWidget::enable_notify_events();
8386 g_signal_handler_unblock(m_pScale, m_nValueChangedSignalId);
8387 }
8388
8389 virtual void set_value(int value) override
8390 {
8391 disable_notify_events();
8392 gtk_range_set_value(GTK_RANGE(m_pScale)((((GtkRange*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pScale)), ((gtk_range_get_type ()))))))
, value);
8393 enable_notify_events();
8394 }
8395
8396 virtual void set_range(int min, int max) override
8397 {
8398 disable_notify_events();
8399 gtk_range_set_range(GTK_RANGE(m_pScale)((((GtkRange*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pScale)), ((gtk_range_get_type ()))))))
, min, max);
8400 enable_notify_events();
8401 }
8402
8403 virtual void set_increments(int step, int page) override
8404 {
8405 disable_notify_events();
8406 gtk_range_set_increments(GTK_RANGE(m_pScale)((((GtkRange*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pScale)), ((gtk_range_get_type ()))))))
, step, page);
8407 enable_notify_events();
8408 }
8409
8410 virtual void get_increments(int& step, int& page) const override
8411 {
8412 GtkAdjustment* pAdjustment = gtk_range_get_adjustment(GTK_RANGE(m_pScale)((((GtkRange*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pScale)), ((gtk_range_get_type ()))))))
);
8413 step = gtk_adjustment_get_step_increment(pAdjustment);
8414 page = gtk_adjustment_get_page_increment(pAdjustment);
8415 }
8416
8417 virtual int get_value() const override
8418 {
8419 return gtk_range_get_value(GTK_RANGE(m_pScale)((((GtkRange*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pScale)), ((gtk_range_get_type ()))))))
);
8420 }
8421
8422 virtual ~GtkInstanceScale() override
8423 {
8424 g_signal_handler_disconnect(m_pScale, m_nValueChangedSignalId);
8425 }
8426};
8427
8428class GtkInstanceProgressBar : public GtkInstanceWidget, public virtual weld::ProgressBar
8429{
8430private:
8431 GtkProgressBar* m_pProgressBar;
8432
8433public:
8434 GtkInstanceProgressBar(GtkProgressBar* pProgressBar, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8435 : GtkInstanceWidget(GTK_WIDGET(pProgressBar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pProgressBar)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8436 , m_pProgressBar(pProgressBar)
8437 {
8438 }
8439
8440 virtual void set_percentage(int value) override
8441 {
8442 gtk_progress_bar_set_fraction(m_pProgressBar, value / 100.0);
8443 }
8444
8445 virtual OUString get_text() const override
8446 {
8447 const gchar* pText = gtk_progress_bar_get_text(m_pProgressBar);
8448 OUString sRet(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
8449 return sRet;
8450 }
8451
8452 virtual void set_text(const OUString& rText) override
8453 {
8454 gtk_progress_bar_set_text(m_pProgressBar, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
8455 }
8456};
8457
8458class GtkInstanceSpinner : public GtkInstanceWidget, public virtual weld::Spinner
8459{
8460private:
8461 GtkSpinner* m_pSpinner;
8462
8463public:
8464 GtkInstanceSpinner(GtkSpinner* pSpinner, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8465 : GtkInstanceWidget(GTK_WIDGET(pSpinner)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pSpinner)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8466 , m_pSpinner(pSpinner)
8467 {
8468 }
8469
8470 virtual void start() override
8471 {
8472 gtk_spinner_start(m_pSpinner);
8473 }
8474
8475 virtual void stop() override
8476 {
8477 gtk_spinner_stop(m_pSpinner);
8478 }
8479};
8480
8481class GtkInstanceImage : public GtkInstanceWidget, public virtual weld::Image
8482{
8483private:
8484 GtkImage* m_pImage;
8485
8486public:
8487 GtkInstanceImage(GtkImage* pImage, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8488 : GtkInstanceWidget(GTK_WIDGET(pImage)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pImage)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8489 , m_pImage(pImage)
8490 {
8491 }
8492
8493 virtual void set_from_icon_name(const OUString& rIconName) override
8494 {
8495 GdkPixbuf* pixbuf = load_icon_by_name(rIconName);
8496 if (!pixbuf)
8497 return;
8498 gtk_image_set_from_pixbuf(m_pImage, pixbuf);
8499 g_object_unref(pixbuf);
8500 }
8501
8502 virtual void set_image(VirtualDevice* pDevice) override
8503 {
8504 if (gtk_check_version(3, 20, 0) == nullptr)
8505 {
8506 if (pDevice)
8507 gtk_image_set_from_surface(m_pImage, get_underlying_cairo_surface(*pDevice));
8508 else
8509 gtk_image_set_from_surface(m_pImage, nullptr);
8510 return;
8511 }
8512
8513 GdkPixbuf* pixbuf = pDevice ? getPixbuf(*pDevice) : nullptr;
8514 gtk_image_set_from_pixbuf(m_pImage, pixbuf);
8515 if (pixbuf)
8516 g_object_unref(pixbuf);
8517 }
8518
8519 virtual void set_image(const css::uno::Reference<css::graphic::XGraphic>& rImage) override
8520 {
8521 GdkPixbuf* pixbuf = getPixbuf(rImage);
8522 gtk_image_set_from_pixbuf(m_pImage, pixbuf);
8523 if (pixbuf)
8524 g_object_unref(pixbuf);
8525 }
8526};
8527
8528class GtkInstanceCalendar : public GtkInstanceWidget, public virtual weld::Calendar
8529{
8530private:
8531 GtkCalendar* m_pCalendar;
8532 gulong m_nDaySelectedSignalId;
8533 gulong m_nDaySelectedDoubleClickSignalId;
8534 gulong m_nKeyPressEventSignalId;
8535 gulong m_nButtonPressEventSignalId;
8536
8537 static void signalDaySelected(GtkCalendar*, gpointer widget)
8538 {
8539 GtkInstanceCalendar* pThis = static_cast<GtkInstanceCalendar*>(widget);
8540 pThis->signal_selected();
8541 }
8542
8543 static void signalDaySelectedDoubleClick(GtkCalendar*, gpointer widget)
8544 {
8545 GtkInstanceCalendar* pThis = static_cast<GtkInstanceCalendar*>(widget);
8546 pThis->signal_activated();
8547 }
8548
8549 bool signal_key_press(GdkEventKey* pEvent)
8550 {
8551 if (pEvent->keyval == GDK_KEY_Return0xff0d || pEvent->keyval == GDK_KEY_KP_Enter0xff8d)
8552 {
8553 signal_activated();
8554 return true;
8555 }
8556 return false;
8557 }
8558
8559 static gboolean signalKeyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
8560 {
8561 GtkInstanceCalendar* pThis = static_cast<GtkInstanceCalendar*>(widget);
8562 return pThis->signal_key_press(pEvent);
8563 }
8564
8565 static gboolean signalButton(GtkWidget*, GdkEventButton*, gpointer)
8566 {
8567 // don't let button press get to parent window, for the case of the
8568 // ImplCFieldFloatWin floating window belonging to CalendarField where
8569 // the click on the calendar continues to the parent GtkWindow and
8570 // closePopup is called by GtkSalFrame::signalButton because the click
8571 // window isn't that of the floating parent GtkWindow
8572 return true;
8573 }
8574
8575public:
8576 GtkInstanceCalendar(GtkCalendar* pCalendar, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8577 : GtkInstanceWidget(GTK_WIDGET(pCalendar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pCalendar)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8578 , m_pCalendar(pCalendar)
8579 , m_nDaySelectedSignalId(g_signal_connect(pCalendar, "day-selected", G_CALLBACK(signalDaySelected), this)g_signal_connect_data ((pCalendar), ("day-selected"), (((GCallback
) (signalDaySelected))), (this), __null, (GConnectFlags) 0)
)
8580 , m_nDaySelectedDoubleClickSignalId(g_signal_connect(pCalendar, "day-selected-double-click", G_CALLBACK(signalDaySelectedDoubleClick), this)g_signal_connect_data ((pCalendar), ("day-selected-double-click"
), (((GCallback) (signalDaySelectedDoubleClick))), (this), __null
, (GConnectFlags) 0)
)
8581 , m_nKeyPressEventSignalId(g_signal_connect(pCalendar, "key-press-event", G_CALLBACK(signalKeyPress), this)g_signal_connect_data ((pCalendar), ("key-press-event"), (((GCallback
) (signalKeyPress))), (this), __null, (GConnectFlags) 0)
)
8582 , m_nButtonPressEventSignalId(g_signal_connect_after(pCalendar, "button-press-event", G_CALLBACK(signalButton), this)g_signal_connect_data ((pCalendar), ("button-press-event"), (
((GCallback) (signalButton))), (this), __null, G_CONNECT_AFTER
)
)
8583 {
8584 }
8585
8586 virtual void set_date(const Date& rDate) override
8587 {
8588 if (!rDate.IsValidAndGregorian())
8589 return;
8590
8591 disable_notify_events();
8592 gtk_calendar_select_month(m_pCalendar, rDate.GetMonth() - 1, rDate.GetYear());
8593 gtk_calendar_select_day(m_pCalendar, rDate.GetDay());
8594 enable_notify_events();
8595 }
8596
8597 virtual Date get_date() const override
8598 {
8599 guint year, month, day;
8600 gtk_calendar_get_date(m_pCalendar, &year, &month, &day);
8601 return Date(day, month + 1, year);
8602 }
8603
8604 virtual void disable_notify_events() override
8605 {
8606 g_signal_handler_block(m_pCalendar, m_nDaySelectedDoubleClickSignalId);
8607 g_signal_handler_block(m_pCalendar, m_nDaySelectedSignalId);
8608 GtkInstanceWidget::disable_notify_events();
8609 }
8610
8611 virtual void enable_notify_events() override
8612 {
8613 GtkInstanceWidget::enable_notify_events();
8614 g_signal_handler_unblock(m_pCalendar, m_nDaySelectedSignalId);
8615 g_signal_handler_unblock(m_pCalendar, m_nDaySelectedDoubleClickSignalId);
8616 }
8617
8618 virtual ~GtkInstanceCalendar() override
8619 {
8620 g_signal_handler_disconnect(m_pCalendar, m_nButtonPressEventSignalId);
8621 g_signal_handler_disconnect(m_pCalendar, m_nKeyPressEventSignalId);
8622 g_signal_handler_disconnect(m_pCalendar, m_nDaySelectedDoubleClickSignalId);
8623 g_signal_handler_disconnect(m_pCalendar, m_nDaySelectedSignalId);
8624 }
8625};
8626
8627 PangoAttrList* create_attr_list(const vcl::Font& rFont)
8628 {
8629 PangoAttrList* pAttrList = pango_attr_list_new();
8630 pango_attr_list_insert(pAttrList, pango_attr_family_new(OUStringToOString(rFont.GetFamilyName(), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr()));
8631 pango_attr_list_insert(pAttrList, pango_attr_size_new(rFont.GetFontSize().Height() * PANGO_SCALE1024));
8632 switch (rFont.GetItalic())
8633 {
8634 case ITALIC_NONE:
8635 pango_attr_list_insert(pAttrList, pango_attr_style_new(PANGO_STYLE_NORMAL));
8636 break;
8637 case ITALIC_NORMAL:
8638 pango_attr_list_insert(pAttrList, pango_attr_style_new(PANGO_STYLE_ITALIC));
8639 break;
8640 case ITALIC_OBLIQUE:
8641 pango_attr_list_insert(pAttrList, pango_attr_style_new(PANGO_STYLE_OBLIQUE));
8642 break;
8643 default:
8644 break;
8645 }
8646 switch (rFont.GetWeight())
8647 {
8648 case WEIGHT_ULTRALIGHT:
8649 pango_attr_list_insert(pAttrList, pango_attr_weight_new(PANGO_WEIGHT_ULTRALIGHT));
8650 break;
8651 case WEIGHT_LIGHT:
8652 pango_attr_list_insert(pAttrList, pango_attr_weight_new(PANGO_WEIGHT_LIGHT));
8653 break;
8654 case WEIGHT_NORMAL:
8655 pango_attr_list_insert(pAttrList, pango_attr_weight_new(PANGO_WEIGHT_NORMAL));
8656 break;
8657 case WEIGHT_BOLD:
8658 pango_attr_list_insert(pAttrList, pango_attr_weight_new(PANGO_WEIGHT_BOLD));
8659 break;
8660 case WEIGHT_ULTRABOLD:
8661 pango_attr_list_insert(pAttrList, pango_attr_weight_new(PANGO_WEIGHT_ULTRABOLD));
8662 break;
8663 default:
8664 break;
8665 }
8666 switch (rFont.GetWidthType())
8667 {
8668 case WIDTH_ULTRA_CONDENSED:
8669 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_ULTRA_CONDENSED));
8670 break;
8671 case WIDTH_EXTRA_CONDENSED:
8672 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_EXTRA_CONDENSED));
8673 break;
8674 case WIDTH_CONDENSED:
8675 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_CONDENSED));
8676 break;
8677 case WIDTH_SEMI_CONDENSED:
8678 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_SEMI_CONDENSED));
8679 break;
8680 case WIDTH_NORMAL:
8681 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_NORMAL));
8682 break;
8683 case WIDTH_SEMI_EXPANDED:
8684 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_SEMI_EXPANDED));
8685 break;
8686 case WIDTH_EXPANDED:
8687 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_EXPANDED));
8688 break;
8689 case WIDTH_EXTRA_EXPANDED:
8690 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_EXTRA_EXPANDED));
8691 break;
8692 case WIDTH_ULTRA_EXPANDED:
8693 pango_attr_list_insert(pAttrList, pango_attr_stretch_new(PANGO_STRETCH_ULTRA_EXPANDED));
8694 break;
8695 default:
8696 break;
8697 }
8698 return pAttrList;
8699 }
8700}
8701
8702namespace
8703{
8704 void set_entry_message_type(GtkEntry* pEntry, weld::EntryMessageType eType)
8705 {
8706 switch (eType)
8707 {
8708 case weld::EntryMessageType::Normal:
8709 gtk_entry_set_icon_from_icon_name(pEntry, GTK_ENTRY_ICON_SECONDARY, nullptr);
8710 break;
8711 case weld::EntryMessageType::Warning:
8712 gtk_entry_set_icon_from_icon_name(pEntry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
8713 break;
8714 case weld::EntryMessageType::Error:
8715 gtk_entry_set_icon_from_icon_name(pEntry, GTK_ENTRY_ICON_SECONDARY, "dialog-error");
8716 break;
8717 }
8718 }
8719
8720 gboolean filter_pango_attrs(PangoAttribute *attr, gpointer data)
8721 {
8722 PangoAttrType* pFilterAttrs = static_cast<PangoAttrType*>(data);
8723 while (*pFilterAttrs)
8724 {
8725 if (attr->klass->type == *pFilterAttrs)
8726 return true;
8727 ++pFilterAttrs;
8728 }
8729 return false;
8730 }
8731
8732class GtkInstanceEntry : public GtkInstanceWidget, public virtual weld::Entry
8733{
8734private:
8735 GtkEntry* m_pEntry;
8736 std::unique_ptr<vcl::Font> m_xFont;
8737 gulong m_nChangedSignalId;
8738 gulong m_nInsertTextSignalId;
8739 gulong m_nCursorPosSignalId;
8740 gulong m_nSelectionPosSignalId;
8741 gulong m_nActivateSignalId;
8742
8743 static void signalChanged(GtkEntry*, gpointer widget)
8744 {
8745 GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget);
8746 SolarMutexGuard aGuard;
8747 pThis->signal_changed();
8748 }
8749
8750 static void signalInsertText(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength,
8751 gint* position, gpointer widget)
8752 {
8753 GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget);
8754 SolarMutexGuard aGuard;
8755 pThis->signal_insert_text(pEntry, pNewText, nNewTextLength, position);
8756 }
8757
8758 void signal_insert_text(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength, gint* position)
8759 {
8760 if (!m_aInsertTextHdl.IsSet())
8761 return;
8762 OUString sText(pNewText, nNewTextLength, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
8763 const bool bContinue = m_aInsertTextHdl.Call(sText);
8764 if (bContinue && !sText.isEmpty())
8765 {
8766 OString sFinalText(OUStringToOString(sText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
8767 g_signal_handlers_block_by_func(pEntry, reinterpret_cast<gpointer>(signalInsertText), this)g_signal_handlers_block_matched ((pEntry), (GSignalMatchType)
(G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<gpointer>(signalInsertText)), (this))
;
8768 gtk_editable_insert_text(GTK_EDITABLE(pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((pEntry)), ((gtk_editable_get_type ()))))))
, sFinalText.getStr(), sFinalText.getLength(), position);
8769 g_signal_handlers_unblock_by_func(pEntry, reinterpret_cast<gpointer>(signalInsertText), this)g_signal_handlers_unblock_matched ((pEntry), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<gpointer>(signalInsertText)), (this))
;
8770 }
8771 g_signal_stop_emission_by_name(pEntry, "insert-text");
8772 }
8773
8774 static void signalCursorPosition(GtkEntry*, GParamSpec*, gpointer widget)
8775 {
8776 GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget);
8777 pThis->signal_cursor_position();
8778 }
8779
8780 static void signalActivate(GtkEntry*, gpointer widget)
8781 {
8782 GtkInstanceEntry* pThis = static_cast<GtkInstanceEntry*>(widget);
8783 pThis->signal_activate();
8784 }
8785
8786protected:
8787
8788 virtual void signal_activate()
8789 {
8790 if (m_aActivateHdl.IsSet())
8791 {
8792 SolarMutexGuard aGuard;
8793 if (m_aActivateHdl.Call(*this))
8794 g_signal_stop_emission_by_name(m_pEntry, "activate");
8795 }
8796 }
8797
8798public:
8799 GtkInstanceEntry(GtkEntry* pEntry, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
8800 : GtkInstanceWidget(GTK_WIDGET(pEntry)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pEntry)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
8801 , m_pEntry(pEntry)
8802 , m_nChangedSignalId(g_signal_connect(pEntry, "changed", G_CALLBACK(signalChanged), this)g_signal_connect_data ((pEntry), ("changed"), (((GCallback) (
signalChanged))), (this), __null, (GConnectFlags) 0)
)
8803 , m_nInsertTextSignalId(g_signal_connect(pEntry, "insert-text", G_CALLBACK(signalInsertText), this)g_signal_connect_data ((pEntry), ("insert-text"), (((GCallback
) (signalInsertText))), (this), __null, (GConnectFlags) 0)
)
8804 , m_nCursorPosSignalId(g_signal_connect(pEntry, "notify::cursor-position", G_CALLBACK(signalCursorPosition), this)g_signal_connect_data ((pEntry), ("notify::cursor-position"),
(((GCallback) (signalCursorPosition))), (this), __null, (GConnectFlags
) 0)
)
8805 , m_nSelectionPosSignalId(g_signal_connect(pEntry, "notify::selection-bound", G_CALLBACK(signalCursorPosition), this)g_signal_connect_data ((pEntry), ("notify::selection-bound"),
(((GCallback) (signalCursorPosition))), (this), __null, (GConnectFlags
) 0)
)
8806 , m_nActivateSignalId(g_signal_connect(pEntry, "activate", G_CALLBACK(signalActivate), this)g_signal_connect_data ((pEntry), ("activate"), (((GCallback) (
signalActivate))), (this), __null, (GConnectFlags) 0)
)
8807 {
8808 }
8809
8810 virtual void set_text(const OUString& rText) override
8811 {
8812 disable_notify_events();
8813 gtk_entry_set_text(m_pEntry, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
8814 enable_notify_events();
8815 }
8816
8817 virtual OUString get_text() const override
8818 {
8819 const gchar* pText = gtk_entry_get_text(m_pEntry);
8820 OUString sRet(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
8821 return sRet;
8822 }
8823
8824 virtual void set_width_chars(int nChars) override
8825 {
8826 disable_notify_events();
8827 gtk_entry_set_width_chars(m_pEntry, nChars);
8828 gtk_entry_set_max_width_chars(m_pEntry, nChars);
8829 enable_notify_events();
8830 }
8831
8832 virtual int get_width_chars() const override
8833 {
8834 return gtk_entry_get_width_chars(m_pEntry);
8835 }
8836
8837 virtual void set_max_length(int nChars) override
8838 {
8839 disable_notify_events();
8840 gtk_entry_set_max_length(m_pEntry, nChars);
8841 enable_notify_events();
8842 }
8843
8844 virtual void select_region(int nStartPos, int nEndPos) override
8845 {
8846 disable_notify_events();
8847 gtk_editable_select_region(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, nStartPos, nEndPos);
8848 enable_notify_events();
8849 }
8850
8851 bool get_selection_bounds(int& rStartPos, int& rEndPos) override
8852 {
8853 return gtk_editable_get_selection_bounds(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, &rStartPos, &rEndPos);
8854 }
8855
8856 virtual void replace_selection(const OUString& rText) override
8857 {
8858 disable_notify_events();
8859 gtk_editable_delete_selection(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8860 OString sText(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
8861 gint position = gtk_editable_get_position(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8862 gtk_editable_insert_text(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, sText.getStr(), sText.getLength(),
8863 &position);
8864 enable_notify_events();
8865 }
8866
8867 virtual void set_position(int nCursorPos) override
8868 {
8869 disable_notify_events();
8870 gtk_editable_set_position(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, nCursorPos);
8871 enable_notify_events();
8872 }
8873
8874 virtual int get_position() const override
8875 {
8876 return gtk_editable_get_position(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8877 }
8878
8879 virtual void set_editable(bool bEditable) override
8880 {
8881 gtk_editable_set_editable(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, bEditable);
8882 }
8883
8884 virtual bool get_editable() const override
8885 {
8886 return gtk_editable_get_editable(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8887 }
8888
8889 virtual void set_overwrite_mode(bool bOn) override
8890 {
8891 gtk_entry_set_overwrite_mode(m_pEntry, bOn);
8892 }
8893
8894 virtual bool get_overwrite_mode() const override
8895 {
8896 return gtk_entry_get_overwrite_mode(m_pEntry);
8897 }
8898
8899 virtual void set_message_type(weld::EntryMessageType eType) override
8900 {
8901 ::set_entry_message_type(m_pEntry, eType);
8902 }
8903
8904 virtual void disable_notify_events() override
8905 {
8906 g_signal_handler_block(m_pEntry, m_nActivateSignalId);
8907 g_signal_handler_block(m_pEntry, m_nSelectionPosSignalId);
8908 g_signal_handler_block(m_pEntry, m_nCursorPosSignalId);
8909 g_signal_handler_block(m_pEntry, m_nInsertTextSignalId);
8910 g_signal_handler_block(m_pEntry, m_nChangedSignalId);
8911 GtkInstanceWidget::disable_notify_events();
8912 }
8913
8914 virtual void enable_notify_events() override
8915 {
8916 GtkInstanceWidget::enable_notify_events();
8917 g_signal_handler_unblock(m_pEntry, m_nChangedSignalId);
8918 g_signal_handler_unblock(m_pEntry, m_nInsertTextSignalId);
8919 g_signal_handler_unblock(m_pEntry, m_nCursorPosSignalId);
8920 g_signal_handler_unblock(m_pEntry, m_nSelectionPosSignalId);
8921 g_signal_handler_unblock(m_pEntry, m_nActivateSignalId);
8922 }
8923
8924 virtual void set_font(const vcl::Font& rFont) override
8925 {
8926 m_xFont.reset(new vcl::Font(rFont));
8927 PangoAttrList* pAttrList = create_attr_list(rFont);
8928 gtk_entry_set_attributes(m_pEntry, pAttrList);
8929 pango_attr_list_unref(pAttrList);
8930 }
8931
8932 virtual vcl::Font get_font() override
8933 {
8934 if (m_xFont)
8935 return *m_xFont;
8936 return GtkInstanceWidget::get_font();
8937 }
8938
8939 void set_font_color(const Color& rColor) override
8940 {
8941 PangoAttrList* pOrigList = gtk_entry_get_attributes(m_pEntry);
8942 if (rColor == COL_AUTO && !pOrigList) // nothing to do
8943 return;
8944
8945 PangoAttrType aFilterAttrs[] = {PANGO_ATTR_FOREGROUND, PANGO_ATTR_INVALID};
8946
8947 PangoAttrList* pAttrs = pOrigList ? pango_attr_list_copy(pOrigList) : pango_attr_list_new();
8948 PangoAttrList* pRemovedAttrs = pOrigList ? pango_attr_list_filter(pAttrs, filter_pango_attrs, &aFilterAttrs) : nullptr;
8949
8950 if (rColor != COL_AUTO)
8951 pango_attr_list_insert(pAttrs, pango_attr_foreground_new(rColor.GetRed()/255.0, rColor.GetGreen()/255.0, rColor.GetBlue()/255.0));
8952
8953 gtk_entry_set_attributes(m_pEntry, pAttrs);
8954 pango_attr_list_unref(pAttrs);
8955 pango_attr_list_unref(pRemovedAttrs);
8956 }
8957
8958 void fire_signal_changed()
8959 {
8960 signal_changed();
8961 }
8962
8963 virtual void cut_clipboard() override
8964 {
8965 gtk_editable_cut_clipboard(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8966 }
8967
8968 virtual void copy_clipboard() override
8969 {
8970 gtk_editable_copy_clipboard(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8971 }
8972
8973 virtual void paste_clipboard() override
8974 {
8975 gtk_editable_paste_clipboard(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
8976 }
8977
8978 virtual void set_placeholder_text(const OUString& rText) override
8979 {
8980 gtk_entry_set_placeholder_text(m_pEntry, rText.toUtf8().getStr());
8981 }
8982
8983 virtual void grab_focus() override
8984 {
8985 disable_notify_events();
8986 gtk_entry_grab_focus_without_selecting(m_pEntry);
8987 enable_notify_events();
8988 }
8989
8990 virtual void set_alignment(TxtAlign eXAlign) override
8991 {
8992 gfloat xalign = 0;
8993 switch (eXAlign)
8994 {
8995 case TxtAlign::Left:
8996 xalign = 0.0;
8997 break;
8998 case TxtAlign::Center:
8999 xalign = 0.5;
9000 break;
9001 case TxtAlign::Right:
9002 xalign = 1.0;
9003 break;
9004 }
9005 gtk_entry_set_alignment(m_pEntry, xalign);
9006 }
9007
9008 virtual ~GtkInstanceEntry() override
9009 {
9010 g_signal_handler_disconnect(m_pEntry, m_nActivateSignalId);
9011 g_signal_handler_disconnect(m_pEntry, m_nSelectionPosSignalId);
9012 g_signal_handler_disconnect(m_pEntry, m_nCursorPosSignalId);
9013 g_signal_handler_disconnect(m_pEntry, m_nInsertTextSignalId);
9014 g_signal_handler_disconnect(m_pEntry, m_nChangedSignalId);
9015 }
9016};
9017
9018 struct Search
9019 {
9020 OString str;
9021 int index;
9022 int col;
9023 Search(const OUString& rText, int nCol)
9024 : str(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))))
9025 , index(-1)
9026 , col(nCol)
9027 {
9028 }
9029 };
9030
9031 gboolean foreach_find(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data)
9032 {
9033 Search* search = static_cast<Search*>(data);
9034 gchar *pStr = nullptr;
9035 gtk_tree_model_get(model, iter, search->col, &pStr, -1);
9036 bool found = strcmp(pStr, search->str.getStr()) == 0;
9037 if (found)
9038 {
9039 gint depth;
9040 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
9041 search->index = indices[depth-1];
9042 }
9043 g_free(pStr);
9044 return found;
9045 }
9046
9047 void insert_row(GtkListStore* pListStore, GtkTreeIter& iter, int pos, const OUString* pId, const OUString& rText, const OUString* pIconName, const VirtualDevice* pDevice)
9048 {
9049 if (!pIconName && !pDevice)
9050 {
9051 gtk_list_store_insert_with_values(pListStore, &iter, pos,
9052 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9053 1, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9054 -1);
9055 }
9056 else
9057 {
9058 if (pIconName)
9059 {
9060 GdkPixbuf* pixbuf = getPixbuf(*pIconName);
9061
9062 gtk_list_store_insert_with_values(pListStore, &iter, pos,
9063 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9064 1, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9065 2, pixbuf,
9066 -1);
9067
9068 if (pixbuf)
9069 g_object_unref(pixbuf);
9070 }
9071 else
9072 {
9073 cairo_surface_t* surface = get_underlying_cairo_surface(*pDevice);
9074
9075 Size aSize(pDevice->GetOutputSizePixel());
9076 cairo_surface_t* target = cairo_surface_create_similar(surface,
9077 cairo_surface_get_content(surface),
9078 aSize.Width(),
9079 aSize.Height());
9080
9081 cairo_t* cr = cairo_create(target);
9082 cairo_set_source_surface(cr, surface, 0, 0);
9083 cairo_paint(cr);
9084 cairo_destroy(cr);
9085
9086 gtk_list_store_insert_with_values(pListStore, &iter, pos,
9087 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9088 1, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9089 3, target,
9090 -1);
9091 cairo_surface_destroy(target);
9092 }
9093 }
9094 }
9095}
9096
9097namespace
9098{
9099 gint default_sort_func(GtkTreeModel* pModel, GtkTreeIter* a, GtkTreeIter* b, gpointer data)
9100 {
9101 comphelper::string::NaturalStringSorter* pSorter = static_cast<comphelper::string::NaturalStringSorter*>(data);
9102 gchar* pName1;
9103 gchar* pName2;
9104 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(pModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((pModel)), ((gtk_tree_sortable_get_type ()))))))
;
9105 gint sort_column_id(0);
9106 gtk_tree_sortable_get_sort_column_id(pSortable, &sort_column_id, nullptr);
9107 gtk_tree_model_get(pModel, a, sort_column_id, &pName1, -1);
9108 gtk_tree_model_get(pModel, b, sort_column_id, &pName2, -1);
9109 gint ret = pSorter->compare(OUString(pName1, pName1 ? strlen(pName1) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))),
9110 OUString(pName2, pName2 ? strlen(pName2) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
9111 g_free(pName1);
9112 g_free(pName2);
9113 return ret;
9114 }
9115
9116 int starts_with(GtkTreeModel* pTreeModel, const OUString& rStr, int col, int nStartRow, bool bCaseSensitive)
9117 {
9118 GtkTreeIter iter;
9119 if (!gtk_tree_model_iter_nth_child(pTreeModel, &iter, nullptr, nStartRow))
9120 return -1;
9121
9122 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
9123 int nRet = nStartRow;
9124 do
9125 {
9126 gchar* pStr;
9127 gtk_tree_model_get(pTreeModel, &iter, col, &pStr, -1);
9128 OUString aStr(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
9129 g_free(pStr);
9130 const bool bMatch = !bCaseSensitive ? rI18nHelper.MatchString(rStr, aStr) : aStr.startsWith(rStr);
9131 if (bMatch)
9132 return nRet;
9133 ++nRet;
9134 } while (gtk_tree_model_iter_next(pTreeModel, &iter));
9135
9136 return -1;
9137 }
9138
9139struct GtkInstanceTreeIter : public weld::TreeIter
9140{
9141 GtkInstanceTreeIter(const GtkInstanceTreeIter* pOrig)
9142 {
9143 if (pOrig)
9144 iter = pOrig->iter;
9145 else
9146 memset(&iter, 0, sizeof(iter));
9147 }
9148 GtkInstanceTreeIter(const GtkTreeIter& rOrig)
9149 {
9150 memcpy(&iter, &rOrig, sizeof(iter));
9151 }
9152 virtual bool equal(const TreeIter& rOther) const override
9153 {
9154 return memcmp(&iter, &static_cast<const GtkInstanceTreeIter&>(rOther).iter, sizeof(GtkTreeIter)) == 0;
9155 }
9156 GtkTreeIter iter;
9157};
9158
9159class GtkInstanceTreeView;
9160
9161}
9162
9163static GtkInstanceTreeView* g_DragSource;
9164
9165namespace {
9166
9167struct CompareGtkTreePath
9168{
9169 bool operator()(const GtkTreePath* lhs, const GtkTreePath* rhs) const
9170 {
9171 return gtk_tree_path_compare(lhs, rhs) < 0;
9172 }
9173};
9174
9175int get_height_row(GtkTreeView* pTreeView, GList* pColumns)
9176{
9177 gint nMaxRowHeight = 0;
9178 for (GList* pEntry = g_list_first(pColumns); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
9179 {
9180 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
9181 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
9182 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
9183 {
9184 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
9185 gint nRowHeight;
9186 gtk_cell_renderer_get_preferred_height(pCellRenderer, GTK_WIDGET(pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pTreeView)), ((gtk_widget_get_type ()))))))
, nullptr, &nRowHeight);
9187 nMaxRowHeight = std::max(nMaxRowHeight, nRowHeight);
9188 }
9189 g_list_free(pRenderers);
9190 }
9191 return nMaxRowHeight;
9192}
9193
9194int get_height_row_separator(GtkTreeView* pTreeView)
9195{
9196 gint nVerticalSeparator;
9197 gtk_widget_style_get(GTK_WIDGET(pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pTreeView)), ((gtk_widget_get_type ()))))))
, "vertical-separator", &nVerticalSeparator, nullptr);
9198 return nVerticalSeparator;
9199}
9200
9201int get_height_rows(GtkTreeView* pTreeView, GList* pColumns, int nRows)
9202{
9203 gint nMaxRowHeight = get_height_row(pTreeView, pColumns);
9204 gint nVerticalSeparator = get_height_row_separator(pTreeView);
9205 return (nMaxRowHeight * nRows) + (nVerticalSeparator * (nRows + 1));
9206}
9207
9208int get_height_rows(int nRowHeight, int nSeparatorHeight, int nRows)
9209{
9210 return (nRowHeight * nRows) + (nSeparatorHeight * (nRows + 1));
9211}
9212
9213tools::Rectangle get_row_area(GtkTreeView* pTreeView, GList* pColumns, GtkTreePath* pPath)
9214{
9215 tools::Rectangle aRet;
9216
9217 GdkRectangle aRect;
9218 for (GList* pEntry = g_list_last(pColumns); pEntry; pEntry = g_list_previous(pEntry)((pEntry) ? (((GList *)(pEntry))->prev) : __null))
9219 {
9220 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
9221 gtk_tree_view_get_cell_area(pTreeView, pPath, pColumn, &aRect);
9222 aRet.Union(tools::Rectangle(aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height));
9223 }
9224
9225 return aRet;
9226}
9227
9228struct GtkTreeRowReferenceDeleter
9229{
9230 void operator()(GtkTreeRowReference* p) const
9231 {
9232 gtk_tree_row_reference_free(p);
9233 }
9234};
9235
9236bool separator_function(const GtkTreePath* path, const std::vector<std::unique_ptr<GtkTreeRowReference, GtkTreeRowReferenceDeleter>>& rSeparatorRows)
9237{
9238 bool bFound = false;
9239 for (auto& a : rSeparatorRows)
9240 {
9241 GtkTreePath* seppath = gtk_tree_row_reference_get_path(a.get());
9242 if (seppath)
9243 {
9244 bFound = gtk_tree_path_compare(path, seppath) == 0;
9245 gtk_tree_path_free(seppath);
9246 }
9247 if (bFound)
9248 break;
9249 }
9250 return bFound;
9251}
9252
9253void tree_store_set(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, ...)
9254{
9255 va_list args;
9256
9257 va_start(args, pIter)__builtin_va_start(args, pIter);
9258 gtk_tree_store_set_valist(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter, args);
9259 va_end(args)__builtin_va_end(args);
9260}
9261
9262void list_store_set(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, ...)
9263{
9264 va_list args;
9265
9266 va_start(args, pIter)__builtin_va_start(args, pIter);
9267 gtk_list_store_set_valist(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter, args);
9268 va_end(args)__builtin_va_end(args);
9269}
9270
9271void tree_store_insert_with_values(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, GtkTreeIter *pParent, gint nPos,
9272 gint nTextCol, const gchar* pText,
9273 gint nIdCol, const gchar* pId)
9274{
9275 gtk_tree_store_insert_with_values(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter, pParent, nPos,
9276 nTextCol, pText, nIdCol, pId, -1);
9277}
9278
9279void list_store_insert_with_values(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, GtkTreeIter *pParent, gint nPos,
9280 gint nTextCol, const gchar* pText,
9281 gint nIdCol, const gchar* pId)
9282{
9283 assert(!pParent)(static_cast <bool> (!pParent) ? void (0) : __assert_fail
("!pParent", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 9283, __extension__ __PRETTY_FUNCTION__))
; (void)pParent;
9284 gtk_list_store_insert_with_values(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter, nPos,
9285 nTextCol, pText, nIdCol, pId, -1);
9286}
9287
9288void tree_store_prepend(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, GtkTreeIter *pParent)
9289{
9290 gtk_tree_store_prepend(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter, pParent);
9291}
9292
9293void list_store_prepend(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, GtkTreeIter *pParent)
9294{
9295 assert(!pParent)(static_cast <bool> (!pParent) ? void (0) : __assert_fail
("!pParent", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 9295, __extension__ __PRETTY_FUNCTION__))
; (void)pParent;
9296 gtk_list_store_prepend(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter);
9297}
9298
9299void tree_store_insert(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, GtkTreeIter *pParent, gint nPosition)
9300{
9301 gtk_tree_store_insert(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter, pParent, nPosition);
9302}
9303
9304void list_store_insert(GtkTreeModel* pTreeModel, GtkTreeIter *pIter, GtkTreeIter *pParent, gint nPosition)
9305{
9306 assert(!pParent)(static_cast <bool> (!pParent) ? void (0) : __assert_fail
("!pParent", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 9306, __extension__ __PRETTY_FUNCTION__))
; (void)pParent;
9307 gtk_list_store_insert(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter, nPosition);
9308}
9309
9310void tree_store_clear(GtkTreeModel* pTreeModel)
9311{
9312 gtk_tree_store_clear(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
);
9313}
9314
9315void list_store_clear(GtkTreeModel* pTreeModel)
9316{
9317 gtk_list_store_clear(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
);
9318}
9319
9320void tree_store_remove(GtkTreeModel* pTreeModel, GtkTreeIter *pIter)
9321{
9322 gtk_tree_store_remove(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter);
9323}
9324
9325void list_store_remove(GtkTreeModel* pTreeModel, GtkTreeIter *pIter)
9326{
9327 gtk_list_store_remove(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter);
9328}
9329
9330void tree_store_swap(GtkTreeModel* pTreeModel, GtkTreeIter* pIter1, GtkTreeIter* pIter2)
9331{
9332 gtk_tree_store_swap(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter1, pIter2);
9333}
9334
9335void list_store_swap(GtkTreeModel* pTreeModel, GtkTreeIter* pIter1, GtkTreeIter* pIter2)
9336{
9337 gtk_list_store_swap(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter1, pIter2);
9338}
9339
9340void tree_store_set_value(GtkTreeModel* pTreeModel, GtkTreeIter* pIter, gint nColumn, GValue* pValue)
9341{
9342 gtk_tree_store_set_value(GTK_TREE_STORE(pTreeModel)((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_tree_store_get_type ()))))))
, pIter, nColumn, pValue);
9343}
9344
9345void list_store_set_value(GtkTreeModel* pTreeModel, GtkTreeIter* pIter, gint nColumn, GValue* pValue)
9346{
9347 gtk_list_store_set_value(GTK_LIST_STORE(pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeModel)), ((gtk_list_store_get_type ()))))))
, pIter, nColumn, pValue);
9348}
9349
9350int promote_arg(bool bArg)
9351{
9352 return static_cast<int>(bArg);
9353}
9354
9355class GtkInstanceTreeView : public GtkInstanceContainer, public virtual weld::TreeView
9356{
9357private:
9358 GtkTreeView* m_pTreeView;
9359 GtkTreeModel* m_pTreeModel;
9360
9361 typedef void(*setterFnc)(GtkTreeModel*, GtkTreeIter*, ...);
9362 setterFnc m_Setter;
9363
9364 typedef void(*insertWithValuesFnc)(GtkTreeModel*, GtkTreeIter*, GtkTreeIter*, gint, gint, const gchar*, gint, const gchar*);
9365 insertWithValuesFnc m_InsertWithValues;
9366
9367 typedef void(*insertFnc)(GtkTreeModel*, GtkTreeIter*, GtkTreeIter*, gint);
9368 insertFnc m_Insert;
9369
9370 typedef void(*prependFnc)(GtkTreeModel*, GtkTreeIter*, GtkTreeIter*);
9371 prependFnc m_Prepend;
9372
9373 typedef void(*clearFnc)(GtkTreeModel*);
9374 clearFnc m_Clear;
9375
9376 typedef void(*removeFnc)(GtkTreeModel*, GtkTreeIter*);
9377 removeFnc m_Remove;
9378
9379 typedef void(*swapFnc)(GtkTreeModel*, GtkTreeIter*, GtkTreeIter*);
9380 swapFnc m_Swap;
9381
9382 typedef void(*setValueFnc)(GtkTreeModel*, GtkTreeIter*, gint, GValue*);
9383 setValueFnc m_SetValue;
9384
9385 std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter;
9386 GList *m_pColumns;
9387 std::vector<gulong> m_aColumnSignalIds;
9388 // map from toggle column to toggle visibility column
9389 std::map<int, int> m_aToggleVisMap;
9390 // map from toggle column to tristate column
9391 std::map<int, int> m_aToggleTriStateMap;
9392 // map from text column to text weight column
9393 std::map<int, int> m_aWeightMap;
9394 // map from text column to sensitive column
9395 std::map<int, int> m_aSensitiveMap;
9396 // map from text column to indent column
9397 std::map<int, int> m_aIndentMap;
9398 // map from text column to text align column
9399 std::map<int, int> m_aAlignMap;
9400 // currently expanding parent that logically, but not currently physically,
9401 // contain placeholders
9402 o3tl::sorted_vector<GtkTreePath*, CompareGtkTreePath> m_aExpandingPlaceHolderParents;
9403 // which rows are separators (rare)
9404 std::vector<std::unique_ptr<GtkTreeRowReference, GtkTreeRowReferenceDeleter>> m_aSeparatorRows;
9405 std::vector<GtkSortType> m_aSavedSortTypes;
9406 std::vector<int> m_aSavedSortColumns;
9407 bool m_bWorkAroundBadDragRegion;
9408 bool m_bInDrag;
9409 gint m_nTextCol;
9410 gint m_nTextView;
9411 gint m_nImageCol;
9412 gint m_nExpanderToggleCol;
9413 gint m_nExpanderImageCol;
9414 gint m_nIdCol;
9415 int m_nPendingVAdjustment;
9416 gulong m_nChangedSignalId;
9417 gulong m_nRowActivatedSignalId;
9418 gulong m_nTestExpandRowSignalId;
9419 gulong m_nTestCollapseRowSignalId;
9420 gulong m_nVAdjustmentChangedSignalId;
9421 gulong m_nRowDeletedSignalId;
9422 gulong m_nRowInsertedSignalId;
9423 gulong m_nPopupMenuSignalId;
9424 gulong m_nKeyPressSignalId;
9425 gulong m_nQueryTooltipSignalId;
9426 GtkAdjustment* m_pVAdjustment;
9427 ImplSVEvent* m_pChangeEvent;
9428
9429 DECL_LINK(async_signal_changed, void*, void)static void LinkStubasync_signal_changed(void *, void*); void
async_signal_changed(void*)
;
9430
9431 void launch_signal_changed()
9432 {
9433 //tdf#117991 selection change is sent before the focus change, and focus change
9434 //is what will cause a spinbutton that currently has the focus to set its contents
9435 //as the spin button value. So any LibreOffice callbacks on
9436 //signal-change would happen before the spinbutton value-change occurs.
9437 //To avoid this, send the signal-change to LibreOffice to occur after focus-change
9438 //has been processed
9439 if (m_pChangeEvent)
9440 Application::RemoveUserEvent(m_pChangeEvent);
9441 m_pChangeEvent = Application::PostUserEvent(LINK(this, GtkInstanceTreeView, async_signal_changed)::tools::detail::makeLink( ::tools::detail::castTo<GtkInstanceTreeView
*>(this), &GtkInstanceTreeView::LinkStubasync_signal_changed
)
);
9442 }
9443
9444 static void signalChanged(GtkTreeView*, gpointer widget)
9445 {
9446 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9447 pThis->launch_signal_changed();
9448 }
9449
9450 void handle_row_activated()
9451 {
9452 if (signal_row_activated())
9453 return;
9454 GtkInstanceTreeIter aIter(nullptr);
9455 if (!get_cursor(&aIter))
9456 return;
9457 if (gtk_tree_model_iter_has_child(m_pTreeModel, &aIter.iter))
9458 get_row_expanded(aIter) ? collapse_row(aIter) : expand_row(aIter);
9459 }
9460
9461 static void signalRowActivated(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer widget)
9462 {
9463 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9464 SolarMutexGuard aGuard;
9465 pThis->handle_row_activated();
9466 }
9467
9468 virtual bool signal_popup_menu(const CommandEvent& rCEvt) override
9469 {
9470 return m_aPopupMenuHdl.Call(rCEvt);
9471 }
9472
9473 void insert_row(GtkTreeIter& iter, const GtkTreeIter* parent, int pos, const OUString* pId, const OUString* pText,
9474 const OUString* pIconName, const VirtualDevice* pDevice)
9475 {
9476 m_InsertWithValues(m_pTreeModel, &iter, const_cast<GtkTreeIter*>(parent), pos,
9477 m_nTextCol, !pText ? nullptr : OUStringToOString(*pText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
9478 m_nIdCol, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
9479
9480 if (pIconName)
9481 {
9482 GdkPixbuf* pixbuf = getPixbuf(*pIconName);
9483 m_Setter(m_pTreeModel, &iter, m_nImageCol, pixbuf, -1);
9484 if (pixbuf)
9485 g_object_unref(pixbuf);
9486 }
9487 else if (pDevice)
9488 {
9489 cairo_surface_t* surface = get_underlying_cairo_surface(*pDevice);
9490
9491 Size aSize(pDevice->GetOutputSizePixel());
9492 cairo_surface_t* target = cairo_surface_create_similar(surface,
9493 cairo_surface_get_content(surface),
9494 aSize.Width(),
9495 aSize.Height());
9496
9497 cairo_t* cr = cairo_create(target);
9498 cairo_set_source_surface(cr, surface, 0, 0);
9499 cairo_paint(cr);
9500 cairo_destroy(cr);
9501
9502 m_Setter(m_pTreeModel, &iter, m_nImageCol, target, -1);
9503 cairo_surface_destroy(target);
9504 }
9505 }
9506
9507 bool separator_function(const GtkTreePath* path)
9508 {
9509 return ::separator_function(path, m_aSeparatorRows);
9510 }
9511
9512 static gboolean separatorFunction(GtkTreeModel* pTreeModel, GtkTreeIter* pIter, gpointer widget)
9513 {
9514 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9515 GtkTreePath* path = gtk_tree_model_get_path(pTreeModel, pIter);
9516 bool bRet = pThis->separator_function(path);
9517 gtk_tree_path_free(path);
9518 return bRet;
9519 }
9520
9521 OUString get(const GtkTreeIter& iter, int col) const
9522 {
9523 gchar* pStr;
9524 gtk_tree_model_get(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, &pStr, -1);
9525 OUString sRet(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
9526 g_free(pStr);
9527 return sRet;
9528 }
9529
9530 OUString get(int pos, int col) const
9531 {
9532 OUString sRet;
9533 GtkTreeIter iter;
9534 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9535 sRet = get(iter, col);
9536 return sRet;
9537 }
9538
9539 gint get_int(const GtkTreeIter& iter, int col) const
9540 {
9541 gint nRet(-1);
9542 gtk_tree_model_get(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, &nRet, -1);
9543 return nRet;
9544 }
9545
9546 gint get_int(int pos, int col) const
9547 {
9548 gint nRet(-1);
9549 GtkTreeIter iter;
9550 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9551 nRet = get_int(iter, col);
9552 gtk_tree_model_get(m_pTreeModel, &iter, col, &nRet, -1);
9553 return nRet;
9554 }
9555
9556 bool get_bool(const GtkTreeIter& iter, int col) const
9557 {
9558 gboolean bRet(false);
9559 gtk_tree_model_get(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, &bRet, -1);
9560 return bRet;
9561 }
9562
9563 bool get_bool(int pos, int col) const
9564 {
9565 bool bRet(false);
9566 GtkTreeIter iter;
9567 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9568 bRet = get_bool(iter, col);
9569 return bRet;
9570 }
9571
9572 void set_toggle(const GtkTreeIter& iter, TriState eState, int col)
9573 {
9574 if (col == -1)
9575 col = m_nExpanderToggleCol;
9576 else
9577 col = to_internal_model(col);
9578
9579 if (eState == TRISTATE_INDET)
9580 {
9581 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter),
9582 m_aToggleVisMap[col], promote_arg(true), // checkbuttons are invisible until toggled on or off
9583 m_aToggleTriStateMap[col], promote_arg(true), // tristate on
9584 -1);
9585 }
9586 else
9587 {
9588 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter),
9589 m_aToggleVisMap[col], promote_arg(true), // checkbuttons are invisible until toggled on or off
9590 m_aToggleTriStateMap[col], promote_arg(false), // tristate off
9591 col, promote_arg(eState == TRISTATE_TRUE), // set toggle state
9592 -1);
9593 }
9594 }
9595
9596 void set(const GtkTreeIter& iter, int col, const OUString& rText)
9597 {
9598 OString aStr(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
9599 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, aStr.getStr(), -1);
9600 }
9601
9602 void set(int pos, int col, const OUString& rText)
9603 {
9604 GtkTreeIter iter;
9605 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9606 set(iter, col, rText);
9607 }
9608
9609 void set(const GtkTreeIter& iter, int col, bool bOn)
9610 {
9611 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, promote_arg(bOn), -1);
9612 }
9613
9614 void set(int pos, int col, bool bOn)
9615 {
9616 GtkTreeIter iter;
9617 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9618 set(iter, col, bOn);
9619 }
9620
9621 void set(const GtkTreeIter& iter, int col, gint bInt)
9622 {
9623 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, bInt, -1);
9624 }
9625
9626 void set(int pos, int col, gint bInt)
9627 {
9628 GtkTreeIter iter;
9629 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9630 set(iter, col, bInt);
9631 }
9632
9633 void set(const GtkTreeIter& iter, int col, double fValue)
9634 {
9635 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, fValue, -1);
9636 }
9637
9638 void set(int pos, int col, double fValue)
9639 {
9640 GtkTreeIter iter;
9641 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
9642 set(iter, col, fValue);
9643 }
9644
9645 static gboolean signalTestExpandRow(GtkTreeView*, GtkTreeIter* iter, GtkTreePath*, gpointer widget)
9646 {
9647 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9648 return !pThis->signal_test_expand_row(*iter);
9649 }
9650
9651 static gboolean signalTestCollapseRow(GtkTreeView*, GtkTreeIter* iter, GtkTreePath*, gpointer widget)
9652 {
9653 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9654 return !pThis->signal_test_collapse_row(*iter);
9655 }
9656
9657 bool child_is_placeholder(GtkInstanceTreeIter& rGtkIter) const
9658 {
9659 GtkTreePath* pPath = gtk_tree_model_get_path(m_pTreeModel, &rGtkIter.iter);
9660 bool bExpanding = m_aExpandingPlaceHolderParents.count(pPath);
9661 gtk_tree_path_free(pPath);
9662 if (bExpanding)
9663 return true;
9664
9665 bool bPlaceHolder = false;
9666 GtkTreeIter tmp;
9667 if (gtk_tree_model_iter_children(m_pTreeModel, &tmp, &rGtkIter.iter))
9668 {
9669 rGtkIter.iter = tmp;
9670 if (get_text(rGtkIter, -1) == "<dummy>")
9671 {
9672 bPlaceHolder = true;
9673 }
9674 }
9675 return bPlaceHolder;
9676 }
9677
9678 bool signal_test_expand_row(GtkTreeIter& iter)
9679 {
9680 disable_notify_events();
9681
9682 // if there's a preexisting placeholder child, required to make this
9683 // potentially expandable in the first place, now we remove it
9684 GtkInstanceTreeIter aIter(iter);
9685 GtkTreePath* pPlaceHolderPath = nullptr;
9686 bool bPlaceHolder = child_is_placeholder(aIter);
9687 if (bPlaceHolder)
9688 {
9689 m_Remove(m_pTreeModel, &aIter.iter);
9690
9691 pPlaceHolderPath = gtk_tree_model_get_path(m_pTreeModel, &iter);
9692 m_aExpandingPlaceHolderParents.insert(pPlaceHolderPath);
9693 }
9694
9695 aIter.iter = iter;
9696 bool bRet = signal_expanding(aIter);
9697
9698 if (bPlaceHolder)
9699 {
9700 //expand disallowed, restore placeholder
9701 if (!bRet)
9702 {
9703 GtkTreeIter subiter;
9704 OUString sDummy("<dummy>");
9705 insert_row(subiter, &iter, -1, nullptr, &sDummy, nullptr, nullptr);
9706 }
9707 m_aExpandingPlaceHolderParents.erase(pPlaceHolderPath);
9708 gtk_tree_path_free(pPlaceHolderPath);
9709 }
9710
9711 enable_notify_events();
9712 return bRet;
9713 }
9714
9715 bool signal_test_collapse_row(const GtkTreeIter& iter)
9716 {
9717 disable_notify_events();
9718
9719 GtkInstanceTreeIter aIter(iter);
9720 bool bRet = signal_collapsing(aIter);
9721
9722 enable_notify_events();
9723 return bRet;
9724 }
9725
9726 static void signalCellToggled(GtkCellRendererToggle* pCell, const gchar *path, gpointer widget)
9727 {
9728 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9729 void* pData = g_object_get_data(G_OBJECT(pCell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCell)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex");
9730 pThis->signal_cell_toggled(path, reinterpret_cast<sal_IntPtr>(pData));
9731 }
9732
9733 void signal_cell_toggled(const gchar *path, int nCol)
9734 {
9735 GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
9736
9737 // additionally set the cursor into the row the toggled element is in
9738 gtk_tree_view_set_cursor(m_pTreeView, tree_path, nullptr, false);
9739
9740 GtkTreeIter iter;
9741 gtk_tree_model_get_iter(m_pTreeModel, &iter, tree_path);
9742
9743 gboolean bRet(false);
9744 gtk_tree_model_get(m_pTreeModel, &iter, nCol, &bRet, -1);
9745 bRet = !bRet;
9746 m_Setter(m_pTreeModel, &iter, nCol, bRet, -1);
9747
9748 set(iter, m_aToggleTriStateMap[nCol], false);
9749
9750 signal_toggled(iter_col(GtkInstanceTreeIter(iter), to_external_model(nCol)));
9751
9752 gtk_tree_path_free(tree_path);
9753 }
9754
9755 DECL_LINK(async_stop_cell_editing, void*, void)static void LinkStubasync_stop_cell_editing(void *, void*); void
async_stop_cell_editing(void*)
;
9756
9757 static void signalCellEditingStarted(GtkCellRenderer*, GtkCellEditable*, const gchar *path, gpointer widget)
9758 {
9759 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9760 if (!pThis->signal_cell_editing_started(path))
9761 Application::PostUserEvent(LINK(pThis, GtkInstanceTreeView, async_stop_cell_editing)::tools::detail::makeLink( ::tools::detail::castTo<GtkInstanceTreeView
*>(pThis), &GtkInstanceTreeView::LinkStubasync_stop_cell_editing
)
);
9762 }
9763
9764 bool signal_cell_editing_started(const gchar *path)
9765 {
9766 GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
9767
9768 GtkInstanceTreeIter aGtkIter(nullptr);
9769 gtk_tree_model_get_iter(m_pTreeModel, &aGtkIter.iter, tree_path);
9770 gtk_tree_path_free(tree_path);
9771
9772 return signal_editing_started(aGtkIter);
9773 }
9774
9775 static void signalCellEdited(GtkCellRendererText* pCell, const gchar *path, const gchar *pNewText, gpointer widget)
9776 {
9777 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9778 pThis->signal_cell_edited(pCell, path, pNewText);
9779 }
9780
9781 static void restoreNonEditable(GObject* pCell)
9782 {
9783 if (g_object_get_data(pCell, "g-lo-RestoreNonEditable"))
9784 {
9785 g_object_set(pCell, "editable", false, "editable-set", false, nullptr);
9786 g_object_set_data(pCell, "g-lo-RestoreNonEditable", reinterpret_cast<gpointer>(false));
9787 }
9788 }
9789
9790 void signal_cell_edited(GtkCellRendererText* pCell, const gchar *path, const gchar* pNewText)
9791 {
9792 GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
9793
9794 GtkInstanceTreeIter aGtkIter(nullptr);
9795 gtk_tree_model_get_iter(m_pTreeModel, &aGtkIter.iter, tree_path);
9796 gtk_tree_path_free(tree_path);
9797
9798 OUString sText(pNewText, pNewText ? strlen(pNewText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
9799 if (signal_editing_done(iter_string(aGtkIter, sText)))
9800 {
9801 void* pData = g_object_get_data(G_OBJECT(pCell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCell)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex");
9802 set(aGtkIter.iter, reinterpret_cast<sal_IntPtr>(pData), sText);
9803 }
9804
9805 restoreNonEditable(G_OBJECT(pCell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCell)), (((GType) ((20) << (2))))))))
);
9806 }
9807
9808 static void signalCellEditingCanceled(GtkCellRenderer* pCell, gpointer /*widget*/)
9809 {
9810 restoreNonEditable(G_OBJECT(pCell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCell)), (((GType) ((20) << (2))))))))
);
9811 }
9812
9813 void signal_column_clicked(GtkTreeViewColumn* pClickedColumn)
9814 {
9815 int nIndex(0);
9816 for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
9817 {
9818 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
9819 if (pColumn == pClickedColumn)
9820 {
9821 TreeView::signal_column_clicked(nIndex);
9822 break;
9823 }
9824 ++nIndex;
9825 }
9826 }
9827
9828 static void signalColumnClicked(GtkTreeViewColumn* pColumn, gpointer widget)
9829 {
9830 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9831 pThis->signal_column_clicked(pColumn);
9832 }
9833
9834 static void signalVAdjustmentChanged(GtkAdjustment*, gpointer widget)
9835 {
9836 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9837 pThis->signal_visible_range_changed();
9838 }
9839
9840 // The outside concept of a column maps to a gtk CellRenderer, rather than
9841 // a TreeViewColumn. If the first TreeViewColumn has a leading Toggle Renderer
9842 // and/or a leading Image Renderer, those are considered special expander
9843 // columns and precede index 0 and can be accessed via outside index -1
9844 int to_external_model(int modelcol) const
9845 {
9846 if (m_nExpanderToggleCol != -1)
9847 --modelcol;
9848 if (m_nExpanderImageCol != -1)
9849 --modelcol;
9850 return modelcol;
9851 }
9852
9853 int to_internal_model(int modelcol) const
9854 {
9855 if (m_nExpanderToggleCol != -1)
9856 ++modelcol;
9857 if (m_nExpanderImageCol != -1)
9858 ++modelcol;
9859 return modelcol;
9860 }
9861
9862 void set_column_editable(int nCol, bool bEditable)
9863 {
9864 nCol = to_internal_model(nCol);
9865
9866 for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
9867 {
9868 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
9869 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
9870 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
9871 {
9872 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
9873 void* pData = g_object_get_data(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex");
9874 if (reinterpret_cast<sal_IntPtr>(pData) == nCol)
9875 {
9876 g_object_set(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "editable", bEditable, "editable-set", true, nullptr);
9877 break;
9878 }
9879 }
9880 g_list_free(pRenderers);
9881 }
9882 }
9883
9884 static void signalRowDeleted(GtkTreeModel*, GtkTreePath*, gpointer widget)
9885 {
9886 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9887 pThis->signal_model_changed();
9888 }
9889
9890 static void signalRowInserted(GtkTreeModel*, GtkTreePath*, GtkTreeIter*, gpointer widget)
9891 {
9892 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9893 pThis->signal_model_changed();
9894 }
9895
9896 static gint sortFunc(GtkTreeModel* pModel, GtkTreeIter* a, GtkTreeIter* b, gpointer widget)
9897 {
9898 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9899 return pThis->sort_func(pModel, a, b);
9900 }
9901
9902 gint sort_func(GtkTreeModel* pModel, GtkTreeIter* a, GtkTreeIter* b)
9903 {
9904 if (m_aCustomSort)
9905 return m_aCustomSort(GtkInstanceTreeIter(*a), GtkInstanceTreeIter(*b));
9906 return default_sort_func(pModel, a, b, m_xSorter.get());
9907 }
9908
9909 bool signal_key_press(GdkEventKey* pEvent)
9910 {
9911 if (pEvent->keyval != GDK_KEY_Left0xff51 && pEvent->keyval != GDK_KEY_Right0xff53)
9912 return false;
9913
9914 GtkInstanceTreeIter aIter(nullptr);
9915 if (!get_cursor(&aIter))
9916 return false;
9917
9918 bool bHasChild = gtk_tree_model_iter_has_child(m_pTreeModel, &aIter.iter);
9919
9920 if (pEvent->keyval == GDK_KEY_Right0xff53)
9921 {
9922 if (bHasChild && !get_row_expanded(aIter))
9923 {
9924 expand_row(aIter);
9925 return true;
9926 }
9927 return false;
9928 }
9929
9930 if (bHasChild && get_row_expanded(aIter))
9931 {
9932 collapse_row(aIter);
9933 return true;
9934 }
9935
9936 if (iter_parent(aIter))
9937 {
9938 unselect_all();
9939 set_cursor(aIter);
9940 select(aIter);
9941 return true;
9942 }
9943
9944 return false;
9945 }
9946
9947 static gboolean signalKeyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
9948 {
9949 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9950 return pThis->signal_key_press(pEvent);
9951 }
9952
9953 static gboolean signalQueryTooltip(GtkWidget* /*pGtkWidget*/, gint x, gint y,
9954 gboolean keyboard_tip, GtkTooltip *tooltip,
9955 gpointer widget)
9956 {
9957 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
9958 GtkTreeIter iter;
9959 GtkTreeView *pTreeView = pThis->m_pTreeView;
9960 GtkTreeModel *pModel = gtk_tree_view_get_model(pTreeView);
9961 GtkTreePath *pPath = nullptr;
9962 if (!gtk_tree_view_get_tooltip_context(pTreeView, &x, &y, keyboard_tip, &pModel, &pPath, &iter))
9963 return false;
9964 OUString aTooltip = pThis->signal_query_tooltip(GtkInstanceTreeIter(iter));
9965 if (aTooltip.isEmpty())
9966 return false;
9967 gtk_tooltip_set_text(tooltip, OUStringToOString(aTooltip, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
9968 gtk_tree_view_set_tooltip_row(pTreeView, tooltip, pPath);
9969 gtk_tree_path_free(pPath);
9970 return true;
9971 }
9972
9973 void last_child(GtkTreeModel* pModel, GtkTreeIter* result, GtkTreeIter* pParent, int nChildren) const
9974 {
9975 gtk_tree_model_iter_nth_child(pModel, result, pParent, nChildren - 1);
9976 nChildren = gtk_tree_model_iter_n_children(pModel, result);
9977 if (nChildren)
9978 {
9979 GtkTreeIter newparent(*result);
9980 last_child(pModel, result, &newparent, nChildren);
9981 }
9982 }
9983
9984 GtkTreePath* get_path_of_last_entry(GtkTreeModel *pModel)
9985 {
9986 GtkTreePath *lastpath;
9987 // find the last entry in the model for comparison
9988 int nChildren = gtk_tree_model_iter_n_children(pModel, nullptr);
9989 if (!nChildren)
9990 lastpath = gtk_tree_path_new_from_indices(0, -1);
9991 else
9992 {
9993 GtkTreeIter iter;
9994 last_child(pModel, &iter, nullptr, nChildren);
9995 lastpath = gtk_tree_model_get_path(pModel, &iter);
9996 }
9997 return lastpath;
9998 }
9999
10000 void set_font_color(const GtkTreeIter& iter, const Color& rColor)
10001 {
10002 if (rColor == COL_AUTO)
10003 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), m_nIdCol + 1, nullptr, -1);
10004 else
10005 {
10006 GdkRGBA aColor{rColor.GetRed()/255.0, rColor.GetGreen()/255.0, rColor.GetBlue()/255.0, 0};
10007 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), m_nIdCol + 1, &aColor, -1);
10008 }
10009 }
10010
10011 int get_expander_size() const
10012 {
10013 gint nExpanderSize;
10014 gint nHorizontalSeparator;
10015
10016 gtk_widget_style_get(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
,
10017 "expander-size", &nExpanderSize,
10018 "horizontal-separator", &nHorizontalSeparator,
10019 nullptr);
10020
10021 return nExpanderSize + (nHorizontalSeparator/ 2);
10022 }
10023
10024 void real_vadjustment_set_value(int value)
10025 {
10026 disable_notify_events();
10027 gtk_adjustment_set_value(m_pVAdjustment, value);
10028 enable_notify_events();
10029 }
10030
10031 static gboolean setAdjustmentCallback(GtkWidget*, GdkFrameClock*, gpointer widget)
10032 {
10033 GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
10034 if (pThis->m_nPendingVAdjustment != -1)
10035 {
10036 pThis->real_vadjustment_set_value(pThis->m_nPendingVAdjustment);
10037 pThis->m_nPendingVAdjustment = -1;
10038 }
10039 return false;
10040 }
10041
10042 bool iter_next(weld::TreeIter& rIter, bool bOnlyExpanded) const
10043 {
10044 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
10045 GtkTreeIter tmp;
10046 GtkTreeIter iter = rGtkIter.iter;
10047
10048 bool ret = gtk_tree_model_iter_children(m_pTreeModel, &tmp, &iter);
10049 if (ret && bOnlyExpanded && !get_row_expanded(rGtkIter))
10050 ret = false;
10051 rGtkIter.iter = tmp;
10052 if (ret)
10053 {
10054 //on-demand dummy entry doesn't count
10055 if (get_text(rGtkIter, -1) == "<dummy>")
10056 return iter_next(rGtkIter, bOnlyExpanded);
10057 return true;
10058 }
10059
10060 tmp = iter;
10061 if (gtk_tree_model_iter_next(m_pTreeModel, &tmp))
10062 {
10063 rGtkIter.iter = tmp;
10064 //on-demand dummy entry doesn't count
10065 if (get_text(rGtkIter, -1) == "<dummy>")
10066 return iter_next(rGtkIter, bOnlyExpanded);
10067 return true;
10068 }
10069 // Move up level(s) until we find the level where the next node exists.
10070 while (gtk_tree_model_iter_parent(m_pTreeModel, &tmp, &iter))
10071 {
10072 iter = tmp;
10073 if (gtk_tree_model_iter_next(m_pTreeModel, &tmp))
10074 {
10075 rGtkIter.iter = tmp;
10076 //on-demand dummy entry doesn't count
10077 if (get_text(rGtkIter, -1) == "<dummy>")
10078 return iter_next(rGtkIter, bOnlyExpanded);
10079 return true;
10080 }
10081 }
10082 return false;
10083 }
10084
10085public:
10086 GtkInstanceTreeView(GtkTreeView* pTreeView, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
10087 : GtkInstanceContainer(GTK_CONTAINER(pTreeView)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeView)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
10088 , m_pTreeView(pTreeView)
10089 , m_pTreeModel(gtk_tree_view_get_model(m_pTreeView))
10090 , m_bWorkAroundBadDragRegion(false)
10091 , m_bInDrag(false)
10092 , m_nTextCol(-1)
10093 , m_nTextView(-1)
10094 , m_nImageCol(-1)
10095 , m_nExpanderToggleCol(-1)
10096 , m_nExpanderImageCol(-1)
10097 , m_nPendingVAdjustment(-1)
10098 , m_nChangedSignalId(g_signal_connect(gtk_tree_view_get_selection(pTreeView), "changed",g_signal_connect_data ((gtk_tree_view_get_selection(pTreeView
)), ("changed"), (((GCallback) (signalChanged))), (this), __null
, (GConnectFlags) 0)
10099 G_CALLBACK(signalChanged), this)g_signal_connect_data ((gtk_tree_view_get_selection(pTreeView
)), ("changed"), (((GCallback) (signalChanged))), (this), __null
, (GConnectFlags) 0)
)
10100 , m_nRowActivatedSignalId(g_signal_connect(pTreeView, "row-activated", G_CALLBACK(signalRowActivated), this)g_signal_connect_data ((pTreeView), ("row-activated"), (((GCallback
) (signalRowActivated))), (this), __null, (GConnectFlags) 0)
)
10101 , m_nTestExpandRowSignalId(g_signal_connect(pTreeView, "test-expand-row", G_CALLBACK(signalTestExpandRow), this)g_signal_connect_data ((pTreeView), ("test-expand-row"), (((GCallback
) (signalTestExpandRow))), (this), __null, (GConnectFlags) 0)
)
10102 , m_nTestCollapseRowSignalId(g_signal_connect(pTreeView, "test-collapse-row", G_CALLBACK(signalTestCollapseRow), this)g_signal_connect_data ((pTreeView), ("test-collapse-row"), ((
(GCallback) (signalTestCollapseRow))), (this), __null, (GConnectFlags
) 0)
)
10103 , m_nVAdjustmentChangedSignalId(0)
10104 , m_nPopupMenuSignalId(g_signal_connect(pTreeView, "popup-menu", G_CALLBACK(signalPopupMenu), this)g_signal_connect_data ((pTreeView), ("popup-menu"), (((GCallback
) (signalPopupMenu))), (this), __null, (GConnectFlags) 0)
)
10105 , m_nKeyPressSignalId(g_signal_connect(pTreeView, "key-press-event", G_CALLBACK(signalKeyPress), this)g_signal_connect_data ((pTreeView), ("key-press-event"), (((GCallback
) (signalKeyPress))), (this), __null, (GConnectFlags) 0)
)
10106 , m_nQueryTooltipSignalId(0)
10107 , m_pVAdjustment(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(pTreeView)((((GtkScrollable*) g_type_check_instance_cast ((GTypeInstance
*) ((pTreeView)), ((gtk_scrollable_get_type ()))))))
))
10108 , m_pChangeEvent(nullptr)
10109 {
10110 if (GTK_IS_TREE_STORE(m_pTreeModel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pTreeModel)); GType __t = ((gtk_tree_store_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
10111 {
10112 m_Setter = tree_store_set;
10113 m_InsertWithValues = tree_store_insert_with_values;
10114 m_Insert = tree_store_insert;
10115 m_Prepend = tree_store_prepend;
10116 m_Remove = tree_store_remove;
10117 m_Swap = tree_store_swap;
10118 m_SetValue = tree_store_set_value;
10119 m_Clear = tree_store_clear;
10120 }
10121 else
10122 {
10123 /*
10124 tdf#136559 see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2693
10125 If we only need a list and not a tree we can get a performance boost from using a ListStore
10126 */
10127 assert(!gtk_tree_view_get_show_expanders(m_pTreeView) && "a liststore can only be used if no tree structure is needed")(static_cast <bool> (!gtk_tree_view_get_show_expanders(
m_pTreeView) && "a liststore can only be used if no tree structure is needed"
) ? void (0) : __assert_fail ("!gtk_tree_view_get_show_expanders(m_pTreeView) && \"a liststore can only be used if no tree structure is needed\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10127, __extension__ __PRETTY_FUNCTION__))
;
10128 m_Setter = list_store_set;
10129 m_InsertWithValues = list_store_insert_with_values;
10130 m_Insert = list_store_insert;
10131 m_Prepend = list_store_prepend;
10132 m_Remove = list_store_remove;
10133 m_Swap = list_store_swap;
10134 m_SetValue = list_store_set_value;
10135 m_Clear = list_store_clear;
10136 }
10137
10138 /* The outside concept of a column maps to a gtk CellRenderer, rather than
10139 a TreeViewColumn. If the first TreeViewColumn has a leading Toggle Renderer
10140 and/or a leading Image Renderer, those are considered special expander
10141 columns and precede index 0 and can be accessed via outside index -1
10142 */
10143 m_pColumns = gtk_tree_view_get_columns(m_pTreeView);
10144 int nIndex(0);
10145 int nViewColumn(0);
10146 for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
10147 {
10148 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
10149 m_aColumnSignalIds.push_back(g_signal_connect(pColumn, "clicked", G_CALLBACK(signalColumnClicked), this)g_signal_connect_data ((pColumn), ("clicked"), (((GCallback) (
signalColumnClicked))), (this), __null, (GConnectFlags) 0)
);
10150 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
10151 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
10152 {
10153 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
10154 if (GTK_IS_CELL_RENDERER_TEXT(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_text_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10155 {
10156 if (m_nTextCol == -1)
10157 {
10158 m_nTextCol = nIndex;
10159 m_nTextView = nViewColumn;
10160 }
10161 m_aWeightMap[nIndex] = -1;
10162 m_aSensitiveMap[nIndex] = -1;
10163 m_aIndentMap[nIndex] = -1;
10164 m_aAlignMap[nIndex] = -1;
10165 g_signal_connect(G_OBJECT(pCellRenderer), "editing-started", G_CALLBACK(signalCellEditingStarted), this)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((pCellRenderer)), (((GType) ((20) <<
(2))))))))), ("editing-started"), (((GCallback) (signalCellEditingStarted
))), (this), __null, (GConnectFlags) 0)
;
10166 g_signal_connect(G_OBJECT(pCellRenderer), "editing-canceled", G_CALLBACK(signalCellEditingCanceled), this)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((pCellRenderer)), (((GType) ((20) <<
(2))))))))), ("editing-canceled"), (((GCallback) (signalCellEditingCanceled
))), (this), __null, (GConnectFlags) 0)
;
10167 g_signal_connect(G_OBJECT(pCellRenderer), "edited", G_CALLBACK(signalCellEdited), this)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((pCellRenderer)), (((GType) ((20) <<
(2))))))))), ("edited"), (((GCallback) (signalCellEdited))),
(this), __null, (GConnectFlags) 0)
;
10168 }
10169 else if (GTK_IS_CELL_RENDERER_TOGGLE(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_toggle_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10170 {
10171 const bool bExpander = nIndex == 0 || (nIndex == 1 && m_nExpanderImageCol == 0);
10172 if (bExpander)
10173 m_nExpanderToggleCol = nIndex;
10174 g_signal_connect(G_OBJECT(pCellRenderer), "toggled", G_CALLBACK(signalCellToggled), this)g_signal_connect_data ((((((GObject*) g_type_check_instance_cast
((GTypeInstance*) ((pCellRenderer)), (((GType) ((20) <<
(2))))))))), ("toggled"), (((GCallback) (signalCellToggled))
), (this), __null, (GConnectFlags) 0)
;
10175 m_aToggleVisMap[nIndex] = -1;
10176 m_aToggleTriStateMap[nIndex] = -1;
10177 }
10178 else if (GTK_IS_CELL_RENDERER_PIXBUF(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_pixbuf_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10179 {
10180 const bool bExpander = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null) != nullptr;
10181 if (bExpander && m_nExpanderImageCol == -1)
10182 m_nExpanderImageCol = nIndex;
10183 else if (m_nImageCol == -1)
10184 m_nImageCol = nIndex;
10185 }
10186 g_object_set_data(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex", reinterpret_cast<gpointer>(nIndex));
10187 ++nIndex;
10188 }
10189 g_list_free(pRenderers);
10190 ++nViewColumn;
10191 }
10192
10193 m_nIdCol = nIndex++;
10194
10195 for (auto& a : m_aToggleVisMap)
10196 a.second = nIndex++;
10197 for (auto& a : m_aToggleTriStateMap)
10198 a.second = nIndex++;
10199 for (auto& a : m_aWeightMap)
10200 a.second = nIndex++;
10201 for (auto& a : m_aSensitiveMap)
10202 a.second = nIndex++;
10203 for (auto& a : m_aIndentMap)
10204 a.second = nIndex++;
10205 for (auto& a : m_aAlignMap)
10206 a.second = nIndex++;
10207
10208 ensure_drag_begin_end();
10209
10210 m_nRowDeletedSignalId = g_signal_connect(m_pTreeModel, "row-deleted", G_CALLBACK(signalRowDeleted), this)g_signal_connect_data ((m_pTreeModel), ("row-deleted"), (((GCallback
) (signalRowDeleted))), (this), __null, (GConnectFlags) 0)
;
10211 m_nRowInsertedSignalId = g_signal_connect(m_pTreeModel, "row-inserted", G_CALLBACK(signalRowInserted), this)g_signal_connect_data ((m_pTreeModel), ("row-inserted"), (((GCallback
) (signalRowInserted))), (this), __null, (GConnectFlags) 0)
;
10212 }
10213
10214 virtual void connect_query_tooltip(const Link<const weld::TreeIter&, OUString>& rLink) override
10215 {
10216 weld::TreeView::connect_query_tooltip(rLink);
10217 m_nQueryTooltipSignalId = g_signal_connect(m_pTreeView, "query-tooltip", G_CALLBACK(signalQueryTooltip), this)g_signal_connect_data ((m_pTreeView), ("query-tooltip"), (((GCallback
) (signalQueryTooltip))), (this), __null, (GConnectFlags) 0)
;
10218 }
10219
10220 virtual void columns_autosize() override
10221 {
10222 gtk_tree_view_columns_autosize(m_pTreeView);
10223 }
10224
10225 virtual void set_column_fixed_widths(const std::vector<int>& rWidths) override
10226 {
10227 GList* pEntry = g_list_first(m_pColumns);
10228 for (auto nWidth : rWidths)
10229 {
10230 assert(pEntry && "wrong count")(static_cast <bool> (pEntry && "wrong count") ?
void (0) : __assert_fail ("pEntry && \"wrong count\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10230, __extension__ __PRETTY_FUNCTION__))
;
10231 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
10232 gtk_tree_view_column_set_fixed_width(pColumn, nWidth);
10233 pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null);
10234 }
10235 }
10236
10237 virtual void set_column_editables(const std::vector<bool>& rEditables) override
10238 {
10239 size_t nTabCount = rEditables.size();
10240 for (size_t i = 0 ; i < nTabCount; ++i)
10241 set_column_editable(i, rEditables[i]);
10242 }
10243
10244 virtual void set_centered_column(int nCol) override
10245 {
10246 for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
10247 {
10248 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
10249 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
10250 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
10251 {
10252 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
10253 void* pData = g_object_get_data(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex");
10254 if (reinterpret_cast<sal_IntPtr>(pData) == nCol)
10255 {
10256 g_object_set(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "xalign", 0.5, nullptr);
10257 break;
10258 }
10259 }
10260 g_list_free(pRenderers);
10261 }
10262 }
10263
10264 virtual int get_column_width(int nColumn) const override
10265 {
10266 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, nColumn))), ((gtk_tree_view_column_get_type
()))))))
;
10267 assert(pColumn && "wrong count")(static_cast <bool> (pColumn && "wrong count") ?
void (0) : __assert_fail ("pColumn && \"wrong count\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10267, __extension__ __PRETTY_FUNCTION__))
;
10268 int nWidth = gtk_tree_view_column_get_width(pColumn);
10269 // https://github.com/exaile/exaile/issues/580
10270 // after setting fixed_width on a column and requesting width before
10271 // gtk has a chance to do its layout of the column means that the width
10272 // request hasn't come into effect
10273 if (!nWidth)
10274 nWidth = gtk_tree_view_column_get_fixed_width(pColumn);
10275 return nWidth;
10276 }
10277
10278 virtual OUString get_column_title(int nColumn) const override
10279 {
10280 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, nColumn))), ((gtk_tree_view_column_get_type
()))))))
;
10281 assert(pColumn && "wrong count")(static_cast <bool> (pColumn && "wrong count") ?
void (0) : __assert_fail ("pColumn && \"wrong count\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10281, __extension__ __PRETTY_FUNCTION__))
;
10282 const gchar* pTitle = gtk_tree_view_column_get_title(pColumn);
10283 OUString sRet(pTitle, pTitle ? strlen(pTitle) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
10284 return sRet;
10285 }
10286
10287 virtual void set_column_title(int nColumn, const OUString& rTitle) override
10288 {
10289 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, nColumn))), ((gtk_tree_view_column_get_type
()))))))
;
10290 assert(pColumn && "wrong count")(static_cast <bool> (pColumn && "wrong count") ?
void (0) : __assert_fail ("pColumn && \"wrong count\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10290, __extension__ __PRETTY_FUNCTION__))
;
10291 gtk_tree_view_column_set_title(pColumn, OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
10292 }
10293
10294 virtual void set_column_custom_renderer(int nColumn, bool bEnable) override
10295 {
10296 assert(n_children() == 0 && "tree must be empty")(static_cast <bool> (n_children() == 0 && "tree must be empty"
) ? void (0) : __assert_fail ("n_children() == 0 && \"tree must be empty\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10296, __extension__ __PRETTY_FUNCTION__))
;
10297 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, nColumn))), ((gtk_tree_view_column_get_type
()))))))
;
10298 assert(pColumn && "wrong count")(static_cast <bool> (pColumn && "wrong count") ?
void (0) : __assert_fail ("pColumn && \"wrong count\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10298, __extension__ __PRETTY_FUNCTION__))
;
10299
10300 GtkCellRenderer* pExpander = nullptr;
10301 GtkCellRenderer* pToggle = nullptr;
10302
10303 // migrate existing editable setting to the new renderer
10304 gboolean is_editable(false);
10305 void* pEditCellData(nullptr);
10306 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
10307 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
10308 {
10309 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
10310
10311 void* pData = g_object_get_data(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex");
10312 auto nCellIndex = reinterpret_cast<sal_IntPtr>(pData);
10313
10314 if (GTK_IS_CELL_RENDERER_TEXT(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_text_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10315 {
10316 g_object_get(pCellRenderer, "editable", &is_editable, nullptr);
10317 pEditCellData = pData;
10318 break;
10319 }
10320 else if (GTK_IS_CELL_RENDERER_TOGGLE(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_toggle_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10321 {
10322 if (nCellIndex == m_nExpanderToggleCol)
10323 {
10324 pToggle = pCellRenderer;
10325 g_object_ref(pToggle);
10326 }
10327 }
10328 else if (GTK_IS_CELL_RENDERER_PIXBUF(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_pixbuf_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10329 {
10330 if (nCellIndex == m_nExpanderImageCol)
10331 {
10332 pExpander = pCellRenderer;
10333 g_object_ref(pExpander);
10334 }
10335 }
10336
10337 }
10338 g_list_free(pRenderers);
10339
10340 GtkCellRenderer* pRenderer;
10341
10342 gtk_cell_layout_clear(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
10343 if (pExpander)
10344 {
10345 gtk_tree_view_column_pack_start(pColumn, pExpander, false);
10346 gtk_tree_view_column_add_attribute(pColumn, pExpander, "pixbuf", m_nExpanderImageCol);
10347 g_object_unref(pExpander);
10348 }
10349 if (pToggle)
10350 {
10351 gtk_tree_view_column_pack_start(pColumn, pToggle, false);
10352 gtk_tree_view_column_add_attribute(pColumn, pToggle, "active", m_nExpanderToggleCol);
10353 gtk_tree_view_column_add_attribute(pColumn, pToggle, "active", m_nExpanderToggleCol);
10354 gtk_tree_view_column_add_attribute(pColumn, pToggle, "visible", m_aToggleTriStateMap[m_nExpanderToggleCol]);
10355 g_object_unref(pToggle);
10356 }
10357
10358 if (bEnable)
10359 {
10360 pRenderer = custom_cell_renderer_surface_new();
10361 GValue value = G_VALUE_INIT{ 0, { { 0 } } };
10362 g_value_init(&value, G_TYPE_POINTER((GType) ((17) << (2))));
10363 g_value_set_pointer(&value, static_cast<gpointer>(this));
10364 g_object_set_property(G_OBJECT(pRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pRenderer)), (((GType) ((20) << (2))))))))
, "instance", &value);
10365 gtk_tree_view_column_pack_start(pColumn, pRenderer, true);
10366 gtk_tree_view_column_add_attribute(pColumn, pRenderer, "text", m_nTextCol);
10367 gtk_tree_view_column_add_attribute(pColumn, pRenderer, "id", m_nIdCol);
10368 }
10369 else
10370 {
10371 pRenderer = gtk_cell_renderer_text_new();
10372 gtk_tree_view_column_pack_start(pColumn, pRenderer, true);
10373 gtk_tree_view_column_add_attribute(pColumn, pRenderer, "text", m_nTextCol);
10374 }
10375
10376 if (is_editable)
10377 {
10378 g_object_set(pRenderer, "editable", true, "editable-set", true, nullptr);
10379 g_object_set_data(G_OBJECT(pRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pRenderer)), (((GType) ((20) << (2))))))))
, "g-lo-CellIndex", pEditCellData);
10380 g_signal_connect(pRenderer, "editing-started", G_CALLBACK(signalCellEditingStarted), this)g_signal_connect_data ((pRenderer), ("editing-started"), (((GCallback
) (signalCellEditingStarted))), (this), __null, (GConnectFlags
) 0)
;
10381 g_signal_connect(pRenderer, "editing-canceled", G_CALLBACK(signalCellEditingCanceled), this)g_signal_connect_data ((pRenderer), ("editing-canceled"), (((
GCallback) (signalCellEditingCanceled))), (this), __null, (GConnectFlags
) 0)
;
10382 g_signal_connect(pRenderer, "edited", G_CALLBACK(signalCellEdited), this)g_signal_connect_data ((pRenderer), ("edited"), (((GCallback)
(signalCellEdited))), (this), __null, (GConnectFlags) 0)
;
10383 }
10384 }
10385
10386 virtual void queue_draw() override
10387 {
10388 gtk_widget_queue_draw(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
);
10389 }
10390
10391 virtual void insert(const weld::TreeIter* pParent, int pos, const OUString* pText, const OUString* pId, const OUString* pIconName,
10392 VirtualDevice* pImageSurface,
10393 bool bChildrenOnDemand, weld::TreeIter* pRet) override
10394 {
10395 disable_notify_events();
10396 GtkTreeIter iter;
10397 const GtkInstanceTreeIter* pGtkIter = static_cast<const GtkInstanceTreeIter*>(pParent);
10398 insert_row(iter, pGtkIter ? &pGtkIter->iter : nullptr, pos, pId, pText, pIconName, pImageSurface);
10399 if (bChildrenOnDemand)
10400 {
10401 GtkTreeIter subiter;
10402 OUString sDummy("<dummy>");
10403 insert_row(subiter, &iter, -1, nullptr, &sDummy, nullptr, nullptr);
10404 }
10405 if (pRet)
10406 {
10407 GtkInstanceTreeIter* pGtkRetIter = static_cast<GtkInstanceTreeIter*>(pRet);
10408 pGtkRetIter->iter = iter;
10409 }
10410 enable_notify_events();
10411 }
10412
10413 virtual void insert_separator(int pos, const OUString& rId) override
10414 {
10415 disable_notify_events();
10416 GtkTreeIter iter;
10417 if (!gtk_tree_view_get_row_separator_func(m_pTreeView))
10418 gtk_tree_view_set_row_separator_func(m_pTreeView, separatorFunction, this, nullptr);
10419 insert_row(iter, nullptr, pos, &rId, nullptr, nullptr, nullptr);
10420 GtkTreePath* pPath = gtk_tree_model_get_path(m_pTreeModel, &iter);
10421 m_aSeparatorRows.emplace_back(gtk_tree_row_reference_new(m_pTreeModel, pPath));
10422 gtk_tree_path_free(pPath);
10423 enable_notify_events();
10424 }
10425
10426 virtual void set_font_color(int pos, const Color& rColor) override
10427 {
10428 GtkTreeIter iter;
10429 gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos);
10430 set_font_color(iter, rColor);
10431 }
10432
10433 virtual void set_font_color(const weld::TreeIter& rIter, const Color& rColor) override
10434 {
10435 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10436 set_font_color(rGtkIter.iter, rColor);
10437 }
10438
10439 virtual void remove(int pos) override
10440 {
10441 disable_notify_events();
10442 GtkTreeIter iter;
10443 gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos);
10444 m_Remove(m_pTreeModel, &iter);
10445 enable_notify_events();
10446 }
10447
10448 virtual int find_text(const OUString& rText) const override
10449 {
10450 Search aSearch(rText, m_nTextCol);
10451 gtk_tree_model_foreach(m_pTreeModel, foreach_find, &aSearch);
10452 return aSearch.index;
10453 }
10454
10455 virtual int find_id(const OUString& rId) const override
10456 {
10457 Search aSearch(rId, m_nIdCol);
10458 gtk_tree_model_foreach(m_pTreeModel, foreach_find, &aSearch);
10459 return aSearch.index;
10460 }
10461
10462 virtual void bulk_insert_for_each(int nSourceCount, const std::function<void(weld::TreeIter&, int nSourceIndex)>& func,
10463 const std::vector<int>* pFixedWidths) override
10464 {
10465 freeze();
10466 clear();
10467 GtkInstanceTreeIter aGtkIter(nullptr);
10468
10469 if (pFixedWidths)
10470 set_column_fixed_widths(*pFixedWidths);
10471
10472 while (nSourceCount)
10473 {
10474 // tdf#125241 inserting backwards is massively faster
10475 m_Prepend(m_pTreeModel, &aGtkIter.iter, nullptr);
10476 func(aGtkIter, --nSourceCount);
10477 }
10478
10479 thaw();
10480 }
10481
10482 virtual void swap(int pos1, int pos2) override
10483 {
10484 disable_notify_events();
10485
10486 GtkTreeIter iter1;
10487 gtk_tree_model_iter_nth_child(m_pTreeModel, &iter1, nullptr, pos1);
10488
10489 GtkTreeIter iter2;
10490 gtk_tree_model_iter_nth_child(m_pTreeModel, &iter2, nullptr, pos2);
10491
10492 m_Swap(m_pTreeModel, &iter1, &iter2);
10493
10494 enable_notify_events();
10495 }
10496
10497 virtual void clear() override
10498 {
10499 disable_notify_events();
10500 gtk_tree_view_set_row_separator_func(m_pTreeView, nullptr, nullptr, nullptr);
10501 m_aSeparatorRows.clear();
10502 m_Clear(m_pTreeModel);
10503 enable_notify_events();
10504 }
10505
10506 virtual void make_sorted() override
10507 {
10508 // thaw wants to restore sort state of freeze
10509 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10509, __extension__ __PRETTY_FUNCTION__))
;
10510 m_xSorter.reset(new comphelper::string::NaturalStringSorter(
10511 ::comphelper::getProcessComponentContext(),
10512 Application::GetSettings().GetUILanguageTag().getLocale()));
10513 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10514 gtk_tree_sortable_set_sort_func(pSortable, m_nTextCol, sortFunc, this, nullptr);
10515 gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, GTK_SORT_ASCENDING);
10516 }
10517
10518 virtual void make_unsorted() override
10519 {
10520 m_xSorter.reset();
10521 int nSortColumn;
10522 GtkSortType eSortType;
10523 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10524 gtk_tree_sortable_get_sort_column_id(pSortable, &nSortColumn, &eSortType);
10525 gtk_tree_sortable_set_sort_column_id(pSortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID(-2), eSortType);
10526 }
10527
10528 virtual void set_sort_order(bool bAscending) override
10529 {
10530 GtkSortType eSortType = bAscending ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING;
10531
10532 gint sort_column_id(0);
10533 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10534 gtk_tree_sortable_get_sort_column_id(pSortable, &sort_column_id, nullptr);
10535 gtk_tree_sortable_set_sort_column_id(pSortable, sort_column_id, eSortType);
10536 }
10537
10538 virtual bool get_sort_order() const override
10539 {
10540 int nSortColumn;
10541 GtkSortType eSortType;
10542
10543 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10544 gtk_tree_sortable_get_sort_column_id(pSortable, &nSortColumn, &eSortType);
10545 return nSortColumn != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID(-2) && eSortType == GTK_SORT_ASCENDING;
10546 }
10547
10548 virtual void set_sort_indicator(TriState eState, int col) override
10549 {
10550 assert(col >= 0 && "cannot sort on expander column")(static_cast <bool> (col >= 0 && "cannot sort on expander column"
) ? void (0) : __assert_fail ("col >= 0 && \"cannot sort on expander column\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10550, __extension__ __PRETTY_FUNCTION__))
;
10551
10552 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, col))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, col))), ((gtk_tree_view_column_get_type
()))))))
;
10553 assert(pColumn && "wrong count")(static_cast <bool> (pColumn && "wrong count") ?
void (0) : __assert_fail ("pColumn && \"wrong count\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10553, __extension__ __PRETTY_FUNCTION__))
;
10554 if (eState == TRISTATE_INDET)
10555 gtk_tree_view_column_set_sort_indicator(pColumn, false);
10556 else
10557 {
10558 gtk_tree_view_column_set_sort_indicator(pColumn, true);
10559 GtkSortType eSortType = eState == TRISTATE_TRUE ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING;
10560 gtk_tree_view_column_set_sort_order(pColumn, eSortType);
10561 }
10562 }
10563
10564 virtual TriState get_sort_indicator(int col) const override
10565 {
10566 assert(col >= 0 && "cannot sort on expander column")(static_cast <bool> (col >= 0 && "cannot sort on expander column"
) ? void (0) : __assert_fail ("col >= 0 && \"cannot sort on expander column\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10566, __extension__ __PRETTY_FUNCTION__))
;
10567
10568 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, col))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, col))), ((gtk_tree_view_column_get_type
()))))))
;
10569 if (!gtk_tree_view_column_get_sort_indicator(pColumn))
10570 return TRISTATE_INDET;
10571 return gtk_tree_view_column_get_sort_order(pColumn) == GTK_SORT_ASCENDING ? TRISTATE_TRUE : TRISTATE_FALSE;
10572 }
10573
10574 virtual int get_sort_column() const override
10575 {
10576 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10577 gint sort_column_id(0);
10578 if (!gtk_tree_sortable_get_sort_column_id(pSortable, &sort_column_id, nullptr))
10579 return -1;
10580 return to_external_model(sort_column_id);
10581 }
10582
10583 virtual void set_sort_column(int nColumn) override
10584 {
10585 if (nColumn == -1)
10586 {
10587 make_unsorted();
10588 return;
10589 }
10590 GtkSortType eSortType;
10591 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10592 gtk_tree_sortable_get_sort_column_id(pSortable, nullptr, &eSortType);
10593 int nSortCol = to_internal_model(nColumn);
10594 gtk_tree_sortable_set_sort_func(pSortable, nSortCol, sortFunc, this, nullptr);
10595 gtk_tree_sortable_set_sort_column_id(pSortable, nSortCol, eSortType);
10596 }
10597
10598 virtual void set_sort_func(const std::function<int(const weld::TreeIter&, const weld::TreeIter&)>& func) override
10599 {
10600 weld::TreeView::set_sort_func(func);
10601 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
10602 gtk_tree_sortable_sort_column_changed(pSortable);
10603 }
10604
10605 virtual int n_children() const override
10606 {
10607 return gtk_tree_model_iter_n_children(m_pTreeModel, nullptr);
10608 }
10609
10610 virtual int iter_n_children(const weld::TreeIter& rIter) const override
10611 {
10612 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10613 return gtk_tree_model_iter_n_children(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
10614 }
10615
10616 virtual void select(int pos) override
10617 {
10618 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10618, __extension__ __PRETTY_FUNCTION__))
;
10619 disable_notify_events();
10620 if (pos == -1 || (pos == 0 && n_children() == 0))
10621 {
10622 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(m_pTreeView));
10623 }
10624 else
10625 {
10626 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
10627 gtk_tree_selection_select_path(gtk_tree_view_get_selection(m_pTreeView), path);
10628 gtk_tree_view_scroll_to_cell(m_pTreeView, path, nullptr, false, 0, 0);
10629 gtk_tree_path_free(path);
10630 }
10631 enable_notify_events();
10632 }
10633
10634 virtual void set_cursor(int pos) override
10635 {
10636 disable_notify_events();
10637 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
10638 gtk_tree_view_scroll_to_cell(m_pTreeView, path, nullptr, false, 0, 0);
10639 gtk_tree_view_set_cursor(m_pTreeView, path, nullptr, false);
10640 gtk_tree_path_free(path);
10641 enable_notify_events();
10642 }
10643
10644 virtual void scroll_to_row(int pos) override
10645 {
10646 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10646, __extension__ __PRETTY_FUNCTION__))
;
10647 disable_notify_events();
10648 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
10649 gtk_tree_view_expand_to_path(m_pTreeView, path);
10650 gtk_tree_view_scroll_to_cell(m_pTreeView, path, nullptr, false, 0, 0);
10651 gtk_tree_path_free(path);
10652 enable_notify_events();
10653 }
10654
10655 virtual bool is_selected(int pos) const override
10656 {
10657 GtkTreeIter iter;
10658 gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos);
10659 return gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(m_pTreeView), &iter);
10660 }
10661
10662 virtual void unselect(int pos) override
10663 {
10664 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 10664, __extension__ __PRETTY_FUNCTION__))
;
10665 disable_notify_events();
10666 if (pos == -1 || (pos == 0 && n_children() == 0))
10667 {
10668 gtk_tree_selection_select_all(gtk_tree_view_get_selection(m_pTreeView));
10669 }
10670 else
10671 {
10672 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
10673 gtk_tree_selection_unselect_path(gtk_tree_view_get_selection(m_pTreeView), path);
10674 gtk_tree_path_free(path);
10675 }
10676 enable_notify_events();
10677 }
10678
10679 virtual std::vector<int> get_selected_rows() const override
10680 {
10681 std::vector<int> aRows;
10682
10683 GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), nullptr);
10684 for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)((pItem) ? (((GList *)(pItem))->next) : __null))
10685 {
10686 GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
10687
10688 gint depth;
10689 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
10690 int nRow = indices[depth-1];
10691
10692 aRows.push_back(nRow);
10693 }
10694 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
10695
10696 return aRows;
10697 }
10698
10699 virtual void all_foreach(const std::function<bool(weld::TreeIter&)>& func) override
10700 {
10701 g_object_freeze_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
10702
10703 GtkInstanceTreeIter aGtkIter(nullptr);
10704 if (get_iter_first(aGtkIter))
10705 {
10706 do
10707 {
10708 if (func(aGtkIter))
10709 break;
10710 } while (iter_next(aGtkIter));
10711 }
10712
10713 g_object_thaw_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
10714 }
10715
10716 virtual void selected_foreach(const std::function<bool(weld::TreeIter&)>& func) override
10717 {
10718 g_object_freeze_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
10719
10720 GtkInstanceTreeIter aGtkIter(nullptr);
10721
10722 GtkTreeModel* pModel;
10723 GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), &pModel);
10724 for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)((pItem) ? (((GList *)(pItem))->next) : __null))
10725 {
10726 GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
10727 gtk_tree_model_get_iter(pModel, &aGtkIter.iter, path);
10728 if (func(aGtkIter))
10729 break;
10730 }
10731 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
10732
10733 g_object_thaw_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
10734 }
10735
10736 virtual void visible_foreach(const std::function<bool(weld::TreeIter&)>& func) override
10737 {
10738 g_object_freeze_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
10739
10740 GtkTreePath* start_path;
10741 GtkTreePath* end_path;
10742
10743 if (!gtk_tree_view_get_visible_range(m_pTreeView, &start_path, &end_path))
10744 return;
10745
10746 GtkInstanceTreeIter aGtkIter(nullptr);
10747 gtk_tree_model_get_iter(m_pTreeModel, &aGtkIter.iter, start_path);
10748
10749 do
10750 {
10751 if (func(aGtkIter))
10752 break;
10753 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, &aGtkIter.iter);
10754 bool bContinue = gtk_tree_path_compare(path, end_path) != 0;
10755 gtk_tree_path_free(path);
10756 if (!bContinue)
10757 break;
10758 if (!iter_next(aGtkIter))
10759 break;
10760 } while(true);
10761
10762 gtk_tree_path_free(start_path);
10763 gtk_tree_path_free(end_path);
10764
10765 g_object_thaw_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
10766 }
10767
10768 virtual void connect_visible_range_changed(const Link<weld::TreeView&, void>& rLink) override
10769 {
10770 weld::TreeView::connect_visible_range_changed(rLink);
10771 if (!m_nVAdjustmentChangedSignalId)
10772 {
10773 GtkAdjustment* pVAdjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(m_pTreeView)((((GtkScrollable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeView)), ((gtk_scrollable_get_type ()))))))
);
10774 m_nVAdjustmentChangedSignalId = g_signal_connect(pVAdjustment, "value-changed", G_CALLBACK(signalVAdjustmentChanged), this)g_signal_connect_data ((pVAdjustment), ("value-changed"), (((
GCallback) (signalVAdjustmentChanged))), (this), __null, (GConnectFlags
) 0)
;
10775 }
10776 }
10777
10778 virtual bool is_selected(const weld::TreeIter& rIter) const override
10779 {
10780 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10781 return gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(m_pTreeView), const_cast<GtkTreeIter*>(&rGtkIter.iter));
10782 }
10783
10784 virtual OUString get_text(int pos, int col) const override
10785 {
10786 if (col == -1)
10787 col = m_nTextCol;
10788 else
10789 col = to_internal_model(col);
10790 return get(pos, col);
10791 }
10792
10793 virtual void set_text(int pos, const OUString& rText, int col) override
10794 {
10795 if (col == -1)
10796 col = m_nTextCol;
10797 else
10798 col = to_internal_model(col);
10799 set(pos, col, rText);
10800 }
10801
10802 virtual TriState get_toggle(int pos, int col) const override
10803 {
10804 if (col == -1)
10805 col = m_nExpanderToggleCol;
10806 else
10807 col = to_internal_model(col);
10808
10809 if (get_bool(pos, m_aToggleTriStateMap.find(col)->second))
10810 return TRISTATE_INDET;
10811 return get_bool(pos, col) ? TRISTATE_TRUE : TRISTATE_FALSE;
10812 }
10813
10814 virtual TriState get_toggle(const weld::TreeIter& rIter, int col) const override
10815 {
10816 if (col == -1)
10817 col = m_nExpanderToggleCol;
10818 else
10819 col = to_internal_model(col);
10820
10821 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10822 if (get_bool(rGtkIter.iter, m_aToggleTriStateMap.find(col)->second))
10823 return TRISTATE_INDET;
10824 return get_bool(rGtkIter.iter, col) ? TRISTATE_TRUE : TRISTATE_FALSE;
10825 }
10826
10827 virtual void set_toggle(const weld::TreeIter& rIter, TriState eState, int col) override
10828 {
10829 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10830 set_toggle(rGtkIter.iter, eState, col);
10831 }
10832
10833 virtual void set_toggle(int pos, TriState eState, int col) override
10834 {
10835 GtkTreeIter iter;
10836 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
10837 set_toggle(iter, eState, col);
10838 }
10839
10840 virtual void enable_toggle_buttons(weld::ColumnToggleType eType) override
10841 {
10842 for (GList* pEntry = g_list_first(m_pColumns); pEntry; pEntry = g_list_next(pEntry)((pEntry) ? (((GList *)(pEntry))->next) : __null))
10843 {
10844 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
10845 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
10846 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
10847 {
10848 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
10849 if (!GTK_IS_CELL_RENDERER_TOGGLE(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_toggle_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
10850 continue;
10851 GtkCellRendererToggle* pToggle = GTK_CELL_RENDERER_TOGGLE(pCellRenderer)((((GtkCellRendererToggle*) g_type_check_instance_cast ((GTypeInstance
*) ((pCellRenderer)), ((gtk_cell_renderer_toggle_get_type ())
)))))
;
10852 gtk_cell_renderer_toggle_set_radio(pToggle, eType == weld::ColumnToggleType::Radio);
10853 }
10854 g_list_free(pRenderers);
10855 }
10856 }
10857
10858 virtual void set_extra_row_indent(const weld::TreeIter& rIter, int nIndentLevel) override
10859 {
10860 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10861 set(rGtkIter.iter, m_aIndentMap[m_nTextCol], nIndentLevel * get_expander_size());
10862 }
10863
10864 virtual void set_text_emphasis(const weld::TreeIter& rIter, bool bOn, int col) override
10865 {
10866 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10867 col = to_internal_model(col);
10868 set(rGtkIter.iter, m_aWeightMap[col], bOn ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
10869 }
10870
10871 virtual void set_text_emphasis(int pos, bool bOn, int col) override
10872 {
10873 col = to_internal_model(col);
10874 set(pos, m_aWeightMap[col], bOn ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
10875 }
10876
10877 virtual bool get_text_emphasis(const weld::TreeIter& rIter, int col) const override
10878 {
10879 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10880 col = to_internal_model(col);
10881 return get_int(rGtkIter.iter, m_aWeightMap.find(col)->second) == PANGO_WEIGHT_BOLD;
10882 }
10883
10884 virtual bool get_text_emphasis(int pos, int col) const override
10885 {
10886 col = to_internal_model(col);
10887 return get_int(pos, m_aWeightMap.find(col)->second) == PANGO_WEIGHT_BOLD;
10888 }
10889
10890 virtual void set_text_align(const weld::TreeIter& rIter, double fAlign, int col) override
10891 {
10892 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10893 col = to_internal_model(col);
10894 set(rGtkIter.iter, m_aAlignMap[col], fAlign);
10895 }
10896
10897 virtual void set_text_align(int pos, double fAlign, int col) override
10898 {
10899 col = to_internal_model(col);
10900 set(pos, m_aAlignMap[col], fAlign);
10901 }
10902
10903 using GtkInstanceWidget::set_sensitive;
10904
10905 virtual void set_sensitive(int pos, bool bSensitive, int col) override
10906 {
10907 if (col == -1)
10908 col = m_nTextCol;
10909 else
10910 col = to_internal_model(col);
10911 set(pos, m_aSensitiveMap[col], bSensitive);
10912 }
10913
10914 virtual void set_sensitive(const weld::TreeIter& rIter, bool bSensitive, int col) override
10915 {
10916 if (col == -1)
10917 col = m_nTextCol;
10918 else
10919 col = to_internal_model(col);
10920 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10921 set(rGtkIter.iter, m_aSensitiveMap[col], bSensitive);
10922 }
10923
10924 void set_image(const GtkTreeIter& iter, int col, GdkPixbuf* pixbuf)
10925 {
10926 if (col == -1)
10927 col = m_nExpanderImageCol;
10928 else
10929 col = to_internal_model(col);
10930 m_Setter(m_pTreeModel, const_cast<GtkTreeIter*>(&iter), col, pixbuf, -1);
10931 if (pixbuf)
10932 g_object_unref(pixbuf);
10933 }
10934
10935 void set_image(int pos, GdkPixbuf* pixbuf, int col)
10936 {
10937 GtkTreeIter iter;
10938 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
10939 {
10940 set_image(iter, col, pixbuf);
10941 }
10942 }
10943
10944 virtual void set_image(int pos, const css::uno::Reference<css::graphic::XGraphic>& rImage, int col) override
10945 {
10946 set_image(pos, getPixbuf(rImage), col);
10947 }
10948
10949 virtual void set_image(int pos, const OUString& rImage, int col) override
10950 {
10951 set_image(pos, getPixbuf(rImage), col);
10952 }
10953
10954 virtual void set_image(int pos, VirtualDevice& rImage, int col) override
10955 {
10956 set_image(pos, getPixbuf(rImage), col);
10957 }
10958
10959 virtual void set_image(const weld::TreeIter& rIter, const css::uno::Reference<css::graphic::XGraphic>& rImage, int col) override
10960 {
10961 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10962 set_image(rGtkIter.iter, col, getPixbuf(rImage));
10963 }
10964
10965 virtual void set_image(const weld::TreeIter& rIter, const OUString& rImage, int col) override
10966 {
10967 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10968 set_image(rGtkIter.iter, col, getPixbuf(rImage));
10969 }
10970
10971 virtual void set_image(const weld::TreeIter& rIter, VirtualDevice& rImage, int col) override
10972 {
10973 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10974 set_image(rGtkIter.iter, col, getPixbuf(rImage));
10975 }
10976
10977 virtual OUString get_id(int pos) const override
10978 {
10979 return get(pos, m_nIdCol);
10980 }
10981
10982 virtual void set_id(int pos, const OUString& rId) override
10983 {
10984 return set(pos, m_nIdCol, rId);
10985 }
10986
10987 virtual int get_iter_index_in_parent(const weld::TreeIter& rIter) const override
10988 {
10989 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
10990
10991 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
10992
10993 gint depth;
10994 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
10995 int nRet = indices[depth-1];
10996
10997 gtk_tree_path_free(path);
10998
10999 return nRet;
11000 }
11001
11002 virtual int iter_compare(const weld::TreeIter& a, const weld::TreeIter& b) const override
11003 {
11004 const GtkInstanceTreeIter& rGtkIterA = static_cast<const GtkInstanceTreeIter&>(a);
11005 const GtkInstanceTreeIter& rGtkIterB = static_cast<const GtkInstanceTreeIter&>(b);
11006
11007 GtkTreePath* pathA = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIterA.iter));
11008 GtkTreePath* pathB = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIterB.iter));
11009
11010 int nRet = gtk_tree_path_compare(pathA, pathB);
11011
11012 gtk_tree_path_free(pathB);
11013 gtk_tree_path_free(pathA);
11014
11015 return nRet;
11016 }
11017
11018 // by copy and delete of old copy
11019 void move_subtree(GtkTreeIter& rFromIter, GtkTreeIter* pGtkParentIter, int nIndexInNewParent)
11020 {
11021 int nCols = gtk_tree_model_get_n_columns(m_pTreeModel);
11022 GValue value;
11023
11024 GtkTreeIter toiter;
11025 m_Insert(m_pTreeModel, &toiter, pGtkParentIter, nIndexInNewParent);
11026
11027 for (int i = 0; i < nCols; ++i)
11028 {
11029 memset(&value, 0, sizeof(GValue));
11030 gtk_tree_model_get_value(m_pTreeModel, &rFromIter, i, &value);
11031 m_SetValue(m_pTreeModel, &toiter, i, &value);
11032 g_value_unset(&value);
11033 }
11034
11035 GtkTreeIter tmpfromiter;
11036 if (gtk_tree_model_iter_children(m_pTreeModel, &tmpfromiter, &rFromIter))
11037 {
11038 int j = 0;
11039 do
11040 {
11041 move_subtree(tmpfromiter, &toiter, j++);
11042 } while (gtk_tree_model_iter_next(m_pTreeModel, &tmpfromiter));
11043 }
11044
11045 m_Remove(m_pTreeModel, &rFromIter);
11046 }
11047
11048 virtual void move_subtree(weld::TreeIter& rNode, const weld::TreeIter* pNewParent, int nIndexInNewParent) override
11049 {
11050 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rNode);
11051 const GtkInstanceTreeIter* pGtkParentIter = static_cast<const GtkInstanceTreeIter*>(pNewParent);
11052 move_subtree(rGtkIter.iter, pGtkParentIter ? const_cast<GtkTreeIter*>(&pGtkParentIter->iter) : nullptr, nIndexInNewParent);
11053 }
11054
11055 virtual int get_selected_index() const override
11056 {
11057 assert(gtk_tree_view_get_model(m_pTreeView) && "don't request selection when frozen")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11057, __extension__ __PRETTY_FUNCTION__))
;
11058 int nRet = -1;
11059 GtkTreeSelection *selection = gtk_tree_view_get_selection(m_pTreeView);
11060 if (gtk_tree_selection_get_mode(selection) != GTK_SELECTION_MULTIPLE)
11061 {
11062 GtkTreeIter iter;
11063 GtkTreeModel* pModel;
11064 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), &pModel, &iter))
11065 {
11066 GtkTreePath* path = gtk_tree_model_get_path(pModel, &iter);
11067
11068 gint depth;
11069 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
11070 nRet = indices[depth-1];
11071
11072 gtk_tree_path_free(path);
11073 }
11074 }
11075 else
11076 {
11077 auto vec = get_selected_rows();
11078 return vec.empty() ? -1 : vec[0];
11079 }
11080 return nRet;
11081 }
11082
11083 bool get_selected_iterator(GtkTreeIter* pIter) const
11084 {
11085 assert(gtk_tree_view_get_model(m_pTreeView) && "don't request selection when frozen")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11085, __extension__ __PRETTY_FUNCTION__))
;
11086 bool bRet = false;
11087 GtkTreeSelection *selection = gtk_tree_view_get_selection(m_pTreeView);
11088 if (gtk_tree_selection_get_mode(selection) != GTK_SELECTION_MULTIPLE)
11089 bRet = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), nullptr, pIter);
11090 else
11091 {
11092 GtkTreeModel* pModel;
11093 GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), &pModel);
11094 for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)((pItem) ? (((GList *)(pItem))->next) : __null))
11095 {
11096 if (pIter)
11097 {
11098 GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
11099 gtk_tree_model_get_iter(pModel, pIter, path);
11100 }
11101 bRet = true;
11102 break;
11103 }
11104 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
11105 }
11106 return bRet;
11107 }
11108
11109 virtual OUString get_selected_text() const override
11110 {
11111 assert(gtk_tree_view_get_model(m_pTreeView) && "don't request selection when frozen")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11111, __extension__ __PRETTY_FUNCTION__))
;
11112 GtkTreeIter iter;
11113 if (get_selected_iterator(&iter))
11114 return get(iter, m_nTextCol);
11115 return OUString();
11116 }
11117
11118 virtual OUString get_selected_id() const override
11119 {
11120 assert(gtk_tree_view_get_model(m_pTreeView) && "don't request selection when frozen")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11120, __extension__ __PRETTY_FUNCTION__))
;
11121 GtkTreeIter iter;
11122 if (get_selected_iterator(&iter))
11123 return get(iter, m_nIdCol);
11124 return OUString();
11125 }
11126
11127 virtual std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pOrig) const override
11128 {
11129 return std::unique_ptr<weld::TreeIter>(new GtkInstanceTreeIter(static_cast<const GtkInstanceTreeIter*>(pOrig)));
11130 }
11131
11132 virtual void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const override
11133 {
11134 const GtkInstanceTreeIter& rGtkSource(static_cast<const GtkInstanceTreeIter&>(rSource));
11135 GtkInstanceTreeIter& rGtkDest(static_cast<GtkInstanceTreeIter&>(rDest));
11136 rGtkDest.iter = rGtkSource.iter;
11137 }
11138
11139 virtual bool get_selected(weld::TreeIter* pIter) const override
11140 {
11141 GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pIter);
11142 return get_selected_iterator(pGtkIter ? &pGtkIter->iter : nullptr);
11143 }
11144
11145 virtual bool get_cursor(weld::TreeIter* pIter) const override
11146 {
11147 GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pIter);
11148 GtkTreePath* path;
11149 gtk_tree_view_get_cursor(m_pTreeView, &path, nullptr);
11150 if (pGtkIter && path)
11151 {
11152 gtk_tree_model_get_iter(m_pTreeModel, &pGtkIter->iter, path);
11153 }
11154 if (!path)
11155 return false;
11156 gtk_tree_path_free(path);
11157 return true;
11158 }
11159
11160 virtual int get_cursor_index() const override
11161 {
11162 int nRet = -1;
11163
11164 GtkTreePath* path;
11165 gtk_tree_view_get_cursor(m_pTreeView, &path, nullptr);
11166 if (path)
11167 {
11168 gint depth;
11169 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
11170 nRet = indices[depth-1];
11171 gtk_tree_path_free(path);
11172 }
11173
11174 return nRet;
11175 }
11176
11177 virtual void set_cursor(const weld::TreeIter& rIter) override
11178 {
11179 disable_notify_events();
11180 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11181 GtkTreeIter Iter;
11182 if (gtk_tree_model_iter_parent(m_pTreeModel, &Iter, const_cast<GtkTreeIter*>(&rGtkIter.iter)))
11183 {
11184 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, &Iter);
11185 if (!gtk_tree_view_row_expanded(m_pTreeView, path))
11186 gtk_tree_view_expand_to_path(m_pTreeView, path);
11187 gtk_tree_path_free(path);
11188 }
11189 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11190 gtk_tree_view_scroll_to_cell(m_pTreeView, path, nullptr, false, 0, 0);
11191 gtk_tree_view_set_cursor(m_pTreeView, path, nullptr, false);
11192 gtk_tree_path_free(path);
11193 enable_notify_events();
11194 }
11195
11196 virtual bool get_iter_first(weld::TreeIter& rIter) const override
11197 {
11198 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
11199 return gtk_tree_model_get_iter_first(m_pTreeModel, &rGtkIter.iter);
11200 }
11201
11202 virtual bool iter_next_sibling(weld::TreeIter& rIter) const override
11203 {
11204 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
11205 return gtk_tree_model_iter_next(m_pTreeModel, &rGtkIter.iter);
11206 }
11207
11208 virtual bool iter_previous_sibling(weld::TreeIter& rIter) const override
11209 {
11210 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
11211 return gtk_tree_model_iter_previous(m_pTreeModel, &rGtkIter.iter);
11212 }
11213
11214 virtual bool iter_next(weld::TreeIter& rIter) const override
11215 {
11216 return iter_next(rIter, false);
11217 }
11218
11219 virtual bool iter_previous(weld::TreeIter& rIter) const override
11220 {
11221 bool ret = false;
11222 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
11223 GtkTreeIter iter = rGtkIter.iter;
11224 GtkTreeIter tmp = iter;
11225 if (gtk_tree_model_iter_previous(m_pTreeModel, &tmp))
11226 {
11227 // Move down level(s) until we find the level where the last node exists.
11228 int nChildren = gtk_tree_model_iter_n_children(m_pTreeModel, &tmp);
11229 if (!nChildren)
11230 rGtkIter.iter = tmp;
11231 else
11232 last_child(m_pTreeModel, &rGtkIter.iter, &tmp, nChildren);
11233 ret = true;
11234 }
11235 else
11236 {
11237 // Move up level
11238 if (gtk_tree_model_iter_parent(m_pTreeModel, &tmp, &iter))
11239 {
11240 rGtkIter.iter = tmp;
11241 ret = true;
11242 }
11243 }
11244
11245 if (ret)
11246 {
11247 //on-demand dummy entry doesn't count
11248 if (get_text(rGtkIter, -1) == "<dummy>")
11249 return iter_previous(rGtkIter);
11250 return true;
11251 }
11252
11253 return false;
11254 }
11255
11256 virtual bool iter_children(weld::TreeIter& rIter) const override
11257 {
11258 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
11259 GtkTreeIter tmp;
11260 bool ret = gtk_tree_model_iter_children(m_pTreeModel, &tmp, &rGtkIter.iter);
11261 rGtkIter.iter = tmp;
11262 if (ret)
11263 {
11264 //on-demand dummy entry doesn't count
11265 return get_text(rGtkIter, -1) != "<dummy>";
11266 }
11267 return ret;
11268 }
11269
11270 virtual bool iter_parent(weld::TreeIter& rIter) const override
11271 {
11272 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
11273 GtkTreeIter tmp;
11274 auto ret = gtk_tree_model_iter_parent(m_pTreeModel, &tmp, &rGtkIter.iter);
11275 rGtkIter.iter = tmp;
11276 return ret;
11277 }
11278
11279 virtual void remove(const weld::TreeIter& rIter) override
11280 {
11281 disable_notify_events();
11282 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11283 m_Remove(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11284 enable_notify_events();
11285 }
11286
11287 virtual void remove_selection() override
11288 {
11289 disable_notify_events();
11290
11291 std::vector<GtkTreeIter> aIters;
11292 GtkTreeModel* pModel;
11293 GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), &pModel);
11294 for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)((pItem) ? (((GList *)(pItem))->next) : __null))
11295 {
11296 GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
11297 aIters.emplace_back();
11298 gtk_tree_model_get_iter(pModel, &aIters.back(), path);
11299 }
11300 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
11301
11302 for (auto& iter : aIters)
11303 m_Remove(m_pTreeModel, &iter);
11304
11305 enable_notify_events();
11306 }
11307
11308 virtual void select(const weld::TreeIter& rIter) override
11309 {
11310 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11310, __extension__ __PRETTY_FUNCTION__))
;
11311 disable_notify_events();
11312 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11313 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(m_pTreeView), const_cast<GtkTreeIter*>(&rGtkIter.iter));
11314 enable_notify_events();
11315 }
11316
11317 virtual void scroll_to_row(const weld::TreeIter& rIter) override
11318 {
11319 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11319, __extension__ __PRETTY_FUNCTION__))
;
11320 disable_notify_events();
11321 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11322 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11323 gtk_tree_view_expand_to_path(m_pTreeView, path);
11324 gtk_tree_view_scroll_to_cell(m_pTreeView, path, nullptr, false, 0, 0);
11325 gtk_tree_path_free(path);
11326 enable_notify_events();
11327 }
11328
11329 virtual void unselect(const weld::TreeIter& rIter) override
11330 {
11331 assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_tree_view_get_model(m_pTreeView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11331, __extension__ __PRETTY_FUNCTION__))
;
11332 disable_notify_events();
11333 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11334 gtk_tree_selection_unselect_iter(gtk_tree_view_get_selection(m_pTreeView), const_cast<GtkTreeIter*>(&rGtkIter.iter));
11335 enable_notify_events();
11336 }
11337
11338 virtual int get_iter_depth(const weld::TreeIter& rIter) const override
11339 {
11340 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11341 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11342 int ret = gtk_tree_path_get_depth(path) - 1;
11343 gtk_tree_path_free(path);
11344 return ret;
11345 }
11346
11347 virtual bool iter_has_child(const weld::TreeIter& rIter) const override
11348 {
11349 weld::TreeIter& rNonConstIter = const_cast<weld::TreeIter&>(rIter);
11350 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rNonConstIter);
11351 GtkTreeIter restore(rGtkIter.iter);
11352 bool ret = iter_children(rNonConstIter);
11353 rGtkIter.iter = restore;
11354 return ret;
11355 }
11356
11357 virtual bool get_row_expanded(const weld::TreeIter& rIter) const override
11358 {
11359 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11360 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11361 bool ret = gtk_tree_view_row_expanded(m_pTreeView, path);
11362 gtk_tree_path_free(path);
11363 return ret;
11364 }
11365
11366 virtual bool get_children_on_demand(const weld::TreeIter& rIter) const override
11367 {
11368 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11369 GtkInstanceTreeIter aIter(&rGtkIter);
11370 return child_is_placeholder(aIter);
11371 }
11372
11373 virtual void set_children_on_demand(const weld::TreeIter& rIter, bool bChildrenOnDemand) override
11374 {
11375 disable_notify_events();
11376
11377 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11378 GtkInstanceTreeIter aPlaceHolderIter(&rGtkIter);
11379
11380 bool bPlaceHolder = child_is_placeholder(aPlaceHolderIter);
11381
11382 if (bChildrenOnDemand && !bPlaceHolder)
11383 {
11384 GtkTreeIter subiter;
11385 OUString sDummy("<dummy>");
11386 insert_row(subiter, &rGtkIter.iter, -1, nullptr, &sDummy, nullptr, nullptr);
11387 }
11388 else if (!bChildrenOnDemand && bPlaceHolder)
11389 remove(aPlaceHolderIter);
11390
11391 enable_notify_events();
11392 }
11393
11394 virtual void expand_row(const weld::TreeIter& rIter) override
11395 {
11396 assert(gtk_tree_view_get_model(m_pTreeView) && "don't expand when frozen")(static_cast <bool> (gtk_tree_view_get_model(m_pTreeView
) && "don't expand when frozen") ? void (0) : __assert_fail
("gtk_tree_view_get_model(m_pTreeView) && \"don't expand when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11396, __extension__ __PRETTY_FUNCTION__))
;
11397
11398 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11399 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11400 if (!gtk_tree_view_row_expanded(m_pTreeView, path))
11401 gtk_tree_view_expand_to_path(m_pTreeView, path);
11402 gtk_tree_path_free(path);
11403 }
11404
11405 virtual void collapse_row(const weld::TreeIter& rIter) override
11406 {
11407 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11408 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11409 if (gtk_tree_view_row_expanded(m_pTreeView, path))
11410 gtk_tree_view_collapse_row(m_pTreeView, path);
11411 gtk_tree_path_free(path);
11412 }
11413
11414 virtual OUString get_text(const weld::TreeIter& rIter, int col) const override
11415 {
11416 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11417 if (col == -1)
11418 col = m_nTextCol;
11419 else
11420 col = to_internal_model(col);
11421 return get(rGtkIter.iter, col);
11422 }
11423
11424 virtual void set_text(const weld::TreeIter& rIter, const OUString& rText, int col) override
11425 {
11426 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11427 if (col == -1)
11428 col = m_nTextCol;
11429 else
11430 col = to_internal_model(col);
11431 set(rGtkIter.iter, col, rText);
11432 }
11433
11434 virtual OUString get_id(const weld::TreeIter& rIter) const override
11435 {
11436 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11437 return get(rGtkIter.iter, m_nIdCol);
11438 }
11439
11440 virtual void set_id(const weld::TreeIter& rIter, const OUString& rId) override
11441 {
11442 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11443 set(rGtkIter.iter, m_nIdCol, rId);
11444 }
11445
11446 virtual void freeze() override
11447 {
11448 disable_notify_events();
11449 GtkInstanceContainer::freeze();
11450 g_object_ref(m_pTreeModel);
11451 gtk_tree_view_set_model(m_pTreeView, nullptr);
11452 g_object_freeze_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
11453 if (m_xSorter)
11454 {
11455 int nSortColumn;
11456 GtkSortType eSortType;
11457 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
11458 gtk_tree_sortable_get_sort_column_id(pSortable, &nSortColumn, &eSortType);
11459 gtk_tree_sortable_set_sort_column_id(pSortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID(-2), eSortType);
11460
11461 m_aSavedSortColumns.push_back(nSortColumn);
11462 m_aSavedSortTypes.push_back(eSortType);
11463 }
11464 enable_notify_events();
11465 }
11466
11467 virtual void thaw() override
11468 {
11469 disable_notify_events();
11470 if (m_xSorter)
11471 {
11472 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
11473 gtk_tree_sortable_set_sort_column_id(pSortable, m_aSavedSortColumns.back(), m_aSavedSortTypes.back());
11474 m_aSavedSortTypes.pop_back();
11475 m_aSavedSortColumns.pop_back();
11476 }
11477 g_object_thaw_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
11478 gtk_tree_view_set_model(m_pTreeView, GTK_TREE_MODEL(m_pTreeModel)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_model_get_type ()))))))
);
11479 g_object_unref(m_pTreeModel);
11480 GtkInstanceContainer::thaw();
11481 enable_notify_events();
11482 }
11483
11484 virtual int get_height_rows(int nRows) const override
11485 {
11486 return ::get_height_rows(m_pTreeView, m_pColumns, nRows);
11487 }
11488
11489 virtual Size get_size_request() const override
11490 {
11491 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
11492 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
11493 {
11494 return Size(gtk_scrolled_window_get_min_content_width(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
),
11495 gtk_scrolled_window_get_min_content_height(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
));
11496 }
11497 int nWidth, nHeight;
11498 gtk_widget_get_size_request(m_pWidget, &nWidth, &nHeight);
11499 return Size(nWidth, nHeight);
11500 }
11501
11502 virtual Size get_preferred_size() const override
11503 {
11504 Size aRet(-1, -1);
11505 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
11506 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
11507 {
11508 aRet = Size(gtk_scrolled_window_get_min_content_width(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
),
11509 gtk_scrolled_window_get_min_content_height(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
));
11510 }
11511 GtkRequisition size;
11512 gtk_widget_get_preferred_size(m_pWidget, nullptr, &size);
11513 if (aRet.Width() == -1)
11514 aRet.setWidth(size.width);
11515 if (aRet.Height() == -1)
11516 aRet.setHeight(size.height);
11517 return aRet;
11518 }
11519
11520 virtual void show() override
11521 {
11522 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
11523 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
11524 gtk_widget_show(pParent);
11525 gtk_widget_show(m_pWidget);
11526 }
11527
11528 virtual void hide() override
11529 {
11530 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
11531 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
11532 gtk_widget_hide(pParent);
11533 gtk_widget_hide(m_pWidget);
11534 }
11535
11536 virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) override
11537 {
11538 do_enable_drag_source(rHelper, eDNDConstants);
11539 }
11540
11541 virtual void drag_source_set(const std::vector<GtkTargetEntry>& rGtkTargets, GdkDragAction eDragAction) override
11542 {
11543 gtk_tree_view_enable_model_drag_source(m_pTreeView, GDK_BUTTON1_MASK, rGtkTargets.data(), rGtkTargets.size(), eDragAction);
11544 }
11545
11546 virtual void set_selection_mode(SelectionMode eMode) override
11547 {
11548 disable_notify_events();
11549 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(m_pTreeView), VclToGtk(eMode));
11550 enable_notify_events();
11551 }
11552
11553 virtual int count_selected_rows() const override
11554 {
11555 return gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(m_pTreeView));
11556 }
11557
11558 int starts_with(const OUString& rStr, int nStartRow, bool bCaseSensitive)
11559 {
11560 return ::starts_with(m_pTreeModel, rStr, m_nTextCol, nStartRow, bCaseSensitive);
11561 }
11562
11563 virtual void disable_notify_events() override
11564 {
11565 g_signal_handler_block(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId);
11566 g_signal_handler_block(m_pTreeView, m_nRowActivatedSignalId);
11567
11568 g_signal_handler_block(m_pTreeModel, m_nRowDeletedSignalId);
11569 g_signal_handler_block(m_pTreeModel, m_nRowInsertedSignalId);
11570
11571 GtkInstanceContainer::disable_notify_events();
11572 }
11573
11574 virtual void enable_notify_events() override
11575 {
11576 GtkInstanceContainer::enable_notify_events();
11577
11578 g_signal_handler_unblock(m_pTreeModel, m_nRowDeletedSignalId);
11579 g_signal_handler_unblock(m_pTreeModel, m_nRowInsertedSignalId);
11580
11581 g_signal_handler_unblock(m_pTreeView, m_nRowActivatedSignalId);
11582 g_signal_handler_unblock(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId);
11583 }
11584
11585 virtual void connect_popup_menu(const Link<const CommandEvent&, bool>& rLink) override
11586 {
11587 ensureButtonPressSignal();
11588 weld::TreeView::connect_popup_menu(rLink);
11589 }
11590
11591 virtual bool get_dest_row_at_pos(const Point &rPos, weld::TreeIter* pResult, bool bDnDMode) override
11592 {
11593 if (rPos.X() < 0 || rPos.Y() < 0)
11594 {
11595 // short-circuit to avoid "gtk_tree_view_get_dest_row_at_pos: assertion 'drag_x >= 0'" g_assert
11596 return false;
11597 }
11598
11599 const bool bAsTree = gtk_tree_view_get_enable_tree_lines(m_pTreeView);
11600
11601 // to keep it simple we'll default to always drop before the current row
11602 // except for the special edge cases
11603 GtkTreeViewDropPosition pos = bAsTree ? GTK_TREE_VIEW_DROP_INTO_OR_BEFORE : GTK_TREE_VIEW_DROP_BEFORE;
11604
11605 // unhighlight current highlighted row
11606 gtk_tree_view_set_drag_dest_row(m_pTreeView, nullptr, pos);
11607
11608 if (m_bWorkAroundBadDragRegion)
11609 gtk_drag_unhighlight(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
);
11610
11611 GtkTreePath *path = nullptr;
11612 GtkTreeViewDropPosition gtkpos = bAsTree ? GTK_TREE_VIEW_DROP_INTO_OR_BEFORE : GTK_TREE_VIEW_DROP_BEFORE;
11613 bool ret = gtk_tree_view_get_dest_row_at_pos(m_pTreeView, rPos.X(), rPos.Y(),
11614 &path, &gtkpos);
11615
11616 // find the last entry in the model for comparison
11617 GtkTreePath *lastpath = get_path_of_last_entry(m_pTreeModel);
11618
11619 if (!ret)
11620 {
11621 // empty space, draw an indicator at the last entry
11622 assert(!path)(static_cast <bool> (!path) ? void (0) : __assert_fail (
"!path", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11622, __extension__ __PRETTY_FUNCTION__))
;
11623 path = gtk_tree_path_copy(lastpath);
11624 pos = GTK_TREE_VIEW_DROP_AFTER;
11625 }
11626 else if (bDnDMode && gtk_tree_path_compare(path, lastpath) == 0)
11627 {
11628 // if we're on the last entry, see if gtk thinks
11629 // the drop should be before or after it, and if
11630 // its after, treat it like a drop into empty
11631 // space, i.e. append it
11632 if (gtkpos == GTK_TREE_VIEW_DROP_AFTER ||
11633 gtkpos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
11634 {
11635 ret = false;
11636 pos = bAsTree ? gtkpos : GTK_TREE_VIEW_DROP_AFTER;
11637 }
11638 }
11639
11640 if (ret && pResult)
11641 {
11642 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(*pResult);
11643 gtk_tree_model_get_iter(m_pTreeModel, &rGtkIter.iter, path);
11644 }
11645
11646 if (m_bInDrag && bDnDMode)
11647 {
11648 // highlight the row
11649 gtk_tree_view_set_drag_dest_row(m_pTreeView, path, pos);
11650 }
11651
11652 assert(path)(static_cast <bool> (path) ? void (0) : __assert_fail (
"path", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11652, __extension__ __PRETTY_FUNCTION__))
;
11653 gtk_tree_path_free(path);
11654 gtk_tree_path_free(lastpath);
11655
11656 // auto scroll if we're close to the edges
11657 GtkAdjustment* pVAdjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(m_pTreeView)((((GtkScrollable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeView)), ((gtk_scrollable_get_type ()))))))
);
11658 double fStep = gtk_adjustment_get_step_increment(pVAdjustment);
11659 if (rPos.Y() < fStep)
11660 {
11661 double fValue = gtk_adjustment_get_value(pVAdjustment) - fStep;
11662 if (fValue < 0)
11663 fValue = 0.0;
11664 gtk_adjustment_set_value(pVAdjustment, fValue);
11665 }
11666 else
11667 {
11668 GdkRectangle aRect;
11669 gtk_tree_view_get_visible_rect(m_pTreeView, &aRect);
11670 if (rPos.Y() > aRect.height - fStep)
11671 {
11672 double fValue = gtk_adjustment_get_value(pVAdjustment) + fStep;
11673 double fMax = gtk_adjustment_get_upper(pVAdjustment);
11674 if (fValue > fMax)
11675 fValue = fMax;
11676 gtk_adjustment_set_value(pVAdjustment, fValue);
11677 }
11678 }
11679
11680 return ret;
11681 }
11682
11683 virtual void unset_drag_dest_row() override
11684 {
11685 gtk_tree_view_set_drag_dest_row(m_pTreeView, nullptr, GTK_TREE_VIEW_DROP_BEFORE);
11686 }
11687
11688 virtual tools::Rectangle get_row_area(const weld::TreeIter& rIter) const override
11689 {
11690 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11691 GtkTreePath* pPath = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11692 tools::Rectangle aRet = ::get_row_area(m_pTreeView, m_pColumns, pPath);
11693 gtk_tree_path_free(pPath);
11694 return aRet;
11695 }
11696
11697 virtual void start_editing(const weld::TreeIter& rIter) override
11698 {
11699 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, m_nTextView))((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((g_list_nth_data(m_pColumns, m_nTextView))), ((gtk_tree_view_column_get_type
()))))))
;
11700 assert(pColumn && "wrong column")(static_cast <bool> (pColumn && "wrong column")
? void (0) : __assert_fail ("pColumn && \"wrong column\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11700, __extension__ __PRETTY_FUNCTION__))
;
11701
11702 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
11703 GtkTreePath* path = gtk_tree_model_get_path(m_pTreeModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
11704
11705 // allow editing of cells which are not usually editable, so we can have double click
11706 // do its usual row-activate but if we explicitly want to edit (remote files dialog)
11707 // we can still do that
11708 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
11709 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
11710 {
11711 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
11712 if (GTK_IS_CELL_RENDERER_TEXT(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((gtk_cell_renderer_text_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
11713 {
11714 gboolean is_editable(false);
11715 g_object_get(pCellRenderer, "editable", &is_editable, nullptr);
11716 if (!is_editable)
11717 {
11718 g_object_set(pCellRenderer, "editable", true, "editable-set", true, nullptr);
11719 g_object_set_data(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "g-lo-RestoreNonEditable", reinterpret_cast<gpointer>(true));
11720 break;
11721 }
11722 }
11723 }
11724 g_list_free(pRenderers);
11725
11726 gtk_tree_view_scroll_to_cell(m_pTreeView, path, pColumn, false, 0, 0);
11727 gtk_tree_view_set_cursor(m_pTreeView, path, pColumn, true);
11728
11729 gtk_tree_path_free(path);
11730 }
11731
11732 virtual void end_editing() override
11733 {
11734 GtkTreeViewColumn *focus_column = nullptr;
11735 gtk_tree_view_get_cursor(m_pTreeView, nullptr, &focus_column);
11736 if (focus_column)
11737 gtk_cell_area_stop_editing(gtk_cell_layout_get_area(GTK_CELL_LAYOUT(focus_column)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((focus_column)), ((gtk_cell_layout_get_type ()))))))
), true);
11738 }
11739
11740 virtual TreeView* get_drag_source() const override
11741 {
11742 return g_DragSource;
11743 }
11744
11745 virtual bool do_signal_drag_begin(bool& rUnsetDragIcon) override
11746 {
11747 if (m_aDragBeginHdl.Call(rUnsetDragIcon))
11748 return true;
11749 g_DragSource = this;
11750 return false;
11751 }
11752
11753 virtual void do_signal_drag_end() override
11754 {
11755 g_DragSource = nullptr;
11756 }
11757
11758 // Under gtk 3.24.8 dragging into the TreeView is not highlighting
11759 // entire TreeView widget, just the rectangle which has no entries
11760 // in it, so as a workaround highlight the parent container
11761 // on drag start, and undo it on drag end, and trigger removal
11762 // of the treeview's highlight effort
11763 virtual void drag_started() override
11764 {
11765 m_bInDrag = true;
11766 GtkWidget* pWidget = GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
;
11767 GtkWidget* pParent = gtk_widget_get_parent(pWidget);
11768 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
11769 {
11770 gtk_drag_unhighlight(pWidget);
11771 gtk_drag_highlight(pParent);
11772 m_bWorkAroundBadDragRegion = true;
11773 }
11774 }
11775
11776 virtual void drag_ended() override
11777 {
11778 m_bInDrag = false;
11779 if (m_bWorkAroundBadDragRegion)
11780 {
11781 GtkWidget* pWidget = GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
;
11782 GtkWidget* pParent = gtk_widget_get_parent(pWidget);
11783 gtk_drag_unhighlight(pParent);
11784 m_bWorkAroundBadDragRegion = false;
11785 }
11786 // unhighlight the row
11787 gtk_tree_view_set_drag_dest_row(m_pTreeView, nullptr, GTK_TREE_VIEW_DROP_BEFORE);
11788 }
11789
11790 virtual int vadjustment_get_value() const override
11791 {
11792 if (m_nPendingVAdjustment != -1)
11793 return m_nPendingVAdjustment;
11794 return gtk_adjustment_get_value(m_pVAdjustment);
11795 }
11796
11797 virtual void vadjustment_set_value(int value) override
11798 {
11799 disable_notify_events();
11800
11801 /* This rube goldberg device is to remove flicker from setting the
11802 scroll position of a GtkTreeView directly after clearing it and
11803 filling it. As a specific example the writer navigator with ~100
11804 tables, scroll to the end, right click on an entry near the end
11805 and rename it, the tree is cleared and refilled and an attempt
11806 made to set the scroll position of the freshly refilled tree to
11807 the same point as before the clear.
11808 */
11809
11810 // This forces the tree to recalculate now its preferred size
11811 // after being cleared
11812 GtkRequisition size;
11813 gtk_widget_get_preferred_size(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
, nullptr, &size);
11814
11815 m_nPendingVAdjustment = value;
11816
11817 // The value set here just has to be different to the final value
11818 // set later so that isn't a no-op
11819 gtk_adjustment_set_value(m_pVAdjustment, value - 0.0001);
11820
11821 // This will set the desired m_nPendingVAdjustment value right
11822 // before the tree gets drawn
11823 gtk_widget_add_tick_callback(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
, setAdjustmentCallback, this, nullptr);
11824
11825 enable_notify_events();
11826 }
11827
11828 void call_signal_custom_render(VirtualDevice& rOutput, const tools::Rectangle& rRect, bool bSelected, const OUString& rId)
11829 {
11830 signal_custom_render(rOutput, rRect, bSelected, rId);
11831 }
11832
11833 Size call_signal_custom_get_size(VirtualDevice& rOutput, const OUString& rId)
11834 {
11835 return signal_custom_get_size(rOutput, rId);
11836 }
11837
11838 virtual void set_show_expanders(bool bShow) override
11839 {
11840 gtk_tree_view_set_show_expanders(m_pTreeView, bShow);
11841 }
11842
11843 virtual ~GtkInstanceTreeView() override
11844 {
11845 if (m_pChangeEvent)
11846 Application::RemoveUserEvent(m_pChangeEvent);
11847 if (m_nQueryTooltipSignalId)
11848 g_signal_handler_disconnect(m_pTreeView, m_nQueryTooltipSignalId);
11849 g_signal_handler_disconnect(m_pTreeView, m_nKeyPressSignalId);
11850 g_signal_handler_disconnect(m_pTreeView, m_nPopupMenuSignalId);
11851 g_signal_handler_disconnect(m_pTreeModel, m_nRowDeletedSignalId);
11852 g_signal_handler_disconnect(m_pTreeModel, m_nRowInsertedSignalId);
11853
11854 if (m_nVAdjustmentChangedSignalId)
11855 {
11856 GtkAdjustment* pVAdjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(m_pTreeView)((((GtkScrollable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeView)), ((gtk_scrollable_get_type ()))))))
);
11857 g_signal_handler_disconnect(pVAdjustment, m_nVAdjustmentChangedSignalId);
11858 }
11859
11860 g_signal_handler_disconnect(m_pTreeView, m_nTestCollapseRowSignalId);
11861 g_signal_handler_disconnect(m_pTreeView, m_nTestExpandRowSignalId);
11862 g_signal_handler_disconnect(m_pTreeView, m_nRowActivatedSignalId);
11863 g_signal_handler_disconnect(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId);
11864
11865 GValue value = G_VALUE_INIT{ 0, { { 0 } } };
11866 g_value_init(&value, G_TYPE_POINTER((GType) ((17) << (2))));
11867 g_value_set_pointer(&value, static_cast<gpointer>(nullptr));
11868
11869 for (GList* pEntry = g_list_last(m_pColumns); pEntry; pEntry = g_list_previous(pEntry)((pEntry) ? (((GList *)(pEntry))->prev) : __null))
11870 {
11871 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pEntry->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pEntry->data)), ((gtk_tree_view_column_get_type ())))
)))
;
11872 g_signal_handler_disconnect(pColumn, m_aColumnSignalIds.back());
11873 m_aColumnSignalIds.pop_back();
11874
11875 // unset "instance" to avoid dangling "instance" points in any CustomCellRenderers
11876 GList *pRenderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
11877 for (GList* pRenderer = g_list_first(pRenderers); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
11878 {
11879 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
11880 if (!CUSTOM_IS_CELL_RENDERER_SURFACE(pCellRenderer)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pCellRenderer)); GType __t = ((custom_cell_renderer_surface_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
11881 continue;
11882 g_object_set_property(G_OBJECT(pCellRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pCellRenderer)), (((GType) ((20) << (2))))))))
, "instance", &value);
11883 }
11884 g_list_free(pRenderers);
11885 }
11886 g_list_free(m_pColumns);
11887 }
11888};
11889
11890void ensure_device(CustomCellRendererSurface *cellsurface, weld::Widget* pWidget)
11891{
11892 if (!cellsurface->device)
11893 {
11894 cellsurface->device = VclPtr<VirtualDevice>::Create();
11895 cellsurface->device->SetBackground(COL_TRANSPARENT);
11896 // expand the point size of the desired font to the equivalent pixel size
11897 if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
11898 pDefaultDevice->SetPointFont(*cellsurface->device, pWidget->get_font());
11899 }
11900}
11901
11902}
11903
11904IMPL_LINK_NOARG(GtkInstanceTreeView, async_signal_changed, void*, void)void GtkInstanceTreeView::LinkStubasync_signal_changed(void *
instance, void* data) { return static_cast<GtkInstanceTreeView
*>(instance)->async_signal_changed(data); } void GtkInstanceTreeView
::async_signal_changed(__attribute__ ((unused)) void*)
11905{
11906 m_pChangeEvent = nullptr;
11907 signal_changed();
11908}
11909
11910IMPL_LINK_NOARG(GtkInstanceTreeView, async_stop_cell_editing, void*, void)void GtkInstanceTreeView::LinkStubasync_stop_cell_editing(void
* instance, void* data) { return static_cast<GtkInstanceTreeView
*>(instance)->async_stop_cell_editing(data); } void GtkInstanceTreeView
::async_stop_cell_editing(__attribute__ ((unused)) void*)
11911{
11912 end_editing();
11913}
11914
11915namespace {
11916
11917class GtkInstanceIconView : public GtkInstanceContainer, public virtual weld::IconView
11918{
11919private:
11920 GtkIconView* m_pIconView;
11921 GtkTreeStore* m_pTreeStore;
11922 gint m_nTextCol;
11923 gint m_nImageCol;
11924 gint m_nIdCol;
11925 gulong m_nSelectionChangedSignalId;
11926 gulong m_nItemActivatedSignalId;
11927 ImplSVEvent* m_pSelectionChangeEvent;
11928
11929 DECL_LINK(async_signal_selection_changed, void*, void)static void LinkStubasync_signal_selection_changed(void *, void
*); void async_signal_selection_changed(void*)
;
11930
11931 void launch_signal_selection_changed()
11932 {
11933 //tdf#117991 selection change is sent before the focus change, and focus change
11934 //is what will cause a spinbutton that currently has the focus to set its contents
11935 //as the spin button value. So any LibreOffice callbacks on
11936 //signal-change would happen before the spinbutton value-change occurs.
11937 //To avoid this, send the signal-change to LibreOffice to occur after focus-change
11938 //has been processed
11939 if (m_pSelectionChangeEvent)
11940 Application::RemoveUserEvent(m_pSelectionChangeEvent);
11941 m_pSelectionChangeEvent = Application::PostUserEvent(LINK(this, GtkInstanceIconView, async_signal_selection_changed)::tools::detail::makeLink( ::tools::detail::castTo<GtkInstanceIconView
*>(this), &GtkInstanceIconView::LinkStubasync_signal_selection_changed
)
);
11942 }
11943
11944 static void signalSelectionChanged(GtkIconView*, gpointer widget)
11945 {
11946 GtkInstanceIconView* pThis = static_cast<GtkInstanceIconView*>(widget);
11947 pThis->launch_signal_selection_changed();
11948 }
11949
11950 void handle_item_activated()
11951 {
11952 if (signal_item_activated())
11953 return;
11954 }
11955
11956 static void signalItemActivated(GtkIconView*, GtkTreePath*, gpointer widget)
11957 {
11958 GtkInstanceIconView* pThis = static_cast<GtkInstanceIconView*>(widget);
11959 SolarMutexGuard aGuard;
11960 pThis->handle_item_activated();
11961 }
11962
11963 void insert_item(GtkTreeIter& iter, int pos, const OUString* pId, const OUString* pText, const OUString* pIconName)
11964 {
11965 gtk_tree_store_insert_with_values(m_pTreeStore, &iter, nullptr, pos,
11966 m_nTextCol, !pText ? nullptr : OUStringToOString(*pText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
11967 m_nIdCol, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(),
11968 -1);
11969 if (pIconName)
11970 {
11971 GdkPixbuf* pixbuf = getPixbuf(*pIconName);
11972 gtk_tree_store_set(m_pTreeStore, &iter, m_nImageCol, pixbuf, -1);
11973 if (pixbuf)
11974 g_object_unref(pixbuf);
11975 }
11976 }
11977
11978 OUString get(const GtkTreeIter& iter, int col) const
11979 {
11980 GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
11981 gchar* pStr;
11982 gtk_tree_model_get(pModel, const_cast<GtkTreeIter*>(&iter), col, &pStr, -1);
11983 OUString sRet(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
11984 g_free(pStr);
11985 return sRet;
11986 }
11987
11988 bool get_selected_iterator(GtkTreeIter* pIter) const
11989 {
11990 assert(gtk_icon_view_get_model(m_pIconView) && "don't request selection when frozen")(static_cast <bool> (gtk_icon_view_get_model(m_pIconView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_icon_view_get_model(m_pIconView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 11990, __extension__ __PRETTY_FUNCTION__))
;
11991 bool bRet = false;
11992 {
11993 GtkTreeModel* pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
11994 GList* pList = gtk_icon_view_get_selected_items(m_pIconView);
11995 for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)((pItem) ? (((GList *)(pItem))->next) : __null))
11996 {
11997 if (pIter)
11998 {
11999 GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
12000 gtk_tree_model_get_iter(pModel, pIter, path);
12001 }
12002 bRet = true;
12003 break;
12004 }
12005 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
12006 }
12007 return bRet;
12008 }
12009
12010public:
12011 GtkInstanceIconView(GtkIconView* pIconView, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
12012 : GtkInstanceContainer(GTK_CONTAINER(pIconView)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pIconView)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
12013 , m_pIconView(pIconView)
12014 , m_pTreeStore(GTK_TREE_STORE(gtk_icon_view_get_model(m_pIconView))((((GtkTreeStore*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_icon_view_get_model(m_pIconView))), ((gtk_tree_store_get_type
()))))))
)
12015 , m_nTextCol(gtk_icon_view_get_text_column(m_pIconView))
12016 , m_nImageCol(gtk_icon_view_get_pixbuf_column(m_pIconView))
12017 , m_nSelectionChangedSignalId(g_signal_connect(pIconView, "selection-changed",g_signal_connect_data ((pIconView), ("selection-changed"), ((
(GCallback) (signalSelectionChanged))), (this), __null, (GConnectFlags
) 0)
12018 G_CALLBACK(signalSelectionChanged), this)g_signal_connect_data ((pIconView), ("selection-changed"), ((
(GCallback) (signalSelectionChanged))), (this), __null, (GConnectFlags
) 0)
)
12019 , m_nItemActivatedSignalId(g_signal_connect(pIconView, "item-activated", G_CALLBACK(signalItemActivated), this)g_signal_connect_data ((pIconView), ("item-activated"), (((GCallback
) (signalItemActivated))), (this), __null, (GConnectFlags) 0)
)
12020 , m_pSelectionChangeEvent(nullptr)
12021 {
12022 m_nIdCol = m_nTextCol + 1;
12023 }
12024
12025 virtual void insert(int pos, const OUString* pText, const OUString* pId, const OUString* pIconName, weld::TreeIter* pRet) override
12026 {
12027 disable_notify_events();
12028 GtkTreeIter iter;
12029 insert_item(iter, pos, pId, pText, pIconName);
12030 if (pRet)
12031 {
12032 GtkInstanceTreeIter* pGtkRetIter = static_cast<GtkInstanceTreeIter*>(pRet);
12033 pGtkRetIter->iter = iter;
12034 }
12035 enable_notify_events();
12036 }
12037
12038 virtual OUString get_selected_id() const override
12039 {
12040 assert(gtk_icon_view_get_model(m_pIconView) && "don't request selection when frozen")(static_cast <bool> (gtk_icon_view_get_model(m_pIconView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_icon_view_get_model(m_pIconView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 12040, __extension__ __PRETTY_FUNCTION__))
;
12041 GtkTreeIter iter;
12042 if (get_selected_iterator(&iter))
12043 return get(iter, m_nIdCol);
12044 return OUString();
12045 }
12046
12047 virtual void clear() override
12048 {
12049 disable_notify_events();
12050 gtk_tree_store_clear(m_pTreeStore);
12051 enable_notify_events();
12052 }
12053
12054 virtual void freeze() override
12055 {
12056 disable_notify_events();
12057 GtkInstanceContainer::freeze();
12058 g_object_ref(m_pTreeStore);
12059 gtk_icon_view_set_model(m_pIconView, nullptr);
12060 g_object_freeze_notify(G_OBJECT(m_pTreeStore)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeStore)), (((GType) ((20) << (2))))))))
);
12061 enable_notify_events();
12062 }
12063
12064 virtual void thaw() override
12065 {
12066 disable_notify_events();
12067 g_object_thaw_notify(G_OBJECT(m_pTreeStore)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeStore)), (((GType) ((20) << (2))))))))
);
12068 gtk_icon_view_set_model(m_pIconView, GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
);
12069 g_object_unref(m_pTreeStore);
12070 GtkInstanceContainer::thaw();
12071 enable_notify_events();
12072 }
12073
12074 virtual Size get_size_request() const override
12075 {
12076 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
12077 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
12078 {
12079 return Size(gtk_scrolled_window_get_min_content_width(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
),
12080 gtk_scrolled_window_get_min_content_height(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
));
12081 }
12082 int nWidth, nHeight;
12083 gtk_widget_get_size_request(m_pWidget, &nWidth, &nHeight);
12084 return Size(nWidth, nHeight);
12085 }
12086
12087 virtual Size get_preferred_size() const override
12088 {
12089 Size aRet(-1, -1);
12090 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
12091 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
12092 {
12093 aRet = Size(gtk_scrolled_window_get_min_content_width(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
),
12094 gtk_scrolled_window_get_min_content_height(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
));
12095 }
12096 GtkRequisition size;
12097 gtk_widget_get_preferred_size(m_pWidget, nullptr, &size);
12098 if (aRet.Width() == -1)
12099 aRet.setWidth(size.width);
12100 if (aRet.Height() == -1)
12101 aRet.setHeight(size.height);
12102 return aRet;
12103 }
12104
12105 virtual void show() override
12106 {
12107 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
12108 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
12109 gtk_widget_show(pParent);
12110 gtk_widget_show(m_pWidget);
12111 }
12112
12113 virtual void hide() override
12114 {
12115 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
12116 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
12117 gtk_widget_hide(pParent);
12118 gtk_widget_hide(m_pWidget);
12119 }
12120
12121 virtual OUString get_selected_text() const override
12122 {
12123 assert(gtk_icon_view_get_model(m_pIconView) && "don't request selection when frozen")(static_cast <bool> (gtk_icon_view_get_model(m_pIconView
) && "don't request selection when frozen") ? void (0
) : __assert_fail ("gtk_icon_view_get_model(m_pIconView) && \"don't request selection when frozen\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 12123, __extension__ __PRETTY_FUNCTION__))
;
12124 GtkTreeIter iter;
12125 if (get_selected_iterator(&iter))
12126 return get(iter, m_nTextCol);
12127 return OUString();
12128 }
12129
12130 virtual int count_selected_items() const override
12131 {
12132 GList* pList = gtk_icon_view_get_selected_items(m_pIconView);
12133 int nRet = g_list_length(pList);
12134 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
12135 return nRet;
12136 }
12137
12138 virtual void select(int pos) override
12139 {
12140 assert(gtk_icon_view_get_model(m_pIconView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_icon_view_get_model(m_pIconView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_icon_view_get_model(m_pIconView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 12140, __extension__ __PRETTY_FUNCTION__))
;
12141 disable_notify_events();
12142 if (pos == -1 || (pos == 0 && n_children() == 0))
12143 {
12144 gtk_icon_view_unselect_all(m_pIconView);
12145 }
12146 else
12147 {
12148 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
12149 gtk_icon_view_select_path(m_pIconView, path);
12150 gtk_icon_view_scroll_to_path(m_pIconView, path, false, 0, 0);
12151 gtk_tree_path_free(path);
12152 }
12153 enable_notify_events();
12154 }
12155
12156 virtual void unselect(int pos) override
12157 {
12158 assert(gtk_icon_view_get_model(m_pIconView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_icon_view_get_model(m_pIconView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_icon_view_get_model(m_pIconView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 12158, __extension__ __PRETTY_FUNCTION__))
;
12159 disable_notify_events();
12160 if (pos == -1 || (pos == 0 && n_children() == 0))
12161 {
12162 gtk_icon_view_select_all(m_pIconView);
12163 }
12164 else
12165 {
12166 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
12167 gtk_icon_view_select_path(m_pIconView, path);
12168 gtk_tree_path_free(path);
12169 }
12170 enable_notify_events();
12171 }
12172
12173 virtual bool get_selected(weld::TreeIter* pIter) const override
12174 {
12175 GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pIter);
12176 return get_selected_iterator(pGtkIter ? &pGtkIter->iter : nullptr);
12177 }
12178
12179 virtual bool get_cursor(weld::TreeIter* pIter) const override
12180 {
12181 GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pIter);
12182 GtkTreePath* path;
12183 gtk_icon_view_get_cursor(m_pIconView, &path, nullptr);
12184 if (pGtkIter && path)
12185 {
12186 GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
12187 gtk_tree_model_get_iter(pModel, &pGtkIter->iter, path);
12188 }
12189 return path != nullptr;
12190 }
12191
12192 virtual void set_cursor(const weld::TreeIter& rIter) override
12193 {
12194 disable_notify_events();
12195 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
12196 GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
12197 GtkTreePath* path = gtk_tree_model_get_path(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
12198 gtk_icon_view_set_cursor(m_pIconView, path, nullptr, false);
12199 gtk_tree_path_free(path);
12200 enable_notify_events();
12201 }
12202
12203 virtual bool get_iter_first(weld::TreeIter& rIter) const override
12204 {
12205 GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
12206 GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
12207 return gtk_tree_model_get_iter_first(pModel, &rGtkIter.iter);
12208 }
12209
12210 virtual void scroll_to_item(const weld::TreeIter& rIter) override
12211 {
12212 assert(gtk_icon_view_get_model(m_pIconView) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze")(static_cast <bool> (gtk_icon_view_get_model(m_pIconView
) && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"
) ? void (0) : __assert_fail ("gtk_icon_view_get_model(m_pIconView) && \"don't select when frozen, select after thaw. Note selection doesn't survive a freeze\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 12212, __extension__ __PRETTY_FUNCTION__))
;
12213 disable_notify_events();
12214 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
12215 GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
12216 GtkTreePath* path = gtk_tree_model_get_path(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
12217 gtk_icon_view_scroll_to_path(m_pIconView, path, false, 0, 0);
12218 gtk_tree_path_free(path);
12219 enable_notify_events();
12220 }
12221
12222 virtual std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pOrig) const override
12223 {
12224 return std::unique_ptr<weld::TreeIter>(new GtkInstanceTreeIter(static_cast<const GtkInstanceTreeIter*>(pOrig)));
12225 }
12226
12227 virtual void selected_foreach(const std::function<bool(weld::TreeIter&)>& func) override
12228 {
12229 GtkInstanceTreeIter aGtkIter(nullptr);
12230
12231 GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
;
12232 GList* pList = gtk_icon_view_get_selected_items(m_pIconView);
12233 for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)((pItem) ? (((GList *)(pItem))->next) : __null))
12234 {
12235 GtkTreePath* path = static_cast<GtkTreePath*>(pItem->data);
12236 gtk_tree_model_get_iter(pModel, &aGtkIter.iter, path);
12237 if (func(aGtkIter))
12238 break;
12239 }
12240 g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free));
12241 }
12242
12243 virtual int n_children() const override
12244 {
12245 return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pTreeStore)((((GtkTreeModel*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeStore)), ((gtk_tree_model_get_type ()))))))
, nullptr);
12246 }
12247
12248 virtual OUString get_id(const weld::TreeIter& rIter) const override
12249 {
12250 const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
12251 return get(rGtkIter.iter, m_nIdCol);
12252 }
12253
12254 virtual void disable_notify_events() override
12255 {
12256 g_signal_handler_block(m_pIconView, m_nSelectionChangedSignalId);
12257 g_signal_handler_block(m_pIconView, m_nItemActivatedSignalId);
12258
12259 GtkInstanceContainer::disable_notify_events();
12260 }
12261
12262 virtual void enable_notify_events() override
12263 {
12264 GtkInstanceContainer::enable_notify_events();
12265
12266 g_signal_handler_unblock(m_pIconView, m_nItemActivatedSignalId);
12267 g_signal_handler_unblock(m_pIconView, m_nSelectionChangedSignalId);
12268 }
12269
12270 virtual ~GtkInstanceIconView() override
12271 {
12272 if (m_pSelectionChangeEvent)
12273 Application::RemoveUserEvent(m_pSelectionChangeEvent);
12274
12275 g_signal_handler_disconnect(m_pIconView, m_nItemActivatedSignalId);
12276 g_signal_handler_disconnect(m_pIconView, m_nSelectionChangedSignalId);
12277 }
12278};
12279
12280}
12281
12282IMPL_LINK_NOARG(GtkInstanceIconView, async_signal_selection_changed, void*, void)void GtkInstanceIconView::LinkStubasync_signal_selection_changed
(void * instance, void* data) { return static_cast<GtkInstanceIconView
*>(instance)->async_signal_selection_changed(data); } void
GtkInstanceIconView::async_signal_selection_changed(__attribute__
((unused)) void*)
12283{
12284 m_pSelectionChangeEvent = nullptr;
12285 signal_selection_changed();
12286}
12287
12288namespace {
12289
12290class GtkInstanceSpinButton : public GtkInstanceEntry, public virtual weld::SpinButton
12291{
12292private:
12293 GtkSpinButton* m_pButton;
12294 gulong m_nValueChangedSignalId;
12295 gulong m_nOutputSignalId;
12296 gulong m_nInputSignalId;
12297 bool m_bFormatting;
12298 bool m_bBlockOutput;
12299 bool m_bBlank;
12300
12301 static void signalValueChanged(GtkSpinButton*, gpointer widget)
12302 {
12303 GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget);
12304 SolarMutexGuard aGuard;
12305 pThis->m_bBlank = false;
12306 pThis->signal_value_changed();
12307 }
12308
12309 bool guarded_signal_output()
12310 {
12311 if (m_bBlockOutput)
12312 return true;
12313 m_bFormatting = true;
12314 bool bRet = signal_output();
12315 m_bFormatting = false;
12316 return bRet;
12317 }
12318
12319 static gboolean signalOutput(GtkSpinButton*, gpointer widget)
12320 {
12321 GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget);
12322 SolarMutexGuard aGuard;
12323 return pThis->guarded_signal_output();
12324 }
12325
12326 static gint signalInput(GtkSpinButton*, gdouble* new_value, gpointer widget)
12327 {
12328 GtkInstanceSpinButton* pThis = static_cast<GtkInstanceSpinButton*>(widget);
12329 SolarMutexGuard aGuard;
12330 int result;
12331 TriState eHandled = pThis->signal_input(&result);
12332 if (eHandled == TRISTATE_INDET)
12333 return 0;
12334 if (eHandled == TRISTATE_TRUE)
12335 {
12336 *new_value = pThis->toGtk(result);
12337 return 1;
12338 }
12339 return GTK_INPUT_ERROR-1;
12340 }
12341
12342 virtual void signal_activate() override
12343 {
12344 gtk_spin_button_update(m_pButton);
12345 GtkInstanceEntry::signal_activate();
12346 }
12347
12348 double toGtk(int nValue) const
12349 {
12350 return static_cast<double>(nValue) / Power10(get_digits());
12351 }
12352
12353 int fromGtk(double fValue) const
12354 {
12355 return FRound(fValue * Power10(get_digits()));
12356 }
12357
12358public:
12359 GtkInstanceSpinButton(GtkSpinButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
12360 : GtkInstanceEntry(GTK_ENTRY(pButton)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_entry_get_type ()))))))
, pBuilder, bTakeOwnership)
12361 , m_pButton(pButton)
12362 , m_nValueChangedSignalId(g_signal_connect(pButton, "value-changed", G_CALLBACK(signalValueChanged), this)g_signal_connect_data ((pButton), ("value-changed"), (((GCallback
) (signalValueChanged))), (this), __null, (GConnectFlags) 0)
)
12363 , m_nOutputSignalId(g_signal_connect(pButton, "output", G_CALLBACK(signalOutput), this)g_signal_connect_data ((pButton), ("output"), (((GCallback) (
signalOutput))), (this), __null, (GConnectFlags) 0)
)
12364 , m_nInputSignalId(g_signal_connect(pButton, "input", G_CALLBACK(signalInput), this)g_signal_connect_data ((pButton), ("input"), (((GCallback) (signalInput
))), (this), __null, (GConnectFlags) 0)
)
12365 , m_bFormatting(false)
12366 , m_bBlockOutput(false)
12367 , m_bBlank(false)
12368 {
12369 }
12370
12371 virtual int get_value() const override
12372 {
12373 return fromGtk(gtk_spin_button_get_value(m_pButton));
12374 }
12375
12376 virtual void set_value(int value) override
12377 {
12378 disable_notify_events();
12379 m_bBlank = false;
12380 gtk_spin_button_set_value(m_pButton, toGtk(value));
12381 enable_notify_events();
12382 }
12383
12384 virtual void set_text(const OUString& rText) override
12385 {
12386 disable_notify_events();
12387 // tdf#122786 if we're just formatting a value, then we're done,
12388 // however if set_text has been called directly we want to update our
12389 // value from this new text, but don't want to reformat with that value
12390 if (!m_bFormatting)
12391 {
12392 gtk_entry_set_text(GTK_ENTRY(m_pButton)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButton)), ((gtk_entry_get_type ()))))))
, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
12393
12394 m_bBlockOutput = true;
12395 gtk_spin_button_update(m_pButton);
12396 m_bBlank = rText.isEmpty();
12397 m_bBlockOutput = false;
12398 }
12399 else
12400 {
12401 bool bKeepBlank = m_bBlank && get_value() == 0;
12402 if (!bKeepBlank)
12403 {
12404 gtk_entry_set_text(GTK_ENTRY(m_pButton)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pButton)), ((gtk_entry_get_type ()))))))
, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
12405 m_bBlank = false;
12406 }
12407 }
12408 enable_notify_events();
12409 }
12410
12411 virtual void set_range(int min, int max) override
12412 {
12413 disable_notify_events();
12414 gtk_spin_button_set_range(m_pButton, toGtk(min), toGtk(max));
12415 enable_notify_events();
12416 }
12417
12418 virtual void get_range(int& min, int& max) const override
12419 {
12420 double gtkmin, gtkmax;
12421 gtk_spin_button_get_range(m_pButton, &gtkmin, &gtkmax);
12422 min = fromGtk(gtkmin);
12423 max = fromGtk(gtkmax);
12424 }
12425
12426 virtual void set_increments(int step, int page) override
12427 {
12428 disable_notify_events();
12429 gtk_spin_button_set_increments(m_pButton, toGtk(step), toGtk(page));
12430 enable_notify_events();
12431 }
12432
12433 virtual void get_increments(int& step, int& page) const override
12434 {
12435 double gtkstep, gtkpage;
12436 gtk_spin_button_get_increments(m_pButton, &gtkstep, &gtkpage);
12437 step = fromGtk(gtkstep);
12438 page = fromGtk(gtkpage);
12439 }
12440
12441 virtual void set_digits(unsigned int digits) override
12442 {
12443 disable_notify_events();
12444 gtk_spin_button_set_digits(m_pButton, digits);
12445 enable_notify_events();
12446 }
12447
12448 virtual unsigned int get_digits() const override
12449 {
12450 return gtk_spin_button_get_digits(m_pButton);
12451 }
12452
12453 virtual void disable_notify_events() override
12454 {
12455 g_signal_handler_block(m_pButton, m_nValueChangedSignalId);
12456 GtkInstanceEntry::disable_notify_events();
12457 }
12458
12459 virtual void enable_notify_events() override
12460 {
12461 GtkInstanceEntry::enable_notify_events();
12462 g_signal_handler_unblock(m_pButton, m_nValueChangedSignalId);
12463 }
12464
12465 virtual ~GtkInstanceSpinButton() override
12466 {
12467 g_signal_handler_disconnect(m_pButton, m_nInputSignalId);
12468 g_signal_handler_disconnect(m_pButton, m_nOutputSignalId);
12469 g_signal_handler_disconnect(m_pButton, m_nValueChangedSignalId);
12470 }
12471};
12472
12473class GtkInstanceFormattedSpinButton : public GtkInstanceEntry, public virtual weld::FormattedSpinButton
12474{
12475private:
12476 GtkSpinButton* m_pButton;
12477 std::unique_ptr<weld::EntryFormatter> m_xOwnFormatter;
12478 weld::EntryFormatter* m_pFormatter;
12479 gulong m_nValueChangedSignalId;
12480 gulong m_nOutputSignalId;
12481 gulong m_nInputSignalId;
12482 bool m_bEmptyField;
12483 bool m_bSyncingValue;
12484 double m_dValueWhenEmpty;
12485
12486 bool signal_output()
12487 {
12488 double fValue = gtk_spin_button_get_value(m_pButton);
12489 m_bEmptyField &= fValue == m_dValueWhenEmpty;
12490 if (!m_bEmptyField)
12491 GetFormatter().SetValue(fValue);
12492 return true;
12493 }
12494
12495 static gboolean signalOutput(GtkSpinButton*, gpointer widget)
12496 {
12497 GtkInstanceFormattedSpinButton* pThis = static_cast<GtkInstanceFormattedSpinButton*>(widget);
12498 SolarMutexGuard aGuard;
12499 return pThis->signal_output();
12500 }
12501
12502 gint signal_input(double* value)
12503 {
12504 Formatter& rFormatter = GetFormatter();
12505 rFormatter.Modify();
12506 // if the blank-mode is enabled then if the input is empty don't parse
12507 // the input but keep the value as it is. store what the value the
12508 // blank is associated with and until the value is changed, or the text
12509 // is updated from the outside, don't output that value
12510 m_bEmptyField = rFormatter.IsEmptyFieldEnabled() && get_text().isEmpty();
12511 if (m_bEmptyField)
12512 {
12513 m_dValueWhenEmpty = gtk_spin_button_get_value(m_pButton);
12514 *value = m_dValueWhenEmpty;
12515 }
12516 else
12517 *value = rFormatter.GetValue();
12518 return 1;
12519 }
12520
12521 static gint signalInput(GtkSpinButton*, gdouble* new_value, gpointer widget)
12522 {
12523 GtkInstanceFormattedSpinButton* pThis = static_cast<GtkInstanceFormattedSpinButton*>(widget);
12524 SolarMutexGuard aGuard;
12525 return pThis->signal_input(new_value);
12526 }
12527
12528 static void signalValueChanged(GtkSpinButton*, gpointer widget)
12529 {
12530 GtkInstanceFormattedSpinButton* pThis = static_cast<GtkInstanceFormattedSpinButton*>(widget);
12531 SolarMutexGuard aGuard;
12532 pThis->signal_value_changed();
12533 }
12534
12535public:
12536 GtkInstanceFormattedSpinButton(GtkSpinButton* pButton, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
12537 : GtkInstanceEntry(GTK_ENTRY(pButton)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_entry_get_type ()))))))
, pBuilder, bTakeOwnership)
12538 , m_pButton(pButton)
12539 , m_pFormatter(nullptr)
12540 , m_nValueChangedSignalId(g_signal_connect(pButton, "value-changed", G_CALLBACK(signalValueChanged), this)g_signal_connect_data ((pButton), ("value-changed"), (((GCallback
) (signalValueChanged))), (this), __null, (GConnectFlags) 0)
)
12541 , m_nOutputSignalId(g_signal_connect(pButton, "output", G_CALLBACK(signalOutput), this)g_signal_connect_data ((pButton), ("output"), (((GCallback) (
signalOutput))), (this), __null, (GConnectFlags) 0)
)
12542 , m_nInputSignalId(g_signal_connect(pButton, "input", G_CALLBACK(signalInput), this)g_signal_connect_data ((pButton), ("input"), (((GCallback) (signalInput
))), (this), __null, (GConnectFlags) 0)
)
12543 , m_bEmptyField(false)
12544 , m_bSyncingValue(false)
12545 , m_dValueWhenEmpty(0.0)
12546 {
12547 }
12548
12549 virtual void set_text(const OUString& rText) override
12550 {
12551 GtkInstanceEntry::set_text(rText);
12552 Formatter& rFormatter = GetFormatter();
12553 m_bEmptyField = rFormatter.IsEmptyFieldEnabled() && rText.isEmpty();
12554 if (m_bEmptyField)
12555 m_dValueWhenEmpty = gtk_spin_button_get_value(m_pButton);
12556 }
12557
12558 virtual void connect_changed(const Link<weld::Entry&, void>& rLink) override
12559 {
12560 if (!m_pFormatter) // once a formatter is set, it takes over "changed"
12561 {
12562 GtkInstanceEntry::connect_changed(rLink);
12563 return;
12564 }
12565 m_pFormatter->connect_changed(rLink);
12566 }
12567
12568 virtual void connect_focus_out(const Link<weld::Widget&, void>& rLink) override
12569 {
12570 if (!m_pFormatter) // once a formatter is set, it takes over "focus-out"
12571 {
12572 GtkInstanceEntry::connect_focus_out(rLink);
12573 return;
12574 }
12575 m_pFormatter->connect_focus_out(rLink);
12576 }
12577
12578 virtual void SetFormatter(weld::EntryFormatter* pFormatter) override
12579 {
12580 m_xOwnFormatter.reset();
12581 m_pFormatter = pFormatter;
12582 sync_range_from_formatter();
12583 sync_value_from_formatter();
12584 sync_increments_from_formatter();
12585 }
12586
12587 virtual weld::EntryFormatter& GetFormatter() override
12588 {
12589 if (!m_pFormatter)
12590 {
12591 auto aFocusOutHdl = m_aFocusOutHdl;
12592 m_aFocusOutHdl = Link<weld::Widget&, void>();
12593 auto aChangeHdl = m_aChangeHdl;
12594 m_aChangeHdl = Link<weld::Entry&, void>();
12595
12596 double fValue = gtk_spin_button_get_value(m_pButton);
12597 double fMin, fMax;
12598 gtk_spin_button_get_range(m_pButton, &fMin, &fMax);
12599 double fStep;
12600 gtk_spin_button_get_increments(m_pButton, &fStep, nullptr);
12601 m_xOwnFormatter.reset(new weld::EntryFormatter(*this));
12602 m_xOwnFormatter->SetMinValue(fMin);
12603 m_xOwnFormatter->SetMaxValue(fMax);
12604 m_xOwnFormatter->SetSpinSize(fStep);
12605 m_xOwnFormatter->SetValue(fValue);
12606
12607 m_xOwnFormatter->connect_focus_out(aFocusOutHdl);
12608 m_xOwnFormatter->connect_changed(aChangeHdl);
12609
12610 m_pFormatter = m_xOwnFormatter.get();
12611 }
12612 return *m_pFormatter;
12613 }
12614
12615 virtual void sync_value_from_formatter() override
12616 {
12617 if (!m_pFormatter)
12618 return;
12619 // tdf#135317 avoid reenterence
12620 if (m_bSyncingValue)
12621 return;
12622 m_bSyncingValue = true;
12623 disable_notify_events();
12624 gtk_spin_button_set_value(m_pButton, m_pFormatter->GetValue());
12625 enable_notify_events();
12626 m_bSyncingValue = false;
12627 }
12628
12629 virtual void sync_range_from_formatter() override
12630 {
12631 if (!m_pFormatter)
12632 return;
12633 disable_notify_events();
12634 double fMin = m_pFormatter->HasMinValue() ? m_pFormatter->GetMinValue() : std::numeric_limits<double>::lowest();
12635 double fMax = m_pFormatter->HasMaxValue() ? m_pFormatter->GetMaxValue() : std::numeric_limits<double>::max();
12636 gtk_spin_button_set_range(m_pButton, fMin, fMax);
12637 enable_notify_events();
12638 }
12639
12640 virtual void sync_increments_from_formatter() override
12641 {
12642 if (!m_pFormatter)
12643 return;
12644 disable_notify_events();
12645 double fSpinSize = m_pFormatter->GetSpinSize();
12646 gtk_spin_button_set_increments(m_pButton, fSpinSize, fSpinSize * 10);
12647 enable_notify_events();
12648 }
12649
12650 virtual ~GtkInstanceFormattedSpinButton() override
12651 {
12652 g_signal_handler_disconnect(m_pButton, m_nInputSignalId);
12653 g_signal_handler_disconnect(m_pButton, m_nOutputSignalId);
12654 g_signal_handler_disconnect(m_pButton, m_nValueChangedSignalId);
12655
12656 m_pFormatter = nullptr;
12657 m_xOwnFormatter.reset();
12658 }
12659};
12660
12661class GtkInstanceLabel : public GtkInstanceWidget, public virtual weld::Label
12662{
12663private:
12664 GtkLabel* m_pLabel;
12665
12666 void set_text_background_color(const Color& rColor)
12667 {
12668 guint16 nRed = rColor.GetRed() << 8;
12669 guint16 nGreen = rColor.GetRed() << 8;
12670 guint16 nBlue = rColor.GetBlue() << 8;
12671
12672 PangoAttrType aFilterAttrs[] = {PANGO_ATTR_BACKGROUND, PANGO_ATTR_INVALID};
12673
12674 PangoAttrList* pOrigList = gtk_label_get_attributes(m_pLabel);
12675 PangoAttrList* pAttrs = pOrigList ? pango_attr_list_copy(pOrigList) : pango_attr_list_new();
12676 PangoAttrList* pRemovedAttrs = pOrigList ? pango_attr_list_filter(pAttrs, filter_pango_attrs, &aFilterAttrs) : nullptr;
12677 pango_attr_list_insert(pAttrs, pango_attr_background_new(nRed, nGreen, nBlue));
12678 gtk_label_set_attributes(m_pLabel, pAttrs);
12679 pango_attr_list_unref(pAttrs);
12680 pango_attr_list_unref(pRemovedAttrs);
12681 }
12682
12683 void set_text_foreground_color(const Color& rColor, bool bSetBold)
12684 {
12685 guint16 nRed = rColor.GetRed() << 8;
12686 guint16 nGreen = rColor.GetRed() << 8;
12687 guint16 nBlue = rColor.GetBlue() << 8;
12688
12689 PangoAttrType aFilterAttrs[] = {PANGO_ATTR_FOREGROUND, PANGO_ATTR_WEIGHT, PANGO_ATTR_INVALID};
12690
12691 if (!bSetBold)
12692 aFilterAttrs[1] = PANGO_ATTR_INVALID;
12693
12694 PangoAttrList* pOrigList = gtk_label_get_attributes(m_pLabel);
12695 PangoAttrList* pAttrs = pOrigList ? pango_attr_list_copy(pOrigList) : pango_attr_list_new();
12696 PangoAttrList* pRemovedAttrs = pOrigList ? pango_attr_list_filter(pAttrs, filter_pango_attrs, &aFilterAttrs) : nullptr;
12697 if (rColor != COL_AUTO)
12698 pango_attr_list_insert(pAttrs, pango_attr_foreground_new(nRed, nGreen, nBlue));
12699 if (bSetBold)
12700 pango_attr_list_insert(pAttrs, pango_attr_weight_new(PANGO_WEIGHT_BOLD));
12701 gtk_label_set_attributes(m_pLabel, pAttrs);
12702 pango_attr_list_unref(pAttrs);
12703 pango_attr_list_unref(pRemovedAttrs);
12704 }
12705
12706public:
12707 GtkInstanceLabel(GtkLabel* pLabel, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
12708 : GtkInstanceWidget(GTK_WIDGET(pLabel)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pLabel)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
12709 , m_pLabel(pLabel)
12710 {
12711 }
12712
12713 virtual void set_label(const OUString& rText) override
12714 {
12715 ::set_label(m_pLabel, rText);
12716 }
12717
12718 virtual OUString get_label() const override
12719 {
12720 return ::get_label(m_pLabel);
12721 }
12722
12723 virtual void set_mnemonic_widget(Widget* pTarget) override
12724 {
12725 assert(!gtk_label_get_selectable(m_pLabel) && "don't use set_mnemonic_widget on selectable labels, for consistency with gen backend")(static_cast <bool> (!gtk_label_get_selectable(m_pLabel
) && "don't use set_mnemonic_widget on selectable labels, for consistency with gen backend"
) ? void (0) : __assert_fail ("!gtk_label_get_selectable(m_pLabel) && \"don't use set_mnemonic_widget on selectable labels, for consistency with gen backend\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 12725, __extension__ __PRETTY_FUNCTION__))
;
12726 GtkInstanceWidget* pTargetWidget = dynamic_cast<GtkInstanceWidget*>(pTarget);
12727 gtk_label_set_mnemonic_widget(m_pLabel, pTargetWidget ? pTargetWidget->getWidget() : nullptr);
12728 }
12729
12730 virtual void set_label_type(weld::LabelType eType) override
12731 {
12732 switch (eType)
12733 {
12734 case weld::LabelType::Normal:
12735 gtk_label_set_attributes(m_pLabel, nullptr);
12736 break;
12737 case weld::LabelType::Warning:
12738 set_text_background_color(COL_YELLOW);
12739 break;
12740 case weld::LabelType::Error:
12741 set_text_background_color(Application::GetSettings().GetStyleSettings().GetHighlightColor());
12742 break;
12743 case weld::LabelType::Title:
12744 set_text_foreground_color(Application::GetSettings().GetStyleSettings().GetLightColor(), true);
12745 break;
12746 }
12747 }
12748
12749 virtual void set_font(const vcl::Font& rFont) override
12750 {
12751 // TODO, clear old props like set_text_foreground_color does
12752 PangoAttrList* pAttrList = create_attr_list(rFont);
12753 gtk_label_set_attributes(m_pLabel, pAttrList);
12754 pango_attr_list_unref(pAttrList);
12755 }
12756
12757 virtual void set_font_color(const Color& rColor) override
12758 {
12759 set_text_foreground_color(rColor, false);
12760 }
12761};
12762
12763}
12764
12765std::unique_ptr<weld::Label> GtkInstanceFrame::weld_label_widget() const
12766{
12767 GtkWidget* pLabel = gtk_frame_get_label_widget(m_pFrame);
12768 if (!pLabel || !GTK_IS_LABEL(pLabel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pLabel)); GType __t = ((gtk_label_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
12769 return nullptr;
12770 return std::make_unique<GtkInstanceLabel>(GTK_LABEL(pLabel)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pLabel)), ((gtk_label_get_type ()))))))
, m_pBuilder, false);
12771}
12772
12773namespace {
12774
12775class GtkInstanceTextView : public GtkInstanceContainer, public virtual weld::TextView
12776{
12777private:
12778 GtkTextView* m_pTextView;
12779 GtkTextBuffer* m_pTextBuffer;
12780 GtkAdjustment* m_pVAdjustment;
12781 GtkCssProvider* m_pFgCssProvider;
12782 int m_nMaxTextLength;
12783 gulong m_nChangedSignalId; // we don't disable/enable this one, it's to implement max-length
12784 gulong m_nInsertTextSignalId;
12785 gulong m_nCursorPosSignalId;
12786 gulong m_nHasSelectionSignalId; // we don't disable/enable this one, it's to implement
12787 // auto-scroll to cursor on losing selection
12788 gulong m_nVAdjustChangedSignalId;
12789 gulong m_nButtonPressEvent; // we don't disable/enable this one, it's to block mouse
12790 // click down from getting to (potential) toplevel
12791 // GtkSalFrame parent, which grabs focus away
12792
12793 static gboolean signalButtonPressEvent(GtkWidget*, GdkEventButton*, gpointer)
12794 {
12795 // e.g. on clicking on the help TextView in OTableDesignHelpBar the currently displayed text shouldn't disappear
12796 return true;
12797 }
12798
12799 static void signalChanged(GtkTextBuffer*, gpointer widget)
12800 {
12801 GtkInstanceTextView* pThis = static_cast<GtkInstanceTextView*>(widget);
12802 SolarMutexGuard aGuard;
12803 pThis->signal_changed();
12804 }
12805
12806 static void signalInserText(GtkTextBuffer *pBuffer, GtkTextIter *pLocation, gchar* /*pText*/, gint /*nLen*/, gpointer widget)
12807 {
12808 GtkInstanceTextView* pThis = static_cast<GtkInstanceTextView*>(widget);
12809 pThis->insert_text(pBuffer, pLocation);
12810 }
12811
12812 void insert_text(GtkTextBuffer *pBuffer, GtkTextIter *pLocation)
12813 {
12814 if (m_nMaxTextLength)
12815 {
12816 gint nCount = gtk_text_buffer_get_char_count(pBuffer);
12817 if (nCount > m_nMaxTextLength)
12818 {
12819 GtkTextIter nStart, nEnd;
12820 gtk_text_buffer_get_iter_at_offset(m_pTextBuffer, &nStart, m_nMaxTextLength);
12821 gtk_text_buffer_get_end_iter(m_pTextBuffer, &nEnd);
12822 gtk_text_buffer_delete(m_pTextBuffer, &nStart, &nEnd);
12823 gtk_text_iter_assign(pLocation, &nStart);
12824 }
12825 }
12826 }
12827
12828 static void signalCursorPosition(GtkTextBuffer*, GParamSpec*, gpointer widget)
12829 {
12830 GtkInstanceTextView* pThis = static_cast<GtkInstanceTextView*>(widget);
12831 pThis->signal_cursor_position();
12832 }
12833
12834 static void signalHasSelection(GtkTextBuffer*, GParamSpec*, gpointer widget)
12835 {
12836 GtkInstanceTextView* pThis = static_cast<GtkInstanceTextView*>(widget);
12837 pThis->signal_has_selection();
12838 }
12839
12840 void signal_has_selection()
12841 {
12842 /*
12843 in the data browser (Data Sources, shift+ctrl+f4), entering a
12844 multiline cell selects all, on cursoring to the right, the selection
12845 is lost and the cursor is at the end but gtk doesn't auto-scroll to
12846 the cursor so if the text needs scrolling to see the cursor it is off
12847 screen, another cursor makes gtk auto-scroll as wanted. So on losing
12848 selection help gtk out and do the initial scroll ourselves here
12849 */
12850 if (!gtk_text_buffer_get_has_selection(m_pTextBuffer))
12851 {
12852 GtkTextMark* pMark = gtk_text_buffer_get_insert(m_pTextBuffer);
12853 gtk_text_view_scroll_mark_onscreen(m_pTextView, pMark);
12854 }
12855 }
12856
12857 static void signalVAdjustValueChanged(GtkAdjustment*, gpointer widget)
12858 {
12859 GtkInstanceTextView* pThis = static_cast<GtkInstanceTextView*>(widget);
12860 SolarMutexGuard aGuard;
12861 pThis->signal_vadjustment_changed();
12862 }
12863
12864public:
12865 GtkInstanceTextView(GtkTextView* pTextView, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
12866 : GtkInstanceContainer(GTK_CONTAINER(pTextView)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pTextView)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
12867 , m_pTextView(pTextView)
12868 , m_pTextBuffer(gtk_text_view_get_buffer(pTextView))
12869 , m_pVAdjustment(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(pTextView)((((GtkScrollable*) g_type_check_instance_cast ((GTypeInstance
*) ((pTextView)), ((gtk_scrollable_get_type ()))))))
))
12870 , m_pFgCssProvider(nullptr)
12871 , m_nMaxTextLength(0)
12872 , m_nChangedSignalId(g_signal_connect(m_pTextBuffer, "changed", G_CALLBACK(signalChanged), this)g_signal_connect_data ((m_pTextBuffer), ("changed"), (((GCallback
) (signalChanged))), (this), __null, (GConnectFlags) 0)
)
12873 , m_nInsertTextSignalId(g_signal_connect_after(m_pTextBuffer, "insert-text", G_CALLBACK(signalInserText), this)g_signal_connect_data ((m_pTextBuffer), ("insert-text"), (((GCallback
) (signalInserText))), (this), __null, G_CONNECT_AFTER)
)
12874 , m_nCursorPosSignalId(g_signal_connect(m_pTextBuffer, "notify::cursor-position", G_CALLBACK(signalCursorPosition), this)g_signal_connect_data ((m_pTextBuffer), ("notify::cursor-position"
), (((GCallback) (signalCursorPosition))), (this), __null, (GConnectFlags
) 0)
)
12875 , m_nHasSelectionSignalId(g_signal_connect(m_pTextBuffer, "notify::has-selection", G_CALLBACK(signalHasSelection), this)g_signal_connect_data ((m_pTextBuffer), ("notify::has-selection"
), (((GCallback) (signalHasSelection))), (this), __null, (GConnectFlags
) 0)
)
12876 , m_nVAdjustChangedSignalId(g_signal_connect(m_pVAdjustment, "value-changed", G_CALLBACK(signalVAdjustValueChanged), this)g_signal_connect_data ((m_pVAdjustment), ("value-changed"), (
((GCallback) (signalVAdjustValueChanged))), (this), __null, (
GConnectFlags) 0)
)
12877 , m_nButtonPressEvent(g_signal_connect_after(m_pTextView, "button-press-event", G_CALLBACK(signalButtonPressEvent), this)g_signal_connect_data ((m_pTextView), ("button-press-event"),
(((GCallback) (signalButtonPressEvent))), (this), __null, G_CONNECT_AFTER
)
)
12878 {
12879 }
12880
12881 virtual void set_size_request(int nWidth, int nHeight) override
12882 {
12883 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
12884 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
12885 {
12886 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
, nWidth);
12887 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(pParent)((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_scrolled_window_get_type ()))))))
, nHeight);
12888 return;
12889 }
12890 gtk_widget_set_size_request(m_pWidget, nWidth, nHeight);
12891 }
12892
12893 virtual void set_text(const OUString& rText) override
12894 {
12895 disable_notify_events();
12896 OString sText(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
12897 gtk_text_buffer_set_text(m_pTextBuffer, sText.getStr(), sText.getLength());
12898 enable_notify_events();
12899 }
12900
12901 virtual OUString get_text() const override
12902 {
12903 GtkTextIter start, end;
12904 gtk_text_buffer_get_bounds(m_pTextBuffer, &start, &end);
12905 char* pStr = gtk_text_buffer_get_text(m_pTextBuffer, &start, &end, true);
12906 OUString sRet(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
12907 g_free(pStr);
12908 return sRet;
12909 }
12910
12911 virtual void replace_selection(const OUString& rText) override
12912 {
12913 disable_notify_events();
12914 gtk_text_buffer_delete_selection(m_pTextBuffer, false, gtk_text_view_get_editable(m_pTextView));
12915 OString sText(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
12916 gtk_text_buffer_insert_at_cursor(m_pTextBuffer, sText.getStr(), sText.getLength());
12917 enable_notify_events();
12918 }
12919
12920 virtual bool get_selection_bounds(int& rStartPos, int& rEndPos) override
12921 {
12922 GtkTextIter start, end;
12923 gtk_text_buffer_get_selection_bounds(m_pTextBuffer, &start, &end);
12924 rStartPos = gtk_text_iter_get_offset(&start);
12925 rEndPos = gtk_text_iter_get_offset(&end);
12926 return rStartPos != rEndPos;
12927 }
12928
12929 virtual void select_region(int nStartPos, int nEndPos) override
12930 {
12931 disable_notify_events();
12932 GtkTextIter start, end;
12933 gtk_text_buffer_get_iter_at_offset(m_pTextBuffer, &start, nStartPos);
12934 gtk_text_buffer_get_iter_at_offset(m_pTextBuffer, &end, nEndPos);
12935 gtk_text_buffer_select_range(m_pTextBuffer, &start, &end);
12936 GtkTextMark* mark = gtk_text_buffer_create_mark(m_pTextBuffer, "scroll", &end, true);
12937 gtk_text_view_scroll_mark_onscreen(m_pTextView, mark);
12938 enable_notify_events();
12939 }
12940
12941 virtual void set_editable(bool bEditable) override
12942 {
12943 gtk_text_view_set_editable(m_pTextView, bEditable);
12944 }
12945
12946 virtual bool get_editable() const override
12947 {
12948 return gtk_text_view_get_editable(m_pTextView);
12949 }
12950
12951 virtual void set_max_length(int nChars) override
12952 {
12953 m_nMaxTextLength = nChars;
12954 }
12955
12956 virtual void set_monospace(bool bMonospace) override
12957 {
12958 gtk_text_view_set_monospace(m_pTextView, bMonospace);
12959 }
12960
12961 virtual void set_font_color(const Color& rColor) override
12962 {
12963 const bool bRemoveColor = rColor == COL_AUTO;
12964 if (bRemoveColor && !m_pFgCssProvider)
12965 return;
12966 GtkStyleContext *pWidgetContext = gtk_widget_get_style_context(GTK_WIDGET(m_pTextView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTextView)), ((gtk_widget_get_type ()))))))
);
12967 if (m_pFgCssProvider)
12968 {
12969 gtk_style_context_remove_provider(pWidgetContext, GTK_STYLE_PROVIDER(m_pFgCssProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pFgCssProvider)), ((gtk_style_provider_get_type ()))))
))
);
12970 m_pFgCssProvider = nullptr;
12971 }
12972 if (bRemoveColor)
12973 return;
12974 OUString sColor = rColor.AsRGBHexString();
12975 m_pFgCssProvider = gtk_css_provider_new();
12976 OUString aBuffer = "textview text { color: #" + sColor + "; }";
12977 OString aResult = OUStringToOString(aBuffer, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
12978 gtk_css_provider_load_from_data(m_pFgCssProvider, aResult.getStr(), aResult.getLength(), nullptr);
12979 gtk_style_context_add_provider(pWidgetContext, GTK_STYLE_PROVIDER(m_pFgCssProvider)((((GtkStyleProvider*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pFgCssProvider)), ((gtk_style_provider_get_type ()))))
))
,
12980 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
12981 }
12982
12983 virtual void disable_notify_events() override
12984 {
12985 g_signal_handler_block(m_pVAdjustment, m_nVAdjustChangedSignalId);
12986 g_signal_handler_block(m_pTextBuffer, m_nCursorPosSignalId);
12987 g_signal_handler_block(m_pTextBuffer, m_nChangedSignalId);
12988 GtkInstanceContainer::disable_notify_events();
12989 }
12990
12991 virtual void enable_notify_events() override
12992 {
12993 GtkInstanceContainer::enable_notify_events();
12994 g_signal_handler_unblock(m_pTextBuffer, m_nChangedSignalId);
12995 g_signal_handler_unblock(m_pTextBuffer, m_nCursorPosSignalId);
12996 g_signal_handler_unblock(m_pVAdjustment, m_nVAdjustChangedSignalId);
12997 }
12998
12999 // in gtk, 'up' when on the first line, will jump to the start of the line
13000 // if not there already
13001 virtual bool can_move_cursor_with_up() const override
13002 {
13003 GtkTextIter start, end;
13004 gtk_text_buffer_get_selection_bounds(m_pTextBuffer, &start, &end);
13005 return !gtk_text_iter_equal(&start, &end) || !gtk_text_iter_is_start(&start);
13006 }
13007
13008 // in gtk, 'down' when on the first line, will jump to the end of the line
13009 // if not there already
13010 virtual bool can_move_cursor_with_down() const override
13011 {
13012 GtkTextIter start, end;
13013 gtk_text_buffer_get_selection_bounds(m_pTextBuffer, &start, &end);
13014 return !gtk_text_iter_equal(&start, &end) || !gtk_text_iter_is_end(&end);
13015 }
13016
13017 virtual void cut_clipboard() override
13018 {
13019 GtkClipboard *pClipboard = gtk_widget_get_clipboard(GTK_WIDGET(m_pTextView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTextView)), ((gtk_widget_get_type ()))))))
,
13020 GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))));
13021 gtk_text_buffer_cut_clipboard(m_pTextBuffer, pClipboard, get_editable());
13022 }
13023
13024 virtual void copy_clipboard() override
13025 {
13026 GtkClipboard *pClipboard = gtk_widget_get_clipboard(GTK_WIDGET(m_pTextView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTextView)), ((gtk_widget_get_type ()))))))
,
13027 GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))));
13028 gtk_text_buffer_copy_clipboard(m_pTextBuffer, pClipboard);
13029 }
13030
13031 virtual void paste_clipboard() override
13032 {
13033 GtkClipboard *pClipboard = gtk_widget_get_clipboard(GTK_WIDGET(m_pTextView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTextView)), ((gtk_widget_get_type ()))))))
,
13034 GDK_SELECTION_CLIPBOARD((GdkAtom)((gpointer) (gulong) (69))));
13035 gtk_text_buffer_paste_clipboard(m_pTextBuffer, pClipboard, nullptr, get_editable());
13036 }
13037
13038 virtual void set_alignment(TxtAlign eXAlign) override
13039 {
13040 GtkJustification eJust = GTK_JUSTIFY_LEFT;
13041 switch (eXAlign)
13042 {
13043 case TxtAlign::Left:
13044 eJust = GTK_JUSTIFY_LEFT;
13045 break;
13046 case TxtAlign::Center:
13047 eJust = GTK_JUSTIFY_CENTER;
13048 break;
13049 case TxtAlign::Right:
13050 eJust = GTK_JUSTIFY_RIGHT;
13051 break;
13052 }
13053 gtk_text_view_set_justification(m_pTextView, eJust);
13054 }
13055
13056 virtual int vadjustment_get_value() const override
13057 {
13058 return gtk_adjustment_get_value(m_pVAdjustment);
13059 }
13060
13061 virtual void vadjustment_set_value(int value) override
13062 {
13063 disable_notify_events();
13064 gtk_adjustment_set_value(m_pVAdjustment, value);
13065 enable_notify_events();
13066 }
13067
13068 virtual int vadjustment_get_upper() const override
13069 {
13070 return gtk_adjustment_get_upper(m_pVAdjustment);
13071 }
13072
13073 virtual int vadjustment_get_lower() const override
13074 {
13075 return gtk_adjustment_get_lower(m_pVAdjustment);
13076 }
13077
13078 virtual int vadjustment_get_page_size() const override
13079 {
13080 return gtk_adjustment_get_page_size(m_pVAdjustment);
13081 }
13082
13083 virtual void show() override
13084 {
13085 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
13086 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
13087 gtk_widget_show(pParent);
13088 gtk_widget_show(m_pWidget);
13089 }
13090
13091 virtual void hide() override
13092 {
13093 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
13094 if (GTK_IS_SCROLLED_WINDOW(pParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pParent)); GType __t = ((gtk_scrolled_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
13095 gtk_widget_hide(pParent);
13096 gtk_widget_hide(m_pWidget);
13097 }
13098
13099 virtual ~GtkInstanceTextView() override
13100 {
13101 g_signal_handler_disconnect(m_pTextView, m_nButtonPressEvent);
13102 g_signal_handler_disconnect(m_pVAdjustment, m_nVAdjustChangedSignalId);
13103 g_signal_handler_disconnect(m_pTextBuffer, m_nInsertTextSignalId);
13104 g_signal_handler_disconnect(m_pTextBuffer, m_nChangedSignalId);
13105 g_signal_handler_disconnect(m_pTextBuffer, m_nCursorPosSignalId);
13106 g_signal_handler_disconnect(m_pTextBuffer, m_nHasSelectionSignalId);
13107 }
13108};
13109
13110// IMHandler
13111class IMHandler;
13112
13113AtkObject* (*default_drawing_area_get_accessible)(GtkWidget *widget);
13114
13115class GtkInstanceDrawingArea : public GtkInstanceWidget, public virtual weld::DrawingArea
13116{
13117private:
13118 GtkDrawingArea* m_pDrawingArea;
13119 a11yref m_xAccessible;
13120 AtkObject *m_pAccessible;
13121 ScopedVclPtrInstance<VirtualDevice> m_xDevice;
13122 std::unique_ptr<IMHandler> m_xIMHandler;
13123 cairo_surface_t* m_pSurface;
13124 gulong m_nDrawSignalId;
13125 gulong m_nStyleUpdatedSignalId;
13126 gulong m_nQueryTooltip;
13127 gulong m_nPopupMenu;
13128 gulong m_nScrollEvent;
13129
13130 static gboolean signalDraw(GtkWidget*, cairo_t* cr, gpointer widget)
13131 {
13132 GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
13133 SolarMutexGuard aGuard;
13134 pThis->signal_draw(cr);
13135 return false;
13136 }
13137 void signal_draw(cairo_t* cr)
13138 {
13139 GdkRectangle rect;
13140 if (!m_pSurface || !gdk_cairo_get_clip_rectangle(cr, &rect))
13141 return;
13142 tools::Rectangle aRect(Point(rect.x, rect.y), Size(rect.width, rect.height));
13143 aRect = m_xDevice->PixelToLogic(aRect);
13144 m_xDevice->Erase(aRect);
13145 m_aDrawHdl.Call(std::pair<vcl::RenderContext&, const tools::Rectangle&>(*m_xDevice, aRect));
13146 cairo_surface_mark_dirty(m_pSurface);
13147
13148 cairo_set_source_surface(cr, m_pSurface, 0, 0);
13149 cairo_paint(cr);
13150
13151 tools::Rectangle aFocusRect(m_aGetFocusRectHdl.Call(*this));
13152 if (!aFocusRect.IsEmpty())
13153 {
13154 gtk_render_focus(gtk_widget_get_style_context(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
), cr,
13155 aFocusRect.Left(), aFocusRect.Top(), aFocusRect.GetWidth(), aFocusRect.GetHeight());
13156 }
13157 }
13158 virtual void signal_size_allocate(guint nWidth, guint nHeight) override
13159 {
13160 m_xDevice->SetOutputSizePixel(Size(nWidth, nHeight));
13161 m_pSurface = get_underlying_cairo_surface(*m_xDevice);
13162 GtkInstanceWidget::signal_size_allocate(nWidth, nHeight);
13163 }
13164 static void signalStyleUpdated(GtkWidget*, gpointer widget)
13165 {
13166 GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
13167 SolarMutexGuard aGuard;
13168 return pThis->signal_style_updated();
13169 }
13170 void signal_style_updated()
13171 {
13172 m_aStyleUpdatedHdl.Call(*this);
13173 }
13174 static gboolean signalQueryTooltip(GtkWidget* pGtkWidget, gint x, gint y,
13175 gboolean /*keyboard_mode*/, GtkTooltip *tooltip,
13176 gpointer widget)
13177 {
13178 GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
13179 tools::Rectangle aHelpArea(x, y);
13180 OUString aTooltip = pThis->signal_query_tooltip(aHelpArea);
13181 if (aTooltip.isEmpty())
13182 return false;
13183 gtk_tooltip_set_text(tooltip, OUStringToOString(aTooltip, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
13184 GdkRectangle aGdkHelpArea;
13185 aGdkHelpArea.x = aHelpArea.Left();
13186 aGdkHelpArea.y = aHelpArea.Top();
13187 aGdkHelpArea.width = aHelpArea.GetWidth();
13188 aGdkHelpArea.height = aHelpArea.GetHeight();
13189 if (pThis->SwapForRTL())
13190 aGdkHelpArea.x = gtk_widget_get_allocated_width(pGtkWidget) - aGdkHelpArea.width - 1 - aGdkHelpArea.x;
13191 gtk_tooltip_set_tip_area(tooltip, &aGdkHelpArea);
13192 return true;
13193 }
13194 virtual bool signal_popup_menu(const CommandEvent& rCEvt) override
13195 {
13196 return signal_command(rCEvt);
13197 }
13198 bool signal_scroll(const GdkEventScroll* pEvent)
13199 {
13200 SalWheelMouseEvent aEvt(GtkSalFrame::GetWheelEvent(*pEvent));
13201
13202 if (SwapForRTL())
13203 aEvt.mnX = gtk_widget_get_allocated_width(m_pWidget) - 1 - aEvt.mnX;
13204
13205 CommandWheelMode nMode;
13206 sal_uInt16 nCode = aEvt.mnCode;
13207 bool bHorz = aEvt.mbHorz;
13208 if (nCode & KEY_MOD1)
13209 nMode = CommandWheelMode::ZOOM;
13210 else if (nCode & KEY_MOD2)
13211 nMode = CommandWheelMode::DATAZOOM;
13212 else
13213 {
13214 nMode = CommandWheelMode::SCROLL;
13215 // #i85450# interpret shift-wheel as horizontal wheel action
13216 if( (nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)) == KEY_SHIFT )
13217 bHorz = true;
13218 }
13219
13220 CommandWheelData aWheelData(aEvt.mnDelta, aEvt.mnNotchDelta, aEvt.mnScrollLines,
13221 nMode, nCode, bHorz, aEvt.mbDeltaIsPixel);
13222 CommandEvent aCEvt(Point(aEvt.mnX, aEvt.mnY), CommandEventId::Wheel, true, &aWheelData);
13223 return m_aCommandHdl.Call(aCEvt);
13224 }
13225 static gboolean signalScroll(GtkWidget*, GdkEventScroll* pEvent, gpointer widget)
13226 {
13227 GtkInstanceDrawingArea* pThis = static_cast<GtkInstanceDrawingArea*>(widget);
13228 return pThis->signal_scroll(pEvent);
13229 }
13230public:
13231 GtkInstanceDrawingArea(GtkDrawingArea* pDrawingArea, GtkInstanceBuilder* pBuilder, const a11yref& rA11y, bool bTakeOwnership)
13232 : GtkInstanceWidget(GTK_WIDGET(pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pDrawingArea)), ((gtk_widget_get_type ()))))))
, pBuilder, bTakeOwnership)
13233 , m_pDrawingArea(pDrawingArea)
13234 , m_xAccessible(rA11y)
13235 , m_pAccessible(nullptr)
13236 , m_xDevice(DeviceFormat::DEFAULT)
13237 , m_pSurface(nullptr)
13238 , m_nDrawSignalId(g_signal_connect(m_pDrawingArea, "draw", G_CALLBACK(signalDraw), this)g_signal_connect_data ((m_pDrawingArea), ("draw"), (((GCallback
) (signalDraw))), (this), __null, (GConnectFlags) 0)
)
13239 , m_nStyleUpdatedSignalId(g_signal_connect(m_pDrawingArea,"style-updated", G_CALLBACK(signalStyleUpdated), this)g_signal_connect_data ((m_pDrawingArea), ("style-updated"), (
((GCallback) (signalStyleUpdated))), (this), __null, (GConnectFlags
) 0)
)
13240 , m_nQueryTooltip(g_signal_connect(m_pDrawingArea, "query-tooltip", G_CALLBACK(signalQueryTooltip), this)g_signal_connect_data ((m_pDrawingArea), ("query-tooltip"), (
((GCallback) (signalQueryTooltip))), (this), __null, (GConnectFlags
) 0)
)
13241 , m_nPopupMenu(g_signal_connect(m_pDrawingArea, "popup-menu", G_CALLBACK(signalPopupMenu), this)g_signal_connect_data ((m_pDrawingArea), ("popup-menu"), (((GCallback
) (signalPopupMenu))), (this), __null, (GConnectFlags) 0)
)
13242 , m_nScrollEvent(g_signal_connect(m_pDrawingArea, "scroll-event", G_CALLBACK(signalScroll), this)g_signal_connect_data ((m_pDrawingArea), ("scroll-event"), ((
(GCallback) (signalScroll))), (this), __null, (GConnectFlags)
0)
)
13243 {
13244 gtk_widget_set_has_tooltip(m_pWidget, true);
13245 g_object_set_data(G_OBJECT(m_pDrawingArea)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pDrawingArea)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceDrawingArea", this);
13246 m_xDevice->EnableRTL(get_direction());
13247 }
13248
13249 AtkObject* GetAtkObject(AtkObject* pDefaultAccessible)
13250 {
13251 if (!m_pAccessible && m_xAccessible.is())
13252 {
13253 GtkWidget* pParent = gtk_widget_get_parent(m_pWidget);
13254 m_pAccessible = atk_object_wrapper_new(m_xAccessible, gtk_widget_get_accessible(pParent), pDefaultAccessible);
13255 if (m_pAccessible)
13256 g_object_ref(m_pAccessible);
13257 }
13258 return m_pAccessible;
13259 }
13260
13261 virtual void connect_mouse_press(const Link<const MouseEvent&, bool>& rLink) override
13262 {
13263 if (!(gtk_widget_get_events(m_pWidget) & GDK_BUTTON_PRESS_MASK))
13264 gtk_widget_add_events(m_pWidget, GDK_BUTTON_PRESS_MASK);
13265 GtkInstanceWidget::connect_mouse_press(rLink);
13266 }
13267
13268 virtual void connect_mouse_release(const Link<const MouseEvent&, bool>& rLink) override
13269 {
13270 if (!(gtk_widget_get_events(m_pWidget) & GDK_BUTTON_RELEASE_MASK))
13271 gtk_widget_add_events(m_pWidget, GDK_BUTTON_RELEASE_MASK);
13272 GtkInstanceWidget::connect_mouse_release(rLink);
13273 }
13274
13275 virtual void set_direction(bool bRTL) override
13276 {
13277 GtkInstanceWidget::set_direction(bRTL);
13278 m_xDevice->EnableRTL(bRTL);
13279 }
13280
13281 virtual void set_cursor(PointerStyle ePointerStyle) override
13282 {
13283 GdkCursor *pCursor = GtkSalFrame::getDisplay()->getCursor(ePointerStyle);
13284 if (!gtk_widget_get_realized(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
))
13285 gtk_widget_realize(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
);
13286 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
), pCursor);
13287 }
13288
13289 virtual void set_input_context(const InputContext& rInputContext) override;
13290
13291 virtual void im_context_set_cursor_location(const tools::Rectangle& rCursorRect, int nExtTextInputWidth) override;
13292
13293 int im_context_get_surrounding(OUString& rSurroundingText)
13294 {
13295 return signal_im_context_get_surrounding(rSurroundingText);
13296 }
13297
13298 bool im_context_delete_surrounding(const Selection& rRange)
13299 {
13300 return signal_im_context_delete_surrounding(rRange);
13301 }
13302
13303 virtual void queue_draw() override
13304 {
13305 gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
);
13306 }
13307
13308 virtual void queue_draw_area(int x, int y, int width, int height) override
13309 {
13310 tools::Rectangle aRect(Point(x, y), Size(width, height));
13311 aRect = m_xDevice->LogicToPixel(aRect);
13312 gtk_widget_queue_draw_area(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
13313 }
13314
13315 virtual void queue_resize() override
13316 {
13317 gtk_widget_queue_resize(GTK_WIDGET(m_pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pDrawingArea)), ((gtk_widget_get_type ()))))))
);
13318 }
13319
13320 virtual a11yref get_accessible_parent() override
13321 {
13322 //get_accessible_parent should only be needed for the vcl implementation,
13323 //in the gtk impl the native AtkObject parent set via
13324 //atk_object_wrapper_new(m_xAccessible, gtk_widget_get_accessible(pParent));
13325 //should negate the need.
13326 assert(false && "get_accessible_parent should only be called on a vcl impl")(static_cast <bool> (false && "get_accessible_parent should only be called on a vcl impl"
) ? void (0) : __assert_fail ("false && \"get_accessible_parent should only be called on a vcl impl\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 13326, __extension__ __PRETTY_FUNCTION__))
;
13327 return uno::Reference<css::accessibility::XAccessible>();
13328 }
13329
13330 virtual a11yrelationset get_accessible_relation_set() override
13331 {
13332 //get_accessible_relation_set should only be needed for the vcl implementation,
13333 //in the gtk impl the native equivalent should negate the need.
13334 assert(false && "get_accessible_parent should only be called on a vcl impl")(static_cast <bool> (false && "get_accessible_parent should only be called on a vcl impl"
) ? void (0) : __assert_fail ("false && \"get_accessible_parent should only be called on a vcl impl\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 13334, __extension__ __PRETTY_FUNCTION__))
;
13335 return uno::Reference<css::accessibility::XAccessibleRelationSet>();
13336 }
13337
13338 virtual Point get_accessible_location() override
13339 {
13340 AtkObject* pAtkObject = default_drawing_area_get_accessible(m_pWidget);
13341 gint x(0), y(0);
13342 if (pAtkObject && ATK_IS_COMPONENT(pAtkObject)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pAtkObject)); GType __t = ((atk_component_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))
)
13343 atk_component_get_extents(ATK_COMPONENT(pAtkObject)(((AtkComponent*) g_type_check_instance_cast ((GTypeInstance*
) ((pAtkObject)), ((atk_component_get_type ())))))
, &x, &y, nullptr, nullptr, ATK_XY_WINDOW);
13344 return Point(x, y);
13345 }
13346
13347 virtual void set_accessible_name(const OUString& rName) override
13348 {
13349 AtkObject* pAtkObject = default_drawing_area_get_accessible(m_pWidget);
13350 if (!pAtkObject)
13351 return;
13352 atk_object_set_name(pAtkObject, OUStringToOString(rName, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
13353 }
13354
13355 virtual OUString get_accessible_name() const override
13356 {
13357 AtkObject* pAtkObject = default_drawing_area_get_accessible(m_pWidget);
13358 const char* pStr = pAtkObject ? atk_object_get_name(pAtkObject) : nullptr;
13359 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
13360 }
13361
13362 virtual OUString get_accessible_description() const override
13363 {
13364 AtkObject* pAtkObject = default_drawing_area_get_accessible(m_pWidget);
13365 const char* pStr = pAtkObject ? atk_object_get_description(pAtkObject) : nullptr;
13366 return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
13367 }
13368
13369 virtual void enable_drag_source(rtl::Reference<TransferDataContainer>& rHelper, sal_uInt8 eDNDConstants) override
13370 {
13371 do_enable_drag_source(rHelper, eDNDConstants);
13372 }
13373
13374 virtual bool do_signal_drag_begin(bool& rUnsetDragIcon) override
13375 {
13376 rUnsetDragIcon = false;
13377 if (m_aDragBeginHdl.Call(*this))
13378 return true;
13379 return false;
13380 }
13381
13382 virtual ~GtkInstanceDrawingArea() override
13383 {
13384 g_object_steal_data(G_OBJECT(m_pDrawingArea)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pDrawingArea)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceDrawingArea");
13385 if (m_pAccessible)
13386 g_object_unref(m_pAccessible);
13387 css::uno::Reference<css::lang::XComponent> xComp(m_xAccessible, css::uno::UNO_QUERY);
13388 if (xComp.is())
13389 xComp->dispose();
13390 g_signal_handler_disconnect(m_pDrawingArea, m_nScrollEvent);
13391 g_signal_handler_disconnect(m_pDrawingArea, m_nPopupMenu);
13392 g_signal_handler_disconnect(m_pDrawingArea, m_nQueryTooltip);
13393 g_signal_handler_disconnect(m_pDrawingArea, m_nStyleUpdatedSignalId);
13394 g_signal_handler_disconnect(m_pDrawingArea, m_nDrawSignalId);
13395 }
13396
13397 virtual OutputDevice& get_ref_device() override
13398 {
13399 return *m_xDevice;
13400 }
13401
13402 bool signal_command(const CommandEvent& rCEvt)
13403 {
13404 return m_aCommandHdl.Call(rCEvt);
13405 }
13406
13407 virtual void click(const Point& rPos) override
13408 {
13409 MouseEvent aEvent(rPos);
13410 m_aMousePressHdl.Call(aEvent);
13411 m_aMouseReleaseHdl.Call(aEvent);
13412 }
13413};
13414
13415class IMHandler
13416{
13417private:
13418 GtkInstanceDrawingArea* m_pArea;
13419 GtkIMContext* m_pIMContext;
13420 OUString m_sPreeditText;
13421 gulong m_nFocusInSignalId;
13422 gulong m_nFocusOutSignalId;
13423 bool m_bExtTextInput;
13424
13425public:
13426 IMHandler(GtkInstanceDrawingArea* pArea)
13427 : m_pArea(pArea)
13428 , m_pIMContext(gtk_im_multicontext_new())
13429 , m_nFocusInSignalId(g_signal_connect(m_pArea->getWidget(), "focus-in-event", G_CALLBACK(signalFocusIn), this)g_signal_connect_data ((m_pArea->getWidget()), ("focus-in-event"
), (((GCallback) (signalFocusIn))), (this), __null, (GConnectFlags
) 0)
)
13430 , m_nFocusOutSignalId(g_signal_connect(m_pArea->getWidget(), "focus-out-event", G_CALLBACK(signalFocusOut), this)g_signal_connect_data ((m_pArea->getWidget()), ("focus-out-event"
), (((GCallback) (signalFocusOut))), (this), __null, (GConnectFlags
) 0)
)
13431 , m_bExtTextInput(false)
13432 {
13433 g_signal_connect(m_pIMContext, "preedit-start", G_CALLBACK(signalIMPreeditStart), this)g_signal_connect_data ((m_pIMContext), ("preedit-start"), (((
GCallback) (signalIMPreeditStart))), (this), __null, (GConnectFlags
) 0)
;
13434 g_signal_connect(m_pIMContext, "preedit-end", G_CALLBACK(signalIMPreeditEnd), this)g_signal_connect_data ((m_pIMContext), ("preedit-end"), (((GCallback
) (signalIMPreeditEnd))), (this), __null, (GConnectFlags) 0)
;
13435 g_signal_connect(m_pIMContext, "commit", G_CALLBACK(signalIMCommit), this)g_signal_connect_data ((m_pIMContext), ("commit"), (((GCallback
) (signalIMCommit))), (this), __null, (GConnectFlags) 0)
;
13436 g_signal_connect(m_pIMContext, "preedit-changed", G_CALLBACK(signalIMPreeditChanged), this)g_signal_connect_data ((m_pIMContext), ("preedit-changed"), (
((GCallback) (signalIMPreeditChanged))), (this), __null, (GConnectFlags
) 0)
;
13437 g_signal_connect(m_pIMContext, "retrieve-surrounding", G_CALLBACK(signalIMRetrieveSurrounding), this)g_signal_connect_data ((m_pIMContext), ("retrieve-surrounding"
), (((GCallback) (signalIMRetrieveSurrounding))), (this), __null
, (GConnectFlags) 0)
;
13438 g_signal_connect(m_pIMContext, "delete-surrounding", G_CALLBACK(signalIMDeleteSurrounding), this)g_signal_connect_data ((m_pIMContext), ("delete-surrounding")
, (((GCallback) (signalIMDeleteSurrounding))), (this), __null
, (GConnectFlags) 0)
;
13439
13440 GtkWidget* pWidget = m_pArea->getWidget();
13441 if (!gtk_widget_get_realized(pWidget))
13442 gtk_widget_realize(pWidget);
13443 GdkWindow* pWin = gtk_widget_get_window(pWidget);
13444 gtk_im_context_set_client_window(m_pIMContext, pWin);
13445 gtk_im_context_focus_in(m_pIMContext);
13446 }
13447
13448 void signalFocus(bool bIn)
13449 {
13450 if (bIn)
13451 gtk_im_context_focus_in(m_pIMContext);
13452 else
13453 gtk_im_context_focus_out(m_pIMContext);
13454 }
13455
13456 static gboolean signalFocusIn(GtkWidget*, GdkEvent*, gpointer im_handler)
13457 {
13458 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13459 pThis->signalFocus(true);
13460 return false;
13461 }
13462
13463 static gboolean signalFocusOut(GtkWidget*, GdkEvent*, gpointer im_handler)
13464 {
13465 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13466 pThis->signalFocus(false);
13467 return false;
13468 }
13469
13470 ~IMHandler()
13471 {
13472 EndExtTextInput();
13473
13474 g_signal_handler_disconnect(m_pArea->getWidget(), m_nFocusOutSignalId);
13475 g_signal_handler_disconnect(m_pArea->getWidget(), m_nFocusInSignalId);
13476
13477 // first give IC a chance to deinitialize
13478 gtk_im_context_set_client_window(m_pIMContext, nullptr);
13479 // destroy old IC
13480 g_object_unref(m_pIMContext);
13481 }
13482
13483 void updateIMSpotLocation()
13484 {
13485 CommandEvent aCEvt(Point(), CommandEventId::CursorPos);
13486 // we expect set_cursor_location to get triggered by this
13487 m_pArea->signal_command(aCEvt);
13488 }
13489
13490 void set_cursor_location(const tools::Rectangle& rRect)
13491 {
13492 GdkRectangle aArea{static_cast<int>(rRect.Left()), static_cast<int>(rRect.Top()),
13493 static_cast<int>(rRect.GetWidth()), static_cast<int>(rRect.GetHeight())};
13494 gtk_im_context_set_cursor_location(m_pIMContext, &aArea);
13495 }
13496
13497 static void signalIMCommit(GtkIMContext* /*pContext*/, gchar* pText, gpointer im_handler)
13498 {
13499 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13500
13501 // at least editeng expects to have seen a start before accepting a commit
13502 pThis->StartExtTextInput();
13503
13504 OUString sText(pText, strlen(pText), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
13505 CommandExtTextInputData aData(sText, nullptr, sText.getLength(), 0, false);
13506 CommandEvent aCEvt(Point(), CommandEventId::ExtTextInput, false, &aData);
13507 pThis->m_pArea->signal_command(aCEvt);
13508
13509 pThis->updateIMSpotLocation();
13510
13511 pThis->EndExtTextInput();
13512
13513 pThis->m_sPreeditText.clear();
13514 }
13515
13516 static void signalIMPreeditChanged(GtkIMContext* pIMContext, gpointer im_handler)
13517 {
13518 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13519
13520 sal_Int32 nCursorPos(0);
13521 sal_uInt8 nCursorFlags(0);
13522 std::vector<ExtTextInputAttr> aInputFlags;
13523 OUString sText = GtkSalFrame::GetPreeditDetails(pIMContext, aInputFlags, nCursorPos, nCursorFlags);
13524
13525 // change from nothing to nothing -> do not start preedit e.g. this
13526 // will activate input into a calc cell without user input
13527 if (sText.isEmpty() && pThis->m_sPreeditText.isEmpty())
13528 return;
13529
13530 pThis->m_sPreeditText = sText;
13531
13532 CommandExtTextInputData aData(sText, aInputFlags.data(), nCursorPos, nCursorFlags, false);
13533 CommandEvent aCEvt(Point(), CommandEventId::ExtTextInput, false, &aData);
13534 pThis->m_pArea->signal_command(aCEvt);
13535
13536 pThis->updateIMSpotLocation();
13537 }
13538
13539 static gboolean signalIMRetrieveSurrounding(GtkIMContext* pContext, gpointer im_handler)
13540 {
13541 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13542
13543 OUString sSurroundingText;
13544 int nCursorIndex = pThis->m_pArea->im_context_get_surrounding(sSurroundingText);
13545
13546 if (nCursorIndex != -1)
13547 {
13548 OString sUTF = OUStringToOString(sSurroundingText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
13549 OUString sCursorText(sSurroundingText.copy(0, nCursorIndex));
13550 gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
13551 OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getLength());
13552 }
13553
13554 return true;
13555 }
13556
13557 static gboolean signalIMDeleteSurrounding(GtkIMContext*, gint nOffset, gint nChars,
13558 gpointer im_handler)
13559 {
13560 bool bRet = false;
13561
13562 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13563
13564 OUString sSurroundingText;
13565 sal_Int32 nCursorIndex = pThis->m_pArea->im_context_get_surrounding(sSurroundingText);
13566
13567 if (nCursorIndex != -1)
13568 {
13569 // Note that offset and n_chars are in characters not in bytes
13570 // which differs from the usage other places in GtkIMContext
13571
13572 if (nOffset > 0)
13573 {
13574 while (nCursorIndex < sSurroundingText.getLength())
13575 sSurroundingText.iterateCodePoints(&nCursorIndex, 1);
13576 }
13577 else if (nOffset < 0)
13578 {
13579 while (nCursorIndex > 0)
13580 sSurroundingText.iterateCodePoints(&nCursorIndex, -1);
13581 }
13582
13583 sal_Int32 nCursorEndIndex(nCursorIndex);
13584 sal_Int32 nCount(0);
13585 while (nCount < nChars && nCursorEndIndex < sSurroundingText.getLength())
13586 ++nCount;
13587
13588 bRet = pThis->m_pArea->im_context_delete_surrounding(Selection(nCursorIndex, nCursorEndIndex));
13589 }
13590
13591 return bRet;
13592 }
13593
13594 void StartExtTextInput()
13595 {
13596 if (m_bExtTextInput)
13597 return;
13598 CommandEvent aCEvt(Point(), CommandEventId::StartExtTextInput);
13599 m_pArea->signal_command(aCEvt);
13600 m_bExtTextInput = true;
13601 }
13602
13603 static void signalIMPreeditStart(GtkIMContext*, gpointer im_handler)
13604 {
13605 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13606 pThis->StartExtTextInput();
13607 pThis->updateIMSpotLocation();
13608 }
13609
13610 void EndExtTextInput()
13611 {
13612 if (!m_bExtTextInput)
13613 return;
13614 CommandEvent aCEvt(Point(), CommandEventId::EndExtTextInput);
13615 m_pArea->signal_command(aCEvt);
13616 m_bExtTextInput = false;
13617 }
13618
13619 static void signalIMPreeditEnd(GtkIMContext*, gpointer im_handler)
13620 {
13621 IMHandler* pThis = static_cast<IMHandler*>(im_handler);
13622 pThis->updateIMSpotLocation();
13623 pThis->EndExtTextInput();
13624 }
13625};
13626
13627void GtkInstanceDrawingArea::set_input_context(const InputContext& rInputContext)
13628{
13629 bool bUseIm(rInputContext.GetOptions() & InputContextFlags::Text);
13630 if (!bUseIm)
13631 {
13632 m_xIMHandler.reset();
13633 return;
13634 }
13635 // create a new im context
13636 if (!m_xIMHandler)
13637 m_xIMHandler.reset(new IMHandler(this));
13638}
13639
13640void GtkInstanceDrawingArea::im_context_set_cursor_location(const tools::Rectangle& rCursorRect, int /*nExtTextInputWidth*/)
13641{
13642 if (!m_xIMHandler)
13643 return;
13644 m_xIMHandler->set_cursor_location(rCursorRect);
13645}
13646
13647}
13648
13649namespace {
13650
13651GtkBuilder* makeComboBoxBuilder()
13652{
13653 OUString aUri(AllSettings::GetUIRootDir() + "vcl/ui/combobox.ui");
13654 OUString aPath;
13655 osl::FileBase::getSystemPathFromFileURL(aUri, aPath);
13656 return gtk_builder_new_from_file(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
13657}
13658
13659// pop down the toplevel combobox menu when something is activated from a custom
13660// submenu, i.e. wysiwyg style menu
13661class CustomRenderMenuButtonHelper : public MenuHelper
13662{
13663private:
13664 GtkToggleButton* m_pComboBox;
13665public:
13666 CustomRenderMenuButtonHelper(GtkMenu* pMenu, GtkToggleButton* pComboBox)
13667 : MenuHelper(pMenu, false)
13668 , m_pComboBox(pComboBox)
13669 {
13670 }
13671 virtual void signal_activate(GtkMenuItem*) override
13672 {
13673 gtk_toggle_button_set_active(m_pComboBox, false);
13674 }
13675};
13676
13677class GtkInstanceComboBox : public GtkInstanceContainer, public vcl::ISearchableStringList, public virtual weld::ComboBox
13678{
13679private:
13680 GtkBuilder* m_pComboBuilder;
13681 GtkComboBox* m_pComboBox;
13682 GtkOverlay* m_pOverlay;
13683 GtkTreeView* m_pTreeView;
13684 GtkMenuButton* m_pOverlayButton; // button that the StyleDropdown uses on an active row
13685 GtkWindow* m_pMenuWindow;
13686 GtkTreeModel* m_pTreeModel;
13687 GtkCellRenderer* m_pButtonTextRenderer;
13688 GtkCellRenderer* m_pMenuTextRenderer;
13689 GtkWidget* m_pToggleButton;
13690 GtkWidget* m_pEntry;
13691 GtkCellView* m_pCellView;
13692 std::unique_ptr<CustomRenderMenuButtonHelper> m_xCustomMenuButtonHelper;
13693 std::unique_ptr<vcl::Font> m_xFont;
13694 std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter;
13695 vcl::QuickSelectionEngine m_aQuickSelectionEngine;
13696 std::vector<std::unique_ptr<GtkTreeRowReference, GtkTreeRowReferenceDeleter>> m_aSeparatorRows;
13697 OUString m_sMenuButtonRow;
13698 bool m_bHoverSelection;
13699 bool m_bMouseInOverlayButton;
13700 bool m_bPopupActive;
13701 bool m_bAutoComplete;
13702 bool m_bAutoCompleteCaseSensitive;
13703 bool m_bChangedByMenu;
13704 bool m_bCustomRenderer;
13705 bool m_bActivateCalled;
13706 gint m_nTextCol;
13707 gint m_nIdCol;
13708 gulong m_nToggleFocusInSignalId;
13709 gulong m_nToggleFocusOutSignalId;
13710 gulong m_nRowActivatedSignalId;
13711 gulong m_nChangedSignalId;
13712 gulong m_nPopupShownSignalId;
13713 gulong m_nKeyPressEventSignalId;
13714 gulong m_nEntryInsertTextSignalId;
13715 gulong m_nEntryActivateSignalId;
13716 gulong m_nEntryFocusInSignalId;
13717 gulong m_nEntryFocusOutSignalId;
13718 gulong m_nEntryKeyPressEventSignalId;
13719 guint m_nAutoCompleteIdleId;
13720 gint m_nNonCustomLineHeight;
13721 gint m_nPrePopupCursorPos;
13722 int m_nMRUCount;
13723 int m_nMaxMRUCount;
13724
13725 static gboolean idleAutoComplete(gpointer widget)
13726 {
13727 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13728 pThis->auto_complete();
13729 return false;
13730 }
13731
13732 void auto_complete()
13733 {
13734 m_nAutoCompleteIdleId = 0;
13735 OUString aStartText = get_active_text();
13736 int nStartPos, nEndPos;
13737 get_entry_selection_bounds(nStartPos, nEndPos);
13738 int nMaxSelection = std::max(nStartPos, nEndPos);
13739 if (nMaxSelection != aStartText.getLength())
13740 return;
13741
13742 disable_notify_events();
13743 int nActive = get_active();
13744 int nStart = nActive;
13745
13746 if (nStart == -1)
13747 nStart = 0;
13748
13749 int nPos = -1;
13750
13751 int nZeroRow = 0;
13752 if (m_nMRUCount)
13753 nZeroRow += (m_nMRUCount + 1);
13754
13755 if (!m_bAutoCompleteCaseSensitive)
13756 {
13757 // Try match case insensitive from current position
13758 nPos = starts_with(m_pTreeModel, aStartText, 0, nStart, false);
13759 if (nPos == -1 && nStart != 0)
13760 {
13761 // Try match case insensitive, but from start
13762 nPos = starts_with(m_pTreeModel, aStartText, 0, nZeroRow, false);
13763 }
13764 }
13765
13766 if (nPos == -1)
13767 {
13768 // Try match case sensitive from current position
13769 nPos = starts_with(m_pTreeModel, aStartText, 0, nStart, true);
13770 if (nPos == -1 && nStart != 0)
13771 {
13772 // Try match case sensitive, but from start
13773 nPos = starts_with(m_pTreeModel, aStartText, 0, nZeroRow, true);
13774 }
13775 }
13776
13777 if (nPos != -1)
13778 {
13779 OUString aText = get_text_including_mru(nPos);
13780 if (aText != aStartText)
13781 set_active_text(aText);
13782 select_entry_region(aText.getLength(), aStartText.getLength());
13783 }
13784 enable_notify_events();
13785 }
13786
13787 static void signalEntryInsertText(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength,
13788 gint* position, gpointer widget)
13789 {
13790 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13791 SolarMutexGuard aGuard;
13792 pThis->signal_entry_insert_text(pEntry, pNewText, nNewTextLength, position);
13793 }
13794
13795 void signal_entry_insert_text(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength, gint* position)
13796 {
13797 // first filter inserted text
13798 if (m_aEntryInsertTextHdl.IsSet())
13799 {
13800 OUString sText(pNewText, nNewTextLength, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
13801 const bool bContinue = m_aEntryInsertTextHdl.Call(sText);
13802 if (bContinue && !sText.isEmpty())
13803 {
13804 OString sFinalText(OUStringToOString(sText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
13805 g_signal_handlers_block_by_func(pEntry, reinterpret_cast<gpointer>(signalEntryInsertText), this)g_signal_handlers_block_matched ((pEntry), (GSignalMatchType)
(G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<gpointer>(signalEntryInsertText)), (this
))
;
13806 gtk_editable_insert_text(GTK_EDITABLE(pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((pEntry)), ((gtk_editable_get_type ()))))))
, sFinalText.getStr(), sFinalText.getLength(), position);
13807 g_signal_handlers_unblock_by_func(pEntry, reinterpret_cast<gpointer>(signalEntryInsertText), this)g_signal_handlers_unblock_matched ((pEntry), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
reinterpret_cast<gpointer>(signalEntryInsertText)), (this
))
;
13808 }
13809 g_signal_stop_emission_by_name(pEntry, "insert-text");
13810 }
13811 if (m_bAutoComplete)
13812 {
13813 // now check for autocompletes
13814 if (m_nAutoCompleteIdleId)
13815 g_source_remove(m_nAutoCompleteIdleId);
13816 m_nAutoCompleteIdleId = g_idle_add(idleAutoComplete, this);
13817 }
13818 }
13819
13820 static void signalChanged(GtkEntry*, gpointer widget)
13821 {
13822 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13823 SolarMutexGuard aGuard;
13824 pThis->fire_signal_changed();
13825 }
13826
13827 void fire_signal_changed()
13828 {
13829 signal_changed();
13830 m_bChangedByMenu = false;
13831 }
13832
13833 static void signalPopupToggled(GtkToggleButton* /*pToggleButton*/, gpointer widget)
13834 {
13835 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13836 pThis->signal_popup_toggled();
13837 }
13838
13839 int get_popup_height(gint& rPopupWidth)
13840 {
13841 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
13842
13843 int nMaxRows = rSettings.GetListBoxMaximumLineCount();
13844 bool bAddScrollWidth = false;
13845 int nRows = get_count_including_mru();
13846 if (nMaxRows < nRows)
13847 {
13848 nRows = nMaxRows;
13849 bAddScrollWidth = true;
13850 }
13851
13852 GList* pColumns = gtk_tree_view_get_columns(m_pTreeView);
13853 gint nRowHeight = get_height_row(m_pTreeView, pColumns);
13854 g_list_free(pColumns);
13855
13856 gint nSeparatorHeight = get_height_row_separator(m_pTreeView);
13857 gint nHeight = get_height_rows(nRowHeight, nSeparatorHeight, nRows);
13858
13859 // if we're using a custom renderer, limit the height to the height nMaxRows would be
13860 // for a normal renderer, and then round down to how many custom rows fit in that
13861 // space
13862 if (m_nNonCustomLineHeight != -1 && nRowHeight)
13863 {
13864 gint nNormalHeight = get_height_rows(m_nNonCustomLineHeight, nSeparatorHeight, nMaxRows);
13865 if (nHeight > nNormalHeight)
13866 {
13867 gint nRowsOnly = nNormalHeight - get_height_rows(0, nSeparatorHeight, nMaxRows);
13868 gint nCustomRows = (nRowsOnly + (nRowHeight - 1)) / nRowHeight;
13869 nHeight = get_height_rows(nRowHeight, nSeparatorHeight, nCustomRows);
13870 }
13871 }
13872
13873 if (bAddScrollWidth)
13874 rPopupWidth += rSettings.GetScrollBarSize();
13875
13876 return nHeight;
13877 }
13878
13879 void toggle_menu()
13880 {
13881 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
))
13882 {
13883 if (m_bHoverSelection)
13884 {
13885 // turn hover selection back off until mouse is moved again
13886 // *after* menu is shown again
13887 gtk_tree_view_set_hover_selection(m_pTreeView, false);
13888 m_bHoverSelection = false;
13889 }
13890
13891 do_ungrab(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
);
13892
13893 gtk_widget_hide(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
);
13894
13895 // so gdk_window_move_to_rect will work again the next time
13896 gtk_widget_unrealize(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
);
13897
13898 gtk_widget_set_size_request(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
, -1, -1);
13899
13900 if (!m_bActivateCalled)
13901 tree_view_set_cursor(m_nPrePopupCursorPos);
13902
13903 // undo show_menu tooltip blocking
13904 GtkWidget* pParent = gtk_widget_get_toplevel(m_pToggleButton);
13905 GtkSalFrame* pFrame = pParent ? GtkSalFrame::getFromWindow(pParent) : nullptr;
13906 if (pFrame)
13907 pFrame->UnblockTooltip();
13908 }
13909 else
13910 {
13911 GtkWidget* pComboBox = GTK_WIDGET(getContainer())((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(getContainer())), ((gtk_widget_get_type ()))))))
;
13912
13913 gint nComboWidth = gtk_widget_get_allocated_width(pComboBox);
13914 GtkRequisition size;
13915 gtk_widget_get_preferred_size(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
, nullptr, &size);
13916
13917 gint nPopupWidth = size.width;
13918 gint nPopupHeight = get_popup_height(nPopupWidth);
13919 nPopupWidth = std::max(nPopupWidth, nComboWidth);
13920
13921 gtk_widget_set_size_request(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
, nPopupWidth, nPopupHeight);
13922
13923 m_nPrePopupCursorPos = get_active();
13924
13925 m_bActivateCalled = false;
13926
13927 // if we are in mru mode always start with the cursor at the top of the menu
13928 if (m_nMaxMRUCount)
13929 tree_view_set_cursor(0);
13930
13931 show_menu(pComboBox, m_pMenuWindow);
13932 }
13933 }
13934
13935 virtual void signal_popup_toggled() override
13936 {
13937 m_aQuickSelectionEngine.Reset();
13938
13939 toggle_menu();
13940
13941 bool bIsShown = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
);
13942 if (m_bPopupActive != bIsShown)
13943 {
13944 m_bPopupActive = bIsShown;
13945 ComboBox::signal_popup_toggled();
13946 if (!m_bPopupActive)
13947 {
13948 //restore focus to the entry view when the popup is gone, which
13949 //is what the vcl case does, to ease the transition a little
13950 grab_focus();
13951 }
13952 }
13953 }
13954
13955 static gboolean signalEntryFocusIn(GtkWidget*, GdkEvent*, gpointer widget)
13956 {
13957 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13958 pThis->signal_entry_focus_in();
13959 return false;
13960 }
13961
13962 void signal_entry_focus_in()
13963 {
13964 signal_focus_in();
13965 }
13966
13967 static gboolean signalEntryFocusOut(GtkWidget*, GdkEvent*, gpointer widget)
13968 {
13969 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13970 pThis->signal_entry_focus_out();
13971 return false;
13972 }
13973
13974 void signal_entry_focus_out()
13975 {
13976 // if we have an untidy selection on losing focus remove the selection
13977 int nStartPos, nEndPos;
13978 if (get_entry_selection_bounds(nStartPos, nEndPos))
13979 {
13980 int nMin = std::min(nStartPos, nEndPos);
13981 int nMax = std::max(nStartPos, nEndPos);
13982 if (nMin != 0 || nMax != get_active_text().getLength())
13983 select_entry_region(0, 0);
13984 }
13985 signal_focus_out();
13986 }
13987
13988 static void signalEntryActivate(GtkEntry*, gpointer widget)
13989 {
13990 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
13991 pThis->signal_entry_activate();
13992 }
13993
13994 void signal_entry_activate()
13995 {
13996 if (m_aEntryActivateHdl.IsSet())
13997 {
13998 SolarMutexGuard aGuard;
13999 if (m_aEntryActivateHdl.Call(*this))
14000 g_signal_stop_emission_by_name(m_pEntry, "activate");
14001 }
14002 update_mru();
14003 }
14004
14005 OUString get(int pos, int col) const
14006 {
14007 OUString sRet;
14008 GtkTreeIter iter;
14009 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
14010 {
14011 gchar* pStr;
14012 gtk_tree_model_get(m_pTreeModel, &iter, col, &pStr, -1);
14013 sRet = OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
14014 g_free(pStr);
14015 }
14016 return sRet;
14017 }
14018
14019 void set(int pos, int col, const OUString& rText)
14020 {
14021 GtkTreeIter iter;
14022 if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos))
14023 {
14024 OString aStr(OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
14025 gtk_list_store_set(GTK_LIST_STORE(m_pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_list_store_get_type ()))))))
, &iter, col, aStr.getStr(), -1);
14026 }
14027 }
14028
14029 int find(const OUString& rStr, int col, bool bSearchMRUArea) const
14030 {
14031 GtkTreeIter iter;
14032 if (!gtk_tree_model_get_iter_first(m_pTreeModel, &iter))
14033 return -1;
14034
14035 int nRet = 0;
14036
14037 if (!bSearchMRUArea && m_nMRUCount)
14038 {
14039 if (!gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, m_nMRUCount + 1))
14040 return -1;
14041 nRet += (m_nMRUCount + 1);
14042 }
14043
14044 OString aStr(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
14045 do
14046 {
14047 gchar* pStr;
14048 gtk_tree_model_get(m_pTreeModel, &iter, col, &pStr, -1);
14049 const bool bEqual = g_strcmp0(pStr, aStr.getStr()) == 0;
14050 g_free(pStr);
14051 if (bEqual)
14052 return nRet;
14053 ++nRet;
14054 } while (gtk_tree_model_iter_next(m_pTreeModel, &iter));
14055
14056 return -1;
14057 }
14058
14059 bool separator_function(const GtkTreePath* path)
14060 {
14061 return ::separator_function(path, m_aSeparatorRows);
14062 }
14063
14064 bool separator_function(int pos)
14065 {
14066 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
14067 bool bRet = separator_function(path);
14068 gtk_tree_path_free(path);
14069 return bRet;
14070 }
14071
14072 static gboolean separatorFunction(GtkTreeModel* pTreeModel, GtkTreeIter* pIter, gpointer widget)
14073 {
14074 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14075 GtkTreePath* path = gtk_tree_model_get_path(pTreeModel, pIter);
14076 bool bRet = pThis->separator_function(path);
14077 gtk_tree_path_free(path);
14078 return bRet;
14079 }
14080
14081 // https://gitlab.gnome.org/GNOME/gtk/issues/310
14082 //
14083 // in the absence of a built-in solution
14084 // a) support typeahead for the case where there is no entry widget, typing ahead
14085 // into the button itself will select via the vcl selection engine, a matching
14086 // entry
14087 static gboolean signalKeyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
14088 {
14089 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14090 return pThis->signal_key_press(pEvent);
14091 }
14092
14093 // tdf#131076 we want return in a ComboBox to act like return in a
14094 // GtkEntry and activate the default dialog/assistant button
14095 bool combobox_activate()
14096 {
14097 GtkWidget *pComboBox = GTK_WIDGET(m_pToggleButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pToggleButton)), ((gtk_widget_get_type ()))))))
;
14098 GtkWidget *pToplevel = gtk_widget_get_toplevel(pComboBox);
14099 GtkWindow *pWindow = GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
;
14100 if (!pWindow)
14101 return false;
14102 if (!GTK_IS_DIALOG(pWindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWindow)); GType __t = ((gtk_dialog_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
&& !GTK_IS_ASSISTANT(pWindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWindow)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
14103 return false;
14104 bool bDone = false;
14105 GtkWidget *pDefaultWidget = gtk_window_get_default_widget(pWindow);
14106 if (pDefaultWidget && pDefaultWidget != m_pToggleButton && gtk_widget_get_sensitive(pDefaultWidget))
14107 bDone = gtk_widget_activate(pDefaultWidget);
14108 return bDone;
14109 }
14110
14111 static gboolean signalEntryKeyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
14112 {
14113 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14114 return pThis->signal_entry_key_press(pEvent);
14115 }
14116
14117 bool signal_entry_key_press(const GdkEventKey* pEvent)
14118 {
14119 KeyEvent aKEvt(GtkToVcl(*pEvent));
14120
14121 vcl::KeyCode aKeyCode = aKEvt.GetKeyCode();
14122
14123 bool bDone = false;
14124
14125 auto nCode = aKeyCode.GetCode();
14126 switch (nCode)
14127 {
14128 case KEY_DOWN:
14129 {
14130 sal_uInt16 nKeyMod = aKeyCode.GetModifier();
14131 if (!nKeyMod)
14132 {
14133 int nCount = get_count_including_mru();
14134 int nActive = get_active_including_mru() + 1;
14135 while (nActive < nCount && separator_function(nActive))
14136 ++nActive;
14137 if (nActive < nCount)
14138 set_active_including_mru(nActive, true);
14139 bDone = true;
14140 }
14141 else if (nKeyMod == KEY_MOD2 && !m_bPopupActive)
14142 {
14143 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, true);
14144 bDone = true;
14145 }
14146 break;
14147 }
14148 case KEY_UP:
14149 {
14150 sal_uInt16 nKeyMod = aKeyCode.GetModifier();
14151 if (!nKeyMod)
14152 {
14153 int nStartBound = m_bPopupActive ? 0 : (m_nMRUCount + 1);
14154 int nActive = get_active_including_mru() - 1;
14155 while (nActive >= nStartBound && separator_function(nActive))
14156 --nActive;
14157 if (nActive >= nStartBound)
14158 set_active_including_mru(nActive, true);
14159 bDone = true;
14160 }
14161 break;
14162 }
14163 case KEY_PAGEUP:
14164 {
14165 sal_uInt16 nKeyMod = aKeyCode.GetModifier();
14166 if (!nKeyMod)
14167 {
14168 int nCount = get_count_including_mru();
14169 int nStartBound = m_bPopupActive ? 0 : (m_nMRUCount + 1);
14170 int nActive = nStartBound;
14171 while (nActive < nCount && separator_function(nActive))
14172 ++nActive;
14173 if (nActive < nCount)
14174 set_active_including_mru(nActive, true);
14175 bDone = true;
14176 }
14177 break;
14178 }
14179 case KEY_PAGEDOWN:
14180 {
14181 sal_uInt16 nKeyMod = aKeyCode.GetModifier();
14182 if (!nKeyMod)
14183 {
14184 int nActive = get_count_including_mru() - 1;
14185 int nStartBound = m_bPopupActive ? 0 : (m_nMRUCount + 1);
14186 while (nActive >= nStartBound && separator_function(nActive))
14187 --nActive;
14188 if (nActive >= nStartBound)
14189 set_active_including_mru(nActive, true);
14190 bDone = true;
14191 }
14192 break;
14193 }
14194 default:
14195 break;
14196 }
14197
14198 return bDone;
14199 }
14200
14201 bool signal_key_press(const GdkEventKey* pEvent)
14202 {
14203 if (m_bHoverSelection)
14204 {
14205 // once a key is pressed, turn off hover selection until mouse is
14206 // moved again otherwise when the treeview scrolls it jumps to the
14207 // position under the mouse.
14208 gtk_tree_view_set_hover_selection(m_pTreeView, false);
14209 m_bHoverSelection = false;
14210 }
14211
14212 KeyEvent aKEvt(GtkToVcl(*pEvent));
14213
14214 vcl::KeyCode aKeyCode = aKEvt.GetKeyCode();
14215
14216 bool bDone = false;
14217
14218 auto nCode = aKeyCode.GetCode();
14219 switch (nCode)
14220 {
14221 case KEY_DOWN:
14222 case KEY_UP:
14223 case KEY_PAGEUP:
14224 case KEY_PAGEDOWN:
14225 case KEY_HOME:
14226 case KEY_END:
14227 case KEY_LEFT:
14228 case KEY_RIGHT:
14229 case KEY_RETURN:
14230 {
14231 m_aQuickSelectionEngine.Reset();
14232 sal_uInt16 nKeyMod = aKeyCode.GetModifier();
14233 // tdf#131076 don't let bare return toggle menu popup active, but do allow deactive
14234 if (nCode == KEY_RETURN && !nKeyMod && !m_bPopupActive)
14235 bDone = combobox_activate();
14236 else if (nCode == KEY_UP && nKeyMod == KEY_MOD2 && m_bPopupActive)
14237 {
14238 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, false);
14239 bDone = true;
14240 }
14241 else if (nCode == KEY_DOWN && nKeyMod == KEY_MOD2 && !m_bPopupActive)
14242 {
14243 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, true);
14244 bDone = true;
14245 }
14246 break;
14247 }
14248 case KEY_ESCAPE:
14249 {
14250 m_aQuickSelectionEngine.Reset();
14251 if (m_bPopupActive)
14252 {
14253 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, false);
14254 bDone = true;
14255 }
14256 break;
14257 }
14258 default:
14259 // tdf#131076 let base space toggle menu popup when it's not already visible
14260 if (nCode == KEY_SPACE && !aKeyCode.GetModifier() && !m_bPopupActive)
14261 bDone = false;
14262 else
14263 bDone = m_aQuickSelectionEngine.HandleKeyEvent(aKEvt);
14264 break;
14265 }
14266
14267 if (!bDone && !m_pEntry)
14268 bDone = signal_entry_key_press(pEvent);
14269
14270 return bDone;
14271 }
14272
14273 vcl::StringEntryIdentifier typeahead_getEntry(int nPos, OUString& out_entryText) const
14274 {
14275 int nEntryCount(get_count_including_mru());
14276 if (nPos >= nEntryCount)
14277 nPos = 0;
14278 out_entryText = get_text_including_mru(nPos);
14279
14280 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
14281 // => normalize
14282 return reinterpret_cast<vcl::StringEntryIdentifier>(nPos + 1);
14283 }
14284
14285 static int typeahead_getEntryPos(vcl::StringEntryIdentifier entry)
14286 {
14287 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
14288 return reinterpret_cast<sal_Int64>(entry) - 1;
14289 }
14290
14291 void tree_view_set_cursor(int pos)
14292 {
14293 if (pos == -1)
14294 {
14295 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(m_pTreeView));
14296 if (m_pCellView)
14297 gtk_cell_view_set_displayed_row(m_pCellView, nullptr);
14298 }
14299 else
14300 {
14301 GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
14302 if (gtk_tree_view_get_model(m_pTreeView))
14303 gtk_tree_view_scroll_to_cell(m_pTreeView, path, nullptr, false, 0, 0);
14304 gtk_tree_view_set_cursor(m_pTreeView, path, nullptr, false);
14305 if (m_pCellView)
14306 gtk_cell_view_set_displayed_row(m_pCellView, path);
14307 gtk_tree_path_free(path);
14308 }
14309 }
14310
14311 int tree_view_get_cursor() const
14312 {
14313 int nRet = -1;
14314
14315 GtkTreePath* path;
14316 gtk_tree_view_get_cursor(m_pTreeView, &path, nullptr);
14317 if (path)
14318 {
14319 gint depth;
14320 gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
14321 nRet = indices[depth-1];
14322 gtk_tree_path_free(path);
14323 }
14324
14325 return nRet;
14326 }
14327
14328 int get_selected_entry() const
14329 {
14330 if (m_bPopupActive)
14331 return tree_view_get_cursor();
14332 else
14333 return get_active_including_mru();
14334 }
14335
14336 void set_typeahead_selected_entry(int nSelect)
14337 {
14338 if (m_bPopupActive)
14339 tree_view_set_cursor(nSelect);
14340 else
14341 set_active_including_mru(nSelect, true);
14342 }
14343
14344 virtual vcl::StringEntryIdentifier CurrentEntry(OUString& out_entryText) const override
14345 {
14346 int nCurrentPos = get_selected_entry();
14347 return typeahead_getEntry((nCurrentPos == -1) ? 0 : nCurrentPos, out_entryText);
14348 }
14349
14350 virtual vcl::StringEntryIdentifier NextEntry(vcl::StringEntryIdentifier currentEntry, OUString& out_entryText) const override
14351 {
14352 int nNextPos = typeahead_getEntryPos(currentEntry) + 1;
14353 return typeahead_getEntry(nNextPos, out_entryText);
14354 }
14355
14356 virtual void SelectEntry(vcl::StringEntryIdentifier entry) override
14357 {
14358 int nSelect = typeahead_getEntryPos(entry);
14359 if (nSelect == get_selected_entry())
14360 {
14361 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
14362 // to select the given entry by typing its starting letters. No need to act.
14363 return;
14364 }
14365
14366 // normalize
14367 int nCount = get_count_including_mru();
14368 if (nSelect >= nCount)
14369 nSelect = nCount ? nCount-1 : -1;
14370
14371 set_typeahead_selected_entry(nSelect);
14372 }
14373
14374 static void signalGrabBroken(GtkWidget*, GdkEventGrabBroken *pEvent, gpointer widget)
14375 {
14376 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14377 pThis->grab_broken(pEvent);
14378 }
14379
14380 void grab_broken(const GdkEventGrabBroken *event)
14381 {
14382 if (event->grab_window == nullptr)
14383 {
14384 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, false);
14385 }
14386 else
14387 {
14388 //try and regrab, so when we lose the grab to the menu of the color palette
14389 //combobox we regain it so the color palette doesn't itself disappear on next
14390 //click on the color palette combobox
14391 do_grab(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
);
14392 }
14393 }
14394
14395 static gboolean signalButtonPress(GtkWidget* pWidget, GdkEventButton* pEvent, gpointer widget)
14396 {
14397 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14398 return pThis->button_press(pWidget, pEvent);
14399 }
14400
14401 bool button_press(GtkWidget* pWidget, GdkEventButton* pEvent)
14402 {
14403 //we want to pop down if the button was pressed outside our popup
14404 gdouble x = pEvent->x_root;
14405 gdouble y = pEvent->y_root;
14406 gint xoffset, yoffset;
14407 gdk_window_get_root_origin(gtk_widget_get_window(pWidget), &xoffset, &yoffset);
14408
14409 GtkAllocation alloc;
14410 gtk_widget_get_allocation(pWidget, &alloc);
14411 xoffset += alloc.x;
14412 yoffset += alloc.y;
14413
14414 gtk_widget_get_allocation(GTK_WIDGET(m_pMenuWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pMenuWindow)), ((gtk_widget_get_type ()))))))
, &alloc);
14415 gint x1 = alloc.x + xoffset;
14416 gint y1 = alloc.y + yoffset;
14417 gint x2 = x1 + alloc.width;
14418 gint y2 = y1 + alloc.height;
14419
14420 if (x > x1 && x < x2 && y > y1 && y < y2)
14421 return false;
14422
14423 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, false);
14424
14425 return false;
14426 }
14427
14428 static gboolean signalMotion(GtkWidget*, GdkEventMotion*, gpointer widget)
14429 {
14430 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14431 pThis->signal_motion();
14432 return false;
14433 }
14434
14435 void signal_motion()
14436 {
14437 // if hover-selection was disabled after pressing a key, then turn it back on again
14438 if (!m_bHoverSelection && !m_bMouseInOverlayButton)
14439 {
14440 gtk_tree_view_set_hover_selection(m_pTreeView, true);
14441 m_bHoverSelection = true;
14442 }
14443 }
14444
14445 static void signalRowActivated(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, gpointer widget)
14446 {
14447 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14448 pThis->handle_row_activated();
14449 }
14450
14451 void handle_row_activated()
14452 {
14453 m_bActivateCalled = true;
14454 m_bChangedByMenu = true;
14455 disable_notify_events();
14456 int nActive = get_active();
14457 if (m_pEntry)
14458 gtk_entry_set_text(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, OUStringToOString(get_text(nActive), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
14459 else
14460 tree_view_set_cursor(nActive);
14461 enable_notify_events();
14462 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
, false);
14463 fire_signal_changed();
14464 update_mru();
14465 }
14466
14467 void do_clear()
14468 {
14469 disable_notify_events();
14470 gtk_tree_view_set_row_separator_func(m_pTreeView, nullptr, nullptr, nullptr);
14471 m_aSeparatorRows.clear();
14472 gtk_list_store_clear(GTK_LIST_STORE(m_pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_list_store_get_type ()))))))
);
14473 m_nMRUCount = 0;
14474 enable_notify_events();
14475 }
14476
14477 virtual int get_max_mru_count() const override
14478 {
14479 return m_nMaxMRUCount;
14480 }
14481
14482 virtual void set_max_mru_count(int nMaxMRUCount) override
14483 {
14484 m_nMaxMRUCount = nMaxMRUCount;
14485 update_mru();
14486 }
14487
14488 void update_mru()
14489 {
14490 int nMRUCount = m_nMRUCount;
14491
14492 if (m_nMaxMRUCount)
14493 {
14494 OUString sActiveText = get_active_text();
14495 OUString sActiveId = get_active_id();
14496 insert_including_mru(0, sActiveText, &sActiveId, nullptr, nullptr);
14497 ++m_nMRUCount;
14498
14499 for (int i = 1; i < m_nMRUCount - 1; ++i)
14500 {
14501 if (get_text_including_mru(i) == sActiveText)
14502 {
14503 remove_including_mru(i);
14504 --m_nMRUCount;
14505 break;
14506 }
14507 }
14508 }
14509
14510 while (m_nMRUCount > m_nMaxMRUCount)
14511 {
14512 remove_including_mru(m_nMRUCount - 1);
14513 --m_nMRUCount;
14514 }
14515
14516 if (m_nMRUCount && !nMRUCount)
14517 insert_separator_including_mru(m_nMRUCount, "separator");
14518 else if (!m_nMRUCount && nMRUCount)
14519 remove_including_mru(m_nMRUCount); // remove separator
14520 }
14521
14522 int get_count_including_mru() const
14523 {
14524 return gtk_tree_model_iter_n_children(m_pTreeModel, nullptr);
14525 }
14526
14527 int get_active_including_mru() const
14528 {
14529 return tree_view_get_cursor();
14530 }
14531
14532 void set_active_including_mru(int pos, bool bInteractive)
14533 {
14534 disable_notify_events();
14535
14536 tree_view_set_cursor(pos);
14537
14538 if (m_pEntry)
14539 {
14540 if (pos != -1)
14541 gtk_entry_set_text(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, OUStringToOString(get_text_including_mru(pos), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
14542 else
14543 gtk_entry_set_text(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, "");
14544 }
14545
14546 m_bChangedByMenu = false;
14547 enable_notify_events();
14548
14549 if (bInteractive && !m_bPopupActive && !m_pEntry)
14550 signal_changed();
14551 }
14552
14553 int find_text_including_mru(const OUString& rStr, bool bSearchMRU) const
14554 {
14555 return find(rStr, m_nTextCol, bSearchMRU);
14556 }
14557
14558 int find_id_including_mru(const OUString& rId, bool bSearchMRU) const
14559 {
14560 return find(rId, m_nIdCol, bSearchMRU);
14561 }
14562
14563 OUString get_text_including_mru(int pos) const
14564 {
14565 return get(pos, m_nTextCol);
14566 }
14567
14568 OUString get_id_including_mru(int pos) const
14569 {
14570 return get(pos, m_nIdCol);
14571 }
14572
14573 void set_id_including_mru(int pos, const OUString& rId)
14574 {
14575 set(pos, m_nIdCol, rId);
14576 }
14577
14578 void remove_including_mru(int pos)
14579 {
14580 disable_notify_events();
14581 GtkTreeIter iter;
14582 gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos);
14583 if (!m_aSeparatorRows.empty())
14584 {
14585 bool bFound = false;
14586
14587 GtkTreePath* pPath = gtk_tree_path_new_from_indices(pos, -1);
14588
14589 for (auto aIter = m_aSeparatorRows.begin(); aIter != m_aSeparatorRows.end(); ++aIter)
14590 {
14591 GtkTreePath* seppath = gtk_tree_row_reference_get_path(aIter->get());
14592 if (seppath)
14593 {
14594 if (gtk_tree_path_compare(pPath, seppath) == 0)
14595 bFound = true;
14596 gtk_tree_path_free(seppath);
14597 }
14598 if (bFound)
14599 {
14600 m_aSeparatorRows.erase(aIter);
14601 break;
14602 }
14603 }
14604
14605 gtk_tree_path_free(pPath);
14606 }
14607 gtk_list_store_remove(GTK_LIST_STORE(m_pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_list_store_get_type ()))))))
, &iter);
14608 enable_notify_events();
14609 }
14610
14611 void insert_separator_including_mru(int pos, const OUString& rId)
14612 {
14613 disable_notify_events();
14614 GtkTreeIter iter;
14615 if (!gtk_tree_view_get_row_separator_func(m_pTreeView))
14616 gtk_tree_view_set_row_separator_func(m_pTreeView, separatorFunction, this, nullptr);
14617 insert_row(GTK_LIST_STORE(m_pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_list_store_get_type ()))))))
, iter, pos, &rId, "", nullptr, nullptr);
14618 GtkTreePath* pPath = gtk_tree_path_new_from_indices(pos, -1);
14619 m_aSeparatorRows.emplace_back(gtk_tree_row_reference_new(m_pTreeModel, pPath));
14620 gtk_tree_path_free(pPath);
14621 enable_notify_events();
14622 }
14623
14624 void insert_including_mru(int pos, const OUString& rText, const OUString* pId, const OUString* pIconName, const VirtualDevice* pImageSurface)
14625 {
14626 disable_notify_events();
14627 GtkTreeIter iter;
14628 insert_row(GTK_LIST_STORE(m_pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_list_store_get_type ()))))))
, iter, pos, pId, rText, pIconName, pImageSurface);
14629 enable_notify_events();
14630 }
14631
14632 static gboolean signalGetChildPosition(GtkOverlay*, GtkWidget*, GdkRectangle* pAllocation, gpointer widget)
14633 {
14634 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14635 return pThis->signal_get_child_position(pAllocation);
14636 }
14637
14638 bool signal_get_child_position(GdkRectangle* pAllocation)
14639 {
14640 if (!gtk_widget_get_visible(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
))
14641 return false;
14642 if (!gtk_widget_get_realized(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
))
14643 return false;
14644 int nRow = find_id_including_mru(m_sMenuButtonRow, true);
14645 if (nRow == -1)
14646 return false;
14647
14648 gtk_widget_get_preferred_width(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
, &pAllocation->width, nullptr);
14649
14650 GtkTreePath* pPath = gtk_tree_path_new_from_indices(nRow, -1);
14651 GList* pColumns = gtk_tree_view_get_columns(m_pTreeView);
14652 tools::Rectangle aRect = get_row_area(m_pTreeView, pColumns, pPath);
14653 gtk_tree_path_free(pPath);
14654 g_list_free(pColumns);
14655
14656 pAllocation->x = aRect.Right() - pAllocation->width;
14657 pAllocation->y = aRect.Top();
14658 pAllocation->height = aRect.GetHeight();
14659
14660 return true;
14661 }
14662
14663 static gboolean signalOverlayButtonCrossing(GtkWidget*, GdkEventCrossing* pEvent, gpointer widget)
14664 {
14665 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14666 pThis->signal_overlay_button_crossing(pEvent->type == GDK_ENTER_NOTIFY);
14667 return false;
14668 }
14669
14670 void signal_overlay_button_crossing(bool bEnter)
14671 {
14672 m_bMouseInOverlayButton = bEnter;
14673 if (!bEnter)
14674 return;
14675
14676 if (m_bHoverSelection)
14677 {
14678 // once toggled button is pressed, turn off hover selection until
14679 // mouse leaves the overlay button
14680 gtk_tree_view_set_hover_selection(m_pTreeView, false);
14681 m_bHoverSelection = false;
14682 }
14683 int nRow = find_id_including_mru(m_sMenuButtonRow, true);
14684 assert(nRow != -1)(static_cast <bool> (nRow != -1) ? void (0) : __assert_fail
("nRow != -1", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 14684, __extension__ __PRETTY_FUNCTION__))
;
14685 tree_view_set_cursor(nRow); // select the buttons row
14686 }
14687
14688 void signal_combo_mnemonic_activate()
14689 {
14690 if (m_pEntry)
14691 gtk_widget_grab_focus(m_pEntry);
14692 else
14693 gtk_widget_grab_focus(m_pToggleButton);
14694 }
14695
14696 static gboolean signalComboMnemonicActivate(GtkWidget*, gboolean, gpointer widget)
14697 {
14698 GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
14699 pThis->signal_combo_mnemonic_activate();
14700 return true;
14701 }
14702
14703 // Since tdf#131120 we don't use the original ComboBox menu, but it's still
14704 // listening to additions to the ListStore and slowing things down (tdf#136455)
14705 void destroy_unused_menu()
14706 {
14707 AtkObject* pAtkObj = gtk_combo_box_get_popup_accessible(m_pComboBox);
14708 if (!pAtkObj)
14709 return;
14710 if (!GTK_IS_ACCESSIBLE(pAtkObj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pAtkObj)); GType __t = ((gtk_accessible_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
14711 return;
14712 GtkWidget* pWidget = gtk_accessible_get_widget(GTK_ACCESSIBLE(pAtkObj)((((GtkAccessible*) g_type_check_instance_cast ((GTypeInstance
*) ((pAtkObj)), ((gtk_accessible_get_type ()))))))
);
14713 if (!pWidget)
14714 return;
14715 gtk_widget_destroy(pWidget);
14716 }
14717
14718public:
14719 GtkInstanceComboBox(GtkBuilder* pComboBuilder, GtkComboBox* pComboBox, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
14720 : GtkInstanceContainer(GTK_CONTAINER(gtk_builder_get_object(pComboBuilder, "box"))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(pComboBuilder, "box"))), ((gtk_container_get_type
()))))))
, pBuilder, bTakeOwnership)
14721 , m_pComboBuilder(pComboBuilder)
14722 , m_pComboBox(pComboBox)
14723 , m_pOverlay(GTK_OVERLAY(gtk_builder_get_object(pComboBuilder, "overlay"))((((GtkOverlay*) g_type_check_instance_cast ((GTypeInstance*)
((gtk_builder_get_object(pComboBuilder, "overlay"))), ((gtk_overlay_get_type
()))))))
)
14724 , m_pTreeView(GTK_TREE_VIEW(gtk_builder_get_object(pComboBuilder, "treeview"))((((GtkTreeView*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(pComboBuilder, "treeview"))), ((gtk_tree_view_get_type
()))))))
)
14725 , m_pOverlayButton(GTK_MENU_BUTTON(gtk_builder_get_object(pComboBuilder, "overlaybutton"))((((GtkMenuButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(pComboBuilder, "overlaybutton")))
, ((gtk_menu_button_get_type ()))))))
)
14726 , m_pMenuWindow(GTK_WINDOW(gtk_builder_get_object(pComboBuilder, "popup"))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(pComboBuilder, "popup"))), ((gtk_window_get_type
()))))))
)
14727 , m_pTreeModel(gtk_combo_box_get_model(pComboBox))
14728 , m_pButtonTextRenderer(nullptr)
14729 , m_pToggleButton(GTK_WIDGET(gtk_builder_get_object(pComboBuilder, "button"))((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(pComboBuilder, "button"))), ((gtk_widget_get_type
()))))))
)
14730 , m_pEntry(GTK_WIDGET(gtk_builder_get_object(pComboBuilder, "entry"))((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(pComboBuilder, "entry"))), ((gtk_widget_get_type
()))))))
)
14731 , m_pCellView(nullptr)
14732 , m_aQuickSelectionEngine(*this)
14733 , m_bHoverSelection(false)
14734 , m_bMouseInOverlayButton(false)
14735 , m_bPopupActive(false)
14736 , m_bAutoComplete(false)
14737 , m_bAutoCompleteCaseSensitive(false)
14738 , m_bChangedByMenu(false)
14739 , m_bCustomRenderer(false)
14740 , m_bActivateCalled(false)
14741 , m_nTextCol(gtk_combo_box_get_entry_text_column(pComboBox))
14742 , m_nIdCol(gtk_combo_box_get_id_column(pComboBox))
14743 , m_nToggleFocusInSignalId(0)
14744 , m_nToggleFocusOutSignalId(0)
14745 , m_nRowActivatedSignalId(g_signal_connect(m_pTreeView, "row-activated", G_CALLBACK(signalRowActivated), this)g_signal_connect_data ((m_pTreeView), ("row-activated"), (((GCallback
) (signalRowActivated))), (this), __null, (GConnectFlags) 0)
)
14746 , m_nChangedSignalId(g_signal_connect(m_pEntry, "changed", G_CALLBACK(signalChanged), this)g_signal_connect_data ((m_pEntry), ("changed"), (((GCallback)
(signalChanged))), (this), __null, (GConnectFlags) 0)
)
14747 , m_nPopupShownSignalId(g_signal_connect(m_pToggleButton, "toggled", G_CALLBACK(signalPopupToggled), this)g_signal_connect_data ((m_pToggleButton), ("toggled"), (((GCallback
) (signalPopupToggled))), (this), __null, (GConnectFlags) 0)
)
14748 , m_nAutoCompleteIdleId(0)
14749 , m_nNonCustomLineHeight(-1)
14750 , m_nPrePopupCursorPos(-1)
14751 , m_nMRUCount(0)
14752 , m_nMaxMRUCount(0)
14753 {
14754 int nActive = gtk_combo_box_get_active(m_pComboBox);
14755 insertAsParent(GTK_WIDGET(m_pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pComboBox)), ((gtk_widget_get_type ()))))))
, GTK_WIDGET(getContainer())((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(getContainer())), ((gtk_widget_get_type ()))))))
);
14756 gtk_widget_set_visible(GTK_WIDGET(m_pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pComboBox)), ((gtk_widget_get_type ()))))))
, false);
14757 gtk_widget_set_no_show_all(GTK_WIDGET(m_pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pComboBox)), ((gtk_widget_get_type ()))))))
, true);
14758
14759 gtk_tree_view_set_model(m_pTreeView, m_pTreeModel);
14760 gtk_combo_box_set_model(m_pComboBox, nullptr);
14761 GtkTreeViewColumn* pCol = gtk_tree_view_column_new();
14762 gtk_tree_view_append_column(m_pTreeView, pCol);
14763
14764 bool bPixbufUsedSurface = gtk_tree_model_get_n_columns(m_pTreeModel) == 4;
14765
14766 GList* cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(m_pComboBox)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pComboBox)), ((gtk_cell_layout_get_type ()))))))
);
14767 // move the cell renderers from the combobox to the replacement treeview
14768 m_pMenuTextRenderer = static_cast<GtkCellRenderer*>(cells->data);
14769 for (GList* pRenderer = g_list_first(cells); pRenderer; pRenderer = g_list_next(pRenderer)((pRenderer) ? (((GList *)(pRenderer))->next) : __null))
14770 {
14771 GtkCellRenderer* pCellRenderer = GTK_CELL_RENDERER(pRenderer->data)((((GtkCellRenderer*) g_type_check_instance_cast ((GTypeInstance
*) ((pRenderer->data)), ((gtk_cell_renderer_get_type ())))
)))
;
14772 bool bTextRenderer = pCellRenderer == m_pMenuTextRenderer;
14773 gtk_tree_view_column_pack_end(pCol, pCellRenderer, bTextRenderer);
14774 if (!bTextRenderer)
14775 {
14776 if (bPixbufUsedSurface)
14777 gtk_tree_view_column_set_attributes(pCol, pCellRenderer, "surface", 3, nullptr);
14778 else
14779 gtk_tree_view_column_set_attributes(pCol, pCellRenderer, "pixbuf", 2, nullptr);
14780 }
14781 }
14782
14783 gtk_tree_view_column_set_attributes(pCol, m_pMenuTextRenderer, "text", m_nTextCol, nullptr);
14784
14785 if (gtk_combo_box_get_has_entry(m_pComboBox))
14786 {
14787 m_bAutoComplete = true;
14788 m_nEntryInsertTextSignalId = g_signal_connect(m_pEntry, "insert-text", G_CALLBACK(signalEntryInsertText), this)g_signal_connect_data ((m_pEntry), ("insert-text"), (((GCallback
) (signalEntryInsertText))), (this), __null, (GConnectFlags) 0
)
;
14789 m_nEntryActivateSignalId = g_signal_connect(m_pEntry, "activate", G_CALLBACK(signalEntryActivate), this)g_signal_connect_data ((m_pEntry), ("activate"), (((GCallback
) (signalEntryActivate))), (this), __null, (GConnectFlags) 0)
;
14790 m_nEntryFocusInSignalId = g_signal_connect(m_pEntry, "focus-in-event", G_CALLBACK(signalEntryFocusIn), this)g_signal_connect_data ((m_pEntry), ("focus-in-event"), (((GCallback
) (signalEntryFocusIn))), (this), __null, (GConnectFlags) 0)
;
14791 m_nEntryFocusOutSignalId = g_signal_connect(m_pEntry, "focus-out-event", G_CALLBACK(signalEntryFocusOut), this)g_signal_connect_data ((m_pEntry), ("focus-out-event"), (((GCallback
) (signalEntryFocusOut))), (this), __null, (GConnectFlags) 0)
;
14792 m_nEntryKeyPressEventSignalId = g_signal_connect(m_pEntry, "key-press-event", G_CALLBACK(signalEntryKeyPress), this)g_signal_connect_data ((m_pEntry), ("key-press-event"), (((GCallback
) (signalEntryKeyPress))), (this), __null, (GConnectFlags) 0)
;
14793 m_nKeyPressEventSignalId = 0;
14794 }
14795 else
14796 {
14797 gtk_widget_set_visible(m_pEntry, false);
14798 m_pEntry = nullptr;
14799
14800 GtkWidget* pArrow = GTK_WIDGET(gtk_builder_get_object(pComboBuilder, "arrow"))((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(pComboBuilder, "arrow"))), ((gtk_widget_get_type
()))))))
;
14801 gtk_container_child_set(getContainer(), m_pToggleButton, "expand", true, nullptr);
14802
14803 auto m_pCellArea = gtk_cell_area_box_new();
14804 m_pCellView = GTK_CELL_VIEW(gtk_cell_view_new_with_context(m_pCellArea, nullptr))((((GtkCellView*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_cell_view_new_with_context(m_pCellArea, nullptr))), (
(gtk_cell_view_get_type ()))))))
;
14805 gtk_widget_set_hexpand(GTK_WIDGET(m_pCellView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pCellView)), ((gtk_widget_get_type ()))))))
, true);
14806 GtkBox* pBox = GTK_BOX(gtk_widget_get_parent(pArrow))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_widget_get_parent
(pArrow))), ((gtk_box_get_type ()))))))
;
14807
14808 gint nImageSpacing(2);
14809 GtkStyleContext *pContext = gtk_widget_get_style_context(GTK_WIDGET(m_pToggleButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pToggleButton)), ((gtk_widget_get_type ()))))))
);
14810 gtk_style_context_get_style(pContext, "image-spacing", &nImageSpacing, nullptr);
14811 gtk_box_set_spacing(pBox, nImageSpacing);
14812
14813 gtk_box_pack_start(pBox, GTK_WIDGET(m_pCellView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pCellView)), ((gtk_widget_get_type ()))))))
, false, true, 0);
14814
14815 gtk_cell_view_set_fit_model(m_pCellView, true);
14816 gtk_cell_view_set_model(m_pCellView, m_pTreeModel);
14817
14818 m_pButtonTextRenderer = gtk_cell_renderer_text_new();
14819 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(m_pCellView)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pCellView)), ((gtk_cell_layout_get_type ()))))))
, m_pButtonTextRenderer, true);
14820 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(m_pCellView)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pCellView)), ((gtk_cell_layout_get_type ()))))))
, m_pButtonTextRenderer, "text", m_nTextCol, nullptr);
14821 if (g_list_length(cells) > 1)
14822 {
14823 GtkCellRenderer* pCellRenderer = gtk_cell_renderer_pixbuf_new();
14824 gtk_cell_layout_pack_end(GTK_CELL_LAYOUT(m_pCellView)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pCellView)), ((gtk_cell_layout_get_type ()))))))
, pCellRenderer, false);
14825 if (bPixbufUsedSurface)
14826 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(m_pCellView)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pCellView)), ((gtk_cell_layout_get_type ()))))))
, pCellRenderer, "surface", 3, nullptr);
14827 else
14828 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(m_pCellView)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pCellView)), ((gtk_cell_layout_get_type ()))))))
, pCellRenderer, "pixbuf", 2, nullptr);
14829 }
14830
14831 gtk_widget_show_all(GTK_WIDGET(m_pCellView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pCellView)), ((gtk_widget_get_type ()))))))
);
14832
14833 m_nEntryInsertTextSignalId = 0;
14834 m_nEntryActivateSignalId = 0;
14835 m_nEntryFocusInSignalId = 0;
14836 m_nEntryFocusOutSignalId = 0;
14837 m_nEntryKeyPressEventSignalId = 0;
14838 m_nKeyPressEventSignalId = g_signal_connect(m_pToggleButton, "key-press-event", G_CALLBACK(signalKeyPress), this)g_signal_connect_data ((m_pToggleButton), ("key-press-event")
, (((GCallback) (signalKeyPress))), (this), __null, (GConnectFlags
) 0)
;
14839 }
14840
14841 g_list_free(cells);
14842
14843 if (nActive != -1)
14844 tree_view_set_cursor(nActive);
14845
14846 g_signal_connect(getContainer(), "mnemonic-activate", G_CALLBACK(signalComboMnemonicActivate), this)g_signal_connect_data ((getContainer()), ("mnemonic-activate"
), (((GCallback) (signalComboMnemonicActivate))), (this), __null
, (GConnectFlags) 0)
;
14847
14848 g_signal_connect(m_pMenuWindow, "grab-broken-event", G_CALLBACK(signalGrabBroken), this)g_signal_connect_data ((m_pMenuWindow), ("grab-broken-event")
, (((GCallback) (signalGrabBroken))), (this), __null, (GConnectFlags
) 0)
;
14849 g_signal_connect(m_pMenuWindow, "button-press-event", G_CALLBACK(signalButtonPress), this)g_signal_connect_data ((m_pMenuWindow), ("button-press-event"
), (((GCallback) (signalButtonPress))), (this), __null, (GConnectFlags
) 0)
;
14850 g_signal_connect(m_pMenuWindow, "motion-notify-event", G_CALLBACK(signalMotion), this)g_signal_connect_data ((m_pMenuWindow), ("motion-notify-event"
), (((GCallback) (signalMotion))), (this), __null, (GConnectFlags
) 0)
;
14851 // support typeahead for the menu itself, typing into the menu will
14852 // select via the vcl selection engine, a matching entry.
14853 g_signal_connect(m_pMenuWindow, "key-press-event", G_CALLBACK(signalKeyPress), this)g_signal_connect_data ((m_pMenuWindow), ("key-press-event"), (
((GCallback) (signalKeyPress))), (this), __null, (GConnectFlags
) 0)
;
14854
14855 g_signal_connect(m_pOverlay, "get-child-position", G_CALLBACK(signalGetChildPosition), this)g_signal_connect_data ((m_pOverlay), ("get-child-position"), (
((GCallback) (signalGetChildPosition))), (this), __null, (GConnectFlags
) 0)
;
14856 gtk_overlay_add_overlay(m_pOverlay, GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
);
14857 g_signal_connect(m_pOverlayButton, "leave-notify-event", G_CALLBACK(signalOverlayButtonCrossing), this)g_signal_connect_data ((m_pOverlayButton), ("leave-notify-event"
), (((GCallback) (signalOverlayButtonCrossing))), (this), __null
, (GConnectFlags) 0)
;
14858 g_signal_connect(m_pOverlayButton, "enter-notify-event", G_CALLBACK(signalOverlayButtonCrossing), this)g_signal_connect_data ((m_pOverlayButton), ("enter-notify-event"
), (((GCallback) (signalOverlayButtonCrossing))), (this), __null
, (GConnectFlags) 0)
;
14859
14860 destroy_unused_menu();
14861 }
14862
14863 virtual int get_active() const override
14864 {
14865 int nActive = get_active_including_mru();
14866 if (nActive == -1)
14867 return -1;
14868
14869 if (m_nMRUCount)
14870 {
14871 if (nActive < m_nMRUCount)
14872 nActive = find_text(get_text_including_mru(nActive));
14873 else
14874 nActive -= (m_nMRUCount + 1);
14875 }
14876
14877 return nActive;
14878 }
14879
14880 virtual OUString get_active_id() const override
14881 {
14882 int nActive = get_active();
14883 return nActive != -1 ? get_id(nActive) : OUString();
14884 }
14885
14886 virtual void set_active_id(const OUString& rStr) override
14887 {
14888 set_active(find_id(rStr));
14889 m_bChangedByMenu = false;
14890 }
14891
14892 virtual void set_size_request(int nWidth, int nHeight) override
14893 {
14894 if (m_pButtonTextRenderer)
14895 {
14896 // tweak the cell render to get a narrower size to stick
14897 if (nWidth != -1)
14898 {
14899 // this bit isn't great, I really want to be able to ellipse the text in the comboboxtext itself and let
14900 // the popup menu render them in full, in the interim ellipse both of them
14901 g_object_set(G_OBJECT(m_pButtonTextRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pButtonTextRenderer)), (((GType) ((20) << (2))))))))
, "ellipsize", PANGO_ELLIPSIZE_MIDDLE, nullptr);
14902
14903 // to find out how much of the width of the combobox belongs to the cell, set
14904 // the cell and widget to the min cell width and see what the difference is
14905 int min;
14906 gtk_cell_renderer_get_preferred_width(m_pButtonTextRenderer, m_pWidget, &min, nullptr);
14907 gtk_cell_renderer_set_fixed_size(m_pButtonTextRenderer, min, -1);
14908 gtk_widget_set_size_request(m_pWidget, min, -1);
14909 int nNonCellWidth = get_preferred_size().Width() - min;
14910
14911 int nCellWidth = nWidth - nNonCellWidth;
14912 if (nCellWidth >= 0)
14913 {
14914 // now set the cell to the max width which it can be within the
14915 // requested widget width
14916 gtk_cell_renderer_set_fixed_size(m_pButtonTextRenderer, nWidth - nNonCellWidth, -1);
14917 }
14918 }
14919 else
14920 {
14921 g_object_set(G_OBJECT(m_pButtonTextRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pButtonTextRenderer)), (((GType) ((20) << (2))))))))
, "ellipsize", PANGO_ELLIPSIZE_NONE, nullptr);
14922 gtk_cell_renderer_set_fixed_size(m_pButtonTextRenderer, -1, -1);
14923 }
14924 }
14925
14926 gtk_widget_set_size_request(m_pWidget, nWidth, nHeight);
14927 }
14928
14929 virtual void set_active(int pos) override
14930 {
14931 if (m_nMRUCount && pos != -1)
14932 pos += (m_nMRUCount + 1);
14933 set_active_including_mru(pos, false);
14934 }
14935
14936 virtual OUString get_active_text() const override
14937 {
14938 if (m_pEntry)
14939 {
14940 const gchar* pText = gtk_entry_get_text(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
);
14941 return OUString(pText, pText ? strlen(pText) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
14942 }
14943
14944 int nActive = get_active();
14945 if (nActive == -1)
14946 return OUString();
14947
14948 return get_text(nActive);
14949 }
14950
14951 virtual OUString get_text(int pos) const override
14952 {
14953 if (m_nMRUCount)
14954 pos += (m_nMRUCount + 1);
14955 return get_text_including_mru(pos);
14956 }
14957
14958 virtual OUString get_id(int pos) const override
14959 {
14960 if (m_nMRUCount)
14961 pos += (m_nMRUCount + 1);
14962 return get_id_including_mru(pos);
14963 }
14964
14965 virtual void set_id(int pos, const OUString& rId) override
14966 {
14967 if (m_nMRUCount)
14968 pos += (m_nMRUCount + 1);
14969 set_id_including_mru(pos, rId);
14970 }
14971
14972 virtual void insert_vector(const std::vector<weld::ComboBoxEntry>& rItems, bool bKeepExisting) override
14973 {
14974 freeze();
14975
14976 int nInsertionPoint;
14977 if (!bKeepExisting)
14978 {
14979 clear();
14980 nInsertionPoint = 0;
14981 }
14982 else
14983 nInsertionPoint = get_count();
14984
14985 GtkTreeIter iter;
14986 // tdf#125241 inserting backwards is faster
14987 for (auto aI = rItems.rbegin(); aI != rItems.rend(); ++aI)
14988 {
14989 const auto& rItem = *aI;
14990 insert_row(GTK_LIST_STORE(m_pTreeModel)((((GtkListStore*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_list_store_get_type ()))))))
, iter, nInsertionPoint, rItem.sId.isEmpty() ? nullptr : &rItem.sId,
14991 rItem.sString, rItem.sImage.isEmpty() ? nullptr : &rItem.sImage, nullptr);
14992 }
14993
14994 thaw();
14995 }
14996
14997 virtual void remove(int pos) override
14998 {
14999 if (m_nMRUCount)
15000 pos += (m_nMRUCount + 1);
15001 remove_including_mru(pos);
15002 }
15003
15004 virtual void insert(int pos, const OUString& rText, const OUString* pId, const OUString* pIconName, VirtualDevice* pImageSurface) override
15005 {
15006 if (m_nMRUCount && pos != -1)
15007 pos += (m_nMRUCount + 1);
15008 insert_including_mru(pos, rText, pId, pIconName, pImageSurface);
15009 }
15010
15011 virtual void insert_separator(int pos, const OUString& rId) override
15012 {
15013 pos = pos == -1 ? get_count() : pos;
15014 if (m_nMRUCount)
15015 pos += (m_nMRUCount + 1);
15016 insert_separator_including_mru(pos, rId);
15017 }
15018
15019 virtual int get_count() const override
15020 {
15021 int nCount = get_count_including_mru();
15022 if (m_nMRUCount)
15023 nCount -= (m_nMRUCount + 1);
15024 return nCount;
15025 }
15026
15027 virtual int find_text(const OUString& rStr) const override
15028 {
15029 int nPos = find_text_including_mru(rStr, false);
15030 if (nPos != -1 && m_nMRUCount)
15031 nPos -= (m_nMRUCount + 1);
15032 return nPos;
15033 }
15034
15035 virtual int find_id(const OUString& rId) const override
15036 {
15037 int nPos = find_id_including_mru(rId, false);
15038 if (nPos != -1 && m_nMRUCount)
15039 nPos -= (m_nMRUCount + 1);
15040 return nPos;
15041 }
15042
15043 virtual void clear() override
15044 {
15045 do_clear();
15046 }
15047
15048 virtual void make_sorted() override
15049 {
15050 m_xSorter.reset(new comphelper::string::NaturalStringSorter(
15051 ::comphelper::getProcessComponentContext(),
15052 Application::GetSettings().GetUILanguageTag().getLocale()));
15053 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
15054 gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, GTK_SORT_ASCENDING);
15055 gtk_tree_sortable_set_sort_func(pSortable, m_nTextCol, default_sort_func, m_xSorter.get(), nullptr);
15056 }
15057
15058 virtual bool has_entry() const override
15059 {
15060 return gtk_combo_box_get_has_entry(m_pComboBox);
15061 }
15062
15063 virtual void set_entry_message_type(weld::EntryMessageType eType) override
15064 {
15065 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15065, __extension__ __PRETTY_FUNCTION__))
;
15066 ::set_entry_message_type(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, eType);
15067 }
15068
15069 virtual void set_entry_text(const OUString& rText) override
15070 {
15071 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15071, __extension__ __PRETTY_FUNCTION__))
;
15072 disable_notify_events();
15073 gtk_entry_set_text(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, OUStringToOString(rText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
15074 enable_notify_events();
15075 }
15076
15077 virtual void set_entry_width_chars(int nChars) override
15078 {
15079 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15079, __extension__ __PRETTY_FUNCTION__))
;
15080 disable_notify_events();
15081 gtk_entry_set_width_chars(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, nChars);
15082 gtk_entry_set_max_width_chars(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, nChars);
15083 enable_notify_events();
15084 }
15085
15086 virtual void set_entry_max_length(int nChars) override
15087 {
15088 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15088, __extension__ __PRETTY_FUNCTION__))
;
15089 disable_notify_events();
15090 gtk_entry_set_max_length(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, nChars);
15091 enable_notify_events();
15092 }
15093
15094 virtual void select_entry_region(int nStartPos, int nEndPos) override
15095 {
15096 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15096, __extension__ __PRETTY_FUNCTION__))
;
15097 disable_notify_events();
15098 gtk_editable_select_region(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, nStartPos, nEndPos);
15099 enable_notify_events();
15100 }
15101
15102 virtual bool get_entry_selection_bounds(int& rStartPos, int &rEndPos) override
15103 {
15104 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15104, __extension__ __PRETTY_FUNCTION__))
;
15105 return gtk_editable_get_selection_bounds(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, &rStartPos, &rEndPos);
15106 }
15107
15108 virtual void set_entry_completion(bool bEnable, bool bCaseSensitive) override
15109 {
15110 m_bAutoComplete = bEnable;
15111 m_bAutoCompleteCaseSensitive = bCaseSensitive;
15112 }
15113
15114 virtual void set_entry_placeholder_text(const OUString& rText) override
15115 {
15116 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15116, __extension__ __PRETTY_FUNCTION__))
;
15117 gtk_entry_set_placeholder_text(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, rText.toUtf8().getStr());
15118 }
15119
15120 virtual void set_entry_editable(bool bEditable) override
15121 {
15122 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15122, __extension__ __PRETTY_FUNCTION__))
;
15123 gtk_editable_set_editable(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
, bEditable);
15124 }
15125
15126 virtual void cut_entry_clipboard() override
15127 {
15128 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15128, __extension__ __PRETTY_FUNCTION__))
;
15129 gtk_editable_cut_clipboard(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
15130 }
15131
15132 virtual void copy_entry_clipboard() override
15133 {
15134 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15134, __extension__ __PRETTY_FUNCTION__))
;
15135 gtk_editable_copy_clipboard(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
15136 }
15137
15138 virtual void paste_entry_clipboard() override
15139 {
15140 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15140, __extension__ __PRETTY_FUNCTION__))
;
15141 gtk_editable_paste_clipboard(GTK_EDITABLE(m_pEntry)((((GtkEditable*) g_type_check_instance_cast ((GTypeInstance*
) ((m_pEntry)), ((gtk_editable_get_type ()))))))
);
15142 }
15143
15144 virtual void set_entry_font(const vcl::Font& rFont) override
15145 {
15146 m_xFont.reset(new vcl::Font(rFont));
15147 PangoAttrList* pAttrList = create_attr_list(rFont);
15148 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15148, __extension__ __PRETTY_FUNCTION__))
;
15149 gtk_entry_set_attributes(GTK_ENTRY(m_pEntry)((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pEntry)), ((gtk_entry_get_type ()))))))
, pAttrList);
15150 pango_attr_list_unref(pAttrList);
15151 }
15152
15153 virtual vcl::Font get_entry_font() override
15154 {
15155 if (m_xFont)
15156 return *m_xFont;
15157 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15157, __extension__ __PRETTY_FUNCTION__))
;
15158 PangoContext* pContext = gtk_widget_get_pango_context(m_pEntry);
15159 return pango_to_vcl(pango_context_get_font_description(pContext),
15160 Application::GetSettings().GetUILanguageTag().getLocale());
15161 }
15162
15163 virtual void disable_notify_events() override
15164 {
15165 if (m_pEntry)
15166 {
15167 g_signal_handler_block(m_pEntry, m_nEntryInsertTextSignalId);
15168 g_signal_handler_block(m_pEntry, m_nEntryActivateSignalId);
15169 g_signal_handler_block(m_pEntry, m_nEntryFocusInSignalId);
15170 g_signal_handler_block(m_pEntry, m_nEntryFocusOutSignalId);
15171 g_signal_handler_block(m_pEntry, m_nEntryKeyPressEventSignalId);
15172 g_signal_handler_block(m_pEntry, m_nChangedSignalId);
15173 }
15174 else
15175 g_signal_handler_block(m_pToggleButton, m_nKeyPressEventSignalId);
15176 if (m_nToggleFocusInSignalId)
15177 g_signal_handler_block(m_pToggleButton, m_nToggleFocusInSignalId);
15178 if (m_nToggleFocusOutSignalId)
15179 g_signal_handler_block(m_pToggleButton, m_nToggleFocusOutSignalId);
15180 g_signal_handler_block(m_pTreeView, m_nRowActivatedSignalId);
15181 g_signal_handler_block(m_pToggleButton, m_nPopupShownSignalId);
15182 GtkInstanceContainer::disable_notify_events();
15183 }
15184
15185 virtual void enable_notify_events() override
15186 {
15187 GtkInstanceContainer::enable_notify_events();
15188 g_signal_handler_unblock(m_pToggleButton, m_nPopupShownSignalId);
15189 g_signal_handler_unblock(m_pTreeView, m_nRowActivatedSignalId);
15190 if (m_nToggleFocusInSignalId)
15191 g_signal_handler_unblock(m_pToggleButton, m_nToggleFocusInSignalId);
15192 if (m_nToggleFocusOutSignalId)
15193 g_signal_handler_unblock(m_pToggleButton, m_nToggleFocusOutSignalId);
15194 if (m_pEntry)
15195 {
15196 g_signal_handler_unblock(m_pEntry, m_nChangedSignalId);
15197 g_signal_handler_unblock(m_pEntry, m_nEntryActivateSignalId);
15198 g_signal_handler_unblock(m_pEntry, m_nEntryFocusInSignalId);
15199 g_signal_handler_unblock(m_pEntry, m_nEntryFocusOutSignalId);
15200 g_signal_handler_unblock(m_pEntry, m_nEntryKeyPressEventSignalId);
15201 g_signal_handler_unblock(m_pEntry, m_nEntryInsertTextSignalId);
15202 }
15203 else
15204 g_signal_handler_unblock(m_pToggleButton, m_nKeyPressEventSignalId);
15205 }
15206
15207 virtual void freeze() override
15208 {
15209 disable_notify_events();
15210 GtkInstanceContainer::freeze();
15211 g_object_ref(m_pTreeModel);
15212 gtk_tree_view_set_model(m_pTreeView, nullptr);
15213 g_object_freeze_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
15214 if (m_xSorter)
15215 {
15216 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
15217 gtk_tree_sortable_set_sort_column_id(pSortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID(-2), GTK_SORT_ASCENDING);
15218 }
15219 enable_notify_events();
15220 }
15221
15222 virtual void thaw() override
15223 {
15224 disable_notify_events();
15225 if (m_xSorter)
15226 {
15227 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pTreeModel)), ((gtk_tree_sortable_get_type ()))))))
;
15228 gtk_tree_sortable_set_sort_column_id(pSortable, m_nTextCol, GTK_SORT_ASCENDING);
15229 }
15230 g_object_thaw_notify(G_OBJECT(m_pTreeModel)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pTreeModel)), (((GType) ((20) << (2))))))))
);
15231 gtk_tree_view_set_model(m_pTreeView, m_pTreeModel);
15232 g_object_unref(m_pTreeModel);
15233
15234 GtkInstanceContainer::thaw();
15235 enable_notify_events();
15236 }
15237
15238 virtual bool get_popup_shown() const override
15239 {
15240 return m_bPopupActive;
15241 }
15242
15243 virtual void connect_focus_in(const Link<Widget&, void>& rLink) override
15244 {
15245 if (!m_nToggleFocusInSignalId)
15246 m_nToggleFocusInSignalId = g_signal_connect(m_pToggleButton, "focus-in-event", G_CALLBACK(signalFocusIn), this)g_signal_connect_data ((m_pToggleButton), ("focus-in-event"),
(((GCallback) (signalFocusIn))), (this), __null, (GConnectFlags
) 0)
;
15247 weld::Widget::connect_focus_in(rLink);
15248 }
15249
15250 virtual void connect_focus_out(const Link<Widget&, void>& rLink) override
15251 {
15252 if (!m_nToggleFocusOutSignalId)
15253 m_nToggleFocusOutSignalId = g_signal_connect(m_pToggleButton, "focus-out-event", G_CALLBACK(signalFocusOut), this)g_signal_connect_data ((m_pToggleButton), ("focus-out-event")
, (((GCallback) (signalFocusOut))), (this), __null, (GConnectFlags
) 0)
;
15254 weld::Widget::connect_focus_out(rLink);
15255 }
15256
15257 virtual void grab_focus() override
15258 {
15259 disable_notify_events();
15260 if (m_pEntry)
15261 gtk_widget_grab_focus(m_pEntry);
15262 else
15263 gtk_widget_grab_focus(m_pToggleButton);
15264 enable_notify_events();
15265 }
15266
15267 virtual bool has_focus() const override
15268 {
15269 if (m_pEntry && gtk_widget_has_focus(m_pEntry))
15270 return true;
15271 return gtk_widget_has_focus(m_pToggleButton) ||
15272 gtk_widget_has_focus(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
) ||
15273 gtk_widget_has_focus(GTK_WIDGET(m_pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pTreeView)), ((gtk_widget_get_type ()))))))
) || GtkInstanceWidget::has_focus();
15274 }
15275
15276 virtual bool changed_by_direct_pick() const override
15277 {
15278 return m_bChangedByMenu;
15279 }
15280
15281 virtual void set_custom_renderer(bool bOn) override
15282 {
15283 if (bOn == m_bCustomRenderer)
15284 return;
15285 GList* pColumns = gtk_tree_view_get_columns(m_pTreeView);
15286 // keep the original height around for optimal popup height calculation
15287 m_nNonCustomLineHeight = bOn ? ::get_height_row(m_pTreeView, pColumns) : -1;
15288 GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pColumns->data)((((GtkTreeViewColumn*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumns->data)), ((gtk_tree_view_column_get_type ())
)))))
;
15289 gtk_cell_layout_clear(GTK_CELL_LAYOUT(pColumn)((((GtkCellLayout*) g_type_check_instance_cast ((GTypeInstance
*) ((pColumn)), ((gtk_cell_layout_get_type ()))))))
);
15290 if (bOn)
15291 {
15292 GtkCellRenderer *pRenderer = custom_cell_renderer_surface_new();
15293 GValue value = G_VALUE_INIT{ 0, { { 0 } } };
15294 g_value_init(&value, G_TYPE_POINTER((GType) ((17) << (2))));
15295 g_value_set_pointer(&value, static_cast<gpointer>(this));
15296 g_object_set_property(G_OBJECT(pRenderer)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pRenderer)), (((GType) ((20) << (2))))))))
, "instance", &value);
15297 gtk_tree_view_column_pack_start(pColumn, pRenderer, true);
15298 gtk_tree_view_column_add_attribute(pColumn, pRenderer, "text", m_nTextCol);
15299 gtk_tree_view_column_add_attribute(pColumn, pRenderer, "id", m_nIdCol);
15300 }
15301 else
15302 {
15303 GtkCellRenderer *pRenderer = gtk_cell_renderer_text_new();
15304 gtk_tree_view_column_pack_start(pColumn, pRenderer, true);
15305 gtk_tree_view_column_add_attribute(pColumn, pRenderer, "text", m_nTextCol);
15306 }
15307 g_list_free(pColumns);
15308 m_bCustomRenderer = bOn;
15309 }
15310
15311 void call_signal_custom_render(VirtualDevice& rOutput, const tools::Rectangle& rRect, bool bSelected, const OUString& rId)
15312 {
15313 signal_custom_render(rOutput, rRect, bSelected, rId);
15314 }
15315
15316 Size call_signal_custom_get_size(VirtualDevice& rOutput)
15317 {
15318 return signal_custom_get_size(rOutput);
15319 }
15320
15321 VclPtr<VirtualDevice> create_render_virtual_device() const override
15322 {
15323 return create_virtual_device();
15324 }
15325
15326 virtual void set_item_menu(const OString& rIdent, weld::Menu* pMenu) override
15327 {
15328 m_xCustomMenuButtonHelper.reset();
15329 GtkInstanceMenu* pPopoverWidget = dynamic_cast<GtkInstanceMenu*>(pMenu);
15330 GtkWidget* pMenuWidget = GTK_WIDGET(pPopoverWidget ? pPopoverWidget->getMenu() : nullptr)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pPopoverWidget ? pPopoverWidget->getMenu() : nullptr)), (
(gtk_widget_get_type ()))))))
;
15331 gtk_menu_button_set_popup(m_pOverlayButton, pMenuWidget);
15332 gtk_widget_set_visible(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
, pMenuWidget != nullptr);
15333 gtk_widget_queue_resize_no_redraw(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
); // force location recalc
15334 if (pMenuWidget)
15335 m_xCustomMenuButtonHelper.reset(new CustomRenderMenuButtonHelper(GTK_MENU(pMenuWidget)((((GtkMenu*) g_type_check_instance_cast ((GTypeInstance*) ((
pMenuWidget)), ((gtk_menu_get_type ()))))))
, GTK_TOGGLE_BUTTON(m_pToggleButton)((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pToggleButton)), ((gtk_toggle_button_get_type ()))))))
));
15336 m_sMenuButtonRow = OUString::fromUtf8(rIdent);
15337 }
15338
15339 OUString get_mru_entries() const override
15340 {
15341 const sal_Unicode cSep = ';';
15342
15343 OUStringBuffer aEntries;
15344 for (sal_Int32 n = 0; n < m_nMRUCount; n++)
15345 {
15346 aEntries.append(get_text_including_mru(n));
15347 if (n < m_nMRUCount - 1)
15348 aEntries.append(cSep);
15349 }
15350 return aEntries.makeStringAndClear();
15351 }
15352
15353 virtual void set_mru_entries(const OUString& rEntries) override
15354 {
15355 const sal_Unicode cSep = ';';
15356
15357 // Remove old MRU entries
15358 for (sal_Int32 n = m_nMRUCount; n;)
15359 remove_including_mru(--n);
15360
15361 sal_Int32 nMRUCount = 0;
15362 sal_Int32 nIndex = 0;
15363 do
15364 {
15365 OUString aEntry = rEntries.getToken(0, cSep, nIndex);
15366 // Accept only existing entries
15367 int nPos = find_text(aEntry);
15368 if (nPos != -1)
15369 {
15370 OUString sId = get_id(nPos);
15371 insert_including_mru(0, aEntry, &sId, nullptr, nullptr);
15372 ++nMRUCount;
15373 }
15374 }
15375 while (nIndex >= 0);
15376
15377 if (nMRUCount && !m_nMRUCount)
15378 insert_separator_including_mru(nMRUCount, "separator");
15379 else if (!nMRUCount && m_nMRUCount)
15380 remove_including_mru(m_nMRUCount); // remove separator
15381
15382 m_nMRUCount = nMRUCount;
15383 }
15384
15385 int get_menu_button_width() const override
15386 {
15387 bool bVisible = gtk_widget_get_visible(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
);
15388 if (!bVisible)
15389 gtk_widget_set_visible(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
, true);
15390 gint nWidth;
15391 gtk_widget_get_preferred_width(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
, &nWidth, nullptr);
15392 if (!bVisible)
15393 gtk_widget_set_visible(GTK_WIDGET(m_pOverlayButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pOverlayButton)), ((gtk_widget_get_type ()))))))
, false);
15394 return nWidth;
15395 }
15396
15397 virtual ~GtkInstanceComboBox() override
15398 {
15399 m_xCustomMenuButtonHelper.reset();
15400 do_clear();
15401 if (m_nAutoCompleteIdleId)
15402 g_source_remove(m_nAutoCompleteIdleId);
15403 if (m_pEntry)
15404 {
15405 g_signal_handler_disconnect(m_pEntry, m_nChangedSignalId);
15406 g_signal_handler_disconnect(m_pEntry, m_nEntryInsertTextSignalId);
15407 g_signal_handler_disconnect(m_pEntry, m_nEntryActivateSignalId);
15408 g_signal_handler_disconnect(m_pEntry, m_nEntryFocusInSignalId);
15409 g_signal_handler_disconnect(m_pEntry, m_nEntryFocusOutSignalId);
15410 g_signal_handler_disconnect(m_pEntry, m_nEntryKeyPressEventSignalId);
15411 }
15412 else
15413 g_signal_handler_disconnect(m_pToggleButton, m_nKeyPressEventSignalId);
15414 if (m_nToggleFocusInSignalId)
15415 g_signal_handler_disconnect(m_pToggleButton, m_nToggleFocusInSignalId);
15416 if (m_nToggleFocusOutSignalId)
15417 g_signal_handler_disconnect(m_pToggleButton, m_nToggleFocusOutSignalId);
15418 g_signal_handler_disconnect(m_pTreeView, m_nRowActivatedSignalId);
15419 g_signal_handler_disconnect(m_pToggleButton, m_nPopupShownSignalId);
15420
15421 gtk_combo_box_set_model(m_pComboBox, m_pTreeModel);
15422 gtk_tree_view_set_model(m_pTreeView, nullptr);
15423
15424 // restore original hierarchy in dtor so a new GtkInstanceComboBox will
15425 // result in the same layout each time
15426 {
15427 g_object_ref(m_pComboBox);
15428
15429 GtkContainer* pContainer = getContainer();
15430
15431 gtk_container_remove(pContainer, GTK_WIDGET(m_pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pComboBox)), ((gtk_widget_get_type ()))))))
);
15432
15433 replaceWidget(GTK_WIDGET(pContainer)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pContainer)), ((gtk_widget_get_type ()))))))
, GTK_WIDGET(m_pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pComboBox)), ((gtk_widget_get_type ()))))))
);
15434
15435 g_object_unref(m_pComboBox);
15436 }
15437
15438 g_object_unref(m_pComboBuilder);
15439 }
15440};
15441
15442}
15443
15444bool custom_cell_renderer_surface_get_preferred_size(GtkCellRenderer *cell,
15445 GtkOrientation orientation,
15446 gint *minimum_size,
15447 gint *natural_size)
15448{
15449 GValue value = G_VALUE_INIT{ 0, { { 0 } } };
15450 g_value_init(&value, G_TYPE_STRING((GType) ((16) << (2))));
15451 g_object_get_property(G_OBJECT(cell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
cell)), (((GType) ((20) << (2))))))))
, "id", &value);
15452
15453 const char* pStr = g_value_get_string(&value);
15454
15455 OUString sId(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
15456
15457 value = G_VALUE_INIT{ 0, { { 0 } } };
15458 g_value_init(&value, G_TYPE_POINTER((GType) ((17) << (2))));
15459 g_object_get_property(G_OBJECT(cell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
cell)), (((GType) ((20) << (2))))))))
, "instance", &value);
15460
15461 CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell)((((CustomCellRendererSurface*) g_type_check_instance_cast ((
GTypeInstance*) ((cell)), ((custom_cell_renderer_surface_get_type
()))))))
;
15462
15463 GtkInstanceWidget* pWidget = static_cast<GtkInstanceWidget*>(g_value_get_pointer(&value));
15464
15465 Size aSize;
15466
15467 if (pWidget)
15468 {
15469 ensure_device(cellsurface, pWidget);
15470 if (GtkInstanceTreeView* pTreeView = dynamic_cast<GtkInstanceTreeView*>(pWidget))
15471 aSize = pTreeView->call_signal_custom_get_size(*cellsurface->device, sId);
15472 else if (GtkInstanceComboBox* pComboBox = dynamic_cast<GtkInstanceComboBox*>(pWidget))
15473 aSize = pComboBox->call_signal_custom_get_size(*cellsurface->device);
15474 }
15475
15476 if (orientation == GTK_ORIENTATION_HORIZONTAL)
15477 {
15478 if (minimum_size)
15479 *minimum_size = aSize.Width();
15480
15481 if (natural_size)
15482 *natural_size = aSize.Width();
15483 }
15484 else
15485 {
15486 if (minimum_size)
15487 *minimum_size = aSize.Height();
15488
15489 if (natural_size)
15490 *natural_size = aSize.Height();
15491 }
15492
15493 return true;
15494}
15495
15496void custom_cell_renderer_surface_render(GtkCellRenderer* cell,
15497 cairo_t* cr,
15498 GtkWidget* /*widget*/,
15499 const GdkRectangle* /*background_area*/,
15500 const GdkRectangle* cell_area,
15501 GtkCellRendererState flags)
15502{
15503 GValue value = G_VALUE_INIT{ 0, { { 0 } } };
15504 g_value_init(&value, G_TYPE_STRING((GType) ((16) << (2))));
15505 g_object_get_property(G_OBJECT(cell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
cell)), (((GType) ((20) << (2))))))))
, "id", &value);
15506
15507 const char* pStr = g_value_get_string(&value);
15508 OUString sId(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
15509
15510 value = G_VALUE_INIT{ 0, { { 0 } } };
15511 g_value_init(&value, G_TYPE_POINTER((GType) ((17) << (2))));
15512 g_object_get_property(G_OBJECT(cell)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
cell)), (((GType) ((20) << (2))))))))
, "instance", &value);
15513
15514 CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell)((((CustomCellRendererSurface*) g_type_check_instance_cast ((
GTypeInstance*) ((cell)), ((custom_cell_renderer_surface_get_type
()))))))
;
15515
15516 GtkInstanceWidget* pWidget = static_cast<GtkInstanceWidget*>(g_value_get_pointer(&value));
15517
15518 if (!pWidget)
15519 return;
15520
15521 ensure_device(cellsurface, pWidget);
15522
15523 Size aSize(cell_area->width, cell_area->height);
15524 // false to not bother setting the bg on resize as we'll do that
15525 // ourself via cairo
15526 cellsurface->device->SetOutputSizePixel(aSize, false);
15527
15528 cairo_surface_t* pSurface = get_underlying_cairo_surface(*cellsurface->device);
15529
15530 // fill surface as transparent so it can be blended with the potentially
15531 // selected background
15532 cairo_t* tempcr = cairo_create(pSurface);
15533 cairo_set_source_rgba(tempcr, 0, 0, 0, 0);
15534 cairo_set_operator(tempcr, CAIRO_OPERATOR_SOURCE);
15535 cairo_paint(tempcr);
15536 cairo_destroy(tempcr);
15537 cairo_surface_flush(pSurface);
15538
15539 if (GtkInstanceTreeView* pTreeView = dynamic_cast<GtkInstanceTreeView*>(pWidget))
15540 pTreeView->call_signal_custom_render(*cellsurface->device, tools::Rectangle(Point(0, 0), aSize), flags & GTK_CELL_RENDERER_SELECTED, sId);
15541 else if (GtkInstanceComboBox* pComboBox = dynamic_cast<GtkInstanceComboBox*>(pWidget))
15542 pComboBox->call_signal_custom_render(*cellsurface->device, tools::Rectangle(Point(0, 0), aSize), flags & GTK_CELL_RENDERER_SELECTED, sId);
15543 cairo_surface_mark_dirty(pSurface);
15544
15545 cairo_set_source_surface(cr, pSurface, cell_area->x, cell_area->y);
15546 cairo_paint(cr);
15547}
15548
15549namespace {
15550
15551class GtkInstanceEntryTreeView : public GtkInstanceContainer, public virtual weld::EntryTreeView
15552{
15553private:
15554 GtkInstanceEntry* m_pEntry;
15555 GtkInstanceTreeView* m_pTreeView;
15556 gulong m_nKeyPressSignalId;
15557 gulong m_nEntryInsertTextSignalId;
15558 guint m_nAutoCompleteIdleId;
15559 bool m_bAutoCompleteCaseSensitive;
15560 bool m_bTreeChange;
15561
15562 bool signal_key_press(GdkEventKey* pEvent)
15563 {
15564 if (GtkSalFrame::GetMouseModCode(pEvent->state)) // only with no modifiers held
15565 return false;
15566
15567 if (pEvent->keyval == GDK_KEY_KP_Up0xff97 || pEvent->keyval == GDK_KEY_Up0xff52 || pEvent->keyval == GDK_KEY_KP_Page_Up0xff9a || pEvent->keyval == GDK_KEY_Page_Up0xff55 ||
15568 pEvent->keyval == GDK_KEY_KP_Down0xff99 || pEvent->keyval == GDK_KEY_Down0xff54 || pEvent->keyval == GDK_KEY_KP_Page_Down0xff9b || pEvent->keyval == GDK_KEY_Page_Down0xff56)
15569 {
15570 gboolean ret;
15571 disable_notify_events();
15572 GtkWidget* pWidget = m_pTreeView->getWidget();
15573 if (m_pTreeView->get_selected_index() == -1)
15574 {
15575 m_pTreeView->set_cursor(0);
15576 m_pTreeView->select(0);
15577 m_xEntry->set_text(m_xTreeView->get_selected_text());
15578 }
15579 else
15580 {
15581 gtk_widget_grab_focus(pWidget);
15582 g_signal_emit_by_name(pWidget, "key-press-event", pEvent, &ret);
15583 m_xEntry->set_text(m_xTreeView->get_selected_text());
15584 gtk_widget_grab_focus(m_pEntry->getWidget());
15585 }
15586 m_xEntry->select_region(0, -1);
15587 enable_notify_events();
15588 m_bTreeChange = true;
15589 m_pEntry->fire_signal_changed();
15590 m_bTreeChange = false;
15591 return true;
15592 }
15593 return false;
15594 }
15595
15596 static gboolean signalKeyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
15597 {
15598 GtkInstanceEntryTreeView* pThis = static_cast<GtkInstanceEntryTreeView*>(widget);
15599 return pThis->signal_key_press(pEvent);
15600 }
15601
15602 static gboolean idleAutoComplete(gpointer widget)
15603 {
15604 GtkInstanceEntryTreeView* pThis = static_cast<GtkInstanceEntryTreeView*>(widget);
15605 pThis->auto_complete();
15606 return false;
15607 }
15608
15609 void auto_complete()
15610 {
15611 m_nAutoCompleteIdleId = 0;
15612 OUString aStartText = get_active_text();
15613 int nStartPos, nEndPos;
15614 get_entry_selection_bounds(nStartPos, nEndPos);
15615 int nMaxSelection = std::max(nStartPos, nEndPos);
15616 if (nMaxSelection != aStartText.getLength())
15617 return;
15618
15619 disable_notify_events();
15620 int nActive = get_active();
15621 int nStart = nActive;
15622
15623 if (nStart == -1)
15624 nStart = 0;
15625
15626 // Try match case sensitive from current position
15627 int nPos = m_pTreeView->starts_with(aStartText, nStart, true);
15628 if (nPos == -1 && nStart != 0)
15629 {
15630 // Try match case insensitive, but from start
15631 nPos = m_pTreeView->starts_with(aStartText, 0, true);
15632 }
15633
15634 if (!m_bAutoCompleteCaseSensitive)
15635 {
15636 // Try match case insensitive from current position
15637 nPos = m_pTreeView->starts_with(aStartText, nStart, false);
15638 if (nPos == -1 && nStart != 0)
15639 {
15640 // Try match case insensitive, but from start
15641 nPos = m_pTreeView->starts_with(aStartText, 0, false);
15642 }
15643 }
15644
15645 if (nPos == -1)
15646 {
15647 // Try match case sensitive from current position
15648 nPos = m_pTreeView->starts_with(aStartText, nStart, true);
15649 if (nPos == -1 && nStart != 0)
15650 {
15651 // Try match case sensitive, but from start
15652 nPos = m_pTreeView->starts_with(aStartText, 0, true);
15653 }
15654 }
15655
15656 if (nPos != -1)
15657 {
15658 OUString aText = get_text(nPos);
15659 if (aText != aStartText)
15660 set_active_text(aText);
15661 select_entry_region(aText.getLength(), aStartText.getLength());
15662 }
15663 enable_notify_events();
15664 }
15665
15666 void signal_entry_insert_text(GtkEntry*, const gchar*, gint, gint*)
15667 {
15668 // now check for autocompletes
15669 if (m_nAutoCompleteIdleId)
15670 g_source_remove(m_nAutoCompleteIdleId);
15671 m_nAutoCompleteIdleId = g_idle_add(idleAutoComplete, this);
15672 }
15673
15674 static void signalEntryInsertText(GtkEntry* pEntry, const gchar* pNewText, gint nNewTextLength,
15675 gint* position, gpointer widget)
15676 {
15677 GtkInstanceEntryTreeView* pThis = static_cast<GtkInstanceEntryTreeView*>(widget);
15678 pThis->signal_entry_insert_text(pEntry, pNewText, nNewTextLength, position);
15679 }
15680
15681
15682public:
15683 GtkInstanceEntryTreeView(GtkContainer* pContainer, GtkInstanceBuilder* pBuilder, bool bTakeOwnership,
15684 std::unique_ptr<weld::Entry> xEntry, std::unique_ptr<weld::TreeView> xTreeView)
15685 : EntryTreeView(std::move(xEntry), std::move(xTreeView))
15686 , GtkInstanceContainer(pContainer, pBuilder, bTakeOwnership)
15687 , m_pEntry(dynamic_cast<GtkInstanceEntry*>(m_xEntry.get()))
15688 , m_pTreeView(dynamic_cast<GtkInstanceTreeView*>(m_xTreeView.get()))
15689 , m_nAutoCompleteIdleId(0)
15690 , m_bAutoCompleteCaseSensitive(false)
15691 , m_bTreeChange(false)
15692 {
15693 assert(m_pEntry)(static_cast <bool> (m_pEntry) ? void (0) : __assert_fail
("m_pEntry", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15693, __extension__ __PRETTY_FUNCTION__))
;
15694 GtkWidget* pWidget = m_pEntry->getWidget();
15695 m_nKeyPressSignalId = g_signal_connect(pWidget, "key-press-event", G_CALLBACK(signalKeyPress), this)g_signal_connect_data ((pWidget), ("key-press-event"), (((GCallback
) (signalKeyPress))), (this), __null, (GConnectFlags) 0)
;
15696 m_nEntryInsertTextSignalId = g_signal_connect(pWidget, "insert-text", G_CALLBACK(signalEntryInsertText), this)g_signal_connect_data ((pWidget), ("insert-text"), (((GCallback
) (signalEntryInsertText))), (this), __null, (GConnectFlags) 0
)
;
15697 }
15698
15699 virtual void insert_separator(int /*pos*/, const OUString& /*rId*/) override
15700 {
15701 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15701, __extension__ __PRETTY_FUNCTION__))
;
15702 }
15703
15704 virtual void make_sorted() override
15705 {
15706 GtkWidget* pTreeView = m_pTreeView->getWidget();
15707 GtkTreeModel* pModel = gtk_tree_view_get_model(GTK_TREE_VIEW(pTreeView)((((GtkTreeView*) g_type_check_instance_cast ((GTypeInstance*
) ((pTreeView)), ((gtk_tree_view_get_type ()))))))
);
15708 GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(pModel)((((GtkTreeSortable*) g_type_check_instance_cast ((GTypeInstance
*) ((pModel)), ((gtk_tree_sortable_get_type ()))))))
;
15709 gtk_tree_sortable_set_sort_column_id(pSortable, 1, GTK_SORT_ASCENDING);
15710 }
15711
15712 virtual void set_entry_completion(bool bEnable, bool bCaseSensitive) override
15713 {
15714 assert(!bEnable && "not implemented yet")(static_cast <bool> (!bEnable && "not implemented yet"
) ? void (0) : __assert_fail ("!bEnable && \"not implemented yet\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15714, __extension__ __PRETTY_FUNCTION__))
; (void)bEnable;
15715 m_bAutoCompleteCaseSensitive = bCaseSensitive;
15716 }
15717
15718 virtual void set_entry_placeholder_text(const OUString& rText) override
15719 {
15720 m_xEntry->set_placeholder_text(rText);
15721 }
15722
15723 virtual void set_entry_editable(bool bEditable) override
15724 {
15725 m_xEntry->set_editable(bEditable);
15726 }
15727
15728 virtual void cut_entry_clipboard() override
15729 {
15730 m_xEntry->cut_clipboard();
15731 }
15732
15733 virtual void copy_entry_clipboard() override
15734 {
15735 m_xEntry->copy_clipboard();
15736 }
15737
15738 virtual void paste_entry_clipboard() override
15739 {
15740 m_xEntry->paste_clipboard();
15741 }
15742
15743 virtual void set_entry_font(const vcl::Font& rFont) override
15744 {
15745 m_xEntry->set_font(rFont);
15746 }
15747
15748 virtual vcl::Font get_entry_font() override
15749 {
15750 return m_xEntry->get_font();
15751 }
15752
15753 virtual void grab_focus() override { m_xEntry->grab_focus(); }
15754
15755 virtual void connect_focus_in(const Link<Widget&, void>& rLink) override
15756 {
15757 m_xEntry->connect_focus_in(rLink);
15758 }
15759
15760 virtual void connect_focus_out(const Link<Widget&, void>& rLink) override
15761 {
15762 m_xEntry->connect_focus_out(rLink);
15763 }
15764
15765 virtual void disable_notify_events() override
15766 {
15767 GtkWidget* pWidget = m_pEntry->getWidget();
15768 g_signal_handler_block(pWidget, m_nEntryInsertTextSignalId);
15769 g_signal_handler_block(pWidget, m_nKeyPressSignalId);
15770 m_pTreeView->disable_notify_events();
15771 GtkInstanceContainer::disable_notify_events();
15772 }
15773
15774 virtual void enable_notify_events() override
15775 {
15776 GtkWidget* pWidget = m_pEntry->getWidget();
15777 g_signal_handler_unblock(pWidget, m_nKeyPressSignalId);
15778 g_signal_handler_unblock(pWidget, m_nEntryInsertTextSignalId);
15779 m_pTreeView->enable_notify_events();
15780 GtkInstanceContainer::disable_notify_events();
15781 }
15782
15783 virtual bool changed_by_direct_pick() const override
15784 {
15785 return m_bTreeChange;
15786 }
15787
15788 virtual void set_custom_renderer(bool /*bOn*/) override
15789 {
15790 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15790, __extension__ __PRETTY_FUNCTION__))
;
15791 }
15792
15793 virtual int get_max_mru_count() const override
15794 {
15795 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15795, __extension__ __PRETTY_FUNCTION__))
;
15796 return 0;
15797 }
15798
15799 virtual void set_max_mru_count(int) override
15800 {
15801 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15801, __extension__ __PRETTY_FUNCTION__))
;
15802 }
15803
15804 virtual OUString get_mru_entries() const override
15805 {
15806 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15806, __extension__ __PRETTY_FUNCTION__))
;
15807 return OUString();
15808 }
15809
15810 virtual void set_mru_entries(const OUString&) override
15811 {
15812 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15812, __extension__ __PRETTY_FUNCTION__))
;
15813 }
15814
15815 virtual void set_item_menu(const OString&, weld::Menu*) override
15816 {
15817 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15817, __extension__ __PRETTY_FUNCTION__))
;
15818 }
15819
15820 VclPtr<VirtualDevice> create_render_virtual_device() const override
15821 {
15822 return create_virtual_device();
15823 }
15824
15825 int get_menu_button_width() const override
15826 {
15827 assert(false && "not implemented")(static_cast <bool> (false && "not implemented"
) ? void (0) : __assert_fail ("false && \"not implemented\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 15827, __extension__ __PRETTY_FUNCTION__))
;
15828 return 0;
15829 }
15830
15831 virtual ~GtkInstanceEntryTreeView() override
15832 {
15833 if (m_nAutoCompleteIdleId)
15834 g_source_remove(m_nAutoCompleteIdleId);
15835 GtkWidget* pWidget = m_pEntry->getWidget();
15836 g_signal_handler_disconnect(pWidget, m_nKeyPressSignalId);
15837 g_signal_handler_disconnect(pWidget, m_nEntryInsertTextSignalId);
15838 }
15839};
15840
15841class GtkInstanceExpander : public GtkInstanceContainer, public virtual weld::Expander
15842{
15843private:
15844 GtkExpander* m_pExpander;
15845 gulong m_nSignalId;
15846
15847 static void signalExpanded(GtkExpander* pExpander, GParamSpec*, gpointer widget)
15848 {
15849 GtkInstanceExpander* pThis = static_cast<GtkInstanceExpander*>(widget);
15850 SolarMutexGuard aGuard;
15851
15852 GtkWidget *pToplevel = gtk_widget_get_toplevel(GTK_WIDGET(pExpander)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pExpander)), ((gtk_widget_get_type ()))))))
);
15853
15854 // https://gitlab.gnome.org/GNOME/gtk/issues/70
15855 // I imagine at some point a release with a fix will be available in which
15856 // case this can be avoided depending on version number
15857 if (pToplevel && GTK_IS_WINDOW(pToplevel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pToplevel)); GType __t = ((gtk_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
&& gtk_widget_get_realized(pToplevel))
15858 {
15859 int nToplevelWidth, nToplevelHeight;
15860 int nChildHeight;
15861
15862 GtkWidget* child = gtk_bin_get_child(GTK_BIN(pExpander)((((GtkBin*) g_type_check_instance_cast ((GTypeInstance*) ((pExpander
)), ((gtk_bin_get_type ()))))))
);
15863 gtk_widget_get_preferred_height(child, &nChildHeight, nullptr);
15864 gtk_window_get_size(GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
, &nToplevelWidth, &nToplevelHeight);
15865
15866 if (pThis->get_expanded())
15867 nToplevelHeight += nChildHeight;
15868 else
15869 nToplevelHeight -= nChildHeight;
15870
15871 gtk_window_resize(GTK_WINDOW(pToplevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pToplevel)), ((gtk_window_get_type ()))))))
, nToplevelWidth, nToplevelHeight);
15872 }
15873
15874 pThis->signal_expanded();
15875 }
15876
15877public:
15878 GtkInstanceExpander(GtkExpander* pExpander, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
15879 : GtkInstanceContainer(GTK_CONTAINER(pExpander)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pExpander)), ((gtk_container_get_type ()))))))
, pBuilder, bTakeOwnership)
15880 , m_pExpander(pExpander)
15881 , m_nSignalId(g_signal_connect(m_pExpander, "notify::expanded", G_CALLBACK(signalExpanded), this)g_signal_connect_data ((m_pExpander), ("notify::expanded"), (
((GCallback) (signalExpanded))), (this), __null, (GConnectFlags
) 0)
)
15882 {
15883 }
15884
15885 virtual bool get_expanded() const override
15886 {
15887 return gtk_expander_get_expanded(m_pExpander);
15888 }
15889
15890 virtual void set_expanded(bool bExpand) override
15891 {
15892 gtk_expander_set_expanded(m_pExpander, bExpand);
15893 }
15894
15895 virtual ~GtkInstanceExpander() override
15896 {
15897 g_signal_handler_disconnect(m_pExpander, m_nSignalId);
15898 }
15899};
15900
15901 gboolean signalTooltipQuery(GtkWidget* pWidget, gint /*x*/, gint /*y*/,
15902 gboolean /*keyboard_mode*/, GtkTooltip *tooltip)
15903 {
15904 const ImplSVHelpData& aHelpData = ImplGetSVHelpData();
15905 if (aHelpData.mbBalloonHelp) // extended tips
15906 {
15907 // by default use accessible description
15908 AtkObject* pAtkObject = gtk_widget_get_accessible(pWidget);
15909 const char* pDesc = pAtkObject ? atk_object_get_description(pAtkObject) : nullptr;
15910 if (pDesc && pDesc[0])
15911 {
15912 gtk_tooltip_set_text(tooltip, pDesc);
15913 return true;
15914 }
15915
15916 // fallback to the mechanism which needs help installed
15917 OString sHelpId = ::get_help_id(pWidget);
15918 Help* pHelp = !sHelpId.isEmpty() ? Application::GetHelp() : nullptr;
15919 if (pHelp)
15920 {
15921 OUString sHelpText = pHelp->GetHelpText(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))), static_cast<weld::Widget*>(nullptr));
15922 if (!sHelpText.isEmpty())
15923 {
15924 gtk_tooltip_set_text(tooltip, OUStringToOString(sHelpText, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr());
15925 return true;
15926 }
15927 }
15928 }
15929
15930 const char* pDesc = gtk_widget_get_tooltip_text(pWidget);
15931 if (pDesc && pDesc[0])
15932 {
15933 gtk_tooltip_set_text(tooltip, pDesc);
15934 return true;
15935 }
15936
15937 return false;
15938 }
15939}
15940
15941namespace
15942{
15943
15944AtkObject* drawing_area_get_accessibity(GtkWidget *pWidget)
15945{
15946 AtkObject* pDefaultAccessible = default_drawing_area_get_accessible(pWidget);
15947 void* pData = g_object_get_data(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "g-lo-GtkInstanceDrawingArea");
15948 GtkInstanceDrawingArea* pDrawingArea = static_cast<GtkInstanceDrawingArea*>(pData);
15949 AtkObject *pAtkObj = pDrawingArea ? pDrawingArea->GetAtkObject(pDefaultAccessible) : nullptr;
15950 if (pAtkObj)
15951 return pAtkObj;
15952 return pDefaultAccessible;
15953}
15954
15955void ensure_intercept_drawing_area_accessibility()
15956{
15957 static bool bDone;
15958 if (!bDone)
15959 {
15960 gpointer pClass = g_type_class_ref(GTK_TYPE_DRAWING_AREA(gtk_drawing_area_get_type ()));
15961 GtkWidgetClass* pWidgetClass = GTK_WIDGET_CLASS(pClass)((((GtkWidgetClass*) g_type_check_class_cast ((GTypeClass*) (
(pClass)), ((gtk_widget_get_type ()))))))
;
15962 default_drawing_area_get_accessible = pWidgetClass->get_accessible;
15963 pWidgetClass->get_accessible = drawing_area_get_accessibity;
15964 g_type_class_unref(pClass);
15965 bDone = true;
15966 }
15967}
15968
15969void ensure_disable_ctrl_page_up_down(GType eType)
15970{
15971 gpointer pClass = g_type_class_ref(eType);
15972 GtkWidgetClass* pWidgetClass = GTK_WIDGET_CLASS(pClass)((((GtkWidgetClass*) g_type_check_class_cast ((GTypeClass*) (
(pClass)), ((gtk_widget_get_type ()))))))
;
15973 GtkBindingSet* pBindingSet = gtk_binding_set_by_class(pWidgetClass);
15974 gtk_binding_entry_remove(pBindingSet, GDK_KEY_Page_Up0xff55, GDK_CONTROL_MASK);
15975 gtk_binding_entry_remove(pBindingSet, GDK_KEY_Page_Up0xff55, static_cast<GdkModifierType>(GDK_SHIFT_MASK|GDK_CONTROL_MASK));
15976 gtk_binding_entry_remove(pBindingSet, GDK_KEY_Page_Down0xff56, GDK_CONTROL_MASK);
15977 gtk_binding_entry_remove(pBindingSet, GDK_KEY_Page_Down0xff56, static_cast<GdkModifierType>(GDK_SHIFT_MASK|GDK_CONTROL_MASK));
15978 g_type_class_unref(pClass);
15979}
15980
15981// tdf#130400 disable ctrl+page_up and ctrl+page_down bindings so the
15982// keystrokes are consumed by the surrounding notebook bindings instead
15983void ensure_disable_ctrl_page_up_down_bindings()
15984{
15985 static bool bDone;
15986 if (!bDone)
15987 {
15988 ensure_disable_ctrl_page_up_down(GTK_TYPE_TREE_VIEW(gtk_tree_view_get_type ()));
15989 ensure_disable_ctrl_page_up_down(GTK_TYPE_SPIN_BUTTON(gtk_spin_button_get_type ()));
15990 bDone = true;
15991 }
15992}
15993
15994class GtkInstanceBuilder : public weld::Builder
15995{
15996private:
15997 ResHookProc m_pStringReplace;
15998 OString m_aUtf8HelpRoot;
15999 OUString m_aIconTheme;
16000 OUString m_aUILang;
16001 GtkBuilder* m_pBuilder;
16002 GSList* m_pObjectList;
16003 GtkWidget* m_pParentWidget;
16004 gulong m_nNotifySignalId;
16005 std::vector<GtkButton*> m_aMnemonicButtons;
16006 std::vector<GtkLabel*> m_aMnemonicLabels;
16007
16008 VclPtr<SystemChildWindow> m_xInterimGlue;
16009
16010 void postprocess_widget(GtkWidget* pWidget)
16011 {
16012 const bool bHideHelp = comphelper::LibreOfficeKit::isActive() &&
16013 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty();
16014
16015 //fixup icons
16016 //wanted: better way to do this, e.g. make gtk use gio for
16017 //loading from a filename and provide gio protocol handler
16018 //for our image in a zip urls
16019 //
16020 //unpack the images and keep them as dirs and just
16021 //add the paths to the gtk icon theme dir
16022 if (GTK_IS_IMAGE(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_image_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16023 {
16024 GtkImage* pImage = GTK_IMAGE(pWidget)((((GtkImage*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_image_get_type ()))))))
;
16025 const gchar* icon_name;
16026 gtk_image_get_icon_name(pImage, &icon_name, nullptr);
16027 if (icon_name)
16028 {
16029 OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
16030 GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang);
16031 if (pixbuf)
16032 {
16033 gtk_image_set_from_pixbuf(pImage, pixbuf);
16034 g_object_unref(pixbuf);
16035 }
16036 }
16037 }
16038 else if (GTK_IS_TOOL_BUTTON(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_tool_button_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16039 {
16040 GtkToolButton* pToolButton = GTK_TOOL_BUTTON(pWidget)((((GtkToolButton*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_tool_button_get_type ()))))))
;
16041 const gchar* icon_name = gtk_tool_button_get_icon_name(pToolButton);
16042 if (icon_name)
16043 {
16044 OUString aIconName(icon_name, strlen(icon_name), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
16045 GdkPixbuf* pixbuf = load_icon_by_name_theme_lang(aIconName, m_aIconTheme, m_aUILang);
16046 if (pixbuf)
16047 {
16048 GtkWidget* pImage = gtk_image_new_from_pixbuf(pixbuf);
16049 g_object_unref(pixbuf);
16050 gtk_tool_button_set_icon_widget(pToolButton, pImage);
16051 gtk_widget_show(pImage);
16052 }
16053 }
16054
16055 // if no tooltip reuse the label as default tooltip
16056 if (!gtk_widget_get_tooltip_text(pWidget))
16057 {
16058 if (const gchar* label = gtk_tool_button_get_label(pToolButton))
16059 gtk_widget_set_tooltip_text(pWidget, label);
16060 }
16061 }
16062
16063 //set helpids
16064 const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget)((((GtkBuildable*) g_type_check_instance_cast ((GTypeInstance
*) ((pWidget)), ((gtk_buildable_get_type ()))))))
);
16065 size_t nLen = pStr ? strlen(pStr) : 0;
16066 if (nLen)
16067 {
16068 OString sBuildableName(pStr, nLen);
16069 OString sHelpId = m_aUtf8HelpRoot + sBuildableName;
16070 set_help_id(pWidget, sHelpId);
16071 //hook up for extended help
16072 const ImplSVHelpData& aHelpData = ImplGetSVHelpData();
16073 if (aHelpData.mbBalloonHelp && !GTK_IS_DIALOG(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_dialog_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
&& !GTK_IS_ASSISTANT(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16074 {
16075 gtk_widget_set_has_tooltip(pWidget, true);
16076 g_signal_connect(pWidget, "query-tooltip", G_CALLBACK(signalTooltipQuery), nullptr)g_signal_connect_data ((pWidget), ("query-tooltip"), (((GCallback
) (signalTooltipQuery))), (nullptr), __null, (GConnectFlags) 0
)
;
16077 }
16078
16079 if (bHideHelp && sBuildableName == "help")
16080 gtk_widget_hide(pWidget);
16081 }
16082
16083 // expand placeholder and collect potentially missing mnemonics
16084 if (GTK_IS_BUTTON(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_button_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16085 {
16086 GtkButton* pButton = GTK_BUTTON(pWidget)((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_button_get_type ()))))))
;
16087 if (m_pStringReplace != nullptr)
16088 {
16089 OUString aLabel(get_label(pButton));
16090 if (!aLabel.isEmpty())
16091 set_label(pButton, (*m_pStringReplace)(aLabel));
16092 }
16093 if (gtk_button_get_use_underline(pButton) && !gtk_button_get_use_stock(pButton))
16094 m_aMnemonicButtons.push_back(pButton);
16095 }
16096 else if (GTK_IS_LABEL(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_label_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16097 {
16098 GtkLabel* pLabel = GTK_LABEL(pWidget)((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_label_get_type ()))))))
;
16099 if (m_pStringReplace != nullptr)
16100 {
16101 OUString aLabel(get_label(pLabel));
16102 if (!aLabel.isEmpty())
16103 set_label(pLabel, (*m_pStringReplace)(aLabel));
16104 }
16105 if (gtk_label_get_use_underline(pLabel))
16106 m_aMnemonicLabels.push_back(pLabel);
16107 }
16108 else if (GTK_IS_TEXT_VIEW(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_text_view_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16109 {
16110 GtkTextView* pTextView = GTK_TEXT_VIEW(pWidget)((((GtkTextView*) g_type_check_instance_cast ((GTypeInstance*
) ((pWidget)), ((gtk_text_view_get_type ()))))))
;
16111 if (m_pStringReplace != nullptr)
16112 {
16113 GtkTextBuffer* pBuffer = gtk_text_view_get_buffer(pTextView);
16114 GtkTextIter start, end;
16115 gtk_text_buffer_get_bounds(pBuffer, &start, &end);
16116 char* pTextStr = gtk_text_buffer_get_text(pBuffer, &start, &end, true);
16117 int nTextLen = pTextStr ? strlen(pTextStr) : 0;
16118 if (nTextLen)
16119 {
16120 OUString sOldText(pTextStr, nTextLen, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
16121 OString sText(OUStringToOString((*m_pStringReplace)(sOldText), RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
16122 gtk_text_buffer_set_text(pBuffer, sText.getStr(), sText.getLength());
16123 }
16124 g_free(pTextStr);
16125 }
16126 }
16127 else if (GTK_IS_WINDOW(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_window_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16128 {
16129 if (m_pStringReplace != nullptr) {
16130 GtkWindow* pWindow = GTK_WINDOW(pWidget)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pWidget)), ((gtk_window_get_type ()))))))
;
16131 set_title(pWindow, (*m_pStringReplace)(get_title(pWindow)));
16132 if (GTK_IS_MESSAGE_DIALOG(pWindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWindow)); GType __t = ((gtk_message_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16133 {
16134 GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(pWindow)((((GtkMessageDialog*) g_type_check_instance_cast ((GTypeInstance
*) ((pWindow)), ((gtk_message_dialog_get_type ()))))))
;
16135 set_primary_text(pMessageDialog, (*m_pStringReplace)(get_primary_text(pMessageDialog)));
16136 set_secondary_text(pMessageDialog, (*m_pStringReplace)(get_secondary_text(pMessageDialog)));
16137 }
16138 }
16139 }
16140 }
16141
16142 //GtkBuilder sets translation domain during parse, and unsets it again afterwards.
16143 //In order for GtkBuilder to find the translations bindtextdomain has to be called
16144 //for the domain. So here on the first setting of "domain" we call Translate::Create
16145 //to make sure that happens. Without this, if some other part of LibreOffice has
16146 //used the translation machinery for this domain it will still work, but if it
16147 //hasn't, e.g. tdf#119929, then the translation fails
16148 void translation_domain_set()
16149 {
16150 Translate::Create(gtk_builder_get_translation_domain(m_pBuilder), LanguageTag(m_aUILang));
16151 g_signal_handler_disconnect(m_pBuilder, m_nNotifySignalId);
16152 }
16153
16154 static void signalNotify(GObject*, GParamSpec *pSpec, gpointer pData)
16155 {
16156 g_return_if_fail(pSpec != nullptr)do { if ((pSpec != nullptr)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__PRETTY_FUNCTION__)), "pSpec != nullptr"
); return; } } while (0)
;
16157 if (strcmp(pSpec->name, "translation-domain") == 0)
16158 {
16159 GtkInstanceBuilder* pBuilder = static_cast<GtkInstanceBuilder*>(pData);
16160 pBuilder->translation_domain_set();
16161 }
16162 }
16163
16164 static void postprocess(gpointer data, gpointer user_data)
16165 {
16166 GObject* pObject = static_cast<GObject*>(data);
16167 if (!GTK_IS_WIDGET(pObject)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pObject)); GType __t = ((gtk_widget_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16168 return;
16169 GtkInstanceBuilder* pThis = static_cast<GtkInstanceBuilder*>(user_data);
16170 pThis->postprocess_widget(GTK_WIDGET(pObject)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pObject)), ((gtk_widget_get_type ()))))))
);
16171 }
16172public:
16173 GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile, SystemChildWindow* pInterimGlue)
16174 : weld::Builder()
16175 , m_pStringReplace(Translate::GetReadStringHook())
16176 , m_pParentWidget(pParent)
16177 , m_nNotifySignalId(0)
16178 , m_xInterimGlue(pInterimGlue)
16179 {
16180 OUString sHelpRoot(rUIFile);
16181 ensure_intercept_drawing_area_accessibility();
16182 ensure_disable_ctrl_page_up_down_bindings();
16183
16184 sal_Int32 nIdx = sHelpRoot.lastIndexOf('.');
16185 if (nIdx != -1)
16186 sHelpRoot = sHelpRoot.copy(0, nIdx);
16187 sHelpRoot += OUString('/');
16188 m_aUtf8HelpRoot = OUStringToOString(sHelpRoot, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
16189 m_aIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme();
16190 m_aUILang = Application::GetSettings().GetUILanguageTag().getBcp47();
16191
16192 OUString aUri(rUIRoot + rUIFile);
16193 OUString aPath;
16194 osl::FileBase::getSystemPathFromFileURL(aUri, aPath);
16195 m_pBuilder = gtk_builder_new();
16196 m_nNotifySignalId = g_signal_connect_data(G_OBJECT(m_pBuilder)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pBuilder)), (((GType) ((20) << (2))))))))
, "notify", G_CALLBACK(signalNotify)((GCallback) (signalNotify)), this, nullptr, G_CONNECT_AFTER);
16197 auto rc = gtk_builder_add_from_file(m_pBuilder, OUStringToOString(aPath, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))).getStr(), nullptr);
16198 assert(rc && "could not load UI file")(static_cast <bool> (rc && "could not load UI file"
) ? void (0) : __assert_fail ("rc && \"could not load UI file\""
, "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 16198, __extension__ __PRETTY_FUNCTION__))
;
16199 (void) rc;
16200
16201 m_pObjectList = gtk_builder_get_objects(m_pBuilder);
16202 g_slist_foreach(m_pObjectList, postprocess, this);
16203
16204 GenerateMissingMnemonics();
16205
16206 if (m_xInterimGlue)
16207 {
16208 assert(m_pParentWidget)(static_cast <bool> (m_pParentWidget) ? void (0) : __assert_fail
("m_pParentWidget", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 16208, __extension__ __PRETTY_FUNCTION__))
;
16209 g_object_set_data(G_OBJECT(m_pParentWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
m_pParentWidget)), (((GType) ((20) << (2))))))))
, "InterimWindowGlue", m_xInterimGlue.get());
16210 }
16211 }
16212
16213 void GenerateMissingMnemonics()
16214 {
16215 MnemonicGenerator aMnemonicGenerator('_');
16216 for (const auto a : m_aMnemonicButtons)
16217 aMnemonicGenerator.RegisterMnemonic(get_label(a));
16218 for (const auto a : m_aMnemonicLabels)
16219 aMnemonicGenerator.RegisterMnemonic(get_label(a));
16220
16221 for (const auto a : m_aMnemonicButtons)
16222 {
16223 OUString aLabel(get_label(a));
16224 OUString aNewLabel = aMnemonicGenerator.CreateMnemonic(aLabel);
16225 if (aLabel == aNewLabel)
16226 continue;
16227 set_label(a, aNewLabel);
16228 }
16229 for (const auto a : m_aMnemonicLabels)
16230 {
16231 OUString aLabel(get_label(a));
16232 OUString aNewLabel = aMnemonicGenerator.CreateMnemonic(aLabel);
16233 if (aLabel == aNewLabel)
16234 continue;
16235 set_label(a, aNewLabel);
16236 }
16237
16238 m_aMnemonicLabels.clear();
16239 m_aMnemonicButtons.clear();
16240 }
16241
16242 OString get_current_page_help_id()
16243 {
16244 OString sPageHelpId;
16245 // check to see if there is a notebook called tabcontrol and get the
16246 // helpid for the current page of that
16247 std::unique_ptr<weld::Notebook> xNotebook(weld_notebook("tabcontrol"));
16248 if (xNotebook)
16249 {
16250 if (GtkInstanceContainer* pPage = dynamic_cast<GtkInstanceContainer*>(xNotebook->get_page(xNotebook->get_current_page_ident())))
16251 {
16252 GtkWidget* pContainer = pPage->getWidget();
16253 GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pContainer)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pContainer)), ((gtk_container_get_type ()))))))
);
16254 GList* pChild = g_list_first(pChildren);
16255 if (pChild)
16256 {
16257 GtkWidget* pPageWidget = static_cast<GtkWidget*>(pChild->data);
16258 sPageHelpId = ::get_help_id(pPageWidget);
16259 }
16260 g_list_free(pChildren);
16261 }
16262 }
16263 return sPageHelpId;
16264 }
16265
16266 virtual ~GtkInstanceBuilder() override
16267 {
16268 g_slist_free(m_pObjectList);
16269 g_object_unref(m_pBuilder);
16270 m_xInterimGlue.disposeAndClear();
16271 }
16272
16273 //ideally we would have/use weld::Container add and explicitly
16274 //call add when we want to do this, but in the vcl impl the
16275 //parent has to be set when the child is created, so for the
16276 //gtk impl emulate this by doing this implicitly at weld time
16277 void auto_add_parentless_widgets_to_container(GtkWidget* pWidget)
16278 {
16279 if (gtk_widget_get_toplevel(pWidget) == pWidget && !GTK_IS_POPOVER(pWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pWidget)); GType __t = ((gtk_popover_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16280 gtk_container_add(GTK_CONTAINER(m_pParentWidget)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pParentWidget)), ((gtk_container_get_type ()))))))
, pWidget);
16281 }
16282
16283 virtual std::unique_ptr<weld::MessageDialog> weld_message_dialog(const OString &id) override
16284 {
16285 GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkMessageDialog*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_message_dialog_get_type
()))))))
;
16286 if (!pMessageDialog)
16287 return nullptr;
16288 gtk_window_set_transient_for(GTK_WINDOW(pMessageDialog)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pMessageDialog)), ((gtk_window_get_type ()))))))
, GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(m_pParentWidget))), ((gtk_window_get_type
()))))))
);
16289 return std::make_unique<GtkInstanceMessageDialog>(pMessageDialog, this, true);
16290 }
16291
16292 virtual std::unique_ptr<weld::Assistant> weld_assistant(const OString &id) override
16293 {
16294 GtkAssistant* pAssistant = GTK_ASSISTANT(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkAssistant*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_assistant_get_type
()))))))
;
16295 if (!pAssistant)
16296 return nullptr;
16297 if (m_pParentWidget)
16298 gtk_window_set_transient_for(GTK_WINDOW(pAssistant)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pAssistant)), ((gtk_window_get_type ()))))))
, GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(m_pParentWidget))), ((gtk_window_get_type
()))))))
);
16299 return std::make_unique<GtkInstanceAssistant>(pAssistant, this, true);
16300 }
16301
16302 virtual std::unique_ptr<weld::Dialog> weld_dialog(const OString &id) override
16303 {
16304 GtkWindow* pDialog = GTK_WINDOW(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_window_get_type
()))))))
;
16305 if (!pDialog)
16306 return nullptr;
16307 if (m_pParentWidget)
16308 gtk_window_set_transient_for(pDialog, GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(m_pParentWidget))), ((gtk_window_get_type
()))))))
);
16309 return std::make_unique<GtkInstanceDialog>(pDialog, this, true);
16310 }
16311
16312 virtual std::unique_ptr<weld::Window> create_screenshot_window() override
16313 {
16314 GtkWidget* pTopLevel = nullptr;
16315
16316 for (GSList* l = m_pObjectList; l; l = g_slist_next(l)((l) ? (((GSList *)(l))->next) : __null))
16317 {
16318 GObject* pObj = static_cast<GObject*>(l->data);
16319
16320 if (!GTK_IS_WIDGET(pObj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pObj)); GType __t = ((gtk_widget_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
|| gtk_widget_get_parent(GTK_WIDGET(pObj)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pObj)), ((gtk_widget_get_type ()))))))
))
16321 continue;
16322
16323 if (!pTopLevel)
16324 pTopLevel = GTK_WIDGET(pObj)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pObj)), ((gtk_widget_get_type ()))))))
;
16325 else if (GTK_IS_WINDOW(pObj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pObj)); GType __t = ((gtk_window_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16326 pTopLevel = GTK_WIDGET(pObj)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pObj)), ((gtk_widget_get_type ()))))))
;
16327 }
16328
16329 if (!pTopLevel)
16330 return nullptr;
16331
16332 GtkWindow* pDialog;
16333 if (GTK_IS_WINDOW(pTopLevel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(pTopLevel)); GType __t = ((gtk_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16334 pDialog = GTK_WINDOW(pTopLevel)((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(pTopLevel)), ((gtk_window_get_type ()))))))
;
16335 else
16336 {
16337 pDialog = GTK_WINDOW(gtk_dialog_new())((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_dialog_new())), ((gtk_window_get_type ()))))))
;
16338 ::set_help_id(GTK_WIDGET(pDialog)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pDialog)), ((gtk_widget_get_type ()))))))
, ::get_help_id(pTopLevel));
16339
16340 GtkWidget* pContentArea = gtk_dialog_get_content_area(GTK_DIALOG(pDialog)((((GtkDialog*) g_type_check_instance_cast ((GTypeInstance*) (
(pDialog)), ((gtk_dialog_get_type ()))))))
);
16341 gtk_container_add(GTK_CONTAINER(pContentArea)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pContentArea)), ((gtk_container_get_type ()))))))
, pTopLevel);
16342 gtk_widget_show_all(pTopLevel);
16343 }
16344
16345 if (m_pParentWidget)
16346 gtk_window_set_transient_for(pDialog, GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(m_pParentWidget))), ((gtk_window_get_type
()))))))
);
16347 return std::make_unique<GtkInstanceDialog>(pDialog, this, true);
16348 }
16349
16350 virtual std::unique_ptr<weld::Widget> weld_widget(const OString &id) override
16351 {
16352 GtkWidget* pWidget = GTK_WIDGET(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_widget_get_type
()))))))
;
16353 if (!pWidget)
16354 return nullptr;
16355 auto_add_parentless_widgets_to_container(pWidget);
16356 return std::make_unique<GtkInstanceWidget>(pWidget, this, false);
16357 }
16358
16359 virtual std::unique_ptr<weld::Container> weld_container(const OString &id) override
16360 {
16361 GtkContainer* pContainer = GTK_CONTAINER(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_container_get_type
()))))))
;
16362 if (!pContainer)
16363 return nullptr;
16364 auto_add_parentless_widgets_to_container(GTK_WIDGET(pContainer)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pContainer)), ((gtk_widget_get_type ()))))))
);
16365 return std::make_unique<GtkInstanceContainer>(pContainer, this, false);
16366 }
16367
16368 virtual std::unique_ptr<weld::Box> weld_box(const OString &id) override
16369 {
16370 GtkBox* pBox = GTK_BOX(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkBox*) g_type_check_instance_cast ((GTypeInstance*) ((gtk_builder_get_object
(m_pBuilder, id.getStr()))), ((gtk_box_get_type ()))))))
;
16371 if (!pBox)
16372 return nullptr;
16373 auto_add_parentless_widgets_to_container(GTK_WIDGET(pBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pBox)), ((gtk_widget_get_type ()))))))
);
16374 return std::make_unique<GtkInstanceBox>(pBox, this, false);
16375 }
16376
16377 virtual std::unique_ptr<weld::Paned> weld_paned(const OString &id) override
16378 {
16379 GtkPaned* pPaned = GTK_PANED(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkPaned*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_paned_get_type
()))))))
;
16380 if (!pPaned)
16381 return nullptr;
16382 auto_add_parentless_widgets_to_container(GTK_WIDGET(pPaned)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pPaned)), ((gtk_widget_get_type ()))))))
);
16383 return std::make_unique<GtkInstancePaned>(pPaned, this, false);
16384 }
16385
16386 virtual std::unique_ptr<weld::Frame> weld_frame(const OString &id) override
16387 {
16388 GtkFrame* pFrame = GTK_FRAME(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkFrame*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_frame_get_type
()))))))
;
16389 if (!pFrame)
16390 return nullptr;
16391 auto_add_parentless_widgets_to_container(GTK_WIDGET(pFrame)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pFrame)), ((gtk_widget_get_type ()))))))
);
16392 return std::make_unique<GtkInstanceFrame>(pFrame, this, false);
16393 }
16394
16395 virtual std::unique_ptr<weld::ScrolledWindow> weld_scrolled_window(const OString &id, bool bUserManagedScrolling = false) override
16396 {
16397 GtkScrolledWindow* pScrolledWindow = GTK_SCROLLED_WINDOW(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkScrolledWindow*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_scrolled_window_get_type
()))))))
;
16398 if (!pScrolledWindow)
16399 return nullptr;
16400 auto_add_parentless_widgets_to_container(GTK_WIDGET(pScrolledWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pScrolledWindow)), ((gtk_widget_get_type ()))))))
);
16401 return std::make_unique<GtkInstanceScrolledWindow>(pScrolledWindow, this, false, bUserManagedScrolling);
16402 }
16403
16404 virtual std::unique_ptr<weld::Notebook> weld_notebook(const OString &id) override
16405 {
16406 GtkNotebook* pNotebook = GTK_NOTEBOOK(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkNotebook*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_notebook_get_type
()))))))
;
16407 if (!pNotebook)
16408 return nullptr;
16409 auto_add_parentless_widgets_to_container(GTK_WIDGET(pNotebook)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pNotebook)), ((gtk_widget_get_type ()))))))
);
16410 return std::make_unique<GtkInstanceNotebook>(pNotebook, this, false);
16411 }
16412
16413 virtual std::unique_ptr<weld::Button> weld_button(const OString &id) override
16414 {
16415 GtkButton* pButton = GTK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkButton*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_button_get_type
()))))))
;
16416 if (!pButton)
16417 return nullptr;
16418 auto_add_parentless_widgets_to_container(GTK_WIDGET(pButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_widget_get_type ()))))))
);
16419 return std::make_unique<GtkInstanceButton>(pButton, this, false);
16420 }
16421
16422 virtual std::unique_ptr<weld::MenuButton> weld_menu_button(const OString &id) override
16423 {
16424 GtkMenuButton* pButton = GTK_MENU_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkMenuButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_menu_button_get_type
()))))))
;
16425 if (!pButton)
16426 return nullptr;
16427 auto_add_parentless_widgets_to_container(GTK_WIDGET(pButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_widget_get_type ()))))))
);
16428 return std::make_unique<GtkInstanceMenuButton>(pButton, nullptr, this, false);
16429 }
16430
16431 virtual std::unique_ptr<weld::LinkButton> weld_link_button(const OString &id) override
16432 {
16433 GtkLinkButton* pButton = GTK_LINK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkLinkButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_link_button_get_type
()))))))
;
16434 if (!pButton)
16435 return nullptr;
16436 auto_add_parentless_widgets_to_container(GTK_WIDGET(pButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pButton)), ((gtk_widget_get_type ()))))))
);
16437 return std::make_unique<GtkInstanceLinkButton>(pButton, this, false);
16438 }
16439
16440 virtual std::unique_ptr<weld::ToggleButton> weld_toggle_button(const OString &id) override
16441 {
16442 GtkToggleButton* pToggleButton = GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkToggleButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_toggle_button_get_type
()))))))
;
16443 if (!pToggleButton)
16444 return nullptr;
16445 auto_add_parentless_widgets_to_container(GTK_WIDGET(pToggleButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pToggleButton)), ((gtk_widget_get_type ()))))))
);
16446 return std::make_unique<GtkInstanceToggleButton>(pToggleButton, this, false);
16447 }
16448
16449 virtual std::unique_ptr<weld::RadioButton> weld_radio_button(const OString &id) override
16450 {
16451 GtkRadioButton* pRadioButton = GTK_RADIO_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkRadioButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_radio_button_get_type
()))))))
;
16452 if (!pRadioButton)
16453 return nullptr;
16454 auto_add_parentless_widgets_to_container(GTK_WIDGET(pRadioButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pRadioButton)), ((gtk_widget_get_type ()))))))
);
16455 return std::make_unique<GtkInstanceRadioButton>(pRadioButton, this, false);
16456 }
16457
16458 virtual std::unique_ptr<weld::CheckButton> weld_check_button(const OString &id) override
16459 {
16460 GtkCheckButton* pCheckButton = GTK_CHECK_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkCheckButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_check_button_get_type
()))))))
;
16461 if (!pCheckButton)
16462 return nullptr;
16463 auto_add_parentless_widgets_to_container(GTK_WIDGET(pCheckButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pCheckButton)), ((gtk_widget_get_type ()))))))
);
16464 return std::make_unique<GtkInstanceCheckButton>(pCheckButton, this, false);
16465 }
16466
16467 virtual std::unique_ptr<weld::Scale> weld_scale(const OString &id) override
16468 {
16469 GtkScale* pScale = GTK_SCALE(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkScale*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_scale_get_type
()))))))
;
16470 if (!pScale)
16471 return nullptr;
16472 auto_add_parentless_widgets_to_container(GTK_WIDGET(pScale)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pScale)), ((gtk_widget_get_type ()))))))
);
16473 return std::make_unique<GtkInstanceScale>(pScale, this, false);
16474 }
16475
16476 virtual std::unique_ptr<weld::ProgressBar> weld_progress_bar(const OString &id) override
16477 {
16478 GtkProgressBar* pProgressBar = GTK_PROGRESS_BAR(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkProgressBar*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_progress_bar_get_type
()))))))
;
16479 if (!pProgressBar)
16480 return nullptr;
16481 auto_add_parentless_widgets_to_container(GTK_WIDGET(pProgressBar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pProgressBar)), ((gtk_widget_get_type ()))))))
);
16482 return std::make_unique<GtkInstanceProgressBar>(pProgressBar, this, false);
16483 }
16484
16485 virtual std::unique_ptr<weld::Spinner> weld_spinner(const OString &id) override
16486 {
16487 GtkSpinner* pSpinner = GTK_SPINNER(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkSpinner*) g_type_check_instance_cast ((GTypeInstance*)
((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_spinner_get_type
()))))))
;
16488 if (!pSpinner)
16489 return nullptr;
16490 auto_add_parentless_widgets_to_container(GTK_WIDGET(pSpinner)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pSpinner)), ((gtk_widget_get_type ()))))))
);
16491 return std::make_unique<GtkInstanceSpinner>(pSpinner, this, false);
16492 }
16493
16494 virtual std::unique_ptr<weld::Image> weld_image(const OString &id) override
16495 {
16496 GtkImage* pImage = GTK_IMAGE(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkImage*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_image_get_type
()))))))
;
16497 if (!pImage)
16498 return nullptr;
16499 auto_add_parentless_widgets_to_container(GTK_WIDGET(pImage)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pImage)), ((gtk_widget_get_type ()))))))
);
16500 return std::make_unique<GtkInstanceImage>(pImage, this, false);
16501 }
16502
16503 virtual std::unique_ptr<weld::Calendar> weld_calendar(const OString &id) override
16504 {
16505 GtkCalendar* pCalendar = GTK_CALENDAR(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkCalendar*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_calendar_get_type
()))))))
;
16506 if (!pCalendar)
16507 return nullptr;
16508 auto_add_parentless_widgets_to_container(GTK_WIDGET(pCalendar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pCalendar)), ((gtk_widget_get_type ()))))))
);
16509 return std::make_unique<GtkInstanceCalendar>(pCalendar, this, false);
16510 }
16511
16512 virtual std::unique_ptr<weld::Entry> weld_entry(const OString &id) override
16513 {
16514 GtkEntry* pEntry = GTK_ENTRY(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkEntry*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_entry_get_type
()))))))
;
16515 if (!pEntry)
16516 return nullptr;
16517 auto_add_parentless_widgets_to_container(GTK_WIDGET(pEntry)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pEntry)), ((gtk_widget_get_type ()))))))
);
16518 return std::make_unique<GtkInstanceEntry>(pEntry, this, false);
16519 }
16520
16521 virtual std::unique_ptr<weld::SpinButton> weld_spin_button(const OString &id) override
16522 {
16523 GtkSpinButton* pSpinButton = GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkSpinButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_spin_button_get_type
()))))))
;
16524 if (!pSpinButton)
16525 return nullptr;
16526 auto_add_parentless_widgets_to_container(GTK_WIDGET(pSpinButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pSpinButton)), ((gtk_widget_get_type ()))))))
);
16527 return std::make_unique<GtkInstanceSpinButton>(pSpinButton, this, false);
16528 }
16529
16530 virtual std::unique_ptr<weld::MetricSpinButton> weld_metric_spin_button(const OString& id, FieldUnit eUnit) override
16531 {
16532 return std::make_unique<weld::MetricSpinButton>(weld_spin_button(id), eUnit);
16533 }
16534
16535 virtual std::unique_ptr<weld::FormattedSpinButton> weld_formatted_spin_button(const OString &id) override
16536 {
16537 GtkSpinButton* pSpinButton = GTK_SPIN_BUTTON(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkSpinButton*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_spin_button_get_type
()))))))
;
16538 if (!pSpinButton)
16539 return nullptr;
16540 auto_add_parentless_widgets_to_container(GTK_WIDGET(pSpinButton)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pSpinButton)), ((gtk_widget_get_type ()))))))
);
16541 return std::make_unique<GtkInstanceFormattedSpinButton>(pSpinButton, this, false);
16542 }
16543
16544 virtual std::unique_ptr<weld::ComboBox> weld_combo_box(const OString &id) override
16545 {
16546 GtkComboBox* pComboBox = GTK_COMBO_BOX(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkComboBox*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_combo_box_get_type
()))))))
;
16547 if (!pComboBox)
16548 return nullptr;
16549 auto_add_parentless_widgets_to_container(GTK_WIDGET(pComboBox)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pComboBox)), ((gtk_widget_get_type ()))))))
);
16550
16551 /* we replace GtkComboBox because of difficulties with too tall menus
16552
16553 1) https://gitlab.gnome.org/GNOME/gtk/issues/1910
16554 has_entry long menus take forever to appear (tdf#125388)
16555
16556 on measuring each row, the GtkComboBox GtkTreeMenu will call
16557 its area_apply_attributes_cb function on the row, but that calls
16558 gtk_tree_menu_get_path_item which then loops through each child of the
16559 menu looking for the widget of the row, so performance drops to useless.
16560
16561 All area_apply_attributes_cb does it set menu item sensitivity, so block it from running
16562 with fragile hackery which assumes that the unwanted callback is the only one with a
16563
16564 2) https://gitlab.gnome.org/GNOME/gtk/issues/94
16565 when a super tall combobox menu is activated, and the selected
16566 entry is sufficiently far down the list, then the menu doesn't
16567 appear under wayland
16568
16569 3) https://gitlab.gnome.org/GNOME/gtk/issues/310
16570 no typeahead support
16571
16572 4) we want to be able to control the width of the button, but have a drop down menu which
16573 is not limited to the width of the button
16574
16575 5) https://bugs.documentfoundation.org/show_bug.cgi?id=131120
16576 super tall menu doesn't appear under X sometimes
16577 */
16578 GtkBuilder* pComboBuilder = makeComboBoxBuilder();
16579 return std::make_unique<GtkInstanceComboBox>(pComboBuilder, pComboBox, this, false);
16580 }
16581
16582 virtual std::unique_ptr<weld::TreeView> weld_tree_view(const OString &id) override
16583 {
16584 GtkTreeView* pTreeView = GTK_TREE_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkTreeView*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_tree_view_get_type
()))))))
;
16585 if (!pTreeView)
16586 return nullptr;
16587 auto_add_parentless_widgets_to_container(GTK_WIDGET(pTreeView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pTreeView)), ((gtk_widget_get_type ()))))))
);
16588 return std::make_unique<GtkInstanceTreeView>(pTreeView, this, false);
16589 }
16590
16591 virtual std::unique_ptr<weld::IconView> weld_icon_view(const OString &id) override
16592 {
16593 GtkIconView* pIconView = GTK_ICON_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkIconView*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_icon_view_get_type
()))))))
;
16594 if (!pIconView)
16595 return nullptr;
16596 auto_add_parentless_widgets_to_container(GTK_WIDGET(pIconView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pIconView)), ((gtk_widget_get_type ()))))))
);
16597 return std::make_unique<GtkInstanceIconView>(pIconView, this, false);
16598 }
16599
16600 virtual std::unique_ptr<weld::EntryTreeView> weld_entry_tree_view(const OString& containerid, const OString& entryid, const OString& treeviewid) override
16601 {
16602 GtkContainer* pContainer = GTK_CONTAINER(gtk_builder_get_object(m_pBuilder, containerid.getStr()))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, containerid.getStr())
)), ((gtk_container_get_type ()))))))
;
16603 if (!pContainer)
16604 return nullptr;
16605 auto_add_parentless_widgets_to_container(GTK_WIDGET(pContainer)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pContainer)), ((gtk_widget_get_type ()))))))
);
16606 return std::make_unique<GtkInstanceEntryTreeView>(pContainer, this, false,
16607 weld_entry(entryid),
16608 weld_tree_view(treeviewid));
16609 }
16610
16611 virtual std::unique_ptr<weld::Label> weld_label(const OString &id) override
16612 {
16613 GtkLabel* pLabel = GTK_LABEL(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkLabel*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_label_get_type
()))))))
;
16614 if (!pLabel)
16615 return nullptr;
16616 auto_add_parentless_widgets_to_container(GTK_WIDGET(pLabel)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pLabel)), ((gtk_widget_get_type ()))))))
);
16617 return std::make_unique<GtkInstanceLabel>(pLabel, this, false);
16618 }
16619
16620 virtual std::unique_ptr<weld::TextView> weld_text_view(const OString &id) override
16621 {
16622 GtkTextView* pTextView = GTK_TEXT_VIEW(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkTextView*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_text_view_get_type
()))))))
;
16623 if (!pTextView)
16624 return nullptr;
16625 auto_add_parentless_widgets_to_container(GTK_WIDGET(pTextView)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pTextView)), ((gtk_widget_get_type ()))))))
);
16626 return std::make_unique<GtkInstanceTextView>(pTextView, this, false);
16627 }
16628
16629 virtual std::unique_ptr<weld::Expander> weld_expander(const OString &id) override
16630 {
16631 GtkExpander* pExpander = GTK_EXPANDER(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkExpander*) g_type_check_instance_cast ((GTypeInstance*
) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_expander_get_type
()))))))
;
16632 if (!pExpander)
16633 return nullptr;
16634 auto_add_parentless_widgets_to_container(GTK_WIDGET(pExpander)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pExpander)), ((gtk_widget_get_type ()))))))
);
16635 return std::make_unique<GtkInstanceExpander>(pExpander, this, false);
16636 }
16637
16638 virtual std::unique_ptr<weld::DrawingArea> weld_drawing_area(const OString &id, const a11yref& rA11y,
16639 FactoryFunction /*pUITestFactoryFunction*/, void* /*pUserData*/) override
16640 {
16641 GtkDrawingArea* pDrawingArea = GTK_DRAWING_AREA(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkDrawingArea*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_drawing_area_get_type
()))))))
;
16642 if (!pDrawingArea)
16643 return nullptr;
16644 auto_add_parentless_widgets_to_container(GTK_WIDGET(pDrawingArea)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pDrawingArea)), ((gtk_widget_get_type ()))))))
);
16645 return std::make_unique<GtkInstanceDrawingArea>(pDrawingArea, this, rA11y, false);
16646 }
16647
16648 virtual std::unique_ptr<weld::Menu> weld_menu(const OString &id) override
16649 {
16650 GtkMenu* pMenu = GTK_MENU(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkMenu*) g_type_check_instance_cast ((GTypeInstance*) ((
gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_menu_get_type
()))))))
;
16651 if (!pMenu)
16652 return nullptr;
16653 return std::make_unique<GtkInstanceMenu>(pMenu, true);
16654 }
16655
16656 virtual std::unique_ptr<weld::Toolbar> weld_toolbar(const OString &id) override
16657 {
16658 GtkToolbar* pToolbar = GTK_TOOLBAR(gtk_builder_get_object(m_pBuilder, id.getStr()))((((GtkToolbar*) g_type_check_instance_cast ((GTypeInstance*)
((gtk_builder_get_object(m_pBuilder, id.getStr()))), ((gtk_toolbar_get_type
()))))))
;
16659 if (!pToolbar)
16660 return nullptr;
16661 auto_add_parentless_widgets_to_container(GTK_WIDGET(pToolbar)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pToolbar)), ((gtk_widget_get_type ()))))))
);
16662 return std::make_unique<GtkInstanceToolbar>(pToolbar, this, false);
16663 }
16664
16665 virtual std::unique_ptr<weld::SizeGroup> create_size_group() override
16666 {
16667 return std::make_unique<GtkInstanceSizeGroup>();
16668 }
16669};
16670
16671}
16672
16673void GtkInstanceWindow::help()
16674{
16675 //show help for widget with keyboard focus
16676 GtkWidget* pWidget = gtk_window_get_focus(m_pWindow);
16677 if (!pWidget)
16678 pWidget = GTK_WIDGET(m_pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(m_pWindow)), ((gtk_widget_get_type ()))))))
;
16679 OString sHelpId = ::get_help_id(pWidget);
16680 while (sHelpId.isEmpty())
16681 {
16682 pWidget = gtk_widget_get_parent(pWidget);
16683 if (!pWidget)
16684 break;
16685 sHelpId = ::get_help_id(pWidget);
16686 }
16687 std::unique_ptr<weld::Widget> xTemp(pWidget != m_pWidget ? new GtkInstanceWidget(pWidget, m_pBuilder, false) : nullptr);
16688 weld::Widget* pSource = xTemp ? xTemp.get() : this;
16689 bool bRunNormalHelpRequest = !m_aHelpRequestHdl.IsSet() || m_aHelpRequestHdl.Call(*pSource);
16690 Help* pHelp = bRunNormalHelpRequest ? Application::GetHelp() : nullptr;
16691 if (!pHelp)
16692 return;
16693
16694 // tdf#126007, there's a nice fallback route for offline help where
16695 // the current page of a notebook will get checked when the help
16696 // button is pressed and there was no help for the dialog found.
16697 //
16698 // But for online help that route doesn't get taken, so bodge this here
16699 // by using the page help id if available and if the help button itself
16700 // was the original id
16701 if (m_pBuilder && sHelpId.endsWith("/help"))
16702 {
16703 OString sPageId = m_pBuilder->get_current_page_help_id();
16704 if (!sPageId.isEmpty())
16705 sHelpId = sPageId;
16706 else
16707 {
16708 // tdf#129068 likewise the help for the wrapping dialog is less
16709 // helpful than the help for the content area could be
16710 GtkContainer* pContainer = nullptr;
16711 if (GTK_IS_DIALOG(m_pWindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pWindow)); GType __t = ((gtk_dialog_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16712 pContainer = GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(m_pWindow)))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_dialog_get_content_area(((((GtkDialog*) g_type_check_instance_cast
((GTypeInstance*) ((m_pWindow)), ((gtk_dialog_get_type ())))
)))))), ((gtk_container_get_type ()))))))
;
16713 else if (GTK_IS_ASSISTANT(m_pWindow)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(m_pWindow)); GType __t = ((gtk_assistant_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
16714 {
16715 GtkAssistant* pAssistant = GTK_ASSISTANT(m_pWindow)((((GtkAssistant*) g_type_check_instance_cast ((GTypeInstance
*) ((m_pWindow)), ((gtk_assistant_get_type ()))))))
;
16716 pContainer = GTK_CONTAINER(gtk_assistant_get_nth_page(pAssistant, gtk_assistant_get_current_page(pAssistant)))((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_assistant_get_nth_page(pAssistant, gtk_assistant_get_current_page
(pAssistant)))), ((gtk_container_get_type ()))))))
;
16717 }
16718 if (pContainer)
16719 {
16720 GList* pChildren = gtk_container_get_children(pContainer);
16721 GList* pChild = g_list_first(pChildren);
16722 if (pChild)
16723 {
16724 GtkWidget* pContentWidget = static_cast<GtkWidget*>(pChild->data);
16725 sHelpId = ::get_help_id(pContentWidget);
16726 }
16727 g_list_free(pChildren);
16728 }
16729 }
16730 }
16731 pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))), pSource);
16732}
16733
16734//iterate upwards through the hierarchy from this widgets through its parents
16735//calling func with their helpid until func returns true or we run out of parents
16736void GtkInstanceWidget::help_hierarchy_foreach(const std::function<bool(const OString&)>& func)
16737{
16738 GtkWidget* pParent = m_pWidget;
16739 while ((pParent = gtk_widget_get_parent(pParent)))
16740 {
16741 if (func(::get_help_id(pParent)))
16742 return;
16743 }
16744}
16745
16746weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile)
16747{
16748 GtkInstanceWidget* pParentWidget = dynamic_cast<GtkInstanceWidget*>(pParent);
16749 if (pParent && !pParentWidget) //remove when complete
16750 return SalInstance::CreateBuilder(pParent, rUIRoot, rUIFile);
16751 GtkWidget* pBuilderParent = pParentWidget ? pParentWidget->getWidget() : nullptr;
16752 return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr);
16753}
16754
16755// tdf#135965 for the case of native widgets inside a GtkSalFrame and F1 pressed, run help
16756// on gtk widget help ids until we hit a vcl parent and then use vcl window help ids
16757gboolean GtkSalFrame::NativeWidgetHelpPressed(GtkAccelGroup*, GObject*, guint, GdkModifierType, gpointer pFrame)
16758{
16759 Help* pHelp = Application::GetHelp();
16760 if (!pHelp)
16761 return true;
16762
16763 GtkWindow* pWindow = static_cast<GtkWindow*>(pFrame);
16764
16765 vcl::Window* pChildWindow = nullptr;
16766
16767 //show help for widget with keyboard focus
16768 GtkWidget* pWidget = gtk_window_get_focus(pWindow);
16769 if (!pWidget)
16770 pWidget = GTK_WIDGET(pWindow)((((GtkWidget*) g_type_check_instance_cast ((GTypeInstance*) (
(pWindow)), ((gtk_widget_get_type ()))))))
;
16771 OString sHelpId = ::get_help_id(pWidget);
16772 while (sHelpId.isEmpty())
16773 {
16774 pWidget = gtk_widget_get_parent(pWidget);
16775 if (!pWidget)
16776 break;
16777 pChildWindow = static_cast<vcl::Window*>(g_object_get_data(G_OBJECT(pWidget)((((GObject*) g_type_check_instance_cast ((GTypeInstance*) ((
pWidget)), (((GType) ((20) << (2))))))))
, "InterimWindowGlue"));
16778 if (pChildWindow)
16779 {
16780 sHelpId = pChildWindow->GetHelpId();
16781 break;
16782 }
16783 sHelpId = ::get_help_id(pWidget);
16784 }
16785
16786 if (pChildWindow)
16787 {
16788 while (sHelpId.isEmpty())
16789 {
16790 pChildWindow = pChildWindow->GetParent();
16791 if (!pChildWindow)
16792 break;
16793 sHelpId = pChildWindow->GetHelpId();
16794 }
16795 if (!pChildWindow)
16796 return true;
16797 pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))), pChildWindow);
16798 return true;
16799 }
16800
16801 if (!pWidget)
16802 return true;
16803 std::unique_ptr<weld::Widget> xTemp(new GtkInstanceWidget(pWidget, nullptr, false));
16804 pHelp->Start(OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))), xTemp.get());
16805 return true;
16806}
16807
16808weld::Builder* GtkInstance::CreateInterimBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile,
16809 bool bAllowCycleFocusOut, sal_uInt64)
16810{
16811 // Create a foreign window which we know is a GtkGrid and make the native widgets a child of that, so we can
16812 // support GtkWidgets within a vcl::Window
16813 SystemWindowData winData = {};
16814 winData.bClipUsingNativeWidget = true;
16815 auto xEmbedWindow = VclPtr<SystemChildWindow>::Create(pParent, 0, &winData, false);
16816 xEmbedWindow->Show(true, ShowFlags::NoActivate);
16817 xEmbedWindow->set_expand(true);
16818
16819 const SystemEnvData* pEnvData = xEmbedWindow->GetSystemData();
16820 if (!pEnvData)
16821 return nullptr;
16822
16823 GtkWidget *pWindow = static_cast<GtkWidget*>(pEnvData->pWidget);
16824 gtk_widget_show_all(pWindow);
16825
16826 if (!bAllowCycleFocusOut)
16827 {
16828 GtkWidget* pTopLevel = gtk_widget_get_toplevel(pWindow);
16829 assert(pTopLevel)(static_cast <bool> (pTopLevel) ? void (0) : __assert_fail
("pTopLevel", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 16829, __extension__ __PRETTY_FUNCTION__))
;
16830 GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
16831 assert(pFrame)(static_cast <bool> (pFrame) ? void (0) : __assert_fail
("pFrame", "/home/maarten/src/libreoffice/core/vcl/unx/gtk3/gtk3gtkinst.cxx"
, 16831, __extension__ __PRETTY_FUNCTION__))
;
16832 // unhook handler and let gtk cycle its own way through this widget's
16833 // children because it has no non-gtk siblings
16834 pFrame->DisallowCycleFocusOut();
16835 }
16836
16837 // build the widget tree as a child of the GtkEventBox GtkGrid parent
16838 return new GtkInstanceBuilder(pWindow, rUIRoot, rUIFile, xEmbedWindow.get());
16839}
16840
16841weld::MessageDialog* GtkInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString &rPrimaryMessage)
16842{
16843 GtkInstanceWidget* pParentInstance = dynamic_cast<GtkInstanceWidget*>(pParent);
16844 GtkWindow* pParentWindow = pParentInstance ? pParentInstance->getWindow() : nullptr;
16845 GtkMessageDialog* pMessageDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL,((((GtkMessageDialog*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL, VclToGtk
(eMessageType), VclToGtk(eButtonsType), "%s", OUStringToOString
(rPrimaryMessage, (((rtl_TextEncoding) 76))).getStr()))), ((gtk_message_dialog_get_type
()))))))
16846 VclToGtk(eMessageType), VclToGtk(eButtonsType), "%s",((((GtkMessageDialog*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL, VclToGtk
(eMessageType), VclToGtk(eButtonsType), "%s", OUStringToOString
(rPrimaryMessage, (((rtl_TextEncoding) 76))).getStr()))), ((gtk_message_dialog_get_type
()))))))
16847 OUStringToOString(rPrimaryMessage, RTL_TEXTENCODING_UTF8).getStr()))((((GtkMessageDialog*) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_message_dialog_new(pParentWindow, GTK_DIALOG_MODAL, VclToGtk
(eMessageType), VclToGtk(eButtonsType), "%s", OUStringToOString
(rPrimaryMessage, (((rtl_TextEncoding) 76))).getStr()))), ((gtk_message_dialog_get_type
()))))))
;
16848 return new GtkInstanceMessageDialog(pMessageDialog, nullptr, true);
16849}
16850
16851weld::Window* GtkInstance::GetFrameWeld(const css::uno::Reference<css::awt::XWindow>& rWindow)
16852{
16853 if (SalGtkXWindow* pGtkXWindow = dynamic_cast<SalGtkXWindow*>(rWindow.get()))
16854 return pGtkXWindow->getFrameWeld();
16855 return SalInstance::GetFrameWeld(rWindow);
16856}
16857
16858weld::Window* GtkSalFrame::GetFrameWeld() const
16859{
16860 if (!m_xFrameWeld)
16861 m_xFrameWeld.reset(new GtkInstanceWindow(GTK_WINDOW(gtk_widget_get_toplevel(getWindow()))((((GtkWindow*) g_type_check_instance_cast ((GTypeInstance*) (
(gtk_widget_get_toplevel(getWindow()))), ((gtk_window_get_type
()))))))
, nullptr, false));
16862 return m_xFrameWeld.get();
16863}
16864
16865void* GtkInstance::CreateGStreamerSink(const SystemChildWindow *pWindow)
16866{
16867#if ENABLE_GSTREAMER_1_01
16868 auto aSymbol = gstElementFactoryNameSymbol();
16869 if (!aSymbol)
16870 return nullptr;
16871
16872 const SystemEnvData* pEnvData = pWindow->GetSystemData();
16873 if (!pEnvData)
16874 return nullptr;
16875
16876 GstElement* pVideosink = aSymbol("gtksink", "gtksink");
16877 if (!pVideosink)
16878 return nullptr;
16879
16880 GtkWidget *pGstWidget;
16881 g_object_get(pVideosink, "widget", &pGstWidget, nullptr);
16882 gtk_widget_set_vexpand(pGstWidget, true);
16883 gtk_widget_set_hexpand(pGstWidget, true);
16884
16885 GtkWidget *pParent = static_cast<GtkWidget*>(pEnvData->pWidget);
16886 gtk_container_add(GTK_CONTAINER(pParent)((((GtkContainer*) g_type_check_instance_cast ((GTypeInstance
*) ((pParent)), ((gtk_container_get_type ()))))))
, pGstWidget);
16887 g_object_unref(pGstWidget);
16888 gtk_widget_show_all(pParent);
16889
16890 return pVideosink;
16891#else
16892 (void)pWindow;
16893 return nullptr;
16894#endif
16895}
16896
16897/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
17
Taking true branch
206 aTmp->disposeOnce();
207 }
208 }
18
Calling '~Reference'
25
Returning from '~Reference'
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
8
Calling implicit copy constructor for 'VclPtr<AbstractScreenshotAnnotationDlg>'
9
Calling copy constructor for 'Reference<AbstractScreenshotAnnotationDlg>'
12
Returning from copy constructor for 'Reference<AbstractScreenshotAnnotationDlg>'
13
Returning from copy constructor for 'VclPtr<AbstractScreenshotAnnotationDlg>'
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
16
Calling 'VclPtr::disposeAndClear'
26
Returning; memory was released
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
27
'?' condition is true
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
10
Assuming field 'm_pBody' is non-null
11
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
18.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
18.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
18.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
18.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
)
19
Taking true branch
31
Taking true branch
113 m_pBody->release();
20
Calling 'VclReferenceBase::release'
24
Returning; memory was released
32
Use of memory after it is freed
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
21
Assuming the condition is true
22
Taking true branch
40 delete this;
23
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif