aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzr-builddeb/default.conf2
-rw-r--r--COPYING.GPLv3674
-rw-r--r--Makefile.am1
-rw-r--r--NEWS7
-rw-r--r--common/Makefile.am32
-rw-r--r--common/com.canonical.indicator.messages.application.xml39
-rw-r--r--common/com.canonical.indicator.messages.service.xml (renamed from src/messages-service.xml)0
-rw-r--r--configure.ac5
-rw-r--r--debian/changelog912
-rw-r--r--debian/compat1
-rw-r--r--debian/control84
-rw-r--r--debian/copyright19
-rw-r--r--debian/gir1.2-messagingmenu-1.0.install1
-rw-r--r--debian/indicator-messages.install5
-rw-r--r--debian/libmessaging-menu-dev.install5
-rw-r--r--debian/libmessaging-menu0.install1
-rw-r--r--debian/libmessaging-menu0.symbols38
-rwxr-xr-xdebian/rules17
-rw-r--r--debian/source/format1
-rw-r--r--debian/watch2
-rw-r--r--doc/reference/Makefile.am4
-rw-r--r--doc/reference/messaging-menu-docs.xml.in3
-rw-r--r--libmessaging-menu/Makefile.am37
-rw-r--r--libmessaging-menu/gtupleaction.c354
-rw-r--r--libmessaging-menu/gtupleaction.h40
-rw-r--r--libmessaging-menu/messaging-menu-app.c (renamed from libmessaging-menu/messaging-menu.c)704
-rw-r--r--libmessaging-menu/messaging-menu-app.h163
-rw-r--r--libmessaging-menu/messaging-menu-message.c547
-rw-r--r--libmessaging-menu/messaging-menu-message.h70
-rw-r--r--libmessaging-menu/messaging-menu.h125
-rw-r--r--po/indicator-messages.pot46
-rw-r--r--src/Makefile.am36
-rw-r--r--src/app-section.c424
-rw-r--r--src/dbus-data.h17
-rw-r--r--src/gactionmuxer.c8
-rw-r--r--src/gactionmuxer.h3
-rw-r--r--src/im-application-list.c880
-rw-r--r--src/im-application-list.h52
-rw-r--r--src/im-phone-menu.c331
-rw-r--r--src/im-phone-menu.h70
-rw-r--r--src/messages-service.c590
-rw-r--r--test/Makefile.am5
-rw-r--r--test/indicator-messages-service-activate.c2
-rw-r--r--test/test-gactionmuxer.cpp26
44 files changed, 4903 insertions, 1480 deletions
diff --git a/.bzr-builddeb/default.conf b/.bzr-builddeb/default.conf
new file mode 100644
index 0000000..6c96a98
--- /dev/null
+++ b/.bzr-builddeb/default.conf
@@ -0,0 +1,2 @@
+[BUILDDEB]
+split = True
diff --git a/COPYING.GPLv3 b/COPYING.GPLv3
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING.GPLv3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Makefile.am b/Makefile.am
index daeb2b7..f8141a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,6 @@
SUBDIRS = \
+ common \
src \
libmessaging-menu \
data \
diff --git a/NEWS b/NEWS
index 629218d..341594a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,11 @@
+12.10.5
+
+* fix crash caused by GError not being cleared (lp #1064314)
+* fix crash when registering an app that was previously unregistered (lp #1065169)
+* remove the icon if NULL is passed to source_set_icon (lp #1070421)
+* call gtk-update-icon-cache (lp #1060618)
+
12.10.4
* specify fallback icons for the ones with status emblem (lp #1056595)
diff --git a/common/Makefile.am b/common/Makefile.am
new file mode 100644
index 0000000..0b8bad4
--- /dev/null
+++ b/common/Makefile.am
@@ -0,0 +1,32 @@
+
+noinst_LTLIBRARIES = libmessaging-common.la
+
+indicator-messages-service.c: com.canonical.indicator.messages.service.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix com.canonical.indicator.messages. \
+ --generate-c-code indicator-messages-service \
+ --c-namespace IndicatorMessages \
+ $^
+indicator-messages-service.h: indicator-messages-service.c
+
+indicator-messages-application.c: com.canonical.indicator.messages.application.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix com.canonical.indicator.messages. \
+ --generate-c-code indicator-messages-application \
+ --c-namespace IndicatorMessages \
+ $^
+indicator-messages-application.h: indicator-messages-application.c
+
+BUILT_SOURCES = \
+ indicator-messages-service.c \
+ indicator-messages-service.h \
+ indicator-messages-application.c \
+ indicator-messages-application.h
+
+libmessaging_common_la_SOURCES = \
+ $(BUILT_SOURCES)
+
+libmessaging_common_la_CFLAGS = $(GIO_CFLAGS)
+libmessaging_common_la_LIBADD = $(GIO_LIBS)
+
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/common/com.canonical.indicator.messages.application.xml b/common/com.canonical.indicator.messages.application.xml
new file mode 100644
index 0000000..6f038e6
--- /dev/null
+++ b/common/com.canonical.indicator.messages.application.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+ <interface name="com.canonical.indicator.messages.application">
+ <method name="ListSources">
+ <arg type="a(sssuxsb)" name="sources" direction="out" />
+ </method>
+ <method name="ListMessages">
+ <arg type="a(sssssxaa{sv}b)" name="message" direction="out" />
+ </method>
+ <method name="ActivateSource">
+ <arg type="s" name="source_id" direction="in" />
+ </method>
+ <method name="ActivateMessage">
+ <arg type="s" name="message_id" direction="in" />
+ <arg type="s" name="action_id" direction="in" />
+ <arg type="av" name="parameter" direction="in" />
+ </method>
+ <method name="Dismiss">
+ <arg type="as" name="sources" direction="in" />
+ <arg type="as" name="messages" direction="in" />
+ </method>
+ <signal name="SourceAdded">
+ <arg type="u" name="position" direction="in" />
+ <arg type="(sssuxsb)" name="source" direction="in" />
+ </signal>
+ <signal name="SourceChanged">
+ <arg type="(sssuxsb)" name="source" direction="in" />
+ </signal>
+ <signal name="SourceRemoved">
+ <arg type="s" name="source_id" direction="in" />
+ </signal>
+ <signal name="MessageAdded">
+ <arg type="(sssssxaa{sv}b)" name="message" direction="in" />
+ </signal>
+ <signal name="MessageRemoved">
+ <arg type="s" name="message_id" direction="in" />
+ </signal>
+ </interface>
+</node>
diff --git a/src/messages-service.xml b/common/com.canonical.indicator.messages.service.xml
index 00ae154..00ae154 100644
--- a/src/messages-service.xml
+++ b/common/com.canonical.indicator.messages.service.xml
diff --git a/configure.ac b/configure.ac
index 971bd96..b020d30 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
-AC_INIT(indicator-messages, 12.10.4)
+AC_INIT(indicator-messages, 12.10.5)
AC_PREREQ(2.62)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE()
+AM_INIT_AUTOMAKE([check-news])
AM_MAINTAINER_MODE
@@ -156,6 +156,7 @@ AM_GLIB_GNU_GETTEXT
AC_OUTPUT([
Makefile
src/Makefile
+common/Makefile
data/Makefile
data/icons/Makefile
data/icons/16x16/Makefile
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..6919c93
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,912 @@
+indicator-messages (13.10.0phablet1) raring; urgency=low
+
+ * Version bump to not pull from archives
+
+ -- Sergio Schvezov <sergio.schvezov@canonical.com> Fri, 26 Apr 2013 13:53:53 -0300
+
+indicator-messages (12.10.6phablet1) quantal; urgency=low
+
+ * Adding guards for g_type_init
+
+ -- Sergio Schvezov <sergio.schvezov@canonical.com> Fri, 22 Mar 2013 17:23:45 -0300
+
+indicator-messages (12.10.6-0ubuntu1phablet9) quantal; urgency=low
+
+ * add "remove-all" signal to imapplicationlist (temporarily)
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 20 Dec 2012 18:49:50 +0100
+
+indicator-messages (12.10.6-0ubuntu1phablet8) quantal; urgency=low
+
+ * Make messaging_menu_app_remove_message() work for messages with a ref count of 1
+ * Make handling of multiple processes with the same desktop id more robust
+ * ImPhoneMenu: sort messages by time (fixes LP #1090266)
+ * Don't show message sources
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 17 Dec 2012 14:42:03 +0100
+
+indicator-messages (12.10.6-0ubuntu1phablet7) quantal; urgency=low
+
+ * Remove variant wrapper from 'parameter' argument of the "activate" signal
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Tue, 11 Dec 2012 14:28:15 +0100
+
+indicator-messages (12.10.6-0ubuntu1phablet6) quantal; urgency=low
+
+ * Don't show sources
+ * Always use the "messageitem" widget type for messages
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 10 Dec 2012 14:38:16 +0100
+
+indicator-messages (12.10.6-0ubuntu1phablet5) quantal; urgency=low
+
+ * Don't shorten the app id to seven characters (fixes LP #1086729)
+ * Add messaging_menu_app_get_message
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 06 Dec 2012 15:06:34 +0000
+
+indicator-messages (12.10.6-0ubuntu1phablet4) quantal; urgency=low
+
+ [Lars Uebernickel]
+ * Add the concept of actions to messages
+ * Stop using IndicatorService
+ * Reverse order of messages
+ * Expose symbolic application icon
+ * Change icon when there are any messages in the menu
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Tue, 04 Dec 2012 21:10:26 +0000
+
+indicator-messages (12.10.6-0ubuntu1phablet3) quantal; urgency=low
+
+ [Lars Uebernickel]
+ * expose root menu item of which the indicator menu is a submenu
+ * fix crash in im-application-list on arm
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 29 Nov 2012 21:44:19 +0100
+
+indicator-messages (12.10.6-0ubuntu1phablet2) quantal; urgency=low
+
+ [Lars Uebernickel]
+ * refactor messages-service.c
+ * notify applications about message and source activations
+ * add "Clear All" menu item
+ * allow dismissing of messages
+ * include application icons on message items
+
+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 26 Nov 2012 22:19:51 +0100
+
+indicator-messages (12.10.6-0ubuntu1phablet1) quantal; urgency=low
+
+ [ Mathieu Trudel-Lapierre ]
+ * debian/rules:
+ - Use autogen.sh for dh_autoreconf.
+ - Drop the override for dh_makeshlibs.
+ - Add DPKG_GENSYMBOLS_CHECK_LEVEL=4.
+ * debian/control:
+ - Fix styling: add trailing commas at the end of lists.
+ - Update Vcs-Bzr, Vcs-Browser fields and add a notice for developers.
+ - Add libgtest-dev to Build-Depends.
+ * Automatic snapshot from revision 329 (bootstrap):
+ - Clear the detail (count or time) of a source when another type of detail
+ is set. (LP: #1071640)
+
+ [ Ricardo Mendoza ]
+ * Releasing upstream for phablet
+
+ -- Ricardo Mendoza <ricardo.mendoza@canonical.com> Tue, 20 Nov 2012 10:08:59 -0430
+
+indicator-messages (12.10.5-0ubuntu2) raring; urgency=low
+
+ * Upload to raring
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Wed, 07 Nov 2012 15:16:08 +0100
+
+indicator-messages (12.10.5-0ubuntu1) quantal-proposed; urgency=low
+
+ * New upstream release:
+ - fix crash caused by GError not being cleared (lp #1064314)
+ - fix crash when registering an app that was previously unregistered
+ (lp #1065169)
+ - remove the icon if NULL is passed to source_set_icon (lp #1070421)
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Wed, 24 Oct 2012 17:30:45 +0200
+
+indicator-messages (12.10.4-0ubuntu1) quantal; urgency=low
+
+ * New upstream release:
+ - don't segfault if .desktop file is not installed (lp: #1058386)
+ - Use fallback icon names (without status emblems).
+ (lp: #1056595)
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Tue, 02 Oct 2012 23:20:19 +0200
+
+indicator-messages (12.10.2-0ubuntu1) quantal; urgency=low
+
+ * New upstream release, includes apis to allow changing the label and
+ the icon of sources and add documentation
+ * debian/libmessaging-menu0.symbols:
+ - new version update
+ * debian/libmessaging-menu-dev.install:
+ - install the documentation
+ * debian/rules:
+ - build the documentation
+ - updated shlibs version
+ - use --with gir so gir:Depends work as it should
+ (lp: #1044125)
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Sat, 01 Sep 2012 12:36:35 +0200
+
+indicator-messages (12.10.1-0ubuntu1) quantal-proposed; urgency=low
+
+ * New upstream version
+ * debian/control:
+ - breaks on version of ported clients using libindicate
+ - set some conflicts on the old deprecated status provider binaries
+ - updated Build-Depends
+ * debian/control, debian/*.install:
+ - drop indicator-status-provider-*, those are deprecated
+ - new binaries for the libmessaging-menu library
+ * debian/libmessaging-menu0.symbols:
+ - symbol file for the new library
+ * Updated packaging to dh9, current standards
+ * Drop gtk2 build from the packaging since support for it was
+ dropped in trunk, thanks Lars Uebernickel
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Mon, 27 Aug 2012 18:56:59 +0200
+
+indicator-messages (0.6.0-0ubuntu1) precise; urgency=low
+
+ * New upstream release.
+ * Handle blank icons properly (LP: #956147)
+ * Fix telepathy offline/disconnected state bug
+
+ -- Charles Kerr <charles.kerr@canonical.com> Wed, 11 Apr 2012 11:09:46 -0500
+
+indicator-messages (0.5.95-0ubuntu1) precise; urgency=low
+
+ [ Charles Kerr ]
+ * New upstream release.
+ * Fix 0.5.94 blacklist regression.
+
+ [ Ken VanDine ]
+ * src/indicator-messages.c
+ * revert fix for the broken images in indicator-messages-service, it
+ caused the service to build against gtk and we can't parallel install
+ the service anyway
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 05 Apr 2012 16:47:19 -0400
+
+indicator-messages (0.5.94-0ubuntu1) precise; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Fix for missing icons in the messaging menu (LP: #960553)
+ * Fix i18n for description (LP: #957525)
+ * Implementing initial testing
+ * Fixing blacklists (LP: #939258)
+ * debian/control: Adding dep on libgtest-dev
+
+ [ Ken VanDine ]
+ * debian/control: Don't build depend on libgtest-dev, it isn't in main
+ * debian/rules: disable tests, they require libgtest-dev
+
+ -- Ken VanDine <ken.vandine@canonical.com> Wed, 21 Mar 2012 17:00:10 -0400
+
+indicator-messages (0.5.93-0ubuntu2) precise; urgency=low
+
+ * src/im-menu-item.c
+ - cherry picked fix for missing icons in the messaging menu (LP: #960553)
+
+ -- Ken VanDine <ken.vandine@canonical.com> Tue, 20 Mar 2012 16:41:13 -0400
+
+indicator-messages (0.5.93-0ubuntu1) precise; urgency=low
+
+ * debian/control:
+ - drop build-depends on gnome-doc-utils and scrollkeeper, not required
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Fixing alignment of menu items (LP: #939953)
+ * Vertically centering alignment of double high items (LP: #770486)
+ * Fixing setting of status on telepathy (LP: #943757)
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Thu, 08 Mar 2012 22:11:24 +0100
+
+indicator-messages (0.5.92-0ubuntu1) precise; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Fix goto handling (by removing) (LP: #937441, LP: #937438)
+ * Tell accountsservice when user has messages for the benefit of
+ LightDM.
+ * Dropping debian/patches: Merged upstream
+
+ [ Ken VanDine ]
+ * debian/source/format
+ - dropped "3.0 (quilt), it doesn't play well with bzr maintained packages
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 23 Feb 2012 02:48:09 -0500
+
+indicator-messages (0.5.91-0ubuntu3) precise; urgency=low
+
+ * debian/source/format:
+ - Make "3.0 (quilt)"
+ * debian/patches/tell-accounts-service.patch:
+ - Tell accountsservice when user has messages for the benefit of
+ LightDM.
+
+ -- Michael Terry <mterry@ubuntu.com> Wed, 15 Feb 2012 15:32:16 -0500
+
+indicator-messages (0.5.91-0ubuntu2) precise; urgency=low
+
+ * debian/control: build-depends on dh-autoreconf as well
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Tue, 14 Feb 2012 23:50:15 +0100
+
+indicator-messages (0.5.91-0ubuntu1) precise; urgency=low
+
+ * New upstream release.
+ * Better lozenges that look nice
+ * debian/rules: Adding autoreconf and running make check
+ * debian/compat: 5
+ * debian/source/format: Dropping
+
+ -- Ted Gould <ted@ubuntu.com> Tue, 14 Feb 2012 15:29:52 -0600
+
+indicator-messages (0.5.90-0ubuntu1) precise; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Adding code coverage targets
+ * Match libindicate 0.6.90
+ * Updating for Dbusmenu 0.5.90
+ * Plug leak in launcher_menu_item_new
+ * Fix memory leak: Free path string.
+ * Compare server and path for multi-server clients
+ * Using the new GTK3 box API to avoid deprecations
+ * Adding a name hint
+ * debian/control: Requiring libindicate 0.6.90 and dbusmenu 0.5.90
+
+ [ Ken VanDine ]
+ * debian/rules
+ - drop no-error=deprecated-declarations from CFLAGS
+
+ -- Ken VanDine <ken.vandine@canonical.com> Fri, 10 Feb 2012 14:29:59 -0500
+
+indicator-messages (0.5.0-1ubuntu1) precise; urgency=low
+
+ * rebuild for libindicator7
+ * debian/rules
+ - build with no-error=deprecated-declarations
+ * debian/control
+ - set ubuntu-desktop VCS and maintainer
+
+ -- Ken VanDine <ken.vandine@canonical.com> Wed, 25 Jan 2012 09:56:59 -0500
+
+indicator-messages (0.5.0-1) experimental; urgency=low
+
+ * Merge new upstream from Ubuntu.
+
+ -- Evgeni Golov <evgeni@debian.org> Wed, 19 Oct 2011 13:36:00 +0200
+
+indicator-messages (0.5.0-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ * Fix memory leak (LP: #690668)
+ * Drop debian/patches/lp_690668.patch: Merged upstream
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 28 Sep 2011 10:39:26 -0500
+
+indicator-messages (0.4.95-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ * Fix naming of "Clear" item
+ * Fix alignment of items to there is a consistent gutter
+ * debian/patches/lp_690668.patch: Updating
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 25 Aug 2011 09:09:20 -0500
+
+indicator-messages (0.4.94-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ ∘ Fix drawing of triangles and capsules in GTK3
+ ∘ Fix Emesene statuses (LP: #817504)
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 18 Aug 2011 10:57:40 -0500
+
+indicator-messages (0.4.93-0ubuntu2) oneiric; urgency=low
+
+ * debian/rules
+ - run intltool-update to update the translations template
+
+ -- Ken VanDine <ken.vandine@canonical.com> Fri, 12 Aug 2011 10:05:01 -0400
+
+indicator-messages (0.4.93-0ubuntu1) oneiric; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Add an item to clear the alert
+ * Choose mail applications based on the default application
+ * Clear based on middle click
+
+ [ Ken VanDine ]
+ * debian/control
+ - Bumped build depends for libindicate to >= 0.5.90
+ * debian/rules
+ - Fixed configure arg for gtk version
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 11 Aug 2011 14:18:05 -0400
+
+indicator-messages (0.4.92-0ubuntu4) oneiric; urgency=low
+
+ * debian/control
+ - Dropped recommends for gwibber now that it is seeded
+ * cherry picked r220 from trunk
+ - Make sure to insert in the right locations
+ * cherry picked r221 from trunk
+ - Making mail applications based on the default mail client not a
+ hardcoded desktop file.
+
+ -- Ken VanDine <ken.vandine@canonical.com> Fri, 05 Aug 2011 14:33:39 -0400
+
+indicator-messages (0.4.92-0ubuntu3) oneiric; urgency=low
+
+ * debian/control
+ - Added recommends for gwibber, it got missed when we dropped indicator-me
+ should get removed after we get it seeded properly
+
+ -- Ken VanDine <ken.vandine@canonical.com> Sun, 31 Jul 2011 16:36:09 -0400
+
+indicator-messages (0.4.92-0ubuntu2) oneiric; urgency=low
+
+ * debian/control:
+ - use conflicts against indicator-me
+
+ -- Michael Vogt <michael.vogt@ubuntu.com> Fri, 29 Jul 2011 15:49:40 +0200
+
+indicator-messages (0.4.92-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ * debian/control
+ - Added Replaces indicator-me
+ - Added build depends for libtelepathy-glib-dev
+ - Added new binary packages, libindicator-messages-status-provider-dev,
+ libindicator-messages-status-provider1, and each provider
+ - Make indicator-messages recommend indicator-status-provider-mc5
+ * debian/libindicator-messages-status-provider1.symbols
+ - Added symbols file
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 14 Jul 2011 16:28:23 -0400
+
+indicator-messages (0.4.91-0ubuntu1) oneiric; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Update for libindicator 0.4
+
+ [ Ken VanDine ]
+ * debian/control
+ - Bumped build depends for libindicator to >= 0.3.90
+
+ -- Ken VanDine <ken.vandine@canonical.com> Fri, 08 Jul 2011 11:23:58 -0400
+
+indicator-messages (0.4.90-0ubuntu2) oneiric; urgency=low
+
+ * Rebuild for libdbusmenu-gtk3-4
+ * debian/control
+ - Removed duplicate build depends
+ - Dropped build depends on indicator-messages-gtk2
+
+ -- Ken VanDine <ken.vandine@canonical.com> Tue, 28 Jun 2011 09:01:12 -0400
+
+indicator-messages (0.4.90-0ubuntu1) oneiric; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * GTK 3
+
+ [ Ken VanDine ]
+ * debian/control
+ - Bumped standards version to 3.9.2
+ - Add new binary for indicator-messages-gtk2
+ - Make indicator-messages recommend indicator-messages-gtk2 (until unity
+ can load gtk3 indicators)
+ - indicator-messages-gtk2 replaces indicator-messages << 0.4.90
+ - Added build depends for libdbusmenu-gtk3-dev and libindicator3-dev
+ * debian/rules
+ - build for both gtk2 and gtk3
+
+ -- Ken VanDine <ken.vandine@canonical.com> Wed, 22 Jun 2011 12:34:43 -0400
+
+indicator-messages (0.4.0-1) unstable; urgency=low
+
+ * Merge new upstream from Ubuntu.
+ * Standards-Version: 3.9.2
+
+ -- Evgeni Golov <evgeni@debian.org> Sun, 05 Jun 2011 13:16:03 +0200
+
+indicator-messages (0.4.0-0ubuntu1) natty; urgency=low
+
+ * New upstream release.
+ ∘ Set the type before other variables to get default handling more
+ reliable (LP: #723873)
+ ∘ Add support for overriding the default icon with a specific one
+ for the messaging menu (LP: #741068)
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 07 Apr 2011 12:35:36 -0500
+
+indicator-messages (0.3.92-1) unstable; urgency=low
+
+ * Merge new upstream from Ubuntu.
+ * Fix 0.3.11-0ubuntu3 changelog entry (missed a space), so that
+ bzr builddeb won't go crazy (see Debian Bug #620242)
+ * Fix debian/copyright, was refering to libdbusmenu by mistake.
+
+ -- Evgeni Golov <evgeni@debian.org> Sun, 03 Apr 2011 13:37:33 +0200
+
+indicator-messages (0.3.92-0ubuntu3) natty; urgency=low
+
+ * debian/patches/lp_690668.patch
+ - Memory leak fixes (LP: #690668)
+ * debian/control
+ - Bump standards version to 3.9.1
+ * debian/source/format
+ - Use source format 3.0 (quilt)
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 24 Feb 2011 12:13:33 -0500
+
+indicator-messages (0.3.92-0ubuntu2) natty; urgency=low
+
+ * src/launcher-menu-item.c
+ - Make sure menu entries are displayed for launchers that aren't running (LP: #723873)
+
+ -- Ken VanDine <ken.vandine@canonical.com> Wed, 23 Feb 2011 16:06:37 -0500
+
+indicator-messages (0.3.92-0ubuntu1) natty; urgency=low
+
+ * New upstream release.
+ * Adding in accessible description support
+ * debian/control: libindicator version 0.3.19
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 17 Feb 2011 12:18:32 -0600
+
+indicator-messages (0.3.91-0ubuntu1) natty; urgency=low
+
+ * New upstream release.
+ * Fixing the service file
+ * Adding a log domain
+ * Fixing type handler for dbusmenu 0.3.94
+ * debian/control: dbusmenu to 0.3.94
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 27 Jan 2011 17:01:34 -0600
+
+indicator-messages (0.3.90-0ubuntu1) natty; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * GDBus Port
+ * New libindicate and dbusmenu
+
+ [ Ken VanDine ]
+ * debian/control
+ - Build depends on libindicate-dev to 0.4.91
+ - Build depends on dbusmenu to 0.3.91
+ - Set Vcs to ~ubuntu-desktop
+ * data/indicator-messages.service.in
+ - Fixed dbus interface name
+
+ -- Ken VanDine <ken.vandine@canonical.com> Fri, 14 Jan 2011 14:50:30 -0600
+
+indicator-messages (0.3.11-0ubuntu4) natty; urgency=low
+
+ * debian/control
+ - Bump build depends for libdbusmenu-* to >= 0.3.90
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 09 Dec 2010 11:39:40 -0500
+
+indicator-messages (0.3.11-0ubuntu3) UNRELEASED; urgency=low
+
+ * debian/control: package description spelling (LP: #658096)
+
+ -- Greg Auger <gregory.auger@googlemail.com> Tue, 09 Nov 2010 18:49:38 +0000
+
+indicator-messages (0.3.11-0ubuntu2) maverick; urgency=low
+
+ * Rebuild for libindicator ABI change (LP: #637692)
+ * debian/control: depends on latest libindicator-dev
+
+ -- Didier Roche <didrocks@ubuntu.com> Wed, 22 Sep 2010 18:39:27 +0200
+
+indicator-messages (0.3.11-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ * Fixing triangles by passing data to callback (LP: #623453)
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 09 Sep 2010 13:24:13 -0500
+
+indicator-messages (0.3.10-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ * Shifting icons into the gutter and adjusting the arrow
+ padding.
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 26 Aug 2010 15:08:31 -0500
+
+indicator-messages (0.3.9-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ * Remove parens from counts
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 12 Aug 2010 13:10:10 -0500
+
+indicator-messages (0.3.8-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ - running apps triangle indicator overlay
+ - message counters are now rendered with a nice rounded background
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 29 Jul 2010 13:33:14 -0400
+
+indicator-messages (0.3.7-1) unstable; urgency=low
+
+ * Merge from Ubuntu.
+ Closes: #586132
+ * debian/control:
+ - Homepage is at LP/indicator-messages, not -applet.
+ - Update package description.
+ - Update Vcs-* fields.
+ - Standards-Version: 3.8.4.
+ * debian/copyright:
+ - Convert to DEP5 format.
+ - Add missing copyright holders of debian/.
+
+ -- Evgeni Golov <evgeni@debian.org> Thu, 17 Jun 2010 13:02:37 +0200
+
+indicator-messages (0.3.7-0ubuntu1~ppa1) lucid; urgency=low
+
+ * New upstream release.
+ * When loading desktop files check to see if they've
+ already been eclipsed by an app. (LP: #549096)
+ * Track better application shortcuts and ensure that they
+ get removed when the application is. (LP: #539167)
+ * Track blacklisted apps to ensure that the messaging menu
+ hides when there is no app. (LP: #533021)
+
+ -- Ted Gould <ted@ubuntu.com> Fri, 21 May 2010 15:02:16 -0500
+
+indicator-messages (0.3.6-0ubuntu2) lucid; urgency=low
+
+ * Upstream Merge
+ * When loading desktop files check to see if they've
+ already been eclipsed by an app. (LP: #549096)
+ * Track better application shortcuts and ensure that they
+ get removed when the application is. (LP: #539167)
+
+ -- Ted Gould <ted@ubuntu.com> Sat, 17 Apr 2010 13:10:42 -0500
+
+indicator-messages (0.3.6-0ubuntu1) lucid; urgency=low
+
+ * New upstream release.
+ * Fixing several bugs with regards to visibility and placement
+ if items and separators in the menu. (LP: #446914)
+ * Changing the service management over to using libindicator
+ services and service manager for robustness.
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 01 Apr 2010 10:13:38 -0500
+
+indicator-messages (0.3.5-0ubuntu2) lucid; urgency=low
+
+ * debian/control:
+ - change the indicator-applet depends to a recommends to let other
+ desktops use other options rather than having to trigger GNOME
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Tue, 30 Mar 2010 10:35:59 +0200
+
+indicator-messages (0.3.5-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.5
+ * Show which applications are running with a small icon
+ next to their entry. (LP: #438526)
+ * Shift command items to line up with application names.
+ (LP: #537312)
+ * Track applications we've seen so that we can show "Set Up"
+ text if we've not seen the app before.
+ * Fix avatar spacing to match other menu items
+ * Use standard libindicator icon handling in panel
+ * Fix translation of non-running applications (LP: #540148)
+ * Handling bools for requesting attention from apps
+ * Changing microblogging to broadcast to match Me Menu (LP: #534952)
+ * debian/control:
+ - Updating requirement to libindicator 0.3.5
+ - Increasing dbusmenu-glib dep to 0.2.8
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 25 Mar 2010 10:53:01 -0500
+
+indicator-messages (0.3.4-0ubuntu1~ppa1) lucid; urgency=low
+
+ * Upstream release 0.3.4
+ * Fix avatar spacing to match other menu items
+ * Use standard libindicator icon handling in panel
+ * Fix translation of non-running applications (LP: #540148)
+ * Handling bools for requesting attention from apps
+ * Changing microblogging to broadcast to match Me Menu (LP: #534952)
+ * debian/control: Updating requirement to libindicator 0.3.5
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 18 Mar 2010 13:45:19 -0500
+
+indicator-messages (0.3.3-0ubuntu2) lucid; urgency=low
+
+ * src/default-applications.c
+ - string change for consistency (LP: #534952)
+
+ -- Ken VanDine <ken.vandine@canonical.com> Fri, 12 Mar 2010 11:44:46 -0500
+
+indicator-messages (0.3.3-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.3
+ * Changing names of default applications to generic names
+ * Making icons of default applications match panel theme
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 04 Mar 2010 16:02:11 -0600
+
+indicator-messages (0.3.2-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.2
+ * Removing extra ref
+ * Moving locally defined variable to use the one defined in
+ the function to fix a NULL pointer. (lp: #518547)
+ * Disconnect the count changed signal property
+ * Adding static desktop shortcuts to application items
+ * Adding dynamic application menuitems
+ * Switching application menu items to remove descriptions
+ and add in application icons
+ * debian/control:
+ * libindicator build dependency to 0.3.3
+ * dbusmenu build dependency to 0.2.5
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 18 Feb 2010 12:23:29 -0600
+
+indicator-messages (0.3.1-0ubuntu2) lucid; urgency=low
+
+ * Upstream Merge
+ * Removing extra ref
+ * Moving locally defined variable to use the one defined in
+ the function to fix a NULL pointer. (lp: #518547)
+
+ -- Ted Gould <ted@ubuntu.com> Tue, 09 Feb 2010 09:30:10 -0600
+
+indicator-messages (0.3.1-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.1
+ * Updates for dbusmenu 0.2.2
+ * Updates for libindicate 0.3.0
+ * debian/control:
+ * dbusmenu* depends to 0.2.2
+ * libindicate* depends to 0.3.0
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 04 Feb 2010 18:23:34 -0800
+
+indicator-messages (0.3.0-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.0
+ - Disabling static builds.
+ - Porting to libindicator 0.3.0
+ - Adding translator comments from hours and minutes strings.
+ (LP: #456437)
+ - Upgrading to dbusmenu 0.2.0
+ * debian/control: Updating dbusmenu dependency to 0.2.0
+ * debian/control: Increasing libindicator-dev dependency to
+ 0.3.0
+
+ -- Ted Gould <ted@ubuntu.com> Fri, 08 Jan 2010 12:05:25 -0600
+
+indicator-messages (0.2.6+r156-0ubuntu2) lucid; urgency=low
+
+ * debian/control
+ - add a Breaks for indicator-applet (<< 0.3.0)
+
+ -- Ken VanDine <ken.vandine@canonical.com> Tue, 15 Dec 2009 11:57:42 -0500
+
+indicator-messages (0.2.6+r156-0ubuntu1) lucid; urgency=low
+
+ * New snapshot for libindicator 0.3.0
+ * debian/control
+ - Build-Depends on libindicator >= 0.3.0
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 10 Dec 2009 14:35:46 -0500
+
+indicator-messages (0.2.6-0ubuntu1) karmic; urgency=low
+
+ * Upstream release 0.2.6 (LP: #446629)
+ * Building the menu after checking the blacklist so that the
+ separators are all correct.
+ * Small fix for a perspective memory leak.
+
+ -- Ted Gould <ted@ubuntu.com> Fri, 09 Oct 2009 08:14:27 +0200
+
+indicator-messages (0.2.5-0ubuntu1) karmic; urgency=low
+
+ * Upstream release 0.2.5 (LP: #440217)
+ * Adding a check on addition of launchers to ensure icon is correctly
+ visible. (LP: #433274)
+ * Making it so that if applications don't set the time on an indicator
+ the time isn't shown in the menu. (LP: #438237)
+ * Putting icons in the right places. (LP: #436460)
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 01 Oct 2009 23:34:28 +0200
+
+indicator-messages (0.2.4-0ubuntu1) karmic; urgency=low
+
+ * Upstream release 0.2.4 (LP: #436093)
+ - Merging in the min menu width feature (LP: #428292)
+ - Merging in icon scaling branch from trunk. Now better icons (LP: #433143)
+ - Merging in updated trunk (LP: #434097 and LP: #435184)
+ - add i18n support
+ - Prevent null entries (LP: #435184)
+ - add a path for indicators in /usr/share (LP: #434097)
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 24 Sep 2009 13:07:46 -0500
+
+indicator-messages (0.2.2-0ubuntu2) karmic; urgency=low
+
+ * src/messages-service.c: initialise the translations
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Tue, 15 Sep 2009 16:41:03 +0200
+
+indicator-messages (0.2.2-0ubuntu1) karmic; urgency=low
+
+ * New release (LP: #427357)
+ * Adds in separators between application groups
+ * Merging in v2-api stuff which will become 0.2.1
+ * debian/control:
+ - Requiring > 0.2.0 of libindicate-*
+ - bump dbusmenu dependencies.
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 10 Sep 2009 09:11:57 -0500
+
+indicator-messages (0.2.0-0ubuntu2) karmic; urgency=low
+
+ * debian/control
+ - Bump build depends on dbusmenu to 0.1.0
+
+ -- Ken VanDine <ken.vandine@canonical.com> Thu, 27 Aug 2009 21:14:46 +0200
+
+indicator-messages (0.2.0-0ubuntu1) karmic; urgency=low
+
+ [ Ted Gould ]
+ * Upstream version 0.2.0
+ * debian/control: Adding dependency information for libdbusmenu
+ to say >= 0.0.2 to match upstream build system.
+ * debian/watch: Changing to use indicator-messages project.
+
+ [ Martin Pitt ]
+ * debian/control: Update Vcs-Bzr: for new branch location.
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 27 Aug 2009 20:46:27 +0200
+
+indicator-messages (0.2.0~bzr124-0ubuntu1) karmic; urgency=low
+
+ * Update to fix build issue
+
+ -- Sebastien Bacher <seb128@ubuntu.com> Fri, 07 Aug 2009 17:12:40 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu3) karmic; urgency=low
+
+ * Fix to dereference the application menu items correctly so that
+ the signal handlers are dropped as well. (lp: #410251)
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 05 Aug 2009 19:00:31 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu2) karmic; urgency=low
+
+ * Run autogen.sh before upload
+
+ -- Jonathan Riddell <jriddell@ubuntu.com> Wed, 05 Aug 2009 00:42:39 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu1) karmic; urgency=low
+
+ [ Ted Gould ]
+ * debian/control: Adding in a build dep on libindicate-gtk-dev
+ * Changes for the changing libindicate stuff.
+ * Merge in the dbusmenu changes from the dbusmenu branch
+ * debian/control: Adding in a build dependency on libdbusmenu-glib and
+ libdbusmenu-gtk to catch up with the merge.
+
+ -- Jonathan Riddell <jriddell@ubuntu.com> Wed, 05 Aug 2009 00:21:50 +0100
+
+indicator-messages (0.2.0~bzr120-0ubuntu1) jaunty; urgency=low
+
+ * Fix to track the timer. (LP: #365187)
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 13 May 2009 09:56:20 -0500
+
+indicator-messages (0.2.0~bzr119-0ubuntu1) jaunty; urgency=low
+
+ * Upstream update
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 22 Apr 2009 23:34:21 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu3) jaunty; urgency=low
+
+ * debian/rules: Adding a rule to remove the .la/.a clutter
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 22 Apr 2009 16:46:59 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu2) jaunty; urgency=low
+
+ * debian/control: libindicator-dev to ~bzr301
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 22 Apr 2009 15:58:45 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu1) jaunty; urgency=low
+
+ * Upstream release
+ * Bug fixes
+ * Update API to new libindicator
+ * debian/control: Adding new dependency on libindicator-dev
+
+ -- Ted Gould <ted@ubuntu.com> Wed, 22 Apr 2009 15:45:21 -0500
+
+indicator-messages (0.1.6-0ubuntu1) jaunty; urgency=low
+
+ * New upstream version
+ * Patch from Cody Russell to fix LP: #359018 by correctly implementing
+ the finalize functions.
+
+ -- Ted Gould <ted@ubuntu.com> Tue, 14 Apr 2009 11:32:00 +0200
+
+indicator-messages (0.1.5-0ubuntu1) jaunty; urgency=low
+
+ * New upstream version
+ * Fixes the lifecycle of the various structures tracking the messages
+ and applications. Fixing bugs like (LP: #355616) (LP: #352881)
+ * Fixes the visual appearance by setting the widget name to grab the
+ style settings from the main applet. (LP: #351979)
+ * debian/control: Upgrading dependency on libindicate-dev to 0.1.5 or
+ higher as the new version requires that.
+
+ -- Ted Gould <ted@ubuntu.com> Fri, 03 Apr 2009 16:32:49 -0500
+
+indicator-messages (0.1.4-0ubuntu1) jaunty; urgency=low
+
+ * New upstream version
+ * Adding the display of indicators that are login messages coming from
+ other applications. (LP: #345494)
+ * Making all times displayed for IM messages relative instead of
+ absolute. (LP: #346345)
+ * Cleaning up the server removal code. May fix (LP: #345599), I can't
+ recreate it anymore afterwards.
+
+ -- Ted Gould <ted@ubuntu.com> Mon, 30 Mar 2009 09:40:40 +0200
+
+indicator-messages (0.1.3-0ubuntu1) jaunty; urgency=low
+
+ [ Ted Gould ]
+ * New upstream version.
+ - Now changes the icon based on non-IM indicators so that Evolution
+ works much better. (LP: #342480)
+ - Now the menu items are in a predictable order, alphabetical.
+ - The Messages for a particular client (i.e. Pidgin) are grouped with
+ the client they're associated with.
+ - Adjusting the icon size to match the new one in the Human theme.
+ - Adjusting the build so that all the different libraries are not
+ built in a versioned manner. Now it's just one .so, which is
+ what it should have been originally.
+
+ [ Martin Pitt ]
+ * Add debian/watch.
+ * Add bzr-builddeb configuration.
+ * debian/copyright: Fix download location.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com> Thu, 19 Mar 2009 12:23:17 +0100
+
+indicator-messages (0.1-0ubuntu1) jaunty; urgency=low
+
+ * Initial release, based on DX team's PPA packaging branch.
+ (lp:~indicator-applet-developers/indicator-applet/messages-packaging)
+ * debian/control: Add Homepage:, Vcs-Bzr:, and fix package
+ description.
+ * debian/copyright: Properly describe license.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com> Tue, 17 Feb 2009 11:35:38 +0100
+
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..546b5c9
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,84 @@
+Source: indicator-messages
+Section: gnome
+Priority: optional
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: The Ayatana Packagers <pkg-ayatana-devel@lists.alioth.debian.org>
+Uploaders: Evgeni Golov <evgeni@debian.org>
+Build-Depends: debhelper (>= 9),
+ dh-autoreconf,
+ dh-translations,
+ libgtk-3-dev (>= 3.5.12),
+ libdbus-glib-1-dev,
+ intltool,
+ libindicator3-dev,
+ libdbusmenu-glib-dev (>= 0.5.90),
+ libdbusmenu-gtk3-dev (>= 0.5.90),
+ libtelepathy-glib-dev (>= 0.9.0),
+ gobject-introspection (>= 0.9.12-4~),
+ libgirepository1.0-dev (>= 0.9.12),
+ gtk-doc-tools,
+ libgtest-dev,
+Standards-Version: 3.9.3
+Homepage: https://launchpad.net/indicator-messages
+# If you aren't a member of ~indicator-applet-developers but need to upload
+# packaging changes, just go ahead. ~indicator-applet-developers will notice
+# and sync up the code again.
+Vcs-Bzr: https://code.launchpad.net/~indicator-applet-developers/indicator-messages/trunk.13.04
+Vcs-Browser: https://bazaar.launchpad.net/~indicator-applet-developers/indicator-messages/trunk.13.04/files
+
+Package: indicator-messages
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: indicator-applet | indicator-renderer
+Replaces: libindicator-messages-status-provider1,
+ libindicator-messages-status-provider-dev,
+ indicator-status-provider-mc5,
+ indicator-status-provider-pidgin,
+ indicator-status-provider-telepathy,
+ indicator-status-provider-emesene,
+Conflicts: libindicator-messages-status-provider1,
+ libindicator-messages-status-provider-dev,
+ indicator-status-provider-mc5,
+ indicator-status-provider-pidgin,
+ indicator-status-provider-telepathy,
+ indicator-status-provider-emesene,
+Breaks: gwibber-services (<< 3.5.4-0ubuntu1~),
+ telepathy-indicator (<< 0.3.0-0ubuntu1~),
+ thunderbird (<< 15.0+build1-0ubuntu1~),
+ xchat-indicator (<< 0.3.11-0ubuntu2~),
+ xchat-gnome-indicator (<< 0.3.11-0ubuntu2~),
+Description: indicator that collects messages that need a response
+ A place on the user's desktop that collects messages that need a response.
+ This menu provides a condensed and collected view of all of those messages
+ for quick access, but without making them annoying in times that you want
+ to ignore them.
+
+Package: libmessaging-menu0
+Architecture: any
+Section: libs
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+Description: Messaging Menu - shared library
+ This library contains information to build status providers to go into
+ the messaging menu.
+
+Package: libmessaging-menu-dev
+Architecture: any
+Section: libdevel
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libmessaging-menu0 (=${binary:Version}),
+ libglib2.0-dev,
+Description: Messaging Menu - library development files
+ This library contains information to build status providers to go into
+ the messaging menu.
+
+Package: gir1.2-messagingmenu-1.0
+Section: libs
+Architecture: any
+Depends: ${misc:Depends},
+ ${gir:Depends},
+Description: Messaging Menu - gir bindings
+ .
+ This package can be used by other packages using the GIRepository format
+ to generate dynamic bindings.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..ba41392
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,19 @@
+Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
+Name: indicator-messages
+Maintainer: Ted Gould <ted@canonical.com>
+Source: https://launchpad.net/indicator-messages
+
+Files: *
+Copyright: 2009-2010 Ted Gould <ted@canonical.com>, Canonical Ltd.
+License: GPL-3
+
+Files: debian/*
+Copyright: 2009-2010 Evgeni Golov <evgeni@debian.org>
+Copyright: 2009-2010 Ted Gould <ted@canonical.com>, Canonical Ltd.
+Copyright: 2009-2010 Sebastien Bacher <seb128@ubuntu.com>
+Copyright: 2009-2010 Ken VanDine <ken.vandine@canonical.com>
+License: GPL-3
+
+License: GPL-3
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in `/usr/share/common-licenses/GPL-3'.
diff --git a/debian/gir1.2-messagingmenu-1.0.install b/debian/gir1.2-messagingmenu-1.0.install
new file mode 100644
index 0000000..c1d8cfe
--- /dev/null
+++ b/debian/gir1.2-messagingmenu-1.0.install
@@ -0,0 +1 @@
+usr/lib/girepository-1.0/*.typelib
diff --git a/debian/indicator-messages.install b/debian/indicator-messages.install
new file mode 100644
index 0000000..c0f6e98
--- /dev/null
+++ b/debian/indicator-messages.install
@@ -0,0 +1,5 @@
+usr/lib/indicators3
+usr/lib/indicator-messages/indicator-messages-service
+usr/share/dbus-1
+usr/share/glib-2.0
+usr/share/icons
diff --git a/debian/libmessaging-menu-dev.install b/debian/libmessaging-menu-dev.install
new file mode 100644
index 0000000..75ef089
--- /dev/null
+++ b/debian/libmessaging-menu-dev.install
@@ -0,0 +1,5 @@
+usr/lib/libmessaging-menu.so
+usr/lib/pkgconfig
+usr/include /usr/
+usr/share/gir-1.0/
+usr/share/gtk-doc
diff --git a/debian/libmessaging-menu0.install b/debian/libmessaging-menu0.install
new file mode 100644
index 0000000..54b098e
--- /dev/null
+++ b/debian/libmessaging-menu0.install
@@ -0,0 +1 @@
+usr/lib/libmessaging-menu.so.* /usr/lib/
diff --git a/debian/libmessaging-menu0.symbols b/debian/libmessaging-menu0.symbols
new file mode 100644
index 0000000..d5eaed1
--- /dev/null
+++ b/debian/libmessaging-menu0.symbols
@@ -0,0 +1,38 @@
+libmessaging-menu.so.0 libmessaging-menu0 #MINVER#
+ messaging_menu_app_append_message@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_app_append_source@Base 12.10.0
+ messaging_menu_app_append_source_with_count@Base 12.10.0
+ messaging_menu_app_append_source_with_string@Base 12.10.0
+ messaging_menu_app_append_source_with_time@Base 12.10.0
+ messaging_menu_app_draw_attention@Base 12.10.0
+ messaging_menu_app_get_message@Base 0replaceme
+ messaging_menu_app_get_type@Base 12.10.0
+ messaging_menu_app_has_source@Base 12.10.0
+ messaging_menu_app_insert_source@Base 12.10.0
+ messaging_menu_app_insert_source_with_count@Base 12.10.0
+ messaging_menu_app_insert_source_with_string@Base 12.10.0
+ messaging_menu_app_insert_source_with_time@Base 12.10.0
+ messaging_menu_app_new@Base 12.10.0
+ messaging_menu_app_register@Base 12.10.0
+ messaging_menu_app_remove_attention@Base 12.10.0
+ messaging_menu_app_remove_message@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_app_remove_message_by_id@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_app_remove_source@Base 12.10.0
+ messaging_menu_app_set_source_count@Base 12.10.0
+ messaging_menu_app_set_source_icon@Base 12.10.2
+ messaging_menu_app_set_source_label@Base 12.10.2
+ messaging_menu_app_set_source_string@Base 12.10.0
+ messaging_menu_app_set_source_time@Base 12.10.0
+ messaging_menu_app_set_status@Base 12.10.0
+ messaging_menu_app_unregister@Base 12.10.0
+ messaging_menu_message_add_action@Base 12.10.6-0ubuntu1phablet3
+ messaging_menu_message_get_body@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_draws_attention@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_icon@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_id@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_subtitle@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_time@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_title@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_get_type@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_new@Base 12.10.6-0ubuntu1phablet1
+ messaging_menu_message_set_draws_attention@Base 12.10.6-0ubuntu1phablet1
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..649b0ad
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+
+export DPKG_GENSYMBOLS_CHECK_LEVEL=4
+
+%:
+ dh $@ --with autoreconf,translations,gir
+
+override_dh_autoreconf:
+ NO_CONFIGURE=1 dh_autoreconf ./autogen.sh
+
+override_dh_auto_configure:
+ dh_auto_configure -- --libdir="\$${prefix}/lib" --libexecdir="\$${prefix}/lib/indicator-messages" --enable-gtk-doc
+
+override_dh_install:
+ find debian/tmp/usr/lib -name *.la -delete
+ dh_install --fail-missing
+
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..d3827e7
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+1.0
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..a744070
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,2 @@
+version=3
+http://launchpad.net/indicator-messages/+download .*/indicator-messages-([0-9.]+)\.tar\.gz
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
index 023f1e7..3993b41 100644
--- a/doc/reference/Makefile.am
+++ b/doc/reference/Makefile.am
@@ -4,7 +4,6 @@ DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
DOC_SOURCE_DIR = $(top_srcdir)/libmessaging-menu
-SCANGOBJ_OPTIONS=--type-init-func="g_type_init()"
MKDB_OPTIONS=--xml-mode --output-format=xml
# Used for dependencies. The docs will be rebuilt if any of these change.
@@ -12,8 +11,7 @@ HFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.h
CFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.c
IGNORE_HFILES= \
- indicator-messages-service.h \
- gtupleaction.h
+ indicator-messages-service.h
INCLUDES=-I$(top_srcdir)/libmessaging-menu $(GIO_CFLAGS)
GTKDOC_LIBS=$(top_builddir)/libmessaging-menu/libmessaging-menu.la
diff --git a/doc/reference/messaging-menu-docs.xml.in b/doc/reference/messaging-menu-docs.xml.in
index 742d37b..4c1cec1 100644
--- a/doc/reference/messaging-menu-docs.xml.in
+++ b/doc/reference/messaging-menu-docs.xml.in
@@ -18,7 +18,8 @@
<chapter>
<title>API Reference</title>
- <xi:include href="xml/messaging-menu.xml"/>
+ <xi:include href="xml/messaging-menu-app.xml" />
+ <xi:include href="xml/messaging-menu-message.xml" />
</chapter>
<chapter id="object-tree">
diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am
index 7a6ee31..d18538b 100644
--- a/libmessaging-menu/Makefile.am
+++ b/libmessaging-menu/Makefile.am
@@ -4,36 +4,25 @@ lib_LTLIBRARIES = libmessaging-menu.la
libmessaging_menu_ladir = $(includedir)/messaging-menu
libmessaging_menu_la_SOURCES = \
- messaging-menu.c \
- gtupleaction.c \
- gtupleaction.h \
- $(BUILT_SOURCES)
+ messaging-menu-app.c \
+ messaging-menu-message.c
libmessaging_menu_la_HEADERS = \
- messaging-menu.h
+ messaging-menu-app.h \
+ messaging-menu.h \
+ messaging-menu-message.h
-libmessaging_menu_la_LIBADD = $(GIO_LIBS)
+libmessaging_menu_la_LIBADD = \
+ $(GIO_LIBS) \
+ $(top_builddir)/common/libmessaging-common.la
libmessaging_menu_la_CFLAGS = \
+ -I$(top_builddir)/common \
$(GIO_CFLAGS) \
-Wall
libmessaging_menu_la_LDFLAGS = -export-symbols-regex "^messaging_menu_.*"
-BUILT_SOURCES = \
- indicator-messages-service.c \
- indicator-messages-service.h
-
-CLEANFILES = $(BUILT_SOURCES)
-
-indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
- $(AM_V_GEN) gdbus-codegen \
- --interface-prefix com.canonical.indicator.messages. \
- --generate-c-code indicator-messages-service \
- --c-namespace IndicatorMessages \
- $^
-indicator-messages-service.h: indicator-messages-service.c
-
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = messaging-menu.pc
@@ -52,7 +41,11 @@ MessagingMenu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0
MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS)
MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h"
MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la
-MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h
+MessagingMenu_1_0_gir_FILES = \
+ messaging-menu-app.c \
+ messaging-menu-app.h \
+ messaging-menu-message.c \
+ messaging-menu-message.h
MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu
INTROSPECTION_GIRS += MessagingMenu-1.0.gir
@@ -62,5 +55,5 @@ gir_DATA = $(INTROSPECTION_GIRS)
typelibdir = $(libdir)/girepository-1.0
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
-CLEANFILES +=$(gir_DATA) $(typelib_DATA)
+CLEANFILES = $(gir_DATA) $(typelib_DATA)
endif
diff --git a/libmessaging-menu/gtupleaction.c b/libmessaging-menu/gtupleaction.c
deleted file mode 100644
index 21bc003..0000000
--- a/libmessaging-menu/gtupleaction.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright 2012 Canonical Ltd.
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- * Lars Uebernickel <lars.uebernickel@canonical.com>
- */
-
-#include "gtupleaction.h"
-
-typedef GObjectClass GTupleActionClass;
-
-struct _GTupleAction
-{
- GObject parent;
-
- gchar *name;
- GVariantType *type;
- gboolean enabled;
-
- gsize n_children;
- GVariant **children;
-};
-
-static void action_interface_init (GActionInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GTupleAction, g_tuple_action, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_interface_init));
-
-enum
-{
- PROP_0,
- PROP_NAME,
- PROP_PARAMETER_TYPE,
- PROP_ENABLED,
- PROP_STATE_TYPE,
- PROP_STATE,
- N_PROPERTIES
-};
-
-enum
-{
- SIGNAL_ACTIVATE,
- N_SIGNALS
-};
-
-static GParamSpec *properties[N_PROPERTIES];
-static guint signal_ids[N_SIGNALS];
-
-static const gchar *
-g_tuple_action_get_name (GAction *action)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (action);
-
- return tuple->name;
-}
-
-static const GVariantType *
-g_tuple_action_get_parameter_type (GAction *action)
-{
- return NULL;
-}
-
-static const GVariantType *
-g_tuple_action_get_state_type (GAction *action)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (action);
-
- return tuple->type;
-}
-
-static GVariant *
-g_tuple_action_get_state_hint (GAction *action)
-{
- return NULL;
-}
-
-static gboolean
-g_tuple_action_get_enabled (GAction *action)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (action);
-
- return tuple->enabled;
-}
-
-static GVariant *
-g_tuple_action_get_state (GAction *action)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (action);
- GVariant *result;
-
- result = g_variant_new_tuple (tuple->children, tuple->n_children);
- return g_variant_ref_sink (result);
-}
-
-static void
-g_tuple_action_set_state (GTupleAction *tuple,
- GVariant *state)
-{
- int i;
-
- g_return_if_fail (g_variant_type_is_tuple (g_variant_get_type (state)));
-
- if (tuple->type == NULL)
- {
- tuple->type = g_variant_type_copy (g_variant_get_type (state));
- tuple->n_children = g_variant_n_children (state);
- tuple->children = g_new0 (GVariant *, tuple->n_children);
- }
-
- for (i = 0; i < tuple->n_children; i++)
- {
- if (tuple->children[i])
- g_variant_unref (tuple->children[i]);
- tuple->children[i] = g_variant_get_child_value (state, i);
- }
-
- g_object_notify_by_pspec (G_OBJECT (tuple), properties[PROP_STATE]);
-}
-
-static void
-g_tuple_action_change_state (GAction *action,
- GVariant *value)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (action);
-
- g_return_if_fail (value != NULL);
- g_return_if_fail (g_variant_is_of_type (value, tuple->type));
-
- g_variant_ref_sink (value);
-
- /* TODO add a change-state signal similar to GSimpleAction */
- g_tuple_action_set_state (tuple, value);
-
- g_variant_unref (value);
-}
-
-static void
-g_tuple_action_activate (GAction *action,
- GVariant *parameter)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (action);
-
- g_return_if_fail (parameter == NULL);
-
- if (tuple->enabled)
- g_signal_emit (tuple, signal_ids[SIGNAL_ACTIVATE], 0, NULL);
-}
-
-static void
-g_tuple_action_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GAction *action = G_ACTION (object);
-
- switch (prop_id)
- {
- case PROP_NAME:
- g_value_set_string (value, g_tuple_action_get_name (action));
- break;
-
- case PROP_PARAMETER_TYPE:
- g_value_set_boxed (value, g_tuple_action_get_parameter_type (action));
- break;
-
- case PROP_ENABLED:
- g_value_set_boolean (value, g_tuple_action_get_enabled (action));
- break;
-
- case PROP_STATE_TYPE:
- g_value_set_boxed (value, g_tuple_action_get_state_type (action));
- break;
-
- case PROP_STATE:
- g_value_take_variant (value, g_tuple_action_get_state (action));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-g_tuple_action_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (object);
-
- switch (prop_id)
- {
- case PROP_NAME:
- tuple->name = g_value_dup_string (value);
- g_object_notify_by_pspec (object, properties[PROP_NAME]);
- break;
-
- case PROP_ENABLED:
- tuple->enabled = g_value_get_boolean (value);
- g_object_notify_by_pspec (object, properties[PROP_ENABLED]);
- break;
-
- case PROP_STATE:
- g_tuple_action_set_state (tuple, g_value_get_variant (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-g_tuple_action_finalize (GObject *object)
-{
- GTupleAction *tuple = G_TUPLE_ACTION (object);
- int i;
-
- g_free (tuple->name);
- g_variant_type_free (tuple->type);
-
- for (i = 0; i < tuple->n_children; i++)
- g_variant_unref (tuple->children[i]);
-
- g_free (tuple->children);
-
- G_OBJECT_CLASS (g_tuple_action_parent_class)->finalize (object);
-}
-
-static void
-action_interface_init (GActionInterface *iface)
-{
- iface->get_name = g_tuple_action_get_name;
- iface->get_parameter_type = g_tuple_action_get_parameter_type;
- iface->get_state_type = g_tuple_action_get_state_type;
- iface->get_state_hint = g_tuple_action_get_state_hint;
- iface->get_enabled = g_tuple_action_get_enabled;
- iface->get_state = g_tuple_action_get_state;
- iface->change_state = g_tuple_action_change_state;
- iface->activate = g_tuple_action_activate;
-}
-
-static void
-g_tuple_action_class_init (GTupleActionClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
-
- object_class->get_property = g_tuple_action_get_property;
- object_class->set_property = g_tuple_action_set_property;
- object_class->finalize = g_tuple_action_finalize;
-
- properties[PROP_NAME] = g_param_spec_string ("name",
- "Name",
- "The name of the action",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type",
- "Parameter Type",
- "The variant type passed to activate",
- G_TYPE_VARIANT_TYPE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_ENABLED] = g_param_spec_boolean ("enabled",
- "Enabled",
- "Whether the action can be activated",
- TRUE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type",
- "State Type",
- "The variant type of the state, must be a tuple",
- G_TYPE_VARIANT_TYPE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE] = g_param_spec_variant ("state",
- "State",
- "The state of the action",
- G_VARIANT_TYPE_TUPLE,
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- signal_ids[SIGNAL_ACTIVATE] = g_signal_new ("activate",
- G_TYPE_TUPLE_ACTION,
- G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VARIANT,
- G_TYPE_NONE, 1,
- G_TYPE_VARIANT);
-}
-
-static void
-g_tuple_action_init (GTupleAction *action)
-{
- action->enabled = TRUE;
-}
-
-GTupleAction *
-g_tuple_action_new (const gchar *name,
- GVariant *initial_state)
-{
- const GVariantType *type;
-
- g_return_val_if_fail (name != NULL, NULL);
- g_return_val_if_fail (initial_state != NULL, NULL);
-
- type = g_variant_get_type (initial_state);
- g_return_val_if_fail (g_variant_type_is_tuple (type), NULL);
-
- return g_object_new (G_TYPE_TUPLE_ACTION,
- "name", name,
- "state", initial_state,
- NULL);
-}
-
-void
-g_tuple_action_set_child (GTupleAction *action,
- gsize index,
- GVariant *value)
-{
- const GVariantType *type;
-
- g_return_if_fail (G_IS_TUPLE_ACTION (action));
- g_return_if_fail (index < action->n_children);
- g_return_if_fail (value != NULL);
-
- type = g_variant_get_type (value);
- g_return_if_fail (g_variant_is_of_type (value, type));
-
- g_variant_unref (action->children[index]);
- action->children[index] = g_variant_ref_sink (value);
-
- g_object_notify_by_pspec (G_OBJECT (action), properties[PROP_STATE]);
-}
diff --git a/libmessaging-menu/gtupleaction.h b/libmessaging-menu/gtupleaction.h
deleted file mode 100644
index c447d71..0000000
--- a/libmessaging-menu/gtupleaction.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2012 Canonical Ltd.
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- * Lars Uebernickel <lars.uebernickel@canonical.com>
- */
-
-#ifndef __g_tuple_action_h__
-#define __g_tuple_action_h__
-
-#include <gio/gio.h>
-
-#define G_TYPE_TUPLE_ACTION (g_tuple_action_get_type ())
-#define G_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TUPLE_ACTION, GTupleAction))
-#define G_IS_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TUPLE_ACTION))
-
-typedef struct _GTupleAction GTupleAction;
-
-GType g_tuple_action_get_type (void) G_GNUC_CONST;
-
-GTupleAction * g_tuple_action_new (const gchar *name,
- GVariant *initial_state);
-
-void g_tuple_action_set_child (GTupleAction *action,
- gsize index,
- GVariant *value);
-
-#endif
diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu-app.c
index 70861d3..c841db2 100644
--- a/libmessaging-menu/messaging-menu.c
+++ b/libmessaging-menu/messaging-menu-app.c
@@ -17,11 +17,12 @@
* Lars Uebernickel <lars.uebernickel@canonical.com>
*/
-#include "messaging-menu.h"
+#include "messaging-menu-app.h"
#include "indicator-messages-service.h"
-#include "gtupleaction.h"
+#include "indicator-messages-application.h"
#include <gio/gdesktopappinfo.h>
+#include <string.h>
/**
* SECTION:messaging-menu
@@ -103,8 +104,11 @@ struct _MessagingMenuApp
int registered; /* -1 for unknown */
MessagingMenuStatus status;
gboolean status_set;
- GSimpleActionGroup *source_actions;
- GMenu *menu;
+ GDBusConnection *bus;
+
+ GHashTable *messages;
+ GList *sources;
+ IndicatorMessagesApplication *app_interface;
IndicatorMessagesService *messages_service;
guint watch_id;
@@ -114,14 +118,6 @@ struct _MessagingMenuApp
G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT);
-enum
-{
- INDEX_COUNT,
- INDEX_TIME,
- INDEX_STRING,
- INDEX_DRAWS_ATTENTION
-};
-
enum {
PROP_0,
PROP_DESKTOP_ID,
@@ -139,10 +135,61 @@ static guint signals[N_SIGNALS];
static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };
+typedef struct
+{
+ gchar *id;
+ GIcon *icon;
+ gchar *label;
+
+ guint32 count;
+ gint64 time;
+ gchar *string;
+ gboolean draws_attention;
+} Source;
+
static void global_status_changed (IndicatorMessagesService *service,
const gchar *status_str,
gpointer user_data);
+/* in messaging-menu-message.c */
+GVariant * _messaging_menu_message_to_variant (MessagingMenuMessage *msg);
+
+static void
+source_free (gpointer data)
+{
+ Source *source = data;
+
+ if (source)
+ {
+ g_free (source->id);
+ g_clear_object (&source->icon);
+ g_free (source->label);
+ g_free (source->string);
+ g_slice_free (Source, source);
+ }
+}
+
+static GVariant *
+source_to_variant (Source *source)
+{
+ GVariant *v;
+ gchar *iconstr;
+
+ iconstr = source->icon ? g_icon_to_string (source->icon) : NULL;
+
+ v = g_variant_new ("(sssuxsb)", source->id,
+ source->label,
+ iconstr ? iconstr : "",
+ source->count,
+ source->time,
+ source->string ? source->string : "",
+ source->draws_attention);
+
+ g_free (iconstr);
+
+ return v;
+}
+
static gchar *
messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app)
{
@@ -161,49 +208,32 @@ messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app)
}
static void
-export_menus_and_actions (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+messaging_menu_app_got_bus (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
MessagingMenuApp *app = user_data;
- GDBusConnection *bus;
GError *error = NULL;
- guint id;
gchar *object_path;
- object_path = messaging_menu_app_get_dbus_object_path (app);
- if (!object_path)
- return;
-
- bus = g_bus_get_finish (res, &error);
- if (bus == NULL)
+ app->bus = g_bus_get_finish (res, &error);
+ if (app->bus == NULL)
{
g_warning ("unable to connect to session bus: %s", error->message);
g_error_free (error);
return;
}
- id = g_dbus_connection_export_action_group (bus,
- object_path,
- G_ACTION_GROUP (app->source_actions),
- &error);
- if (!id)
- {
- g_warning ("unable to export action group: %s", error->message);
- g_error_free (error);
- }
+ object_path = messaging_menu_app_get_dbus_object_path (app);
- id = g_dbus_connection_export_menu_model (bus,
- object_path,
- G_MENU_MODEL (app->menu),
- &error);
- if (!id)
+ if (object_path &&
+ !g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (app->app_interface),
+ app->bus, object_path, &error))
{
- g_warning ("unable to export menu: %s", error->message);
- g_error_free (error);
+ g_warning ("unable to export application interface: %s", error->message);
+ g_clear_error (&error);
}
- g_object_unref (bus);
g_free (object_path);
}
@@ -223,7 +253,7 @@ messaging_menu_app_set_desktop_id (MessagingMenuApp *app,
g_bus_get (G_BUS_TYPE_SESSION,
app->cancellable,
- export_menus_and_actions,
+ messaging_menu_app_got_bus,
app);
}
@@ -278,9 +308,14 @@ messaging_menu_app_dispose (GObject *object)
g_clear_object (&app->messages_service);
}
+ g_clear_pointer (&app->messages, g_hash_table_unref);
+
+ g_list_free_full (app->sources, source_free);
+ app->sources = NULL;
+
+ g_clear_object (&app->app_interface);
g_clear_object (&app->appinfo);
- g_clear_object (&app->source_actions);
- g_clear_object (&app->menu);
+ g_clear_object (&app->bus);
G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object);
}
@@ -411,18 +446,190 @@ indicator_messages_vanished (GDBusConnection *bus,
}
}
+static gboolean
+messaging_menu_app_list_sources (IndicatorMessagesApplication *app_interface,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ GVariantBuilder builder;
+ GList *it;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssuxsb)"));
+
+ for (it = app->sources; it; it = it->next)
+ g_variant_builder_add_value (&builder, source_to_variant (it->data));
+
+ indicator_messages_application_complete_list_sources (app_interface,
+ invocation,
+ g_variant_builder_end (&builder));
+
+ return TRUE;
+}
+
+static gint
+compare_source_id (gconstpointer a,
+ gconstpointer b)
+{
+ const Source *source = a;
+ const gchar *id = b;
+
+ return strcmp (source->id, id);
+}
+
+static gboolean
+messaging_menu_app_remove_source_internal (MessagingMenuApp *app,
+ const gchar *source_id)
+{
+ GList *node;
+
+ node = g_list_find_custom (app->sources, source_id, compare_source_id);
+ if (node)
+ {
+ source_free (node->data);
+ app->sources = g_list_delete_link (app->sources, node);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+messaging_menu_app_remove_message_internal (MessagingMenuApp *app,
+ const gchar *message_id)
+{
+ return g_hash_table_remove (app->messages, message_id);
+}
+
+static gboolean
+messaging_menu_app_activate_source (IndicatorMessagesApplication *app_interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *source_id,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ GQuark q = g_quark_from_string (source_id);
+
+ /* Activate implies removing the source, no need for SourceRemoved */
+ if (messaging_menu_app_remove_source_internal (app, source_id))
+ g_signal_emit (app, signals[ACTIVATE_SOURCE], q, source_id);
+
+ indicator_messages_application_complete_activate_source (app_interface, invocation);
+
+ return TRUE;
+}
+
+static gboolean
+messaging_menu_app_list_messages (IndicatorMessagesApplication *app_interface,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ GVariantBuilder builder;
+ GHashTableIter iter;
+ MessagingMenuMessage *message;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssssxaa{sv}b)"));
+
+ g_hash_table_iter_init (&iter, app->messages);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &message))
+ g_variant_builder_add_value (&builder, _messaging_menu_message_to_variant (message));
+
+ indicator_messages_application_complete_list_messages (app_interface,
+ invocation,
+ g_variant_builder_end (&builder));
+
+ return TRUE;
+}
+
+static gboolean
+messaging_menu_app_activate_message (IndicatorMessagesApplication *app_interface,
+ GDBusMethodInvocation *invocation,
+ const gchar *message_id,
+ const gchar *action_id,
+ GVariant *params,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ MessagingMenuMessage *msg;
+
+ msg = g_hash_table_lookup (app->messages, message_id);
+ if (msg)
+ {
+ if (*action_id)
+ {
+ gchar *signal;
+
+ signal = g_strconcat ("activate::", action_id, NULL);
+
+ if (g_variant_n_children (params))
+ {
+ GVariant *param;
+
+ g_variant_get_child (params, 0, "v", &param);
+ g_signal_emit_by_name (msg, signal, action_id, param);
+
+ g_variant_unref (param);
+ }
+ else
+ g_signal_emit_by_name (msg, signal, action_id, NULL);
+
+ g_free (signal);
+ }
+ else
+ g_signal_emit_by_name (msg, "activate", NULL, NULL);
+
+
+ /* Activate implies removing the message, no need for MessageRemoved */
+ messaging_menu_app_remove_message_internal (app, message_id);
+ }
+
+ indicator_messages_application_complete_activate_message (app_interface, invocation);
+
+ return TRUE;
+}
+
+static gboolean
+messaging_menu_app_dismiss (IndicatorMessagesApplication *app_interface,
+ GDBusMethodInvocation *invocation,
+ const gchar * const *sources,
+ const gchar * const *messages,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ const gchar * const *it;
+
+ for (it = sources; *it; it++)
+ messaging_menu_app_remove_source_internal (app, *it);
+
+ for (it = messages; *it; it++)
+ messaging_menu_app_remove_message_internal (app, *it);
+
+ return TRUE;
+}
+
static void
messaging_menu_app_init (MessagingMenuApp *app)
{
app->registered = -1;
app->status_set = FALSE;
+ app->bus = NULL;
app->cancellable = g_cancellable_new ();
- app->source_actions = g_simple_action_group_new ();
- app->menu = g_menu_new ();
+ app->app_interface = indicator_messages_application_skeleton_new ();
+ g_signal_connect (app->app_interface, "handle-list-sources",
+ G_CALLBACK (messaging_menu_app_list_sources), app);
+ g_signal_connect (app->app_interface, "handle-activate-source",
+ G_CALLBACK (messaging_menu_app_activate_source), app);
+ g_signal_connect (app->app_interface, "handle-list-messages",
+ G_CALLBACK (messaging_menu_app_list_messages), app);
+ g_signal_connect (app->app_interface, "handle-activate-message",
+ G_CALLBACK (messaging_menu_app_activate_message), app);
+ g_signal_connect (app->app_interface, "handle-dismiss",
+ G_CALLBACK (messaging_menu_app_dismiss), app);
- app->cancellable = g_cancellable_new ();
+ app->messages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
"com.canonical.indicator.messages",
@@ -595,77 +802,73 @@ global_status_changed (IndicatorMessagesService *service,
g_signal_emit (app, signals[STATUS_CHANGED], 0, status);
}
-static void
-source_action_activated (GTupleAction *action,
- GVariant *parameter,
- gpointer user_data)
+static Source *
+messaging_menu_app_lookup_source (MessagingMenuApp *app,
+ const gchar *id)
{
- MessagingMenuApp *app = user_data;
- const gchar *name = g_action_get_name (G_ACTION (action));
- GQuark q = g_quark_from_string (name);
+ GList *node;
- messaging_menu_app_remove_source (app, name);
+ node = g_list_find_custom (app->sources, id, compare_source_id);
- g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name);
+ return node ? node->data : NULL;
}
-static void
-messaging_menu_app_insert_source_action (MessagingMenuApp *app,
- gint position,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- GVariant *state)
+static Source *
+messaging_menu_app_get_source (MessagingMenuApp *app,
+ const gchar *id)
{
- GTupleAction *action;
- GMenuItem *menuitem;
+ Source *source;
- g_return_if_fail (MESSAGING_MENU_IS_APP (app));
- g_return_if_fail (id != NULL);
+ source = messaging_menu_app_lookup_source (app, id);
+ if (!source)
+ g_warning ("a source with id '%s' doesn't exist", id);
- if (g_simple_action_group_lookup (app->source_actions, id))
- {
- g_warning ("a source with id '%s' already exists", id);
- return;
- }
-
- action = g_tuple_action_new (id, state);
- g_signal_connect (action, "activate",
- G_CALLBACK (source_action_activated), app);
- g_simple_action_group_insert (app->source_actions, G_ACTION (action));
- g_object_unref (action);
+ return source;
+}
- menuitem = g_menu_item_new (label, id);
- g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem");
- if (icon)
- {
- gchar *iconstr = g_icon_to_string (icon);
- g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr);
- g_free (iconstr);
- }
- g_menu_insert_item (app->menu, position, menuitem);
- g_object_unref (menuitem);
+static void
+messaging_menu_app_notify_source_changed (MessagingMenuApp *app,
+ Source *source)
+{
+ indicator_messages_application_emit_source_changed (app->app_interface,
+ source_to_variant (source));
}
static void
-messaging_menu_app_set_source_action (MessagingMenuApp *app,
- const gchar *source_id,
- gsize index,
- GVariant *child)
+messaging_menu_app_insert_source_internal (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count,
+ gint64 time,
+ const gchar *string)
{
- GAction *action;
+ Source *source;
g_return_if_fail (MESSAGING_MENU_IS_APP (app));
- g_return_if_fail (source_id != NULL);
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (label != NULL);
- action = g_simple_action_group_lookup (app->source_actions, source_id);
- if (action == NULL)
+ if (messaging_menu_app_lookup_source (app, id))
{
- g_warning ("a source with id '%s' doesn't exist", source_id);
+ g_warning ("a source with id '%s' already exists", id);
return;
}
- g_tuple_action_set_child (G_TUPLE_ACTION (action), index, child);
+ source = g_slice_new0 (Source);
+ source->id = g_strdup (id);
+ source->label = g_strdup (label);
+ if (icon)
+ source->icon = g_object_ref (icon);
+ source->count = count;
+ source->time = time;
+ source->string = g_strdup (string);
+ app->sources = g_list_insert (app->sources, source, position);
+
+ indicator_messages_application_emit_source_added (app->app_interface,
+ position,
+ source_to_variant (source));
}
/**
@@ -742,8 +945,7 @@ messaging_menu_app_insert_source_with_count (MessagingMenuApp *app,
const gchar *label,
guint count)
{
- messaging_menu_app_insert_source_action (app, position, id, icon, label,
- g_variant_new ("(uxsb)", count, 0, "", FALSE));
+ messaging_menu_app_insert_source_internal (app, position, id, icon, label, count, 0, "");
}
/**
@@ -797,8 +999,7 @@ messaging_menu_app_insert_source_with_time (MessagingMenuApp *app,
const gchar *label,
gint64 time)
{
- messaging_menu_app_insert_source_action (app, position, id, icon, label,
- g_variant_new ("(uxsb)", 0, time, "", FALSE));
+ messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, time, "");
}
/**
@@ -854,8 +1055,7 @@ messaging_menu_app_insert_source_with_string (MessagingMenuApp *app,
const gchar *label,
const gchar *str)
{
- messaging_menu_app_insert_source_action (app, position, id, icon, label,
- g_variant_new ("(uxsb)", 0, 0, str, FALSE));
+ messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, 0, str);
}
/**
@@ -895,34 +1095,11 @@ void
messaging_menu_app_remove_source (MessagingMenuApp *app,
const gchar *source_id)
{
- int n_items;
- int i;
-
g_return_if_fail (MESSAGING_MENU_IS_APP (app));
g_return_if_fail (source_id != NULL);
- if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL)
- return;
-
- n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu));
- for (i = 0; i < n_items; i++)
- {
- gchar *action;
-
- if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i,
- "action", "s", &action))
- {
- if (!g_strcmp0 (action, source_id))
- {
- g_menu_remove (app->menu, i);
- break;
- }
-
- g_free (action);
- }
- }
-
- g_simple_action_group_remove (app->source_actions, source_id);
+ if (messaging_menu_app_remove_source_internal (app, source_id))
+ indicator_messages_application_emit_source_removed (app->app_interface, source_id);
}
/**
@@ -939,46 +1116,7 @@ messaging_menu_app_has_source (MessagingMenuApp *app,
g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE);
g_return_val_if_fail (source_id != NULL, FALSE);
- return g_simple_action_group_lookup (app->source_actions, source_id) != NULL;
-}
-
-static GMenuItem *
-g_menu_find_item_with_action (GMenu *menu,
- const gchar *action,
- gint *out_pos)
-{
- gint i;
- gint n_elements;
- GMenuItem *item = NULL;
-
- n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu));
-
- for (i = 0; i < n_elements && item == NULL; i++)
- {
- GVariant *attr;
-
- item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
- attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING);
-
- if (!g_str_equal (action, g_variant_get_string (attr, NULL)))
- g_clear_object (&item);
-
- g_variant_unref (attr);
- }
-
- if (item && out_pos)
- *out_pos = i - 1;
-
- return item;
-}
-
-static void
-g_menu_replace_item (GMenu *menu,
- gint pos,
- GMenuItem *item)
-{
- g_menu_remove (menu, pos);
- g_menu_insert_item (menu, pos, item);
+ return messaging_menu_app_lookup_source (app, source_id) != NULL;
}
/**
@@ -994,28 +1132,26 @@ messaging_menu_app_set_source_label (MessagingMenuApp *app,
const gchar *source_id,
const gchar *label)
{
- gint pos;
- GMenuItem *item;
+ Source *source;
g_return_if_fail (MESSAGING_MENU_IS_APP (app));
g_return_if_fail (source_id != NULL);
g_return_if_fail (label != NULL);
- item = g_menu_find_item_with_action (app->menu, source_id, &pos);
- if (item == NULL)
- return;
-
- g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label);
- g_menu_replace_item (app->menu, pos, item);
-
- g_object_unref (item);
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ g_free (source->label);
+ source->label = g_strdup (label);
+ messaging_menu_app_notify_source_changed (app, source);
+ }
}
/**
* messaging_menu_app_set_source_icon:
* @app: a #MessagingMenuApp
* @source_id: a source id
- * @icon: the new icon for the source
+ * @icon: (allow-none): the new icon for the source
*
* Changes the icon of @source_id to @icon.
*/
@@ -1024,23 +1160,19 @@ messaging_menu_app_set_source_icon (MessagingMenuApp *app,
const gchar *source_id,
GIcon *icon)
{
- gint pos;
- GMenuItem *item;
- gchar *iconstr;
+ Source *source;
g_return_if_fail (MESSAGING_MENU_IS_APP (app));
g_return_if_fail (source_id != NULL);
- item = g_menu_find_item_with_action (app->menu, source_id, &pos);
- if (item == NULL)
- return;
-
- iconstr = icon ? g_icon_to_string (icon) : NULL;
- g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
- g_menu_replace_item (app->menu, pos, item);
-
- g_free (iconstr);
- g_object_unref (item);
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ g_clear_object (&source->icon);
+ if (icon)
+ source->icon = g_object_ref (icon);
+ messaging_menu_app_notify_source_changed (app, source);
+ }
}
/**
@@ -1055,8 +1187,17 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app,
const gchar *source_id,
guint count)
{
- messaging_menu_app_set_source_action (app, source_id, INDEX_COUNT,
- g_variant_new_uint32 (count));
+ Source *source;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ source->count = count;
+ messaging_menu_app_notify_source_changed (app, source);
+ }
}
/**
@@ -1066,17 +1207,23 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app,
* @time: the new time for the source, in microseconds
*
* Updates the time of @source_id to @time.
- *
- * Note that the time is only displayed if the source does not also have a
- * count associated with it.
*/
void
messaging_menu_app_set_source_time (MessagingMenuApp *app,
const gchar *source_id,
gint64 time)
{
- messaging_menu_app_set_source_action (app, source_id, INDEX_TIME,
- g_variant_new_int64 (time));
+ Source *source;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ source->time = time;
+ messaging_menu_app_notify_source_changed (app, source);
+ }
}
/**
@@ -1086,17 +1233,24 @@ messaging_menu_app_set_source_time (MessagingMenuApp *app,
* @str: the new string for the source
*
* Updates the string displayed next to @source_id to @str.
- *
- * Note that the string is only displayed if the source does not also have a
- * count or time associated with it.
*/
void
messaging_menu_app_set_source_string (MessagingMenuApp *app,
const gchar *source_id,
const gchar *str)
{
- messaging_menu_app_set_source_action (app, source_id, INDEX_STRING,
- g_variant_new_string (str));
+ Source *source;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ g_free (source->string);
+ source->string = g_strdup (str);
+ messaging_menu_app_notify_source_changed (app, source);
+ }
}
/**
@@ -1114,8 +1268,17 @@ void
messaging_menu_app_draw_attention (MessagingMenuApp *app,
const gchar *source_id)
{
- messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION,
- g_variant_new_boolean (TRUE));
+ Source *source;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ source->draws_attention = TRUE;
+ messaging_menu_app_notify_source_changed (app, source);
+ }
}
/**
@@ -1136,6 +1299,131 @@ void
messaging_menu_app_remove_attention (MessagingMenuApp *app,
const gchar *source_id)
{
- messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION,
- g_variant_new_boolean (FALSE));
+ Source *source;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source)
+ {
+ source->draws_attention = FALSE;
+ messaging_menu_app_notify_source_changed (app, source);
+ }
+}
+
+/**
+ * messaging_menu_app_append_message:
+ * @app: a #MessagingMenuApp
+ * @msg: the #MessagingMenuMessage to append
+ * @source_id: (allow-none): the source id to which @msg is added, or NULL
+ * @notify: whether a notification bubble should be shown for this
+ * message
+ *
+ * Appends @msg to the source with id @source_id of @app. The messaging
+ * menu might not display this message immediately if other messages are
+ * queued before this one.
+ *
+ * If @source_id has a count associated with it, that count will be
+ * increased by one.
+ *
+ * If @source_id is %NULL, @msg won't be associated with a source.
+ */
+void
+messaging_menu_app_append_message (MessagingMenuApp *app,
+ MessagingMenuMessage *msg,
+ const gchar *source_id,
+ gboolean notify)
+{
+ const gchar *id;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
+
+ id = messaging_menu_message_get_id (msg);
+
+ if (g_hash_table_lookup (app->messages, id))
+ {
+ g_warning ("a message with id '%s' already exists", id);
+ return;
+ }
+
+ g_hash_table_insert (app->messages, g_strdup (id), g_object_ref (msg));
+ indicator_messages_application_emit_message_added (app->app_interface,
+ _messaging_menu_message_to_variant (msg));
+
+ if (source_id)
+ {
+ Source *source;
+
+ source = messaging_menu_app_get_source (app, source_id);
+ if (source && source->count >= 0)
+ {
+ source->count++;
+ messaging_menu_app_notify_source_changed (app, source);
+ }
+ }
+}
+
+/**
+ * messaging_menu_app_get_message:
+ * @app: a #MessagingMenuApp
+ * @id: id of the message to retrieve
+ *
+ * Retrieves the message with @id, that was added with
+ * messaging_menu_app_append_message().
+ *
+ * Returns: (transfer none) (allow-none): the #MessagingMenuApp with
+ * @id, or %NULL
+ */
+MessagingMenuMessage *
+messaging_menu_app_get_message (MessagingMenuApp *app,
+ const gchar *id)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_hash_table_lookup (app->messages, id);
+}
+
+/**
+ * messaging_menu_app_remove_message:
+ * @app: a #MessagingMenuApp
+ * @msg: the #MessagingMenuMessage to remove
+ *
+ * Removes @msg from @app.
+ *
+ * If @source_id has a count associated with it, that count will be
+ * decreased by one.
+ */
+void
+messaging_menu_app_remove_message (MessagingMenuApp *app,
+ MessagingMenuMessage *msg)
+{
+ /* take a ref of @msg here to make sure the pointer returned by
+ * _get_id() is valid for the duration of remove_message_by_id. */
+ g_object_ref (msg);
+ messaging_menu_app_remove_message_by_id (app, messaging_menu_message_get_id (msg));
+ g_object_unref (msg);
+}
+
+/**
+ * messaging_menu_app_remove_message_by_id:
+ * @app: a #MessagingMenuApp
+ * @id: the unique id of @msg
+ *
+ * Removes the message with the id @id from @app.
+ *
+ * If @source_id has a count associated with it, that count will be
+ * decreased by one.
+ */
+void
+messaging_menu_app_remove_message_by_id (MessagingMenuApp *app,
+ const gchar *id)
+{
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (id != NULL);
+
+ if (messaging_menu_app_remove_message_internal (app, id))
+ indicator_messages_application_emit_message_removed (app->app_interface, id);
}
diff --git a/libmessaging-menu/messaging-menu-app.h b/libmessaging-menu/messaging-menu-app.h
new file mode 100644
index 0000000..c8097e1
--- /dev/null
+++ b/libmessaging-menu/messaging-menu-app.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#ifndef __messaging_menu_app_h__
+#define __messaging_menu_app_h__
+
+#include <gio/gio.h>
+#include "messaging-menu-message.h"
+
+G_BEGIN_DECLS
+
+#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type()
+#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp))
+#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass))
+#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP))
+
+/**
+ * MessagingMenuStatus:
+ * @MESSAGING_MENU_STATUS_AVAILABLE: available
+ * @MESSAGING_MENU_STATUS_AWAY: away
+ * @MESSAGING_MENU_STATUS_BUSY: busy
+ * @MESSAGING_MENU_STATUS_INVISIBLE: invisible
+ * @MESSAGING_MENU_STATUS_OFFLINE: offline
+ *
+ * An enumeration for the possible chat statuses the messaging menu can be in.
+ */
+typedef enum {
+ MESSAGING_MENU_STATUS_AVAILABLE,
+ MESSAGING_MENU_STATUS_AWAY,
+ MESSAGING_MENU_STATUS_BUSY,
+ MESSAGING_MENU_STATUS_INVISIBLE,
+ MESSAGING_MENU_STATUS_OFFLINE
+} MessagingMenuStatus;
+
+
+typedef GObjectClass MessagingMenuAppClass;
+typedef struct _MessagingMenuApp MessagingMenuApp;
+
+GType messaging_menu_app_get_type (void) G_GNUC_CONST;
+
+MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id);
+
+void messaging_menu_app_register (MessagingMenuApp *app);
+void messaging_menu_app_unregister (MessagingMenuApp *app);
+
+void messaging_menu_app_set_status (MessagingMenuApp *app,
+ MessagingMenuStatus status);
+
+void messaging_menu_app_insert_source (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label);
+
+void messaging_menu_app_append_source (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label);
+
+void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count);
+
+void messaging_menu_app_append_source_with_count (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count);
+
+void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ gint64 time);
+
+void messaging_menu_app_append_source_with_time (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ gint64 time);
+
+void messaging_menu_app_append_source_with_string (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ const gchar *str);
+
+void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ const gchar *str);
+
+void messaging_menu_app_remove_source (MessagingMenuApp *app,
+ const gchar *source_id);
+
+gboolean messaging_menu_app_has_source (MessagingMenuApp *app,
+ const gchar *source_id);
+
+void messaging_menu_app_set_source_label (MessagingMenuApp *app,
+ const gchar *source_id,
+ const gchar *label);
+
+void messaging_menu_app_set_source_icon (MessagingMenuApp *app,
+ const gchar *source_id,
+ GIcon *icon);
+
+void messaging_menu_app_set_source_count (MessagingMenuApp *app,
+ const gchar *source_id,
+ guint count);
+
+void messaging_menu_app_set_source_time (MessagingMenuApp *app,
+ const gchar *source_id,
+ gint64 time);
+
+void messaging_menu_app_set_source_string (MessagingMenuApp *app,
+ const gchar *source_id,
+ const gchar *str);
+
+void messaging_menu_app_draw_attention (MessagingMenuApp *app,
+ const gchar *source_id);
+
+void messaging_menu_app_remove_attention (MessagingMenuApp *app,
+ const gchar *source_id);
+
+void messaging_menu_app_append_message (MessagingMenuApp *app,
+ MessagingMenuMessage *msg,
+ const gchar *source_id,
+ gboolean notify);
+
+MessagingMenuMessage * messaging_menu_app_get_message (MessagingMenuApp *app,
+ const gchar *id);
+
+void messaging_menu_app_remove_message (MessagingMenuApp *app,
+ MessagingMenuMessage *msg);
+
+void messaging_menu_app_remove_message_by_id (MessagingMenuApp *app,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif
diff --git a/libmessaging-menu/messaging-menu-message.c b/libmessaging-menu/messaging-menu-message.c
new file mode 100644
index 0000000..b81cbea
--- /dev/null
+++ b/libmessaging-menu/messaging-menu-message.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#include "messaging-menu-message.h"
+
+typedef GObjectClass MessagingMenuMessageClass;
+
+struct _MessagingMenuMessage
+{
+ GObject parent;
+
+ gchar *id;
+ GIcon *icon;
+ gchar *title;
+ gchar *subtitle;
+ gchar *body;
+ gint64 time;
+ gboolean draws_attention;
+
+ GSList *actions;
+};
+
+G_DEFINE_TYPE (MessagingMenuMessage, messaging_menu_message, G_TYPE_OBJECT);
+
+enum
+{
+ PROP_0,
+ PROP_ID,
+ PROP_ICON,
+ PROP_TITLE,
+ PROP_SUBTITLE,
+ PROP_BODY,
+ PROP_TIME,
+ PROP_DRAWS_ATTENTION,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+typedef struct
+{
+ gchar *id;
+ gchar *label;
+ GVariantType *parameter_type;
+ GVariant *parameter_hint;
+} Action;
+
+static void
+action_free (gpointer data)
+{
+ Action *action = data;
+
+ g_free (action->id);
+ g_free (action->label);
+
+ if (action->parameter_type)
+ g_variant_type_free (action->parameter_type);
+
+ if (action->parameter_hint)
+ g_variant_unref (action->parameter_hint);
+
+ g_slice_free (Action, action);
+}
+
+static void
+messaging_menu_message_dispose (GObject *object)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ g_clear_object (&msg->icon);
+
+ G_OBJECT_CLASS (messaging_menu_message_parent_class)->dispose (object);
+}
+
+static void
+messaging_menu_message_finalize (GObject *object)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ g_free (msg->id);
+ g_free (msg->title);
+ g_free (msg->subtitle);
+ g_free (msg->body);
+
+ g_slist_free_full (msg->actions, action_free);
+ msg->actions = NULL;
+
+ G_OBJECT_CLASS (messaging_menu_message_parent_class)->finalize (object);
+}
+
+static void
+messaging_menu_message_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, msg->id);
+ break;
+
+ case PROP_ICON:
+ g_value_set_object (value, msg->icon);
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, msg->title);
+ break;
+
+ case PROP_SUBTITLE:
+ g_value_set_string (value, msg->subtitle);
+ break;
+
+ case PROP_BODY:
+ g_value_set_string (value, msg->body);
+
+ case PROP_TIME:
+ g_value_set_int64 (value, msg->time);
+ break;
+
+ case PROP_DRAWS_ATTENTION:
+ g_value_set_boolean (value, msg->draws_attention);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+messaging_menu_message_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ msg->id = g_value_dup_string (value);
+ break;
+
+ case PROP_ICON:
+ msg->icon = g_value_dup_object (value);
+ break;
+
+ case PROP_TITLE:
+ msg->title = g_value_dup_string (value);
+ break;
+
+ case PROP_SUBTITLE:
+ msg->subtitle = g_value_dup_string (value);
+ break;
+
+ case PROP_BODY:
+ msg->body = g_value_dup_string (value);
+
+ case PROP_TIME:
+ msg->time = g_value_get_int64 (value);
+ break;
+
+ case PROP_DRAWS_ATTENTION:
+ messaging_menu_message_set_draws_attention (msg, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+messaging_menu_message_class_init (MessagingMenuMessageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = messaging_menu_message_dispose;
+ object_class->finalize = messaging_menu_message_finalize;
+ object_class->get_property = messaging_menu_message_get_property;
+ object_class->set_property = messaging_menu_message_set_property;
+
+ properties[PROP_ID] = g_param_spec_string ("id", "Id",
+ "Unique id of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] = g_param_spec_object ("icon", "Icon",
+ "Icon of the message",
+ G_TYPE_ICON,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TITLE] = g_param_spec_string ("title", "Title",
+ "Title of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SUBTITLE] = g_param_spec_string ("subtitle", "Subtitle",
+ "Subtitle of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_BODY] = g_param_spec_string ("body", "Body",
+ "First lines of the body of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TIME] = g_param_spec_int64 ("time", "Time",
+ "Time the message was sent, in microseconds", 0, G_MAXINT64, 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention", "Draws attention",
+ "Whether the message should draw attention",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (klass, NUM_PROPERTIES, properties);
+
+ /**
+ * MessagingMenuMessage::activate:
+ * @msg: the #MessagingMenuMessage
+ * @action: (allow-none): the id of activated action, or %NULL
+ * @parameter: (allow-none): activation parameter, or %NULL
+ *
+ * Emitted when the user has activated the message. The message is
+ * immediately removed from the application's menu, handlers of this
+ * signal do not need to call messaging_menu_app_remove_message().
+ */
+ g_signal_new ("activate",
+ MESSAGING_MENU_TYPE_MESSAGE,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_VARIANT);
+}
+
+static void
+messaging_menu_message_init (MessagingMenuMessage *self)
+{
+}
+
+/**
+ * messaging_menu_message_new:
+ * @id: unique id of the message
+ * @icon: (transfer full) (allow-none): a #GIcon representing the message
+ * @title: the title of the message
+ * @subtitle: (allow-none): the subtitle of the message
+ * @body: (allow-none): the message body
+ * @time: the time the message was received
+ *
+ * Creates a new #MessagingMenuMessage.
+ *
+ * Returns: (transfer full): a new #MessagingMenuMessage
+ */
+MessagingMenuMessage *
+messaging_menu_message_new (const gchar *id,
+ GIcon *icon,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *body,
+ gint64 time)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (title != NULL, NULL);
+
+ return g_object_new (MESSAGING_MENU_TYPE_MESSAGE,
+ "id", id,
+ "icon", icon,
+ "title", title,
+ "subtitle", subtitle,
+ "body", body,
+ "time", time,
+ NULL);
+}
+
+/**
+ * messaging_menu_message_get_id:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the unique id of @msg
+ */
+const gchar *
+messaging_menu_message_get_id (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->id;
+}
+
+/**
+ * messaging_menu_message_get_icon:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: (transfer none): the icon of @msg
+ */
+GIcon *
+messaging_menu_message_get_icon (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->icon;
+}
+
+/**
+ * messaging_menu_message_get_title:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the title of @msg
+ */
+const gchar *
+messaging_menu_message_get_title (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->title;
+}
+
+/**
+ * messaging_menu_message_get_subtitle:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the subtitle of @msg
+ */
+const gchar *
+messaging_menu_message_get_subtitle (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->subtitle;
+}
+
+/**
+ * messaging_menu_message_get_body:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the body of @msg
+ */
+const gchar *
+messaging_menu_message_get_body (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->body;
+}
+
+/**
+ * messaging_menu_message_get_time:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the time at which @msg was received
+ */
+gint64
+messaging_menu_message_get_time (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), 0);
+
+ return msg->time;
+}
+
+/**
+ * messaging_menu_message_get_draws_attention:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: whether @msg is drawing attention
+ */
+gboolean
+messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), FALSE);
+
+ return msg->draws_attention;
+}
+
+/**
+ * messaging_menu_message_set_draws_attention:
+ * @msg: a #MessagingMenuMessage
+ * @draws_attention: whether @msg should draw attention
+ *
+ * Sets whether @msg is drawing attention.
+ */
+void
+messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
+ gboolean draws_attention)
+{
+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
+
+ msg->draws_attention = draws_attention;
+ g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_DRAWS_ATTENTION]);
+}
+
+/**
+ * messaging_menu_message_add_action:
+ * @msg: a #MessagingMenuMessage
+ * @id: unique id of the action
+ * @label: (allow-none): label of the action
+ * @parameter_type: (allow-none): a #GVariantType
+ * @parameter_hint: (allow-none): a #GVariant suggesting a valid range
+ * for parameters
+ *
+ * Adds an action with @id and @label to @message. Actions are an
+ * alternative way for users to activate a message. Note that messages
+ * can still be activated without an action.
+ *
+ * If @parameter_type is non-%NULL, the action is able to receive user
+ * input in addition to simply activating the action. Currently, only
+ * string parameters are supported.
+ *
+ * A list of predefined parameters can be supplied as a #GVariant array
+ * of @parameter_type in @parameter_hint. If @parameter_hint is
+ * floating, it will be consumed.
+ *
+ * It is recommended to add at most two actions to a message.
+ */
+void
+messaging_menu_message_add_action (MessagingMenuMessage *msg,
+ const gchar *id,
+ const gchar *label,
+ const GVariantType *parameter_type,
+ GVariant *parameter_hint)
+{
+ Action *action;
+
+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
+ g_return_if_fail (id != NULL);
+
+ action = g_slice_new (Action);
+ action->id = g_strdup (id);
+ action->label = g_strdup (label);
+ action->parameter_type = parameter_type ? g_variant_type_copy (parameter_type) : NULL;
+ action->parameter_hint = parameter_hint ? g_variant_ref_sink (parameter_hint) : NULL;
+
+ msg->actions = g_slist_append (msg->actions, action);
+}
+
+static GVariant *
+action_to_variant (Action *action)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string (action->id));
+
+ if (action->label)
+ g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (action->label));
+
+ if (action->parameter_type)
+ {
+ gchar *type = g_variant_type_dup_string (action->parameter_type);
+ g_variant_builder_add (&builder, "{sv}", "parameter-type", g_variant_new_signature (type));
+ g_free (type);
+ }
+
+ if (action->parameter_hint)
+ g_variant_builder_add (&builder, "{sv}", "parameter-hint", action->parameter_hint);
+
+ return g_variant_builder_end (&builder);
+}
+
+/*<internal>
+ * _messaging_menu_message_to_variant:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Serializes @msg to a #GVariant of the form (sssssxaa{sv}b):
+ *
+ * id
+ * icon
+ * title
+ * subtitle
+ * body
+ * time
+ * array of action dictionaries
+ * draws_attention
+ *
+ * Returns: a new floating #GVariant instance
+ */
+GVariant *
+_messaging_menu_message_to_variant (MessagingMenuMessage *msg)
+{
+ GVariantBuilder builder;
+ GSList *it;
+
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sssssxaa{sv}b)"));
+
+ g_variant_builder_add (&builder, "s", msg->id);
+
+ if (msg->icon)
+ {
+ gchar *iconstr;
+
+ iconstr = g_icon_to_string (msg->icon);
+ g_variant_builder_add (&builder, "s", iconstr);
+
+ g_free (iconstr);
+ }
+ else
+ g_variant_builder_add (&builder, "s", "");
+
+ g_variant_builder_add (&builder, "s", msg->title ? msg->title : "");
+ g_variant_builder_add (&builder, "s", msg->subtitle ? msg->subtitle : "");
+ g_variant_builder_add (&builder, "s", msg->body ? msg->body : "");
+ g_variant_builder_add (&builder, "x", msg->time);
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("aa{sv}"));
+ for (it = msg->actions; it; it = it->next)
+ g_variant_builder_add_value (&builder, action_to_variant (it->data));
+ g_variant_builder_close (&builder);
+
+ g_variant_builder_add (&builder, "b", msg->draws_attention);
+
+ return g_variant_builder_end (&builder);
+}
diff --git a/libmessaging-menu/messaging-menu-message.h b/libmessaging-menu/messaging-menu-message.h
new file mode 100644
index 0000000..4708246
--- /dev/null
+++ b/libmessaging-menu/messaging-menu-message.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#ifndef __messaging_menu_message_h__
+#define __messaging_menu_message_h__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define MESSAGING_MENU_TYPE_MESSAGE (messaging_menu_message_get_type ())
+#define MESSAGING_MENU_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessage))
+#define MESSAGING_MENU_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass))
+#define MESSAGING_MENU_IS_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MESSAGING_MENU_TYPE_MESSAGE))
+#define MESSAGING_MENU_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGING_MENU_TYPE_MESSAGE))
+#define MESSAGING_MENU_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass))
+
+typedef struct _MessagingMenuMessage MessagingMenuMessage;
+
+GType messaging_menu_message_get_type (void) G_GNUC_CONST;
+
+MessagingMenuMessage * messaging_menu_message_new (const gchar *id,
+ GIcon *icon,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *body,
+ gint64 time);
+
+const gchar * messaging_menu_message_get_id (MessagingMenuMessage *msg);
+
+GIcon * messaging_menu_message_get_icon (MessagingMenuMessage *msg);
+
+const gchar * messaging_menu_message_get_title (MessagingMenuMessage *msg);
+
+const gchar * messaging_menu_message_get_subtitle (MessagingMenuMessage *msg);
+
+const gchar * messaging_menu_message_get_body (MessagingMenuMessage *msg);
+
+gint64 messaging_menu_message_get_time (MessagingMenuMessage *msg);
+
+gboolean messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg);
+
+void messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
+ gboolean draws_attention);
+
+void messaging_menu_message_add_action (MessagingMenuMessage *msg,
+ const gchar *id,
+ const gchar *label,
+ const GVariantType *parameter_type,
+ GVariant *parameter_hint);
+
+G_END_DECLS
+
+#endif
diff --git a/libmessaging-menu/messaging-menu.h b/libmessaging-menu/messaging-menu.h
index 6c405c7..929b229 100644
--- a/libmessaging-menu/messaging-menu.h
+++ b/libmessaging-menu/messaging-menu.h
@@ -20,129 +20,6 @@
#ifndef __messaging_menu_h__
#define __messaging_menu_h__
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type()
-#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp))
-#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass))
-#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP))
-
-/**
- * MessagingMenuStatus:
- * @MESSAGING_MENU_STATUS_AVAILABLE: available
- * @MESSAGING_MENU_STATUS_AWAY: away
- * @MESSAGING_MENU_STATUS_BUSY: busy
- * @MESSAGING_MENU_STATUS_INVISIBLE: invisible
- * @MESSAGING_MENU_STATUS_OFFLINE: offline
- *
- * An enumeration for the possible chat statuses the messaging menu can be in.
- */
-typedef enum {
- MESSAGING_MENU_STATUS_AVAILABLE,
- MESSAGING_MENU_STATUS_AWAY,
- MESSAGING_MENU_STATUS_BUSY,
- MESSAGING_MENU_STATUS_INVISIBLE,
- MESSAGING_MENU_STATUS_OFFLINE
-} MessagingMenuStatus;
-
-
-typedef GObjectClass MessagingMenuAppClass;
-typedef struct _MessagingMenuApp MessagingMenuApp;
-
-GType messaging_menu_app_get_type (void) G_GNUC_CONST;
-
-MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id);
-
-void messaging_menu_app_register (MessagingMenuApp *app);
-void messaging_menu_app_unregister (MessagingMenuApp *app);
-
-void messaging_menu_app_set_status (MessagingMenuApp *app,
- MessagingMenuStatus status);
-
-void messaging_menu_app_insert_source (MessagingMenuApp *app,
- gint position,
- const gchar *id,
- GIcon *icon,
- const gchar *label);
-
-void messaging_menu_app_append_source (MessagingMenuApp *app,
- const gchar *id,
- GIcon *icon,
- const gchar *label);
-
-void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app,
- gint position,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- guint count);
-
-void messaging_menu_app_append_source_with_count (MessagingMenuApp *app,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- guint count);
-
-void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app,
- gint position,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- gint64 time);
-
-void messaging_menu_app_append_source_with_time (MessagingMenuApp *app,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- gint64 time);
-
-void messaging_menu_app_append_source_with_string (MessagingMenuApp *app,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- const gchar *str);
-
-void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app,
- gint position,
- const gchar *id,
- GIcon *icon,
- const gchar *label,
- const gchar *str);
-
-void messaging_menu_app_remove_source (MessagingMenuApp *app,
- const gchar *source_id);
-
-gboolean messaging_menu_app_has_source (MessagingMenuApp *app,
- const gchar *source_id);
-
-void messaging_menu_app_set_source_label (MessagingMenuApp *app,
- const gchar *source_id,
- const gchar *label);
-
-void messaging_menu_app_set_source_icon (MessagingMenuApp *app,
- const gchar *source_id,
- GIcon *icon);
-
-void messaging_menu_app_set_source_count (MessagingMenuApp *app,
- const gchar *source_id,
- guint count);
-
-void messaging_menu_app_set_source_time (MessagingMenuApp *app,
- const gchar *source_id,
- gint64 time);
-
-void messaging_menu_app_set_source_string (MessagingMenuApp *app,
- const gchar *source_id,
- const gchar *str);
-
-void messaging_menu_app_draw_attention (MessagingMenuApp *app,
- const gchar *source_id);
-
-void messaging_menu_app_remove_attention (MessagingMenuApp *app,
- const gchar *source_id);
-
-G_END_DECLS
+#include "messaging-menu-app.h"
#endif
diff --git a/po/indicator-messages.pot b/po/indicator-messages.pot
new file mode 100644
index 0000000..3788bb5
--- /dev/null
+++ b/po/indicator-messages.pot
@@ -0,0 +1,46 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-11-16 14:53+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/messages-service.c:329
+msgid "Messages"
+msgstr ""
+
+#: ../src/messages-service.c:552
+msgid "Available"
+msgstr ""
+
+#: ../src/messages-service.c:553
+msgid "Away"
+msgstr ""
+
+#: ../src/messages-service.c:554
+msgid "Busy"
+msgstr ""
+
+#: ../src/messages-service.c:555
+msgid "Invisible"
+msgstr ""
+
+#: ../src/messages-service.c:556
+msgid "Offline"
+msgstr ""
+
+#: ../src/messages-service.c:659
+msgid "Clear"
+msgstr ""
diff --git a/src/Makefile.am b/src/Makefile.am
index 1df80e5..5d8bad8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,8 +1,5 @@
-BUILT_SOURCES =
EXTRA_DIST =
-CLEANFILES =
-DISTCLEANFILES =
libexec_PROGRAMS = indicator-messages-service
@@ -23,19 +20,20 @@ libmessaging_la_SOURCES = \
im-source-menu-item.h \
ido-detail-label.c \
ido-detail-label.h \
- indicator-messages-service.c \
- indicator-messages-service.h
dbus-data.h
libmessaging_la_CFLAGS = \
$(APPLET_CFLAGS) \
$(COVERAGE_CFLAGS) \
+ -I$(top_builddir)/common \
-Wall \
-Wl,-Bsymbolic-functions \
-Wl,-z,defs \
-Wl,--as-needed \
-Werror \
-DG_LOG_DOMAIN=\"Indicator-Messages\"
-libmessaging_la_LIBADD = $(APPLET_LIBS) -lm
+libmessaging_la_LIBADD = \
+ $(top_builddir)/common/libmessaging-common.la \
+ $(APPLET_LIBS) -lm
libmessaging_la_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
-module -avoid-version
@@ -46,8 +44,6 @@ libmessaging_la_LDFLAGS = \
indicator_messages_service_SOURCES = \
messages-service.c \
- indicator-messages-service.c \
- indicator-messages-service.h \
app-section.c \
app-section.h \
dbus-data.h \
@@ -56,11 +52,16 @@ indicator_messages_service_SOURCES = \
gsettingsstrv.c \
gsettingsstrv.h \
gmenuutils.c \
- gmenuutils.h
+ gmenuutils.h \
+ im-phone-menu.c \
+ im-phone-menu.h \
+ im-application-list.c \
+ im-application-list.h
indicator_messages_service_CFLAGS = \
$(APPLET_CFLAGS) \
$(COVERAGE_CFLAGS) \
+ -I$(top_builddir)/common \
-Wall \
-Wl,-Bsymbolic-functions \
-Wl,-z,defs \
@@ -69,26 +70,11 @@ indicator_messages_service_CFLAGS = \
-DG_LOG_DOMAIN=\"Indicator-Messages\"
indicator_messages_service_LDADD = \
+ $(top_builddir)/common/libmessaging-common.la \
$(APPLET_LIBS)
indicator_messages_service_LDFLAGS = \
$(COVERAGE_LDFLAGS)
-indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
- $(AM_V_GEN) gdbus-codegen \
- --interface-prefix com.canonical.indicator.messages. \
- --generate-c-code indicator-messages-service \
- --c-namespace IndicatorMessages \
- $^
-indicator-messages-service.h: indicator-messages-service.c
-
-BUILT_SOURCES += \
- indicator-messages-service.c \
- indicator-messages-service.h
-
EXTRA_DIST += \
messages-service.xml
-
-CLEANFILES += \
- $(BUILT_SOURCES)
-
diff --git a/src/app-section.c b/src/app-section.c
index 823d75a..3a55147 100644
--- a/src/app-section.c
+++ b/src/app-section.c
@@ -33,6 +33,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dbus-data.h"
#include "gmenuutils.h"
#include "gactionmuxer.h"
+#include "indicator-messages-application.h"
struct _AppSectionPrivate
{
@@ -41,11 +42,14 @@ struct _AppSectionPrivate
IndicatorDesktopShortcuts * ids;
+ GCancellable *app_proxy_cancellable;
+ IndicatorMessagesApplication *app_proxy;
+
GMenu *menu;
- GMenuModel *source_menu;
+ GMenu *source_menu;
GSimpleActionGroup *static_shortcuts;
- GActionGroup *source_actions;
+ GSimpleActionGroup *source_actions;
GActionMuxer *muxer;
gboolean draws_attention;
@@ -89,19 +93,6 @@ static void launch_action_change_state (GSimpleAction *action,
gpointer user_data);
static void app_section_set_app_info (AppSection *self,
GDesktopAppInfo *appinfo);
-static gboolean any_action_draws_attention (GActionGroup *group,
- const gchar *ignored_action);
-static void action_added (GActionGroup *group,
- const gchar *action_name,
- gpointer user_data);
-static void action_state_changed (GActionGroup *group,
- const gchar *action_name,
- GVariant *value,
- gpointer user_data);
-static void action_removed (GActionGroup *group,
- const gchar *action_name,
- gpointer user_data);
-static gboolean action_draws_attention (GVariant *state);
static void desktop_file_changed_cb (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
@@ -169,6 +160,7 @@ static void
app_section_init (AppSection *self)
{
AppSectionPrivate *priv;
+ GMenuItem *item;
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
APP_SECTION_TYPE,
@@ -178,10 +170,19 @@ app_section_init (AppSection *self)
priv->appinfo = NULL;
priv->menu = g_menu_new ();
+
+ priv->source_menu = g_menu_new ();
+ item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->source_menu));
+ g_menu_item_set_attribute (item, "action-namespace", "s", "source");
+ g_menu_append_item (priv->menu, item);
+ g_object_unref (item);
+
priv->static_shortcuts = g_simple_action_group_new ();
+ priv->source_actions = g_simple_action_group_new ();
priv->muxer = g_action_muxer_new ();
g_action_muxer_insert (priv->muxer, NULL, G_ACTION_GROUP (priv->static_shortcuts));
+ g_action_muxer_insert (priv->muxer, "source", G_ACTION_GROUP (priv->source_actions));
priv->draws_attention = FALSE;
@@ -248,32 +249,30 @@ app_section_dispose (GObject *object)
AppSection * self = APP_SECTION(object);
AppSectionPrivate * priv = self->priv;
+ if (priv->app_proxy_cancellable) {
+ g_cancellable_cancel (priv->app_proxy_cancellable);
+ g_clear_object (&priv->app_proxy_cancellable);
+ }
+
if (priv->desktop_file_monitor) {
g_signal_handlers_disconnect_by_func (priv->desktop_file_monitor, desktop_file_changed_cb, self);
g_clear_object (&priv->desktop_file_monitor);
}
+ g_clear_object (&priv->app_proxy);
+
g_clear_object (&priv->menu);
+ g_clear_object (&priv->source_menu);
g_clear_object (&priv->static_shortcuts);
+ g_clear_object (&priv->source_actions);
if (priv->name_watch_id) {
g_bus_unwatch_name (priv->name_watch_id);
priv->name_watch_id = 0;
}
- if (priv->source_actions) {
- g_action_muxer_remove (priv->muxer, "source");
- g_object_disconnect (priv->source_actions,
- "any_signal::action-added", action_added, self,
- "any_signal::action-state-changed", action_state_changed, self,
- "any_signal::action-removed", action_removed, self,
- NULL);
- g_clear_object (&priv->source_actions);
- }
-
g_clear_object (&priv->muxer);
- g_clear_object (&priv->source_menu);
g_clear_object (&priv->ids);
g_clear_object (&priv->appinfo);
@@ -429,6 +428,11 @@ app_section_update_menu (AppSection *self)
g_free(name);
}
+ item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->source_menu));
+ g_menu_item_set_attribute (item, "action-namespace", "s", "source");
+ g_menu_append_item (priv->menu, item);
+ g_object_unref (item);
+
keyfile = g_file_new_for_path (g_desktop_app_info_get_filename (priv->appinfo));
g_file_load_contents_async (keyfile, NULL, keyfile_loaded, self);
@@ -564,49 +568,242 @@ app_section_get_draws_attention (AppSection *self)
void
app_section_clear_draws_attention (AppSection *self)
{
- AppSectionPrivate * priv = self->priv;
- gchar **action_names;
+ self->priv->draws_attention = FALSE;
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+}
+
+static void
+application_vanished (GDBusConnection *bus,
+ const gchar *name,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+
+ app_section_unset_object_path (self);
+}
+
+static void
+update_draws_attention (AppSection *self)
+{
+ AppSectionPrivate *priv = self->priv;
+ gchar **actions;
gchar **it;
+ gboolean draws_attention = FALSE;
+
+ actions = g_action_group_list_actions (G_ACTION_GROUP (priv->source_actions));
+
+ for (it = actions; *it; it++) {
+ GVariant *state;
+
+ state = g_action_group_get_action_state (G_ACTION_GROUP (priv->source_actions), *it);
+ if (state) {
+ gboolean b;
+ g_variant_get (state, "(uxsb)", NULL, NULL, NULL, &b);
+ draws_attention = b || draws_attention;
+ g_variant_unref (state);
+ }
+
+ if (draws_attention)
+ break;
+ }
+
+ if (draws_attention != priv->draws_attention) {
+ priv->draws_attention = draws_attention;
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+ }
+
+ g_strfreev (actions);
+}
+
+static void
+remove_source (AppSection *self,
+ const gchar *id)
+{
+ AppSectionPrivate *priv = self->priv;
+ guint n_items;
+ guint i;
+
+ n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->source_menu));
+ for (i = 0; i < n_items; i++) {
+ gchar *action;
+ gboolean found = FALSE;
+
+ if (g_menu_model_get_item_attribute (G_MENU_MODEL (priv->source_menu), i,
+ G_MENU_ATTRIBUTE_ACTION, "s", &action)) {
+ found = g_str_equal (action, id);
+ g_free (action);
+ }
+
+ if (found) {
+ g_menu_remove (priv->source_menu, i);
+ break;
+ }
+ }
+
+ g_simple_action_group_remove (priv->source_actions, id);
+ update_draws_attention (self);
+}
+
+static void
+source_action_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ AppSection *self = APP_SECTION (user_data);
+ AppSectionPrivate *priv = APP_SECTION (user_data)->priv;
+
+ g_return_if_fail (priv->app_proxy != NULL);
+
+ indicator_messages_application_call_activate_source (priv->app_proxy,
+ g_action_get_name (G_ACTION (action)),
+ priv->app_proxy_cancellable,
+ NULL, NULL);
+
+ remove_source (self, g_action_get_name (G_ACTION (action)));
+}
+
+static void
+sources_listed (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ AppSectionPrivate *priv = self->priv;
+ GVariant *sources = NULL;
+ GError *error = NULL;
+ GVariantIter iter;
+ const gchar *id;
+ const gchar *label;
+ const gchar *iconstr;
+ guint32 count;
+ gint64 time;
+ const gchar *string;
+ gboolean draws_attention;
- if (priv->source_actions == NULL)
+ if (!indicator_messages_application_call_list_sources_finish (INDICATOR_MESSAGES_APPLICATION (source_object),
+ &sources, result, &error))
+ {
+ g_warning ("could not fetch the list of sources: %s", error->message);
+ g_error_free (error);
return;
+ }
- action_names = g_action_group_list_actions (priv->source_actions);
+ g_menu_clear (priv->source_menu);
+ g_simple_action_group_clear (priv->source_actions);
+ priv->draws_attention = FALSE;
- for (it = action_names; *it; it++) {
+ g_variant_iter_init (&iter, sources);
+ while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr,
+ &count, &time, &string, &draws_attention))
+ {
GVariant *state;
+ GSimpleAction *action;
+ GMenuItem *item;
- state = g_action_group_get_action_state (priv->source_actions, *it);
- if (!state)
- continue;
+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
+ action = g_simple_action_new_stateful (id, NULL, state);
+ g_signal_connect (action, "activate", G_CALLBACK (source_action_activated), self);
+ g_simple_action_group_insert (priv->source_actions, G_ACTION (action));
- /* clear draws-attention while preserving other state */
- if (action_draws_attention (state)) {
- guint32 count;
- gint64 time;
- const gchar *str;
- GVariant *new_state;
+ item = g_menu_item_new (label, id);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "ImSourceMenuItem");
+ g_menu_append_item (priv->source_menu, item);
- g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
+ priv->draws_attention = priv->draws_attention || draws_attention;
- new_state = g_variant_new ("(uxsb)", count, time, str, FALSE);
- g_action_group_change_action_state (priv->source_actions, *it, new_state);
- }
+ g_object_unref (item);
+ g_object_unref (action);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+
+ g_variant_unref (sources);
+}
+
+static void
+source_added (IndicatorMessagesApplication *app,
+ const gchar *id,
+ const gchar *label,
+ const gchar *iconstr,
+ guint count,
+ gint64 time,
+ const gchar *string,
+ gboolean draws_attention,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ AppSectionPrivate *priv = self->priv;
+ GVariant *state;
+ GSimpleAction *action;
+
+ /* TODO put label and icon into the action as well */
- g_variant_unref (state);
+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
+ action = g_simple_action_new_stateful (id, NULL, state);
+
+ g_simple_action_group_insert (priv->source_actions, G_ACTION (action));
+
+ if (draws_attention && !priv->draws_attention) {
+ priv->draws_attention = TRUE;
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
}
- g_strfreev (action_names);
+ g_object_unref (action);
+}
+static void
+source_changed (IndicatorMessagesApplication *app,
+ const gchar *id,
+ const gchar *label,
+ const gchar *iconstr,
+ guint count,
+ gint64 time,
+ const gchar *string,
+ gboolean draws_attention,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ AppSectionPrivate *priv = self->priv;
+ GVariant *state;
+
+ /* TODO put label and icon into the action as well */
+
+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
+ g_action_group_change_action_state (G_ACTION_GROUP (priv->source_actions), id, state);
+
+ update_draws_attention (self);
}
static void
-application_vanished (GDBusConnection *bus,
- const gchar *name,
- gpointer user_data)
+source_removed (IndicatorMessagesApplication *app,
+ const gchar *id,
+ gpointer user_data)
{
AppSection *self = user_data;
- app_section_unset_object_path (self);
+ remove_source (self, id);
+}
+
+static void
+app_proxy_created (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AppSectionPrivate *priv = APP_SECTION (user_data)->priv;
+ GError *error = NULL;
+
+ priv->app_proxy = indicator_messages_application_proxy_new_finish (result, &error);
+ if (!priv->app_proxy) {
+ g_warning ("could not create application proxy: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ indicator_messages_application_call_list_sources (priv->app_proxy, priv->app_proxy_cancellable,
+ sources_listed, user_data);
+
+ g_signal_connect (priv->app_proxy, "source-added", G_CALLBACK (source_added), user_data);
+ g_signal_connect (priv->app_proxy, "source-changed", G_CALLBACK (source_changed), user_data);
+ g_signal_connect (priv->app_proxy, "source-removed", G_CALLBACK (source_removed), user_data);
}
/*
@@ -627,27 +824,20 @@ app_section_set_object_path (AppSection *self,
const gchar *object_path)
{
AppSectionPrivate *priv = self->priv;
- GMenuItem *item;
g_object_freeze_notify (G_OBJECT (self));
app_section_unset_object_path (self);
- priv->source_actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path));
- g_action_muxer_insert (priv->muxer, "source", priv->source_actions);
-
- priv->draws_attention = any_action_draws_attention (priv->source_actions, NULL);
- g_object_connect (priv->source_actions,
- "signal::action-added", action_added, self,
- "signal::action-state-changed", action_state_changed, self,
- "signal::action-removed", action_removed, self,
- NULL);
+ priv->app_proxy_cancellable = g_cancellable_new ();
+ indicator_messages_application_proxy_new (bus,
+ G_DBUS_PROXY_FLAGS_NONE,
+ bus_name,
+ object_path,
+ priv->app_proxy_cancellable,
+ app_proxy_created,
+ self);
- priv->source_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path));
-
- item = g_menu_item_new_section (NULL, priv->source_menu);
- g_menu_item_set_attribute (item, "action-namespace", "s", "source");
- g_menu_append_item (priv->menu, item);
- g_object_unref (item);
+ priv->draws_attention = FALSE;
priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0,
NULL, application_vanished,
@@ -675,26 +865,19 @@ app_section_unset_object_path (AppSection *self)
{
AppSectionPrivate *priv = self->priv;
+ if (priv->app_proxy_cancellable) {
+ g_cancellable_cancel (priv->app_proxy_cancellable);
+ g_clear_object (&priv->app_proxy_cancellable);
+ }
+ g_clear_object (&priv->app_proxy);
+
if (priv->name_watch_id) {
g_bus_unwatch_name (priv->name_watch_id);
priv->name_watch_id = 0;
}
- if (priv->source_actions) {
- g_object_disconnect (priv->source_actions,
- "any_signal::action-added", action_added, self,
- "any_signal::action-state-changed", action_state_changed, self,
- "any_signal::action-removed", action_removed, self,
- NULL);
- g_clear_object (&priv->source_actions);
- }
-
- if (priv->source_menu) {
- /* the last menu item points is linked to the app's menumodel */
- gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu));
- g_menu_remove (priv->menu, n_items -1);
- g_clear_object (&priv->source_menu);
- }
+ g_simple_action_group_clear (priv->source_actions);
+ g_menu_clear (priv->source_menu);
priv->draws_attention = FALSE;
g_clear_pointer (&priv->chat_status, g_free);
@@ -708,85 +891,6 @@ app_section_unset_object_path (AppSection *self)
"launch", g_variant_new_boolean (FALSE));
}
-static gboolean
-action_draws_attention (GVariant *state)
-{
- gboolean attention;
-
- if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")))
- g_variant_get_child (state, 3, "b", &attention);
- else
- attention = FALSE;
-
- return attention;
-}
-
-static gboolean
-any_action_draws_attention (GActionGroup *group,
- const gchar *ignored_action)
-{
- gchar **actions;
- gchar **it;
- gboolean attention = FALSE;
-
- actions = g_action_group_list_actions (group);
-
- for (it = actions; *it && !attention; it++) {
- GVariant *state;
-
- if (ignored_action && g_str_equal (ignored_action, *it))
- continue;
-
- state = g_action_group_get_action_state (group, *it);
- if (state) {
- attention = action_draws_attention (state);
- g_variant_unref (state);
- }
- }
-
- g_strfreev (actions);
- return attention;
-}
-
-static void
-action_added (GActionGroup *group,
- const gchar *action_name,
- gpointer user_data)
-{
- AppSection *self = user_data;
- GVariant *state;
-
- state = g_action_group_get_action_state (group, action_name);
- if (state) {
- self->priv->draws_attention |= action_draws_attention (state);
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
- g_variant_unref (state);
- }
-}
-
-static void
-action_state_changed (GActionGroup *group,
- const gchar *action_name,
- GVariant *value,
- gpointer user_data)
-{
- AppSection *self = user_data;
-
- self->priv->draws_attention = any_action_draws_attention (group, NULL);
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
-}
-
-static void
-action_removed (GActionGroup *group,
- const gchar *action_name,
- gpointer user_data)
-{
- AppSection *self = user_data;
-
- self->priv->draws_attention = any_action_draws_attention (group, action_name);
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
-}
-
gboolean
app_section_get_uses_chat_status (AppSection *self)
{
diff --git a/src/dbus-data.h b/src/dbus-data.h
index 64747a9..59bd305 100644
--- a/src/dbus-data.h
+++ b/src/dbus-data.h
@@ -1,9 +1,24 @@
+/*
+ * Copyright 2012-2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#ifndef __DBUS_DATA_H__
#define __DBUS_DATA_H__ 1
#define INDICATOR_MESSAGES_DBUS_NAME "com.canonical.indicator.messages"
-#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages/menu"
+#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages"
#define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service"
#define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service"
diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c
index 2b1d11a..0f3cda4 100644
--- a/src/gactionmuxer.c
+++ b/src/gactionmuxer.c
@@ -483,3 +483,11 @@ g_action_muxer_remove (GActionMuxer *muxer,
g_clear_object (&muxer->global_actions);
}
+GActionGroup *
+g_action_muxer_get_group (GActionMuxer *muxer,
+ const gchar *prefix)
+{
+ g_return_val_if_fail (G_IS_ACTION_MUXER (muxer), NULL);
+
+ return prefix ? g_hash_table_lookup (muxer->groups, prefix) : muxer->global_actions;
+}
diff --git a/src/gactionmuxer.h b/src/gactionmuxer.h
index 5c5e839..caf9ec7 100644
--- a/src/gactionmuxer.h
+++ b/src/gactionmuxer.h
@@ -40,5 +40,8 @@ void g_action_muxer_insert (GActionMuxer *muxer,
void g_action_muxer_remove (GActionMuxer *muxer,
const gchar *prefix);
+GActionGroup * g_action_muxer_get_group (GActionMuxer *muxer,
+ const gchar *prefix);
+
#endif
diff --git a/src/im-application-list.c b/src/im-application-list.c
new file mode 100644
index 0000000..9a673c9
--- /dev/null
+++ b/src/im-application-list.c
@@ -0,0 +1,880 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#include "im-application-list.h"
+
+#include "indicator-messages-application.h"
+#include "gactionmuxer.h"
+
+#include <gio/gdesktopappinfo.h>
+#include <string.h>
+
+typedef GObjectClass ImApplicationListClass;
+
+struct _ImApplicationList
+{
+ GObject parent;
+
+ GHashTable *applications;
+ GActionMuxer *muxer;
+};
+
+G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT);
+
+enum
+{
+ SOURCE_ADDED,
+ SOURCE_CHANGED,
+ SOURCE_REMOVED,
+ MESSAGE_ADDED,
+ MESSAGE_REMOVED,
+ APP_STOPPED,
+ REMOVE_ALL,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+typedef struct
+{
+ ImApplicationList *list;
+ GDesktopAppInfo *info;
+ gchar *id;
+ IndicatorMessagesApplication *proxy;
+ GActionMuxer *actions;
+ GSimpleActionGroup *source_actions;
+ GSimpleActionGroup *message_actions;
+ GActionMuxer *message_sub_actions;
+ GCancellable *cancellable;
+} Application;
+
+static void
+application_free (gpointer data)
+{
+ Application *app = data;
+
+ if (!app)
+ return;
+
+ g_object_unref (app->info);
+ g_free (app->id);
+
+ if (app->cancellable)
+ {
+ g_cancellable_cancel (app->cancellable);
+ g_clear_object (&app->cancellable);
+ }
+
+ if (app->proxy)
+ g_object_unref (app->proxy);
+
+ if (app->actions)
+ {
+ g_object_unref (app->actions);
+ g_object_unref (app->source_actions);
+ g_object_unref (app->message_actions);
+ g_object_unref (app->message_sub_actions);
+ }
+
+ g_slice_free (Application, app);
+}
+
+static void
+im_application_list_source_removed (Application *app,
+ const gchar *id)
+{
+ g_simple_action_group_remove (app->source_actions, id);
+
+ g_signal_emit (app->list, signals[SOURCE_REMOVED], 0, app->id, id);
+}
+
+static void
+im_application_list_source_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ Application *app = user_data;
+ const gchar *source_id;
+
+ source_id = g_action_get_name (G_ACTION (action));
+
+ if (g_variant_get_boolean (parameter))
+ {
+ indicator_messages_application_call_activate_source (app->proxy,
+ source_id,
+ app->cancellable,
+ NULL, NULL);
+ }
+ else
+ {
+ const gchar *sources[] = { source_id, NULL };
+ const gchar *messages[] = { NULL };
+ indicator_messages_application_call_dismiss (app->proxy, sources, messages,
+ app->cancellable, NULL, NULL);
+ }
+
+ im_application_list_source_removed (app, source_id);
+}
+
+static guint
+g_action_group_get_n_actions (GActionGroup *group)
+{
+ guint len;
+ gchar **actions;
+
+ actions = g_action_group_list_actions (group);
+ len = g_strv_length (actions);
+
+ g_strfreev (actions);
+ return len;
+}
+
+static gboolean
+application_draws_attention (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ Application *app = value;
+
+ return (g_action_group_get_n_actions (G_ACTION_GROUP (app->source_actions)) +
+ g_action_group_get_n_actions (G_ACTION_GROUP (app->message_actions))) > 0;
+}
+
+static void
+im_application_list_update_draws_attention (ImApplicationList *list)
+{
+ const gchar *icon_name;
+ GVariant *state;
+ GActionGroup *main_actions;
+
+ if (g_hash_table_find (list->applications, application_draws_attention, NULL))
+ icon_name = "indicator-messages-new";
+ else
+ icon_name = "indicator-messages";
+
+ main_actions = g_action_muxer_get_group (list->muxer, NULL);
+ state = g_variant_new ("(sssb)", "", icon_name, "Messages", TRUE);
+ g_action_group_change_action_state (main_actions, "messages", state);
+}
+
+static void
+im_application_list_message_removed (Application *app,
+ const gchar *id)
+{
+ g_simple_action_group_remove (app->message_actions, id);
+ g_action_muxer_remove (app->message_sub_actions, id);
+
+ im_application_list_update_draws_attention (app->list);
+
+ g_signal_emit (app->list, signals[MESSAGE_REMOVED], 0, app->id, id);
+}
+
+static void
+im_application_list_message_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ Application *app = user_data;
+ const gchar *message_id;
+
+ message_id = g_action_get_name (G_ACTION (action));
+
+ if (g_variant_get_boolean (parameter))
+ {
+ indicator_messages_application_call_activate_message (app->proxy,
+ message_id,
+ "",
+ g_variant_new_array (G_VARIANT_TYPE_VARIANT, NULL, 0),
+ app->cancellable,
+ NULL, NULL);
+ }
+ else
+ {
+ const gchar *sources[] = { NULL };
+ const gchar *messages[] = { message_id, NULL };
+ indicator_messages_application_call_dismiss (app->proxy, sources, messages,
+ app->cancellable, NULL, NULL);
+ }
+
+ im_application_list_message_removed (app, message_id);
+}
+
+static void
+im_application_list_sub_message_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ Application *app = user_data;
+ const gchar *message_id;
+ const gchar *action_id;
+ GVariantBuilder builder;
+
+ message_id = g_object_get_data (G_OBJECT (action), "message");
+ action_id = g_action_get_name (G_ACTION (action));
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
+ if (parameter)
+ g_variant_builder_add (&builder, "v", parameter);
+
+ indicator_messages_application_call_activate_message (app->proxy,
+ message_id,
+ action_id,
+ g_variant_builder_end (&builder),
+ app->cancellable,
+ NULL, NULL);
+
+ im_application_list_message_removed (app, message_id);
+}
+
+
+static void
+im_application_list_remove_all (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ ImApplicationList *list = user_data;
+ GHashTableIter iter;
+ Application *app;
+
+ g_signal_emit (list, signals[REMOVE_ALL], 0);
+
+ g_hash_table_iter_init (&iter, list->applications);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &app))
+ {
+ gchar **source_actions;
+ gchar **message_actions;
+ gchar **it;
+
+ source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
+ for (it = source_actions; *it; it++)
+ im_application_list_source_removed (app, *it);
+
+ message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
+ for (it = message_actions; *it; it++)
+ im_application_list_message_removed (app, *it);
+
+ indicator_messages_application_call_dismiss (app->proxy,
+ (const gchar * const *) source_actions,
+ (const gchar * const *) message_actions,
+ app->cancellable, NULL, NULL);
+
+ g_strfreev (source_actions);
+ g_strfreev (message_actions);
+ }
+}
+
+static void
+im_application_list_dispose (GObject *object)
+{
+ ImApplicationList *list = IM_APPLICATION_LIST (object);
+
+ g_clear_pointer (&list->applications, g_hash_table_unref);
+ g_clear_object (&list->muxer);
+
+ G_OBJECT_CLASS (im_application_list_parent_class)->dispose (object);
+}
+
+static void
+im_application_list_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (im_application_list_parent_class)->finalize (object);
+}
+
+static void
+im_application_list_class_init (ImApplicationListClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = im_application_list_dispose;
+ object_class->finalize = im_application_list_finalize;
+
+ signals[SOURCE_ADDED] = g_signal_new ("source-added",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[SOURCE_CHANGED] = g_signal_new ("source-changed",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[MESSAGE_ADDED] = g_signal_new ("message-added",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 10,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_VARIANT,
+ G_TYPE_INT64,
+ G_TYPE_BOOLEAN);
+
+ signals[MESSAGE_REMOVED] = g_signal_new ("message-removed",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[APP_STOPPED] = g_signal_new ("app-stopped",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[REMOVE_ALL] = g_signal_new ("remove-all",
+ IM_TYPE_APPLICATION_LIST,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+im_application_list_init (ImApplicationList *list)
+{
+ const GActionEntry action_entries[] = {
+ { "messages", NULL, NULL, "('', 'indicator-messages', 'Messages', true)", NULL },
+ { "remove-all", im_application_list_remove_all }
+ };
+
+ GSimpleActionGroup *actions;
+
+ list->applications = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, application_free);
+
+ actions = g_simple_action_group_new ();
+ g_simple_action_group_add_entries (actions, action_entries, G_N_ELEMENTS (action_entries), list);
+
+ list->muxer = g_action_muxer_new ();
+ g_action_muxer_insert (list->muxer, NULL, G_ACTION_GROUP (actions));
+
+ g_object_unref (actions);
+}
+
+ImApplicationList *
+im_application_list_new (void)
+{
+ return g_object_new (IM_TYPE_APPLICATION_LIST, NULL);
+}
+
+static gchar *
+im_application_list_canonical_id (const gchar *id)
+{
+ gchar *str;
+ gchar *p;
+ int len;
+
+ len = strlen (id);
+ if (g_str_has_suffix (id, ".desktop"))
+ len -= 8;
+
+ str = g_strndup (id, len);
+
+ for (p = str; *p; p++)
+ {
+ if (*p == '.')
+ *p = '_';
+ }
+
+ return str;
+}
+
+static Application *
+im_application_list_lookup (ImApplicationList *list,
+ const gchar *desktop_id)
+{
+ gchar *id;
+ Application *app;
+
+ id = im_application_list_canonical_id (desktop_id);
+ app = g_hash_table_lookup (list->applications, id);
+
+ g_free (id);
+ return app;
+}
+
+void
+im_application_list_add (ImApplicationList *list,
+ const gchar *desktop_id)
+{
+ GDesktopAppInfo *info;
+ Application *app;
+ const gchar *id;
+
+ g_return_if_fail (IM_IS_APPLICATION_LIST (list));
+ g_return_if_fail (desktop_id != NULL);
+
+ if (im_application_list_lookup (list, desktop_id))
+ return;
+
+ info = g_desktop_app_info_new (desktop_id);
+ if (!info)
+ {
+ g_warning ("an application with id '%s' is not installed", desktop_id);
+ return;
+ }
+
+ id = g_app_info_get_id (G_APP_INFO (info));
+ g_return_if_fail (id != NULL);
+
+ app = g_slice_new0 (Application);
+ app->info = info;
+ app->id = im_application_list_canonical_id (id);
+ app->list = list;
+ app->actions = g_action_muxer_new ();
+ app->source_actions = g_simple_action_group_new ();
+ app->message_actions = g_simple_action_group_new ();
+ app->message_sub_actions = g_action_muxer_new ();
+
+ g_action_muxer_insert (app->actions, "src", G_ACTION_GROUP (app->source_actions));
+ g_action_muxer_insert (app->actions, "msg", G_ACTION_GROUP (app->message_actions));
+ g_action_muxer_insert (app->actions, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
+
+ g_hash_table_insert (list->applications, (gpointer) app->id, app);
+ g_action_muxer_insert (list->muxer, app->id, G_ACTION_GROUP (app->actions));
+}
+
+void
+im_application_list_remove (ImApplicationList *list,
+ const gchar *id)
+{
+ Application *app;
+
+ g_return_if_fail (IM_IS_APPLICATION_LIST (list));
+
+ app = im_application_list_lookup (list, id);
+ if (app)
+ {
+ if (app->proxy || app->cancellable)
+ g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
+
+ g_hash_table_remove (list->applications, id);
+ g_action_muxer_remove (list->muxer, id);
+ }
+}
+
+static void
+im_application_list_source_added (Application *app,
+ guint position,
+ GVariant *source)
+{
+ const gchar *id;
+ const gchar *label;
+ const gchar *iconstr;
+ guint32 count;
+ gint64 time;
+ const gchar *string;
+ gboolean draws_attention;
+ GVariant *state;
+ GSimpleAction *action;
+
+ g_variant_get (source, "(&s&s&sux&sb)",
+ &id, &label, &iconstr, &count, &time, &string, &draws_attention);
+
+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
+ action = g_simple_action_new_stateful (id, G_VARIANT_TYPE_BOOLEAN, state);
+ g_signal_connect (action, "activate", G_CALLBACK (im_application_list_source_activated), app);
+
+ g_simple_action_group_insert (app->source_actions, G_ACTION (action));
+
+ g_signal_emit (app->list, signals[SOURCE_ADDED], 0, app->id, id, label, iconstr);
+
+ g_object_unref (action);
+}
+
+static void
+im_application_list_source_changed (Application *app,
+ GVariant *source)
+{
+ const gchar *id;
+ const gchar *label;
+ const gchar *iconstr;
+ guint32 count;
+ gint64 time;
+ const gchar *string;
+ gboolean draws_attention;
+
+ g_variant_get (source, "(&s&s&sux&sb)",
+ &id, &label, &iconstr, &count, &time, &string, &draws_attention);
+
+ g_action_group_change_action_state (G_ACTION_GROUP (app->source_actions), id,
+ g_variant_new ("(uxsb)", count, time, string, draws_attention));
+
+ g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, app->id, id, label, iconstr);
+}
+
+static void
+im_application_list_sources_listed (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Application *app = user_data;
+ GVariant *sources;
+ GError *error = NULL;
+
+ if (indicator_messages_application_call_list_sources_finish (app->proxy, &sources, result, &error))
+ {
+ GVariantIter iter;
+ GVariant *source;
+ guint i = 0;
+
+ g_variant_iter_init (&iter, sources);
+ while ((source = g_variant_iter_next_value (&iter)))
+ {
+ im_application_list_source_added (app, i++, source);
+ g_variant_unref (source);
+ }
+
+ g_variant_unref (sources);
+ }
+ else
+ {
+ g_warning ("could not fetch the list of sources: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static gchar *
+get_symbolic_app_icon_string (GIcon *icon)
+{
+ const gchar * const *names;
+ gchar *symbolic_name;
+ GIcon *symbolic_icon;
+ gchar *str;
+
+ if (!G_IS_THEMED_ICON (icon))
+ return NULL;
+
+ names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+ if (!names || !names[0])
+ return NULL;
+
+ symbolic_icon = g_themed_icon_new_from_names ((gchar **) names, -1);
+
+ symbolic_name = g_strconcat (names[0], "-symbolic", NULL);
+ g_themed_icon_prepend_name (G_THEMED_ICON (symbolic_icon), symbolic_name);
+
+ str = g_icon_to_string (symbolic_icon);
+
+ g_free (symbolic_name);
+ g_object_unref (symbolic_icon);
+ return str;
+}
+
+static void
+im_application_list_message_added (Application *app,
+ GVariant *message)
+{
+ const gchar *id;
+ const gchar *iconstr;
+ const gchar *title;
+ const gchar *subtitle;
+ const gchar *body;
+ gint64 time;
+ GVariantIter *action_iter;
+ gboolean draws_attention;
+ GSimpleAction *action;
+ GIcon *app_icon;
+ gchar *app_iconstr = NULL;
+ GVariant *actions = NULL;
+
+ g_variant_get (message, "(&s&s&s&s&sxaa{sv}b)",
+ &id, &iconstr, &title, &subtitle, &body, &time, &action_iter, &draws_attention);
+
+ app_icon = g_app_info_get_icon (G_APP_INFO (app->info));
+ if (app_icon)
+ app_iconstr = get_symbolic_app_icon_string (app_icon);
+
+ action = g_simple_action_new (id, G_VARIANT_TYPE_BOOLEAN);
+ g_signal_connect (action, "activate", G_CALLBACK (im_application_list_message_activated), app);
+ g_simple_action_group_insert (app->message_actions, G_ACTION (action));
+
+ {
+ GVariant *entry;
+ GSimpleActionGroup *action_group;
+ GVariantBuilder actions_builder;
+
+ g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
+ action_group = g_simple_action_group_new ();
+
+ while ((entry = g_variant_iter_next_value (action_iter)))
+ {
+ const gchar *name;
+ GSimpleAction *action;
+ GVariant *label;
+ const gchar *type = NULL;
+ GVariant *hint;
+ GVariantBuilder dict_builder;
+ gchar *prefixed_name;
+
+ if (!g_variant_lookup (entry, "name", "&s", &name))
+ {
+ g_warning ("action dictionary for message '%s' is missing 'name' key", id);
+ continue;
+ }
+
+ label = g_variant_lookup_value (entry, "label", G_VARIANT_TYPE_STRING);
+ g_variant_lookup (entry, "parameter-type", "&g", &type);
+ hint = g_variant_lookup_value (entry, "parameter-hint", NULL);
+
+ action = g_simple_action_new (name, type ? G_VARIANT_TYPE (type) : NULL);
+ g_object_set_data_full (G_OBJECT (action), "message", g_strdup (id), g_free);
+ g_signal_connect (action, "activate", G_CALLBACK (im_application_list_sub_message_activated), app);
+ g_simple_action_group_insert (action_group, G_ACTION (action));
+
+ g_variant_builder_init (&dict_builder, G_VARIANT_TYPE ("a{sv}"));
+
+ prefixed_name = g_strjoin (".", app->id, "msg-actions", id, name, NULL);
+ g_variant_builder_add (&dict_builder, "{sv}", "name", g_variant_new_string (prefixed_name));
+
+ if (label)
+ {
+ g_variant_builder_add (&dict_builder, "{sv}", "label", label);
+ g_variant_unref (label);
+ }
+
+ if (type)
+ g_variant_builder_add (&dict_builder, "{sv}", "parameter-type", g_variant_new_string (type));
+
+ if (hint)
+ {
+ g_variant_builder_add (&dict_builder, "{sv}", "parameter-hint", hint);
+ g_variant_unref (hint);
+ }
+
+ g_variant_builder_add (&actions_builder, "a{sv}", &dict_builder);
+
+ g_object_unref (action);
+ g_variant_unref (entry);
+ g_free (prefixed_name);
+ }
+
+ g_action_muxer_insert (app->message_sub_actions, id, G_ACTION_GROUP (action_group));
+ actions = g_variant_builder_end (&actions_builder);
+
+ g_object_unref (action_group);
+ }
+
+ im_application_list_update_draws_attention (app->list);
+
+ g_signal_emit (app->list, signals[MESSAGE_ADDED], 0,
+ app->id, app_iconstr, id, iconstr, title,
+ subtitle, body, actions, time, draws_attention);
+
+ g_variant_iter_free (action_iter);
+ g_free (app_iconstr);
+ g_object_unref (action);
+}
+
+static void
+im_application_list_messages_listed (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Application *app = user_data;
+ GVariant *messages;
+ GError *error = NULL;
+
+ if (indicator_messages_application_call_list_messages_finish (app->proxy, &messages, result, &error))
+ {
+ GVariantIter iter;
+ GVariant *message;
+
+ g_variant_iter_init (&iter, messages);
+ while ((message = g_variant_iter_next_value (&iter)))
+ {
+ im_application_list_message_added (app, message);
+ g_variant_unref (message);
+ }
+
+ g_variant_unref (messages);
+ }
+ else
+ {
+ g_warning ("could not fetch the list of messages: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+im_application_list_unset_remote (Application *app)
+{
+ gboolean was_running;
+
+ was_running = app->proxy || app->cancellable;
+
+ if (app->cancellable)
+ {
+ g_cancellable_cancel (app->cancellable);
+ g_clear_object (&app->cancellable);
+ }
+ g_clear_object (&app->proxy);
+
+ /* clear actions by creating a new action group and overriding it in
+ * the muxer */
+ g_object_unref (app->source_actions);
+ g_object_unref (app->message_actions);
+ g_object_unref (app->message_sub_actions);
+ app->source_actions = g_simple_action_group_new ();
+ app->message_actions = g_simple_action_group_new ();
+ app->message_sub_actions = g_action_muxer_new ();
+ g_action_muxer_insert (app->actions, "src", G_ACTION_GROUP (app->source_actions));
+ g_action_muxer_insert (app->actions, "msg", G_ACTION_GROUP (app->message_actions));
+ g_action_muxer_insert (app->actions, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
+
+ im_application_list_update_draws_attention (app->list);
+
+ if (was_running)
+ g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
+}
+
+static void
+im_application_list_app_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ Application *app = user_data;
+
+ im_application_list_unset_remote (app);
+}
+
+static void
+im_application_list_proxy_created (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Application *app = user_data;
+ GError *error = NULL;
+
+ app->proxy = indicator_messages_application_proxy_new_finish (result, &error);
+ if (!app->proxy)
+ {
+ if (error->code != G_IO_ERROR_CANCELLED)
+ g_warning ("could not create application proxy: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ indicator_messages_application_call_list_sources (app->proxy, app->cancellable,
+ im_application_list_sources_listed, app);
+ indicator_messages_application_call_list_messages (app->proxy, app->cancellable,
+ im_application_list_messages_listed, app);
+
+ g_signal_connect_swapped (app->proxy, "source-added", G_CALLBACK (im_application_list_source_added), app);
+ g_signal_connect_swapped (app->proxy, "source-changed", G_CALLBACK (im_application_list_source_changed), app);
+ g_signal_connect_swapped (app->proxy, "source-removed", G_CALLBACK (im_application_list_source_removed), app);
+ g_signal_connect_swapped (app->proxy, "message-added", G_CALLBACK (im_application_list_message_added), app);
+ g_signal_connect_swapped (app->proxy, "message-removed", G_CALLBACK (im_application_list_message_removed), app);
+
+ g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (G_DBUS_PROXY (app->proxy)),
+ g_dbus_proxy_get_name (G_DBUS_PROXY (app->proxy)),
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL, im_application_list_app_vanished,
+ app, NULL);
+}
+
+void
+im_application_list_set_remote (ImApplicationList *list,
+ const gchar *id,
+ GDBusConnection *connection,
+ const gchar *unique_bus_name,
+ const gchar *object_path)
+{
+ Application *app;
+
+ g_return_if_fail (IM_IS_APPLICATION_LIST (list));
+
+ app = im_application_list_lookup (list, id);
+ if (!app)
+ {
+ g_warning ("'%s' is not a registered application", id);
+ return;
+ }
+
+ if (app->cancellable)
+ {
+ gchar *name_owner = NULL;
+
+ if (app->proxy)
+ name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy));
+ g_warning ("replacing '%s' at %s with %s", id, name_owner, unique_bus_name);
+
+ im_application_list_unset_remote (app);
+
+ g_free (name_owner);
+ }
+
+ app->cancellable = g_cancellable_new ();
+ indicator_messages_application_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE,
+ unique_bus_name, object_path, app->cancellable,
+ im_application_list_proxy_created, app);
+}
+
+GActionGroup *
+im_application_list_get_action_group (ImApplicationList *list)
+{
+ g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
+
+ return G_ACTION_GROUP (list->muxer);
+}
diff --git a/src/im-application-list.h b/src/im-application-list.h
new file mode 100644
index 0000000..ecba312
--- /dev/null
+++ b/src/im-application-list.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#ifndef __IM_APPLICATION_LIST_H__
+#define __IM_APPLICATION_LIST_H__
+
+#include <gio/gio.h>
+
+#define IM_TYPE_APPLICATION_LIST (im_application_list_get_type ())
+#define IM_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationList))
+#define IM_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_APPLICATION_LIST, ImApplicationListClass))
+#define IM_IS_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_APPLICATION_LIST))
+#define IM_IS_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_APPLICATION_LIST))
+#define IM_APPLICATION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationListClass))
+
+typedef struct _ImApplicationList ImApplicationList;
+
+GType im_application_list_get_type (void);
+
+ImApplicationList * im_application_list_new (void);
+
+void im_application_list_add (ImApplicationList *list,
+ const gchar *desktop_id);
+
+void im_application_list_remove (ImApplicationList *list,
+ const gchar *id);
+
+void im_application_list_set_remote (ImApplicationList *list,
+ const gchar *id,
+ GDBusConnection *connection,
+ const gchar *unique_bus_name,
+ const gchar *object_path);
+
+GActionGroup * im_application_list_get_action_group (ImApplicationList *list);
+
+#endif
diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c
new file mode 100644
index 0000000..3d5f94d
--- /dev/null
+++ b/src/im-phone-menu.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#include "im-phone-menu.h"
+
+#include <string.h>
+
+typedef GObjectClass ImPhoneMenuClass;
+
+struct _ImPhoneMenu
+{
+ GObject parent;
+
+ GMenu *toplevel_menu;
+ GMenu *message_section;
+ GMenu *source_section;
+
+};
+
+G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, G_TYPE_OBJECT);
+
+typedef void (*ImMenuForeachFunc) (GMenuModel *menu, gint pos);
+
+static void
+im_phone_menu_foreach_item_with_action (GMenuModel *menu,
+ const gchar *action,
+ ImMenuForeachFunc func)
+{
+ gint n_items;
+ gint i;
+
+ n_items = g_menu_model_get_n_items (menu);
+ for (i = 0; i < n_items; i++)
+ {
+ gchar *item_action;
+
+ g_menu_model_get_item_attribute (menu, i, G_MENU_ATTRIBUTE_ACTION, "s", &item_action);
+
+ if (g_str_equal (action, item_action))
+ func (menu, i);
+
+ g_free (item_action);
+ }
+}
+
+static void
+im_phone_menu_update_toplevel (ImPhoneMenu *menu)
+{
+ if (g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section)) ||
+ g_menu_model_get_n_items (G_MENU_MODEL (menu->source_section)))
+ {
+ if (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)) == 0)
+ {
+ GMenuItem *item;
+
+ g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->message_section));
+ g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->source_section));
+
+ item = g_menu_item_new ("Clear All", "remove-all");
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.button");
+ g_menu_append_item (menu->toplevel_menu, item);
+
+ g_object_unref (item);
+ }
+ }
+ else
+ {
+ while (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)))
+ g_menu_remove (menu->toplevel_menu, 0);
+ }
+}
+
+static void
+im_phone_menu_dispose (GObject *object)
+{
+ ImPhoneMenu *menu = IM_PHONE_MENU (object);
+
+ g_clear_object (&menu->toplevel_menu);
+ g_clear_object (&menu->message_section);
+ g_clear_object (&menu->source_section);
+
+ G_OBJECT_CLASS (im_phone_menu_parent_class)->dispose (object);
+}
+
+static void
+im_phone_menu_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (im_phone_menu_parent_class)->finalize (object);
+}
+
+static void
+im_phone_menu_class_init (ImPhoneMenuClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = im_phone_menu_dispose;
+ object_class->finalize = im_phone_menu_finalize;
+}
+
+static void
+im_phone_menu_init (ImPhoneMenu *menu)
+{
+ menu->toplevel_menu = g_menu_new ();
+ menu->message_section = g_menu_new ();
+ menu->source_section = g_menu_new ();
+
+ g_signal_connect_swapped (menu->message_section, "items-changed",
+ G_CALLBACK (im_phone_menu_update_toplevel), menu);
+ g_signal_connect_swapped (menu->source_section, "items-changed",
+ G_CALLBACK (im_phone_menu_update_toplevel), menu);
+
+ im_phone_menu_update_toplevel (menu);
+}
+
+ImPhoneMenu *
+im_phone_menu_new (void)
+{
+ return g_object_new (IM_TYPE_PHONE_MENU, NULL);
+}
+
+GMenuModel *
+im_phone_menu_get_model (ImPhoneMenu *menu)
+{
+ g_return_val_if_fail (IM_IS_PHONE_MENU (menu), NULL);
+
+ return G_MENU_MODEL (menu->toplevel_menu);
+}
+
+static gint64
+im_phone_menu_get_message_time (GMenuModel *model,
+ gint i)
+{
+ gint64 time;
+
+ g_menu_model_get_item_attribute (model, i, "x-canonical-time", "x", &time);
+
+ return time;
+}
+
+void
+im_phone_menu_add_message (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *app_icon,
+ const gchar *id,
+ const gchar *iconstr,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *body,
+ GVariant *actions,
+ gint64 time)
+{
+ GMenuItem *item;
+ gchar *action_name;
+ gint n_messages;
+ gint pos;
+
+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
+ g_return_if_fail (app_id);
+
+ action_name = g_strconcat (app_id, ".msg.", id, NULL);
+
+ item = g_menu_item_new (title, action_name);
+
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.messageitem");
+ g_menu_item_set_attribute (item, "x-canonical-message-id", "s", id);
+ g_menu_item_set_attribute (item, "x-canonical-subtitle", "s", subtitle);
+ g_menu_item_set_attribute (item, "x-canonical-text", "s", body);
+ g_menu_item_set_attribute (item, "x-canonical-time", "x", time);
+
+ if (iconstr)
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
+
+ if (app_icon)
+ g_menu_item_set_attribute (item, "x-canonical-app-icon", "s", app_icon);
+
+ if (actions)
+ g_menu_item_set_attribute (item, "x-canonical-message-actions", "v", actions);
+
+ n_messages = g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section));
+ pos = 0;
+ while (pos < n_messages &&
+ time < im_phone_menu_get_message_time (G_MENU_MODEL (menu->message_section), pos))
+ pos++;
+
+ g_menu_insert_item (menu->message_section, pos, item);
+
+ g_free (action_name);
+ g_object_unref (item);
+}
+
+void
+im_phone_menu_remove_message (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *id)
+{
+ gchar *action_name;
+
+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
+ g_return_if_fail (app_id != NULL);
+
+ action_name = g_strconcat (app_id, ".msg.", id, NULL);
+ im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->message_section),
+ action_name,
+ (ImMenuForeachFunc) g_menu_remove);
+
+ g_free (action_name);
+}
+
+void
+im_phone_menu_add_source (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *id,
+ const gchar *label,
+ const gchar *iconstr)
+{
+ GMenuItem *item;
+ gchar *action_name;
+
+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
+ g_return_if_fail (app_id != NULL);
+
+ action_name = g_strconcat (app_id, ".src.", id, NULL);
+
+ item = g_menu_item_new (label, action_name);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.sourceitem");
+
+ if (iconstr)
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
+
+ g_menu_prepend_item (menu->source_section, item);
+
+ g_free (action_name);
+ g_object_unref (item);
+}
+
+void
+im_phone_menu_remove_source (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *id)
+{
+ gchar *action_name;
+
+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
+ g_return_if_fail (app_id != NULL);
+
+ action_name = g_strconcat (app_id, ".src.", id, NULL);
+ im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->source_section),
+ action_name,
+ (ImMenuForeachFunc) g_menu_remove);
+
+ g_free (action_name);
+}
+
+static void
+im_phone_menu_remove_all_for_app (GMenu *menu,
+ const gchar *app_id)
+{
+ gchar *prefix;
+ gint n_items;
+ gint i = 0;
+
+ prefix = g_strconcat (app_id, ".", NULL);
+
+ n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu));
+ while (i < n_items)
+ {
+ gchar *action;
+
+ g_menu_model_get_item_attribute (G_MENU_MODEL (menu), i, G_MENU_ATTRIBUTE_ACTION, "s", &action);
+ if (g_str_has_prefix (action, prefix))
+ {
+ g_menu_remove (menu, i);
+ n_items--;
+ }
+ else
+ {
+ i++;
+ }
+
+ g_free (action);
+ }
+
+ g_free (prefix);
+}
+
+void
+im_phone_menu_remove_application (ImPhoneMenu *menu,
+ const gchar *app_id)
+{
+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
+ g_return_if_fail (app_id != NULL);
+
+ im_phone_menu_remove_all_for_app (menu->source_section, app_id);
+ im_phone_menu_remove_all_for_app (menu->message_section, app_id);
+}
+
+void
+im_phone_menu_remove_all (ImPhoneMenu *menu)
+{
+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
+
+ while (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)))
+ g_menu_remove (menu->toplevel_menu, 0);
+
+ g_object_unref (menu->message_section);
+ g_object_unref (menu->source_section);
+
+ menu->message_section = g_menu_new ();
+ menu->source_section = g_menu_new ();
+
+ g_signal_connect_swapped (menu->message_section, "items-changed",
+ G_CALLBACK (im_phone_menu_update_toplevel), menu);
+ g_signal_connect_swapped (menu->source_section, "items-changed",
+ G_CALLBACK (im_phone_menu_update_toplevel), menu);
+}
diff --git a/src/im-phone-menu.h b/src/im-phone-menu.h
new file mode 100644
index 0000000..258ce73
--- /dev/null
+++ b/src/im-phone-menu.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#ifndef __IM_PHONE_MENU_H__
+#define __IM_PHONE_MENU_H__
+
+#include <gio/gio.h>
+
+#define IM_TYPE_PHONE_MENU (im_phone_menu_get_type ())
+#define IM_PHONE_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_PHONE_MENU, ImPhoneMenu))
+#define IM_PHONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_PHONE_MENU, ImPhoneMenuClass))
+#define IM_IS_PHONE_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_PHONE_MENU))
+#define IM_IS_PHONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_PHONE_MENU))
+#define IM_PHONE_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_PHONE_MENU, ImPhoneMenuClass))
+
+typedef struct _ImPhoneMenu ImPhoneMenu;
+
+GType im_phone_menu_get_type (void);
+
+ImPhoneMenu * im_phone_menu_new (void);
+
+GMenuModel * im_phone_menu_get_model (ImPhoneMenu *menu);
+
+void im_phone_menu_add_message (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *app_icon,
+ const gchar *id,
+ const gchar *iconstr,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *body,
+ GVariant *actions,
+ gint64 time);
+
+void im_phone_menu_remove_message (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *id);
+
+void im_phone_menu_add_source (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *id,
+ const gchar *label,
+ const gchar *iconstr);
+
+void im_phone_menu_remove_source (ImPhoneMenu *menu,
+ const gchar *app_id,
+ const gchar *id);
+
+void im_phone_menu_remove_application (ImPhoneMenu *menu,
+ const gchar *app_id);
+
+void im_phone_menu_remove_all (ImPhoneMenu *menu);
+
+#endif
diff --git a/src/messages-service.c b/src/messages-service.c
index 8f64478..5f320fc 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -23,418 +23,25 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <config.h>
#include <locale.h>
-#include <libindicator/indicator-service.h>
#include <gio/gio.h>
-#include <gio/gdesktopappinfo.h>
#include <glib/gi18n.h>
-#include "app-section.h"
#include "dbus-data.h"
-#include "gactionmuxer.h"
#include "gsettingsstrv.h"
#include "gmenuutils.h"
#include "indicator-messages-service.h"
+#include "indicator-messages-application.h"
+#include "im-phone-menu.h"
+#include "im-application-list.h"
#define NUM_STATUSES 5
-static GHashTable *applications;
+static ImApplicationList *applications;
static IndicatorMessagesService *messages_service;
-static GSimpleActionGroup *actions;
-static GActionMuxer *action_muxer;
static GMenu *toplevel_menu;
-static GMenu *menu;
-static GMenuModel *chat_section;
+static ImPhoneMenu *menu;
static GSettings *settings;
-static gboolean draws_attention;
-static const gchar *global_status[6]; /* max 5: available, away, busy, invisible, offline */
-
-static gchar *
-indicator_messages_get_icon_name ()
-{
- GString *name;
- GIcon *icon;
- gchar *iconstr;
-
- name = g_string_new ("indicator-messages");
-
- if (global_status[0] != NULL)
- {
- if (global_status[1] != NULL)
- g_string_append (name, "-mixed");
- else
- g_string_append_printf (name, "-%s", global_status[0]);
- }
-
- if (draws_attention)
- g_string_append (name, "-new");
-
- icon = g_themed_icon_new (name->str);
- g_themed_icon_append_name (G_THEMED_ICON (icon),
- draws_attention ? "indicator-messages-new"
- : "indicator-messages");
-
- iconstr = g_icon_to_string (icon);
-
- g_object_unref (icon);
- g_string_free (name, TRUE);
-
- return iconstr;
-}
-
-static void
-indicator_messages_update_icon ()
-{
- GSimpleAction *messages;
- gchar *icon;
-
- messages = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "messages"));
- g_return_if_fail (messages != NULL);
-
- icon = indicator_messages_get_icon_name ();
- g_simple_action_set_state (messages, g_variant_new_string (icon));
-
- g_free (icon);
-}
-
-static gchar *
-g_app_info_get_simple_id (GAppInfo *appinfo)
-{
- const gchar *id;
-
- id = g_app_info_get_id (appinfo);
- if (!id)
- return NULL;
-
- if (g_str_has_suffix (id, ".desktop"))
- return g_strndup (id, strlen (id) - 8);
- else
- return g_strdup (id);
-}
-
-static void
-actions_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- AppSection *section = APP_SECTION (object);
- gchar *id;
- GActionGroup *actions;
-
- id = g_app_info_get_simple_id (app_section_get_app_info (section));
- actions = app_section_get_actions (section);
-
- g_action_muxer_insert (action_muxer, id, actions);
- g_free (id);
-}
-
-
-static gboolean
-app_section_draws_attention (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- AppSection *section = value;
- return app_section_get_draws_attention (section);
-}
-
-static void
-draws_attention_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- GSimpleAction *clear;
-
- clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear"));
- g_return_if_fail (clear != NULL);
-
- draws_attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL;
-
- g_simple_action_set_enabled (clear, draws_attention);
-
- indicator_messages_update_icon ();
-}
-
-static gboolean
-app_section_uses_chat (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- AppSection *section = value;
- return app_section_get_uses_chat_status (section);
-}
-
-static void
-update_chat_section ()
-{
- gboolean show_chat;
- GMenuModel *first_section;
-
- show_chat = g_hash_table_find (applications, app_section_uses_chat, NULL) != NULL;
-
- first_section = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, G_MENU_LINK_SECTION);
- if (first_section == chat_section) {
- if (!show_chat)
- g_menu_remove (menu, 0);
- }
- else {
- if (show_chat)
- g_menu_insert_section (menu, 0, NULL, chat_section);
- }
-
- if (first_section != NULL)
- g_object_unref (first_section);
-
- indicator_messages_update_icon ();
-}
-
-static void
-uses_chat_status_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- update_chat_section ();
-}
-
-static gboolean
-strv_contains (const gchar **strv,
- const gchar *needle)
-{
- const gchar **it;
-
- it = strv;
- while (*it != NULL && !g_str_equal (*it, needle))
- it++;
-
- return *it != NULL;
-}
-
-static void
-update_chat_status ()
-{
- GHashTableIter iter;
- AppSection *section;
- int pos;
- GAction *status;
-
- for (pos = 0; pos < G_N_ELEMENTS (global_status); pos++)
- global_status[pos] = NULL;
-
- pos = 0;
- g_hash_table_iter_init (&iter, applications);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer) &section) &&
- pos < G_N_ELEMENTS (global_status))
- {
- const gchar *status_str = NULL;
-
- status_str = app_section_get_status (section);
- if (status_str != NULL && !strv_contains (global_status, status_str))
- global_status[pos++] = status_str;
- }
-
- if (pos == 0)
- global_status[0] = "offline";
-
- status = g_simple_action_group_lookup (actions, "status");
- g_return_if_fail (status != NULL);
-
- g_simple_action_set_state (G_SIMPLE_ACTION (status), g_variant_new_strv (global_status, -1));
-
- indicator_messages_update_icon ();
-}
-
-static void
-chat_status_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- update_chat_status ();
-}
-
-static void
-remove_section (AppSection *section,
- const gchar *id)
-{
- int pos = g_menu_find_section (menu, app_section_get_menu (section));
- if (pos >= 0)
- g_menu_remove (menu, pos);
- g_action_muxer_remove (action_muxer, id);
-
- g_signal_handlers_disconnect_by_func (section, actions_changed, NULL);
- g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL);
- g_signal_handlers_disconnect_by_func (section, uses_chat_status_changed, NULL);
- g_signal_handlers_disconnect_by_func (section, chat_status_changed, NULL);
- g_signal_handlers_disconnect_by_func (section, remove_section, NULL);
-
- g_hash_table_remove (applications, id);
-
- if (g_hash_table_size (applications) == 0 &&
- g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 1) {
- g_menu_remove (toplevel_menu, 0);
- }
-
- update_chat_status ();
- update_chat_section ();
-}
-
-static AppSection *
-add_application (const gchar *desktop_id)
-{
- GDesktopAppInfo *appinfo;
- gchar *id;
- AppSection *section;
-
- appinfo = g_desktop_app_info_new (desktop_id);
- if (!appinfo) {
- g_warning ("could not add '%s', there's no desktop file with that id", desktop_id);
- return NULL;
- }
-
- id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
- section = g_hash_table_lookup (applications, id);
-
- if (!section) {
- GMenuItem *menuitem;
-
- section = app_section_new(appinfo);
- g_hash_table_insert (applications, g_strdup (id), section);
-
- g_action_muxer_insert (action_muxer, id, app_section_get_actions (section));
- g_signal_connect (section, "notify::actions",
- G_CALLBACK (actions_changed), NULL);
- g_signal_connect (section, "notify::draws-attention",
- G_CALLBACK (draws_attention_changed), NULL);
- g_signal_connect (section, "notify::uses-chat-status",
- G_CALLBACK (uses_chat_status_changed), NULL);
- g_signal_connect (section, "notify::chat-status",
- G_CALLBACK (chat_status_changed), NULL);
- g_signal_connect_data (section, "destroy",
- G_CALLBACK (remove_section),
- g_strdup (id),
- (GClosureNotify) g_free,
- 0);
-
- /* TODO insert it at the right position (alphabetically by application name) */
- menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section));
- g_menu_item_set_attribute (menuitem, "action-namespace", "s", id);
- g_menu_insert_item (menu, g_menu_model_get_n_items (G_MENU_MODEL (menu)) -1, menuitem);
- g_object_unref (menuitem);
- }
-
- if (g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 0) {
- GMenuItem *header;
-
- header = g_menu_item_new (NULL, "messages");
- g_menu_item_set_submenu (header, G_MENU_MODEL (menu));
- g_menu_item_set_attribute (header, "x-canonical-accessible-description", "s", _("Messages"));
- g_menu_append_item (toplevel_menu, header);
-
- g_object_unref (header);
- }
-
- g_free (id);
- g_object_unref (appinfo);
- return section;
-}
-
-static void
-remove_application (const char *desktop_id)
-{
- GDesktopAppInfo *appinfo;
- gchar *id;
- AppSection *section;
-
- appinfo = g_desktop_app_info_new (desktop_id);
- if (!appinfo) {
- g_warning ("could not remove '%s', there's no desktop file with that id", desktop_id);
- return;
- }
-
- id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
-
- section = g_hash_table_lookup (applications, id);
- if (section) {
- remove_section (section, id);
- }
- else {
- g_warning ("could not remove '%s', it's not registered", desktop_id);
- }
-
- g_free (id);
- g_object_unref (appinfo);
-}
-
-/* This function turns a specific desktop id into a menu
- item and registers it appropriately with everyone */
-static gboolean
-build_launcher (gpointer data)
-{
- gchar *desktop_id = data;
-
- add_application (desktop_id);
-
- g_free (desktop_id);
- return FALSE;
-}
-
-/* This function goes through all the launchers that we're
- supposed to be grabbing and decides to show turn them
- into menu items or not. It doens't do the work, but it
- makes the decision. */
-static gboolean
-build_launchers (gpointer data)
-{
- gchar **applications = g_settings_get_strv (settings, "applications");
- gchar **app;
-
- g_return_val_if_fail (applications != NULL, FALSE);
-
- for (app = applications; *app; app++)
- {
- g_idle_add(build_launcher, g_strdup (*app));
- }
-
- g_strfreev (applications);
- return FALSE;
-}
-
-static void
-service_shutdown (IndicatorService * service, gpointer user_data)
-{
- GMainLoop *mainloop = user_data;
-
- g_warning("Shutting down service!");
- g_main_loop_quit(mainloop);
-}
-
-static void
-app_section_remove_attention (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- AppSection *section = value;
- app_section_clear_draws_attention (section);
-}
-
-static void
-clear_action_activate (GSimpleAction *simple,
- GVariant *param,
- gpointer user_data)
-{
- g_hash_table_foreach (applications, app_section_remove_attention, NULL);
-}
-
-static void
-status_action_activate (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- const gchar *status;
-
- status = g_variant_get_string (parameter, NULL);
-
- indicator_messages_service_emit_status_changed (messages_service, status);
-}
static void
register_application (IndicatorMessagesService *service,
@@ -443,18 +50,15 @@ register_application (IndicatorMessagesService *service,
const gchar *menu_path,
gpointer user_data)
{
- AppSection *section;
GDBusConnection *bus;
const gchar *sender;
- section = add_application (desktop_id);
- if (!section)
- return;
+ im_application_list_add (applications, desktop_id);
bus = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (service));
sender = g_dbus_method_invocation_get_sender (invocation);
- app_section_set_object_path (section, bus, sender, menu_path);
+ im_application_list_set_remote (applications, desktop_id, bus, sender, menu_path);
g_settings_strv_append_unique (settings, "applications", desktop_id);
indicator_messages_service_complete_register_application (service, invocation);
@@ -466,137 +70,29 @@ unregister_application (IndicatorMessagesService *service,
const gchar *desktop_id,
gpointer user_data)
{
- remove_application (desktop_id);
+ im_application_list_remove (applications, desktop_id);
g_settings_strv_remove (settings, "applications", desktop_id);
indicator_messages_service_complete_unregister_application (service, invocation);
}
static void
-set_status (IndicatorMessagesService *service,
- GDBusMethodInvocation *invocation,
- const gchar *desktop_id,
- const gchar *status_str,
- gpointer user_data)
+on_bus_acquired (GDBusConnection *bus,
+ const gchar *name,
+ gpointer user_data)
{
- GDesktopAppInfo *appinfo;
- gchar *id;
- AppSection *section;
-
- g_return_if_fail (g_str_equal (status_str, "available") ||
- g_str_equal (status_str, "away")||
- g_str_equal (status_str, "busy") ||
- g_str_equal (status_str, "invisible") ||
- g_str_equal (status_str, "offline"));
-
- appinfo = g_desktop_app_info_new (desktop_id);
- if (!appinfo) {
- g_warning ("could not set status for '%s', there's no desktop file with that id", desktop_id);
- return;
- }
-
- id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
- section = g_hash_table_lookup (applications, id);
- if (section != NULL)
- app_section_set_status (section, status_str);
-
- indicator_messages_service_complete_set_status (service, invocation);
-
- g_free (id);
- g_object_unref (appinfo);
-}
-
-static GSimpleActionGroup *
-create_action_group (void)
-{
- GSimpleActionGroup *actions;
- GSimpleAction *messages;
- GSimpleAction *clear;
- GSimpleAction *status;
- const gchar *default_status[] = { "offline", NULL };
- gchar *icon;
-
- actions = g_simple_action_group_new ();
-
- /* state of the messages action is its icon name */
- icon = indicator_messages_get_icon_name ();
- messages = g_simple_action_new_stateful ("messages", G_VARIANT_TYPE ("s"),
- g_variant_new_string (icon));
-
- status = g_simple_action_new_stateful ("status", G_VARIANT_TYPE ("s"),
- g_variant_new_strv (default_status, -1));
- g_signal_connect (status, "activate", G_CALLBACK (status_action_activate), NULL);
-
- clear = g_simple_action_new ("clear", NULL);
- g_simple_action_set_enabled (clear, FALSE);
- g_signal_connect (clear, "activate", G_CALLBACK (clear_action_activate), NULL);
-
- g_simple_action_group_insert (actions, G_ACTION (messages));
- g_simple_action_group_insert (actions, G_ACTION (status));
- g_simple_action_group_insert (actions, G_ACTION (clear));
-
- g_free (icon);
- return actions;
-}
-
-static GMenuModel *
-create_status_section (void)
-{
- GMenu *menu;
- GMenuItem *item;
- struct status_item {
- gchar *label;
- gchar *action;
- gchar *icon_name;
- } status_items[] = {
- { _("Available"), "status::available", "user-available" },
- { _("Away"), "status::away", "user-away" },
- { _("Busy"), "status::busy", "user-busy" },
- { _("Invisible"), "status::invisible", "user-invisible" },
- { _("Offline"), "status::offline", "user-offline" }
- };
- int i;
-
- menu = g_menu_new ();
-
- item = g_menu_item_new (NULL, NULL);
- g_menu_item_set_attribute (item, "x-canonical-type", "s", "IdoMenuItem");
-
- for (i = 0; i < G_N_ELEMENTS (status_items); i++) {
- g_menu_item_set_label (item, status_items[i].label);
- g_menu_item_set_detailed_action (item, status_items[i].action);
- g_menu_item_set_attribute (item, "x-canonical-icon", "s", status_items[i].icon_name);
- g_menu_append_item (menu, item);
- }
-
- g_object_unref (item);
- return G_MENU_MODEL (menu);
-}
-
-static void
-got_bus (GObject *object,
- GAsyncResult * res,
- gpointer user_data)
-{
- GDBusConnection *bus;
GError *error = NULL;
- bus = g_bus_get_finish (res, &error);
- if (!bus) {
- g_warning ("unable to connect to the session bus: %s", error->message);
- g_error_free (error);
- return;
- }
-
g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT,
- G_ACTION_GROUP (action_muxer), &error);
+ im_application_list_get_action_group (applications),
+ &error);
if (error) {
g_warning ("unable to export action group on dbus: %s", error->message);
g_error_free (error);
return;
}
- g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT,
+ g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT "/phone",
G_MENU_MODEL (toplevel_menu), &error);
if (error) {
g_warning ("unable to export menu on dbus: %s", error->message);
@@ -616,17 +112,29 @@ got_bus (GObject *object,
g_object_unref (bus);
}
+static void
+on_name_lost (GDBusConnection *bus,
+ const gchar *name,
+ gpointer user_data)
+{
+ GMainLoop *mainloop = user_data;
+
+ g_main_loop_quit (mainloop);
+}
+
int
main (int argc, char ** argv)
{
GMainLoop * mainloop = NULL;
- IndicatorService * service = NULL;
+ GMenuItem *root;
+ GBusNameOwnerFlags flags;
- mainloop = g_main_loop_new (NULL, FALSE);
+ /* Glib init */
+#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
+ g_type_init();
+#endif
- /* Create the Indicator Service interface */
- service = indicator_service_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1);
- g_signal_connect(service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), mainloop);
+ mainloop = g_main_loop_new (NULL, FALSE);
/* Setting up i18n and gettext. Apparently, we need
all of these. */
@@ -637,38 +145,44 @@ main (int argc, char ** argv)
/* Bring up the service DBus interface */
messages_service = indicator_messages_service_skeleton_new ();
- g_bus_get (G_BUS_TYPE_SESSION, NULL, got_bus, NULL);
+ flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
+ if (argc >= 2 && g_str_equal (argv[1], "--replace"))
+ flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
- actions = create_action_group ();
-
- action_muxer = g_action_muxer_new ();
- g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions));
+ g_bus_own_name (G_BUS_TYPE_SESSION, "com.canonical.indicator.messages", flags,
+ on_bus_acquired, NULL, on_name_lost, mainloop, NULL);
g_signal_connect (messages_service, "handle-register-application",
G_CALLBACK (register_application), NULL);
g_signal_connect (messages_service, "handle-unregister-application",
G_CALLBACK (unregister_application), NULL);
- g_signal_connect (messages_service, "handle-set-status",
- G_CALLBACK (set_status), NULL);
- menu = g_menu_new ();
- chat_section = create_status_section ();
- g_menu_append (menu, _("Clear"), "clear");
+ menu = im_phone_menu_new ();
toplevel_menu = g_menu_new ();
+ root = g_menu_item_new (NULL, "messages");
+ g_menu_item_set_attribute (root, "x-canonical-type", "s", "com.canonical.indicator.root");
+ g_menu_item_set_submenu (root, im_phone_menu_get_model (menu));
+ g_menu_append_item (toplevel_menu, root);
settings = g_settings_new ("com.canonical.indicator.messages");
- applications = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-
- g_idle_add(build_launchers, NULL);
+ applications = im_application_list_new ();
+ g_signal_connect_swapped (applications, "message-added",
+ G_CALLBACK (im_phone_menu_add_message), menu);
+ g_signal_connect_swapped (applications, "message-removed",
+ G_CALLBACK (im_phone_menu_remove_message), menu);
+ g_signal_connect_swapped (applications, "app-stopped",
+ G_CALLBACK (im_phone_menu_remove_application), menu);
+ g_signal_connect_swapped (applications, "remove-all",
+ G_CALLBACK (im_phone_menu_remove_all), menu);
g_main_loop_run(mainloop);
/* Clean up */
+ g_object_unref (root);
g_object_unref (messages_service);
- g_object_unref (chat_section);
g_object_unref (settings);
- g_hash_table_unref (applications);
+ g_object_unref (applications);
return 0;
}
diff --git a/test/Makefile.am b/test/Makefile.am
index 4671446..8c8c160 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -38,8 +38,8 @@ noinst_LTLIBRARIES = \
libindicator-messages-service.la
libindicator_messages_service_la_SOURCES = \
- $(top_builddir)/src/indicator-messages-service.c \
- $(top_builddir)/src/indicator-messages-service.h \
+ $(top_builddir)/common/indicator-messages-service.c \
+ $(top_builddir)/common/indicator-messages-service.h \
$(top_srcdir)/src/app-section.c \
$(top_srcdir)/src/app-section.h \
$(top_srcdir)/src/gactionmuxer.c \
@@ -53,6 +53,7 @@ libindicator_messages_service_la_CFLAGS = \
$(APPLET_CFLAGS) \
$(COVERAGE_CFLAGS) \
-I$(top_builddir)/src \
+ -I$(top_builddir)/common \
-Wall \
-Wl,-Bsymbolic-functions \
-Wl,-z,defs \
diff --git a/test/indicator-messages-service-activate.c b/test/indicator-messages-service-activate.c
index 98c6522..f5a26b0 100644
--- a/test/indicator-messages-service-activate.c
+++ b/test/indicator-messages-service-activate.c
@@ -28,7 +28,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
int
main (int argc, char ** argv)
{
+#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
g_type_init();
+#endif
guint returnval = 0;
GError * error = NULL;
diff --git a/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp
index 6304853..efd6e4f 100644
--- a/test/test-gactionmuxer.cpp
+++ b/test/test-gactionmuxer.cpp
@@ -1,3 +1,21 @@
+/*
+An indicator to show information that is in messaging applications
+that the user is using.
+
+Copyright 2012 Canonical Ltd.
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
#include <glib.h>
#include <gio/gio.h>
@@ -25,7 +43,9 @@ strv_contains (gchar **str_array,
TEST(GActionMuxerTest, Sanity) {
GActionMuxer *muxer;
+#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
g_type_init ();
+#endif
g_action_muxer_insert (NULL, NULL, NULL);
g_action_muxer_remove (NULL, NULL);
@@ -46,7 +66,9 @@ TEST(GActionMuxerTest, Empty) {
GActionMuxer *muxer;
gchar **actions;
+#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
g_type_init ();
+#endif
muxer = g_action_muxer_new ();
@@ -67,7 +89,9 @@ TEST(GActionMuxerTest, AddAndRemove) {
GActionMuxer *muxer;
gchar **actions;
+#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
g_type_init ();
+#endif
group1 = g_simple_action_group_new ();
g_simple_action_group_add_entries (group1,
@@ -160,7 +184,9 @@ TEST(GActionMuxerTest, ActionAttributes) {
GVariant *state_hint[2];
GVariant *state[2];
+#if G_ENCODE_VERSION(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) <= GLIB_VERSION_2_34
g_type_init ();
+#endif
group = g_simple_action_group_new ();
action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING);