qmenumodel-0.10.0/AUTHORS 0000664 0000000 0000000 00000001022 15212610716 011672 0 ustar Albert Astals
Albert Astals Cid
Alberto Mardegan
Antti Kaijanmäki
Aurelien Jarno
Bill Filler
Charles Kerr
Dalton Durst
Florian Boucault
Florian Leeber
Gustavo Pichorim Boiko
Ivan Semkin
Jeremy Bícha
Lars Uebernickel
Luca Weiss
Lukáš Tinkl
Marco Trevisan (Treviño)
Marcus Tomlinson
Marius Gripsgard
Mathieu Trudel-Lapierre
Michael Terry
Michał Sawicz
Mike Gabriel
Mirco Müller
Nick Dedekind
Olivier Tilloy
OPNA2608
Pete Woods
Ratchanan Srirattanamet
Renato Araujo Oliveira Filho
Ricardo Mendoza
Robert Tari
Sergey Chupligin
qmenumodel-0.10.0/.build.yml 0000664 0000000 0000000 00000007031 15212610716 012530 0 ustar ##########################################################
# THE FOLLOWING LINES IS USED BY docker-build
##########################################################
requires:
# Useful URL: https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=qmenumodel
# FIXME: qmenumodel has not been packaged for Archlinux, yet.
archlinux:
- clang
- gcc
- git
- make
- startup-notification
- which
- cmake
- cmake-extras
- mate-common
# FIXME (Archlinux build requirements)
debian:
# Useful URL: https://salsa.debian.org/debian-ayatana-team/qmenumodel
- autopoint
- clang
- clang-tools
- g++
- cppcheck
- git
- cmake
- cmake-extras
- mate-common
- libglib2.0-dev
- qt5-qmake
- qtbase5-dev
- qtdeclarative5-dev
- python3
- python3-dbus
- python3-gi
- gir1.2-glib-2.0
- dbus-test-runner
- libgl-dev
ubuntu:
- autopoint
- clang
- clang-tools
- g++
- cppcheck
- git
- cmake
- cmake-extras
- mate-common
- libglib2.0-dev
- qt5-qmake
- qtbase5-dev
- qtdeclarative5-dev
- python3
- python3-dbus
- python3-gi
- gir1.2-glib-2.0
- dbus-test-runner
- libgl-dev
variables:
- 'CHECKERS="
-enable-checker deadcode.DeadStores
-enable-checker alpha.deadcode.UnreachableCode
-enable-checker alpha.core.CastSize
-enable-checker alpha.core.CastToStruct
-enable-checker alpha.core.IdenticalExpr
-enable-checker alpha.core.SizeofPtr
-enable-checker alpha.security.ArrayBoundV2
-enable-checker alpha.security.MallocOverflow
-enable-checker alpha.security.ReturnPtrRange
-enable-checker alpha.unix.SimpleStream
-enable-checker alpha.unix.cstring.BufferOverlap
-enable-checker alpha.unix.cstring.NotNullTerminated
-enable-checker alpha.unix.cstring.OutOfBounds
-enable-checker alpha.core.FixedAddr
-enable-checker security.insecureAPI.strcpy"'
build_scripts:
- if [ ${DISTRO_NAME} == "debian" ];then
- cppcheck --enable=warning,style,performance,portability,information,missingInclude .
- fi
-
- if [ -e ./autogen.sh ]; then
- NOCONFIGURE=1 ./autogen.sh
- scan-build $CHECKERS ./configure --prefix=/usr --enable-gtk-doc --enable-compile-warnings=maximum
- elif [ -e ./CMakeLists.txt ]; then
- if [ ${DISTRO_NAME} == "debian" ];then
- scan-build $CHECKERS cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_VERBOSE_MAKEFILE=ON -DENABLE_WERROR=ON -DENABLE_TESTS=ON
- else
- scan-build $CHECKERS cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_VERBOSE_MAKEFILE=ON -DENABLE_WERROR=ON
- fi
- else
- exit 1
- fi
-
- if [ $CPU_COUNT -gt 1 ]; then
- if [ ${DISTRO_NAME} == "debian" ];then
- scan-build $CHECKERS --keep-cc --use-cc=clang --use-c++=clang++ -o html-report make -j $CPU_COUNT
- make clean
- fi
- scan-build $CHECKERS --keep-cc -o html-report make -j $CPU_COUNT
- else
- if [ ${DISTRO_NAME} == "debian" ];then
- scan-build $CHECKERS --keep-cc --use-cc=clang --use-c++=clang++ -o html-report make
- make clean
- fi
- scan-build $CHECKERS --keep-cc -o html-report make
- fi
after_scripts:
- if [ ${BUILD_TYPE} == "scripts" ];then
- XVFB_RUN="$(which xvfb-run || true)"
- if [ ${DISTRO_NAME} == "debian" ];then
- if [ -e ./autogen.sh ]; then
- ${XVFB_RUN} make check
- elif [ -e ./CMakeLists.txt ]; then
- ${XVFB_RUN} make test
- fi
- fi
- fi
qmenumodel-0.10.0/ChangeLog 0000664 0000000 0000000 00000146570 15212610716 012416 0 ustar 2026-06-11 Mike Gabriel
* Release 0.10.0 (HEAD -> main, tag: 0.10.0)
* d/changelog: prepare release v0.10.0 (057eb26)
* d/rules: Enable unit tests for Qt 5 + Qt 6 (727a02d)
* debian/: Build Qt 6 variant alongside Qt 5 variant (3ab0271)
* libqmenumodel/src/CMakeLists.txt: Ship Qt 5 and Qt 6 includes in
different paths; eases packaging (2c34f4e)
* libqmenumodel/QMenuModel/CMakeLists.txt: Omit API version from
QMenuModel module name when building Qt 6 variant
(710e67e)
* libqmenumodel/: White-space fixes (d4dc874)
* .gitignore: Don't ignore files that stem from DEB packaging.
(0a00214)
* Merge branch 'OPNA2608-port-qt6' (d20734d)
2026-03-26 OPNA2608
* {libqmenumodel/src,tests/client}: Fix warnings with Qt6 (5f421cc)
* libqmenumodel/src: Fix build errors with Qt6 (07e7bde)
* treewide: Allow Qt6 build to be configured via CMake (f619b88)
2026-06-11 Mike Gabriel
* Revert "src/gtk Update gtk part to version 3.24.8" (f33cda5)
* Merge branch 'jbicha-personal/jbicha/increase-test-timeout'
(4fd46b9)
2024-11-02 Aurelien Jarno
* tests: Increase test timeout (c3f100c)
2026-06-11 Mike Gabriel
* Merge branch 'jbicha-personal/jbicha/debian-sync-20260403'
(187d02d)
2026-04-03 Jeremy Bícha
* debian: Sync with Debian (ed50241)
2023-08-24 Mike Gabriel
* Merge branch 'neochapay-update_gtk' (c8b25f7)
2022-06-14 Sergey Chupligin
* src/gtk Update gtk part to version 3.24.8 (ceaa2df)
2023-08-24 Mike Gabriel
* release 0.9.2 (017363f) (tag: 0.9.2)
2023-08-07 Mike Gabriel
* Merge branch 'tari01-pr/build-fixes' (b8050c4)
2023-08-01 Robert Tari
* Fix build errors (18ef013)
2023-07-12 Robert Tari
* Merge branch 'personal/peat-psuwit/uint16' (08289ff)
2023-06-15 Ratchanan Srirattanamet
* ayatanamenumodel: add support for {u,}int of all sizes (0defce2)
2022-02-08 Mike Gabriel
* Merge branch 'tari01-pr/fix-forced-coverage' (24cc4ee)
2022-02-06 Robert Tari
* tests/client/CMakeLists.txt: Only enable coverage reporting if the
flag is set for it (44e35e3)
2022-02-08 Mike Gabriel
* release 0.9.1 (2561e46) (tag: 0.9.1)
2022-02-08 Robert Tari
* .travis.yml: Run CI builds on Travis CI's Ubuntu focal base system
+ disable ppc64el builds (5e46aa7)
2022-02-01 Mike Gabriel
* Merge branch 'tari01-pr/cleanup-compile-flags' (45da057)
2022-01-13 Robert Tari
* .build.yml: Drop extra compilation flags and build with -Werror
(f441fab)
* CMakeLists.txt: Clean up compilation flags (59283b0)
* Fix all build warnings (d23a290)
2022-02-01 Mike Gabriel
* Merge branch 'correct-1-0' (7f5119f)
2021-12-23 Dalton Durst
* Make the qmltests test imports, at least (03a23b0)
* Fix build warning regarding qchar (fbb94cd)
* Fix naming of AyatanaMenuModel qml type (0333149)
* Fix versioning in examples and tests (02c973a)
2022-02-01 Mike Gabriel
* Merge branch 'tari01-pr/ayatana-style-cmake' (cc2c2d9)
2021-12-15 Robert Tari
* CMakeLists.txt: Rewrite and enable Ayatana-style options (8e228ca)
2021-12-14 Mike Gabriel
* release 0.9.0 (4c27ec6) (tag: 0.9.0)
* Merge branch 'tari01-pr/qml-1-0' (0924c28)
2021-12-08 Mike Gabriel
* debian/{control,*qmenumodel*}: Rename bin:pkg qmenumodel-qml to
qml-module-qmenumodel1 (reflecting the version bump _and_
becoming compliant to Debian's naming policy for QML
modules. (efb9bed)
2021-12-02 Robert Tari
* debian/qmenumodel-qml.install: Update QMenuModel name (a22b26b)
* Bump QMenuModel to 1.0 (8fda779)
2021-12-10 Robert Tari
* Fix CMake version and add required test packages (6abf908)
2021-12-08 Mike Gabriel
* Merge branch 'tari01-pr/fix-qt5-use-modules-warning' (66af742)
2021-12-07 Robert Tari
* Fix qt5_use_modules warning (af5a575)
2021-11-18 Mike Gabriel
* Merge branch 'tari01-pr/bump-std-version' (5b84c10)
2021-11-18 Robert Tari
* CMakeLists.txt: Stop enforcing C++11 standard. (621d577)
2021-11-18 Mike Gabriel
* Merge branch 'tari01-pr/bump-soversion' (a817c0d)
2021-11-18 Robert Tari
* debian/*: Update libqmenumodel0 to libqmenumodel1 (6a0f949)
* libqmenumodel/src/CMakeLists.txt: Bump the SOVERSION of
libqmenumodel (f7f503f)
* Merge branch 'sunweaver-pr/amend-version-in-pkgconfig-file'
(d9d7b02)
2021-11-18 Mike Gabriel
* libqmenumodel/src/qmenumodel.pc.in: Use @PROJECT_VERSION@ for
Version: field. (79516ac)
2021-11-17 Mike Gabriel
* Merge branch 'tari01-pr/rename-unity-symbols' (62a8b8b)
2021-11-16 Robert Tari
* Rename Unity* symbols (f4e75e1)
* Rename unity* source files (f803689)
2021-11-17 Mike Gabriel
* Merge branch 'tari01-pr/rename-canonical-properties' (8089cd5)
2021-11-15 Robert Tari
* Rename com.ubuntu.menu (0d2c880)
* examples/exportmenu.py: Rename x-canonical-currentvalue (a4f024e)
* examples/unityqmlmenumodel.qml: Rename
com.canonical.indicator.sound (f89d653)
* libqmenumodel/QMenuModel/plugin.h: Rename com.canonical.qmenumodel
(9e464fb)
* Rename com.canonical.test* (e728156)
2021-11-13 Robert Tari
* Rename com.canonical.unity.slider (7bb1253)
2021-10-24 Mike Gabriel
* release 0.8.1 (7f41ec3) (tag: 0.8.1)
2021-09-09 Robert Tari
* Merge branch 'sunweaver-pr/use-ayatana-indicators-dev-scripts'
(8df381c)
2021-08-29 Mike Gabriel
* debian/{control,compat}: Bump to level 10. (dec144a)
* debian/rules: Enable unit tests. (55d51db)
* debian/{control,compat}: Bump to level 10. (2aec4a4)
* debian/rules: Enable unit tests. (47cac22)
2021-08-28 Mike Gabriel
* .travis.yml: Use Ayatana Indicators project's dev-scripts repo.
(5e12d85)
2021-06-11 Mike Gabriel
* debian/control: Ignore missing B-D bin:pkg 'qt5-default'. It has
been dropped during the Debian bullseye release cycle.
(fb58fcc)
2021-05-17 Mike Gabriel
* Merge branch 'z3ntu-glib' (ddcccb4)
2021-04-04 Luca Weiss
* Move glib includes outside of extern "C" (a6d79e8)
2021-05-17 Robert Tari
* Merge branch 'sunweaver-pr/travis-ci' (792a56d)
2021-05-12 Mike Gabriel
* Travis CI: Initial draft for CI builds. (184eb5c)
2020-08-18 Mike Gabriel
* release 0.8.0 (095e205) (tag: 0.8.0)
2020-08-15 Marius Gripsgard
* Merge branch 'sunweaver-pr/move-over-to-ayatana-indicators'
(566e0e1)
2020-08-15 Mike Gabriel
* CMakeLists.txt: Introduce shipping PROJECT_VERSION in upstream code
(not just in debian/changelog, which gets removed during
tarball creation). (2361b98)
* Move over qmenumodel into the Ayatana Indicators project, upstream
version bump preparation. (8954090)
* debian/control: Add myself to Uploaders: field. (617c181)
* Merge branch 'ayatana-type' (a05e8b1)
2020-08-15 Marius Gripsgard
* Support ayatana type (fa430b5)
* Use CoverageReport from cmake-extras (a17ce34)
* Correct debian control file (3c9b1ce)
* Cleanup bzr (0e71197)
* Merge branch 'xenial_-_patches' of
https://github.com/z3ntu/qmenumodel (e21000a)
2020-05-18 Luca Weiss
* Remove use of the deprecated QModelIndex::child function (b420ba1)
* Add missing header (bca9dd3)
2018-07-27 Florian Leeber
* Merge pull request #2 from vanyasem/master (30e3dc5)
2018-06-20 Ivan Semkin
* Fix build with Qt 5.11_beta3 (dropping qt5_use_modules) (276a033)
2017-12-27 Marius Gripsgard
* Build for xenial and bump version (f236743)
* Add Jenkinsfile (3463ebe)
2017-04-04 Bileto Bot
* Releasing 0.2.12+17.04.20170404-0ubuntu1 (760d505)
2017-04-04 Albert Astals Cid
* Add a return true (05133b2)
2017-04-03 Albert Astals Cid
* Add a return true (0fd82be)
2017-03-16 Bileto Bot
* Releasing 0.2.12+17.04.20170316.1-0ubuntu1 (42ba9cd)
2017-03-16 Albert Astals Cid
* Use submenu-enabled for those items that don't have an action (if
it exists) (LP: #1670694) (1e6ebcc)
2017-03-16 Bileto Bot
* Add UnityMenuModel::aboutToShow ((LP: 1664578) (f0aa8c3)
2017-03-16 Albert Astals Cid
* Batch add and removes into the model (e2b335b)
* 0 -> G_MAXINT as found by Charles (5c4aae1)
* Fix c&p, this ref should be unref (4216eb7)
* Review improvements (8c08013)
2017-03-08 Albert Astals Cid
* Use submenu-enabled for those items that don't have an action (if
it exists) (c4855ff)
2017-03-07 Albert Astals Cid
* Increase version because of new api (4e10e84)
2017-03-06 Albert Astals Cid
* Call about to show for those items that have a qtubuntu-tag
property (7579572)
2017-02-28 Albert Astals Cid
* valign (9058e74)
* Batch add and removes into the model (87ea781)
2017-01-10 Bileto Bot
* Releasing 0.2.11+17.04.20170110.1-0ubuntu1 (2eaa36e)
* Added shortcut hasSubmenu and roles to UnityMenuModel; Added
actions property to Group (ab9f997)
2016-12-09 Nick Dedekind
* added to changelog (a9c7379)
* fixed version file (6be5a58)
* merged with trunk (69093dc)
2016-11-16 Bileto Bot
* Releasing 0.2.10+17.04.20161116-0ubuntu1 (89f2b36)
2016-11-16 Marco Trevisan (Treviño)
* converter: cleanup and add support for more variant types (9884a79)
2016-11-16 Florian Boucault
* Crossbuilding fixes. (9d914ff)
2016-10-26 Bileto Bot
* Releasing 0.2.10+17.04.20161026.2-0ubuntu1 (24f649f)
* Add ability to activate or change state of an action by variant
string (662f263)
2016-10-26 Marco Trevisan (Treviño)
* converterTest: add content conversions back and further from
gvariant (352a770)
* converter: properly set the QByteArray using ctor, or it will be
created twice (210cae9)
* converterTest: add conversion to GVariant and back to verify
content is correct (e1ee47e)
2016-10-25 Marco Trevisan (Treviño)
* converter: return a variant when the schema is a variant (d56d0ba)
* converter: verify integer type conversions (eb6e5b5)
* converter: free schema type on destruction (fc52f84)
* converter: free the strv container (edfe13a)
* Merged variant-string-parser into converter-improvements. (64a2113)
2016-10-25 Lukáš Tinkl
* converter: use qUtf8Printable function (64ac22d)
2016-10-25 Marco Trevisan (Treviño)
* UnityMenuModel: avoid copy on assignment (0d1bfd6)
* UnityMenuModel: use conversion with gschema in unity actions
(307efb4)
* converterTest: simplify metatype definitions (a4c1bb6)
* Converter: add support to String Arrays (6d2076c)
* Merging with lp:~3v1n0/qmenumodel/variant-string-parser (d25887f)
* ConverterTest: add checks for tuples and lists (c314929)
2016-10-24 Marco Trevisan (Treviño)
* Add conversion tests for maps and lists to QVariant (3509321)
* converterTest: add tests for toQVariantFromVariantString (3bcc60f)
* convertertest: add tests for converting to QVariant (abc65a4)
* converterTest: QVERIFY comparison return value (7f78a2c)
2016-10-22 Marco Trevisan (Treviño)
* remove deprecated g_type_init() calls (3d2c260)
* ConverterTest: remove C++11 features for now (3897067)
* convertertest: create QGVariantType wrapper to avoid
reinterperating a QString (4b495fc)
* convertertest: repeat tests using test data (00ddb5f)
* ConverterTest: use data in the testSchemaConvert (81e73a2)
2016-10-20 Marco Trevisan (Treviño)
* ActionGroupTest: add test for activateByVariantString (6d2a0aa)
* ActionGroupTest: split tests depending on they need the helper
script or not (bba640d)
2016-10-18 Marco Trevisan (Treviño)
* converter: stop looking if w'eve no entryType (901e9dc)
* Converter: use builders and c++ facilities for schema conversions
(3def677)
* Converter: use some c++11 facilities for lists (3bd198e)
* ConverterTest: add QVariantList conversion test (d8aa881)
* convertertest: add conversion from map to qvariant check (d3899e6)
* Converter: use QMetaType to check integer subtypes (36681ba)
* Converter: add support for ByteArrayList (c42bc21)
* Converter: add bytestring support (e87701e)
* ConverterTest: add tests for toQVariant (3edd18d)
* convertertest: use better variant map test (894fbb9)
* CMakeLists.txt: we can safely use c++11 here (c3b6823)
* QStateAction: add ability to activate or change state by variant
string (06687a7)
* Converter: move parseVariantString here from UnityMenuModel
(1adf4a6)
2016-10-17 Marco Trevisan (Treviño)
* convertertest: add tests for [U]LongLong converters (c998da0)
* converterTest: split tests by type (f52b497)
2016-10-15 Marco Trevisan (Treviño)
* UnityMenuModel: avoid initializing an empty QVariant if not needed
(33b7533)
2016-10-14 Marco Trevisan (Treviño)
* UnityMenuModel: avoid copying the string to a new std one (462b842)
* debian/changelog: bump version number (edc354a)
* UnityMenuModel add support for activating and changing state with a
variant string parameter (1e9cf63)
* Converter: add support to LongLong and ULongLong (449ac3d)
2016-10-04 Nick Dedekind
* version bump (a618ff5)
* better boolean check (388be5b)
2016-07-19 Florian Boucault
* Crossbuilding fixes. (c6bba62)
2016-03-29 CI Train Bot
* Releasing 0.2.9+16.04.20160329-0ubuntu1 (9efd410)
2016-03-29 Nick Dedekind
* Use Qt logging categories
Fixes: #1562992 Approved by: Daniel
d'Andrada, PS Jenkins bot (f2b1959)
2016-03-29 Michał Sawicz
* Sync gcc 5.1 rebuild version Approved by: PS Jenkins bot (2e795a2)
2016-02-23 Nick Dedekind
* only log critical (4ad6055)
* added missing file (2bf6347)
2016-02-19 Nick Dedekind
* use logging categories (2291dec)
2016-01-15 Nick Dedekind
* Added roles for submenu & shortcut. Added actions (97b75c9)
2015-12-14 Michał Sawicz
* Sync gcc 5.1 rebuild (df7955d)
2015-09-08 Nick Dedekind
* accelerators (523db87)
2015-04-30 CI Train Bot
* Releasing 0.2.9+15.04.20150430-0ubuntu1 (e6e4bab)
2015-04-30 Michael Terry
* Don't leave a dangling GVariant pointer in GtkMenuTrackerItem,
which can cause a crash. (3e5d807)
* Fix crash from not NULLing a variant that we later might try to
unref (1933513)
2015-01-08 CI Train Bot
* Releasing 0.2.9+15.04.20150108-0ubuntu1 (19e4949)
2015-01-08 Nick Dedekind
* Add support for overriding QDBusActionGroup state parser
Fixes:
#1385331 Approved by: PS Jenkins bot, Albert Astals Cid
(79ef5bc)
2014-12-10 Nick Dedekind
* added comment (7dc65fd)
2014-11-11 Nick Dedekind
* bump version (f1b1f9a)
* Allow override of action state parser (0ca199d)
2014-10-13 CI bot
* Releasing 0.2.8+14.10.20141013-0ubuntu1 (f3a203b)
2014-10-13 Nick Dedekind
* Disconnect QDBusActionGroup add/remove/stateChange signals when
deleting object.
Fixes: 1378941 Approved by: Charles Kerr,
Michael Sheldon, PS Jenkins bot, Lars Uebernickel
(e0ee0a8)
2014-10-10 Nick Dedekind
* disconnect on clear (ec1e10b)
2014-08-15 CI bot
* Releasing 0.2.8+14.10.20140815-0ubuntu1 (49d7bf9)
2014-08-15 Nick Dedekind
* Allow remote URIs to be used from file serialized icons Approved
by: Sergio Schvezov, PS Jenkins bot (8f2a49c)
2014-07-29 Nick Dedekind
* remove check for native file (eac47df)
2014-07-17 CI bot
* Releasing 0.2.8+14.10.20140717-0ubuntu1 (d9a59c0)
2014-07-17 Lars Uebernickel
* unitymenumodel: add nameOwner property
Fixes: 1308011 Approved by:
Mirco Müller, PS Jenkins bot (f7719ce)
2014-07-15 Lars Uebernickel
* Update changelog (166406a)
2014-07-11 Lars Uebernickel
* unitymenumodel: add nameOwner property (35c2996)
* unitymenumodel: notify when the bus name changes (7be80e6)
2014-07-04 CI bot
* Releasing 0.2.7+14.10.20140704-0ubuntu1 (018eaeb)
2014-07-04 Nick Dedekind
* Unset the UnityMenuActions::model when destroying UnityMenuModel
Fixes: 1334203 (2ec6160)
2014-07-04 Charles Kerr
* Fix a dangling UnityMenuAction pointer by ensuring it's registered
with only one menu at a time.
Fixes: 1282282 (d83588e)
2014-07-01 Nick Dedekind
* fixed copywrite (4f4fde0)
* added missing file (99e2882)
2014-06-30 Nick Dedekind
* unset actions model in destructor (6d8d26d)
2014-05-14 CI bot
* Releasing 0.2.7+14.10.20140514.1-0ubuntu1 (c7955b4)
2014-05-14 Antti Kaijanmäki
* Add standard "has the property actually changed" check to
UnityMenuModel::setBusName() (b927a95)
2014-05-08 Antti Kaijanmäki
* wrap the changelog entry. (802224f)
* try to fix debian/changelog for the ci train.. (20eb438)
* manually merge debian/changelog after a manual upload to the
archive. (26a791f)
2014-04-02 Antti Kaijanmäki
* Add standard "has the property actually changed" check to
UnityMenuModel::setBusName() (bc008a3)
* revert the last commit. (112eb60)
* UnityMenuModel::setName: handle empty strings properly. (5809d6f)
2014-03-16 Charles Kerr
* when an action's model changes in UnityMenuAction::setModel(), make
sure the action unregisters itself from the previous
model. (0b31bc9)
2014-03-05 CI bot
* Releasing 0.2.7+14.04.20140305-0ubuntu1 (94aac07)
* No change rebuild against Qt 5.2.1. (f8a07da)
2014-02-28 Albert Astals
* Fix use of un-initialized memory (788ebe3)
* Fix use of un-initialized memory (7b70ef5)
2013-12-13 Automatic PS uploader
* Releasing 0.2.7+14.04.20131213-0ubuntu1 (revision 99 from
lp:qmenumodel). (24aa85f)
* Releasing 0.2.7+14.04.20131213-0ubuntu1, based on r99 (09b0f46)
2013-12-11 Nick Dedekind
* Added dataChange to loadExtendedAttributes function. (9530a3d)
* Added data change to loadExtAttributes (81b68c9)
2013-11-25 Automatic PS uploader
* Releasing 0.2.7+14.04.20131125-0ubuntu1 (revision 97 from
lp:qmenumodel). (c40c4c2)
* Releasing 0.2.7+14.04.20131125-0ubuntu1, based on r97 (27b7d20)
2013-11-21 Marcus Tomlinson
* Fixed #define guard. (12111d2)
2013-11-06 Marcus Tomlinson
* Fixed #define guard (7332db6)
2013-10-16 Automatic PS uploader
* Releasing 0.2.7+13.10.20131016-0ubuntu1 (revision 95 from
lp:qmenumodel). (25e6667)
* Releasing 0.2.7+13.10.20131016-0ubuntu1, based on r95 (cf34565)
2013-10-15 Nick Dedekind
* Added pointer checks for items/iterators. (lp#1239394).
Fixes:
https://bugs.launchpad.net/bugs/1239394. (52d2141)
2013-10-14 Nick Dedekind
* removed unnecessary pointer checks (c50f57f)
* Added iterator/item pointer checks (e7bfaf1)
2013-10-11 Gustavo Pichorim Boiko
* Use g_file_get_uri instead of g_file_get_path to make sure the
URI's percent encoding is properly kept. (867693a)
* Use g_file_get_uri instead of g_file_get_path to make sure the
URI's percent encoding is properly kept. (fa2526b)
2013-10-11 Automatic PS uploader
* Releasing 0.2.7+13.10.20131011-0ubuntu1 (revision 92 from
lp:qmenumodel). (5ac03ca)
* Releasing 0.2.7+13.10.20131011-0ubuntu1, based on r92 (e47e13a)
2013-10-01 Lars Uebernickel
* QStateAction: try to maintain the type of the action's state
(5f66f59)
2013-09-23 Lars Uebernickel
* QStateAction: try to maintain the type of the action's state
(74a9ba6)
2013-09-20 Automatic PS uploader
* Releasing 0.2.7+13.10.20130920-0ubuntu1 (revision 90 from
lp:qmenumodel). (23dee12)
* Releasing 0.2.7+13.10.20130920-0ubuntu1, based on r90 (61b9ea6)
2013-09-18 Pete Woods
* Fix memory leak in unitymenumodel (b6f00b9)
2013-09-17 Pete Woods
* Fix sequence memory leak in unitymenumodel (9b9504f)
2013-09-13 Automatic PS uploader
* Releasing 0.2.7+13.10.20130913-0ubuntu1 (revision 88 from
lp:qmenumodel). (81648d3)
* Releasing 0.2.7+13.10.20130913-0ubuntu1, based on r88 (d0d6d56)
2013-09-09 Mathieu Trudel-Lapierre
* Add changelog for manual upload of 0.2.7+13.10.20130830-0ubuntu2.
(958d147)
* upload version 0.2.7+13.10.20130830-0ubuntu2 (71b514b)
2013-09-04 Lars Uebernickel
* Use fully namespaced action name in UnityMenuModel::activate and
for the action role. (ce35aa4)
2013-09-03 Lars Uebernickel
* fullActioName: make sure 'name' is valid for the duration of the
function (e01b6b5)
* Add UnityMenuAction::index property (9365885)
2013-09-02 Lars Uebernickel
* Add UnityMenuModel::getAction (2641328)
* UnityMenuModel::activate: use gtk_menu_tracker_item_get_action_name
(f58b7c7)
* gtk_menu_tracker_item_get_action_name: return full name, including
namespace (fa058d5)
2013-08-30 Automatic PS uploader
* Releasing 0.2.7+13.10.20130830-0ubuntu1 (revision 85 from
lp:qmenumodel). (28a4548)
* Releasing 0.2.7+13.10.20130830-0ubuntu1, based on r85 (279b43c)
2013-08-30 Nick Dedekind
* Added UnityMenuAction for "out-of-menu" actions. (db40e84)
2013-08-29 Automatic PS uploader
* Releasing 0.2.7+13.10.20130829.1-0ubuntu1 (revision 83 from
lp:qmenumodel). (751f4fb)
* Releasing 0.2.7+13.10.20130829.1-0ubuntu1, based on r83 (f43d10f)
2013-08-29 Lars Uebernickel
* Remove theme image provider (9acfda5)
2013-08-29 Nick Dedekind
* Let Qt manage the destruction of child ActionStateParsers.
(7d013d7)
* Let Qt manage deletion of children (2eeecef)
2013-08-28 Automatic PS uploader
* Releasing 0.2.7+13.10.20130828.2-0ubuntu1 (revision 80 from
lp:qmenumodel). (64ab9df)
* Releasing 0.2.7+13.10.20130828.2-0ubuntu1, based on r80 (a601032)
2013-08-27 Lars Uebernickel
* Make sure the right qt modules are loaded to make QMenuModel tests
pass.
Fixes: https://bugs.launchpad.net/bugs/1217335.
(4f91a49)
2013-08-27 Automatic PS uploader
* Releasing 0.2.7+13.10.20130827.3-0ubuntu1 (revision 78 from
lp:qmenumodel). (68e010e)
2013-08-27 Nick Dedekind
* merged with trunk (8cc3f9a)
* Review comments (ebace67)
2013-08-27 Lars Uebernickel
* Make sure the right qt modules are loaded to make QMenuModel tests
pass (31bdaf0)
2013-08-27 Automatic PS uploader
* Releasing 0.2.7+13.10.20130827.3-0ubuntu1, based on r78 (298bf61)
2013-08-26 Automatic PS uploader
* Releasing 0.2.7+13.10.20130826-0ubuntu1 (revision 75 from
lp:qmenumodel). (8977be5)
2013-08-26 Nick Dedekind
* Adds qt event spawning to direct glib main loop callbacks.
Fixes:
https://bugs.launchpad.net/bugs/1183065,
https://bugs.launchpad.net/bugs/1206991. (aaa8252)
* UnityMenuModel::changeState now uses current state parameter type
as a base for parameter GVariant conversion. (50563a1)
2013-08-26 Automatic PS uploader
* Releasing 0.2.7+13.10.20130826-0ubuntu1, based on r75 (8a3c8c9)
2013-08-26 Nick Dedekind
* Added int64 & variant types to UnityMenuModel ext attribute
parsing. (346f5fc)
2013-08-22 Nick Dedekind
* removed newline (d23d848)
* Added copywrite headers (9ed4538)
* Using qt event loop to pass UnityMenuAction events (c274656)
2013-08-22 Lars Uebernickel
* Remove theme image provider (1439420)
2013-08-22 Nick Dedekind
* Added activate/changeState to UnityMenuModel (d912a0a)
2013-08-21 Nick Dedekind
* Added UnityMenuAction for out-of-line actions. Action muxer copied
to submenus. (72cd124)
2013-08-20 Nick Dedekind
* new unitymenumodel attribute types (d83555e)
2013-08-15 Nick Dedekind
* Added toGVariantWithSchema for UnityMenuModel::changeState
(67394e4)
2013-08-13 Automatic PS uploader
* Releasing 0.2.7+13.10.20130813-0ubuntu1 (revision 73 from
lp:qmenumodel). (bac9f37)
* Releasing 0.2.7+13.10.20130813-0ubuntu1, based on r73 (f26e80d)
2013-08-13 Nick Dedekind
* Release version 0.2.7. (1e14a68)
* version bump (5111d99)
* Removed UnityMenuAction. (a89cb05)
2013-08-12 Automatic PS uploader
* Releasing 0.2.6+13.10.20130812-0ubuntu1 (revision 70 from
lp:qmenumodel). (2713de8)
2013-08-12 Nick Dedekind
* Removed UnityMenuAction. Fixed leaks from unitymenumodel. (3caade3)
2013-08-12 Automatic PS uploader
* Releasing 0.2.6+13.10.20130812-0ubuntu1, based on r70 (9d4e931)
2013-08-12 Nick Dedekind
* Added UnityMenuModel. (d6085f8)
2013-08-12 Lars Uebernickel
* Add isToggled role (94a0809)
2013-08-12 Nick Dedekind
* Use qevents to send between direct glib loop events and qt.
(6914a54)
* use correct qvariant types for sensitive and isSeparator roles
(3ded9bb)
2013-08-12 Lars Uebernickel
* Expose isCheck and isRadio roles (6bd9b68)
2013-08-09 Nick Dedekind
* use correct qvariant types for sensitive and isSeparator roles
(6251412)
2013-08-09 Lars Uebernickel
* Add parameter to unitymenumodel.action.activate (4e1a260)
* Re-add UnityMenuModel::activate() (08a5bb3)
2013-08-09 Nick Dedekind
* glib callbacks pass events through qt. (2bbdf4e)
* moved events to separate file. (db47d07)
* bit of code cleanup (9be2951)
2013-08-08 Nick Dedekind
* Glib callbacks send events through qt. (c6cb726)
2013-08-05 Mirco Müller
* Fix exporting of boolean extended-attribute in
attributeToQVariant() (73223bd)
2013-08-05 Nick Dedekind
* Allow changing action state (248ae8d)
2013-08-01 Mirco Müller
* Fix exporting of boolean extended-attribute in
attributeToQVariant() (c458dff)
2013-07-31 Nick Dedekind
* removed debug code (27e7c3b)
2013-07-30 Nick Dedekind
* Added menu action updateState (37e6246)
* Added action name (56374f1)
* merged with parent (559df4b)
* Add action role (replacing actionState role) (d1c96de)
* merged with trunk (c796dd5)
2013-07-30 Lars Uebernickel
* Set model qdata on items instead of the muxer (d47194b)
2013-07-30 Nick Dedekind
* Add ActionStateParser (01d57d8)
* unitymenumodel: lookup themed icon before turning it into a uri
(ed4b694)
2013-07-26 Lars Uebernickel
* unitymenumodel: add get() (16b480d)
* Expose the state of a menu item's action in model.actionState
(d57caa6)
2013-07-25 Lars Uebernickel
* Fix crash in UnityMenuModel::menuItemChanged (58afcb8)
* examples/unityqmlmenumodel.qml: add license header (57f5b07)
* examples/unitymenumodel.qml: update to newest API (192e9c8)
* unitymenumodel: expose type and extended attributes to qml
(ca81974)
2013-06-25 Lars Uebernickel
* unitymenumodel: add support for icons (6aaafd5)
2013-06-24 Lars Uebernickel
* Remove unityqmlmenumodel (050958c)
* unitymenumodel: allow setting multiple prefixed action groups
(3dd6f65)
* unitymenumodel: set free func on GSequence (1bc2427)
* unitymenumodel: use g_clear_object (7b06205)
* unitymenumodel: remove forSubMenu (edad406)
* unitymenumodel: move role enum into .cpp (f59e06e)
* unitymenumodel: remove redundant priv functions (a74628a)
* Move unityqmlmenumodel's properties to unitymenumodel (bf4e73f)
2013-06-07 Automatic PS uploader
* Releasing 0.2.6daily13.06.07-0ubuntu1 to ubuntu. (52b1700)
* Releasing 0.2.6daily13.06.07-0ubuntu1, based on r68 (a251896)
2013-06-06 Alberto Mardegan
* Use invalid index as root index (2c5855c)
2013-06-05 Lars Uebernickel
* unitymenumodel: call init in the the constructor that is meant to
be used from c++ (45ffd91)
* unitymenumodel: add support for submenus (7892fd9)
* unitymenumodel: add activate() (e735d95)
* Link against the qml module (692926c)
2013-06-04 Lars Uebernickel
* unitymenumodel: expose isSeparator (00885c1)
* examples/exportmenu.py: use g_bus_own_name to avoid race (2a01b1c)
* unitymenumodel: watch the bus name (9f9560d)
* Add qml example for UnityMenuModel (b1009a8)
* CMakeLists.txt: explicitly specify qml include path (5503064)
* Introduce UnityMenuModel and UnityQmlMenuModel (4fc790c)
2013-05-23 Alberto Mardegan
* style (8157af2)
2013-05-20 Alberto Mardegan
* Use invalid index as root index (c5bcb29)
2013-05-03 Automatic PS uploader
* Releasing 0.2.6daily13.05.02-0ubuntu1 to ubuntu. (885710f)
2013-05-02 Automatic PS uploader
* Releasing 0.2.6daily13.05.02-0ubuntu1, based on r66 (cfcd397)
2013-04-23 Mathieu Trudel-Lapierre
* Don't build on powerpc (qtdeclarative5 isn't available there).
(2701b12)
* Don't build binary packages on powerpc; qtdeclarative5 isn't
available; so explicitly list the architectures we can
build on. (47deee0)
2013-04-19 Mathieu Trudel-Lapierre
* Bootstrap package. (4a5edf4)
* fix revision for bootstap (964f03e)
* bootstrap (31ddbce)
2013-03-29 Mathieu Trudel-Lapierre
* Packaging review for daily release. (10d7da0)
2013-03-26 Mathieu Trudel-Lapierre
* - Add Homepage field. - Extend binary packages descriptions.
(43f8630)
* Move libgl-dev as an alternate Build-Depends to libgles2-mesa-dev.
(3a59b8d)
2013-03-25 Mathieu Trudel-Lapierre
* debian/control: - Add Vcs-Browser, add comment to developers.
- Update Vcs-Bzr.; debian/rules: - Override dh_install
to use --fail-missing.; debian/copyright: should be
LGPL-3, not LGPL-3+. (09c56ca)
2013-02-11 Renato Araujo Oliveira Filho
* Added missing file (COPYING.LGPL); Updated debian maintaine.
Update debian scripts to follow Ubuntu standard;.
Fixes:
https://bugs.launchpad.net/bugs/1121721. (46f476e)
* Added missing key ¨Vcs-Bzr" in control file. (f1d16e8)
* Fixed COPYING.LGPL file to use LGPL 3 (0e00948)
* Added missing file . (f6d4f68)
* Added missing file ".bzr-builddeb/default.conf¨ (eb7de53)
* Fixed variable export in rules file. (b0127d3)
* Fixed source format. (8deae77)
* Added missing file (COPYING.LGPL); Updated debian maintaine.
Update debian scripts to follow Ubuntu standard; (0a72006)
2013-01-31 Renato Araujo Oliveira Filho
* releasing version 0.2.6. (54bb804)
* Updated to qt5 final. (095aed4)
* Added missing dependency. (08e25df)
* Used qmake to retrieve the import dir used to install QML modules.
(e5b89ef)
* Fixed extra '/' in the file path. (101c523)
* Fixed missing license header. (b9bbb75)
* Fixed files missing license header. (5a4ff7a)
* releasing version 0.2.6 (35305e3)
2013-01-18 Renato Araujo Oliveira Filho
* Updated to qt5 final. (5234489)
2013-01-15 Renato Araujo Oliveira Filho
* releasing version 0.2.5. (954e6e6)
2013-01-14 Renato Araujo Oliveira Filho
* Fixed changelog. (ba32c60)
2013-01-15 Renato Araujo Oliveira Filho
* Fixed "invokeMethod" call to use only the method name instead of
full signature. (f72cdbb)
2013-01-14 Renato Araujo Oliveira Filho
* releasing version 0.2.5 (9a4f675)
* Fixed "invokeMethod" call to use only the method name instead of
full signature. (f177b47)
* releasing version 0.2.4. (073cbc4)
* releasing version 0.2.4 (aa7a055)
* Implemented QMenuModel as tree model. Sections and SubMenus are
exported as tree.
Fixes:
https://bugs.launchpad.net/bugs/1090305. (c53b046)
* Used 'invokeMethod' to call slot, to make the code simple.
(00bd7d4)
2013-01-11 Renato Araujo Oliveira Filho
* Merged mainline. (6a56cd8)
* Added missing license header.
Fixes:
https://bugs.launchpad.net/bugs/1097080. (84b4e66)
* Added missing license header. (50efc4d)
* Merged mainline. (0115b56)
* Removed the use of Qt Widgets from tests. (774f7c4)
2013-01-10 Renato Araujo Oliveira Filho
* Fixed item removal and insertion. Removed debug messages. Fixed
tests to work with new tree model structure. (33147e9)
2013-01-03 Renato Araujo Oliveira Filho
* Implmeneted QMenuModel as tree model. (2d050cd)
2012-12-17 Renato Araujo Oliveira Filho
* releasing version 0.2.3. (70adf10)
* releasing version 0.2.3 (7002fc2)
* Try to keep the module unchanged until the function
begin[Insert|Remove]Rows is called.
Fixes:
https://bugs.launchpad.net/bugs/1090305. (df3cd0c)
* Added missing test. (c34c5af)
2012-12-16 Renato Araujo Oliveira Filho
* Fixed model changes and singal. (64e7281)
2012-12-15 Renato Araujo Oliveira Filho
* Removed keywords from VIRTUAL functions. (b601ff7)
2012-12-14 Renato Araujo Oliveira Filho
* Only checks for row index in cache. Used Q_EMIT keywork for
signals. (96a4d9c)
* Avoid change rowCount value outside of
BeginModel[Insert|Remove|Reset] functions (9b94a0f)
2012-12-12 Bill Filler
* fix release number and formatting. (c7cd7a4)
2012-12-11 Bill Filler
* releasing version 0.2.2 (83a2418)
2012-12-11 Renato Araujo Oliveira Filho
* Fixed model disconnect function.
Fixes:
https://bugs.launchpad.net/bugs/1088518. (4b2c268)
* Fixed model disconnect function. Set the model null during the
disconnection will make sure that the model was cleared
and the new call of connect will populate the model again.
(edbfcdf)
* Avoid emit signal during the model reset, this can crash qml.
(0f20cc0)
* Avoid emit signal during the model reset, this can crash qml.
(d4ce0d4)
* Fixed crash during model changes. (b9e5fb6)
* Fixed crash during model changes. (0b3bfd9)
2012-12-10 Renato Araujo Oliveira Filho
* releasing version 0.2.1. (5c88419)
* releasing version 0.2.1 (3f548e8)
2012-12-07 Renato Araujo Oliveira Filho
* Implemented conversion for GVariant and Arrays. (afd68a3)
* Implemented conversion for GVariant and Arrays. (e8b1e40)
2012-12-04 Olivier Tilloy
* releasing version 0.2. (94f07ed)
* releasing version 0.2 (cf798a4)
* Cache sub-menus. (c544a5f)
* Better comment. (ac9450d)
* Add myself to the list of authors. (f9ced66)
* Add comments to explain non-trivial cache updates. (395a8c6)
* Add a test to verify that normal menu items are not cached (only
sub-menus are). (02cfba5)
* Add a test to verify that the cache is correctly updated after
multiple insertions and removals. (e8927d8)
* Updated comments. (bf8e579)
* Compare the exact cache indexes instead of just comparing the size
of the cache. (50d449d)
* Simplify test code. (af2608a)
* Remove useless include. (4b57869)
* Add myself to the list of authors. (517c21c)
* Make the cache a pointer, to enforce const correctness. (7b2badf)
2012-12-03 Olivier Tilloy
* Simplify the caching mechanism using a a QHash that associates
indexes (int) to QMenuModel*. (2f32994)
2012-12-03 Renato Araujo Oliveira Filho
* Udated ignored files list. (d39a6e1)
* Changed getLink function to not be const. (5c52963)
2012-12-01 Renato Araujo Oliveira Filho
* QMenuModel now keeps cache of any link element. (15ac92c)
2012-11-29 Renato Araujo Oliveira Filho
* releasing version 0.1.9. (6eb5409)
* releasing version 0.1.9 (85c41ee)
* Created auxiliary functions. To allows access the model data from
JavaScript;. (49810b9)
* Used a shorter QObject::connect signature. (b3ac378)
2012-11-28 Renato Araujo Oliveira Filho
* Created unit test for get data function. (08b143c)
* Optimized get function code. (236259b)
* Merged mainline. (98ed17e)
2012-11-23 Renato Araujo Oliveira Filho
* releasing version 0.1.8. (da5a043)
* releasing version 0.1.8 (8d9b6dc)
* Fixed QMenumodel behavior when the GMenuModel is destroyed.
(68533d0)
* Removed missing function declaration. (bdc349d)
* Take care of object ref internally on QMenumodel, instead of
QDBusMenuModel. (aa56c7b)
* Replaced 'reinterpret_cast' for gobject cast when possible.
(af103eb)
* Removed QAction dependency from QStateAction. Exported activate
function on QStateAction. (7cfd1a4)
* Merged mainline. (f68764a)
* Fixed QMenumodel behaviour when the GMenuModel is destroyed.
(6078bd7)
* Create unit test for name property and activate function. (5d755f4)
* Added 'TEST_XML_OUTPUT' option on cmake to enable/disalbe test
output in xml. OBS: The default value is On. (de8eea6)
* Implemented support to tuple conversions. (374e999)
* Fixed code style. (2b54bfb)
2012-11-22 Renato Araujo Oliveira Filho
* Added docs on new functions. (41f6ce5)
* Only unref variant if its is valid. (193ddd3)
* Implemented support to tuple conversions. (c377489)
* Added 'TEST_XML_OUTPUT' option on cmake to enable/disalbe test
output in xml. OBS: The default value is On. (560f14f)
* Removed QAction dependecy from QStateAction. Exported activate
function on QStateAction. (a745160)
* Fixed memory leak after the service disappear. (04391e9)
* Avoid find children recursive during the model cleanup. (a8dec79)
* Moved model children clear to clearModel function. (f221fee)
2012-11-21 Renato Araujo Oliveira Filho
* Fixed memory leak after the service disapear. (af61347)
2012-11-20 Olivier Tilloy
* Reimplement roleNames() instead of using setRoleNames(…). (3dec94a)
2012-11-19 Olivier Tilloy
* Reimplement roleNames() instead of using setRoleNames(…). (5d33dd5)
2012-11-15 Olivier Tilloy
* releasing version 0.1.7. (1430572)
2012-11-14 Olivier Tilloy
* releasing version 0.1.7 (368a2e2)
2012-11-13 Renato Araujo Oliveira Filho
* Created auxiliary functions. To allows access the model data from
JavaScript; (53dfc2a)
2012-11-08 Renato Araujo Oliveira Filho
* Updates to get coverage and test results in jenkins. (1915b09)
2012-11-07 Renato Araujo Oliveira Filho
* Merged 'lp:~renatofilho/girden/debian-dh'. (67680f3)
* Merged mainline. (e6cddf7)
* Make the rule 'make check' always enabled. (664f162)
* Appended auto generated xml test output files into ignored list.
(9dd5954)
* Updated README file with the new coverage flag. (6b8fd9e)
* Updated debian package to use debhelper instead of cdbs. (fc58dd6)
* Merged 'lp:~renatofilho/girden/debian-dh' branch. (987dd97)
* Merged mainline. (cba9178)
* Updated tests make file to outpu xml results files. (79c1256)
2012-11-06 Renato Araujo Oliveira Filho
* Fixed string comparation on cmake files. (21a8952)
* Skip tests on qemu to avoid crashes. (dd3e64c)
* Removed 'xvfb' from the dependency list. (a086f90)
2012-11-02 Renato Araujo Oliveira Filho
* Fixed tests to avoid crashing if dbus session is not available.
(28245a5)
* Fixed tests code to avoid crash if dbus session is not avaliable.
(59dfda6)
2012-11-01 Renato Araujo Oliveira Filho
* Uses "QT_QPA_PLATFORM=minimal" to run qt tests. (8432596)
2012-10-31 Olivier Tilloy
* releasing version 0.1.6. (2e6ccdb)
* releasing version 0.1.6 (cf0b1b6)
2012-10-31 Renato Araujo Oliveira Filho
* Rename coverage option name. (50600e1)
* Updated dependency list to use python3 packages. (bf5a53e)
* Added missing python dependencies. (abd20be)
* Merged mainline. (c9c9d58)
* Revert last commit. (4aee0f1)
* Reverted use of xvfb for tests. (Does not work with opengl)
(7f4ba1a)
* Removed QtTestGui include from tests. (b4e04e3)
* Added xvfb option on cmake to enable run tests without X running.
(49797fd)
* Added missing opengl dependency. Necessary for examples. (07087af)
* Removed show widgets functions to avoid problems in the auto
builder. (485cab8)
* Added 'dbus-test-runner' ad build dependency. (89f52ae)
2012-10-31 Olivier Tilloy
* Migrate all the scripts to python3. (521a582)
2012-10-31 Renato Araujo Oliveira Filho
* Updated rules to avoid warnings during the package build. (bed4cab)
* Fixed control file to accept any python3 version. (7ee5b38)
* Updated debian package to use debhelper instead of cdbs. (d7ae33e)
2012-10-30 Renato Araujo Oliveira Filho
* Use the correct function "g_action_group_change_action_state" to
change the action state. (e26fff2)
* Used utf8 instead of latin1 for strings. (fac3a65)
2012-10-30 Olivier Tilloy
* Merge the latest changes from trunk. (0ad7c83)
* Migrate all scripts to python3. (209c95e)
2012-10-30 Renato Araujo Oliveira Filho
* Replaced gchar <-> QString convertion function, from Latin1 to
Utf8. (035b608)
* Created function actionActivate on QDbusActionGroup. (fd715d4)
* Use the correct function "g_action_group_change_action_state" to
change the action state. (2496687)
* Created unit test for utf8 strings. (307b793)
* Replaced string convertion from Latin1 to Utf8. (ed490f2)
2012-10-25 Renato Araujo Oliveira Filho
* Changed the 'g_bus_watch_name' flag to auto start the service;.
Approved by PS Jenkins bot, Olivier Tilloy. (4d47b26)
2012-10-24 Renato Araujo Oliveira Filho
* Changed the 'g_bus_watch_name' flag to auto start the servic.
(3c1b2d2)
2012-10-18 Olivier Tilloy
* releasing version 0.1.5 (fef978e)
* Add missing changelog entry. (fe42b80)
2012-10-17 Renato Araujo Oliveira Filho
* Implemented conversion for QVariantMap; Created unit test for
QVariantMap conversion;. Approved by Olivier Tilloy, PS
Jenkins bot. (d46ee24)
* Used utf8 instead of latin1 on QString conversion; (cdd910c)
* Used 'G_VARIANT_TYPE_VARDICT' in GVariantBuilder constructor.
(c805b48)
2012-10-16 Renato Araujo Oliveira Filho
* Merged mainline. (cc79785)
2012-10-16 Olivier Tilloy
* releasing version 0.1.4 (ced307a)
2012-10-16 Renato Araujo Oliveira Filho
* Avoid emit model reset during QMenuModel destructor, to avoid crash
in QML engine.. Approved by Olivier Tilloy, PS Jenkins
bot, jenkins. (340e67d)
2012-10-15 Renato Araujo Oliveira Filho
* Created unit test for QVariantMap conversion; (a98d548)
* Implemented conversion for QVariantMap; (7f09723)
* Merged mainline. (5c56d12)
2012-10-15 Olivier Tilloy
* Expose a C++ library, and separate into 3 binary packages: -
libqmenumodel0: C++ library - libqmenumodel-dev:
development headers for the C++ library - qmenumodel-qml:
QML module. Approved by Renato Araujo Oliveira Filho,
jenkins. (5999e7a)
* Merge the latest changes from trunk. (4366f70)
2012-10-11 Renato Araujo Oliveira Filho
* Merged mainline. (e243399)
2012-10-11 Ricardo Mendoza
* Rebuild for armhf. Approved by Florian Boucault, jenkins. (46b559b)
2012-10-11 Renato Araujo Oliveira Filho
* Added new generated test files into bzrignore. (99229ab)
* Created unit test for crash during model destruction. (9bf1472)
2012-10-11 Ricardo Mendoza
* Rebuild for armhf (ef7435e)
* Bump version to propagate release to the corresponding PPAs.
Approved by Florian Boucault. (0f71225)
* Bump version for Release (bcd640b)
2012-10-11 Renato Araujo Oliveira Filho
* Added comments on qml file used in tests. (f430d60)
2012-10-11 Olivier Tilloy
* Updated the TODO list: upon Renato’s suggestion, it would be
interesting to add a ProjectConfig.cmake file. (f04b692)
* Merge the latest changes from trunk. (6504ccc)
2012-10-10 Renato Araujo Oliveira Filho
* Fixed typo in function name. (7c27fad)
* Clenup qml file, removed debug messages and unused code. (5dd33f3)
* Created a new private function "clearModel" instead of change
signature of "setModel" function. (1e659ae)
2012-10-10 Olivier Tilloy
* Avoid including C headers (glib/gio) in public headers; use
"forward declarations" instead.. Approved by Renato Araujo
Oliveira Filho, jenkins. (24faac7)
* Revert to using g* types, and forward-declare them. This is more
future-proof. (92ee9e3)
2012-10-09 Olivier Tilloy
* Reset the navigation history when the connection to the model is
lost.. Approved by Renato Araujo Oliveira Filho, jenkins.
(f8266c8)
2012-10-09 Renato Araujo Oliveira Filho
* Fixed crash during model destruction in QML. (c07f87e)
2012-10-09 Olivier Tilloy
* Avoid including C headers (glib/gio) in public headers; use
"forward declarations" instead. (bced31c)
* Reset the navigation history when the connection to the model is
lost. (f5e0285)
* Add a changelog entry to explain the split into 3 binary packages.
(a3c6400)
* Add a C++ example that demonstrates the use of libqmenumodel.
(69538ac)
* Update TODO list. (35dfc73)
* Add a missing Pre-Depends field to the control file. Fixes a
lintian error. (b3dc371)
* Ensure dh_makeshlibs ignores the QML module. Fixes an error and two
warnings in lintian. (b81741d)
* Add extended descriptions for all packages. Fixes lintian errors.
(3ba2b41)
2012-10-08 Olivier Tilloy
* Split the package into 3 packages: libqmenumodel0,
libqmenumodel-dev, qmenumodel-qml. (93c81bd)
* Ensure the model is set before advertising the status as
'Connected'. (d2ec653)
* Use the Q_EMIT keyword to emit signals. (bc7eb61)
* Ensure libqmenumodel is linked against libglib and libgio.
(07c3252)
* Call g_type_init() in the constructor for QDBusObject. This ensures
it is always called where needed: clients don’t need to
invoke it themselves. (fa5d7c1)
* Cosmetics: remove trailing spaces. (a7852ea)
* Add a pkgconfig file for developers. (0186c4a)
* Install the shared library and dev headers. (1fec6fd)
* Make libqmenumodel a shared library. (2ebcae8)
2012-10-05 Olivier Tilloy
* Port to Qt5. (a03e7e7)
* Tweaks to the structure of the code, and added example code..
Approved by Renato Araujo Oliveira Filho, jenkins.
(c3fbab2)
* Fixed some deprecation warnings when generating the API
documentation. (900b75e)
* Fix coverage to ignore all moc files. (2956675)
* Use the automoc feature to simplify a lot the build system.
(82677d0)
* Fix packaging for Qt5. (8c51550)
* Port to Qt5. (81dbf09)
* Fix source dir for documentation generation. (696fba5)
2012-10-04 Olivier Tilloy
* Fix variant conversion on 32-bits platforms. (5fb1863)
* Renamed source package to 'qmenumodel', and removed useless build
dependencies. (795bf87)
* Updated ignore rules. (5292d53)
* Updated ignore rules. (c81ecae)
* Do not install under "Ubuntu" prefix. (9fab6d5)
* Ignore clicks on menu items that do not have a submenu. (957046e)
* Updated TODO list. (8e65ebb)
* Updated examples/README to reflect name changes. (3fbfb27)
* Rename the source directories. (36cebbb)
* Add a TODO file. (62d2c4b)
* Fixed some #include statements. (1e045bb)
* Add instructions. (7a410b5)
* Minor doc fixes. (af778cf)
* Merged back doc fixes from Renato. (4385dad)
2012-10-04 Renato Araujo Oliveira Filho
* Created doc source dir. (7961150)
2012-10-04 Olivier Tilloy
* Replace #include statements with forward declarations in
converter.h. (e14ab1e)
* Remove useless code from the Converter namespace. (ba89bb2)
* Add examples. (445945d)
* Remove a leftover dependency. (37dd625)
* Removed leftover examples infrastructure. (244ec05)
* Fix a typo. (c2d5761)
* Move the enums into a class that inherits QObject, so they can be
exposed and used directly from QML. (36426c5)
* Fix signal parameter type, unaccessible in QMl otherwise. (a9416eb)
* Fix a typo. (facb9bf)
* Remove the implementation of columnCount. According to the
documentation
(http://doc.qt.digia.com/stable/model-view-programming.html#model-subclassing-reference),
« List models do not provide this function because it is
already implemented in QAbstractListModel. » (57b1e3f)
* Fix a typo. (90bd3a7)
* Updated ignore rules. (63c4e47)
2012-10-02 Olivier Tilloy
* Add ignore rules. (0ce83ea)
2012-09-14 Renato Araujo Oliveira Filho
* Fixed action state initialization. (759356c)
* Created function to convert from QVariant to GVariant. Moved
QStateAction controler from QACtionGroup. (ebe349e)
* Renamed Converter::parseGVariant. (2b9cf16)
2012-09-13 Renato Araujo Oliveira Filho
* Appended comments on unit test. Added 'valid' property in
QStateAction. (7dec723)
* Created class QStateAction to use as GAction proxy. (a03360c)
2012-09-12 Renato Araujo Oliveira Filho
* Parse extra properties name to remove 'x-' and replace '-' to '_'.
(d2e99cf)
* Removed invalid examples. (48e027e)
* Created debian directory. (d09eaad)
* Created unit test for QDBusActionGroup. (9a62817)
* Added QML documentation. (a3aa532)
2012-09-11 Renato Araujo Oliveira Filho
* Append the default licence header into source files. (638bcc9)
* Splitted qmenumodel plugin in two libraries to make it testable.
Create unit test for qmenumodel library. (6bacc0d)
2012-09-06 Renato Araujo Oliveira Filho
* Implemented QDBusActionGroup. (31f8103)
2012-09-05 Renato Araujo Oliveira Filho
* Initial import. (0dfd3d4)
qmenumodel-0.10.0/CMakeLists.txt 0000664 0000000 0000000 00000004747 15212610716 013403 0 ustar cmake_minimum_required (VERSION 3.13)
project (qmenumodel VERSION 0.10.0)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
SET(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "..." FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
# Options
option(ENABLE_QT6 "Enable building with Qt6" OFF)
option(ENABLE_TESTS "Enable all tests and checks" OFF)
option(ENABLE_COVERAGE "Enable coverage reports (includes enabling all tests and checks)" OFF)
option(ENABLE_WERROR "Treat all build warnings as errors" OFF)
option(TEST_XML_OUTPUT "Print test results to xml files" OFF)
option(GENERATE_DOC "Enable qdoc generation" OFF)
set(QT_VERSION_MAJOR 5)
set(QMENUMODEL_LIB_SUFFIX)
set(QMENUMODEL_PKGCONFIG_SUFFIX)
if(ENABLE_QT6)
set(QT_VERSION_MAJOR 6)
string(APPEND QMENUMODEL_LIB_SUFFIX "-qt6")
string(APPEND QMENUMODEL_PKGCONFIG_SUFFIX "-qt6")
endif()
if(ENABLE_COVERAGE)
set(ENABLE_TESTS ON)
set(CMAKE_BUILD_TYPE "Coverage")
else()
set(CMAKE_BUILD_TYPE "Release")
endif()
if(ENABLE_TESTS)
set(TEST_XML_OUTPUT ON)
endif()
if(ENABLE_WERROR)
add_definitions("-Werror")
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions("-Weverything")
else()
add_definitions("-Wall")
endif()
# Standard install paths
include(GNUInstallDirs)
find_package(QT NAMES Qt${QT_VERSION_MAJOR})
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui Qml Quick)
include(FindPkgConfig)
pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_definitions(-DQT_NO_KEYWORDS)
add_subdirectory(libqmenumodel)
# Tests
if (ENABLE_TESTS)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus Test Widgets)
find_program(DBUS_RUNNER dbus-test-runner REQUIRED)
enable_testing()
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
message(STATUS "Current version of qemu crashes during the tests. We will skip it for now.")
set(ENABLE_TESTS OFF)
set(ENABLE_COVERAGE OFF)
set(TEST_XML_OUTPUT OFF)
else()
add_subdirectory(tests)
endif()
endif()
# Doc
if(GENERATE_DOC)
find_program(QDOC_BIN qdoc REQUIRED)
add_subdirectory(doc)
endif()
# Display config info
message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
message(STATUS "Unit tests: ${ENABLE_TESTS}")
message(STATUS "Build with -Werror: ${ENABLE_WERROR}")
message(STATUS "Print test results to xml files: ${TEST_XML_OUTPUT}")
message(STATUS "QDoc generation: ${GENERATE_DOC}")
qmenumodel-0.10.0/COPYING.LGPL 0000664 0000000 0000000 00000016743 15212610716 012432 0 ustar GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
qmenumodel-0.10.0/doc/CMakeLists.txt 0000664 0000000 0000000 00000000640 15212610716 014134 0 ustar set(QMENUMODEL_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/qmenumodel.qdocconf)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/qmenumodel.qdocconf.in"
${QMENUMODEL_DOC_FILE} @ONLY)
add_custom_target(qdoc)
add_custom_command(TARGET qdoc
COMMAND ${QDOC_BIN} ${QMENUMODEL_DOC_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "QDoc running...")
qmenumodel-0.10.0/doc/qmenumodel.qdocconf.in 0000664 0000000 0000000 00000000335 15212610716 015666 0 ustar project = QMenuModel QML elements
sourcedirs = @src_SOURCE_DIR@
sources.fileextensions = "*.cpp"
outputdir = html
outputformats = HTML
version = 0.1
syntaxhighlighting = true
sourceencoding = UTF-8
outputencoding = UTF-8
qmenumodel-0.10.0/examples/ayatanaqmlmenumodel.qml 0000664 0000000 0000000 00000007174 15212610716 017227 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors: Lars Uebernickel
*/
import QtQuick 2.0
import QMenuModel 1.0
Item {
width: 400;
height: 500;
AyatanaMenuModel {
id: menu
busName: "org.ayatana.indicator.sound"
actions: { "indicator": "/org/ayatana/indicator/sound" }
menuObjectPath: "/org/ayatana/indicator/sound/desktop"
}
ListView {
id: listview
anchors.fill: parent
anchors.margins: 10
spacing: 3
model: menu
delegate: Loader {
sourceComponent: {
if (isSeparator) {
return separator;
}
else if (type == "org.ayatana.indicator.slider") {
listview.model.loadExtendedAttributes(index, {'min-icon': 'icon',
'max-icon': 'icon'});
return slider;
}
else {
return menuitem;
}
}
Component {
id: separator
Rectangle {
width: listview.width
height: 4
color: "blue"
}
}
Component {
id: slider
Rectangle {
width: listview.width
color: "#ddd"
height: 40
Row {
anchors.fill: parent
Image {
source: ext.minIcon
}
Text {
text: model.actionState
}
Image {
source: ext.maxIcon
}
}
}
}
Component {
id: menuitem
Rectangle {
width: listview.width
height: 40
color: "#ddd"
Row {
anchors.fill: parent
anchors.margins: 5
Image {
source: icon
}
Text {
height: parent.height
verticalAlignment: Text.AlignVCenter
color: sensitive ? "black" : "#aaa";
text: label
}
}
MouseArea {
anchors.fill: parent
onClicked: {
var submenu = listview.model.submenu(index);
if (submenu)
listview.model = submenu;
else
action.activate();
}
}
}
}
}
}
}
qmenumodel-0.10.0/examples/CMakeLists.txt 0000664 0000000 0000000 00000001604 15212610716 015206 0 ustar # Standalone CMakeLists.txt to generate the info-menumodel executable.
# This is not built as part of libqmenumodel, it has to be built separately
# and it assumes libqmenumodel-dev is installed on the system.
cmake_minimum_required(VERSION 2.8.9)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
option(ENABLE_QT6 "Enable building with Qt6" OFF)
set(QT_VERSION_MAJOR 5)
set(QMENUMODEL_PKGCONFIG_SUFFIX)
if(ENABLE_QT6)
set(QT_VERSION_MAJOR 6)
string(APPEND QMENUMODEL_PKGCONFIG_SUFFIX "-qt6")
endif()
find_package(QT NAMES Qt${QT_VERSION_MAJOR})
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
include(FindPkgConfig)
pkg_check_modules(QMENUMODEL REQUIRED qmenumodel${QMENUMODEL_PKGCONFIG_SUFFIX})
add_executable(info-menumodel info-menumodel.cpp)
include_directories(${QMENUMODEL_INCLUDE_DIRS})
target_link_libraries(info-menumodel ${QMENUMODEL_LDFLAGS} Qt::Core)
qmenumodel-0.10.0/examples/exportactiongroup.py 0000775 0000000 0000000 00000005012 15212610716 016614 0 ustar #!/usr/bin/env python3
# -*- encoding: utf-8 -*-
#
# Copyright 2013 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
"""
This example script exports an action group on the session bus under the name
org.ayatana.testactiongroup and at the object path
/org/ayatana/testactiongroup.
"""
import sys
from gi.repository import Gio
from gi.repository import GLib
BUS_NAME = 'org.ayatana.testactiongroup'
BUS_OBJECT_PATH = '/org/ayatana/testactiongroup'
def action_activated(action, data):
name = action.get_name()
if action.get_state_type() is None:
print('stateless action activated: %s' % name)
else:
print('stateful action activated: %s (current state: %s)' %
(name, action.get_state()))
if __name__ == '__main__':
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
# Claim well-known bus name and ensure only one instance of self is running
# at any given time.
# http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-names
proxy = Gio.DBusProxy.new_sync(bus, 0, None,
'org.freedesktop.DBus',
'/org/freedesktop/DBus',
'org.freedesktop.DBus', None)
result = proxy.RequestName('(su)', BUS_NAME, 0x4)
if result != 1 :
print >> sys.stderr, ("Name '%s' is already owned on the session bus."
"Aborting.") % BUS_NAME
sys.exit(1)
group = Gio.SimpleActionGroup()
foo = Gio.SimpleAction.new('foo', None)
group.insert(foo)
bar = Gio.SimpleAction.new_stateful('bar', None, GLib.Variant.new_boolean(False))
group.insert(bar)
bleh = Gio.SimpleAction.new_stateful('bleh', None, GLib.Variant.new_string('bleh'))
group.insert(bleh)
for name in group.list_actions():
action = group.lookup_action(name)
action.connect('activate', action_activated)
bus.export_action_group(BUS_OBJECT_PATH, group)
GLib.MainLoop().run()
qmenumodel-0.10.0/examples/exportmenu.py 0000775 0000000 0000000 00000005001 15212610716 015224 0 ustar #!/usr/bin/env python3
# -*- encoding: utf-8 -*-
#
# Copyright 2013 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
"""
This example script exports a menu model on the session bus under the name
org.ayatana.testmenu and at the object path /org/ayatana/testmenu.
The menu model contains items that have attributes with custom values, as well
as sub-menus.
"""
import sys
from gi.repository import Gio
from gi.repository import GLib
BUS_NAME = 'org.ayatana.testmenu'
BUS_OBJECT_PATH = '/org/ayatana/testmenu'
def bus_acquired(bus, name):
menu = Gio.Menu()
foo = Gio.MenuItem.new('foo', 'app.foo')
foo.set_attribute_value('x-additionaltext',
GLib.Variant.new_string('lorem ipsum'))
foo.set_attribute_value('x-enabled', GLib.Variant.new_boolean(True))
menu.append_item(foo)
bar = Gio.MenuItem.new('bar', 'bar')
bar.set_attribute_value('x-defaultvalue',
GLib.Variant.new_string('Hello World!'))
bar.set_attribute_value('x-ayatana-currentvalue',
GLib.Variant.new_string('awesome'))
bar.set_attribute_value('x-velocity', GLib.Variant.new_uint64(83374))
menu.append_item(bar)
menu.append('bleh', 'app.bleh')
submenu = Gio.Menu()
submenu.append('submenu A', 'app.suba')
submenu2 = Gio.Menu()
submenu2.append('submenu2 A', 'app.sub2a')
submenu2.append('submenu2 B', 'app.sub2b')
submenu2.append('submenu2 C', 'app.sub2c')
submenu.append_submenu('submenu submenu', submenu2)
submenu.append('submenu C', 'app.subc')
menu.append_submenu('submenu', submenu)
menu.append('baz', 'app.baz')
bus.export_menu_model(BUS_OBJECT_PATH, menu)
actions = Gio.SimpleActionGroup.new()
actions.add_action(Gio.SimpleAction.new("bar", None))
bus.export_action_group(BUS_OBJECT_PATH, actions)
if __name__ == '__main__':
Gio.bus_own_name(Gio.BusType.SESSION, BUS_NAME, 0, bus_acquired, None, None)
GLib.MainLoop().run()
qmenumodel-0.10.0/examples/info-menumodel.cpp 0000664 0000000 0000000 00000006345 15212610716 016077 0 ustar /*
* Copyright 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Olivier Tilloy
*/
/*
* Example executable that links against libqmenumodel to monitor
* and print information about a menu model exported on D-Bus.
*/
// QMenuModel
#include "qmenumodel/qdbusmenumodel.h"
// stdlib
#include
// Qt
#include
#include
#define BUS_NAME "org.ayatana.testmenu"
#define BUS_OBJECT_PATH "/org/ayatana/testmenu"
class MenuModelMonitor : public QDBusMenuModel
{
Q_OBJECT
public:
MenuModelMonitor(QObject* parent=0)
: QDBusMenuModel(parent)
{
setProperty("busType", DBusEnums::SessionBus);
setProperty("busName", BUS_NAME);
setProperty("objectPath", BUS_OBJECT_PATH);
QObject::connect(this, SIGNAL(statusChanged(DBusEnums::ConnectionStatus)),
SLOT(onStatusChanged(DBusEnums::ConnectionStatus)));
QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
SLOT(onModelChanged()));
QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
SLOT(onModelChanged()));
std::cout << "Monitoring menu model "
<< property("objectPath").toString().toUtf8().constData()
<< " on the well-known name "
<< property("busName").toString().toUtf8().constData()
<< std::endl;
}
private Q_SLOTS:
void onStatusChanged(DBusEnums::ConnectionStatus status)
{
std::cout << "Status of menu model changed to " << status << std::endl;
if (status == DBusEnums::Connected) {
printModel(this);
}
}
void onModelChanged()
{
printModel(this);
}
private:
void printModel(QMenuModel* model, int indent=0)
{
int count = model->rowCount();
for (int i = 0; i < count; ++i) {
QModelIndex index = model->index(i, 0);
QString label = model->data(index, QMenuModel::Label).toString();
QVariant submenu = model->data(index, QMenuModel::LinkSubMenu);
for (int j = 0; j < indent * 2; ++j) std::cout << " ";
std::cout << " > " << label.toUtf8().constData() << std::endl;
if (submenu.isValid()) {
printModel(qobject_cast(submenu.value()), indent + 1);
}
}
}
};
#include "info-menumodel.moc"
int main(int argc, char** argv)
{
MenuModelMonitor monitor;
monitor.start();
int result = QCoreApplication(argc, argv).exec();
monitor.stop();
return result;
}
qmenumodel-0.10.0/examples/README 0000664 0000000 0000000 00000001426 15212610716 013330 0 ustar This directory contains examples that demonstrate how to use the QMenuModel
binding in Qt and QML applications.
To export an example menu model on the bus, run 'exportmenu.py'.
To render this menu in a QML application, run 'render-menumodel.qml' in
qmlscene. You will need to inform qmlscene of the location of the QMenuModel
plugin if it’s not installed system-wide, e.g.:
$ qmlscene -I libqmenumodel examples/render-menumodel.qml
To compile a C++ executable that uses libqmenumodel to monitor and print
information about the exported menu, run `cmake` and then `make` from this
directory. This assumes that libqmenumodel-dev is installed on the system
(it won’t work with a local copy). Then, run the executable generated:
$ cmake .
$ make
$ ./info-menumodel
qmenumodel-0.10.0/examples/render-menumodel.qml 0000664 0000000 0000000 00000011526 15212610716 016427 0 ustar /*
* Copyright 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Olivier Tilloy
*/
// This example QML application renders a menu model exposed on the session bus
// under the well-known name org.ayatana.testmenu and at the object path
// /org/ayatana/testmenu.
import QtQuick 2.0
import QMenuModel 1.0
Item {
id: container
width: 300
height: 300
QDBusMenuModel {
id: menuModel
busType: DBus.SessionBus
busName: "org.ayatana.testmenu"
objectPath: "/org/ayatana/testmenu"
onStatusChanged: {
if (status == DBus.Connecting) {
view.reset()
}
}
}
ListView {
id: view
property variant __back: []
anchors.left: parent.left
anchors.right:parent.right
anchors.top: parent.top
anchors.bottom: backbutton.top
anchors.margins: 10
spacing: 3
model: menuModel
delegate: Rectangle {
width: parent.width
height: 30
radius: 3
color: {
if (linkSubMenu == null) return "lightgrey"
if (delegatearea.containsMouse) return "steelblue"
return "lightsteelblue"
}
Text {
anchors.fill: parent
anchors.margins: 5
verticalAlignment: Text.AlignVCenter
color: (linkSubMenu == null) ? "grey" : "black"
text: {
if (linkSubMenu == null) return "%1 (%2)".arg(label).arg(action)
else return "submenu"
}
}
MouseArea {
id: delegatearea
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (linkSubMenu == null) return
var newback = view.__back
newback.push(view.model)
view.__back = newback
view.model = linkSubMenu
}
onEntered: {
var text = ""
for (var prop in extra) {
text += "%1 = %2\n".arg(prop).arg(extra[prop].toString())
}
if (text != "") {
tooltip.text = text
tooltip.visible = true
}
}
onExited: {
tooltip.visible = false
}
onPositionChanged: {
var pos = container.mapFromItem(delegatearea, mouse.x, mouse.y)
tooltip.x = pos.x + 10
tooltip.y = pos.y + 10
}
}
}
function goback() {
var newback = view.__back
model = newback[newback.length - 1]
newback.pop()
view.__back = newback
}
function reset() {
while (view.__back.length > 0) {
goback()
}
}
}
Rectangle {
id: backbutton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 5
radius: 4
height: 50
color: (mousearea.enabled && mousearea.containsMouse) ? "steelblue" : "lightsteelblue"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "back"
color: mousearea.enabled ? "black" : "grey"
}
MouseArea {
id: mousearea
anchors.fill: parent
enabled: view.__back.length > 0
hoverEnabled: true
onClicked: {
view.goback()
}
}
}
Rectangle {
id: tooltip
property alias text: t.text
visible: false
width: t.width + 10
height: t.height + 10
radius: 4
color: "lightyellow"
Text {
id: t
height: paintedHeight
width: paintedWidth
x: 5
y: 5
anchors.margins: 4
font.pixelSize: 11
}
}
Component.onCompleted: menuModel.start()
}
qmenumodel-0.10.0/Jenkinsfile 0000664 0000000 0000000 00000006010 15212610716 013010 0 ustar pipeline {
agent any
stages {
stage('Build source') {
steps {
sh '/usr/bin/build-source.sh'
stash(name: 'source', includes: '*.gz,*.bz2,*.xz,*.deb,*.dsc,*.changes,*.buildinfo,lintian.txt')
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
}
}
stage('Build binary - armhf') {
steps {
parallel(
"Build binary - armhf": {
node(label: 'arm64') {
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
unstash 'source'
sh '''export architecture="armhf"
build-binary.sh'''
stash(includes: '*.gz,*.bz2,*.xz,*.deb,*.dsc,*.changes,*.buildinfo,lintian.txt', name: 'build-armhf')
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
}
},
"Build binary - arm64": {
node(label: 'arm64') {
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
unstash 'source'
sh '''export architecture="arm64"
build-binary.sh'''
stash(includes: '*.gz,*.bz2,*.xz,*.deb,*.dsc,*.changes,*.buildinfo,lintian.txt', name: 'build-arm64')
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
}
},
"Build binary - amd64": {
node(label: 'amd64') {
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
unstash 'source'
sh '''export architecture="amd64"
build-binary.sh'''
stash(includes: '*.gz,*.bz2,*.xz,*.deb,*.dsc,*.changes,*.buildinfo,lintian.txt', name: 'build-amd64')
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
}
}
)
}
}
stage('Results') {
steps {
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
unstash 'build-armhf'
unstash 'build-arm64'
unstash 'build-amd64'
archiveArtifacts(artifacts: '*.gz,*.bz2,*.xz,*.deb,*.dsc,*.changes,*.buildinfo', fingerprint: true, onlyIfSuccessful: true)
sh '''/usr/bin/build-repo.sh'''
}
}
stage('Cleanup') {
steps {
cleanWs(cleanWhenAborted: true, cleanWhenFailure: true, cleanWhenNotBuilt: true, cleanWhenSuccess: true, cleanWhenUnstable: true, deleteDirs: true)
}
}
}
}
qmenumodel-0.10.0/libqmenumodel/CMakeLists.txt 0000664 0000000 0000000 00000000113 15212610716 016217 0 ustar project(libqmenumodel)
add_subdirectory(src)
add_subdirectory(QMenuModel)
qmenumodel-0.10.0/libqmenumodel/QMenuModel/CMakeLists.txt 0000664 0000000 0000000 00000001576 15212610716 020243 0 ustar project(qmlplugin)
set(QMLPLUGIN_SRC
plugin.cpp
)
add_library(qmenumodel-qml MODULE
${QMLPLUGIN_SRC}
)
include_directories(
${src_SOURCE_DIR}
${GLIB_INCLUDE_DIRS}
)
target_link_libraries(qmenumodel-qml
qmenumodel${QMENUMODEL_LIB_SUFFIX}
${GLIB_LDFLAGS}
${GIO_LDFLAGS}
Qt::Qml Qt::Quick
)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
"${CMAKE_CURRENT_BINARY_DIR}/qmldir")
set(QT_IMPORTS_DIR "${CMAKE_INSTALL_LIBDIR}/qt${QT_VERSION_MAJOR}/qml")
if (ENABLE_QT6)
set(QMLPLUGIN_INSTALL_PREFIX "${QT_IMPORTS_DIR}/QMenuModel")
else()
set(QMLPLUGIN_INSTALL_PREFIX "${QT_IMPORTS_DIR}/QMenuModel.1")
endif()
install(TARGETS qmenumodel-qml DESTINATION ${QMLPLUGIN_INSTALL_PREFIX})
install(FILES qmldir DESTINATION ${QMLPLUGIN_INSTALL_PREFIX})
qmenumodel-0.10.0/libqmenumodel/QMenuModel/plugin.cpp 0000664 0000000 0000000 00000003521 15212610716 017475 0 ustar /*
* Copyright 2012 Canonical Ltd.
* Copyright 2021 Robert Tari
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Renato Araujo Oliveira Filho
* Robert Tari
*/
#include "plugin.h"
#include "qmenumodel.h"
#include "qdbusmenumodel.h"
#include "qdbusactiongroup.h"
#include "qstateaction.h"
#include "ayatanamenuaction.h"
#include "ayatanamenumodel.h"
#include
void QMenuModelQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
}
void QMenuModelQmlPlugin::registerTypes(const char *uri)
{
qmlRegisterUncreatableType(uri, 1, 0, "QMenuModel",
"QMenuModel is a interface");
qmlRegisterUncreatableType(uri, 1, 0, "QStateAction",
"QStateAction must be created by QDBusActionGroup::action");
qmlRegisterUncreatableType(uri, 1, 0, "DBus",
"DBus is only a namespace");
qmlRegisterType(uri, 1, 0, "QDBusMenuModel");
qmlRegisterType(uri, 1, 0, "QDBusActionGroup");
qmlRegisterType(uri, 1, 0, "AyatanaMenuModel");
qmlRegisterType(uri, 1, 0, "AyatanaMenuAction");
}
qmenumodel-0.10.0/libqmenumodel/QMenuModel/plugin.h 0000664 0000000 0000000 00000002047 15212610716 017144 0 ustar /*
* Copyright 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Renato Araujo Oliveira Filho
*/
#ifndef QMENUMODELQMLPLUGIN_H
#define QMENUMODELQMLPLUGIN_H
#include
class QMenuModelQmlPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.ayatana.qmenumodel")
public:
void initializeEngine(QQmlEngine *engine, const char *uri);
void registerTypes(const char *uri);
};
#endif
qmenumodel-0.10.0/libqmenumodel/QMenuModel/qmldir 0000664 0000000 0000000 00000000051 15212610716 016701 0 ustar module QMenuModel
plugin qmenumodel-qml
qmenumodel-0.10.0/libqmenumodel/src/actionstateparser.cpp 0000664 0000000 0000000 00000001756 15212610716 020523 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nick Dedekind
*/
#include "actionstateparser.h"
#include "converter.h"
ActionStateParser::ActionStateParser(QObject* parent)
: QObject(parent)
{
}
QVariant ActionStateParser::toQVariant(GVariant* state) const
{
if (state) {
return Converter::toQVariant(state);
}
return QVariant();
} qmenumodel-0.10.0/libqmenumodel/src/actionstateparser.h 0000664 0000000 0000000 00000002026 15212610716 020157 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nick Dedekind
*/
#ifndef ACTIONSTATEPARSER_H
#define ACTIONSTATEPARSER_H
#include
#include
typedef struct _GVariant GVariant;
class ActionStateParser : public QObject
{
Q_OBJECT
public:
ActionStateParser(QObject* parent = 0);
virtual QVariant toQVariant(GVariant* state) const;
};
#endif // ACTIONSTATEPARSER_H
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenuaction.cpp 0000664 0000000 0000000 00000007113 15212610716 020462 0 ustar /*
* Copyright 2013 Canonical Ltd.
* Copyright 2022 Robert Tari
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nick Dedekind
* Robert Tari
*/
#include "ayatanamenuaction.h"
#include "ayatanamenumodel.h"
#include "ayatanamenuactionevents.h"
AyatanaMenuAction::AyatanaMenuAction(QObject* parent)
: QObject(parent),
m_valid(false),
m_enabled(false),
m_model(NULL),
m_index(-1)
{
}
AyatanaMenuAction::~AyatanaMenuAction()
{
unregisterAction();
}
QString AyatanaMenuAction::name() const
{
return m_name;
}
void AyatanaMenuAction::setName(const QString& name)
{
if (m_name != name) {
m_name = name;
Q_EMIT nameChanged(m_name);
}
}
AyatanaMenuModel* AyatanaMenuAction::model() const
{
return m_model;
}
void AyatanaMenuAction::setModel(AyatanaMenuModel* model)
{
if (m_model != model) {
unregisterAction();
m_model = model;
registerAction();
Q_EMIT modelChanged(model);
}
}
QVariant AyatanaMenuAction::state() const
{
return m_state;
}
void AyatanaMenuAction::setState(const QVariant& state)
{
if (m_state != state) {
m_state = state;
Q_EMIT stateChanged(m_state);
}
}
bool AyatanaMenuAction::isEnabled() const
{
return m_enabled;
}
void AyatanaMenuAction::setEnabled(bool enabled)
{
if (m_enabled != enabled) {
m_enabled = enabled;
Q_EMIT enabledChanged(m_enabled);
}
}
bool AyatanaMenuAction::isValid() const
{
return m_valid;
}
void AyatanaMenuAction::setValid(bool valid)
{
if (m_valid != valid) {
m_valid = valid;
Q_EMIT validChanged(m_valid);
}
}
int AyatanaMenuAction::index() const
{
return m_index;
}
void AyatanaMenuAction::setIndex(int i)
{
if (i != m_index) {
m_index = i;
Q_EMIT indexChanged(m_index);
}
}
void AyatanaMenuAction::registerAction()
{
if (m_model) {
m_model->registerAction(this);
}
}
void AyatanaMenuAction::unregisterAction()
{
if (m_model) {
m_model->unregisterAction(this);
}
}
bool AyatanaMenuAction::event(QEvent* e)
{
if (e->type() == AyatanaMenuActionAddEvent::eventType) {
AyatanaMenuActionAddEvent *umaae = static_cast(e);
setEnabled(umaae->enabled);
setState(umaae->state);
setValid(true);
return true;
} else if (e->type() == AyatanaMenuActionEnabledChangedEvent::eventType) {
AyatanaMenuActionEnabledChangedEvent *umaece = static_cast(e);
setEnabled(umaece->enabled);
return true;
} else if (e->type() == AyatanaMenuActionStateChangeEvent::eventType) {
AyatanaMenuActionStateChangeEvent *umasce = static_cast(e);
setState(umasce->state);
return true;
} else if (e->type() == AyatanaMenuActionRemoveEvent::eventType) {
setValid(false);
return true;
}
return QObject::event(e);
}
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenuactionevents.cpp 0000664 0000000 0000000 00000003560 15212610716 021711 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nicholas Dedekind (QEvent::registerEventType());
const QEvent::Type AyatanaMenuActionRemoveEvent::eventType = static_cast(QEvent::registerEventType());
const QEvent::Type AyatanaMenuActionEnabledChangedEvent::eventType = static_cast(QEvent::registerEventType());
const QEvent::Type AyatanaMenuActionStateChangeEvent::eventType = static_cast(QEvent::registerEventType());
AyatanaMenuActionAddEvent::AyatanaMenuActionAddEvent(bool _enabled, const QVariant& _state)
: QEvent(AyatanaMenuActionAddEvent::eventType),
enabled(_enabled),
state(_state)
{}
AyatanaMenuActionRemoveEvent::AyatanaMenuActionRemoveEvent()
: QEvent(AyatanaMenuActionRemoveEvent::eventType)
{
}
AyatanaMenuActionEnabledChangedEvent::AyatanaMenuActionEnabledChangedEvent(bool _enabled)
: QEvent(AyatanaMenuActionEnabledChangedEvent::eventType),
enabled(_enabled)
{}
AyatanaMenuActionStateChangeEvent::AyatanaMenuActionStateChangeEvent(const QVariant& _state)
: QEvent(AyatanaMenuActionStateChangeEvent::eventType),
state(_state)
{}
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenuactionevents.h 0000664 0000000 0000000 00000003411 15212610716 021351 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nicholas Dedekind
#include
/* Event for a ayatanamenuaction add */
class AyatanaMenuActionAddEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuActionAddEvent(bool enabled, const QVariant& state);
bool enabled;
QVariant state;
};
/* Event for a ayatanamenuaction remove */
class AyatanaMenuActionRemoveEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuActionRemoveEvent();
};
/* Event for change in enabled value of a ayatanamenuaction */
class AyatanaMenuActionEnabledChangedEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuActionEnabledChangedEvent(bool enabled);
int enabled;
};
/* Event for change in state value of a ayatanamenuaction */
class AyatanaMenuActionStateChangeEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuActionStateChangeEvent(const QVariant& state);
QVariant state;
};
#endif //AYATANAMENUACTIONEVENTS_H
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenuaction.h 0000664 0000000 0000000 00000004714 15212610716 020133 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors: Nick Dedekind
*/
#ifndef AYATANAMENUACTION_H
#define AYATANAMENUACTION_H
#include
#include
// cyclical includes, forward-declare
class AyatanaMenuModel;
#include "ayatanamenumodel.h"
class AyatanaMenuAction: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QVariant state READ state NOTIFY stateChanged)
Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
Q_PROPERTY(AyatanaMenuModel* model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged)
public:
AyatanaMenuAction(QObject* parent = 0);
~AyatanaMenuAction();
QString name() const;
void setName(const QString& str);
AyatanaMenuModel* model() const;
void setModel(AyatanaMenuModel* model);
int index() const;
void setIndex(int i);
QVariant state() const;
bool isEnabled() const;
bool isValid() const;
Q_SIGNALS:
Q_INVOKABLE void activate(const QVariant& parameter = QVariant());
Q_INVOKABLE void changeState(const QVariant& parameter);
void nameChanged(const QString& name);
void modelChanged(AyatanaMenuModel* model);
void stateChanged(const QVariant& name);
void enabledChanged(bool enabled);
void validChanged(bool valid);
void indexChanged(int index);
protected:
virtual bool event(QEvent* e);
void setState(const QVariant& state);
void setEnabled(bool enabled);
void setValid(bool valid);
private:
void unregisterAction();
void registerAction();
QString m_name;
QVariant m_state;
bool m_valid;
bool m_enabled;
AyatanaMenuModel* m_model;
int m_index;
};
#endif // AYATANAMENUACTIONGROUP_H
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenumodel.cpp 0000664 0000000 0000000 00000103733 15212610716 020312 0 ustar /*
* Copyright 2013 Canonical Ltd.
* Copyright 2022 Robert Tari
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Lars Uebernickel
* Robert Tari
*/
#include "ayatanamenumodel.h"
#include "converter.h"
#include "actionstateparser.h"
#include "ayatanamenumodelevents.h"
#include "ayatanamenuaction.h"
#include "ayatanamenuactionevents.h"
#include "logging.h"
#include
#include
#include
#include
extern "C" {
#include "gtk/gtkactionmuxer.h"
#include "gtk/gtkmenutracker.h"
#include "gtk/gtksimpleactionobserver.h"
}
Q_LOGGING_CATEGORY(ayatanamenumodel, "qmenumodel.ayatanamenumodel", QtCriticalMsg)
G_DEFINE_QUARK (AYATANA_MENU_MODEL, ayatana_menu_model)
G_DEFINE_QUARK (AYATANA_SUBMENU_MODEL, ayatana_submenu_model)
G_DEFINE_QUARK (AYATANA_MENU_ITEM_EXTENDED_ATTRIBUTES, ayatana_menu_item_extended_attributes)
G_DEFINE_QUARK (AYATANA_MENU_ACTION, ayatana_menu_action)
enum MenuRoles {
LabelRole = Qt::DisplayRole + 1,
SensitiveRole,
IsSeparatorRole,
IconRole,
TypeRole,
ExtendedAttributesRole,
ActionRole,
ActionStateRole,
IsCheckRole,
IsRadioRole,
IsToggledRole,
ShortcutRole,
HasSubmenuRole
};
class AyatanaMenuModelPrivate
{
public:
AyatanaMenuModelPrivate(AyatanaMenuModel *model);
AyatanaMenuModelPrivate(const AyatanaMenuModelPrivate& other, AyatanaMenuModel *model);
~AyatanaMenuModelPrivate();
void clearItems(bool resetModel=true);
void clearName();
void updateActions();
void updateMenuModel();
QVariant itemState(GtkMenuTrackerItem *item);
AyatanaMenuModel *model;
GtkActionMuxer *muxer;
GtkMenuTracker *menutracker;
GSequence *items;
GDBusConnection *connection;
QByteArray busName;
QByteArray nameOwner;
guint nameWatchId;
QVariantMap actions;
QByteArray menuObjectPath;
QHash roles;
ActionStateParser* actionStateParser;
QHash registeredActions;
bool destructorGuard;
static void nameAppeared(GDBusConnection *connection, const gchar *name, const gchar *owner, gpointer user_data);
static void nameVanished(GDBusConnection *connection, const gchar *name, gpointer user_data);
static void menuItemInserted(GPtrArray *items, gint position, gpointer user_data);
static void menuItemRemoved(gint position, gint n_items, gpointer user_data);
static void menuItemChanged(GObject *object, GParamSpec *pspec, gpointer user_data);
static void registeredActionAdded(GtkSimpleActionObserver *observer_item,
const gchar *action_name,
gboolean enabled,
GVariant *state);
static void registeredActionEnabledChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, gboolean enabled);
static void registeredActionStateChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, GVariant *state);
static void registeredActionRemoved(GtkSimpleActionObserver *observer_item, const gchar *action_name);
gchar * fullActionName(AyatanaMenuAction *action);
void updateRegisteredAction(AyatanaMenuAction *action);
};
void menu_item_free (gpointer data)
{
GtkMenuTrackerItem *item = (GtkMenuTrackerItem *) data;
g_signal_handlers_disconnect_by_func (item, (gpointer) AyatanaMenuModelPrivate::menuItemChanged, NULL);
g_object_unref (item);
}
AyatanaMenuModelPrivate::AyatanaMenuModelPrivate(AyatanaMenuModel *model)
{
this->model = model;
this->menutracker = NULL;
this->connection = NULL;
this->nameWatchId = 0;
this->actionStateParser = new ActionStateParser(model);
this->destructorGuard = false;
this->muxer = gtk_action_muxer_new ();
this->items = g_sequence_new (menu_item_free);
}
AyatanaMenuModelPrivate::AyatanaMenuModelPrivate(const AyatanaMenuModelPrivate& other, AyatanaMenuModel *model)
{
this->model = model;
this->menutracker = NULL;
this->connection = NULL;
this->nameWatchId = 0;
this->actionStateParser = new ActionStateParser(model);
this->destructorGuard = false;
this->muxer = GTK_ACTION_MUXER( g_object_ref(other.muxer));
this->items = g_sequence_new (menu_item_free);
}
AyatanaMenuModelPrivate::~AyatanaMenuModelPrivate()
{
this->destructorGuard = true;
this->clearItems(false);
g_sequence_free(this->items);
g_clear_pointer (&this->menutracker, gtk_menu_tracker_free);
g_clear_object (&this->muxer);
g_clear_object (&this->connection);
QHash::const_iterator it = this->registeredActions.constBegin();
for (; it != this->registeredActions.constEnd(); ++it) {
g_object_unref(it.value());
it.key()->setModel(NULL);
}
this->registeredActions.clear();
if (this->nameWatchId)
g_bus_unwatch_name (this->nameWatchId);
}
void AyatanaMenuModelPrivate::clearItems(bool resetModel)
{
AyatanaMenuModelClearEvent ummce(resetModel);
QCoreApplication::sendEvent(model, &ummce);
}
void AyatanaMenuModelPrivate::clearName()
{
this->clearItems();
this->nameOwner = QByteArray();
this->updateActions();
this->updateMenuModel();
Q_EMIT model->nameOwnerChanged (this->nameOwner);
}
void AyatanaMenuModelPrivate::updateActions()
{
Q_FOREACH (QString prefix, this->actions.keys())
gtk_action_muxer_remove (this->muxer, prefix.toUtf8());
if (this->nameOwner.isEmpty())
return;
for (QVariantMap::const_iterator it = this->actions.constBegin(); it != this->actions.constEnd(); ++it) {
GDBusActionGroup *actions;
actions = g_dbus_action_group_get (this->connection, this->nameOwner, it.value().toByteArray());
gtk_action_muxer_insert (this->muxer, it.key().toUtf8(), G_ACTION_GROUP (actions));
g_object_unref (actions);
}
}
void AyatanaMenuModelPrivate::updateMenuModel()
{
this->clearItems();
g_clear_pointer (&this->menutracker, gtk_menu_tracker_free);
if (!this->nameOwner.isEmpty()) {
GDBusMenuModel *menu;
menu = g_dbus_menu_model_get (this->connection, this->nameOwner, this->menuObjectPath.constData());
this->menutracker = gtk_menu_tracker_new (GTK_ACTION_OBSERVABLE (this->muxer),
G_MENU_MODEL (menu), TRUE, NULL,
menuItemInserted, menuItemRemoved, this);
g_object_unref (menu);
}
}
QVariant AyatanaMenuModelPrivate::itemState(GtkMenuTrackerItem *item)
{
QVariant result;
GVariant *state = gtk_menu_tracker_item_get_action_state (item);
if (state != NULL) {
if (actionStateParser != NULL) {
result = actionStateParser->toQVariant(state);
}
g_variant_unref (state);
}
return result;
}
void AyatanaMenuModelPrivate::nameAppeared(GDBusConnection *connection, const gchar *name, const gchar *owner, gpointer user_data)
{
AyatanaMenuModelPrivate *priv = (AyatanaMenuModelPrivate *)user_data;
priv->connection = (GDBusConnection *) g_object_ref (connection);
priv->nameOwner = owner;
priv->updateActions();
priv->updateMenuModel();
Q_EMIT priv->model->nameOwnerChanged (priv->nameOwner);
}
void AyatanaMenuModelPrivate::nameVanished(GDBusConnection *connection, const gchar *name, gpointer user_data)
{
AyatanaMenuModelPrivate *priv = (AyatanaMenuModelPrivate *)user_data;
priv->clearName();
}
void AyatanaMenuModelPrivate::menuItemInserted(GPtrArray *items, gint position, gpointer user_data)
{
AyatanaMenuModelPrivate *priv = (AyatanaMenuModelPrivate *)user_data;
AyatanaMenuModelAddRowEvent ummare(items, position);
QCoreApplication::sendEvent(priv->model, &ummare);
}
void AyatanaMenuModelPrivate::menuItemRemoved(gint position, gint n_items, gpointer user_data)
{
AyatanaMenuModelPrivate *priv = (AyatanaMenuModelPrivate *)user_data;
AyatanaMenuModelRemoveRowEvent ummrre(position, n_items);
QCoreApplication::sendEvent(priv->model, &ummrre);
}
void AyatanaMenuModelPrivate::menuItemChanged(GObject *object, GParamSpec *pspec, gpointer user_data)
{
GSequenceIter *it = (GSequenceIter *) user_data;
GtkMenuTrackerItem *item;
AyatanaMenuModel *model;
gint position;
item = (GtkMenuTrackerItem *) g_sequence_get (it);
model = (AyatanaMenuModel *) g_object_get_qdata (G_OBJECT (item), ayatana_menu_model_quark ());
position = g_sequence_iter_get_position (it);
AyatanaMenuModelDataChangeEvent ummdce(position);
QCoreApplication::sendEvent(model, &ummdce);
}
AyatanaMenuModel::AyatanaMenuModel(QObject *parent):
QAbstractListModel(parent)
{
priv = new AyatanaMenuModelPrivate(this);
}
AyatanaMenuModel::AyatanaMenuModel(const AyatanaMenuModelPrivate& other, AyatanaMenuModel *parent):
QAbstractListModel(parent)
{
priv = new AyatanaMenuModelPrivate(other, this);
}
AyatanaMenuModel::~AyatanaMenuModel()
{
delete priv;
}
QByteArray AyatanaMenuModel::busName() const
{
return priv->busName;
}
QByteArray AyatanaMenuModel::nameOwner() const
{
return priv->nameOwner;
}
void AyatanaMenuModel::setBusName(const QByteArray &name)
{
if (name == priv->busName)
return;
priv->clearName();
if (priv->nameWatchId)
g_bus_unwatch_name (priv->nameWatchId);
priv->nameWatchId = g_bus_watch_name (G_BUS_TYPE_SESSION, name.constData(), G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
AyatanaMenuModelPrivate::nameAppeared, AyatanaMenuModelPrivate::nameVanished,
priv, NULL);
priv->busName = name;
Q_EMIT busNameChanged (priv->busName);
}
QVariantMap AyatanaMenuModel::actions() const
{
return priv->actions;
}
void AyatanaMenuModel::setActions(const QVariantMap &actions)
{
priv->actions = actions;
priv->updateActions();
}
QByteArray AyatanaMenuModel::menuObjectPath() const
{
return priv->menuObjectPath;
}
void AyatanaMenuModel::setMenuObjectPath(const QByteArray &path)
{
priv->menuObjectPath = path;
priv->updateMenuModel();
}
ActionStateParser* AyatanaMenuModel::actionStateParser() const
{
return priv->actionStateParser;
}
void AyatanaMenuModel::setActionStateParser(ActionStateParser* actionStateParser)
{
if (priv->actionStateParser != actionStateParser) {
priv->actionStateParser = actionStateParser;
Q_EMIT actionStateParserChanged(actionStateParser);
}
}
int AyatanaMenuModel::rowCount(const QModelIndex &parent) const
{
return !parent.isValid() ? g_sequence_get_length (priv->items) : 0;
}
int AyatanaMenuModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
static QString iconUri(GIcon *icon)
{
QString uri;
if (G_IS_THEMED_ICON (icon)) {
const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon));
guint index = 0;
while(iconNames[index] != NULL) {
if (QIcon::hasThemeIcon(iconNames[index])) {
uri = QString("image://theme/") + iconNames[index];
break;
}
index++;
}
}
else if (G_IS_FILE_ICON (icon)) {
GFile *file;
file = g_file_icon_get_file (G_FILE_ICON (icon));
if (file) {
gchar *fileuri;
fileuri = g_file_get_uri (file);
uri = QString(fileuri);
g_free (fileuri);
}
}
else if (G_IS_BYTES_ICON (icon)) {
gsize size;
gconstpointer data;
gchar *base64;
data = g_bytes_get_data (g_bytes_icon_get_bytes (G_BYTES_ICON (icon)), &size);
base64 = g_base64_encode ((const guchar *) data, size);
uri = QString("data://");
uri.append (base64);
g_free (base64);
}
return uri;
}
QVariant AyatanaMenuModel::data(const QModelIndex &index, int role) const
{
GSequenceIter *it;
GtkMenuTrackerItem *item;
it = g_sequence_get_iter_at_pos (priv->items, index.row());
if (g_sequence_iter_is_end (it)) {
return QVariant();
}
item = (GtkMenuTrackerItem *) g_sequence_get (it);
if (!item) {
return QVariant();
}
switch (role) {
case LabelRole:
return gtk_menu_tracker_item_get_label (item);
case SensitiveRole:
return gtk_menu_tracker_item_get_sensitive (item) == TRUE ? true : false;
case IsSeparatorRole:
return gtk_menu_tracker_item_get_is_separator (item) == TRUE ? true : false;
case IconRole: {
GIcon *icon = gtk_menu_tracker_item_get_icon (item);
if (icon) {
QString uri = iconUri(icon);
g_object_unref (icon);
return uri;
}
else
return QString();
}
case TypeRole: {
gchar *type;
auto ret = gtk_menu_tracker_item_get_attribute (item, "x-ayatana-type", "s", &type);
// If we can't get x-ayatana-type, try legacy x-canonical-type type
if (!ret)
ret = gtk_menu_tracker_item_get_attribute (item, "x-canonical-type", "s", &type);
if (ret) {
QString v(type);
g_free (type);
return v;
}
else
return QVariant();
}
case ExtendedAttributesRole: {
QVariantMap *map = (QVariantMap *) g_object_get_qdata (G_OBJECT (item), ayatana_menu_item_extended_attributes_quark ());
return map ? *map : QVariant();
}
case ActionRole: {
gchar *action_name = gtk_menu_tracker_item_get_action_name (item);
QString v(action_name);
g_free(action_name);
return v;
}
case ActionStateRole:
return priv->itemState(item);
case IsCheckRole:
return gtk_menu_tracker_item_get_role (item) == GTK_MENU_TRACKER_ITEM_ROLE_CHECK;
case IsRadioRole:
return gtk_menu_tracker_item_get_role (item) == GTK_MENU_TRACKER_ITEM_ROLE_RADIO;
case IsToggledRole:
return gtk_menu_tracker_item_get_toggled (item) != FALSE;
case ShortcutRole:
return QKeySequence(gtk_menu_tracker_item_get_accel (item), QKeySequence::NativeText);
case HasSubmenuRole:
return gtk_menu_tracker_item_get_has_submenu (item) != FALSE;
default:
return QVariant();
}
}
QModelIndex AyatanaMenuModel::index(int row, int column, const QModelIndex &parent) const
{
return createIndex(row, column);
}
QModelIndex AyatanaMenuModel::parent(const QModelIndex &index) const
{
return QModelIndex();
}
QHash AyatanaMenuModel::roleNames() const
{
QHash names;
names[LabelRole] = "label";
names[SensitiveRole] = "sensitive";
names[IsSeparatorRole] = "isSeparator";
names[IconRole] = "icon";
names[TypeRole] = "type";
names[ExtendedAttributesRole] = "ext";
names[ActionRole] = "action";
names[ActionStateRole] = "actionState";
names[IsCheckRole] = "isCheck";
names[IsRadioRole] = "isRadio";
names[IsToggledRole] = "isToggled";
names[ShortcutRole] = "shortcut";
names[HasSubmenuRole] = "hasSubmenu";
return names;
}
QObject * AyatanaMenuModel::submenu(int position, QQmlComponent* actionStateParser)
{
GSequenceIter *it;
GtkMenuTrackerItem *item;
AyatanaMenuModel *model;
it = g_sequence_get_iter_at_pos (priv->items, position);
if (g_sequence_iter_is_end (it)) {
return NULL;
}
item = (GtkMenuTrackerItem *) g_sequence_get (it);
if (!item || !gtk_menu_tracker_item_get_has_submenu (item)) {
return NULL;
}
model = (AyatanaMenuModel *) g_object_get_qdata (G_OBJECT (item), ayatana_submenu_model_quark ());
if (model == NULL) {
model = new AyatanaMenuModel(*priv, this);
if (actionStateParser) {
ActionStateParser* parser = qobject_cast(actionStateParser->create());
if (parser) {
model->setActionStateParser(parser);
}
}
model->priv->menutracker = gtk_menu_tracker_new_for_item_submenu (item,
AyatanaMenuModelPrivate::menuItemInserted,
AyatanaMenuModelPrivate::menuItemRemoved,
model->priv);
g_object_set_qdata (G_OBJECT (item), ayatana_submenu_model_quark (), model);
}
return model;
}
static void freeExtendedAttrs(gpointer data)
{
QVariantMap *extendedAttrs = (QVariantMap *) data;
delete extendedAttrs;
}
static QVariant attributeToQVariant(GVariant *value, const QString &type)
{
QVariant result;
if (type == "int16") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT16)) {
result = QVariant(g_variant_get_int16(value));
}
}
else if (type == "int32" || type == "int") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) {
result = QVariant(g_variant_get_int32(value));
}
}
else if (type == "int64") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT64)) {
result = QVariant((qlonglong)g_variant_get_int64(value));
}
}
else if (type == "uint16") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT16)) {
result = QVariant(g_variant_get_uint16(value));
}
}
else if (type == "uint32") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) {
result = QVariant(g_variant_get_uint32(value));
}
}
else if (type == "uint64") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64)) {
result = QVariant((quint64)g_variant_get_uint64(value));
}
}
else if (type == "bool") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) {
result = QVariant(g_variant_get_boolean(value));
}
}
else if (type == "string") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) {
result = QVariant(g_variant_get_string(value, NULL));
}
}
else if (type == "double") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE)) {
result = QVariant(g_variant_get_double(value));
}
}
else if (type == "variant") {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_VARIANT)) {
result = Converter::toQVariant(value);
}
}
else if (type == "icon") {
GIcon *icon = g_icon_deserialize (value);
if (icon) {
result = iconUri(icon);
g_object_unref (icon);
}
else {
result = QVariant("");
}
}
return result;
}
/* convert 'some-key' to 'someKey' or 'SomeKey'. (from dconf-qt) */
static QString qtify_name(const char *name)
{
bool next_cap = false;
QString result;
while (*name) {
if (*name == '-') {
next_cap = true;
} else if (next_cap) {
result.append(QChar (toupper(*name)));
next_cap = false;
} else {
result.append(*name);
}
name++;
}
return result;
}
bool AyatanaMenuModel::loadExtendedAttributes(int position, const QVariantMap &schema)
{
GSequenceIter *it;
GtkMenuTrackerItem *item;
QVariantMap *extendedAttrs;
it = g_sequence_get_iter_at_pos (priv->items, position);
if (g_sequence_iter_is_end (it)) {
return false;
}
item = (GtkMenuTrackerItem *) g_sequence_get (it);
if (!item) {
return false;
}
extendedAttrs = new QVariantMap;
for (QVariantMap::const_iterator it = schema.constBegin(); it != schema.constEnd(); ++it) {
QString name = it.key();
QString type = it.value().toString();
GVariant *value = gtk_menu_tracker_item_get_attribute_value (item, name.toUtf8(), NULL);
if (value == NULL) {
qCWarning(ayatanamenumodel, "loadExtendedAttributes: menu item does not contain '%s'", it.key().toUtf8().constData());
continue;
}
const QVariant &qvalue = attributeToQVariant(value, type);
if (qvalue.isValid())
extendedAttrs->insert(qtify_name (name.toUtf8()), qvalue);
else
qCWarning(ayatanamenumodel, "loadExtendedAttributes: key '%s' is of type '%s' (expected '%s')",
name.toUtf8().constData(), g_variant_get_type_string(value), type.toUtf8().constData());
g_variant_unref (value);
}
g_object_set_qdata_full (G_OBJECT (item), ayatana_menu_item_extended_attributes_quark (),
extendedAttrs, freeExtendedAttrs);
Q_EMIT dataChanged(index(position, 0), index(position, 0), QVector() << ExtendedAttributesRole);
return true;
}
QVariant AyatanaMenuModel::get(int row, const QByteArray &role)
{
if (priv->roles.isEmpty()) {
QHash names = roleNames();
Q_FOREACH (int role, names.keys())
priv->roles.insert(names[role], role);
}
return this->data(this->index(row, 0), priv->roles[role]);
}
void AyatanaMenuModel::activate(int index, const QVariant& parameter)
{
GSequenceIter *it;
GtkMenuTrackerItem *item;
GVariant *value;
const GVariantType *parameter_type;
it = g_sequence_get_iter_at_pos (priv->items, index);
if (g_sequence_iter_is_end (it)) {
return;
}
item = (GtkMenuTrackerItem *) g_sequence_get (it);
if (!item) {
return;
}
if (parameter.isValid()) {
gchar *action;
action = gtk_menu_tracker_item_get_action_name (item);
parameter_type = g_action_group_get_action_parameter_type (G_ACTION_GROUP (priv->muxer), action);
value = Converter::toGVariantWithSchema(parameter, g_variant_type_peek_string (parameter_type));
g_action_group_activate_action (G_ACTION_GROUP (priv->muxer), action, value);
g_free (action);
} else {
gtk_menu_tracker_item_activated (item);
}
}
void AyatanaMenuModel::aboutToShow(int index)
{
GSequenceIter *it = g_sequence_get_iter_at_pos (priv->items, index);
if (g_sequence_iter_is_end (it)) {
return;
}
auto item = static_cast(g_sequence_get(it));
if (!item) {
return;
}
quint64 actionTag;
if (gtk_menu_tracker_item_get_attribute (item, "qtubuntu-tag", "t", &actionTag)) {
// Child AyatanaMenuModel have priv->connection null, so climb to the parent until we find a non null one
AyatanaMenuModelPrivate *privToUse = priv;
while (privToUse && !privToUse->connection) {
auto pModel = dynamic_cast(privToUse->model->QObject::parent());
if (pModel) {
privToUse = pModel->priv;
} else {
privToUse = nullptr;
}
}
if (privToUse) {
g_dbus_connection_call (privToUse->connection,
privToUse->busName,
privToUse->menuObjectPath,
"qtubuntu.actions.extra",
"aboutToShow",
g_variant_new("(t)", actionTag),
nullptr,
G_DBUS_CALL_FLAGS_NO_AUTO_START,
G_MAXINT,
nullptr,
nullptr,
nullptr);
}
}
}
void AyatanaMenuModel::activateByVariantString(int index, const QString& parameter)
{
activate(index, Converter::toQVariantFromVariantString(parameter));
}
void AyatanaMenuModel::changeStateByVariantString(int index, const QString& parameter)
{
changeState(index, Converter::toQVariantFromVariantString(parameter));
}
void AyatanaMenuModel::changeState(int index, const QVariant& parameter)
{
GSequenceIter *it;
GtkMenuTrackerItem* item;
GVariant* data;
GVariant* current_state;
it = g_sequence_get_iter_at_pos (priv->items, index);
if (g_sequence_iter_is_end (it)) {
return;
}
item = (GtkMenuTrackerItem *) g_sequence_get (it);
if (!item) {
return;
}
current_state = gtk_menu_tracker_item_get_action_state (item);
if (current_state) {
// Attempt to convert the parameter to the expected type
data = Converter::toGVariantWithSchema(parameter, g_variant_get_type_string(current_state));
g_variant_unref (current_state);
} else {
data = Converter::toGVariant(parameter);
}
gtk_menu_tracker_item_change_state (item, data);
if (data) {
g_variant_unref(data);
}
}
bool AyatanaMenuModel::event(QEvent* e)
{
if (e->type() == AyatanaMenuModelClearEvent::eventType) {
AyatanaMenuModelClearEvent *emmce = static_cast(e);
GSequenceIter *begin;
GSequenceIter *end;
if (emmce->reset)
beginResetModel();
begin = g_sequence_get_begin_iter (priv->items);
end = g_sequence_get_end_iter (priv->items);
g_sequence_remove_range (begin, end);
if (emmce->reset)
endResetModel();
return true;
} else if (e->type() == AyatanaMenuModelAddRowEvent::eventType) {
AyatanaMenuModelAddRowEvent *ummrce = static_cast(e);
GSequenceIter *it;
it = g_sequence_get_iter_at_pos (priv->items, ummrce->position);
beginInsertRows(QModelIndex(), ummrce->position, ummrce->position + ummrce->items->len - 1);
for (gint i = ummrce->items->len - 1; i >= 0; --i) {
GtkMenuTrackerItem *item = (GtkMenuTrackerItem*)g_ptr_array_index(ummrce->items, i);
it = g_sequence_insert_before (it, g_object_ref (item));
g_object_set_qdata (G_OBJECT (item), ayatana_menu_model_quark (), this);
g_signal_connect (item, "notify", G_CALLBACK (AyatanaMenuModelPrivate::menuItemChanged), it);
}
endInsertRows();
return true;
} else if (e->type() == AyatanaMenuModelRemoveRowEvent::eventType) {
AyatanaMenuModelRemoveRowEvent *ummrre = static_cast(e);
beginRemoveRows(QModelIndex(), ummrre->position, ummrre->position + ummrre->nItems - 1);
for (int i = 0; i < ummrre->nItems; ++i) {
GSequenceIter *it = g_sequence_get_iter_at_pos (priv->items, ummrre->position);
if (!g_sequence_iter_is_end (it)) {
g_sequence_remove (it);
}
}
endRemoveRows();
return true;
} else if (e->type() == AyatanaMenuModelDataChangeEvent::eventType) {
AyatanaMenuModelDataChangeEvent *ummdce = static_cast(e);
Q_EMIT dataChanged(index(ummdce->position, 0), index(ummdce->position, 0));
return true;
}
return QAbstractListModel::event(e);
}
void AyatanaMenuModel::registerAction(AyatanaMenuAction* action)
{
if (priv->destructorGuard)
return;
if (!priv->registeredActions.contains(action)) {
GtkSimpleActionObserver* observer_item;
observer_item = gtk_simple_action_observer_new(GTK_ACTION_OBSERVABLE (priv->muxer),
AyatanaMenuModelPrivate::registeredActionAdded,
AyatanaMenuModelPrivate::registeredActionEnabledChanged,
AyatanaMenuModelPrivate::registeredActionStateChanged,
AyatanaMenuModelPrivate::registeredActionRemoved);
g_object_set_qdata (G_OBJECT (observer_item), ayatana_menu_action_quark (), action);
priv->registeredActions[action] = observer_item;
connect(action, SIGNAL(nameChanged(const QString&)), SLOT(onRegisteredActionNameChanged(const QString&)));
connect(action, SIGNAL(indexChanged(int)), SLOT(onRegisteredActionIndexChanged(int)));
connect(action, SIGNAL(activate(const QVariant&)), SLOT(onRegisteredActionActivated(const QVariant&)));
connect(action, SIGNAL(changeState(const QVariant&)), SLOT(onRegisteredActionStateChanged(const QVariant&)));
}
}
void AyatanaMenuModel::unregisterAction(AyatanaMenuAction* action)
{
if (priv->destructorGuard)
return;
if (priv->registeredActions.contains(action)) {
GtkSimpleActionObserver* observer_item;
observer_item = priv->registeredActions[action];
g_object_unref(observer_item);
priv->registeredActions.remove(action);
disconnect(action);
}
}
/* Returns the full name for @action
*
* If @action is associated with a menu item that is inside of a
* section or submenu with "action-namespace" set, this namespace
* is prepended to @action->name()
*/
char * AyatanaMenuModelPrivate::fullActionName(AyatanaMenuAction *action)
{
GSequenceIter *iter;
QByteArray bytes;
const gchar *name;
bytes = action->name().toUtf8();
name = bytes.constData();
iter = g_sequence_get_iter_at_pos (this->items, action->index());
if (!g_sequence_iter_is_end (iter)) {
GtkMenuTrackerItem *item;
const gchar *action_namespace;
item = (GtkMenuTrackerItem *) g_sequence_get (iter);
if (!item) {
return g_strdup (name);
}
action_namespace = gtk_menu_tracker_item_get_action_namespace (item);
if (action_namespace != NULL)
return g_strjoin (".", action_namespace, name, NULL);
}
return g_strdup (name);
}
void AyatanaMenuModelPrivate::updateRegisteredAction(AyatanaMenuAction *action)
{
GtkSimpleActionObserver *observer_item;
gchar *action_name;
gboolean enabled;
GVariant *state;
if (!action || !this->registeredActions.contains(action))
return;
action_name = fullActionName(action);
observer_item = this->registeredActions[action];
gtk_simple_action_observer_register_action (observer_item, action_name);
if (g_action_group_query_action (G_ACTION_GROUP (this->muxer), action_name,
&enabled, NULL, NULL, NULL, &state))
{
AyatanaMenuActionAddEvent umaae(enabled, Converter::toQVariant(state));
QCoreApplication::sendEvent(action, &umaae);
if (state) {
g_variant_unref (state);
}
}
g_free(action_name);
}
void AyatanaMenuModel::onRegisteredActionNameChanged(const QString& name)
{
priv->updateRegisteredAction(qobject_cast(sender()));
}
void AyatanaMenuModel::onRegisteredActionIndexChanged(int index)
{
priv->updateRegisteredAction(qobject_cast(sender()));
}
void AyatanaMenuModel::onRegisteredActionActivated(const QVariant& parameter)
{
AyatanaMenuAction* action = qobject_cast(sender());
if (!action || action->name().isEmpty())
return;
gchar* action_name = priv->fullActionName(action);
g_action_group_activate_action (G_ACTION_GROUP (priv->muxer), action_name, Converter::toGVariant(parameter));
g_free(action_name);
}
void AyatanaMenuModel::onRegisteredActionStateChanged(const QVariant& parameter)
{
AyatanaMenuAction* action = qobject_cast(sender());
if (!action || action->name().isEmpty())
return;
gchar* action_name = priv->fullActionName(action);
g_action_group_change_action_state (G_ACTION_GROUP (priv->muxer), action_name, Converter::toGVariant(parameter));
g_free(action_name);
}
void AyatanaMenuModelPrivate::registeredActionAdded(GtkSimpleActionObserver *observer_item,
const gchar *action_name,
gboolean enabled,
GVariant *state)
{
AyatanaMenuAction *action;
action = (AyatanaMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), ayatana_menu_action_quark ());
if (action) {
AyatanaMenuActionAddEvent umaae(enabled, Converter::toQVariant(state));
QCoreApplication::sendEvent(action, &umaae);
}
}
void AyatanaMenuModelPrivate::registeredActionEnabledChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, gboolean enabled)
{
AyatanaMenuAction *action;
action = (AyatanaMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), ayatana_menu_action_quark ());
if (action) {
AyatanaMenuActionEnabledChangedEvent umaece(enabled);
QCoreApplication::sendEvent(action, &umaece);
}
}
void AyatanaMenuModelPrivate::registeredActionStateChanged(GtkSimpleActionObserver *observer_item, const gchar *action_name, GVariant *state)
{
AyatanaMenuAction *action;
action = (AyatanaMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), ayatana_menu_action_quark ());
if (action) {
AyatanaMenuActionStateChangeEvent umasce(Converter::toQVariant(state));
QCoreApplication::sendEvent(action, &umasce);
}
}
void AyatanaMenuModelPrivate::registeredActionRemoved(GtkSimpleActionObserver *observer_item, const gchar *action_name)
{
AyatanaMenuAction *action;
action = (AyatanaMenuAction *) g_object_get_qdata (G_OBJECT (observer_item), ayatana_menu_action_quark ());
if (action) {
AyatanaMenuActionRemoveEvent umare;
QCoreApplication::sendEvent(action, &umare);
}
}
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenumodelevents.cpp 0000664 0000000 0000000 00000004630 15212610716 021533 0 ustar /*
* Copyright 2013 Canonical Ltd.
* Copyright 2022 Robert Tari
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nicholas Dedekind
*/
#include
#include
#include "ayatanamenumodelevents.h"
#include "ayatanamenumodel.h"
const QEvent::Type AyatanaMenuModelClearEvent::eventType = static_cast(QEvent::registerEventType());
const QEvent::Type AyatanaMenuModelAddRowEvent::eventType = static_cast(QEvent::registerEventType());
const QEvent::Type AyatanaMenuModelRemoveRowEvent::eventType = static_cast(QEvent::registerEventType());
const QEvent::Type AyatanaMenuModelDataChangeEvent::eventType = static_cast(QEvent::registerEventType());
AyatanaMenuModelClearEvent::AyatanaMenuModelClearEvent(bool _reset)
: QEvent(AyatanaMenuModelClearEvent::eventType),
reset(_reset)
{}
AyatanaMenuModelAddRowEvent::AyatanaMenuModelAddRowEvent(GPtrArray *_items, int _position)
: QEvent(AyatanaMenuModelAddRowEvent::eventType),
items(_items),
position(_position)
{
if (items) {
for (guint i = 0; i < items->len; ++i)
g_object_ref(g_ptr_array_index(items, i));
g_ptr_array_ref(items);
}
}
AyatanaMenuModelAddRowEvent::~AyatanaMenuModelAddRowEvent()
{
if (items) {
for (guint i = 0; i < items->len; ++i)
g_object_unref(g_ptr_array_index(items, i));
g_ptr_array_unref(items);
}
}
AyatanaMenuModelRemoveRowEvent::AyatanaMenuModelRemoveRowEvent(int _position, int _nItems)
: QEvent(AyatanaMenuModelRemoveRowEvent::eventType),
position(_position), nItems(_nItems)
{}
AyatanaMenuModelDataChangeEvent::AyatanaMenuModelDataChangeEvent(int _position)
: QEvent(AyatanaMenuModelDataChangeEvent::eventType),
position(_position)
{}
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenumodelevents.h 0000664 0000000 0000000 00000003555 15212610716 021205 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Nicholas Dedekind
#include
typedef struct _GtkMenuTrackerItem GtkMenuTrackerItem;
/* Event for a ayatanamenumodel clear */
class AyatanaMenuModelClearEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuModelClearEvent(bool reset);
bool reset;
};
/* Event for a row add for ayatanamenumodel */
class AyatanaMenuModelAddRowEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuModelAddRowEvent(GPtrArray *_items, int position);
~AyatanaMenuModelAddRowEvent();
GPtrArray *items;
int position;
};
/* Event for a row remove for ayatanamenumodel */
class AyatanaMenuModelRemoveRowEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuModelRemoveRowEvent(int position, int nItems);
int position;
int nItems;
};
/* Event for a row data change for ayatanamenumodel */
class AyatanaMenuModelDataChangeEvent : public QEvent
{
public:
static const QEvent::Type eventType;
AyatanaMenuModelDataChangeEvent(int position);
int position;
};
#endif //AYATANAMENUMODELEVENTS_H
qmenumodel-0.10.0/libqmenumodel/src/ayatanamenumodel.h 0000664 0000000 0000000 00000007536 15212610716 017763 0 ustar /*
* Copyright 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors: Lars Uebernickel
*/
#ifndef AYATANAMENUMODEL_H
#define AYATANAMENUMODEL_H
#include
#include
#include "actionstateparser.h"
// cyclical includes, forward-declare
class AyatanaMenuAction;
#include "ayatanamenuaction.h"
class AyatanaMenuModel: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QByteArray busName READ busName WRITE setBusName NOTIFY busNameChanged)
Q_PROPERTY(QByteArray nameOwner READ nameOwner NOTIFY nameOwnerChanged)
Q_PROPERTY(QVariantMap actions READ actions WRITE setActions NOTIFY actionsChanged)
Q_PROPERTY(QByteArray menuObjectPath READ menuObjectPath WRITE setMenuObjectPath NOTIFY menuObjectPathChanged)
Q_PROPERTY(ActionStateParser* actionStateParser READ actionStateParser WRITE setActionStateParser NOTIFY actionStateParserChanged)
public:
AyatanaMenuModel(QObject *parent = NULL);
virtual ~AyatanaMenuModel();
QByteArray busName() const;
void setBusName(const QByteArray &name);
QByteArray nameOwner() const;
QVariantMap actions() const;
void setActions(const QVariantMap &actions);
QByteArray menuObjectPath() const;
void setMenuObjectPath(const QByteArray &path);
ActionStateParser* actionStateParser() const;
void setActionStateParser(ActionStateParser* actionStateParser);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
QHash roleNames() const;
Q_INVOKABLE QObject * submenu(int position, QQmlComponent* actionStateParser = NULL);
Q_INVOKABLE bool loadExtendedAttributes(int position, const QVariantMap &schema);
Q_INVOKABLE QVariant get(int row, const QByteArray &role);
Q_INVOKABLE void activate(int index, const QVariant& parameter = QVariant());
Q_INVOKABLE void aboutToShow(int index);
Q_INVOKABLE void activateByVariantString(int index, const QString& parameter = QString());
Q_INVOKABLE void changeState(int index, const QVariant& parameter);
Q_INVOKABLE void changeStateByVariantString(int index, const QString& parameter);
void registerAction(AyatanaMenuAction* action);
void unregisterAction(AyatanaMenuAction* action);
Q_SIGNALS:
void busNameChanged(const QByteArray &name);
void nameOwnerChanged(const QByteArray &owner);
void actionsChanged(const QByteArray &path);
void menuObjectPathChanged(const QByteArray &path);
void actionStateParserChanged(ActionStateParser* parser);
protected Q_SLOTS:
void onRegisteredActionNameChanged(const QString& name);
void onRegisteredActionIndexChanged(int);
void onRegisteredActionActivated(const QVariant& parameter);
void onRegisteredActionStateChanged(const QVariant& parameter);
protected:
virtual bool event(QEvent* e);
private:
class AyatanaMenuModelPrivate *priv;
friend class AyatanaMenuModelPrivate;
AyatanaMenuModel(const AyatanaMenuModelPrivate& other, AyatanaMenuModel *parent);
};
#endif
qmenumodel-0.10.0/libqmenumodel/src/CMakeLists.txt 0000664 0000000 0000000 00000003374 15212610716 017022 0 ustar project(src)
set(QMENUMODEL_SRC
actionstateparser.cpp
converter.cpp
dbus-enums.h
menunode.cpp
qmenumodel.cpp
qdbusobject.cpp
qdbusmenumodel.cpp
qdbusactiongroup.cpp
qmenumodelevents.cpp
qstateaction.cpp
ayatanamenuaction.cpp
ayatanamenuactionevents.cpp
ayatanamenumodel.cpp
ayatanamenumodelevents.cpp
gtk/gtkactionmuxer.c
gtk/gtkactionmuxer.h
gtk/gtkactionobservable.c
gtk/gtkactionobservable.h
gtk/gtkactionobserver.c
gtk/gtkactionobserver.h
gtk/gtksimpleactionobserver.c
gtk/gtksimpleactionobserver.h
gtk/gtkmenutracker.c
gtk/gtkmenutracker.h
gtk/gtkmenutrackeritem.c
gtk/gtkmenutrackeritem.h
)
set(SHAREDLIBNAME qmenumodel${QMENUMODEL_LIB_SUFFIX})
add_library(${SHAREDLIBNAME} SHARED
${QMENUMODEL_SRC}
)
set_target_properties(${SHAREDLIBNAME} PROPERTIES
COMPILE_FLAGS -fPIC
SOVERSION 1
VERSION 1.0.0
)
include_directories(
${GLIB_INCLUDE_DIRS}
${GIO_INCLUDE_DIRS}
)
target_link_libraries(${SHAREDLIBNAME}
${GLIB_LDFLAGS}
${GIO_LDFLAGS}
Qt::Core Qt::Qml Qt::Quick
)
install(TARGETS ${SHAREDLIBNAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
set(QMENUMODEL_HEADERS
actionstateparser.h
dbus-enums.h
qdbusactiongroup.h
qdbusmenumodel.h
qdbusobject.h
qmenumodel.h
qstateaction.h
ayatanamenuaction.h
ayatanamenumodel.h
)
set(INCLUDEDIR qt${QT_VERSION_MAJOR}/qmenumodel)
install(FILES ${QMENUMODEL_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${INCLUDEDIR}
)
set(PCFILE qmenumodel${QMENUMODEL_PKGCONFIG_SUFFIX}.pc)
configure_file(qmenumodel.pc.in ${CMAKE_CURRENT_BINARY_DIR}/${PCFILE} @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PCFILE}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
qmenumodel-0.10.0/libqmenumodel/src/converter.cpp 0000664 0000000 0000000 00000033600 15212610716 016770 0 ustar /*
* Copyright 2012-2016 Canonical Ltd.
* Copyright 2022 Robert Tari
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Renato Araujo Oliveira Filho
* Marco Trevisan
* Robert Tari
*/
#include
#include "converter.h"
#include
#include
#include
/*! \internal */
QVariant Converter::toQVariant(GVariant *value)
{
QVariant result;
if (value == NULL) {
return result;
}
const GVariantType *type = g_variant_get_type(value);
if (g_variant_type_equal(type, G_VARIANT_TYPE_BOOLEAN)) {
result.setValue((bool)g_variant_get_boolean(value));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) {
result.setValue(g_variant_get_byte(value));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) {
result.setValue(qint16(g_variant_get_int16(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) {
result.setValue(quint16(g_variant_get_uint16(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) {
result.setValue(qint32(g_variant_get_int32(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) {
result.setValue(quint32(g_variant_get_uint32(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) {
result.setValue(qint64(g_variant_get_int64(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) {
result.setValue(quint64(g_variant_get_uint64(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_DOUBLE)) {
result.setValue(g_variant_get_double(value));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_STRING)) {
gsize size = 0;
const gchar *v = g_variant_get_string(value, &size);
result.setValue(QString::fromUtf8(v, size));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_STRING_ARRAY)) {
gsize size = 0;
const gchar **sa = g_variant_get_strv(value, &size);
QStringList list;
for (gsize i = 0; i < size; ++i) {
list << QString::fromUtf8(sa[i]);
}
result.setValue(list);
g_free(sa);
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTESTRING)) {
result.setValue(QByteArray(g_variant_get_bytestring(value)));
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTESTRING_ARRAY)) {
gsize size = 0;
const gchar **bsa = g_variant_get_bytestring_array(value, &size);
QByteArrayList list;
for (gsize i = 0; i < size; ++i) {
list << bsa[i];
}
result.setValue(list);
g_free(bsa);
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_VARIANT)) {
GVariant *var = g_variant_get_variant(value);
result = toQVariant(var);
g_variant_unref(var);
} else if (g_variant_type_equal(type, G_VARIANT_TYPE_VARDICT)) {
GVariantIter iter;
GVariant *vvalue;
gchar *key;
QVariantMap qmap;
g_variant_iter_init (&iter, value);
while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue))
{
qmap.insert(QString::fromUtf8(key), toQVariant(vvalue));
}
result.setValue(qmap);
} else if (g_variant_type_is_array(type)) {
QVariantList lst;
for (int i = 0, iMax = g_variant_n_children(value); i < iMax; i++) {
GVariant *child = g_variant_get_child_value(value, i);
lst << toQVariant(child);
g_variant_unref(child);
}
result.setValue(lst);
} else if (g_variant_type_is_tuple(type)) {
gsize size = g_variant_n_children(value);
QVariantList vlist;
for (gsize i=0; i < size; i++) {
GVariant *v = g_variant_get_child_value(value, i);
if (v) {
vlist << toQVariant(v);
g_variant_unref(v);
}
}
result.setValue(vlist);
} else {
qWarning() << "Unsupported GVariant value" << (char*) type;
}
/* TODO: implement convertions to others types
* G_VARIANT_TYPE_HANDLE
* G_VARIANT_TYPE_OBJECT_PATH
* G_VARIANT_TYPE_SIGNATURE
* G_VARIANT_TYPE_ANY
* G_VARIANT_TYPE_BASIC
* G_VARIANT_TYPE_MAYBE
* G_VARIANT_TYPE_UNIT
* G_VARIANT_TYPE_DICT_ENTRY
* G_VARIANT_TYPE_DICTIONARY
* G_VARIANT_TYPE_OBJECT_PATH_ARRAY
*/
return result;
}
QVariant Converter::toQVariantFromVariantString(const QString &variantString)
{
GVariant *gvariant;
GError *error = NULL;
if (variantString.isEmpty()) {
return QVariant();
}
gvariant = g_variant_parse (NULL, qUtf8Printable(variantString), NULL, NULL, &error);
if (error) {
qWarning() << "Impossible to parse" << variantString << "as variant string:"<< error->message;
g_error_free (error);
return QVariant();
}
const QVariant& qvariant = Converter::toQVariant(gvariant);
g_variant_unref (gvariant);
return qvariant;
}
GVariant* Converter::toGVariant(const QVariant &value)
{
GVariant *result = NULL;
if (value.isNull() || !value.isValid())
return result;
switch(
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
value.typeId()
#else
(QMetaType::Type)value.type()
#endif
) {
case QMetaType::Bool:
result = g_variant_new_boolean(value.toBool());
break;
case QMetaType::QByteArray:
result = g_variant_new_bytestring(value.toByteArray());
break;
case QMetaType::Double:
result = g_variant_new_double(value.toDouble());
break;
case QMetaType::Int:
result = g_variant_new_int32(value.toInt());
break;
case QMetaType::LongLong:
result = g_variant_new_int64(value.toLongLong());
break;
case QMetaType::QString:
result = g_variant_new_string(qUtf8Printable(value.toString()));
break;
case QMetaType::UInt:
result = g_variant_new_uint32(value.toUInt());
break;
case QMetaType::ULongLong:
result = g_variant_new_uint64(value.toULongLong());
break;
case QMetaType::UChar:
result = g_variant_new_byte(value.value());
break;
case QMetaType::Short:
result = g_variant_new_int16(value.value());
break;
case QMetaType::UShort:
result = g_variant_new_uint16(value.value());
break;
case QMetaType::Long:
result = g_variant_new_int64(value.value());
break;
case QMetaType::ULong:
result = g_variant_new_uint64(value.value());
break;
case QMetaType::QVariantMap:
{
GVariantBuilder *b;
b = g_variant_builder_new(G_VARIANT_TYPE_VARDICT);
QMapIterator i(value.toMap());
while (i.hasNext()) {
i.next();
g_variant_builder_add(b, "{sv}", qUtf8Printable(i.key()), toGVariant(i.value()));
}
result = g_variant_builder_end(b);
g_variant_builder_unref(b);
break;
}
case QMetaType::QByteArrayList:
{
const QByteArrayList &list = qvariant_cast(value);
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_BYTESTRING_ARRAY);
for (const QByteArray &ba : list) {
g_variant_builder_add_value(b, g_variant_new_bytestring(ba));
}
result = g_variant_builder_end(b);
g_variant_builder_unref(b);
break;
}
case QMetaType::QVariantList:
{
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_TUPLE);
for (const QVariant &v : value.toList()) {
g_variant_builder_add_value(b, toGVariant(v));
}
result = g_variant_builder_end(b);
g_variant_builder_unref(b);
break;
}
case QMetaType::QStringList:
{
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_STRING_ARRAY);
for (const QString &s : value.toStringList()) {
g_variant_builder_add(b, "s", qUtf8Printable(s));
}
result = g_variant_builder_end(b);
g_variant_builder_unref(b);
break;
}
default:
qWarning() << "QVariant type not supported:" <<
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
value.metaType()
#else
value.type()
#endif
;
}
return result;
}
GVariant* Converter::toGVariantWithSchema(const QVariant &value, const char* schema)
{
if (!g_variant_type_string_is_valid(schema)) {
return Converter::toGVariant(value);
}
GVariant* result = NULL;
GVariantType* schema_type = g_variant_type_new(schema);
if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_BOOLEAN)) {
if (value.canConvert()) {
result = g_variant_new_boolean (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_BYTE)) {
if (value.canConvert()) {
result = g_variant_new_byte (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_INT16)) {
if (value.canConvert()) {
result = g_variant_new_int16 (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_UINT16)) {
if (value.canConvert()) {
result = g_variant_new_uint16 (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_INT32)) {
if (value.canConvert()) {
result = g_variant_new_int32 (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_UINT32)) {
if (value.canConvert()) {
result = g_variant_new_uint32 (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_INT64)) {
if (value.canConvert()) {
result = g_variant_new_int64 (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_UINT64)) {
if (value.canConvert()) {
result = g_variant_new_uint64 (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_DOUBLE)) {
if (value.canConvert()) {
result = g_variant_new_double (value.value());
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_STRING)) {
if (value.canConvert()) {
result = g_variant_new_string(qUtf8Printable(value.toString()));
}
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_VARIANT)) {
result = g_variant_new_variant(Converter::toGVariant(value));
} else if (g_variant_type_equal(schema_type, G_VARIANT_TYPE_VARDICT)) {
if (value.canConvert(
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QMetaType (QVariant::Map)
#else
QVariant::Map
#endif
)) {
result = Converter::toGVariant(value.toMap());
}
} else if (g_variant_type_is_array(schema_type)) {
if (value.canConvert(
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QMetaType (QVariant::List)
#else
QVariant::List
#endif
)) {
const GVariantType* entryType = g_variant_type_element(schema_type);
const gchar* entryTypeString = g_variant_type_peek_string(entryType);
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
bool ok = true;
for (const QVariant &v : value.toList()) {
GVariant *data = toGVariantWithSchema(v, entryTypeString);
if (data) {
g_variant_builder_add_value(b, data);
} else {
ok = false;
qWarning() << "Failed to convert list to array with schema:" << schema;
break;
}
}
if (ok) {
result = g_variant_builder_end(b);
}
g_variant_builder_unref(b);
}
} else if (g_variant_type_is_tuple(schema_type)) {
if (value.canConvert(
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QMetaType (QVariant::List)
#else
QVariant::List
#endif
)) {
const GVariantType* entryType = g_variant_type_first(schema_type);
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_TUPLE);
bool ok = true;
for (const QVariant &v : value.toList()) {
gchar* entryTypeString = g_variant_type_dup_string(entryType);
GVariant *data = toGVariantWithSchema(v, entryTypeString);
g_free(entryTypeString);
if (data) {
g_variant_builder_add_value(b, data);
entryType = g_variant_type_next(entryType);
if (!entryType)
break;
} else {
ok = false;
qWarning() << "Failed to convert list to array with schema:" << schema;
break;
}
}
if (ok) {
result = g_variant_builder_end(b);
}
g_variant_builder_unref(b);
}
}
// fallback to straight convert.
if (!result) {
result = Converter::toGVariant(value);
}
g_free(schema_type);
return result;
}
qmenumodel-0.10.0/libqmenumodel/src/converter.h 0000664 0000000 0000000 00000002443 15212610716 016436 0 ustar /*
* Copyright 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Renato Araujo Oliveira Filho
*/
#ifndef CONVERTER_H
#define CONVERTER_H
#include
#include
typedef struct _GVariant GVariant;
class Converter
{
public:
static QVariant toQVariant(GVariant *value);
static QVariant toQVariantFromVariantString(const QString &variantString);
static GVariant* toGVariant(const QVariant &value);
// This converts a QVariant to a GVariant using a provided gvariant schema as
// a conversion base (it will attempt to convert to this format).
static GVariant* toGVariantWithSchema(const QVariant &value, const char* schema);
};
#endif // CONVERTER_H
qmenumodel-0.10.0/libqmenumodel/src/dbus-enums.h 0000664 0000000 0000000 00000002374 15212610716 016514 0 ustar /*
* Copyright 2012 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Olivier Tilloy
*/
#ifndef __DBUS_ENUMS__
#define __DBUS_ENUMS__
#include
// This class acts as a namespace only, with the addition that its enums
// are registered to be exposed on the QML side.
class DBusEnums : public QObject
{
Q_OBJECT
Q_ENUMS(BusType)
Q_ENUMS(ConnectionStatus)
public:
enum BusType {
None = 0,
SessionBus,
SystemBus,
LastBusType
};
enum ConnectionStatus {
Disconnected = 0,
Connecting,
Connected
};
private:
DBusEnums() {}
};
#endif // __DBUS_ENUMS__
qmenumodel-0.10.0/libqmenumodel/src/gtk/config.h 0000664 0000000 0000000 00000000000 15212610716 016444 0 ustar qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkactionmuxer.c 0000664 0000000 0000000 00000061143 15212610716 020255 0 ustar /*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Author: Ryan Lortie
*/
#include "config.h"
#include "gtkactionmuxer.h"
#include "gtkactionobservable.h"
#include "gtkactionobserver.h"
#include
/**
* SECTION:gtkactionmuxer
* @short_description: Aggregate and monitor several action groups
*
* #GtkActionMuxer is a #GActionGroup and #GtkActionObservable that is
* capable of containing other #GActionGroup instances.
*
* The typical use is aggregating all of the actions applicable to a
* particular context into a single action group, with namespacing.
*
* Consider the case of two action groups -- one containing actions
* applicable to an entire application (such as 'quit') and one
* containing actions applicable to a particular window in the
* application (such as 'fullscreen').
*
* In this case, each of these action groups could be added to a
* #GtkActionMuxer with the prefixes "app" and "win", respectively. This
* would expose the actions as "app.quit" and "win.fullscreen" on the
* #GActionGroup interface presented by the #GtkActionMuxer.
*
* Activations and state change requests on the #GtkActionMuxer are wired
* through to the underlying action group in the expected way.
*
* This class is typically only used at the site of "consumption" of
* actions (eg: when displaying a menu that contains many actions on
* different objects).
*/
static void gtk_action_muxer_group_iface_init (GActionGroupInterface *iface);
static void gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface);
typedef GObjectClass GtkActionMuxerClass;
struct _GtkActionMuxer
{
GObject parent_instance;
GHashTable *observed_actions;
GHashTable *groups;
GtkActionMuxer *parent;
};
G_DEFINE_TYPE_WITH_CODE (GtkActionMuxer, gtk_action_muxer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_action_muxer_group_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVABLE, gtk_action_muxer_observable_iface_init))
enum
{
PROP_0,
PROP_PARENT,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
typedef struct
{
GtkActionMuxer *muxer;
GSList *watchers;
gchar *fullname;
} Action;
typedef struct
{
GtkActionMuxer *muxer;
GActionGroup *group;
gchar *prefix;
gulong handler_ids[4];
} Group;
static void
gtk_action_muxer_append_group_actions (gpointer key,
gpointer value,
gpointer user_data)
{
const gchar *prefix = key;
Group *group = value;
GArray *actions = user_data;
gchar **group_actions;
gchar **action;
group_actions = g_action_group_list_actions (group->group);
for (action = group_actions; *action; action++)
{
gchar *fullname;
fullname = g_strconcat (prefix, ".", *action, NULL);
g_array_append_val (actions, fullname);
}
g_strfreev (group_actions);
}
static gchar **
gtk_action_muxer_list_actions (GActionGroup *action_group)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
GArray *actions;
actions = g_array_new (TRUE, FALSE, sizeof (gchar *));
for ( ; muxer != NULL; muxer = muxer->parent)
{
g_hash_table_foreach (muxer->groups,
gtk_action_muxer_append_group_actions,
actions);
}
return (gchar **) g_array_free (actions, FALSE);
}
static Group *
gtk_action_muxer_find_group (GtkActionMuxer *muxer,
const gchar *full_name,
const gchar **action_name)
{
const gchar *dot;
gchar *prefix;
Group *group;
dot = strchr (full_name, '.');
if (!dot)
return NULL;
prefix = g_strndup (full_name, dot - full_name);
group = g_hash_table_lookup (muxer->groups, prefix);
g_free (prefix);
if (action_name)
*action_name = dot + 1;
return group;
}
static void
gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
const gchar *action_name,
gboolean enabled)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_enabled_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, enabled);
g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), action_name, enabled);
}
static void
gtk_action_muxer_group_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_enabled_changed (group->muxer, fullname, enabled);
g_free (fullname);
}
static void
gtk_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
}
static void
gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer,
const gchar *action_name,
GVariant *state)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_state_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, state);
g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state);
}
static void
gtk_action_muxer_group_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_state_changed (group->muxer, fullname, state);
g_free (fullname);
}
static void
gtk_action_muxer_parent_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_state_changed (muxer, action_name, state);
}
static void
gtk_action_muxer_action_added (GtkActionMuxer *muxer,
const gchar *action_name,
GActionGroup *original_group,
const gchar *orignal_action_name)
{
const GVariantType *parameter_type;
gboolean enabled;
GVariant *state;
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
if (action && action->watchers &&
g_action_group_query_action (original_group, orignal_action_name,
&enabled, ¶meter_type, NULL, NULL, &state))
{
GSList *node;
for (node = action->watchers; node; node = node->next)
gtk_action_observer_action_added (node->data,
GTK_ACTION_OBSERVABLE (muxer),
action_name, parameter_type, enabled, state);
if (state)
g_variant_unref (state);
}
g_action_group_action_added (G_ACTION_GROUP (muxer), action_name);
}
static void
gtk_action_muxer_action_added_to_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_added (group->muxer, fullname, action_group, action_name);
g_free (fullname);
}
static void
gtk_action_muxer_action_added_to_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_added (muxer, action_name, action_group, action_name);
}
static void
gtk_action_muxer_action_removed (GtkActionMuxer *muxer,
const gchar *action_name)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_removed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name);
g_action_group_action_removed (G_ACTION_GROUP (muxer), action_name);
}
static void
gtk_action_muxer_action_removed_from_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_removed (group->muxer, fullname);
g_free (fullname);
}
static void
gtk_action_muxer_action_removed_from_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_removed (muxer, action_name);
}
static gboolean
gtk_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
gboolean *enabled,
const GVariantType **parameter_type,
const GVariantType **state_type,
GVariant **state_hint,
GVariant **state)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
return g_action_group_query_action (group->group, unprefixed_name, enabled,
parameter_type, state_type, state_hint, state);
if (muxer->parent)
return g_action_group_query_action (G_ACTION_GROUP (muxer->parent), action_name,
enabled, parameter_type,
state_type, state_hint, state);
return FALSE;
}
static void
gtk_action_muxer_activate_action (GActionGroup *action_group,
const gchar *action_name,
GVariant *parameter)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
g_action_group_activate_action (group->group, unprefixed_name, parameter);
else if (muxer->parent)
g_action_group_activate_action (G_ACTION_GROUP (muxer->parent), action_name, parameter);
}
static void
gtk_action_muxer_change_action_state (GActionGroup *action_group,
const gchar *action_name,
GVariant *state)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
g_action_group_change_action_state (group->group, unprefixed_name, state);
else if (muxer->parent)
g_action_group_change_action_state (G_ACTION_GROUP (muxer->parent), action_name, state);
}
static void
gtk_action_muxer_unregister_internal (Action *action,
gpointer observer)
{
GtkActionMuxer *muxer = action->muxer;
GSList **ptr;
for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
if ((*ptr)->data == observer)
{
*ptr = g_slist_remove (*ptr, observer);
if (action->watchers == NULL)
g_hash_table_remove (muxer->observed_actions, action->fullname);
break;
}
}
static void
gtk_action_muxer_weak_notify (gpointer data,
GObject *where_the_object_was)
{
Action *action = data;
gtk_action_muxer_unregister_internal (action, where_the_object_was);
}
static void
gtk_action_muxer_register_observer (GtkActionObservable *observable,
const gchar *name,
GtkActionObserver *observer)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, name);
if (action == NULL)
{
action = g_slice_new (Action);
action->muxer = muxer;
action->fullname = g_strdup (name);
action->watchers = NULL;
g_hash_table_insert (muxer->observed_actions, action->fullname, action);
}
action->watchers = g_slist_prepend (action->watchers, observer);
g_object_weak_ref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
}
static void
gtk_action_muxer_unregister_observer (GtkActionObservable *observable,
const gchar *name,
GtkActionObserver *observer)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, name);
g_object_weak_unref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
gtk_action_muxer_unregister_internal (action, observer);
}
static void
gtk_action_muxer_free_group (gpointer data)
{
Group *group = data;
gint i;
/* 'for loop' or 'four loop'? */
for (i = 0; i < 4; i++)
g_signal_handler_disconnect (group->group, group->handler_ids[i]);
g_object_unref (group->group);
g_free (group->prefix);
g_slice_free (Group, group);
}
static void
gtk_action_muxer_free_action (gpointer data)
{
Action *action = data;
GSList *it;
for (it = action->watchers; it; it = it->next)
g_object_weak_unref (G_OBJECT (it->data), gtk_action_muxer_weak_notify, action);
g_slist_free (action->watchers);
g_free (action->fullname);
g_slice_free (Action, action);
}
static void
gtk_action_muxer_finalize (GObject *object)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0);
g_hash_table_unref (muxer->observed_actions);
g_hash_table_unref (muxer->groups);
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->finalize (object);
}
static void
gtk_action_muxer_dispose (GObject *object)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
if (muxer->parent)
{
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
g_clear_object (&muxer->parent);
}
g_hash_table_remove_all (muxer->observed_actions);
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->dispose (object);
}
static void
gtk_action_muxer_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
switch (property_id)
{
case PROP_PARENT:
g_value_set_object (value, gtk_action_muxer_get_parent (muxer));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gtk_action_muxer_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
switch (property_id)
{
case PROP_PARENT:
gtk_action_muxer_set_parent (muxer, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gtk_action_muxer_init (GtkActionMuxer *muxer)
{
muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_action);
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_group);
}
static void
gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface)
{
iface->register_observer = gtk_action_muxer_register_observer;
iface->unregister_observer = gtk_action_muxer_unregister_observer;
}
static void
gtk_action_muxer_group_iface_init (GActionGroupInterface *iface)
{
iface->list_actions = gtk_action_muxer_list_actions;
iface->query_action = gtk_action_muxer_query_action;
iface->activate_action = gtk_action_muxer_activate_action;
iface->change_action_state = gtk_action_muxer_change_action_state;
}
static void
gtk_action_muxer_class_init (GObjectClass *class)
{
class->get_property = gtk_action_muxer_get_property;
class->set_property = gtk_action_muxer_set_property;
class->finalize = gtk_action_muxer_finalize;
class->dispose = gtk_action_muxer_dispose;
properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent",
"The parent muxer",
GTK_TYPE_ACTION_MUXER,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (class, NUM_PROPERTIES, properties);
}
/**
* gtk_action_muxer_insert:
* @muxer: a #GtkActionMuxer
* @prefix: the prefix string for the action group
* @action_group: a #GActionGroup
*
* Adds the actions in @action_group to the list of actions provided by
* @muxer. @prefix is prefixed to each action name, such that for each
* action x in @action_group, there is an equivalent
* action @prefix.x in @muxer.
*
* For example, if @prefix is "app" and @action_group
* contains an action called "quit", then @muxer will
* now contain an action called "app.quit".
*
* If any #GtkActionObservers are registered for actions in the group,
* "action_added" notifications will be emitted, as appropriate.
*
* @prefix must not contain a dot ('.').
*/
void
gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group)
{
gchar **actions;
Group *group;
gint i;
/* TODO: diff instead of ripout and replace */
gtk_action_muxer_remove (muxer, prefix);
group = g_slice_new (Group);
group->muxer = muxer;
group->group = g_object_ref (action_group);
group->prefix = g_strdup (prefix);
g_hash_table_insert (muxer->groups, group->prefix, group);
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
gtk_action_muxer_action_added_to_group (group->group, actions[i], group);
g_strfreev (actions);
group->handler_ids[0] = g_signal_connect (group->group, "action-added",
G_CALLBACK (gtk_action_muxer_action_added_to_group), group);
group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
G_CALLBACK (gtk_action_muxer_action_removed_from_group), group);
group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
G_CALLBACK (gtk_action_muxer_group_action_enabled_changed), group);
group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
G_CALLBACK (gtk_action_muxer_group_action_state_changed), group);
}
/**
* gtk_action_muxer_remove:
* @muxer: a #GtkActionMuxer
* @prefix: the prefix of the action group to remove
*
* Removes a #GActionGroup from the #GtkActionMuxer.
*
* If any #GtkActionObservers are registered for actions in the group,
* "action_removed" notifications will be emitted, as appropriate.
*/
void
gtk_action_muxer_remove (GtkActionMuxer *muxer,
const gchar *prefix)
{
Group *group;
group = g_hash_table_lookup (muxer->groups, prefix);
if (group != NULL)
{
gchar **actions;
gint i;
g_hash_table_steal (muxer->groups, prefix);
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
gtk_action_muxer_action_removed_from_group (group->group, actions[i], group);
g_strfreev (actions);
gtk_action_muxer_free_group (group);
}
}
/**
* gtk_action_muxer_new:
*
* Creates a new #GtkActionMuxer.
*/
GtkActionMuxer *
gtk_action_muxer_new (void)
{
return g_object_new (GTK_TYPE_ACTION_MUXER, NULL);
}
/**
* gtk_action_muxer_get_parent:
* @muxer: a #GtkActionMuxer
*
* Returns: (transfer none): the parent of @muxer, or NULL.
*/
GtkActionMuxer *
gtk_action_muxer_get_parent (GtkActionMuxer *muxer)
{
g_return_val_if_fail (GTK_IS_ACTION_MUXER (muxer), NULL);
return muxer->parent;
}
/**
* gtk_action_muxer_set_parent:
* @muxer: a #GtkActionMuxer
* @parent: (allow-none): the new parent #GtkActionMuxer
*
* Sets the parent of @muxer to @parent.
*/
void
gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
GtkActionMuxer *parent)
{
g_return_if_fail (GTK_IS_ACTION_MUXER (muxer));
g_return_if_fail (parent == NULL || GTK_IS_ACTION_MUXER (parent));
if (muxer->parent == parent)
return;
if (muxer->parent != NULL)
{
gchar **actions;
gchar **it;
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
for (it = actions; *it; it++)
gtk_action_muxer_action_removed (muxer, *it);
g_strfreev (actions);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
g_object_unref (muxer->parent);
}
muxer->parent = parent;
if (muxer->parent != NULL)
{
gchar **actions;
gchar **it;
g_object_ref (muxer->parent);
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
for (it = actions; *it; it++)
gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
g_strfreev (actions);
g_signal_connect (muxer->parent, "action-added",
G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer);
g_signal_connect (muxer->parent, "action-removed",
G_CALLBACK (gtk_action_muxer_action_removed_from_parent), muxer);
g_signal_connect (muxer->parent, "action-enabled-changed",
G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer);
g_signal_connect (muxer->parent, "action-state-changed",
G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer);
}
g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]);
}
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkactionmuxer.h 0000664 0000000 0000000 00000004620 15212610716 020257 0 ustar /*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Author: Ryan Lortie
*/
#ifndef __GTK_ACTION_MUXER_H__
#define __GTK_ACTION_MUXER_H__
#include
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_MUXER (gtk_action_muxer_get_type ())
#define GTK_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_MUXER, GtkActionMuxer))
#define GTK_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_MUXER))
typedef struct _GtkActionMuxer GtkActionMuxer;
GType gtk_action_muxer_get_type (void);
GtkActionMuxer * gtk_action_muxer_new (void);
void gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group);
void gtk_action_muxer_remove (GtkActionMuxer *muxer,
const gchar *prefix);
GtkActionMuxer * gtk_action_muxer_get_parent (GtkActionMuxer *muxer);
void gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
GtkActionMuxer *parent);
G_END_DECLS
#endif /* __GTK_ACTION_MUXER_H__ */
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkactionobservable.c 0000664 0000000 0000000 00000005137 15212610716 021242 0 ustar /*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Ryan Lortie
*/
#include "config.h"
#include "gtkactionobservable.h"
G_DEFINE_INTERFACE (GtkActionObservable, gtk_action_observable, G_TYPE_OBJECT)
/*
* SECTION:gtkactionobserable
* @short_description: an interface implemented by objects that report
* changes to actions
*/
void
gtk_action_observable_default_init (GtkActionObservableInterface *iface)
{
}
/**
* gtk_action_observable_register_observer:
* @observable: a #GtkActionObservable
* @action_name: the name of the action
* @observer: the #GtkActionObserver to which the events will be reported
*
* Registers @observer as being interested in changes to @action_name on
* @observable.
*/
void
gtk_action_observable_register_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
->register_observer (observable, action_name, observer);
}
/**
* gtk_action_observable_unregister_observer:
* @observable: a #GtkActionObservable
* @action_name: the name of the action
* @observer: the #GtkActionObserver to which the events will be reported
*
* Removes the registration of @observer as being interested in changes
* to @action_name on @observable.
*
* If the observer was registered multiple times, it must be
* unregistered an equal number of times.
*/
void
gtk_action_observable_unregister_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
->unregister_observer (observable, action_name, observer);
}
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkactionobservable.h 0000664 0000000 0000000 00000005773 15212610716 021255 0 ustar /*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Ryan Lortie
*/
#ifndef __GTK_ACTION_OBSERVABLE_H__
#define __GTK_ACTION_OBSERVABLE_H__
#include "gtkactionobserver.h"
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_OBSERVABLE (gtk_action_observable_get_type ())
#define GTK_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_OBSERVABLE, GtkActionObservable))
#define GTK_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_OBSERVABLE))
#define GTK_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
GTK_TYPE_ACTION_OBSERVABLE, \
GtkActionObservableInterface))
typedef struct _GtkActionObservableInterface GtkActionObservableInterface;
struct _GtkActionObservableInterface
{
GTypeInterface g_iface;
void (* register_observer) (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
void (* unregister_observer) (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
};
GType gtk_action_observable_get_type (void);
void gtk_action_observable_register_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
void gtk_action_observable_unregister_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
G_END_DECLS
#endif /* __GTK_ACTION_OBSERVABLE_H__ */
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkactionobserver.c 0000664 0000000 0000000 00000013602 15212610716 020741 0 ustar /*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Ryan Lortie
*/
#include "config.h"
#include "gtkactionobserver.h"
G_DEFINE_INTERFACE (GtkActionObserver, gtk_action_observer, G_TYPE_OBJECT)
/**
* SECTION:gtkactionobserver
* @short_description: an interface implemented by objects that are
* interested in monitoring actions for changes
*
* GtkActionObserver is a simple interface allowing objects that wish to
* be notified of changes to actions to be notified of those changes.
*
* It is also possible to monitor changes to action groups using
* #GObject signals, but there are a number of reasons that this
* approach could become problematic:
*
* - there are four separate signals that must be manually connected
* and disconnected
*
* - when a large number of different observers wish to monitor a
* (usually disjoint) set of actions within the same action group,
* there is only one way to avoid having all notifications delivered
* to all observers: signal detail. In order to use signal detail,
* each action name must be quarked, which is not always practical.
*
* - even if quarking is acceptable, #GObject signal details are
* implemented by scanning a linked list, so there is no real
* decrease in complexity
*/
void
gtk_action_observer_default_init (GtkActionObserverInterface *class)
{
}
/**
* gtk_action_observer_action_added:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @enabled: %TRUE if the action is now enabled
* @parameter_type: the parameter type for action invocations, or %NULL
* if no parameter is required
* @state: the current state of the action, or %NULL if the action is
* stateless
*
* This function is called when an action that the observer is
* registered to receive events for is added.
*
* This function should only be called by objects with which the
* observer has explicitly registered itself to receive events.
*/
void
gtk_action_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_added (observer, observable, action_name, parameter_type, enabled, state);
}
/**
* gtk_action_observer_action_enabled_changed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @enabled: %TRUE if the action is now enabled
*
* This function is called when an action that the observer is
* registered to receive events for becomes enabled or disabled.
*
* This function should only be called by objects with which the
* observer has explicitly registered itself to receive events.
*/
void
gtk_action_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_enabled_changed (observer, observable, action_name, enabled);
}
/**
* gtk_action_observer_action_state_changed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @state: the new state of the action
*
* This function is called when an action that the observer is
* registered to receive events for changes to its state.
*
* This function should only be called by objects with which the
* observer has explicitly registered itself to receive events.
*/
void
gtk_action_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_state_changed (observer, observable, action_name, state);
}
/**
* gtk_action_observer_action_removed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
*
* This function is called when an action that the observer is
* registered to receive events for is removed.
*
* This function should only be called by objects with which the
* observer has explicitly registered itself to receive events.
*/
void
gtk_action_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_removed (observer, observable, action_name);
}
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkactionobserver.h 0000664 0000000 0000000 00000011645 15212610716 020753 0 ustar /*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Ryan Lortie
*/
#ifndef __GTK_ACTION_OBSERVER_H__
#define __GTK_ACTION_OBSERVER_H__
#include
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_OBSERVER (gtk_action_observer_get_type ())
#define GTK_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_OBSERVER, GtkActionObserver))
#define GTK_IS_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_OBSERVER))
#define GTK_ACTION_OBSERVER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
GTK_TYPE_ACTION_OBSERVER, GtkActionObserverInterface))
typedef struct _GtkActionObserverInterface GtkActionObserverInterface;
typedef struct _GtkActionObservable GtkActionObservable;
typedef struct _GtkActionObserver GtkActionObserver;
struct _GtkActionObserverInterface
{
GTypeInterface g_iface;
void (* action_added) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
void (* action_enabled_changed) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled);
void (* action_state_changed) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state);
void (* action_removed) (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name);
};
GType gtk_action_observer_get_type (void);
void gtk_action_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
void gtk_action_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled);
void gtk_action_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state);
void gtk_action_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name);
G_END_DECLS
#endif /* __GTK_ACTION_OBSERVER_H__ */
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkmenutracker.c 0000664 0000000 0000000 00000045550 15212610716 020243 0 ustar /*
* Copyright © 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Ryan Lortie
*/
#include "config.h"
#include "gtkmenutracker.h"
/**
* SECTION:gtkmenutracker
* @Title: GtkMenuTracker
* @Short_description: A helper class for interpreting #GMenuModel
*
* #GtkMenuTracker is a simple object to ease implementations of #GMenuModel.
* Given a #GtkActionObservable (usually a #GActionMuxer) along with a
* #GMenuModel, it will tell you which menu items to create and where to place
* them. If a menu item is removed, it will tell you the position of the menu
* item to remove.
*
* Using #GtkMenuTracker is fairly simple. The only guarantee you must make
* to #GtkMenuTracker is that you must obey all insert signals and track the
* position of items that #GtkMenuTracker gives you. That is, #GtkMenuTracker
* expects positions of all the latter items to change when it calls your
* insertion callback with an early position, as it may ask you to remove
* an item with a readjusted position later.
*
* #GtkMenuTracker will give you a #GtkMenuTrackerItem in your callback. You
* must hold onto this object until a remove signal is emitted. This item
* represents a single menu item, which can be one of three classes: normal item,
* separator, or submenu.
*
* Certain properties on the #GtkMenuTrackerItem are mutable, and you must
* listen for changes in the item. For more details, see the documentation
* for #GtkMenuTrackerItem along with https://live.gnome.org/GApplication/GMenuModel.
*
* The idea of @with_separators is for special cases where menu models may
* be tracked in places where separators are not available, like in toplevel
* "File", "Edit" menu bars. Ignoring separator items is wrong, as #GtkMenuTracker
* expects the position to change, so we must tell #GtkMenuTracker to ignore
* separators itself.
*/
typedef struct _GtkMenuTrackerSection GtkMenuTrackerSection;
struct _GtkMenuTracker
{
GtkActionObservable *observable;
GtkMenuTrackerInsertFunc insert_func;
GtkMenuTrackerRemoveFunc remove_func;
gpointer user_data;
GtkMenuTrackerSection *toplevel;
};
struct _GtkMenuTrackerSection
{
GMenuModel *model;
GSList *items;
gchar *action_namespace;
guint with_separators : 1;
guint has_separator : 1;
gulong handler;
};
static GtkMenuTrackerSection * gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
GMenuModel *model,
gboolean with_separators,
gint offset,
const gchar *action_namespace,
GPtrArray *items_already_created);
static void gtk_menu_tracker_section_free (GtkMenuTrackerSection *section);
static GtkMenuTrackerSection *
gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section,
GMenuModel *model,
gint *offset)
{
GSList *item;
if (section->has_separator)
(*offset)++;
if (section->model == model)
return section;
for (item = section->items; item; item = item->next)
{
GtkMenuTrackerSection *subsection = item->data;
if (subsection)
{
GtkMenuTrackerSection *found_section;
found_section = gtk_menu_tracker_section_find_model (subsection, model, offset);
if (found_section)
return found_section;
}
else
(*offset)++;
}
return FALSE;
}
/* this is responsible for syncing the showing of a separator for a
* single subsection (and its children).
*
* we only ever show separators if we have _actual_ children (ie: we do
* not show a separator if the section contains only empty child
* sections). it's difficult to determine this on-the-fly, so we have
* this separate function to come back later and figure it out.
*
* 'section' is that section.
*
* 'tracker' is passed in so that we can emit callbacks when we decide
* to add/remove separators.
*
* 'offset' is passed in so we know which position to emit in our
* callbacks. ie: if we add a separator right at the top of this
* section then we would emit it with this offset. deeper inside, we
* adjust accordingly.
*
* could_have_separator is true in two situations:
*
* - our parent section had with_separators defined and we are not the
* first section (ie: we should add a separator if we have content in
* order to divide us from the items above)
*
* - if we had a 'label' attribute set for this section
*
* parent_model and parent_index are passed in so that we can give them
* to the insertion callback so that it can see the label (and anything
* else that happens to be defined on the section).
*
* we iterate each item in ourselves. for subsections, we recursively
* run ourselves to sync separators. after we are done, we notice if we
* have any items in us or if we are completely empty and sync if our
* separator is shown or not.
*/
static gint
gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
GtkMenuTracker *tracker,
gint offset,
gboolean could_have_separator,
GMenuModel *parent_model,
gint parent_index)
{
gboolean should_have_separator;
gint n_items = 0;
GSList *item;
gint i = 0;
for (item = section->items; item; item = item->next)
{
GtkMenuTrackerSection *subsection = item->data;
if (subsection)
{
gboolean could_have_separator;
could_have_separator = (section->with_separators && i > 0) ||
g_menu_model_get_item_attribute (section->model, i, "label", "s", NULL);
n_items += gtk_menu_tracker_section_sync_separators (subsection, tracker, offset + n_items,
could_have_separator, section->model, i);
}
else
n_items++;
i++;
}
should_have_separator = could_have_separator && n_items != 0;
if (should_have_separator > section->has_separator)
{
/* Add a separator */
GtkMenuTrackerItem *item;
GPtrArray *items = g_ptr_array_new ();
item = _gtk_menu_tracker_item_new (tracker->observable, parent_model, parent_index, NULL, TRUE);
g_ptr_array_add (items, (gpointer) item);
(* tracker->insert_func) (items, offset, tracker->user_data);
g_ptr_array_unref (items);
g_object_unref (item);
section->has_separator = TRUE;
}
else if (should_have_separator < section->has_separator)
{
/* Remove a separator */
(* tracker->remove_func) (offset, 1, tracker->user_data);
section->has_separator = FALSE;
}
n_items += section->has_separator;
return n_items;
}
static gint
gtk_menu_tracker_section_measure (GtkMenuTrackerSection *section)
{
GSList *item;
gint n_items;
if (section == NULL)
return 1;
n_items = 0;
if (section->has_separator)
n_items++;
for (item = section->items; item; item = item->next)
n_items += gtk_menu_tracker_section_measure (item->data);
return n_items;
}
static void
gtk_menu_tracker_remove_items (GtkMenuTracker *tracker,
GSList **change_point,
gint offset,
gint n_items)
{
gint i;
gint n_total_items = 0;
for (i = 0; i < n_items; i++)
{
GtkMenuTrackerSection *subsection;
gint n;
subsection = (*change_point)->data;
*change_point = g_slist_delete_link (*change_point, *change_point);
n = gtk_menu_tracker_section_measure (subsection);
gtk_menu_tracker_section_free (subsection);
n_total_items += n;
}
if (n_total_items)
{
(* tracker->remove_func) (offset, n_total_items, tracker->user_data);
}
}
static void
gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
GtkMenuTrackerSection *section,
GSList **change_point,
gint offset,
GMenuModel *model,
gint position,
gint n_items,
GPtrArray *items_already_created
)
{
GPtrArray *items;
if (items_already_created)
{
items = items_already_created;
}
else
{
items = g_ptr_array_new ();
}
while (n_items--)
{
GMenuModel *submenu;
submenu = g_menu_model_get_item_link (model, position + n_items, G_MENU_LINK_SECTION);
g_assert (submenu != model);
if (submenu != NULL)
{
GtkMenuTrackerSection *subsection;
gchar *action_namespace = NULL;
g_menu_model_get_item_attribute (model, position + n_items,
G_MENU_ATTRIBUTE_ACTION_NAMESPACE, "s", &action_namespace);
if (section->action_namespace)
{
gchar *namespace;
namespace = g_strjoin (".", section->action_namespace, action_namespace, NULL);
subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, namespace, items_already_created);
g_free (namespace);
}
else
subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, section->action_namespace, items_already_created);
*change_point = g_slist_prepend (*change_point, subsection);
g_free (action_namespace);
g_object_unref (submenu);
}
else
{
GtkMenuTrackerItem *item;
item = _gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
section->action_namespace, FALSE);
g_ptr_array_insert (items, 0, (gpointer) item);
*change_point = g_slist_prepend (*change_point, NULL);
}
}
if (!items_already_created)
{
if (items->len)
{
(* tracker->insert_func) (items, offset, tracker->user_data);
for (gint i = 0; i < items->len; ++i)
g_object_unref(g_ptr_array_index(items, i));
}
g_ptr_array_unref (items);
}
}
static void
gtk_menu_tracker_model_changed (GMenuModel *model,
gint position,
gint removed,
gint added,
gpointer user_data)
{
GtkMenuTracker *tracker = user_data;
GtkMenuTrackerSection *section;
GSList **change_point;
gint offset = 0;
gint i;
/* First find which section the changed model corresponds to, and the
* position of that section within the overall menu.
*/
section = gtk_menu_tracker_section_find_model (tracker->toplevel, model, &offset);
/* Next, seek through that section to the change point. This gives us
* the correct GSList** to make the change to and also finds the final
* offset at which we will make the changes (by measuring the number
* of items within each item of the section before the change point).
*/
change_point = §ion->items;
for (i = 0; i < position; i++)
{
offset += gtk_menu_tracker_section_measure ((*change_point)->data);
change_point = &(*change_point)->next;
}
/* We remove items in order and add items in reverse order. This
* means that the offset used for all inserts and removes caused by a
* single change will be the same.
*
* This also has a performance advantage: GtkMenuShell stores the
* menu items in a linked list. In the case where we are creating a
* menu for the first time, adding the items in reverse order means
* that we only ever insert at index zero, prepending the list. This
* means that we can populate in O(n) time instead of O(n^2) that we
* would do by appending.
*/
gtk_menu_tracker_remove_items (tracker, change_point, offset, removed);
gtk_menu_tracker_add_items (tracker, section, change_point, offset, model, position, added, NULL);
/* The offsets for insertion/removal of separators will be all over
* the place, however...
*/
gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
}
static void
gtk_menu_tracker_section_free (GtkMenuTrackerSection *section)
{
if (section == NULL)
return;
g_signal_handler_disconnect (section->model, section->handler);
g_slist_free_full (section->items, (GDestroyNotify) gtk_menu_tracker_section_free);
g_free (section->action_namespace);
g_object_unref (section->model);
g_slice_free (GtkMenuTrackerSection, section);
}
static GtkMenuTrackerSection *
gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
GMenuModel *model,
gboolean with_separators,
gint offset,
const gchar *action_namespace,
GPtrArray *items_already_created)
{
GtkMenuTrackerSection *section;
section = g_slice_new0 (GtkMenuTrackerSection);
section->model = g_object_ref (model);
section->with_separators = with_separators;
section->action_namespace = g_strdup (action_namespace);
gtk_menu_tracker_add_items (tracker, section, §ion->items, offset, model, 0, g_menu_model_get_n_items (model), items_already_created);
section->handler = g_signal_connect (model, "items-changed", G_CALLBACK (gtk_menu_tracker_model_changed), tracker);
return section;
}
/*< private >
* gtk_menu_tracker_new:
* @model: the model to flatten
* @with_separators: if the toplevel should have separators (ie: TRUE
* for menus, FALSE for menubars)
* @action_namespace: the passed-in action namespace
* @insert_func: insert callback
* @remove_func: remove callback
* @user_data user data for callbacks
*
* Creates a GtkMenuTracker for @model, holding a ref on @model for as
* long as the tracker is alive.
*
* This flattens out the model, merging sections and inserting
* separators where appropriate. It monitors for changes and performs
* updates on the fly. It also handles action_namespace for subsections
* (but you will need to handle it yourself for submenus).
*
* When the tracker is first created, @insert_func will be called many
* times to populate the menu with the initial contents of @model
* (unless it is empty), before gtk_menu_tracker_new() returns. For
* this reason, the menu that is using the tracker ought to be empty
* when it creates the tracker.
*
* Future changes to @model will result in more calls to @insert_func
* and @remove_func.
*
* The position argument to both functions is the linear 0-based
* position in the menu at which the item in question should be inserted
* or removed.
*
* For @insert_func, @model and @item_index are used to get the
* information about the menu item to insert. @action_namespace is the
* action namespace that actions referred to from that item should place
* themselves in. Note that if the item is a submenu and the
* "action-namespace" attribute is defined on the item, it will _not_ be
* applied to the @action_namespace argument as it is meant for the
* items inside of the submenu, not the submenu item itself.
*
* @is_separator is set to %TRUE in case the item being added is a
* separator. @model and @item_index will still be meaningfully set in
* this case -- to the section menu item corresponding to the separator.
* This is useful if the section specifies a label, for example. If
* there is an "action-namespace" attribute on this menu item then it
* should be ignored by the consumer because #GtkMenuTracker has already
* handled it.
*
* When using #GtkMenuTracker there is no need to hold onto @model or
* monitor it for changes. The model will be unreffed when
* gtk_menu_tracker_free() is called.
*/
GtkMenuTracker *
gtk_menu_tracker_new (GtkActionObservable *observable,
GMenuModel *model,
gboolean with_separators,
const gchar *action_namespace,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data)
{
GtkMenuTracker *tracker;
tracker = g_slice_new (GtkMenuTracker);
tracker->observable = g_object_ref (observable);
tracker->insert_func = insert_func;
tracker->remove_func = remove_func;
tracker->user_data = user_data;
tracker->toplevel = gtk_menu_tracker_section_new (tracker, model, with_separators, 0, action_namespace, NULL);
gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
return tracker;
}
GtkMenuTracker *
gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data)
{
return gtk_menu_tracker_new (_gtk_menu_tracker_item_get_observable (item),
_gtk_menu_tracker_item_get_submenu (item),
TRUE,
_gtk_menu_tracker_item_get_submenu_namespace (item),
insert_func, remove_func, user_data);
}
/*< private >
* gtk_menu_tracker_free:
* @tracker: a #GtkMenuTracker
*
* Frees the tracker, ...
*/
void
gtk_menu_tracker_free (GtkMenuTracker *tracker)
{
gtk_menu_tracker_section_free (tracker->toplevel);
g_object_unref (tracker->observable);
g_slice_free (GtkMenuTracker, tracker);
}
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkmenutracker.h 0000664 0000000 0000000 00000005673 15212610716 020252 0 ustar /*
* Copyright © 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Ryan Lortie
*/
#ifndef __GTK_MENU_TRACKER_H__
#define __GTK_MENU_TRACKER_H__
#include "gtkmenutrackeritem.h"
typedef struct _GtkMenuTracker GtkMenuTracker;
typedef void (* GtkMenuTrackerInsertFunc) (GPtrArray *items,
gint position,
gpointer user_data);
typedef void (* GtkMenuTrackerRemoveFunc) (gint position,
gint n_items,
gpointer user_data);
GtkMenuTracker * gtk_menu_tracker_new (GtkActionObservable *observer,
GMenuModel *model,
gboolean with_separators,
const gchar *action_namespace,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data);
GtkMenuTracker * gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
GtkMenuTrackerInsertFunc insert_func,
GtkMenuTrackerRemoveFunc remove_func,
gpointer user_data);
void gtk_menu_tracker_free (GtkMenuTracker *tracker);
#endif /* __GTK_MENU_TRACKER_H__ */
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkmenutrackeritem.c 0000664 0000000 0000000 00000072612 15212610716 021121 0 ustar /*
* Copyright © 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Ryan Lortie
*/
#include "config.h"
#include "gtkmenutrackeritem.h"
/**
* SECTION:gtkmenutrackeritem
* @Title: GtkMenuTrackerItem
* @Short_description: Small helper for model menu items
*
* A #GtkMenuTrackerItem is a small helper class used by #GtkMenuTracker to
* represent menu items. It has one of three classes: normal item, separator,
* or submenu.
*
* If an item is one of the non-normal classes (submenu, separator), only the
* label of the item needs to be respected. Otherwise, all the properties
* of the item contribute to the item's appearance and state.
*
* Implementing the appearance of the menu item is up to toolkits, and certain
* toolkits may choose to ignore certain properties, like icon or accel. The
* role of the item determines its accessibility role, along with its
* decoration if the GtkMenuTrackerItem::toggled property is true. As an
* example, if the item has the role %GTK_MENU_TRACKER_ITEM_ROLE_CHECK and
* GtkMenuTrackerItem::toggled is %FALSE, its accessible role should be that of
* a check menu item, and no decoration should be drawn. But if
* GtkMenuTrackerItem::toggled is %TRUE, a checkmark should be drawn.
*
* All properties except for the two class-determining properties,
* GtkMenuTrackerItem::is-separator and GtkMenuTrackerItem::has-submenu are
* allowed to change, so listen to the notify signals to update your item's
* appearance. When using a GObject library, this can conveniently be done
* with g_object_bind_property() and #GBinding, and this is how this is
* implemented in GTK+; the appearance side is implemented in #GtkModelMenuItem.
*
* When an item is clicked, simply call gtk_menu_tracker_item_activated() in
* response. The #GtkMenuTrackerItem will take care of everything related to
* activating the item and will itself update the state of all items in
* response.
*
* Submenus are a special case of menu item. When an item is a submenu, you
* should create a submenu for it with gtk_menu_tracker_new_item_for_submenu(),
* and apply the same menu tracking logic you would for a toplevel menu.
* Applications using submenus may want to lazily build their submenus in
* response to the user clicking on it, as building a submenu may be expensive.
*
* Thus, the submenu has two special controls -- the submenu's visibility
* should be controlled by the GtkMenuTrackerItem::submenu-shown property,
* and if a user clicks on the submenu, do not immediately show the menu,
* but call gtk_menu_tracker_item_request_submenu_shown() and wait for the
* GtkMenuTrackerItem::submenu-shown property to update. If the user navigates,
* the application may want to be notified so it can cancel the expensive
* operation that it was using to build the submenu. Thus,
* gtk_menu_tracker_item_request_submenu_shown() takes a boolean parameter.
* Use %TRUE when the user wants to open the submenu, and %FALSE when the
* user wants to close the submenu.
*/
typedef GObjectClass GtkMenuTrackerItemClass;
struct _GtkMenuTrackerItem
{
GObject parent_instance;
GtkActionObservable *observable;
gchar *action_namespace;
GMenuItem *item;
GtkMenuTrackerItemRole role : 4;
guint is_separator : 1;
guint can_activate : 1;
guint sensitive : 1;
guint toggled : 1;
guint submenu_shown : 1;
guint submenu_requested : 1;
GVariant *action_state;
};
enum {
PROP_0,
PROP_IS_SEPARATOR,
PROP_HAS_SUBMENU,
PROP_LABEL,
PROP_ICON,
PROP_SENSITIVE,
PROP_VISIBLE,
PROP_ROLE,
PROP_TOGGLED,
PROP_ACCEL,
PROP_SUBMENU_SHOWN,
PROP_ACTION_NAME,
PROP_ACTION_STATE,
N_PROPS
};
static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS];
static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVER, gtk_menu_tracker_item_init_observer_iface))
GType
gtk_menu_tracker_item_role_get_type (void)
{
static gsize gtk_menu_tracker_item_role_type;
if (g_once_init_enter (>k_menu_tracker_item_role_type))
{
static const GEnumValue values[] = {
{ GTK_MENU_TRACKER_ITEM_ROLE_NORMAL, "GTK_MENU_TRACKER_ITEM_ROLE_NORMAL", "normal" },
{ GTK_MENU_TRACKER_ITEM_ROLE_CHECK, "GTK_MENU_TRACKER_ITEM_ROLE_CHECK", "check" },
{ GTK_MENU_TRACKER_ITEM_ROLE_RADIO, "GTK_MENU_TRACKER_ITEM_ROLE_RADIO", "radio" },
{ 0, NULL, NULL }
};
GType type;
type = g_enum_register_static ("GtkMenuTrackerItemRole", values);
g_once_init_leave (>k_menu_tracker_item_role_type, type);
}
return gtk_menu_tracker_item_role_type;
}
static void
gtk_menu_tracker_item_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object);
switch (prop_id)
{
case PROP_IS_SEPARATOR:
g_value_set_boolean (value, gtk_menu_tracker_item_get_is_separator (self));
break;
case PROP_HAS_SUBMENU:
g_value_set_boolean (value, gtk_menu_tracker_item_get_has_submenu (self));
break;
case PROP_LABEL:
g_value_set_string (value, gtk_menu_tracker_item_get_label (self));
break;
case PROP_ICON:
g_value_set_object (value, gtk_menu_tracker_item_get_icon (self));
break;
case PROP_SENSITIVE:
g_value_set_boolean (value, gtk_menu_tracker_item_get_sensitive (self));
break;
case PROP_VISIBLE:
g_value_set_boolean (value, gtk_menu_tracker_item_get_visible (self));
break;
case PROP_ROLE:
g_value_set_enum (value, gtk_menu_tracker_item_get_role (self));
break;
case PROP_TOGGLED:
g_value_set_boolean (value, gtk_menu_tracker_item_get_toggled (self));
break;
case PROP_ACCEL:
g_value_set_string (value, gtk_menu_tracker_item_get_accel (self));
break;
case PROP_SUBMENU_SHOWN:
g_value_set_boolean (value, gtk_menu_tracker_item_get_submenu_shown (self));
break;
case PROP_ACTION_NAME:
g_value_take_string (value, gtk_menu_tracker_item_get_action_name (self));
case PROP_ACTION_STATE:
g_value_set_variant (value, self->action_state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_menu_tracker_item_finalize (GObject *object)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (object);
g_free (self->action_namespace);
if (self->observable)
g_object_unref (self->observable);
if (self->action_state)
g_variant_unref (self->action_state);
g_object_unref (self->item);
G_OBJECT_CLASS (gtk_menu_tracker_item_parent_class)->finalize (object);
}
static void
gtk_menu_tracker_item_init (GtkMenuTrackerItem * self)
{
}
static void
gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
{
class->get_property = gtk_menu_tracker_item_get_property;
class->finalize = gtk_menu_tracker_item_finalize;
gtk_menu_tracker_item_pspecs[PROP_IS_SEPARATOR] =
g_param_spec_boolean ("is-separator", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_HAS_SUBMENU] =
g_param_spec_boolean ("has-submenu", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_LABEL] =
g_param_spec_string ("label", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ICON] =
g_param_spec_object ("icon", "", "", G_TYPE_ICON, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_SENSITIVE] =
g_param_spec_boolean ("sensitive", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_VISIBLE] =
g_param_spec_boolean ("visible", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ROLE] =
g_param_spec_enum ("role", "", "",
GTK_TYPE_MENU_TRACKER_ITEM_ROLE, GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_TOGGLED] =
g_param_spec_boolean ("toggled", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ACCEL] =
g_param_spec_string ("accel", "", "", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN] =
g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ACTION_NAME] =
g_param_spec_boolean ("action-name", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE] =
g_param_spec_boolean ("action-state", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs);
}
static void
gtk_menu_tracker_item_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
GVariant *action_target;
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
self->can_activate = (action_target == NULL && parameter_type == NULL) ||
(action_target != NULL && parameter_type != NULL &&
g_variant_is_of_type (action_target, parameter_type));
if (!self->can_activate)
{
if (action_target)
g_variant_unref (action_target);
return;
}
self->sensitive = enabled;
if (action_target != NULL && state != NULL)
{
self->toggled = g_variant_equal (state, action_target);
self->role = GTK_MENU_TRACKER_ITEM_ROLE_RADIO;
}
else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
{
self->toggled = g_variant_get_boolean (state);
self->role = GTK_MENU_TRACKER_ITEM_ROLE_CHECK;
}
g_object_freeze_notify (G_OBJECT (self));
if (self->sensitive)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
if (self->toggled)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
if (state != NULL)
{
self->action_state = g_variant_ref (state);
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE]);
}
g_object_thaw_notify (G_OBJECT (self));
if (action_target)
g_variant_unref (action_target);
}
static void
gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
if (!self->can_activate)
return;
if (self->sensitive == enabled)
return;
self->sensitive = enabled;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
}
static void
gtk_menu_tracker_item_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
GVariant *action_target;
gboolean was_toggled;
if (!self->can_activate)
return;
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
was_toggled = self->toggled;
if (action_target)
{
self->toggled = g_variant_equal (state, action_target);
g_variant_unref (action_target);
}
else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
self->toggled = g_variant_get_boolean (state);
else
self->toggled = FALSE;
if (self->toggled != was_toggled)
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
if (self->action_state)
g_variant_unref (self->action_state);
self->action_state = g_variant_ref (state);
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE]);
}
static void
gtk_menu_tracker_item_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
if (!self->can_activate)
return;
g_object_freeze_notify (G_OBJECT (self));
if (self->sensitive)
{
self->sensitive = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
}
if (self->toggled)
{
self->toggled = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
}
if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
{
self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
}
if (self->action_state != NULL)
{
g_variant_unref (self->action_state);
self->action_state = NULL;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACTION_STATE]);
}
g_object_thaw_notify (G_OBJECT (self));
}
static void
gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface)
{
iface->action_added = gtk_menu_tracker_item_action_added;
iface->action_enabled_changed = gtk_menu_tracker_item_action_enabled_changed;
iface->action_state_changed = gtk_menu_tracker_item_action_state_changed;
iface->action_removed = gtk_menu_tracker_item_action_removed;
}
GtkMenuTrackerItem *
_gtk_menu_tracker_item_new (GtkActionObservable *observable,
GMenuModel *model,
gint item_index,
const gchar *action_namespace,
gboolean is_separator)
{
GtkMenuTrackerItem *self;
const gchar *action_name;
g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL);
g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
self = g_object_new (GTK_TYPE_MENU_TRACKER_ITEM, NULL);
self->item = g_menu_item_new_from_model (model, item_index);
self->action_namespace = g_strdup (action_namespace);
self->observable = g_object_ref (observable);
self->is_separator = is_separator;
if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name))
{
GActionGroup *group = G_ACTION_GROUP (observable);
const GVariantType *parameter_type;
gboolean enabled;
GVariant *state;
gboolean found;
state = NULL;
if (action_namespace)
{
gchar *full_action;
full_action = g_strjoin (".", action_namespace, action_name, NULL);
gtk_action_observable_register_observer (self->observable, full_action, GTK_ACTION_OBSERVER (self));
found = g_action_group_query_action (group, full_action, &enabled, ¶meter_type, NULL, NULL, &state);
g_free (full_action);
}
else
{
gtk_action_observable_register_observer (self->observable, action_name, GTK_ACTION_OBSERVER (self));
found = g_action_group_query_action (group, action_name, &enabled, ¶meter_type, NULL, NULL, &state);
}
if (found)
gtk_menu_tracker_item_action_added (GTK_ACTION_OBSERVER (self), observable, NULL, parameter_type, enabled, state);
else
gtk_menu_tracker_item_action_removed (GTK_ACTION_OBSERVER (self), observable, NULL);
if (state)
g_variant_unref (state);
}
else
{
gboolean submenu_enabled;
if (g_menu_item_get_attribute (self->item, "submenu-enabled", "b", &submenu_enabled))
{
self->sensitive = submenu_enabled;
}
else
{
self->sensitive = TRUE;
}
}
return self;
}
GtkActionObservable *
_gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self)
{
return self->observable;
}
/**
* gtk_menu_tracker_item_get_is_separator:
* @self: A #GtkMenuTrackerItem instance
*
* Returns whether the menu item is a separator. If so, only
* certain properties may need to be obeyed. See the documentation
* for #GtkMenuTrackerItem.
*/
gboolean
gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self)
{
return self->is_separator;
}
/**
* gtk_menu_tracker_item_get_has_submenu:
* @self: A #GtkMenuTrackerItem instance
*
* Returns whether the menu item has a submenu. If so, only
* certain properties may need to be obeyed. See the documentation
* for #GtkMenuTrackerItem.
*/
gboolean
gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self)
{
GMenuModel *link;
link = g_menu_item_get_link (self->item, G_MENU_LINK_SUBMENU);
if (link)
{
g_object_unref (link);
return TRUE;
}
else
return FALSE;
}
const gchar *
gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self)
{
const gchar *label = NULL;
g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_LABEL, "&s", &label);
return label;
}
/**
* gtk_menu_tracker_item_get_icon:
*
* Returns: (transfer full):
*/
GIcon *
gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self)
{
GVariant *icon_data;
GIcon *icon;
icon_data = g_menu_item_get_attribute_value (self->item, "icon", NULL);
if (icon_data == NULL)
return NULL;
icon = g_icon_deserialize (icon_data);
g_variant_unref (icon_data);
return icon;
}
gboolean
gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self)
{
return self->sensitive;
}
gboolean
gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self)
{
return TRUE;
}
GtkMenuTrackerItemRole
gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self)
{
return self->role;
}
gboolean
gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self)
{
return self->toggled;
}
const gchar *
gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self)
{
const gchar *accel = NULL;
g_menu_item_get_attribute (self->item, "accel", "&s", &accel);
return accel;
}
GMenuModel *
_gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self)
{
return g_menu_item_get_link (self->item, "submenu");
}
gchar *
_gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self)
{
const gchar *namespace;
if (g_menu_item_get_attribute (self->item, "action-namespace", "&s", &namespace))
{
if (self->action_namespace)
return g_strjoin (".", self->action_namespace, namespace, NULL);
else
return g_strdup (namespace);
}
else
return g_strdup (self->action_namespace);
}
gboolean
gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self)
{
return g_menu_item_get_attribute (self->item, "submenu-action", "&s", NULL);
}
gboolean
gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self)
{
return self->submenu_shown;
}
/**
* gtk_menu_tracker_item_get_action_name:
* @self: A #GtkMenuTrackerItem instance
*
* Returns a newly-allocated string containing the name of the action
* associated with this menu item.
*
* Returns: (transfer full): the action name, free it with g_free()
*/
gchar *
gtk_menu_tracker_item_get_action_name (GtkMenuTrackerItem *self)
{
const gchar *action_name;
if (!g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name))
return NULL;
if (self->action_namespace)
return g_strjoin (".", self->action_namespace, action_name, NULL);
else
return g_strdup (action_name);
}
GVariant *
gtk_menu_tracker_item_get_action_state (GtkMenuTrackerItem *self)
{
if (self->action_state != NULL)
return g_variant_ref (self->action_state);
return NULL;
}
const gchar *
gtk_menu_tracker_item_get_action_namespace (GtkMenuTrackerItem *self)
{
return self->action_namespace;
}
static void
gtk_menu_tracker_item_set_submenu_shown (GtkMenuTrackerItem *self,
gboolean submenu_shown)
{
if (submenu_shown == self->submenu_shown)
return;
self->submenu_shown = submenu_shown;
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN]);
}
void
gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self)
{
const gchar *action_name;
GVariant *action_target;
g_return_if_fail (GTK_IS_MENU_TRACKER_ITEM (self));
if (!self->can_activate)
return;
g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name);
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
if (self->action_namespace)
{
gchar *full_action;
full_action = g_strjoin (".", self->action_namespace, action_name, NULL);
g_action_group_activate_action (G_ACTION_GROUP (self->observable), full_action, action_target);
g_free (full_action);
}
else
g_action_group_activate_action (G_ACTION_GROUP (self->observable), action_name, action_target);
if (action_target)
g_variant_unref (action_target);
}
void
gtk_menu_tracker_item_change_state (GtkMenuTrackerItem *self,
GVariant *value)
{
const gchar *action_name;
g_return_if_fail (GTK_IS_MENU_TRACKER_ITEM (self));
g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name);
if (self->action_namespace)
{
gchar *full_action;
full_action = g_strjoin (".", self->action_namespace, action_name, NULL);
g_action_group_change_action_state (G_ACTION_GROUP (self->observable), full_action, g_variant_ref(value));
g_free (full_action);
}
else
g_action_group_change_action_state (G_ACTION_GROUP (self->observable), action_name, g_variant_ref(value));
}
typedef struct
{
GtkMenuTrackerItem *item;
gchar *submenu_action;
gboolean first_time;
} GtkMenuTrackerOpener;
static void
gtk_menu_tracker_opener_update (GtkMenuTrackerOpener *opener)
{
GActionGroup *group = G_ACTION_GROUP (opener->item->observable);
gboolean is_open = TRUE;
/* We consider the menu as being "open" if the action does not exist
* or if there is another problem (no state, wrong state type, etc.).
* If the action exists, with the correct state then we consider it
* open if we have ever seen this state equal to TRUE.
*
* In the event that we see the state equal to FALSE, we force it back
* to TRUE. We do not signal that the menu was closed because this is
* likely to create UI thrashing.
*
* The only way the menu can have a true-to-false submenu-shown
* transition is if the user calls _request_submenu_shown (FALSE).
* That is handled in _free() below.
*/
if (g_action_group_has_action (group, opener->submenu_action))
{
GVariant *state = g_action_group_get_action_state (group, opener->submenu_action);
if (state)
{
if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
is_open = g_variant_get_boolean (state);
g_variant_unref (state);
}
}
/* If it is already open, signal that.
*
* If it is not open, ask it to open.
*/
if (is_open)
gtk_menu_tracker_item_set_submenu_shown (opener->item, TRUE);
if (!is_open || opener->first_time)
{
g_action_group_change_action_state (group, opener->submenu_action, g_variant_new_boolean (TRUE));
opener->first_time = FALSE;
}
}
static void
gtk_menu_tracker_opener_added (GActionGroup *group,
const gchar *action_name,
gpointer user_data)
{
GtkMenuTrackerOpener *opener = user_data;
if (g_str_equal (action_name, opener->submenu_action))
gtk_menu_tracker_opener_update (opener);
}
static void
gtk_menu_tracker_opener_removed (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GtkMenuTrackerOpener *opener = user_data;
if (g_str_equal (action_name, opener->submenu_action))
gtk_menu_tracker_opener_update (opener);
}
static void
gtk_menu_tracker_opener_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *new_state,
gpointer user_data)
{
GtkMenuTrackerOpener *opener = user_data;
if (g_str_equal (action_name, opener->submenu_action))
gtk_menu_tracker_opener_update (opener);
}
static void
gtk_menu_tracker_opener_free (gpointer data)
{
GtkMenuTrackerOpener *opener = data;
g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_added, opener);
g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_removed, opener);
g_signal_handlers_disconnect_by_func (opener->item->observable, gtk_menu_tracker_opener_changed, opener);
g_action_group_change_action_state (G_ACTION_GROUP (opener->item->observable),
opener->submenu_action,
g_variant_new_boolean (FALSE));
gtk_menu_tracker_item_set_submenu_shown (opener->item, FALSE);
g_free (opener->submenu_action);
g_slice_free (GtkMenuTrackerOpener, opener);
}
static GtkMenuTrackerOpener *
gtk_menu_tracker_opener_new (GtkMenuTrackerItem *item,
const gchar *submenu_action)
{
GtkMenuTrackerOpener *opener;
opener = g_slice_new (GtkMenuTrackerOpener);
opener->first_time = TRUE;
opener->item = item;
if (item->action_namespace)
opener->submenu_action = g_strjoin (".", item->action_namespace, submenu_action, NULL);
else
opener->submenu_action = g_strdup (submenu_action);
g_signal_connect (item->observable, "action-added", G_CALLBACK (gtk_menu_tracker_opener_added), opener);
g_signal_connect (item->observable, "action-removed", G_CALLBACK (gtk_menu_tracker_opener_removed), opener);
g_signal_connect (item->observable, "action-state-changed", G_CALLBACK (gtk_menu_tracker_opener_changed), opener);
gtk_menu_tracker_opener_update (opener);
return opener;
}
void
gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
gboolean shown)
{
const gchar *submenu_action;
gboolean has_submenu_action;
if (shown == self->submenu_requested)
return;
has_submenu_action = g_menu_item_get_attribute (self->item, "submenu-action", "&s", &submenu_action);
self->submenu_requested = shown;
/* If we have a submenu action, start a submenu opener and wait
* for the reply from the client. Otherwise, simply open the
* submenu immediately.
*/
if (has_submenu_action)
{
if (shown)
g_object_set_data_full (G_OBJECT (self), "submenu-opener",
gtk_menu_tracker_opener_new (self, submenu_action),
gtk_menu_tracker_opener_free);
else
g_object_set_data (G_OBJECT (self), "submenu-opener", NULL);
}
else
gtk_menu_tracker_item_set_submenu_shown (self, shown);
}
gboolean
gtk_menu_tracker_item_get_attribute (GtkMenuTrackerItem *self,
const gchar *attribute,
const gchar *format,
...)
{
gboolean success = FALSE;
GVariant *value;
g_return_val_if_fail (GTK_IS_MENU_TRACKER_ITEM (self), FALSE);
g_return_val_if_fail (attribute != NULL, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
value = g_menu_item_get_attribute_value (self->item, attribute, NULL);
if (value)
{
if (g_variant_check_format_string (value, format, TRUE))
{
va_list args;
va_start (args, format);
g_variant_get_va (value, format, NULL, &args);
va_end (args);
success = TRUE;
}
g_variant_unref (value);
}
return success;
}
GVariant *
gtk_menu_tracker_item_get_attribute_value (GtkMenuTrackerItem *self,
const gchar *attribute,
const GVariantType *expected_type)
{
return g_menu_item_get_attribute_value (self->item, attribute, expected_type);
}
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtkmenutrackeritem.h 0000664 0000000 0000000 00000012320 15212610716 021114 0 ustar /*
* Copyright © 2011, 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Author: Ryan Lortie
*/
#ifndef __GTK_MENU_TRACKER_ITEM_H__
#define __GTK_MENU_TRACKER_ITEM_H__
#include "gtkactionobservable.h"
#define GTK_TYPE_MENU_TRACKER_ITEM (gtk_menu_tracker_item_get_type ())
#define GTK_MENU_TRACKER_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_MENU_TRACKER_ITEM, GtkMenuTrackerItem))
#define GTK_IS_MENU_TRACKER_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_MENU_TRACKER_ITEM))
typedef struct _GtkMenuTrackerItem GtkMenuTrackerItem;
#define GTK_TYPE_MENU_TRACKER_ITEM_ROLE (gtk_menu_tracker_item_role_get_type ())
typedef enum {
GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
GTK_MENU_TRACKER_ITEM_ROLE_CHECK,
GTK_MENU_TRACKER_ITEM_ROLE_RADIO,
} GtkMenuTrackerItemRole;
GType gtk_menu_tracker_item_get_type (void) G_GNUC_CONST;
GType gtk_menu_tracker_item_role_get_type (void) G_GNUC_CONST;
GtkMenuTrackerItem * _gtk_menu_tracker_item_new (GtkActionObservable *observable,
GMenuModel *model,
gint item_index,
const gchar *action_namespace,
gboolean is_separator);
GtkActionObservable * _gtk_menu_tracker_item_get_observable (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_is_separator (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_has_submenu (GtkMenuTrackerItem *self);
const gchar * gtk_menu_tracker_item_get_label (GtkMenuTrackerItem *self);
GIcon * gtk_menu_tracker_item_get_icon (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_sensitive (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_visible (GtkMenuTrackerItem *self);
GtkMenuTrackerItemRole gtk_menu_tracker_item_get_role (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self);
const gchar * gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self);
GMenuModel * _gtk_menu_tracker_item_get_submenu (GtkMenuTrackerItem *self);
gchar * _gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self);
void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self);
void gtk_menu_tracker_item_change_state (GtkMenuTrackerItem *self,
GVariant *value);
void gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
gboolean shown);
gboolean gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self);
gchar * gtk_menu_tracker_item_get_action_name (GtkMenuTrackerItem *self);
GVariant * gtk_menu_tracker_item_get_action_state (GtkMenuTrackerItem *self);
const gchar * gtk_menu_tracker_item_get_action_namespace (GtkMenuTrackerItem *self);
gboolean gtk_menu_tracker_item_get_attribute (GtkMenuTrackerItem *self,
const gchar *attribute,
const gchar *format,
...);
GVariant * gtk_menu_tracker_item_get_attribute_value (GtkMenuTrackerItem *self,
const gchar *attribute,
const GVariantType *expected_type);
#endif
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtksimpleactionobserver.c 0000664 0000000 0000000 00000013477 15212610716 022165 0 ustar /*
* Copyright © 2013 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Nick Dedekind observable);
g_free(self->action_name);
G_OBJECT_CLASS (gtk_simple_action_observer_parent_class)->finalize (object);
}
static void
gtk_simple_action_observer_init (GtkSimpleActionObserver * self)
{
}
static void
gtk_simple_action_observer_class_init (GtkSimpleActionObserverClass *class)
{
class->finalize = gtk_simple_action_observer_finalize;
}
static void
gtk_simple_action_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
GtkSimpleActionObserver* self;
self = GTK_SIMPLE_ACTION_OBSERVER (observer);
self->action_added(self, action_name, enabled, state);
}
static void
gtk_simple_action_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
GtkSimpleActionObserver* self;
self = GTK_SIMPLE_ACTION_OBSERVER (observer);
self->action_enabled_changed(self, action_name, enabled);
}
static void
gtk_simple_action_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
GtkSimpleActionObserver* self;
self = GTK_SIMPLE_ACTION_OBSERVER (observer);
self->action_state_changed(self, action_name, state);
}
static void
gtk_simple_action_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
GtkSimpleActionObserver* self;
self = GTK_SIMPLE_ACTION_OBSERVER (observer);
self->action_removed(self, action_name);
}
static void
gtk_simple_action_observer_init_observer_iface (GtkActionObserverInterface *iface)
{
iface->action_added = gtk_simple_action_observer_action_added;
iface->action_enabled_changed = gtk_simple_action_observer_action_enabled_changed;
iface->action_state_changed = gtk_simple_action_observer_action_state_changed;
iface->action_removed = gtk_simple_action_observer_action_removed;
}
GtkSimpleActionObserver*
gtk_simple_action_observer_new (GtkActionObservable *observable,
GtkActionAddedFunc action_added,
GtkActionEnabledChangedFunc action_enabled_changed,
GtkActionStateChangedFunc action_state_changed,
GtkActionRemovedFunc action_removed)
{
GtkSimpleActionObserver* self;
self = g_object_new (GTK_TYPE_SIMPLE_ACTION_OBSERVER, NULL);
self->observable = g_object_ref (observable);
self->action_name = NULL;
self->action_added = action_added;
self->action_enabled_changed = action_enabled_changed;
self->action_state_changed = action_state_changed;
self->action_removed = action_removed;
return self;
}
void
gtk_simple_action_observer_register_action (GtkSimpleActionObserver *self,
const gchar *action_name)
{
gtk_simple_action_observer_unregister_action(self);
if (action_name && g_strcmp0(action_name, "") != 0) {
self->action_name = g_strdup (action_name);
if (g_strcmp0(self->action_name, "") != 0) {
gtk_action_observable_register_observer (self->observable, self->action_name, GTK_ACTION_OBSERVER (self));
}
}
}
void
gtk_simple_action_observer_unregister_action (GtkSimpleActionObserver *self)
{
if (self->action_name) {
gtk_action_observable_unregister_observer(self->observable, self->action_name, GTK_ACTION_OBSERVER (self));
g_free(self->action_name);
self->action_name = NULL;
}
}
qmenumodel-0.10.0/libqmenumodel/src/gtk/gtksimpleactionobserver.h 0000664 0000000 0000000 00000006641 15212610716 022165 0 ustar /*
* Copyright © 2013 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors: Nick Dedekind