Merge lp:~sergiusens/indicator-messages/bump into lp:~indicator-applet-developers/indicator-messages/trunk.13.10

Proposed by Sergio Schvezov
Status: Superseded
Proposed branch: lp:~sergiusens/indicator-messages/bump
Merge into: lp:~indicator-applet-developers/indicator-messages/trunk.13.10
Diff against target: 5952 lines (+3802/-1351) (has conflicts)
31 files modified
COPYING.GPLv3 (+674/-0)
Makefile.am (+1/-0)
common/Makefile.am (+32/-0)
common/com.canonical.indicator.messages.application.xml (+39/-0)
configure.ac (+1/-0)
debian/changelog (+90/-0)
debian/libmessaging-menu0.symbols (+15/-0)
debian/source/format (+1/-0)
doc/reference/Makefile.am (+1/-2)
doc/reference/messaging-menu-docs.xml.in (+2/-1)
libmessaging-menu/Makefile.am (+15/-22)
libmessaging-menu/gtupleaction.c (+0/-354)
libmessaging-menu/gtupleaction.h (+0/-40)
libmessaging-menu/messaging-menu-app.c (+509/-194)
libmessaging-menu/messaging-menu-app.h (+17/-2)
libmessaging-menu/messaging-menu-message.c (+547/-0)
libmessaging-menu/messaging-menu-message.h (+70/-0)
libmessaging-menu/messaging-menu.h (+25/-0)
src/Makefile.am (+11/-25)
src/app-section.c (+274/-170)
src/dbus-data.h (+16/-1)
src/gactionmuxer.c (+8/-0)
src/gactionmuxer.h (+3/-0)
src/im-application-list.c (+880/-0)
src/im-application-list.h (+52/-0)
src/im-phone-menu.c (+331/-0)
src/im-phone-menu.h (+70/-0)
src/messages-service.c (+62/-538)
test/Makefile.am (+3/-2)
test/indicator-messages-service-activate.c (+7/-0)
test/test-gactionmuxer.cpp (+46/-0)
Text conflict in debian/changelog
Text conflict in libmessaging-menu/messaging-menu-app.c
Text conflict in src/messages-service.c
Text conflict in test/indicator-messages-service-activate.c
Text conflict in test/test-gactionmuxer.cpp
To merge this branch: bzr merge lp:~sergiusens/indicator-messages/bump
Reviewer Review Type Date Requested Status
Indicator Applet Developers Pending
Review via email: mp+161197@code.launchpad.net

This proposal has been superseded by a proposal from 2013-04-26.

Commit message

Version bump to not pull from archive

To post a comment you must log in.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'COPYING.GPLv3'
2--- COPYING.GPLv3 1970-01-01 00:00:00 +0000
3+++ COPYING.GPLv3 2013-04-26 16:57:25 +0000
4@@ -0,0 +1,674 @@
5+ GNU GENERAL PUBLIC LICENSE
6+ Version 3, 29 June 2007
7+
8+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
9+ Everyone is permitted to copy and distribute verbatim copies
10+ of this license document, but changing it is not allowed.
11+
12+ Preamble
13+
14+ The GNU General Public License is a free, copyleft license for
15+software and other kinds of works.
16+
17+ The licenses for most software and other practical works are designed
18+to take away your freedom to share and change the works. By contrast,
19+the GNU General Public License is intended to guarantee your freedom to
20+share and change all versions of a program--to make sure it remains free
21+software for all its users. We, the Free Software Foundation, use the
22+GNU General Public License for most of our software; it applies also to
23+any other work released this way by its authors. You can apply it to
24+your programs, too.
25+
26+ When we speak of free software, we are referring to freedom, not
27+price. Our General Public Licenses are designed to make sure that you
28+have the freedom to distribute copies of free software (and charge for
29+them if you wish), that you receive source code or can get it if you
30+want it, that you can change the software or use pieces of it in new
31+free programs, and that you know you can do these things.
32+
33+ To protect your rights, we need to prevent others from denying you
34+these rights or asking you to surrender the rights. Therefore, you have
35+certain responsibilities if you distribute copies of the software, or if
36+you modify it: responsibilities to respect the freedom of others.
37+
38+ For example, if you distribute copies of such a program, whether
39+gratis or for a fee, you must pass on to the recipients the same
40+freedoms that you received. You must make sure that they, too, receive
41+or can get the source code. And you must show them these terms so they
42+know their rights.
43+
44+ Developers that use the GNU GPL protect your rights with two steps:
45+(1) assert copyright on the software, and (2) offer you this License
46+giving you legal permission to copy, distribute and/or modify it.
47+
48+ For the developers' and authors' protection, the GPL clearly explains
49+that there is no warranty for this free software. For both users' and
50+authors' sake, the GPL requires that modified versions be marked as
51+changed, so that their problems will not be attributed erroneously to
52+authors of previous versions.
53+
54+ Some devices are designed to deny users access to install or run
55+modified versions of the software inside them, although the manufacturer
56+can do so. This is fundamentally incompatible with the aim of
57+protecting users' freedom to change the software. The systematic
58+pattern of such abuse occurs in the area of products for individuals to
59+use, which is precisely where it is most unacceptable. Therefore, we
60+have designed this version of the GPL to prohibit the practice for those
61+products. If such problems arise substantially in other domains, we
62+stand ready to extend this provision to those domains in future versions
63+of the GPL, as needed to protect the freedom of users.
64+
65+ Finally, every program is threatened constantly by software patents.
66+States should not allow patents to restrict development and use of
67+software on general-purpose computers, but in those that do, we wish to
68+avoid the special danger that patents applied to a free program could
69+make it effectively proprietary. To prevent this, the GPL assures that
70+patents cannot be used to render the program non-free.
71+
72+ The precise terms and conditions for copying, distribution and
73+modification follow.
74+
75+ TERMS AND CONDITIONS
76+
77+ 0. Definitions.
78+
79+ "This License" refers to version 3 of the GNU General Public License.
80+
81+ "Copyright" also means copyright-like laws that apply to other kinds of
82+works, such as semiconductor masks.
83+
84+ "The Program" refers to any copyrightable work licensed under this
85+License. Each licensee is addressed as "you". "Licensees" and
86+"recipients" may be individuals or organizations.
87+
88+ To "modify" a work means to copy from or adapt all or part of the work
89+in a fashion requiring copyright permission, other than the making of an
90+exact copy. The resulting work is called a "modified version" of the
91+earlier work or a work "based on" the earlier work.
92+
93+ A "covered work" means either the unmodified Program or a work based
94+on the Program.
95+
96+ To "propagate" a work means to do anything with it that, without
97+permission, would make you directly or secondarily liable for
98+infringement under applicable copyright law, except executing it on a
99+computer or modifying a private copy. Propagation includes copying,
100+distribution (with or without modification), making available to the
101+public, and in some countries other activities as well.
102+
103+ To "convey" a work means any kind of propagation that enables other
104+parties to make or receive copies. Mere interaction with a user through
105+a computer network, with no transfer of a copy, is not conveying.
106+
107+ An interactive user interface displays "Appropriate Legal Notices"
108+to the extent that it includes a convenient and prominently visible
109+feature that (1) displays an appropriate copyright notice, and (2)
110+tells the user that there is no warranty for the work (except to the
111+extent that warranties are provided), that licensees may convey the
112+work under this License, and how to view a copy of this License. If
113+the interface presents a list of user commands or options, such as a
114+menu, a prominent item in the list meets this criterion.
115+
116+ 1. Source Code.
117+
118+ The "source code" for a work means the preferred form of the work
119+for making modifications to it. "Object code" means any non-source
120+form of a work.
121+
122+ A "Standard Interface" means an interface that either is an official
123+standard defined by a recognized standards body, or, in the case of
124+interfaces specified for a particular programming language, one that
125+is widely used among developers working in that language.
126+
127+ The "System Libraries" of an executable work include anything, other
128+than the work as a whole, that (a) is included in the normal form of
129+packaging a Major Component, but which is not part of that Major
130+Component, and (b) serves only to enable use of the work with that
131+Major Component, or to implement a Standard Interface for which an
132+implementation is available to the public in source code form. A
133+"Major Component", in this context, means a major essential component
134+(kernel, window system, and so on) of the specific operating system
135+(if any) on which the executable work runs, or a compiler used to
136+produce the work, or an object code interpreter used to run it.
137+
138+ The "Corresponding Source" for a work in object code form means all
139+the source code needed to generate, install, and (for an executable
140+work) run the object code and to modify the work, including scripts to
141+control those activities. However, it does not include the work's
142+System Libraries, or general-purpose tools or generally available free
143+programs which are used unmodified in performing those activities but
144+which are not part of the work. For example, Corresponding Source
145+includes interface definition files associated with source files for
146+the work, and the source code for shared libraries and dynamically
147+linked subprograms that the work is specifically designed to require,
148+such as by intimate data communication or control flow between those
149+subprograms and other parts of the work.
150+
151+ The Corresponding Source need not include anything that users
152+can regenerate automatically from other parts of the Corresponding
153+Source.
154+
155+ The Corresponding Source for a work in source code form is that
156+same work.
157+
158+ 2. Basic Permissions.
159+
160+ All rights granted under this License are granted for the term of
161+copyright on the Program, and are irrevocable provided the stated
162+conditions are met. This License explicitly affirms your unlimited
163+permission to run the unmodified Program. The output from running a
164+covered work is covered by this License only if the output, given its
165+content, constitutes a covered work. This License acknowledges your
166+rights of fair use or other equivalent, as provided by copyright law.
167+
168+ You may make, run and propagate covered works that you do not
169+convey, without conditions so long as your license otherwise remains
170+in force. You may convey covered works to others for the sole purpose
171+of having them make modifications exclusively for you, or provide you
172+with facilities for running those works, provided that you comply with
173+the terms of this License in conveying all material for which you do
174+not control copyright. Those thus making or running the covered works
175+for you must do so exclusively on your behalf, under your direction
176+and control, on terms that prohibit them from making any copies of
177+your copyrighted material outside their relationship with you.
178+
179+ Conveying under any other circumstances is permitted solely under
180+the conditions stated below. Sublicensing is not allowed; section 10
181+makes it unnecessary.
182+
183+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
184+
185+ No covered work shall be deemed part of an effective technological
186+measure under any applicable law fulfilling obligations under article
187+11 of the WIPO copyright treaty adopted on 20 December 1996, or
188+similar laws prohibiting or restricting circumvention of such
189+measures.
190+
191+ When you convey a covered work, you waive any legal power to forbid
192+circumvention of technological measures to the extent such circumvention
193+is effected by exercising rights under this License with respect to
194+the covered work, and you disclaim any intention to limit operation or
195+modification of the work as a means of enforcing, against the work's
196+users, your or third parties' legal rights to forbid circumvention of
197+technological measures.
198+
199+ 4. Conveying Verbatim Copies.
200+
201+ You may convey verbatim copies of the Program's source code as you
202+receive it, in any medium, provided that you conspicuously and
203+appropriately publish on each copy an appropriate copyright notice;
204+keep intact all notices stating that this License and any
205+non-permissive terms added in accord with section 7 apply to the code;
206+keep intact all notices of the absence of any warranty; and give all
207+recipients a copy of this License along with the Program.
208+
209+ You may charge any price or no price for each copy that you convey,
210+and you may offer support or warranty protection for a fee.
211+
212+ 5. Conveying Modified Source Versions.
213+
214+ You may convey a work based on the Program, or the modifications to
215+produce it from the Program, in the form of source code under the
216+terms of section 4, provided that you also meet all of these conditions:
217+
218+ a) The work must carry prominent notices stating that you modified
219+ it, and giving a relevant date.
220+
221+ b) The work must carry prominent notices stating that it is
222+ released under this License and any conditions added under section
223+ 7. This requirement modifies the requirement in section 4 to
224+ "keep intact all notices".
225+
226+ c) You must license the entire work, as a whole, under this
227+ License to anyone who comes into possession of a copy. This
228+ License will therefore apply, along with any applicable section 7
229+ additional terms, to the whole of the work, and all its parts,
230+ regardless of how they are packaged. This License gives no
231+ permission to license the work in any other way, but it does not
232+ invalidate such permission if you have separately received it.
233+
234+ d) If the work has interactive user interfaces, each must display
235+ Appropriate Legal Notices; however, if the Program has interactive
236+ interfaces that do not display Appropriate Legal Notices, your
237+ work need not make them do so.
238+
239+ A compilation of a covered work with other separate and independent
240+works, which are not by their nature extensions of the covered work,
241+and which are not combined with it such as to form a larger program,
242+in or on a volume of a storage or distribution medium, is called an
243+"aggregate" if the compilation and its resulting copyright are not
244+used to limit the access or legal rights of the compilation's users
245+beyond what the individual works permit. Inclusion of a covered work
246+in an aggregate does not cause this License to apply to the other
247+parts of the aggregate.
248+
249+ 6. Conveying Non-Source Forms.
250+
251+ You may convey a covered work in object code form under the terms
252+of sections 4 and 5, provided that you also convey the
253+machine-readable Corresponding Source under the terms of this License,
254+in one of these ways:
255+
256+ a) Convey the object code in, or embodied in, a physical product
257+ (including a physical distribution medium), accompanied by the
258+ Corresponding Source fixed on a durable physical medium
259+ customarily used for software interchange.
260+
261+ b) Convey the object code in, or embodied in, a physical product
262+ (including a physical distribution medium), accompanied by a
263+ written offer, valid for at least three years and valid for as
264+ long as you offer spare parts or customer support for that product
265+ model, to give anyone who possesses the object code either (1) a
266+ copy of the Corresponding Source for all the software in the
267+ product that is covered by this License, on a durable physical
268+ medium customarily used for software interchange, for a price no
269+ more than your reasonable cost of physically performing this
270+ conveying of source, or (2) access to copy the
271+ Corresponding Source from a network server at no charge.
272+
273+ c) Convey individual copies of the object code with a copy of the
274+ written offer to provide the Corresponding Source. This
275+ alternative is allowed only occasionally and noncommercially, and
276+ only if you received the object code with such an offer, in accord
277+ with subsection 6b.
278+
279+ d) Convey the object code by offering access from a designated
280+ place (gratis or for a charge), and offer equivalent access to the
281+ Corresponding Source in the same way through the same place at no
282+ further charge. You need not require recipients to copy the
283+ Corresponding Source along with the object code. If the place to
284+ copy the object code is a network server, the Corresponding Source
285+ may be on a different server (operated by you or a third party)
286+ that supports equivalent copying facilities, provided you maintain
287+ clear directions next to the object code saying where to find the
288+ Corresponding Source. Regardless of what server hosts the
289+ Corresponding Source, you remain obligated to ensure that it is
290+ available for as long as needed to satisfy these requirements.
291+
292+ e) Convey the object code using peer-to-peer transmission, provided
293+ you inform other peers where the object code and Corresponding
294+ Source of the work are being offered to the general public at no
295+ charge under subsection 6d.
296+
297+ A separable portion of the object code, whose source code is excluded
298+from the Corresponding Source as a System Library, need not be
299+included in conveying the object code work.
300+
301+ A "User Product" is either (1) a "consumer product", which means any
302+tangible personal property which is normally used for personal, family,
303+or household purposes, or (2) anything designed or sold for incorporation
304+into a dwelling. In determining whether a product is a consumer product,
305+doubtful cases shall be resolved in favor of coverage. For a particular
306+product received by a particular user, "normally used" refers to a
307+typical or common use of that class of product, regardless of the status
308+of the particular user or of the way in which the particular user
309+actually uses, or expects or is expected to use, the product. A product
310+is a consumer product regardless of whether the product has substantial
311+commercial, industrial or non-consumer uses, unless such uses represent
312+the only significant mode of use of the product.
313+
314+ "Installation Information" for a User Product means any methods,
315+procedures, authorization keys, or other information required to install
316+and execute modified versions of a covered work in that User Product from
317+a modified version of its Corresponding Source. The information must
318+suffice to ensure that the continued functioning of the modified object
319+code is in no case prevented or interfered with solely because
320+modification has been made.
321+
322+ If you convey an object code work under this section in, or with, or
323+specifically for use in, a User Product, and the conveying occurs as
324+part of a transaction in which the right of possession and use of the
325+User Product is transferred to the recipient in perpetuity or for a
326+fixed term (regardless of how the transaction is characterized), the
327+Corresponding Source conveyed under this section must be accompanied
328+by the Installation Information. But this requirement does not apply
329+if neither you nor any third party retains the ability to install
330+modified object code on the User Product (for example, the work has
331+been installed in ROM).
332+
333+ The requirement to provide Installation Information does not include a
334+requirement to continue to provide support service, warranty, or updates
335+for a work that has been modified or installed by the recipient, or for
336+the User Product in which it has been modified or installed. Access to a
337+network may be denied when the modification itself materially and
338+adversely affects the operation of the network or violates the rules and
339+protocols for communication across the network.
340+
341+ Corresponding Source conveyed, and Installation Information provided,
342+in accord with this section must be in a format that is publicly
343+documented (and with an implementation available to the public in
344+source code form), and must require no special password or key for
345+unpacking, reading or copying.
346+
347+ 7. Additional Terms.
348+
349+ "Additional permissions" are terms that supplement the terms of this
350+License by making exceptions from one or more of its conditions.
351+Additional permissions that are applicable to the entire Program shall
352+be treated as though they were included in this License, to the extent
353+that they are valid under applicable law. If additional permissions
354+apply only to part of the Program, that part may be used separately
355+under those permissions, but the entire Program remains governed by
356+this License without regard to the additional permissions.
357+
358+ When you convey a copy of a covered work, you may at your option
359+remove any additional permissions from that copy, or from any part of
360+it. (Additional permissions may be written to require their own
361+removal in certain cases when you modify the work.) You may place
362+additional permissions on material, added by you to a covered work,
363+for which you have or can give appropriate copyright permission.
364+
365+ Notwithstanding any other provision of this License, for material you
366+add to a covered work, you may (if authorized by the copyright holders of
367+that material) supplement the terms of this License with terms:
368+
369+ a) Disclaiming warranty or limiting liability differently from the
370+ terms of sections 15 and 16 of this License; or
371+
372+ b) Requiring preservation of specified reasonable legal notices or
373+ author attributions in that material or in the Appropriate Legal
374+ Notices displayed by works containing it; or
375+
376+ c) Prohibiting misrepresentation of the origin of that material, or
377+ requiring that modified versions of such material be marked in
378+ reasonable ways as different from the original version; or
379+
380+ d) Limiting the use for publicity purposes of names of licensors or
381+ authors of the material; or
382+
383+ e) Declining to grant rights under trademark law for use of some
384+ trade names, trademarks, or service marks; or
385+
386+ f) Requiring indemnification of licensors and authors of that
387+ material by anyone who conveys the material (or modified versions of
388+ it) with contractual assumptions of liability to the recipient, for
389+ any liability that these contractual assumptions directly impose on
390+ those licensors and authors.
391+
392+ All other non-permissive additional terms are considered "further
393+restrictions" within the meaning of section 10. If the Program as you
394+received it, or any part of it, contains a notice stating that it is
395+governed by this License along with a term that is a further
396+restriction, you may remove that term. If a license document contains
397+a further restriction but permits relicensing or conveying under this
398+License, you may add to a covered work material governed by the terms
399+of that license document, provided that the further restriction does
400+not survive such relicensing or conveying.
401+
402+ If you add terms to a covered work in accord with this section, you
403+must place, in the relevant source files, a statement of the
404+additional terms that apply to those files, or a notice indicating
405+where to find the applicable terms.
406+
407+ Additional terms, permissive or non-permissive, may be stated in the
408+form of a separately written license, or stated as exceptions;
409+the above requirements apply either way.
410+
411+ 8. Termination.
412+
413+ You may not propagate or modify a covered work except as expressly
414+provided under this License. Any attempt otherwise to propagate or
415+modify it is void, and will automatically terminate your rights under
416+this License (including any patent licenses granted under the third
417+paragraph of section 11).
418+
419+ However, if you cease all violation of this License, then your
420+license from a particular copyright holder is reinstated (a)
421+provisionally, unless and until the copyright holder explicitly and
422+finally terminates your license, and (b) permanently, if the copyright
423+holder fails to notify you of the violation by some reasonable means
424+prior to 60 days after the cessation.
425+
426+ Moreover, your license from a particular copyright holder is
427+reinstated permanently if the copyright holder notifies you of the
428+violation by some reasonable means, this is the first time you have
429+received notice of violation of this License (for any work) from that
430+copyright holder, and you cure the violation prior to 30 days after
431+your receipt of the notice.
432+
433+ Termination of your rights under this section does not terminate the
434+licenses of parties who have received copies or rights from you under
435+this License. If your rights have been terminated and not permanently
436+reinstated, you do not qualify to receive new licenses for the same
437+material under section 10.
438+
439+ 9. Acceptance Not Required for Having Copies.
440+
441+ You are not required to accept this License in order to receive or
442+run a copy of the Program. Ancillary propagation of a covered work
443+occurring solely as a consequence of using peer-to-peer transmission
444+to receive a copy likewise does not require acceptance. However,
445+nothing other than this License grants you permission to propagate or
446+modify any covered work. These actions infringe copyright if you do
447+not accept this License. Therefore, by modifying or propagating a
448+covered work, you indicate your acceptance of this License to do so.
449+
450+ 10. Automatic Licensing of Downstream Recipients.
451+
452+ Each time you convey a covered work, the recipient automatically
453+receives a license from the original licensors, to run, modify and
454+propagate that work, subject to this License. You are not responsible
455+for enforcing compliance by third parties with this License.
456+
457+ An "entity transaction" is a transaction transferring control of an
458+organization, or substantially all assets of one, or subdividing an
459+organization, or merging organizations. If propagation of a covered
460+work results from an entity transaction, each party to that
461+transaction who receives a copy of the work also receives whatever
462+licenses to the work the party's predecessor in interest had or could
463+give under the previous paragraph, plus a right to possession of the
464+Corresponding Source of the work from the predecessor in interest, if
465+the predecessor has it or can get it with reasonable efforts.
466+
467+ You may not impose any further restrictions on the exercise of the
468+rights granted or affirmed under this License. For example, you may
469+not impose a license fee, royalty, or other charge for exercise of
470+rights granted under this License, and you may not initiate litigation
471+(including a cross-claim or counterclaim in a lawsuit) alleging that
472+any patent claim is infringed by making, using, selling, offering for
473+sale, or importing the Program or any portion of it.
474+
475+ 11. Patents.
476+
477+ A "contributor" is a copyright holder who authorizes use under this
478+License of the Program or a work on which the Program is based. The
479+work thus licensed is called the contributor's "contributor version".
480+
481+ A contributor's "essential patent claims" are all patent claims
482+owned or controlled by the contributor, whether already acquired or
483+hereafter acquired, that would be infringed by some manner, permitted
484+by this License, of making, using, or selling its contributor version,
485+but do not include claims that would be infringed only as a
486+consequence of further modification of the contributor version. For
487+purposes of this definition, "control" includes the right to grant
488+patent sublicenses in a manner consistent with the requirements of
489+this License.
490+
491+ Each contributor grants you a non-exclusive, worldwide, royalty-free
492+patent license under the contributor's essential patent claims, to
493+make, use, sell, offer for sale, import and otherwise run, modify and
494+propagate the contents of its contributor version.
495+
496+ In the following three paragraphs, a "patent license" is any express
497+agreement or commitment, however denominated, not to enforce a patent
498+(such as an express permission to practice a patent or covenant not to
499+sue for patent infringement). To "grant" such a patent license to a
500+party means to make such an agreement or commitment not to enforce a
501+patent against the party.
502+
503+ If you convey a covered work, knowingly relying on a patent license,
504+and the Corresponding Source of the work is not available for anyone
505+to copy, free of charge and under the terms of this License, through a
506+publicly available network server or other readily accessible means,
507+then you must either (1) cause the Corresponding Source to be so
508+available, or (2) arrange to deprive yourself of the benefit of the
509+patent license for this particular work, or (3) arrange, in a manner
510+consistent with the requirements of this License, to extend the patent
511+license to downstream recipients. "Knowingly relying" means you have
512+actual knowledge that, but for the patent license, your conveying the
513+covered work in a country, or your recipient's use of the covered work
514+in a country, would infringe one or more identifiable patents in that
515+country that you have reason to believe are valid.
516+
517+ If, pursuant to or in connection with a single transaction or
518+arrangement, you convey, or propagate by procuring conveyance of, a
519+covered work, and grant a patent license to some of the parties
520+receiving the covered work authorizing them to use, propagate, modify
521+or convey a specific copy of the covered work, then the patent license
522+you grant is automatically extended to all recipients of the covered
523+work and works based on it.
524+
525+ A patent license is "discriminatory" if it does not include within
526+the scope of its coverage, prohibits the exercise of, or is
527+conditioned on the non-exercise of one or more of the rights that are
528+specifically granted under this License. You may not convey a covered
529+work if you are a party to an arrangement with a third party that is
530+in the business of distributing software, under which you make payment
531+to the third party based on the extent of your activity of conveying
532+the work, and under which the third party grants, to any of the
533+parties who would receive the covered work from you, a discriminatory
534+patent license (a) in connection with copies of the covered work
535+conveyed by you (or copies made from those copies), or (b) primarily
536+for and in connection with specific products or compilations that
537+contain the covered work, unless you entered into that arrangement,
538+or that patent license was granted, prior to 28 March 2007.
539+
540+ Nothing in this License shall be construed as excluding or limiting
541+any implied license or other defenses to infringement that may
542+otherwise be available to you under applicable patent law.
543+
544+ 12. No Surrender of Others' Freedom.
545+
546+ If conditions are imposed on you (whether by court order, agreement or
547+otherwise) that contradict the conditions of this License, they do not
548+excuse you from the conditions of this License. If you cannot convey a
549+covered work so as to satisfy simultaneously your obligations under this
550+License and any other pertinent obligations, then as a consequence you may
551+not convey it at all. For example, if you agree to terms that obligate you
552+to collect a royalty for further conveying from those to whom you convey
553+the Program, the only way you could satisfy both those terms and this
554+License would be to refrain entirely from conveying the Program.
555+
556+ 13. Use with the GNU Affero General Public License.
557+
558+ Notwithstanding any other provision of this License, you have
559+permission to link or combine any covered work with a work licensed
560+under version 3 of the GNU Affero General Public License into a single
561+combined work, and to convey the resulting work. The terms of this
562+License will continue to apply to the part which is the covered work,
563+but the special requirements of the GNU Affero General Public License,
564+section 13, concerning interaction through a network will apply to the
565+combination as such.
566+
567+ 14. Revised Versions of this License.
568+
569+ The Free Software Foundation may publish revised and/or new versions of
570+the GNU General Public License from time to time. Such new versions will
571+be similar in spirit to the present version, but may differ in detail to
572+address new problems or concerns.
573+
574+ Each version is given a distinguishing version number. If the
575+Program specifies that a certain numbered version of the GNU General
576+Public License "or any later version" applies to it, you have the
577+option of following the terms and conditions either of that numbered
578+version or of any later version published by the Free Software
579+Foundation. If the Program does not specify a version number of the
580+GNU General Public License, you may choose any version ever published
581+by the Free Software Foundation.
582+
583+ If the Program specifies that a proxy can decide which future
584+versions of the GNU General Public License can be used, that proxy's
585+public statement of acceptance of a version permanently authorizes you
586+to choose that version for the Program.
587+
588+ Later license versions may give you additional or different
589+permissions. However, no additional obligations are imposed on any
590+author or copyright holder as a result of your choosing to follow a
591+later version.
592+
593+ 15. Disclaimer of Warranty.
594+
595+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
596+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
597+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
598+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
599+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
600+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
601+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
602+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
603+
604+ 16. Limitation of Liability.
605+
606+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
607+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
608+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
609+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
610+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
611+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
612+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
613+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
614+SUCH DAMAGES.
615+
616+ 17. Interpretation of Sections 15 and 16.
617+
618+ If the disclaimer of warranty and limitation of liability provided
619+above cannot be given local legal effect according to their terms,
620+reviewing courts shall apply local law that most closely approximates
621+an absolute waiver of all civil liability in connection with the
622+Program, unless a warranty or assumption of liability accompanies a
623+copy of the Program in return for a fee.
624+
625+ END OF TERMS AND CONDITIONS
626+
627+ How to Apply These Terms to Your New Programs
628+
629+ If you develop a new program, and you want it to be of the greatest
630+possible use to the public, the best way to achieve this is to make it
631+free software which everyone can redistribute and change under these terms.
632+
633+ To do so, attach the following notices to the program. It is safest
634+to attach them to the start of each source file to most effectively
635+state the exclusion of warranty; and each file should have at least
636+the "copyright" line and a pointer to where the full notice is found.
637+
638+ <one line to give the program's name and a brief idea of what it does.>
639+ Copyright (C) <year> <name of author>
640+
641+ This program is free software: you can redistribute it and/or modify
642+ it under the terms of the GNU General Public License as published by
643+ the Free Software Foundation, either version 3 of the License, or
644+ (at your option) any later version.
645+
646+ This program is distributed in the hope that it will be useful,
647+ but WITHOUT ANY WARRANTY; without even the implied warranty of
648+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
649+ GNU General Public License for more details.
650+
651+ You should have received a copy of the GNU General Public License
652+ along with this program. If not, see <http://www.gnu.org/licenses/>.
653+
654+Also add information on how to contact you by electronic and paper mail.
655+
656+ If the program does terminal interaction, make it output a short
657+notice like this when it starts in an interactive mode:
658+
659+ <program> Copyright (C) <year> <name of author>
660+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
661+ This is free software, and you are welcome to redistribute it
662+ under certain conditions; type `show c' for details.
663+
664+The hypothetical commands `show w' and `show c' should show the appropriate
665+parts of the General Public License. Of course, your program's commands
666+might be different; for a GUI interface, you would use an "about box".
667+
668+ You should also get your employer (if you work as a programmer) or school,
669+if any, to sign a "copyright disclaimer" for the program, if necessary.
670+For more information on this, and how to apply and follow the GNU GPL, see
671+<http://www.gnu.org/licenses/>.
672+
673+ The GNU General Public License does not permit incorporating your program
674+into proprietary programs. If your program is a subroutine library, you
675+may consider it more useful to permit linking proprietary applications with
676+the library. If this is what you want to do, use the GNU Lesser General
677+Public License instead of this License. But first, please read
678+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
679
680=== modified file 'Makefile.am'
681--- Makefile.am 2012-08-29 11:27:54 +0000
682+++ Makefile.am 2013-04-26 16:57:25 +0000
683@@ -1,5 +1,6 @@
684
685 SUBDIRS = \
686+ common \
687 src \
688 libmessaging-menu \
689 data \
690
691=== added directory 'common'
692=== added file 'common/Makefile.am'
693--- common/Makefile.am 1970-01-01 00:00:00 +0000
694+++ common/Makefile.am 2013-04-26 16:57:25 +0000
695@@ -0,0 +1,32 @@
696+
697+noinst_LTLIBRARIES = libmessaging-common.la
698+
699+indicator-messages-service.c: com.canonical.indicator.messages.service.xml
700+ $(AM_V_GEN) gdbus-codegen \
701+ --interface-prefix com.canonical.indicator.messages. \
702+ --generate-c-code indicator-messages-service \
703+ --c-namespace IndicatorMessages \
704+ $^
705+indicator-messages-service.h: indicator-messages-service.c
706+
707+indicator-messages-application.c: com.canonical.indicator.messages.application.xml
708+ $(AM_V_GEN) gdbus-codegen \
709+ --interface-prefix com.canonical.indicator.messages. \
710+ --generate-c-code indicator-messages-application \
711+ --c-namespace IndicatorMessages \
712+ $^
713+indicator-messages-application.h: indicator-messages-application.c
714+
715+BUILT_SOURCES = \
716+ indicator-messages-service.c \
717+ indicator-messages-service.h \
718+ indicator-messages-application.c \
719+ indicator-messages-application.h
720+
721+libmessaging_common_la_SOURCES = \
722+ $(BUILT_SOURCES)
723+
724+libmessaging_common_la_CFLAGS = $(GIO_CFLAGS)
725+libmessaging_common_la_LIBADD = $(GIO_LIBS)
726+
727+CLEANFILES = $(BUILT_SOURCES)
728
729=== added file 'common/com.canonical.indicator.messages.application.xml'
730--- common/com.canonical.indicator.messages.application.xml 1970-01-01 00:00:00 +0000
731+++ common/com.canonical.indicator.messages.application.xml 2013-04-26 16:57:25 +0000
732@@ -0,0 +1,39 @@
733+<?xml version="1.0" encoding="UTF-8"?>
734+<node name="/">
735+ <interface name="com.canonical.indicator.messages.application">
736+ <method name="ListSources">
737+ <arg type="a(sssuxsb)" name="sources" direction="out" />
738+ </method>
739+ <method name="ListMessages">
740+ <arg type="a(sssssxaa{sv}b)" name="message" direction="out" />
741+ </method>
742+ <method name="ActivateSource">
743+ <arg type="s" name="source_id" direction="in" />
744+ </method>
745+ <method name="ActivateMessage">
746+ <arg type="s" name="message_id" direction="in" />
747+ <arg type="s" name="action_id" direction="in" />
748+ <arg type="av" name="parameter" direction="in" />
749+ </method>
750+ <method name="Dismiss">
751+ <arg type="as" name="sources" direction="in" />
752+ <arg type="as" name="messages" direction="in" />
753+ </method>
754+ <signal name="SourceAdded">
755+ <arg type="u" name="position" direction="in" />
756+ <arg type="(sssuxsb)" name="source" direction="in" />
757+ </signal>
758+ <signal name="SourceChanged">
759+ <arg type="(sssuxsb)" name="source" direction="in" />
760+ </signal>
761+ <signal name="SourceRemoved">
762+ <arg type="s" name="source_id" direction="in" />
763+ </signal>
764+ <signal name="MessageAdded">
765+ <arg type="(sssssxaa{sv}b)" name="message" direction="in" />
766+ </signal>
767+ <signal name="MessageRemoved">
768+ <arg type="s" name="message_id" direction="in" />
769+ </signal>
770+ </interface>
771+</node>
772
773=== renamed file 'src/messages-service.xml' => 'common/com.canonical.indicator.messages.service.xml'
774=== modified file 'configure.ac'
775--- configure.ac 2013-01-22 20:30:05 +0000
776+++ configure.ac 2013-04-26 16:57:25 +0000
777@@ -156,6 +156,7 @@
778 AC_OUTPUT([
779 Makefile
780 src/Makefile
781+common/Makefile
782 data/Makefile
783 data/icons/Makefile
784 data/icons/16x16/Makefile
785
786=== modified file 'debian/changelog'
787--- debian/changelog 2013-02-13 02:02:12 +0000
788+++ debian/changelog 2013-04-26 16:57:25 +0000
789@@ -1,3 +1,4 @@
790+<<<<<<< TREE
791 indicator-messages (12.10.6daily13.02.13-0ubuntu1) raring; urgency=low
792
793 [ Jason Conti ]
794@@ -33,6 +34,88 @@
795 indicator-messages (12.10.6daily12.11.21.1-0ubuntu1) raring; urgency=low
796
797 [ Mathieu Trudel-Lapierre ]
798+=======
799+indicator-messages (13.10.0phablet1) raring; urgency=low
800+
801+ * Version bump to not pull from archives
802+
803+ -- Sergio Schvezov <sergio.schvezov@canonical.com> Fri, 26 Apr 2013 13:53:53 -0300
804+
805+indicator-messages (12.10.6phablet1) quantal; urgency=low
806+
807+ * Adding guards for g_type_init
808+
809+ -- Sergio Schvezov <sergio.schvezov@canonical.com> Fri, 22 Mar 2013 17:23:45 -0300
810+
811+indicator-messages (12.10.6-0ubuntu1phablet9) quantal; urgency=low
812+
813+ * add "remove-all" signal to imapplicationlist (temporarily)
814+
815+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 20 Dec 2012 18:49:50 +0100
816+
817+indicator-messages (12.10.6-0ubuntu1phablet8) quantal; urgency=low
818+
819+ * Make messaging_menu_app_remove_message() work for messages with a ref count of 1
820+ * Make handling of multiple processes with the same desktop id more robust
821+ * ImPhoneMenu: sort messages by time (fixes LP #1090266)
822+ * Don't show message sources
823+
824+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 17 Dec 2012 14:42:03 +0100
825+
826+indicator-messages (12.10.6-0ubuntu1phablet7) quantal; urgency=low
827+
828+ * Remove variant wrapper from 'parameter' argument of the "activate" signal
829+
830+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Tue, 11 Dec 2012 14:28:15 +0100
831+
832+indicator-messages (12.10.6-0ubuntu1phablet6) quantal; urgency=low
833+
834+ * Don't show sources
835+ * Always use the "messageitem" widget type for messages
836+
837+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 10 Dec 2012 14:38:16 +0100
838+
839+indicator-messages (12.10.6-0ubuntu1phablet5) quantal; urgency=low
840+
841+ * Don't shorten the app id to seven characters (fixes LP #1086729)
842+ * Add messaging_menu_app_get_message
843+
844+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 06 Dec 2012 15:06:34 +0000
845+
846+indicator-messages (12.10.6-0ubuntu1phablet4) quantal; urgency=low
847+
848+ [Lars Uebernickel]
849+ * Add the concept of actions to messages
850+ * Stop using IndicatorService
851+ * Reverse order of messages
852+ * Expose symbolic application icon
853+ * Change icon when there are any messages in the menu
854+
855+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Tue, 04 Dec 2012 21:10:26 +0000
856+
857+indicator-messages (12.10.6-0ubuntu1phablet3) quantal; urgency=low
858+
859+ [Lars Uebernickel]
860+ * expose root menu item of which the indicator menu is a submenu
861+ * fix crash in im-application-list on arm
862+
863+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 29 Nov 2012 21:44:19 +0100
864+
865+indicator-messages (12.10.6-0ubuntu1phablet2) quantal; urgency=low
866+
867+ [Lars Uebernickel]
868+ * refactor messages-service.c
869+ * notify applications about message and source activations
870+ * add "Clear All" menu item
871+ * allow dismissing of messages
872+ * include application icons on message items
873+
874+ -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 26 Nov 2012 22:19:51 +0100
875+
876+indicator-messages (12.10.6-0ubuntu1phablet1) quantal; urgency=low
877+
878+ [ Mathieu Trudel-Lapierre ]
879+>>>>>>> MERGE-SOURCE
880 * debian/rules:
881 - Use autogen.sh for dh_autoreconf.
882 - Drop the override for dh_makeshlibs.
883@@ -45,10 +128,17 @@
884 - Clear the detail (count or time) of a source when another type of detail
885 is set. (LP: #1071640)
886
887+<<<<<<< TREE
888 [ Automatic PS uploader ]
889 * Automatic snapshot from revision 331
890
891 -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Wed, 21 Nov 2012 10:41:37 +0000
892+=======
893+ [ Ricardo Mendoza ]
894+ * Releasing upstream for phablet
895+
896+ -- Ricardo Mendoza <ricardo.mendoza@canonical.com> Tue, 20 Nov 2012 10:08:59 -0430
897+>>>>>>> MERGE-SOURCE
898
899 indicator-messages (12.10.5-0ubuntu2) raring; urgency=low
900
901
902=== modified file 'debian/libmessaging-menu0.symbols'
903--- debian/libmessaging-menu0.symbols 2012-09-01 10:35:36 +0000
904+++ debian/libmessaging-menu0.symbols 2013-04-26 16:57:25 +0000
905@@ -1,9 +1,11 @@
906 libmessaging-menu.so.0 libmessaging-menu0 #MINVER#
907+ messaging_menu_app_append_message@Base 12.10.6-0ubuntu1phablet1
908 messaging_menu_app_append_source@Base 12.10.0
909 messaging_menu_app_append_source_with_count@Base 12.10.0
910 messaging_menu_app_append_source_with_string@Base 12.10.0
911 messaging_menu_app_append_source_with_time@Base 12.10.0
912 messaging_menu_app_draw_attention@Base 12.10.0
913+ messaging_menu_app_get_message@Base 0replaceme
914 messaging_menu_app_get_type@Base 12.10.0
915 messaging_menu_app_has_source@Base 12.10.0
916 messaging_menu_app_insert_source@Base 12.10.0
917@@ -13,6 +15,8 @@
918 messaging_menu_app_new@Base 12.10.0
919 messaging_menu_app_register@Base 12.10.0
920 messaging_menu_app_remove_attention@Base 12.10.0
921+ messaging_menu_app_remove_message@Base 12.10.6-0ubuntu1phablet1
922+ messaging_menu_app_remove_message_by_id@Base 12.10.6-0ubuntu1phablet1
923 messaging_menu_app_remove_source@Base 12.10.0
924 messaging_menu_app_set_source_count@Base 12.10.0
925 messaging_menu_app_set_source_icon@Base 12.10.2
926@@ -21,3 +25,14 @@
927 messaging_menu_app_set_source_time@Base 12.10.0
928 messaging_menu_app_set_status@Base 12.10.0
929 messaging_menu_app_unregister@Base 12.10.0
930+ messaging_menu_message_add_action@Base 12.10.6-0ubuntu1phablet3
931+ messaging_menu_message_get_body@Base 12.10.6-0ubuntu1phablet1
932+ messaging_menu_message_get_draws_attention@Base 12.10.6-0ubuntu1phablet1
933+ messaging_menu_message_get_icon@Base 12.10.6-0ubuntu1phablet1
934+ messaging_menu_message_get_id@Base 12.10.6-0ubuntu1phablet1
935+ messaging_menu_message_get_subtitle@Base 12.10.6-0ubuntu1phablet1
936+ messaging_menu_message_get_time@Base 12.10.6-0ubuntu1phablet1
937+ messaging_menu_message_get_title@Base 12.10.6-0ubuntu1phablet1
938+ messaging_menu_message_get_type@Base 12.10.6-0ubuntu1phablet1
939+ messaging_menu_message_new@Base 12.10.6-0ubuntu1phablet1
940+ messaging_menu_message_set_draws_attention@Base 12.10.6-0ubuntu1phablet1
941
942=== added directory 'debian/source'
943=== added file 'debian/source/format'
944--- debian/source/format 1970-01-01 00:00:00 +0000
945+++ debian/source/format 2013-04-26 16:57:25 +0000
946@@ -0,0 +1,1 @@
947+1.0
948
949=== modified file 'doc/reference/Makefile.am'
950--- doc/reference/Makefile.am 2013-01-22 20:23:57 +0000
951+++ doc/reference/Makefile.am 2013-04-26 16:57:25 +0000
952@@ -11,8 +11,7 @@
953 CFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.c
954
955 IGNORE_HFILES= \
956- indicator-messages-service.h \
957- gtupleaction.h
958+ indicator-messages-service.h
959
960 INCLUDES=-I$(top_srcdir)/libmessaging-menu $(GIO_CFLAGS)
961 GTKDOC_LIBS=$(top_builddir)/libmessaging-menu/libmessaging-menu.la
962
963=== modified file 'doc/reference/messaging-menu-docs.xml.in'
964--- doc/reference/messaging-menu-docs.xml.in 2012-08-29 11:27:54 +0000
965+++ doc/reference/messaging-menu-docs.xml.in 2013-04-26 16:57:25 +0000
966@@ -18,7 +18,8 @@
967
968 <chapter>
969 <title>API Reference</title>
970- <xi:include href="xml/messaging-menu.xml"/>
971+ <xi:include href="xml/messaging-menu-app.xml" />
972+ <xi:include href="xml/messaging-menu-message.xml" />
973 </chapter>
974
975 <chapter id="object-tree">
976
977=== modified file 'libmessaging-menu/Makefile.am'
978--- libmessaging-menu/Makefile.am 2012-09-01 08:27:34 +0000
979+++ libmessaging-menu/Makefile.am 2013-04-26 16:57:25 +0000
980@@ -4,36 +4,25 @@
981 libmessaging_menu_ladir = $(includedir)/messaging-menu
982
983 libmessaging_menu_la_SOURCES = \
984- messaging-menu.c \
985- gtupleaction.c \
986- gtupleaction.h \
987- $(BUILT_SOURCES)
988+ messaging-menu-app.c \
989+ messaging-menu-message.c
990
991 libmessaging_menu_la_HEADERS = \
992- messaging-menu.h
993+ messaging-menu-app.h \
994+ messaging-menu.h \
995+ messaging-menu-message.h
996
997-libmessaging_menu_la_LIBADD = $(GIO_LIBS)
998+libmessaging_menu_la_LIBADD = \
999+ $(GIO_LIBS) \
1000+ $(top_builddir)/common/libmessaging-common.la
1001
1002 libmessaging_menu_la_CFLAGS = \
1003+ -I$(top_builddir)/common \
1004 $(GIO_CFLAGS) \
1005 -Wall
1006
1007 libmessaging_menu_la_LDFLAGS = -export-symbols-regex "^messaging_menu_.*"
1008
1009-BUILT_SOURCES = \
1010- indicator-messages-service.c \
1011- indicator-messages-service.h
1012-
1013-CLEANFILES = $(BUILT_SOURCES)
1014-
1015-indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
1016- $(AM_V_GEN) gdbus-codegen \
1017- --interface-prefix com.canonical.indicator.messages. \
1018- --generate-c-code indicator-messages-service \
1019- --c-namespace IndicatorMessages \
1020- $^
1021-indicator-messages-service.h: indicator-messages-service.c
1022-
1023 pkgconfigdir = $(libdir)/pkgconfig
1024 pkgconfig_DATA = messaging-menu.pc
1025
1026@@ -52,7 +41,11 @@
1027 MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS)
1028 MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h"
1029 MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la
1030-MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h
1031+MessagingMenu_1_0_gir_FILES = \
1032+ messaging-menu-app.c \
1033+ messaging-menu-app.h \
1034+ messaging-menu-message.c \
1035+ messaging-menu-message.h
1036 MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu
1037 INTROSPECTION_GIRS += MessagingMenu-1.0.gir
1038
1039@@ -62,5 +55,5 @@
1040 typelibdir = $(libdir)/girepository-1.0
1041 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
1042
1043-CLEANFILES +=$(gir_DATA) $(typelib_DATA)
1044+CLEANFILES = $(gir_DATA) $(typelib_DATA)
1045 endif
1046
1047=== removed file 'libmessaging-menu/gtupleaction.c'
1048--- libmessaging-menu/gtupleaction.c 2012-08-20 21:09:54 +0000
1049+++ libmessaging-menu/gtupleaction.c 1970-01-01 00:00:00 +0000
1050@@ -1,354 +0,0 @@
1051-/*
1052- * Copyright 2012 Canonical Ltd.
1053- *
1054- * This program is free software: you can redistribute it and/or modify it
1055- * under the terms of the GNU General Public License version 3, as
1056- * published by the Free Software Foundation.
1057- *
1058- * This program is distributed in the hope that it will be useful, but
1059- * WITHOUT ANY WARRANTY; without even the implied warranties of
1060- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1061- * PURPOSE. See the GNU General Public License for more details.
1062- *
1063- * You should have received a copy of the GNU General Public License along
1064- * with this program. If not, see <http://www.gnu.org/licenses/>.
1065- *
1066- * Authors:
1067- * Lars Uebernickel <lars.uebernickel@canonical.com>
1068- */
1069-
1070-#include "gtupleaction.h"
1071-
1072-typedef GObjectClass GTupleActionClass;
1073-
1074-struct _GTupleAction
1075-{
1076- GObject parent;
1077-
1078- gchar *name;
1079- GVariantType *type;
1080- gboolean enabled;
1081-
1082- gsize n_children;
1083- GVariant **children;
1084-};
1085-
1086-static void action_interface_init (GActionInterface *iface);
1087-
1088-G_DEFINE_TYPE_WITH_CODE (GTupleAction, g_tuple_action, G_TYPE_OBJECT,
1089- G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_interface_init));
1090-
1091-enum
1092-{
1093- PROP_0,
1094- PROP_NAME,
1095- PROP_PARAMETER_TYPE,
1096- PROP_ENABLED,
1097- PROP_STATE_TYPE,
1098- PROP_STATE,
1099- N_PROPERTIES
1100-};
1101-
1102-enum
1103-{
1104- SIGNAL_ACTIVATE,
1105- N_SIGNALS
1106-};
1107-
1108-static GParamSpec *properties[N_PROPERTIES];
1109-static guint signal_ids[N_SIGNALS];
1110-
1111-static const gchar *
1112-g_tuple_action_get_name (GAction *action)
1113-{
1114- GTupleAction *tuple = G_TUPLE_ACTION (action);
1115-
1116- return tuple->name;
1117-}
1118-
1119-static const GVariantType *
1120-g_tuple_action_get_parameter_type (GAction *action)
1121-{
1122- return NULL;
1123-}
1124-
1125-static const GVariantType *
1126-g_tuple_action_get_state_type (GAction *action)
1127-{
1128- GTupleAction *tuple = G_TUPLE_ACTION (action);
1129-
1130- return tuple->type;
1131-}
1132-
1133-static GVariant *
1134-g_tuple_action_get_state_hint (GAction *action)
1135-{
1136- return NULL;
1137-}
1138-
1139-static gboolean
1140-g_tuple_action_get_enabled (GAction *action)
1141-{
1142- GTupleAction *tuple = G_TUPLE_ACTION (action);
1143-
1144- return tuple->enabled;
1145-}
1146-
1147-static GVariant *
1148-g_tuple_action_get_state (GAction *action)
1149-{
1150- GTupleAction *tuple = G_TUPLE_ACTION (action);
1151- GVariant *result;
1152-
1153- result = g_variant_new_tuple (tuple->children, tuple->n_children);
1154- return g_variant_ref_sink (result);
1155-}
1156-
1157-static void
1158-g_tuple_action_set_state (GTupleAction *tuple,
1159- GVariant *state)
1160-{
1161- int i;
1162-
1163- g_return_if_fail (g_variant_type_is_tuple (g_variant_get_type (state)));
1164-
1165- if (tuple->type == NULL)
1166- {
1167- tuple->type = g_variant_type_copy (g_variant_get_type (state));
1168- tuple->n_children = g_variant_n_children (state);
1169- tuple->children = g_new0 (GVariant *, tuple->n_children);
1170- }
1171-
1172- for (i = 0; i < tuple->n_children; i++)
1173- {
1174- if (tuple->children[i])
1175- g_variant_unref (tuple->children[i]);
1176- tuple->children[i] = g_variant_get_child_value (state, i);
1177- }
1178-
1179- g_object_notify_by_pspec (G_OBJECT (tuple), properties[PROP_STATE]);
1180-}
1181-
1182-static void
1183-g_tuple_action_change_state (GAction *action,
1184- GVariant *value)
1185-{
1186- GTupleAction *tuple = G_TUPLE_ACTION (action);
1187-
1188- g_return_if_fail (value != NULL);
1189- g_return_if_fail (g_variant_is_of_type (value, tuple->type));
1190-
1191- g_variant_ref_sink (value);
1192-
1193- /* TODO add a change-state signal similar to GSimpleAction */
1194- g_tuple_action_set_state (tuple, value);
1195-
1196- g_variant_unref (value);
1197-}
1198-
1199-static void
1200-g_tuple_action_activate (GAction *action,
1201- GVariant *parameter)
1202-{
1203- GTupleAction *tuple = G_TUPLE_ACTION (action);
1204-
1205- g_return_if_fail (parameter == NULL);
1206-
1207- if (tuple->enabled)
1208- g_signal_emit (tuple, signal_ids[SIGNAL_ACTIVATE], 0, NULL);
1209-}
1210-
1211-static void
1212-g_tuple_action_get_property (GObject *object,
1213- guint prop_id,
1214- GValue *value,
1215- GParamSpec *pspec)
1216-{
1217- GAction *action = G_ACTION (object);
1218-
1219- switch (prop_id)
1220- {
1221- case PROP_NAME:
1222- g_value_set_string (value, g_tuple_action_get_name (action));
1223- break;
1224-
1225- case PROP_PARAMETER_TYPE:
1226- g_value_set_boxed (value, g_tuple_action_get_parameter_type (action));
1227- break;
1228-
1229- case PROP_ENABLED:
1230- g_value_set_boolean (value, g_tuple_action_get_enabled (action));
1231- break;
1232-
1233- case PROP_STATE_TYPE:
1234- g_value_set_boxed (value, g_tuple_action_get_state_type (action));
1235- break;
1236-
1237- case PROP_STATE:
1238- g_value_take_variant (value, g_tuple_action_get_state (action));
1239- break;
1240-
1241- default:
1242- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1243- }
1244-}
1245-
1246-static void
1247-g_tuple_action_set_property (GObject *object,
1248- guint prop_id,
1249- const GValue *value,
1250- GParamSpec *pspec)
1251-{
1252- GTupleAction *tuple = G_TUPLE_ACTION (object);
1253-
1254- switch (prop_id)
1255- {
1256- case PROP_NAME:
1257- tuple->name = g_value_dup_string (value);
1258- g_object_notify_by_pspec (object, properties[PROP_NAME]);
1259- break;
1260-
1261- case PROP_ENABLED:
1262- tuple->enabled = g_value_get_boolean (value);
1263- g_object_notify_by_pspec (object, properties[PROP_ENABLED]);
1264- break;
1265-
1266- case PROP_STATE:
1267- g_tuple_action_set_state (tuple, g_value_get_variant (value));
1268- break;
1269-
1270- default:
1271- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1272- }
1273-}
1274-
1275-static void
1276-g_tuple_action_finalize (GObject *object)
1277-{
1278- GTupleAction *tuple = G_TUPLE_ACTION (object);
1279- int i;
1280-
1281- g_free (tuple->name);
1282- g_variant_type_free (tuple->type);
1283-
1284- for (i = 0; i < tuple->n_children; i++)
1285- g_variant_unref (tuple->children[i]);
1286-
1287- g_free (tuple->children);
1288-
1289- G_OBJECT_CLASS (g_tuple_action_parent_class)->finalize (object);
1290-}
1291-
1292-static void
1293-action_interface_init (GActionInterface *iface)
1294-{
1295- iface->get_name = g_tuple_action_get_name;
1296- iface->get_parameter_type = g_tuple_action_get_parameter_type;
1297- iface->get_state_type = g_tuple_action_get_state_type;
1298- iface->get_state_hint = g_tuple_action_get_state_hint;
1299- iface->get_enabled = g_tuple_action_get_enabled;
1300- iface->get_state = g_tuple_action_get_state;
1301- iface->change_state = g_tuple_action_change_state;
1302- iface->activate = g_tuple_action_activate;
1303-}
1304-
1305-static void
1306-g_tuple_action_class_init (GTupleActionClass *class)
1307-{
1308- GObjectClass *object_class = G_OBJECT_CLASS (class);
1309-
1310- object_class->get_property = g_tuple_action_get_property;
1311- object_class->set_property = g_tuple_action_set_property;
1312- object_class->finalize = g_tuple_action_finalize;
1313-
1314- properties[PROP_NAME] = g_param_spec_string ("name",
1315- "Name",
1316- "The name of the action",
1317- NULL,
1318- G_PARAM_READWRITE |
1319- G_PARAM_CONSTRUCT_ONLY |
1320- G_PARAM_STATIC_STRINGS);
1321-
1322- properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type",
1323- "Parameter Type",
1324- "The variant type passed to activate",
1325- G_TYPE_VARIANT_TYPE,
1326- G_PARAM_READABLE |
1327- G_PARAM_STATIC_STRINGS);
1328-
1329- properties[PROP_ENABLED] = g_param_spec_boolean ("enabled",
1330- "Enabled",
1331- "Whether the action can be activated",
1332- TRUE,
1333- G_PARAM_READWRITE |
1334- G_PARAM_STATIC_STRINGS);
1335-
1336- properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type",
1337- "State Type",
1338- "The variant type of the state, must be a tuple",
1339- G_TYPE_VARIANT_TYPE,
1340- G_PARAM_READABLE |
1341- G_PARAM_STATIC_STRINGS);
1342-
1343- properties[PROP_STATE] = g_param_spec_variant ("state",
1344- "State",
1345- "The state of the action",
1346- G_VARIANT_TYPE_TUPLE,
1347- NULL,
1348- G_PARAM_READWRITE |
1349- G_PARAM_STATIC_STRINGS);
1350-
1351- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
1352-
1353- signal_ids[SIGNAL_ACTIVATE] = g_signal_new ("activate",
1354- G_TYPE_TUPLE_ACTION,
1355- G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
1356- 0, NULL, NULL,
1357- g_cclosure_marshal_VOID__VARIANT,
1358- G_TYPE_NONE, 1,
1359- G_TYPE_VARIANT);
1360-}
1361-
1362-static void
1363-g_tuple_action_init (GTupleAction *action)
1364-{
1365- action->enabled = TRUE;
1366-}
1367-
1368-GTupleAction *
1369-g_tuple_action_new (const gchar *name,
1370- GVariant *initial_state)
1371-{
1372- const GVariantType *type;
1373-
1374- g_return_val_if_fail (name != NULL, NULL);
1375- g_return_val_if_fail (initial_state != NULL, NULL);
1376-
1377- type = g_variant_get_type (initial_state);
1378- g_return_val_if_fail (g_variant_type_is_tuple (type), NULL);
1379-
1380- return g_object_new (G_TYPE_TUPLE_ACTION,
1381- "name", name,
1382- "state", initial_state,
1383- NULL);
1384-}
1385-
1386-void
1387-g_tuple_action_set_child (GTupleAction *action,
1388- gsize index,
1389- GVariant *value)
1390-{
1391- const GVariantType *type;
1392-
1393- g_return_if_fail (G_IS_TUPLE_ACTION (action));
1394- g_return_if_fail (index < action->n_children);
1395- g_return_if_fail (value != NULL);
1396-
1397- type = g_variant_get_type (value);
1398- g_return_if_fail (g_variant_is_of_type (value, type));
1399-
1400- g_variant_unref (action->children[index]);
1401- action->children[index] = g_variant_ref_sink (value);
1402-
1403- g_object_notify_by_pspec (G_OBJECT (action), properties[PROP_STATE]);
1404-}
1405
1406=== removed file 'libmessaging-menu/gtupleaction.h'
1407--- libmessaging-menu/gtupleaction.h 2012-06-28 14:07:17 +0000
1408+++ libmessaging-menu/gtupleaction.h 1970-01-01 00:00:00 +0000
1409@@ -1,40 +0,0 @@
1410-/*
1411- * Copyright 2012 Canonical Ltd.
1412- *
1413- * This program is free software: you can redistribute it and/or modify it
1414- * under the terms of the GNU General Public License version 3, as
1415- * published by the Free Software Foundation.
1416- *
1417- * This program is distributed in the hope that it will be useful, but
1418- * WITHOUT ANY WARRANTY; without even the implied warranties of
1419- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1420- * PURPOSE. See the GNU General Public License for more details.
1421- *
1422- * You should have received a copy of the GNU General Public License along
1423- * with this program. If not, see <http://www.gnu.org/licenses/>.
1424- *
1425- * Authors:
1426- * Lars Uebernickel <lars.uebernickel@canonical.com>
1427- */
1428-
1429-#ifndef __g_tuple_action_h__
1430-#define __g_tuple_action_h__
1431-
1432-#include <gio/gio.h>
1433-
1434-#define G_TYPE_TUPLE_ACTION (g_tuple_action_get_type ())
1435-#define G_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TUPLE_ACTION, GTupleAction))
1436-#define G_IS_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TUPLE_ACTION))
1437-
1438-typedef struct _GTupleAction GTupleAction;
1439-
1440-GType g_tuple_action_get_type (void) G_GNUC_CONST;
1441-
1442-GTupleAction * g_tuple_action_new (const gchar *name,
1443- GVariant *initial_state);
1444-
1445-void g_tuple_action_set_child (GTupleAction *action,
1446- gsize index,
1447- GVariant *value);
1448-
1449-#endif
1450
1451=== renamed file 'libmessaging-menu/messaging-menu.c' => 'libmessaging-menu/messaging-menu-app.c'
1452--- libmessaging-menu/messaging-menu.c 2013-02-12 19:41:16 +0000
1453+++ libmessaging-menu/messaging-menu-app.c 2013-04-26 16:57:25 +0000
1454@@ -17,10 +17,12 @@
1455 * Lars Uebernickel <lars.uebernickel@canonical.com>
1456 */
1457
1458-#include "messaging-menu.h"
1459+#include "messaging-menu-app.h"
1460 #include "indicator-messages-service.h"
1461+#include "indicator-messages-application.h"
1462
1463 #include <gio/gdesktopappinfo.h>
1464+#include <string.h>
1465
1466 /**
1467 * SECTION:messaging-menu
1468@@ -102,14 +104,14 @@
1469 int registered; /* -1 for unknown */
1470 MessagingMenuStatus status;
1471 gboolean status_set;
1472- GSimpleActionGroup *source_actions;
1473- GMenu *menu;
1474 GDBusConnection *bus;
1475
1476+ GHashTable *messages;
1477+ GList *sources;
1478+ IndicatorMessagesApplication *app_interface;
1479+
1480 IndicatorMessagesService *messages_service;
1481 guint watch_id;
1482- guint action_export_id;
1483- guint menu_export_id;
1484
1485 GCancellable *cancellable;
1486 };
1487@@ -133,10 +135,61 @@
1488
1489 static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };
1490
1491+typedef struct
1492+{
1493+ gchar *id;
1494+ GIcon *icon;
1495+ gchar *label;
1496+
1497+ guint32 count;
1498+ gint64 time;
1499+ gchar *string;
1500+ gboolean draws_attention;
1501+} Source;
1502+
1503 static void global_status_changed (IndicatorMessagesService *service,
1504 const gchar *status_str,
1505 gpointer user_data);
1506
1507+/* in messaging-menu-message.c */
1508+GVariant * _messaging_menu_message_to_variant (MessagingMenuMessage *msg);
1509+
1510+static void
1511+source_free (gpointer data)
1512+{
1513+ Source *source = data;
1514+
1515+ if (source)
1516+ {
1517+ g_free (source->id);
1518+ g_clear_object (&source->icon);
1519+ g_free (source->label);
1520+ g_free (source->string);
1521+ g_slice_free (Source, source);
1522+ }
1523+}
1524+
1525+static GVariant *
1526+source_to_variant (Source *source)
1527+{
1528+ GVariant *v;
1529+ gchar *iconstr;
1530+
1531+ iconstr = source->icon ? g_icon_to_string (source->icon) : NULL;
1532+
1533+ v = g_variant_new ("(sssuxsb)", source->id,
1534+ source->label,
1535+ iconstr ? iconstr : "",
1536+ source->count,
1537+ source->time,
1538+ source->string ? source->string : "",
1539+ source->draws_attention);
1540+
1541+ g_free (iconstr);
1542+
1543+ return v;
1544+}
1545+
1546 static gchar *
1547 messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app)
1548 {
1549@@ -155,18 +208,14 @@
1550 }
1551
1552 static void
1553-export_menus_and_actions (GObject *source,
1554- GAsyncResult *res,
1555- gpointer user_data)
1556+messaging_menu_app_got_bus (GObject *source,
1557+ GAsyncResult *res,
1558+ gpointer user_data)
1559 {
1560 MessagingMenuApp *app = user_data;
1561 GError *error = NULL;
1562 gchar *object_path;
1563
1564- object_path = messaging_menu_app_get_dbus_object_path (app);
1565- if (!object_path)
1566- return;
1567-
1568 app->bus = g_bus_get_finish (res, &error);
1569 if (app->bus == NULL)
1570 {
1571@@ -175,23 +224,13 @@
1572 return;
1573 }
1574
1575- app->action_export_id = g_dbus_connection_export_action_group (app->bus,
1576- object_path,
1577- G_ACTION_GROUP (app->source_actions),
1578- &error);
1579- if (!app->action_export_id)
1580- {
1581- g_warning ("unable to export action group: %s", error->message);
1582- g_clear_error (&error);
1583- }
1584+ object_path = messaging_menu_app_get_dbus_object_path (app);
1585
1586- app->menu_export_id = g_dbus_connection_export_menu_model (app->bus,
1587- object_path,
1588- G_MENU_MODEL (app->menu),
1589- &error);
1590- if (!app->menu_export_id)
1591+ if (object_path &&
1592+ !g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (app->app_interface),
1593+ app->bus, object_path, &error))
1594 {
1595- g_warning ("unable to export menu: %s", error->message);
1596+ g_warning ("unable to export application interface: %s", error->message);
1597 g_clear_error (&error);
1598 }
1599
1600@@ -214,7 +253,7 @@
1601
1602 g_bus_get (G_BUS_TYPE_SESSION,
1603 app->cancellable,
1604- export_menus_and_actions,
1605+ messaging_menu_app_got_bus,
1606 app);
1607 }
1608
1609@@ -248,20 +287,6 @@
1610 {
1611 MessagingMenuApp *app = MESSAGING_MENU_APP (object);
1612
1613- if (app->bus)
1614- {
1615- if (app->action_export_id > 0)
1616- g_dbus_connection_unexport_action_group (app->bus, app->action_export_id);
1617-
1618- if (app->menu_export_id > 0)
1619- g_dbus_connection_unexport_menu_model (app->bus, app->menu_export_id);
1620-
1621- app->action_export_id = 0;
1622- app->menu_export_id = 0;
1623- g_object_unref (app->bus);
1624- app->bus = NULL;
1625- }
1626-
1627 if (app->watch_id > 0)
1628 {
1629 g_bus_unwatch_name (app->watch_id);
1630@@ -283,9 +308,14 @@
1631 g_clear_object (&app->messages_service);
1632 }
1633
1634+ g_clear_pointer (&app->messages, g_hash_table_unref);
1635+
1636+ g_list_free_full (app->sources, source_free);
1637+ app->sources = NULL;
1638+
1639+ g_clear_object (&app->app_interface);
1640 g_clear_object (&app->appinfo);
1641- g_clear_object (&app->source_actions);
1642- g_clear_object (&app->menu);
1643+ g_clear_object (&app->bus);
1644
1645 G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object);
1646 }
1647@@ -416,6 +446,168 @@
1648 }
1649 }
1650
1651+static gboolean
1652+messaging_menu_app_list_sources (IndicatorMessagesApplication *app_interface,
1653+ GDBusMethodInvocation *invocation,
1654+ gpointer user_data)
1655+{
1656+ MessagingMenuApp *app = user_data;
1657+ GVariantBuilder builder;
1658+ GList *it;
1659+
1660+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssuxsb)"));
1661+
1662+ for (it = app->sources; it; it = it->next)
1663+ g_variant_builder_add_value (&builder, source_to_variant (it->data));
1664+
1665+ indicator_messages_application_complete_list_sources (app_interface,
1666+ invocation,
1667+ g_variant_builder_end (&builder));
1668+
1669+ return TRUE;
1670+}
1671+
1672+static gint
1673+compare_source_id (gconstpointer a,
1674+ gconstpointer b)
1675+{
1676+ const Source *source = a;
1677+ const gchar *id = b;
1678+
1679+ return strcmp (source->id, id);
1680+}
1681+
1682+static gboolean
1683+messaging_menu_app_remove_source_internal (MessagingMenuApp *app,
1684+ const gchar *source_id)
1685+{
1686+ GList *node;
1687+
1688+ node = g_list_find_custom (app->sources, source_id, compare_source_id);
1689+ if (node)
1690+ {
1691+ source_free (node->data);
1692+ app->sources = g_list_delete_link (app->sources, node);
1693+ return TRUE;
1694+ }
1695+
1696+ return FALSE;
1697+}
1698+
1699+static gboolean
1700+messaging_menu_app_remove_message_internal (MessagingMenuApp *app,
1701+ const gchar *message_id)
1702+{
1703+ return g_hash_table_remove (app->messages, message_id);
1704+}
1705+
1706+static gboolean
1707+messaging_menu_app_activate_source (IndicatorMessagesApplication *app_interface,
1708+ GDBusMethodInvocation *invocation,
1709+ const gchar *source_id,
1710+ gpointer user_data)
1711+{
1712+ MessagingMenuApp *app = user_data;
1713+ GQuark q = g_quark_from_string (source_id);
1714+
1715+ /* Activate implies removing the source, no need for SourceRemoved */
1716+ if (messaging_menu_app_remove_source_internal (app, source_id))
1717+ g_signal_emit (app, signals[ACTIVATE_SOURCE], q, source_id);
1718+
1719+ indicator_messages_application_complete_activate_source (app_interface, invocation);
1720+
1721+ return TRUE;
1722+}
1723+
1724+static gboolean
1725+messaging_menu_app_list_messages (IndicatorMessagesApplication *app_interface,
1726+ GDBusMethodInvocation *invocation,
1727+ gpointer user_data)
1728+{
1729+ MessagingMenuApp *app = user_data;
1730+ GVariantBuilder builder;
1731+ GHashTableIter iter;
1732+ MessagingMenuMessage *message;
1733+
1734+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssssxaa{sv}b)"));
1735+
1736+ g_hash_table_iter_init (&iter, app->messages);
1737+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &message))
1738+ g_variant_builder_add_value (&builder, _messaging_menu_message_to_variant (message));
1739+
1740+ indicator_messages_application_complete_list_messages (app_interface,
1741+ invocation,
1742+ g_variant_builder_end (&builder));
1743+
1744+ return TRUE;
1745+}
1746+
1747+static gboolean
1748+messaging_menu_app_activate_message (IndicatorMessagesApplication *app_interface,
1749+ GDBusMethodInvocation *invocation,
1750+ const gchar *message_id,
1751+ const gchar *action_id,
1752+ GVariant *params,
1753+ gpointer user_data)
1754+{
1755+ MessagingMenuApp *app = user_data;
1756+ MessagingMenuMessage *msg;
1757+
1758+ msg = g_hash_table_lookup (app->messages, message_id);
1759+ if (msg)
1760+ {
1761+ if (*action_id)
1762+ {
1763+ gchar *signal;
1764+
1765+ signal = g_strconcat ("activate::", action_id, NULL);
1766+
1767+ if (g_variant_n_children (params))
1768+ {
1769+ GVariant *param;
1770+
1771+ g_variant_get_child (params, 0, "v", &param);
1772+ g_signal_emit_by_name (msg, signal, action_id, param);
1773+
1774+ g_variant_unref (param);
1775+ }
1776+ else
1777+ g_signal_emit_by_name (msg, signal, action_id, NULL);
1778+
1779+ g_free (signal);
1780+ }
1781+ else
1782+ g_signal_emit_by_name (msg, "activate", NULL, NULL);
1783+
1784+
1785+ /* Activate implies removing the message, no need for MessageRemoved */
1786+ messaging_menu_app_remove_message_internal (app, message_id);
1787+ }
1788+
1789+ indicator_messages_application_complete_activate_message (app_interface, invocation);
1790+
1791+ return TRUE;
1792+}
1793+
1794+static gboolean
1795+messaging_menu_app_dismiss (IndicatorMessagesApplication *app_interface,
1796+ GDBusMethodInvocation *invocation,
1797+ const gchar * const *sources,
1798+ const gchar * const *messages,
1799+ gpointer user_data)
1800+{
1801+ MessagingMenuApp *app = user_data;
1802+ const gchar * const *it;
1803+
1804+ for (it = sources; *it; it++)
1805+ messaging_menu_app_remove_source_internal (app, *it);
1806+
1807+ for (it = messages; *it; it++)
1808+ messaging_menu_app_remove_message_internal (app, *it);
1809+
1810+ return TRUE;
1811+}
1812+
1813 static void
1814 messaging_menu_app_init (MessagingMenuApp *app)
1815 {
1816@@ -423,15 +615,21 @@
1817 app->status_set = FALSE;
1818 app->bus = NULL;
1819
1820- app->action_export_id = 0;
1821- app->menu_export_id = 0;
1822-
1823- app->cancellable = g_cancellable_new ();
1824-
1825- app->source_actions = g_simple_action_group_new ();
1826- app->menu = g_menu_new ();
1827-
1828- app->cancellable = g_cancellable_new ();
1829+ app->cancellable = g_cancellable_new ();
1830+
1831+ app->app_interface = indicator_messages_application_skeleton_new ();
1832+ g_signal_connect (app->app_interface, "handle-list-sources",
1833+ G_CALLBACK (messaging_menu_app_list_sources), app);
1834+ g_signal_connect (app->app_interface, "handle-activate-source",
1835+ G_CALLBACK (messaging_menu_app_activate_source), app);
1836+ g_signal_connect (app->app_interface, "handle-list-messages",
1837+ G_CALLBACK (messaging_menu_app_list_messages), app);
1838+ g_signal_connect (app->app_interface, "handle-activate-message",
1839+ G_CALLBACK (messaging_menu_app_activate_message), app);
1840+ g_signal_connect (app->app_interface, "handle-dismiss",
1841+ G_CALLBACK (messaging_menu_app_dismiss), app);
1842+
1843+ app->messages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
1844
1845 app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
1846 "com.canonical.indicator.messages",
1847@@ -604,49 +802,65 @@
1848 g_signal_emit (app, signals[STATUS_CHANGED], 0, status);
1849 }
1850
1851-static void
1852-source_action_activated (GSimpleAction *action,
1853- GVariant *parameter,
1854- gpointer user_data)
1855-{
1856- MessagingMenuApp *app = user_data;
1857- const gchar *name = g_action_get_name (G_ACTION (action));
1858- GQuark q = g_quark_from_string (name);
1859-
1860- messaging_menu_app_remove_source (app, name);
1861-
1862- g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name);
1863-}
1864-
1865-static void
1866-messaging_menu_app_insert_source_action (MessagingMenuApp *app,
1867- gint position,
1868- const gchar *id,
1869- GIcon *icon,
1870- const gchar *label,
1871- GVariant *state)
1872-{
1873- GSimpleAction *action;
1874- GMenuItem *menuitem;
1875+static Source *
1876+messaging_menu_app_lookup_source (MessagingMenuApp *app,
1877+ const gchar *id)
1878+{
1879+ GList *node;
1880+
1881+ node = g_list_find_custom (app->sources, id, compare_source_id);
1882+
1883+ return node ? node->data : NULL;
1884+}
1885+
1886+static Source *
1887+messaging_menu_app_get_source (MessagingMenuApp *app,
1888+ const gchar *id)
1889+{
1890+ Source *source;
1891+
1892+ source = messaging_menu_app_lookup_source (app, id);
1893+ if (!source)
1894+ g_warning ("a source with id '%s' doesn't exist", id);
1895+
1896+ return source;
1897+}
1898+
1899+static void
1900+messaging_menu_app_notify_source_changed (MessagingMenuApp *app,
1901+ Source *source)
1902+{
1903+ indicator_messages_application_emit_source_changed (app->app_interface,
1904+ source_to_variant (source));
1905+}
1906+
1907+static void
1908+messaging_menu_app_insert_source_internal (MessagingMenuApp *app,
1909+ gint position,
1910+ const gchar *id,
1911+ GIcon *icon,
1912+ const gchar *label,
1913+ guint count,
1914+ gint64 time,
1915+ const gchar *string)
1916+{
1917+ Source *source;
1918
1919 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1920 g_return_if_fail (id != NULL);
1921+ g_return_if_fail (label != NULL);
1922
1923- if (g_simple_action_group_lookup (app->source_actions, id))
1924+ if (messaging_menu_app_lookup_source (app, id))
1925 {
1926 g_warning ("a source with id '%s' already exists", id);
1927 return;
1928 }
1929
1930- action = g_simple_action_new_stateful (id, NULL, state);
1931- g_signal_connect (action, "activate",
1932- G_CALLBACK (source_action_activated), app);
1933- g_simple_action_group_insert (app->source_actions, G_ACTION (action));
1934- g_object_unref (action);
1935-
1936- menuitem = g_menu_item_new (label, id);
1937- g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem");
1938+ source = g_slice_new0 (Source);
1939+ source->id = g_strdup (id);
1940+ source->label = g_strdup (label);
1941 if (icon)
1942+<<<<<<< TREE
1943 {
1944 gchar *iconstr = g_icon_to_string (icon);
1945 g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr);
1946@@ -721,6 +935,17 @@
1947 g_simple_action_set_state (action, new_state);
1948
1949 g_variant_unref (state);
1950+=======
1951+ source->icon = g_object_ref (icon);
1952+ source->count = count;
1953+ source->time = time;
1954+ source->string = g_strdup (string);
1955+ app->sources = g_list_insert (app->sources, source, position);
1956+
1957+ indicator_messages_application_emit_source_added (app->app_interface,
1958+ position,
1959+ source_to_variant (source));
1960+>>>>>>> MERGE-SOURCE
1961 }
1962
1963 /**
1964@@ -797,8 +1022,7 @@
1965 const gchar *label,
1966 guint count)
1967 {
1968- messaging_menu_app_insert_source_action (app, position, id, icon, label,
1969- g_variant_new ("(uxsb)", count, 0, "", FALSE));
1970+ messaging_menu_app_insert_source_internal (app, position, id, icon, label, count, 0, "");
1971 }
1972
1973 /**
1974@@ -852,8 +1076,7 @@
1975 const gchar *label,
1976 gint64 time)
1977 {
1978- messaging_menu_app_insert_source_action (app, position, id, icon, label,
1979- g_variant_new ("(uxsb)", 0, time, "", FALSE));
1980+ messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, time, "");
1981 }
1982
1983 /**
1984@@ -909,8 +1132,7 @@
1985 const gchar *label,
1986 const gchar *str)
1987 {
1988- messaging_menu_app_insert_source_action (app, position, id, icon, label,
1989- g_variant_new ("(uxsb)", 0, 0, str, FALSE));
1990+ messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, 0, str);
1991 }
1992
1993 /**
1994@@ -950,34 +1172,11 @@
1995 messaging_menu_app_remove_source (MessagingMenuApp *app,
1996 const gchar *source_id)
1997 {
1998- int n_items;
1999- int i;
2000-
2001 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2002 g_return_if_fail (source_id != NULL);
2003
2004- if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL)
2005- return;
2006-
2007- n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu));
2008- for (i = 0; i < n_items; i++)
2009- {
2010- gchar *action;
2011-
2012- if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i,
2013- "action", "s", &action))
2014- {
2015- if (!g_strcmp0 (action, source_id))
2016- {
2017- g_menu_remove (app->menu, i);
2018- break;
2019- }
2020-
2021- g_free (action);
2022- }
2023- }
2024-
2025- g_simple_action_group_remove (app->source_actions, source_id);
2026+ if (messaging_menu_app_remove_source_internal (app, source_id))
2027+ indicator_messages_application_emit_source_removed (app->app_interface, source_id);
2028 }
2029
2030 /**
2031@@ -994,46 +1193,7 @@
2032 g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE);
2033 g_return_val_if_fail (source_id != NULL, FALSE);
2034
2035- return g_simple_action_group_lookup (app->source_actions, source_id) != NULL;
2036-}
2037-
2038-static GMenuItem *
2039-g_menu_find_item_with_action (GMenu *menu,
2040- const gchar *action,
2041- gint *out_pos)
2042-{
2043- gint i;
2044- gint n_elements;
2045- GMenuItem *item = NULL;
2046-
2047- n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu));
2048-
2049- for (i = 0; i < n_elements && item == NULL; i++)
2050- {
2051- GVariant *attr;
2052-
2053- item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
2054- attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING);
2055-
2056- if (!g_str_equal (action, g_variant_get_string (attr, NULL)))
2057- g_clear_object (&item);
2058-
2059- g_variant_unref (attr);
2060- }
2061-
2062- if (item && out_pos)
2063- *out_pos = i - 1;
2064-
2065- return item;
2066-}
2067-
2068-static void
2069-g_menu_replace_item (GMenu *menu,
2070- gint pos,
2071- GMenuItem *item)
2072-{
2073- g_menu_remove (menu, pos);
2074- g_menu_insert_item (menu, pos, item);
2075+ return messaging_menu_app_lookup_source (app, source_id) != NULL;
2076 }
2077
2078 /**
2079@@ -1049,21 +1209,19 @@
2080 const gchar *source_id,
2081 const gchar *label)
2082 {
2083- gint pos;
2084- GMenuItem *item;
2085+ Source *source;
2086
2087 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2088 g_return_if_fail (source_id != NULL);
2089 g_return_if_fail (label != NULL);
2090
2091- item = g_menu_find_item_with_action (app->menu, source_id, &pos);
2092- if (item == NULL)
2093- return;
2094-
2095- g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label);
2096- g_menu_replace_item (app->menu, pos, item);
2097-
2098- g_object_unref (item);
2099+ source = messaging_menu_app_get_source (app, source_id);
2100+ if (source)
2101+ {
2102+ g_free (source->label);
2103+ source->label = g_strdup (label);
2104+ messaging_menu_app_notify_source_changed (app, source);
2105+ }
2106 }
2107
2108 /**
2109@@ -1079,33 +1237,19 @@
2110 const gchar *source_id,
2111 GIcon *icon)
2112 {
2113- gint pos;
2114- GMenuItem *item;
2115+ Source *source;
2116
2117 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2118 g_return_if_fail (source_id != NULL);
2119
2120- item = g_menu_find_item_with_action (app->menu, source_id, &pos);
2121- if (item == NULL)
2122- return;
2123-
2124- if (icon)
2125- {
2126- gchar *iconstr;
2127-
2128- iconstr = g_icon_to_string (icon);
2129- g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
2130-
2131- g_free (iconstr);
2132- }
2133- else
2134- {
2135- g_menu_item_set_attribute_value (item, "x-canonical-icon", NULL);
2136- }
2137-
2138- g_menu_replace_item (app->menu, pos, item);
2139-
2140- g_object_unref (item);
2141+ source = messaging_menu_app_get_source (app, source_id);
2142+ if (source)
2143+ {
2144+ g_clear_object (&source->icon);
2145+ if (icon)
2146+ source->icon = g_object_ref (icon);
2147+ messaging_menu_app_notify_source_changed (app, source);
2148+ }
2149 }
2150
2151 /**
2152@@ -1120,7 +1264,17 @@
2153 const gchar *source_id,
2154 guint count)
2155 {
2156- messaging_menu_app_set_source_action (app, source_id, count, 0, "");
2157+ Source *source;
2158+
2159+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2160+ g_return_if_fail (source_id != NULL);
2161+
2162+ source = messaging_menu_app_get_source (app, source_id);
2163+ if (source)
2164+ {
2165+ source->count = count;
2166+ messaging_menu_app_notify_source_changed (app, source);
2167+ }
2168 }
2169
2170 /**
2171@@ -1136,7 +1290,17 @@
2172 const gchar *source_id,
2173 gint64 time)
2174 {
2175- messaging_menu_app_set_source_action (app, source_id, 0, time, "");
2176+ Source *source;
2177+
2178+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2179+ g_return_if_fail (source_id != NULL);
2180+
2181+ source = messaging_menu_app_get_source (app, source_id);
2182+ if (source)
2183+ {
2184+ source->time = time;
2185+ messaging_menu_app_notify_source_changed (app, source);
2186+ }
2187 }
2188
2189 /**
2190@@ -1152,7 +1316,18 @@
2191 const gchar *source_id,
2192 const gchar *str)
2193 {
2194- messaging_menu_app_set_source_action (app, source_id, 0, 0, str);
2195+ Source *source;
2196+
2197+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2198+ g_return_if_fail (source_id != NULL);
2199+
2200+ source = messaging_menu_app_get_source (app, source_id);
2201+ if (source)
2202+ {
2203+ g_free (source->string);
2204+ source->string = g_strdup (str);
2205+ messaging_menu_app_notify_source_changed (app, source);
2206+ }
2207 }
2208
2209 /**
2210@@ -1170,7 +1345,17 @@
2211 messaging_menu_app_draw_attention (MessagingMenuApp *app,
2212 const gchar *source_id)
2213 {
2214- messaging_menu_app_set_draws_attention (app, source_id, TRUE);
2215+ Source *source;
2216+
2217+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2218+ g_return_if_fail (source_id != NULL);
2219+
2220+ source = messaging_menu_app_get_source (app, source_id);
2221+ if (source)
2222+ {
2223+ source->draws_attention = TRUE;
2224+ messaging_menu_app_notify_source_changed (app, source);
2225+ }
2226 }
2227
2228 /**
2229@@ -1191,5 +1376,135 @@
2230 messaging_menu_app_remove_attention (MessagingMenuApp *app,
2231 const gchar *source_id)
2232 {
2233+<<<<<<< TREE
2234 messaging_menu_app_set_draws_attention (app, source_id, FALSE);
2235+=======
2236+ Source *source;
2237+
2238+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2239+ g_return_if_fail (source_id != NULL);
2240+
2241+ source = messaging_menu_app_get_source (app, source_id);
2242+ if (source)
2243+ {
2244+ source->draws_attention = FALSE;
2245+ messaging_menu_app_notify_source_changed (app, source);
2246+ }
2247+}
2248+
2249+/**
2250+ * messaging_menu_app_append_message:
2251+ * @app: a #MessagingMenuApp
2252+ * @msg: the #MessagingMenuMessage to append
2253+ * @source_id: (allow-none): the source id to which @msg is added, or NULL
2254+ * @notify: whether a notification bubble should be shown for this
2255+ * message
2256+ *
2257+ * Appends @msg to the source with id @source_id of @app. The messaging
2258+ * menu might not display this message immediately if other messages are
2259+ * queued before this one.
2260+ *
2261+ * If @source_id has a count associated with it, that count will be
2262+ * increased by one.
2263+ *
2264+ * If @source_id is %NULL, @msg won't be associated with a source.
2265+ */
2266+void
2267+messaging_menu_app_append_message (MessagingMenuApp *app,
2268+ MessagingMenuMessage *msg,
2269+ const gchar *source_id,
2270+ gboolean notify)
2271+{
2272+ const gchar *id;
2273+
2274+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2275+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
2276+
2277+ id = messaging_menu_message_get_id (msg);
2278+
2279+ if (g_hash_table_lookup (app->messages, id))
2280+ {
2281+ g_warning ("a message with id '%s' already exists", id);
2282+ return;
2283+ }
2284+
2285+ g_hash_table_insert (app->messages, g_strdup (id), g_object_ref (msg));
2286+ indicator_messages_application_emit_message_added (app->app_interface,
2287+ _messaging_menu_message_to_variant (msg));
2288+
2289+ if (source_id)
2290+ {
2291+ Source *source;
2292+
2293+ source = messaging_menu_app_get_source (app, source_id);
2294+ if (source && source->count >= 0)
2295+ {
2296+ source->count++;
2297+ messaging_menu_app_notify_source_changed (app, source);
2298+ }
2299+ }
2300+}
2301+
2302+/**
2303+ * messaging_menu_app_get_message:
2304+ * @app: a #MessagingMenuApp
2305+ * @id: id of the message to retrieve
2306+ *
2307+ * Retrieves the message with @id, that was added with
2308+ * messaging_menu_app_append_message().
2309+ *
2310+ * Returns: (transfer none) (allow-none): the #MessagingMenuApp with
2311+ * @id, or %NULL
2312+ */
2313+MessagingMenuMessage *
2314+messaging_menu_app_get_message (MessagingMenuApp *app,
2315+ const gchar *id)
2316+{
2317+ g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL);
2318+ g_return_val_if_fail (id != NULL, NULL);
2319+
2320+ return g_hash_table_lookup (app->messages, id);
2321+}
2322+
2323+/**
2324+ * messaging_menu_app_remove_message:
2325+ * @app: a #MessagingMenuApp
2326+ * @msg: the #MessagingMenuMessage to remove
2327+ *
2328+ * Removes @msg from @app.
2329+ *
2330+ * If @source_id has a count associated with it, that count will be
2331+ * decreased by one.
2332+ */
2333+void
2334+messaging_menu_app_remove_message (MessagingMenuApp *app,
2335+ MessagingMenuMessage *msg)
2336+{
2337+ /* take a ref of @msg here to make sure the pointer returned by
2338+ * _get_id() is valid for the duration of remove_message_by_id. */
2339+ g_object_ref (msg);
2340+ messaging_menu_app_remove_message_by_id (app, messaging_menu_message_get_id (msg));
2341+ g_object_unref (msg);
2342+}
2343+
2344+/**
2345+ * messaging_menu_app_remove_message_by_id:
2346+ * @app: a #MessagingMenuApp
2347+ * @id: the unique id of @msg
2348+ *
2349+ * Removes the message with the id @id from @app.
2350+ *
2351+ * If @source_id has a count associated with it, that count will be
2352+ * decreased by one.
2353+ */
2354+void
2355+messaging_menu_app_remove_message_by_id (MessagingMenuApp *app,
2356+ const gchar *id)
2357+{
2358+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
2359+ g_return_if_fail (id != NULL);
2360+
2361+ if (messaging_menu_app_remove_message_internal (app, id))
2362+ indicator_messages_application_emit_message_removed (app->app_interface, id);
2363+>>>>>>> MERGE-SOURCE
2364 }
2365
2366=== renamed file 'libmessaging-menu/messaging-menu.h' => 'libmessaging-menu/messaging-menu-app.h'
2367--- libmessaging-menu/messaging-menu.h 2012-08-31 17:19:21 +0000
2368+++ libmessaging-menu/messaging-menu-app.h 2013-04-26 16:57:25 +0000
2369@@ -17,10 +17,11 @@
2370 * Lars Uebernickel <lars.uebernickel@canonical.com>
2371 */
2372
2373-#ifndef __messaging_menu_h__
2374-#define __messaging_menu_h__
2375+#ifndef __messaging_menu_app_h__
2376+#define __messaging_menu_app_h__
2377
2378 #include <gio/gio.h>
2379+#include "messaging-menu-message.h"
2380
2381 G_BEGIN_DECLS
2382
2383@@ -143,6 +144,20 @@
2384 void messaging_menu_app_remove_attention (MessagingMenuApp *app,
2385 const gchar *source_id);
2386
2387+void messaging_menu_app_append_message (MessagingMenuApp *app,
2388+ MessagingMenuMessage *msg,
2389+ const gchar *source_id,
2390+ gboolean notify);
2391+
2392+MessagingMenuMessage * messaging_menu_app_get_message (MessagingMenuApp *app,
2393+ const gchar *id);
2394+
2395+void messaging_menu_app_remove_message (MessagingMenuApp *app,
2396+ MessagingMenuMessage *msg);
2397+
2398+void messaging_menu_app_remove_message_by_id (MessagingMenuApp *app,
2399+ const gchar *id);
2400+
2401 G_END_DECLS
2402
2403 #endif
2404
2405=== added file 'libmessaging-menu/messaging-menu-message.c'
2406--- libmessaging-menu/messaging-menu-message.c 1970-01-01 00:00:00 +0000
2407+++ libmessaging-menu/messaging-menu-message.c 2013-04-26 16:57:25 +0000
2408@@ -0,0 +1,547 @@
2409+/*
2410+ * Copyright 2012 Canonical Ltd.
2411+ *
2412+ * This program is free software: you can redistribute it and/or modify it
2413+ * under the terms of the GNU General Public License version 3, as
2414+ * published by the Free Software Foundation.
2415+ *
2416+ * This program is distributed in the hope that it will be useful, but
2417+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2418+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2419+ * PURPOSE. See the GNU General Public License for more details.
2420+ *
2421+ * You should have received a copy of the GNU General Public License along
2422+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2423+ *
2424+ * Authors:
2425+ * Lars Uebernickel <lars.uebernickel@canonical.com>
2426+ */
2427+
2428+#include "messaging-menu-message.h"
2429+
2430+typedef GObjectClass MessagingMenuMessageClass;
2431+
2432+struct _MessagingMenuMessage
2433+{
2434+ GObject parent;
2435+
2436+ gchar *id;
2437+ GIcon *icon;
2438+ gchar *title;
2439+ gchar *subtitle;
2440+ gchar *body;
2441+ gint64 time;
2442+ gboolean draws_attention;
2443+
2444+ GSList *actions;
2445+};
2446+
2447+G_DEFINE_TYPE (MessagingMenuMessage, messaging_menu_message, G_TYPE_OBJECT);
2448+
2449+enum
2450+{
2451+ PROP_0,
2452+ PROP_ID,
2453+ PROP_ICON,
2454+ PROP_TITLE,
2455+ PROP_SUBTITLE,
2456+ PROP_BODY,
2457+ PROP_TIME,
2458+ PROP_DRAWS_ATTENTION,
2459+ NUM_PROPERTIES
2460+};
2461+
2462+static GParamSpec *properties[NUM_PROPERTIES];
2463+
2464+typedef struct
2465+{
2466+ gchar *id;
2467+ gchar *label;
2468+ GVariantType *parameter_type;
2469+ GVariant *parameter_hint;
2470+} Action;
2471+
2472+static void
2473+action_free (gpointer data)
2474+{
2475+ Action *action = data;
2476+
2477+ g_free (action->id);
2478+ g_free (action->label);
2479+
2480+ if (action->parameter_type)
2481+ g_variant_type_free (action->parameter_type);
2482+
2483+ if (action->parameter_hint)
2484+ g_variant_unref (action->parameter_hint);
2485+
2486+ g_slice_free (Action, action);
2487+}
2488+
2489+static void
2490+messaging_menu_message_dispose (GObject *object)
2491+{
2492+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
2493+
2494+ g_clear_object (&msg->icon);
2495+
2496+ G_OBJECT_CLASS (messaging_menu_message_parent_class)->dispose (object);
2497+}
2498+
2499+static void
2500+messaging_menu_message_finalize (GObject *object)
2501+{
2502+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
2503+
2504+ g_free (msg->id);
2505+ g_free (msg->title);
2506+ g_free (msg->subtitle);
2507+ g_free (msg->body);
2508+
2509+ g_slist_free_full (msg->actions, action_free);
2510+ msg->actions = NULL;
2511+
2512+ G_OBJECT_CLASS (messaging_menu_message_parent_class)->finalize (object);
2513+}
2514+
2515+static void
2516+messaging_menu_message_get_property (GObject *object,
2517+ guint property_id,
2518+ GValue *value,
2519+ GParamSpec *pspec)
2520+{
2521+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
2522+
2523+ switch (property_id)
2524+ {
2525+ case PROP_ID:
2526+ g_value_set_string (value, msg->id);
2527+ break;
2528+
2529+ case PROP_ICON:
2530+ g_value_set_object (value, msg->icon);
2531+ break;
2532+
2533+ case PROP_TITLE:
2534+ g_value_set_string (value, msg->title);
2535+ break;
2536+
2537+ case PROP_SUBTITLE:
2538+ g_value_set_string (value, msg->subtitle);
2539+ break;
2540+
2541+ case PROP_BODY:
2542+ g_value_set_string (value, msg->body);
2543+
2544+ case PROP_TIME:
2545+ g_value_set_int64 (value, msg->time);
2546+ break;
2547+
2548+ case PROP_DRAWS_ATTENTION:
2549+ g_value_set_boolean (value, msg->draws_attention);
2550+ break;
2551+
2552+ default:
2553+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2554+ }
2555+}
2556+
2557+static void
2558+messaging_menu_message_set_property (GObject *object,
2559+ guint property_id,
2560+ const GValue *value,
2561+ GParamSpec *pspec)
2562+{
2563+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
2564+
2565+ switch (property_id)
2566+ {
2567+ case PROP_ID:
2568+ msg->id = g_value_dup_string (value);
2569+ break;
2570+
2571+ case PROP_ICON:
2572+ msg->icon = g_value_dup_object (value);
2573+ break;
2574+
2575+ case PROP_TITLE:
2576+ msg->title = g_value_dup_string (value);
2577+ break;
2578+
2579+ case PROP_SUBTITLE:
2580+ msg->subtitle = g_value_dup_string (value);
2581+ break;
2582+
2583+ case PROP_BODY:
2584+ msg->body = g_value_dup_string (value);
2585+
2586+ case PROP_TIME:
2587+ msg->time = g_value_get_int64 (value);
2588+ break;
2589+
2590+ case PROP_DRAWS_ATTENTION:
2591+ messaging_menu_message_set_draws_attention (msg, g_value_get_boolean (value));
2592+ break;
2593+
2594+ default:
2595+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2596+ }
2597+}
2598+
2599+static void
2600+messaging_menu_message_class_init (MessagingMenuMessageClass *klass)
2601+{
2602+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2603+
2604+ object_class->dispose = messaging_menu_message_dispose;
2605+ object_class->finalize = messaging_menu_message_finalize;
2606+ object_class->get_property = messaging_menu_message_get_property;
2607+ object_class->set_property = messaging_menu_message_set_property;
2608+
2609+ properties[PROP_ID] = g_param_spec_string ("id", "Id",
2610+ "Unique id of the message",
2611+ NULL,
2612+ G_PARAM_CONSTRUCT_ONLY |
2613+ G_PARAM_READWRITE |
2614+ G_PARAM_STATIC_STRINGS);
2615+
2616+ properties[PROP_ICON] = g_param_spec_object ("icon", "Icon",
2617+ "Icon of the message",
2618+ G_TYPE_ICON,
2619+ G_PARAM_CONSTRUCT_ONLY |
2620+ G_PARAM_READWRITE |
2621+ G_PARAM_STATIC_STRINGS);
2622+
2623+ properties[PROP_TITLE] = g_param_spec_string ("title", "Title",
2624+ "Title of the message",
2625+ NULL,
2626+ G_PARAM_CONSTRUCT_ONLY |
2627+ G_PARAM_READWRITE |
2628+ G_PARAM_STATIC_STRINGS);
2629+
2630+ properties[PROP_SUBTITLE] = g_param_spec_string ("subtitle", "Subtitle",
2631+ "Subtitle of the message",
2632+ NULL,
2633+ G_PARAM_CONSTRUCT_ONLY |
2634+ G_PARAM_READWRITE |
2635+ G_PARAM_STATIC_STRINGS);
2636+
2637+ properties[PROP_BODY] = g_param_spec_string ("body", "Body",
2638+ "First lines of the body of the message",
2639+ NULL,
2640+ G_PARAM_CONSTRUCT_ONLY |
2641+ G_PARAM_READWRITE |
2642+ G_PARAM_STATIC_STRINGS);
2643+
2644+ properties[PROP_TIME] = g_param_spec_int64 ("time", "Time",
2645+ "Time the message was sent, in microseconds", 0, G_MAXINT64, 0,
2646+ G_PARAM_CONSTRUCT_ONLY |
2647+ G_PARAM_READWRITE |
2648+ G_PARAM_STATIC_STRINGS);
2649+
2650+ properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention", "Draws attention",
2651+ "Whether the message should draw attention",
2652+ FALSE,
2653+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2654+
2655+ g_object_class_install_properties (klass, NUM_PROPERTIES, properties);
2656+
2657+ /**
2658+ * MessagingMenuMessage::activate:
2659+ * @msg: the #MessagingMenuMessage
2660+ * @action: (allow-none): the id of activated action, or %NULL
2661+ * @parameter: (allow-none): activation parameter, or %NULL
2662+ *
2663+ * Emitted when the user has activated the message. The message is
2664+ * immediately removed from the application's menu, handlers of this
2665+ * signal do not need to call messaging_menu_app_remove_message().
2666+ */
2667+ g_signal_new ("activate",
2668+ MESSAGING_MENU_TYPE_MESSAGE,
2669+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
2670+ 0,
2671+ NULL, NULL,
2672+ g_cclosure_marshal_generic,
2673+ G_TYPE_NONE, 2,
2674+ G_TYPE_STRING,
2675+ G_TYPE_VARIANT);
2676+}
2677+
2678+static void
2679+messaging_menu_message_init (MessagingMenuMessage *self)
2680+{
2681+}
2682+
2683+/**
2684+ * messaging_menu_message_new:
2685+ * @id: unique id of the message
2686+ * @icon: (transfer full) (allow-none): a #GIcon representing the message
2687+ * @title: the title of the message
2688+ * @subtitle: (allow-none): the subtitle of the message
2689+ * @body: (allow-none): the message body
2690+ * @time: the time the message was received
2691+ *
2692+ * Creates a new #MessagingMenuMessage.
2693+ *
2694+ * Returns: (transfer full): a new #MessagingMenuMessage
2695+ */
2696+MessagingMenuMessage *
2697+messaging_menu_message_new (const gchar *id,
2698+ GIcon *icon,
2699+ const gchar *title,
2700+ const gchar *subtitle,
2701+ const gchar *body,
2702+ gint64 time)
2703+{
2704+ g_return_val_if_fail (id != NULL, NULL);
2705+ g_return_val_if_fail (title != NULL, NULL);
2706+
2707+ return g_object_new (MESSAGING_MENU_TYPE_MESSAGE,
2708+ "id", id,
2709+ "icon", icon,
2710+ "title", title,
2711+ "subtitle", subtitle,
2712+ "body", body,
2713+ "time", time,
2714+ NULL);
2715+}
2716+
2717+/**
2718+ * messaging_menu_message_get_id:
2719+ * @msg: a #MessagingMenuMessage
2720+ *
2721+ * Returns: the unique id of @msg
2722+ */
2723+const gchar *
2724+messaging_menu_message_get_id (MessagingMenuMessage *msg)
2725+{
2726+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
2727+
2728+ return msg->id;
2729+}
2730+
2731+/**
2732+ * messaging_menu_message_get_icon:
2733+ * @msg: a #MessagingMenuMessage
2734+ *
2735+ * Returns: (transfer none): the icon of @msg
2736+ */
2737+GIcon *
2738+messaging_menu_message_get_icon (MessagingMenuMessage *msg)
2739+{
2740+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
2741+
2742+ return msg->icon;
2743+}
2744+
2745+/**
2746+ * messaging_menu_message_get_title:
2747+ * @msg: a #MessagingMenuMessage
2748+ *
2749+ * Returns: the title of @msg
2750+ */
2751+const gchar *
2752+messaging_menu_message_get_title (MessagingMenuMessage *msg)
2753+{
2754+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
2755+
2756+ return msg->title;
2757+}
2758+
2759+/**
2760+ * messaging_menu_message_get_subtitle:
2761+ * @msg: a #MessagingMenuMessage
2762+ *
2763+ * Returns: the subtitle of @msg
2764+ */
2765+const gchar *
2766+messaging_menu_message_get_subtitle (MessagingMenuMessage *msg)
2767+{
2768+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
2769+
2770+ return msg->subtitle;
2771+}
2772+
2773+/**
2774+ * messaging_menu_message_get_body:
2775+ * @msg: a #MessagingMenuMessage
2776+ *
2777+ * Returns: the body of @msg
2778+ */
2779+const gchar *
2780+messaging_menu_message_get_body (MessagingMenuMessage *msg)
2781+{
2782+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
2783+
2784+ return msg->body;
2785+}
2786+
2787+/**
2788+ * messaging_menu_message_get_time:
2789+ * @msg: a #MessagingMenuMessage
2790+ *
2791+ * Returns: the time at which @msg was received
2792+ */
2793+gint64
2794+messaging_menu_message_get_time (MessagingMenuMessage *msg)
2795+{
2796+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), 0);
2797+
2798+ return msg->time;
2799+}
2800+
2801+/**
2802+ * messaging_menu_message_get_draws_attention:
2803+ * @msg: a #MessagingMenuMessage
2804+ *
2805+ * Returns: whether @msg is drawing attention
2806+ */
2807+gboolean
2808+messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg)
2809+{
2810+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), FALSE);
2811+
2812+ return msg->draws_attention;
2813+}
2814+
2815+/**
2816+ * messaging_menu_message_set_draws_attention:
2817+ * @msg: a #MessagingMenuMessage
2818+ * @draws_attention: whether @msg should draw attention
2819+ *
2820+ * Sets whether @msg is drawing attention.
2821+ */
2822+void
2823+messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
2824+ gboolean draws_attention)
2825+{
2826+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
2827+
2828+ msg->draws_attention = draws_attention;
2829+ g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_DRAWS_ATTENTION]);
2830+}
2831+
2832+/**
2833+ * messaging_menu_message_add_action:
2834+ * @msg: a #MessagingMenuMessage
2835+ * @id: unique id of the action
2836+ * @label: (allow-none): label of the action
2837+ * @parameter_type: (allow-none): a #GVariantType
2838+ * @parameter_hint: (allow-none): a #GVariant suggesting a valid range
2839+ * for parameters
2840+ *
2841+ * Adds an action with @id and @label to @message. Actions are an
2842+ * alternative way for users to activate a message. Note that messages
2843+ * can still be activated without an action.
2844+ *
2845+ * If @parameter_type is non-%NULL, the action is able to receive user
2846+ * input in addition to simply activating the action. Currently, only
2847+ * string parameters are supported.
2848+ *
2849+ * A list of predefined parameters can be supplied as a #GVariant array
2850+ * of @parameter_type in @parameter_hint. If @parameter_hint is
2851+ * floating, it will be consumed.
2852+ *
2853+ * It is recommended to add at most two actions to a message.
2854+ */
2855+void
2856+messaging_menu_message_add_action (MessagingMenuMessage *msg,
2857+ const gchar *id,
2858+ const gchar *label,
2859+ const GVariantType *parameter_type,
2860+ GVariant *parameter_hint)
2861+{
2862+ Action *action;
2863+
2864+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
2865+ g_return_if_fail (id != NULL);
2866+
2867+ action = g_slice_new (Action);
2868+ action->id = g_strdup (id);
2869+ action->label = g_strdup (label);
2870+ action->parameter_type = parameter_type ? g_variant_type_copy (parameter_type) : NULL;
2871+ action->parameter_hint = parameter_hint ? g_variant_ref_sink (parameter_hint) : NULL;
2872+
2873+ msg->actions = g_slist_append (msg->actions, action);
2874+}
2875+
2876+static GVariant *
2877+action_to_variant (Action *action)
2878+{
2879+ GVariantBuilder builder;
2880+
2881+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
2882+
2883+ g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string (action->id));
2884+
2885+ if (action->label)
2886+ g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (action->label));
2887+
2888+ if (action->parameter_type)
2889+ {
2890+ gchar *type = g_variant_type_dup_string (action->parameter_type);
2891+ g_variant_builder_add (&builder, "{sv}", "parameter-type", g_variant_new_signature (type));
2892+ g_free (type);
2893+ }
2894+
2895+ if (action->parameter_hint)
2896+ g_variant_builder_add (&builder, "{sv}", "parameter-hint", action->parameter_hint);
2897+
2898+ return g_variant_builder_end (&builder);
2899+}
2900+
2901+/*<internal>
2902+ * _messaging_menu_message_to_variant:
2903+ * @msg: a #MessagingMenuMessage
2904+ *
2905+ * Serializes @msg to a #GVariant of the form (sssssxaa{sv}b):
2906+ *
2907+ * id
2908+ * icon
2909+ * title
2910+ * subtitle
2911+ * body
2912+ * time
2913+ * array of action dictionaries
2914+ * draws_attention
2915+ *
2916+ * Returns: a new floating #GVariant instance
2917+ */
2918+GVariant *
2919+_messaging_menu_message_to_variant (MessagingMenuMessage *msg)
2920+{
2921+ GVariantBuilder builder;
2922+ GSList *it;
2923+
2924+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
2925+
2926+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sssssxaa{sv}b)"));
2927+
2928+ g_variant_builder_add (&builder, "s", msg->id);
2929+
2930+ if (msg->icon)
2931+ {
2932+ gchar *iconstr;
2933+
2934+ iconstr = g_icon_to_string (msg->icon);
2935+ g_variant_builder_add (&builder, "s", iconstr);
2936+
2937+ g_free (iconstr);
2938+ }
2939+ else
2940+ g_variant_builder_add (&builder, "s", "");
2941+
2942+ g_variant_builder_add (&builder, "s", msg->title ? msg->title : "");
2943+ g_variant_builder_add (&builder, "s", msg->subtitle ? msg->subtitle : "");
2944+ g_variant_builder_add (&builder, "s", msg->body ? msg->body : "");
2945+ g_variant_builder_add (&builder, "x", msg->time);
2946+
2947+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("aa{sv}"));
2948+ for (it = msg->actions; it; it = it->next)
2949+ g_variant_builder_add_value (&builder, action_to_variant (it->data));
2950+ g_variant_builder_close (&builder);
2951+
2952+ g_variant_builder_add (&builder, "b", msg->draws_attention);
2953+
2954+ return g_variant_builder_end (&builder);
2955+}
2956
2957=== added file 'libmessaging-menu/messaging-menu-message.h'
2958--- libmessaging-menu/messaging-menu-message.h 1970-01-01 00:00:00 +0000
2959+++ libmessaging-menu/messaging-menu-message.h 2013-04-26 16:57:25 +0000
2960@@ -0,0 +1,70 @@
2961+/*
2962+ * Copyright 2012 Canonical Ltd.
2963+ *
2964+ * This program is free software: you can redistribute it and/or modify it
2965+ * under the terms of the GNU General Public License version 3, as
2966+ * published by the Free Software Foundation.
2967+ *
2968+ * This program is distributed in the hope that it will be useful, but
2969+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2970+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2971+ * PURPOSE. See the GNU General Public License for more details.
2972+ *
2973+ * You should have received a copy of the GNU General Public License along
2974+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2975+ *
2976+ * Authors:
2977+ * Lars Uebernickel <lars.uebernickel@canonical.com>
2978+ */
2979+
2980+#ifndef __messaging_menu_message_h__
2981+#define __messaging_menu_message_h__
2982+
2983+#include <gio/gio.h>
2984+
2985+G_BEGIN_DECLS
2986+
2987+#define MESSAGING_MENU_TYPE_MESSAGE (messaging_menu_message_get_type ())
2988+#define MESSAGING_MENU_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessage))
2989+#define MESSAGING_MENU_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass))
2990+#define MESSAGING_MENU_IS_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MESSAGING_MENU_TYPE_MESSAGE))
2991+#define MESSAGING_MENU_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGING_MENU_TYPE_MESSAGE))
2992+#define MESSAGING_MENU_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass))
2993+
2994+typedef struct _MessagingMenuMessage MessagingMenuMessage;
2995+
2996+GType messaging_menu_message_get_type (void) G_GNUC_CONST;
2997+
2998+MessagingMenuMessage * messaging_menu_message_new (const gchar *id,
2999+ GIcon *icon,
3000+ const gchar *title,
3001+ const gchar *subtitle,
3002+ const gchar *body,
3003+ gint64 time);
3004+
3005+const gchar * messaging_menu_message_get_id (MessagingMenuMessage *msg);
3006+
3007+GIcon * messaging_menu_message_get_icon (MessagingMenuMessage *msg);
3008+
3009+const gchar * messaging_menu_message_get_title (MessagingMenuMessage *msg);
3010+
3011+const gchar * messaging_menu_message_get_subtitle (MessagingMenuMessage *msg);
3012+
3013+const gchar * messaging_menu_message_get_body (MessagingMenuMessage *msg);
3014+
3015+gint64 messaging_menu_message_get_time (MessagingMenuMessage *msg);
3016+
3017+gboolean messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg);
3018+
3019+void messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
3020+ gboolean draws_attention);
3021+
3022+void messaging_menu_message_add_action (MessagingMenuMessage *msg,
3023+ const gchar *id,
3024+ const gchar *label,
3025+ const GVariantType *parameter_type,
3026+ GVariant *parameter_hint);
3027+
3028+G_END_DECLS
3029+
3030+#endif
3031
3032=== added file 'libmessaging-menu/messaging-menu.h'
3033--- libmessaging-menu/messaging-menu.h 1970-01-01 00:00:00 +0000
3034+++ libmessaging-menu/messaging-menu.h 2013-04-26 16:57:25 +0000
3035@@ -0,0 +1,25 @@
3036+/*
3037+ * Copyright 2012 Canonical Ltd.
3038+ *
3039+ * This program is free software: you can redistribute it and/or modify it
3040+ * under the terms of the GNU General Public License version 3, as
3041+ * published by the Free Software Foundation.
3042+ *
3043+ * This program is distributed in the hope that it will be useful, but
3044+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3045+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3046+ * PURPOSE. See the GNU General Public License for more details.
3047+ *
3048+ * You should have received a copy of the GNU General Public License along
3049+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3050+ *
3051+ * Authors:
3052+ * Lars Uebernickel <lars.uebernickel@canonical.com>
3053+ */
3054+
3055+#ifndef __messaging_menu_h__
3056+#define __messaging_menu_h__
3057+
3058+#include "messaging-menu-app.h"
3059+
3060+#endif
3061
3062=== modified file 'src/Makefile.am'
3063--- src/Makefile.am 2012-09-03 13:37:23 +0000
3064+++ src/Makefile.am 2013-04-26 16:57:25 +0000
3065@@ -1,8 +1,5 @@
3066
3067-BUILT_SOURCES =
3068 EXTRA_DIST =
3069-CLEANFILES =
3070-DISTCLEANFILES =
3071
3072 libexec_PROGRAMS = indicator-messages-service
3073
3074@@ -23,19 +20,20 @@
3075 im-source-menu-item.h \
3076 ido-detail-label.c \
3077 ido-detail-label.h \
3078- indicator-messages-service.c \
3079- indicator-messages-service.h
3080 dbus-data.h
3081 libmessaging_la_CFLAGS = \
3082 $(APPLET_CFLAGS) \
3083 $(COVERAGE_CFLAGS) \
3084+ -I$(top_builddir)/common \
3085 -Wall \
3086 -Wl,-Bsymbolic-functions \
3087 -Wl,-z,defs \
3088 -Wl,--as-needed \
3089 -Werror \
3090 -DG_LOG_DOMAIN=\"Indicator-Messages\"
3091-libmessaging_la_LIBADD = $(APPLET_LIBS) -lm
3092+libmessaging_la_LIBADD = \
3093+ $(top_builddir)/common/libmessaging-common.la \
3094+ $(APPLET_LIBS) -lm
3095 libmessaging_la_LDFLAGS = \
3096 $(COVERAGE_LDFLAGS) \
3097 -module -avoid-version
3098@@ -46,8 +44,6 @@
3099
3100 indicator_messages_service_SOURCES = \
3101 messages-service.c \
3102- indicator-messages-service.c \
3103- indicator-messages-service.h \
3104 app-section.c \
3105 app-section.h \
3106 dbus-data.h \
3107@@ -56,11 +52,16 @@
3108 gsettingsstrv.c \
3109 gsettingsstrv.h \
3110 gmenuutils.c \
3111- gmenuutils.h
3112+ gmenuutils.h \
3113+ im-phone-menu.c \
3114+ im-phone-menu.h \
3115+ im-application-list.c \
3116+ im-application-list.h
3117
3118 indicator_messages_service_CFLAGS = \
3119 $(APPLET_CFLAGS) \
3120 $(COVERAGE_CFLAGS) \
3121+ -I$(top_builddir)/common \
3122 -Wall \
3123 -Wl,-Bsymbolic-functions \
3124 -Wl,-z,defs \
3125@@ -69,26 +70,11 @@
3126 -DG_LOG_DOMAIN=\"Indicator-Messages\"
3127
3128 indicator_messages_service_LDADD = \
3129+ $(top_builddir)/common/libmessaging-common.la \
3130 $(APPLET_LIBS)
3131
3132 indicator_messages_service_LDFLAGS = \
3133 $(COVERAGE_LDFLAGS)
3134
3135-indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
3136- $(AM_V_GEN) gdbus-codegen \
3137- --interface-prefix com.canonical.indicator.messages. \
3138- --generate-c-code indicator-messages-service \
3139- --c-namespace IndicatorMessages \
3140- $^
3141-indicator-messages-service.h: indicator-messages-service.c
3142-
3143-BUILT_SOURCES += \
3144- indicator-messages-service.c \
3145- indicator-messages-service.h
3146-
3147 EXTRA_DIST += \
3148 messages-service.xml
3149-
3150-CLEANFILES += \
3151- $(BUILT_SOURCES)
3152-
3153
3154=== modified file 'src/app-section.c'
3155--- src/app-section.c 2013-04-22 08:45:52 +0000
3156+++ src/app-section.c 2013-04-26 16:57:25 +0000
3157@@ -34,6 +34,7 @@
3158 #include "dbus-data.h"
3159 #include "gmenuutils.h"
3160 #include "gactionmuxer.h"
3161+#include "indicator-messages-application.h"
3162
3163 struct _AppSectionPrivate
3164 {
3165@@ -42,11 +43,14 @@
3166
3167 IndicatorDesktopShortcuts * ids;
3168
3169+ GCancellable *app_proxy_cancellable;
3170+ IndicatorMessagesApplication *app_proxy;
3171+
3172 GMenu *menu;
3173- GMenuModel *source_menu;
3174+ GMenu *source_menu;
3175
3176 GSimpleActionGroup *static_shortcuts;
3177- GActionGroup *source_actions;
3178+ GSimpleActionGroup *source_actions;
3179 GActionMuxer *muxer;
3180
3181 gboolean draws_attention;
3182@@ -90,19 +94,6 @@
3183 gpointer user_data);
3184 static void app_section_set_app_info (AppSection *self,
3185 GDesktopAppInfo *appinfo);
3186-static gboolean any_action_draws_attention (GActionGroup *group,
3187- const gchar *ignored_action);
3188-static void action_added (GActionGroup *group,
3189- const gchar *action_name,
3190- gpointer user_data);
3191-static void action_state_changed (GActionGroup *group,
3192- const gchar *action_name,
3193- GVariant *value,
3194- gpointer user_data);
3195-static void action_removed (GActionGroup *group,
3196- const gchar *action_name,
3197- gpointer user_data);
3198-static gboolean action_draws_attention (GVariant *state);
3199 static void desktop_file_changed_cb (GFileMonitor *monitor,
3200 GFile *file,
3201 GFile *other_file,
3202@@ -170,6 +161,7 @@
3203 app_section_init (AppSection *self)
3204 {
3205 AppSectionPrivate *priv;
3206+ GMenuItem *item;
3207
3208 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
3209 APP_SECTION_TYPE,
3210@@ -179,10 +171,19 @@
3211 priv->appinfo = NULL;
3212
3213 priv->menu = g_menu_new ();
3214+
3215+ priv->source_menu = g_menu_new ();
3216+ item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->source_menu));
3217+ g_menu_item_set_attribute (item, "action-namespace", "s", "source");
3218+ g_menu_append_item (priv->menu, item);
3219+ g_object_unref (item);
3220+
3221 priv->static_shortcuts = g_simple_action_group_new ();
3222+ priv->source_actions = g_simple_action_group_new ();
3223
3224 priv->muxer = g_action_muxer_new ();
3225 g_action_muxer_insert (priv->muxer, NULL, G_ACTION_GROUP (priv->static_shortcuts));
3226+ g_action_muxer_insert (priv->muxer, "source", G_ACTION_GROUP (priv->source_actions));
3227
3228 priv->draws_attention = FALSE;
3229
3230@@ -249,32 +250,30 @@
3231 AppSection * self = APP_SECTION(object);
3232 AppSectionPrivate * priv = self->priv;
3233
3234+ if (priv->app_proxy_cancellable) {
3235+ g_cancellable_cancel (priv->app_proxy_cancellable);
3236+ g_clear_object (&priv->app_proxy_cancellable);
3237+ }
3238+
3239 if (priv->desktop_file_monitor) {
3240 g_signal_handlers_disconnect_by_func (priv->desktop_file_monitor, desktop_file_changed_cb, self);
3241 g_clear_object (&priv->desktop_file_monitor);
3242 }
3243
3244+ g_clear_object (&priv->app_proxy);
3245+
3246 g_clear_object (&priv->menu);
3247+ g_clear_object (&priv->source_menu);
3248 g_clear_object (&priv->static_shortcuts);
3249+ g_clear_object (&priv->source_actions);
3250
3251 if (priv->name_watch_id) {
3252 g_bus_unwatch_name (priv->name_watch_id);
3253 priv->name_watch_id = 0;
3254 }
3255
3256- if (priv->source_actions) {
3257- g_action_muxer_remove (priv->muxer, "source");
3258- g_object_disconnect (priv->source_actions,
3259- "any_signal::action-added", action_added, self,
3260- "any_signal::action-state-changed", action_state_changed, self,
3261- "any_signal::action-removed", action_removed, self,
3262- NULL);
3263- g_clear_object (&priv->source_actions);
3264- }
3265-
3266 g_clear_object (&priv->muxer);
3267
3268- g_clear_object (&priv->source_menu);
3269 g_clear_object (&priv->ids);
3270 g_clear_object (&priv->appinfo);
3271
3272@@ -430,6 +429,11 @@
3273 g_free(name);
3274 }
3275
3276+ item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->source_menu));
3277+ g_menu_item_set_attribute (item, "action-namespace", "s", "source");
3278+ g_menu_append_item (priv->menu, item);
3279+ g_object_unref (item);
3280+
3281 keyfile = g_file_new_for_path (g_desktop_app_info_get_filename (priv->appinfo));
3282 g_file_load_contents_async (keyfile, NULL, keyfile_loaded, self);
3283
3284@@ -571,39 +575,8 @@
3285 void
3286 app_section_clear_draws_attention (AppSection *self)
3287 {
3288- AppSectionPrivate * priv = self->priv;
3289- gchar **action_names;
3290- gchar **it;
3291-
3292- if (priv->source_actions == NULL)
3293- return;
3294-
3295- action_names = g_action_group_list_actions (priv->source_actions);
3296-
3297- for (it = action_names; *it; it++) {
3298- GVariant *state;
3299-
3300- state = g_action_group_get_action_state (priv->source_actions, *it);
3301- if (!state)
3302- continue;
3303-
3304- /* clear draws-attention while preserving other state */
3305- if (action_draws_attention (state)) {
3306- guint32 count;
3307- gint64 time;
3308- const gchar *str;
3309- GVariant *new_state;
3310-
3311- g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
3312-
3313- new_state = g_variant_new ("(uxsb)", count, time, str, FALSE);
3314- g_action_group_change_action_state (priv->source_actions, *it, new_state);
3315- }
3316-
3317- g_variant_unref (state);
3318- }
3319-
3320- g_strfreev (action_names);
3321+ self->priv->draws_attention = FALSE;
3322+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3323 }
3324
3325 static void
3326@@ -616,6 +589,230 @@
3327 app_section_unset_object_path (self);
3328 }
3329
3330+static void
3331+update_draws_attention (AppSection *self)
3332+{
3333+ AppSectionPrivate *priv = self->priv;
3334+ gchar **actions;
3335+ gchar **it;
3336+ gboolean draws_attention = FALSE;
3337+
3338+ actions = g_action_group_list_actions (G_ACTION_GROUP (priv->source_actions));
3339+
3340+ for (it = actions; *it; it++) {
3341+ GVariant *state;
3342+
3343+ state = g_action_group_get_action_state (G_ACTION_GROUP (priv->source_actions), *it);
3344+ if (state) {
3345+ gboolean b;
3346+ g_variant_get (state, "(uxsb)", NULL, NULL, NULL, &b);
3347+ draws_attention = b || draws_attention;
3348+ g_variant_unref (state);
3349+ }
3350+
3351+ if (draws_attention)
3352+ break;
3353+ }
3354+
3355+ if (draws_attention != priv->draws_attention) {
3356+ priv->draws_attention = draws_attention;
3357+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3358+ }
3359+
3360+ g_strfreev (actions);
3361+}
3362+
3363+static void
3364+remove_source (AppSection *self,
3365+ const gchar *id)
3366+{
3367+ AppSectionPrivate *priv = self->priv;
3368+ guint n_items;
3369+ guint i;
3370+
3371+ n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->source_menu));
3372+ for (i = 0; i < n_items; i++) {
3373+ gchar *action;
3374+ gboolean found = FALSE;
3375+
3376+ if (g_menu_model_get_item_attribute (G_MENU_MODEL (priv->source_menu), i,
3377+ G_MENU_ATTRIBUTE_ACTION, "s", &action)) {
3378+ found = g_str_equal (action, id);
3379+ g_free (action);
3380+ }
3381+
3382+ if (found) {
3383+ g_menu_remove (priv->source_menu, i);
3384+ break;
3385+ }
3386+ }
3387+
3388+ g_simple_action_group_remove (priv->source_actions, id);
3389+ update_draws_attention (self);
3390+}
3391+
3392+static void
3393+source_action_activated (GSimpleAction *action,
3394+ GVariant *parameter,
3395+ gpointer user_data)
3396+{
3397+ AppSection *self = APP_SECTION (user_data);
3398+ AppSectionPrivate *priv = APP_SECTION (user_data)->priv;
3399+
3400+ g_return_if_fail (priv->app_proxy != NULL);
3401+
3402+ indicator_messages_application_call_activate_source (priv->app_proxy,
3403+ g_action_get_name (G_ACTION (action)),
3404+ priv->app_proxy_cancellable,
3405+ NULL, NULL);
3406+
3407+ remove_source (self, g_action_get_name (G_ACTION (action)));
3408+}
3409+
3410+static void
3411+sources_listed (GObject *source_object,
3412+ GAsyncResult *result,
3413+ gpointer user_data)
3414+{
3415+ AppSection *self = user_data;
3416+ AppSectionPrivate *priv = self->priv;
3417+ GVariant *sources = NULL;
3418+ GError *error = NULL;
3419+ GVariantIter iter;
3420+ const gchar *id;
3421+ const gchar *label;
3422+ const gchar *iconstr;
3423+ guint32 count;
3424+ gint64 time;
3425+ const gchar *string;
3426+ gboolean draws_attention;
3427+
3428+ if (!indicator_messages_application_call_list_sources_finish (INDICATOR_MESSAGES_APPLICATION (source_object),
3429+ &sources, result, &error))
3430+ {
3431+ g_warning ("could not fetch the list of sources: %s", error->message);
3432+ g_error_free (error);
3433+ return;
3434+ }
3435+
3436+ g_menu_clear (priv->source_menu);
3437+ g_simple_action_group_clear (priv->source_actions);
3438+ priv->draws_attention = FALSE;
3439+
3440+ g_variant_iter_init (&iter, sources);
3441+ while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr,
3442+ &count, &time, &string, &draws_attention))
3443+ {
3444+ GVariant *state;
3445+ GSimpleAction *action;
3446+ GMenuItem *item;
3447+
3448+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
3449+ action = g_simple_action_new_stateful (id, NULL, state);
3450+ g_signal_connect (action, "activate", G_CALLBACK (source_action_activated), self);
3451+ g_simple_action_group_insert (priv->source_actions, G_ACTION (action));
3452+
3453+ item = g_menu_item_new (label, id);
3454+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "ImSourceMenuItem");
3455+ g_menu_append_item (priv->source_menu, item);
3456+
3457+ priv->draws_attention = priv->draws_attention || draws_attention;
3458+
3459+ g_object_unref (item);
3460+ g_object_unref (action);
3461+ }
3462+
3463+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3464+
3465+ g_variant_unref (sources);
3466+}
3467+
3468+static void
3469+source_added (IndicatorMessagesApplication *app,
3470+ const gchar *id,
3471+ const gchar *label,
3472+ const gchar *iconstr,
3473+ guint count,
3474+ gint64 time,
3475+ const gchar *string,
3476+ gboolean draws_attention,
3477+ gpointer user_data)
3478+{
3479+ AppSection *self = user_data;
3480+ AppSectionPrivate *priv = self->priv;
3481+ GVariant *state;
3482+ GSimpleAction *action;
3483+
3484+ /* TODO put label and icon into the action as well */
3485+
3486+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
3487+ action = g_simple_action_new_stateful (id, NULL, state);
3488+
3489+ g_simple_action_group_insert (priv->source_actions, G_ACTION (action));
3490+
3491+ if (draws_attention && !priv->draws_attention) {
3492+ priv->draws_attention = TRUE;
3493+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3494+ }
3495+
3496+ g_object_unref (action);
3497+}
3498+static void
3499+source_changed (IndicatorMessagesApplication *app,
3500+ const gchar *id,
3501+ const gchar *label,
3502+ const gchar *iconstr,
3503+ guint count,
3504+ gint64 time,
3505+ const gchar *string,
3506+ gboolean draws_attention,
3507+ gpointer user_data)
3508+{
3509+ AppSection *self = user_data;
3510+ AppSectionPrivate *priv = self->priv;
3511+ GVariant *state;
3512+
3513+ /* TODO put label and icon into the action as well */
3514+
3515+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
3516+ g_action_group_change_action_state (G_ACTION_GROUP (priv->source_actions), id, state);
3517+
3518+ update_draws_attention (self);
3519+}
3520+
3521+static void
3522+source_removed (IndicatorMessagesApplication *app,
3523+ const gchar *id,
3524+ gpointer user_data)
3525+{
3526+ AppSection *self = user_data;
3527+
3528+ remove_source (self, id);
3529+}
3530+
3531+static void
3532+app_proxy_created (GObject *source_object,
3533+ GAsyncResult *result,
3534+ gpointer user_data)
3535+{
3536+ AppSectionPrivate *priv = APP_SECTION (user_data)->priv;
3537+ GError *error = NULL;
3538+
3539+ priv->app_proxy = indicator_messages_application_proxy_new_finish (result, &error);
3540+ if (!priv->app_proxy) {
3541+ g_warning ("could not create application proxy: %s", error->message);
3542+ g_error_free (error);
3543+ return;
3544+ }
3545+
3546+ indicator_messages_application_call_list_sources (priv->app_proxy, priv->app_proxy_cancellable,
3547+ sources_listed, user_data);
3548+
3549+ g_signal_connect (priv->app_proxy, "source-added", G_CALLBACK (source_added), user_data);
3550+ g_signal_connect (priv->app_proxy, "source-changed", G_CALLBACK (source_changed), user_data);
3551+ g_signal_connect (priv->app_proxy, "source-removed", G_CALLBACK (source_removed), user_data);
3552+}
3553+
3554 /*
3555 * app_section_set_object_path:
3556 * @self: an #AppSection
3557@@ -634,27 +831,20 @@
3558 const gchar *object_path)
3559 {
3560 AppSectionPrivate *priv = self->priv;
3561- GMenuItem *item;
3562
3563 g_object_freeze_notify (G_OBJECT (self));
3564 app_section_unset_object_path (self);
3565
3566- priv->source_actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path));
3567- g_action_muxer_insert (priv->muxer, "source", priv->source_actions);
3568-
3569- priv->draws_attention = any_action_draws_attention (priv->source_actions, NULL);
3570- g_object_connect (priv->source_actions,
3571- "signal::action-added", action_added, self,
3572- "signal::action-state-changed", action_state_changed, self,
3573- "signal::action-removed", action_removed, self,
3574- NULL);
3575-
3576- priv->source_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path));
3577-
3578- item = g_menu_item_new_section (NULL, priv->source_menu);
3579- g_menu_item_set_attribute (item, "action-namespace", "s", "source");
3580- g_menu_append_item (priv->menu, item);
3581- g_object_unref (item);
3582+ priv->app_proxy_cancellable = g_cancellable_new ();
3583+ indicator_messages_application_proxy_new (bus,
3584+ G_DBUS_PROXY_FLAGS_NONE,
3585+ bus_name,
3586+ object_path,
3587+ priv->app_proxy_cancellable,
3588+ app_proxy_created,
3589+ self);
3590+
3591+ priv->draws_attention = FALSE;
3592
3593 priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0,
3594 NULL, application_vanished,
3595@@ -682,26 +872,19 @@
3596 {
3597 AppSectionPrivate *priv = self->priv;
3598
3599+ if (priv->app_proxy_cancellable) {
3600+ g_cancellable_cancel (priv->app_proxy_cancellable);
3601+ g_clear_object (&priv->app_proxy_cancellable);
3602+ }
3603+ g_clear_object (&priv->app_proxy);
3604+
3605 if (priv->name_watch_id) {
3606 g_bus_unwatch_name (priv->name_watch_id);
3607 priv->name_watch_id = 0;
3608 }
3609
3610- if (priv->source_actions) {
3611- g_object_disconnect (priv->source_actions,
3612- "any_signal::action-added", action_added, self,
3613- "any_signal::action-state-changed", action_state_changed, self,
3614- "any_signal::action-removed", action_removed, self,
3615- NULL);
3616- g_clear_object (&priv->source_actions);
3617- }
3618-
3619- if (priv->source_menu) {
3620- /* the last menu item points is linked to the app's menumodel */
3621- gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu));
3622- g_menu_remove (priv->menu, n_items -1);
3623- g_clear_object (&priv->source_menu);
3624- }
3625+ g_simple_action_group_clear (priv->source_actions);
3626+ g_menu_clear (priv->source_menu);
3627
3628 priv->draws_attention = FALSE;
3629 g_clear_pointer (&priv->chat_status, g_free);
3630@@ -715,85 +898,6 @@
3631 "launch", g_variant_new_boolean (FALSE));
3632 }
3633
3634-static gboolean
3635-action_draws_attention (GVariant *state)
3636-{
3637- gboolean attention;
3638-
3639- if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")))
3640- g_variant_get_child (state, 3, "b", &attention);
3641- else
3642- attention = FALSE;
3643-
3644- return attention;
3645-}
3646-
3647-static gboolean
3648-any_action_draws_attention (GActionGroup *group,
3649- const gchar *ignored_action)
3650-{
3651- gchar **actions;
3652- gchar **it;
3653- gboolean attention = FALSE;
3654-
3655- actions = g_action_group_list_actions (group);
3656-
3657- for (it = actions; *it && !attention; it++) {
3658- GVariant *state;
3659-
3660- if (ignored_action && g_str_equal (ignored_action, *it))
3661- continue;
3662-
3663- state = g_action_group_get_action_state (group, *it);
3664- if (state) {
3665- attention = action_draws_attention (state);
3666- g_variant_unref (state);
3667- }
3668- }
3669-
3670- g_strfreev (actions);
3671- return attention;
3672-}
3673-
3674-static void
3675-action_added (GActionGroup *group,
3676- const gchar *action_name,
3677- gpointer user_data)
3678-{
3679- AppSection *self = user_data;
3680- GVariant *state;
3681-
3682- state = g_action_group_get_action_state (group, action_name);
3683- if (state) {
3684- self->priv->draws_attention |= action_draws_attention (state);
3685- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3686- g_variant_unref (state);
3687- }
3688-}
3689-
3690-static void
3691-action_state_changed (GActionGroup *group,
3692- const gchar *action_name,
3693- GVariant *value,
3694- gpointer user_data)
3695-{
3696- AppSection *self = user_data;
3697-
3698- self->priv->draws_attention = any_action_draws_attention (group, NULL);
3699- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3700-}
3701-
3702-static void
3703-action_removed (GActionGroup *group,
3704- const gchar *action_name,
3705- gpointer user_data)
3706-{
3707- AppSection *self = user_data;
3708-
3709- self->priv->draws_attention = any_action_draws_attention (group, action_name);
3710- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
3711-}
3712-
3713 gboolean
3714 app_section_get_uses_chat_status (AppSection *self)
3715 {
3716
3717=== modified file 'src/dbus-data.h'
3718--- src/dbus-data.h 2012-08-21 09:40:47 +0000
3719+++ src/dbus-data.h 2013-04-26 16:57:25 +0000
3720@@ -1,9 +1,24 @@
3721+/*
3722+ * Copyright 2012-2013 Canonical Ltd.
3723+ *
3724+ * This program is free software: you can redistribute it and/or modify it
3725+ * under the terms of the GNU General Public License version 3, as published
3726+ * by the Free Software Foundation.
3727+ *
3728+ * This program is distributed in the hope that it will be useful, but
3729+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3730+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3731+ * PURPOSE. See the GNU General Public License for more details.
3732+ *
3733+ * You should have received a copy of the GNU General Public License along
3734+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3735+ */
3736
3737 #ifndef __DBUS_DATA_H__
3738 #define __DBUS_DATA_H__ 1
3739
3740 #define INDICATOR_MESSAGES_DBUS_NAME "com.canonical.indicator.messages"
3741-#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages/menu"
3742+#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages"
3743
3744 #define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service"
3745 #define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service"
3746
3747=== modified file 'src/gactionmuxer.c'
3748--- src/gactionmuxer.c 2012-06-04 21:43:56 +0000
3749+++ src/gactionmuxer.c 2013-04-26 16:57:25 +0000
3750@@ -483,3 +483,11 @@
3751 g_clear_object (&muxer->global_actions);
3752 }
3753
3754+GActionGroup *
3755+g_action_muxer_get_group (GActionMuxer *muxer,
3756+ const gchar *prefix)
3757+{
3758+ g_return_val_if_fail (G_IS_ACTION_MUXER (muxer), NULL);
3759+
3760+ return prefix ? g_hash_table_lookup (muxer->groups, prefix) : muxer->global_actions;
3761+}
3762
3763=== modified file 'src/gactionmuxer.h'
3764--- src/gactionmuxer.h 2012-06-03 06:33:31 +0000
3765+++ src/gactionmuxer.h 2013-04-26 16:57:25 +0000
3766@@ -40,5 +40,8 @@
3767 void g_action_muxer_remove (GActionMuxer *muxer,
3768 const gchar *prefix);
3769
3770+GActionGroup * g_action_muxer_get_group (GActionMuxer *muxer,
3771+ const gchar *prefix);
3772+
3773 #endif
3774
3775
3776=== added file 'src/im-application-list.c'
3777--- src/im-application-list.c 1970-01-01 00:00:00 +0000
3778+++ src/im-application-list.c 2013-04-26 16:57:25 +0000
3779@@ -0,0 +1,880 @@
3780+/*
3781+ * Copyright 2012 Canonical Ltd.
3782+ *
3783+ * This program is free software: you can redistribute it and/or modify it
3784+ * under the terms of the GNU General Public License version 3, as published
3785+ * by the Free Software Foundation.
3786+ *
3787+ * This program is distributed in the hope that it will be useful, but
3788+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3789+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3790+ * PURPOSE. See the GNU General Public License for more details.
3791+ *
3792+ * You should have received a copy of the GNU General Public License along
3793+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3794+ *
3795+ * Authors:
3796+ * Lars Uebernickel <lars.uebernickel@canonical.com>
3797+ */
3798+
3799+#include "im-application-list.h"
3800+
3801+#include "indicator-messages-application.h"
3802+#include "gactionmuxer.h"
3803+
3804+#include <gio/gdesktopappinfo.h>
3805+#include <string.h>
3806+
3807+typedef GObjectClass ImApplicationListClass;
3808+
3809+struct _ImApplicationList
3810+{
3811+ GObject parent;
3812+
3813+ GHashTable *applications;
3814+ GActionMuxer *muxer;
3815+};
3816+
3817+G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT);
3818+
3819+enum
3820+{
3821+ SOURCE_ADDED,
3822+ SOURCE_CHANGED,
3823+ SOURCE_REMOVED,
3824+ MESSAGE_ADDED,
3825+ MESSAGE_REMOVED,
3826+ APP_STOPPED,
3827+ REMOVE_ALL,
3828+ N_SIGNALS
3829+};
3830+
3831+static guint signals[N_SIGNALS];
3832+
3833+typedef struct
3834+{
3835+ ImApplicationList *list;
3836+ GDesktopAppInfo *info;
3837+ gchar *id;
3838+ IndicatorMessagesApplication *proxy;
3839+ GActionMuxer *actions;
3840+ GSimpleActionGroup *source_actions;
3841+ GSimpleActionGroup *message_actions;
3842+ GActionMuxer *message_sub_actions;
3843+ GCancellable *cancellable;
3844+} Application;
3845+
3846+static void
3847+application_free (gpointer data)
3848+{
3849+ Application *app = data;
3850+
3851+ if (!app)
3852+ return;
3853+
3854+ g_object_unref (app->info);
3855+ g_free (app->id);
3856+
3857+ if (app->cancellable)
3858+ {
3859+ g_cancellable_cancel (app->cancellable);
3860+ g_clear_object (&app->cancellable);
3861+ }
3862+
3863+ if (app->proxy)
3864+ g_object_unref (app->proxy);
3865+
3866+ if (app->actions)
3867+ {
3868+ g_object_unref (app->actions);
3869+ g_object_unref (app->source_actions);
3870+ g_object_unref (app->message_actions);
3871+ g_object_unref (app->message_sub_actions);
3872+ }
3873+
3874+ g_slice_free (Application, app);
3875+}
3876+
3877+static void
3878+im_application_list_source_removed (Application *app,
3879+ const gchar *id)
3880+{
3881+ g_simple_action_group_remove (app->source_actions, id);
3882+
3883+ g_signal_emit (app->list, signals[SOURCE_REMOVED], 0, app->id, id);
3884+}
3885+
3886+static void
3887+im_application_list_source_activated (GSimpleAction *action,
3888+ GVariant *parameter,
3889+ gpointer user_data)
3890+{
3891+ Application *app = user_data;
3892+ const gchar *source_id;
3893+
3894+ source_id = g_action_get_name (G_ACTION (action));
3895+
3896+ if (g_variant_get_boolean (parameter))
3897+ {
3898+ indicator_messages_application_call_activate_source (app->proxy,
3899+ source_id,
3900+ app->cancellable,
3901+ NULL, NULL);
3902+ }
3903+ else
3904+ {
3905+ const gchar *sources[] = { source_id, NULL };
3906+ const gchar *messages[] = { NULL };
3907+ indicator_messages_application_call_dismiss (app->proxy, sources, messages,
3908+ app->cancellable, NULL, NULL);
3909+ }
3910+
3911+ im_application_list_source_removed (app, source_id);
3912+}
3913+
3914+static guint
3915+g_action_group_get_n_actions (GActionGroup *group)
3916+{
3917+ guint len;
3918+ gchar **actions;
3919+
3920+ actions = g_action_group_list_actions (group);
3921+ len = g_strv_length (actions);
3922+
3923+ g_strfreev (actions);
3924+ return len;
3925+}
3926+
3927+static gboolean
3928+application_draws_attention (gpointer key,
3929+ gpointer value,
3930+ gpointer user_data)
3931+{
3932+ Application *app = value;
3933+
3934+ return (g_action_group_get_n_actions (G_ACTION_GROUP (app->source_actions)) +
3935+ g_action_group_get_n_actions (G_ACTION_GROUP (app->message_actions))) > 0;
3936+}
3937+
3938+static void
3939+im_application_list_update_draws_attention (ImApplicationList *list)
3940+{
3941+ const gchar *icon_name;
3942+ GVariant *state;
3943+ GActionGroup *main_actions;
3944+
3945+ if (g_hash_table_find (list->applications, application_draws_attention, NULL))
3946+ icon_name = "indicator-messages-new";
3947+ else
3948+ icon_name = "indicator-messages";
3949+
3950+ main_actions = g_action_muxer_get_group (list->muxer, NULL);
3951+ state = g_variant_new ("(sssb)", "", icon_name, "Messages", TRUE);
3952+ g_action_group_change_action_state (main_actions, "messages", state);
3953+}
3954+
3955+static void
3956+im_application_list_message_removed (Application *app,
3957+ const gchar *id)
3958+{
3959+ g_simple_action_group_remove (app->message_actions, id);
3960+ g_action_muxer_remove (app->message_sub_actions, id);
3961+
3962+ im_application_list_update_draws_attention (app->list);
3963+
3964+ g_signal_emit (app->list, signals[MESSAGE_REMOVED], 0, app->id, id);
3965+}
3966+
3967+static void
3968+im_application_list_message_activated (GSimpleAction *action,
3969+ GVariant *parameter,
3970+ gpointer user_data)
3971+{
3972+ Application *app = user_data;
3973+ const gchar *message_id;
3974+
3975+ message_id = g_action_get_name (G_ACTION (action));
3976+
3977+ if (g_variant_get_boolean (parameter))
3978+ {
3979+ indicator_messages_application_call_activate_message (app->proxy,
3980+ message_id,
3981+ "",
3982+ g_variant_new_array (G_VARIANT_TYPE_VARIANT, NULL, 0),
3983+ app->cancellable,
3984+ NULL, NULL);
3985+ }
3986+ else
3987+ {
3988+ const gchar *sources[] = { NULL };
3989+ const gchar *messages[] = { message_id, NULL };
3990+ indicator_messages_application_call_dismiss (app->proxy, sources, messages,
3991+ app->cancellable, NULL, NULL);
3992+ }
3993+
3994+ im_application_list_message_removed (app, message_id);
3995+}
3996+
3997+static void
3998+im_application_list_sub_message_activated (GSimpleAction *action,
3999+ GVariant *parameter,
4000+ gpointer user_data)
4001+{
4002+ Application *app = user_data;
4003+ const gchar *message_id;
4004+ const gchar *action_id;
4005+ GVariantBuilder builder;
4006+
4007+ message_id = g_object_get_data (G_OBJECT (action), "message");
4008+ action_id = g_action_get_name (G_ACTION (action));
4009+
4010+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
4011+ if (parameter)
4012+ g_variant_builder_add (&builder, "v", parameter);
4013+
4014+ indicator_messages_application_call_activate_message (app->proxy,
4015+ message_id,
4016+ action_id,
4017+ g_variant_builder_end (&builder),
4018+ app->cancellable,
4019+ NULL, NULL);
4020+
4021+ im_application_list_message_removed (app, message_id);
4022+}
4023+
4024+
4025+static void
4026+im_application_list_remove_all (GSimpleAction *action,
4027+ GVariant *parameter,
4028+ gpointer user_data)
4029+{
4030+ ImApplicationList *list = user_data;
4031+ GHashTableIter iter;
4032+ Application *app;
4033+
4034+ g_signal_emit (list, signals[REMOVE_ALL], 0);
4035+
4036+ g_hash_table_iter_init (&iter, list->applications);
4037+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &app))
4038+ {
4039+ gchar **source_actions;
4040+ gchar **message_actions;
4041+ gchar **it;
4042+
4043+ source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
4044+ for (it = source_actions; *it; it++)
4045+ im_application_list_source_removed (app, *it);
4046+
4047+ message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
4048+ for (it = message_actions; *it; it++)
4049+ im_application_list_message_removed (app, *it);
4050+
4051+ indicator_messages_application_call_dismiss (app->proxy,
4052+ (const gchar * const *) source_actions,
4053+ (const gchar * const *) message_actions,
4054+ app->cancellable, NULL, NULL);
4055+
4056+ g_strfreev (source_actions);
4057+ g_strfreev (message_actions);
4058+ }
4059+}
4060+
4061+static void
4062+im_application_list_dispose (GObject *object)
4063+{
4064+ ImApplicationList *list = IM_APPLICATION_LIST (object);
4065+
4066+ g_clear_pointer (&list->applications, g_hash_table_unref);
4067+ g_clear_object (&list->muxer);
4068+
4069+ G_OBJECT_CLASS (im_application_list_parent_class)->dispose (object);
4070+}
4071+
4072+static void
4073+im_application_list_finalize (GObject *object)
4074+{
4075+ G_OBJECT_CLASS (im_application_list_parent_class)->finalize (object);
4076+}
4077+
4078+static void
4079+im_application_list_class_init (ImApplicationListClass *klass)
4080+{
4081+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
4082+
4083+ object_class->dispose = im_application_list_dispose;
4084+ object_class->finalize = im_application_list_finalize;
4085+
4086+ signals[SOURCE_ADDED] = g_signal_new ("source-added",
4087+ IM_TYPE_APPLICATION_LIST,
4088+ G_SIGNAL_RUN_FIRST,
4089+ 0,
4090+ NULL, NULL,
4091+ g_cclosure_marshal_generic,
4092+ G_TYPE_NONE,
4093+ 4,
4094+ G_TYPE_STRING,
4095+ G_TYPE_STRING,
4096+ G_TYPE_STRING,
4097+ G_TYPE_STRING);
4098+
4099+ signals[SOURCE_CHANGED] = g_signal_new ("source-changed",
4100+ IM_TYPE_APPLICATION_LIST,
4101+ G_SIGNAL_RUN_FIRST,
4102+ 0,
4103+ NULL, NULL,
4104+ g_cclosure_marshal_generic,
4105+ G_TYPE_NONE,
4106+ 4,
4107+ G_TYPE_STRING,
4108+ G_TYPE_STRING,
4109+ G_TYPE_STRING,
4110+ G_TYPE_STRING);
4111+
4112+ signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
4113+ IM_TYPE_APPLICATION_LIST,
4114+ G_SIGNAL_RUN_FIRST,
4115+ 0,
4116+ NULL, NULL,
4117+ g_cclosure_marshal_generic,
4118+ G_TYPE_NONE,
4119+ 2,
4120+ G_TYPE_STRING,
4121+ G_TYPE_STRING);
4122+
4123+ signals[MESSAGE_ADDED] = g_signal_new ("message-added",
4124+ IM_TYPE_APPLICATION_LIST,
4125+ G_SIGNAL_RUN_FIRST,
4126+ 0,
4127+ NULL, NULL,
4128+ g_cclosure_marshal_generic,
4129+ G_TYPE_NONE,
4130+ 10,
4131+ G_TYPE_STRING,
4132+ G_TYPE_STRING,
4133+ G_TYPE_STRING,
4134+ G_TYPE_STRING,
4135+ G_TYPE_STRING,
4136+ G_TYPE_STRING,
4137+ G_TYPE_STRING,
4138+ G_TYPE_VARIANT,
4139+ G_TYPE_INT64,
4140+ G_TYPE_BOOLEAN);
4141+
4142+ signals[MESSAGE_REMOVED] = g_signal_new ("message-removed",
4143+ IM_TYPE_APPLICATION_LIST,
4144+ G_SIGNAL_RUN_FIRST,
4145+ 0,
4146+ NULL, NULL,
4147+ g_cclosure_marshal_generic,
4148+ G_TYPE_NONE,
4149+ 2,
4150+ G_TYPE_STRING,
4151+ G_TYPE_STRING);
4152+
4153+ signals[APP_STOPPED] = g_signal_new ("app-stopped",
4154+ IM_TYPE_APPLICATION_LIST,
4155+ G_SIGNAL_RUN_FIRST,
4156+ 0,
4157+ NULL, NULL,
4158+ g_cclosure_marshal_VOID__OBJECT,
4159+ G_TYPE_NONE,
4160+ 1,
4161+ G_TYPE_STRING);
4162+
4163+ signals[REMOVE_ALL] = g_signal_new ("remove-all",
4164+ IM_TYPE_APPLICATION_LIST,
4165+ G_SIGNAL_RUN_FIRST,
4166+ 0,
4167+ NULL, NULL,
4168+ g_cclosure_marshal_VOID__VOID,
4169+ G_TYPE_NONE,
4170+ 0);
4171+}
4172+
4173+static void
4174+im_application_list_init (ImApplicationList *list)
4175+{
4176+ const GActionEntry action_entries[] = {
4177+ { "messages", NULL, NULL, "('', 'indicator-messages', 'Messages', true)", NULL },
4178+ { "remove-all", im_application_list_remove_all }
4179+ };
4180+
4181+ GSimpleActionGroup *actions;
4182+
4183+ list->applications = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, application_free);
4184+
4185+ actions = g_simple_action_group_new ();
4186+ g_simple_action_group_add_entries (actions, action_entries, G_N_ELEMENTS (action_entries), list);
4187+
4188+ list->muxer = g_action_muxer_new ();
4189+ g_action_muxer_insert (list->muxer, NULL, G_ACTION_GROUP (actions));
4190+
4191+ g_object_unref (actions);
4192+}
4193+
4194+ImApplicationList *
4195+im_application_list_new (void)
4196+{
4197+ return g_object_new (IM_TYPE_APPLICATION_LIST, NULL);
4198+}
4199+
4200+static gchar *
4201+im_application_list_canonical_id (const gchar *id)
4202+{
4203+ gchar *str;
4204+ gchar *p;
4205+ int len;
4206+
4207+ len = strlen (id);
4208+ if (g_str_has_suffix (id, ".desktop"))
4209+ len -= 8;
4210+
4211+ str = g_strndup (id, len);
4212+
4213+ for (p = str; *p; p++)
4214+ {
4215+ if (*p == '.')
4216+ *p = '_';
4217+ }
4218+
4219+ return str;
4220+}
4221+
4222+static Application *
4223+im_application_list_lookup (ImApplicationList *list,
4224+ const gchar *desktop_id)
4225+{
4226+ gchar *id;
4227+ Application *app;
4228+
4229+ id = im_application_list_canonical_id (desktop_id);
4230+ app = g_hash_table_lookup (list->applications, id);
4231+
4232+ g_free (id);
4233+ return app;
4234+}
4235+
4236+void
4237+im_application_list_add (ImApplicationList *list,
4238+ const gchar *desktop_id)
4239+{
4240+ GDesktopAppInfo *info;
4241+ Application *app;
4242+ const gchar *id;
4243+
4244+ g_return_if_fail (IM_IS_APPLICATION_LIST (list));
4245+ g_return_if_fail (desktop_id != NULL);
4246+
4247+ if (im_application_list_lookup (list, desktop_id))
4248+ return;
4249+
4250+ info = g_desktop_app_info_new (desktop_id);
4251+ if (!info)
4252+ {
4253+ g_warning ("an application with id '%s' is not installed", desktop_id);
4254+ return;
4255+ }
4256+
4257+ id = g_app_info_get_id (G_APP_INFO (info));
4258+ g_return_if_fail (id != NULL);
4259+
4260+ app = g_slice_new0 (Application);
4261+ app->info = info;
4262+ app->id = im_application_list_canonical_id (id);
4263+ app->list = list;
4264+ app->actions = g_action_muxer_new ();
4265+ app->source_actions = g_simple_action_group_new ();
4266+ app->message_actions = g_simple_action_group_new ();
4267+ app->message_sub_actions = g_action_muxer_new ();
4268+
4269+ g_action_muxer_insert (app->actions, "src", G_ACTION_GROUP (app->source_actions));
4270+ g_action_muxer_insert (app->actions, "msg", G_ACTION_GROUP (app->message_actions));
4271+ g_action_muxer_insert (app->actions, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
4272+
4273+ g_hash_table_insert (list->applications, (gpointer) app->id, app);
4274+ g_action_muxer_insert (list->muxer, app->id, G_ACTION_GROUP (app->actions));
4275+}
4276+
4277+void
4278+im_application_list_remove (ImApplicationList *list,
4279+ const gchar *id)
4280+{
4281+ Application *app;
4282+
4283+ g_return_if_fail (IM_IS_APPLICATION_LIST (list));
4284+
4285+ app = im_application_list_lookup (list, id);
4286+ if (app)
4287+ {
4288+ if (app->proxy || app->cancellable)
4289+ g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
4290+
4291+ g_hash_table_remove (list->applications, id);
4292+ g_action_muxer_remove (list->muxer, id);
4293+ }
4294+}
4295+
4296+static void
4297+im_application_list_source_added (Application *app,
4298+ guint position,
4299+ GVariant *source)
4300+{
4301+ const gchar *id;
4302+ const gchar *label;
4303+ const gchar *iconstr;
4304+ guint32 count;
4305+ gint64 time;
4306+ const gchar *string;
4307+ gboolean draws_attention;
4308+ GVariant *state;
4309+ GSimpleAction *action;
4310+
4311+ g_variant_get (source, "(&s&s&sux&sb)",
4312+ &id, &label, &iconstr, &count, &time, &string, &draws_attention);
4313+
4314+ state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
4315+ action = g_simple_action_new_stateful (id, G_VARIANT_TYPE_BOOLEAN, state);
4316+ g_signal_connect (action, "activate", G_CALLBACK (im_application_list_source_activated), app);
4317+
4318+ g_simple_action_group_insert (app->source_actions, G_ACTION (action));
4319+
4320+ g_signal_emit (app->list, signals[SOURCE_ADDED], 0, app->id, id, label, iconstr);
4321+
4322+ g_object_unref (action);
4323+}
4324+
4325+static void
4326+im_application_list_source_changed (Application *app,
4327+ GVariant *source)
4328+{
4329+ const gchar *id;
4330+ const gchar *label;
4331+ const gchar *iconstr;
4332+ guint32 count;
4333+ gint64 time;
4334+ const gchar *string;
4335+ gboolean draws_attention;
4336+
4337+ g_variant_get (source, "(&s&s&sux&sb)",
4338+ &id, &label, &iconstr, &count, &time, &string, &draws_attention);
4339+
4340+ g_action_group_change_action_state (G_ACTION_GROUP (app->source_actions), id,
4341+ g_variant_new ("(uxsb)", count, time, string, draws_attention));
4342+
4343+ g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, app->id, id, label, iconstr);
4344+}
4345+
4346+static void
4347+im_application_list_sources_listed (GObject *source_object,
4348+ GAsyncResult *result,
4349+ gpointer user_data)
4350+{
4351+ Application *app = user_data;
4352+ GVariant *sources;
4353+ GError *error = NULL;
4354+
4355+ if (indicator_messages_application_call_list_sources_finish (app->proxy, &sources, result, &error))
4356+ {
4357+ GVariantIter iter;
4358+ GVariant *source;
4359+ guint i = 0;
4360+
4361+ g_variant_iter_init (&iter, sources);
4362+ while ((source = g_variant_iter_next_value (&iter)))
4363+ {
4364+ im_application_list_source_added (app, i++, source);
4365+ g_variant_unref (source);
4366+ }
4367+
4368+ g_variant_unref (sources);
4369+ }
4370+ else
4371+ {
4372+ g_warning ("could not fetch the list of sources: %s", error->message);
4373+ g_error_free (error);
4374+ }
4375+}
4376+
4377+static gchar *
4378+get_symbolic_app_icon_string (GIcon *icon)
4379+{
4380+ const gchar * const *names;
4381+ gchar *symbolic_name;
4382+ GIcon *symbolic_icon;
4383+ gchar *str;
4384+
4385+ if (!G_IS_THEMED_ICON (icon))
4386+ return NULL;
4387+
4388+ names = g_themed_icon_get_names (G_THEMED_ICON (icon));
4389+ if (!names || !names[0])
4390+ return NULL;
4391+
4392+ symbolic_icon = g_themed_icon_new_from_names ((gchar **) names, -1);
4393+
4394+ symbolic_name = g_strconcat (names[0], "-symbolic", NULL);
4395+ g_themed_icon_prepend_name (G_THEMED_ICON (symbolic_icon), symbolic_name);
4396+
4397+ str = g_icon_to_string (symbolic_icon);
4398+
4399+ g_free (symbolic_name);
4400+ g_object_unref (symbolic_icon);
4401+ return str;
4402+}
4403+
4404+static void
4405+im_application_list_message_added (Application *app,
4406+ GVariant *message)
4407+{
4408+ const gchar *id;
4409+ const gchar *iconstr;
4410+ const gchar *title;
4411+ const gchar *subtitle;
4412+ const gchar *body;
4413+ gint64 time;
4414+ GVariantIter *action_iter;
4415+ gboolean draws_attention;
4416+ GSimpleAction *action;
4417+ GIcon *app_icon;
4418+ gchar *app_iconstr = NULL;
4419+ GVariant *actions = NULL;
4420+
4421+ g_variant_get (message, "(&s&s&s&s&sxaa{sv}b)",
4422+ &id, &iconstr, &title, &subtitle, &body, &time, &action_iter, &draws_attention);
4423+
4424+ app_icon = g_app_info_get_icon (G_APP_INFO (app->info));
4425+ if (app_icon)
4426+ app_iconstr = get_symbolic_app_icon_string (app_icon);
4427+
4428+ action = g_simple_action_new (id, G_VARIANT_TYPE_BOOLEAN);
4429+ g_signal_connect (action, "activate", G_CALLBACK (im_application_list_message_activated), app);
4430+ g_simple_action_group_insert (app->message_actions, G_ACTION (action));
4431+
4432+ {
4433+ GVariant *entry;
4434+ GSimpleActionGroup *action_group;
4435+ GVariantBuilder actions_builder;
4436+
4437+ g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
4438+ action_group = g_simple_action_group_new ();
4439+
4440+ while ((entry = g_variant_iter_next_value (action_iter)))
4441+ {
4442+ const gchar *name;
4443+ GSimpleAction *action;
4444+ GVariant *label;
4445+ const gchar *type = NULL;
4446+ GVariant *hint;
4447+ GVariantBuilder dict_builder;
4448+ gchar *prefixed_name;
4449+
4450+ if (!g_variant_lookup (entry, "name", "&s", &name))
4451+ {
4452+ g_warning ("action dictionary for message '%s' is missing 'name' key", id);
4453+ continue;
4454+ }
4455+
4456+ label = g_variant_lookup_value (entry, "label", G_VARIANT_TYPE_STRING);
4457+ g_variant_lookup (entry, "parameter-type", "&g", &type);
4458+ hint = g_variant_lookup_value (entry, "parameter-hint", NULL);
4459+
4460+ action = g_simple_action_new (name, type ? G_VARIANT_TYPE (type) : NULL);
4461+ g_object_set_data_full (G_OBJECT (action), "message", g_strdup (id), g_free);
4462+ g_signal_connect (action, "activate", G_CALLBACK (im_application_list_sub_message_activated), app);
4463+ g_simple_action_group_insert (action_group, G_ACTION (action));
4464+
4465+ g_variant_builder_init (&dict_builder, G_VARIANT_TYPE ("a{sv}"));
4466+
4467+ prefixed_name = g_strjoin (".", app->id, "msg-actions", id, name, NULL);
4468+ g_variant_builder_add (&dict_builder, "{sv}", "name", g_variant_new_string (prefixed_name));
4469+
4470+ if (label)
4471+ {
4472+ g_variant_builder_add (&dict_builder, "{sv}", "label", label);
4473+ g_variant_unref (label);
4474+ }
4475+
4476+ if (type)
4477+ g_variant_builder_add (&dict_builder, "{sv}", "parameter-type", g_variant_new_string (type));
4478+
4479+ if (hint)
4480+ {
4481+ g_variant_builder_add (&dict_builder, "{sv}", "parameter-hint", hint);
4482+ g_variant_unref (hint);
4483+ }
4484+
4485+ g_variant_builder_add (&actions_builder, "a{sv}", &dict_builder);
4486+
4487+ g_object_unref (action);
4488+ g_variant_unref (entry);
4489+ g_free (prefixed_name);
4490+ }
4491+
4492+ g_action_muxer_insert (app->message_sub_actions, id, G_ACTION_GROUP (action_group));
4493+ actions = g_variant_builder_end (&actions_builder);
4494+
4495+ g_object_unref (action_group);
4496+ }
4497+
4498+ im_application_list_update_draws_attention (app->list);
4499+
4500+ g_signal_emit (app->list, signals[MESSAGE_ADDED], 0,
4501+ app->id, app_iconstr, id, iconstr, title,
4502+ subtitle, body, actions, time, draws_attention);
4503+
4504+ g_variant_iter_free (action_iter);
4505+ g_free (app_iconstr);
4506+ g_object_unref (action);
4507+}
4508+
4509+static void
4510+im_application_list_messages_listed (GObject *source_object,
4511+ GAsyncResult *result,
4512+ gpointer user_data)
4513+{
4514+ Application *app = user_data;
4515+ GVariant *messages;
4516+ GError *error = NULL;
4517+
4518+ if (indicator_messages_application_call_list_messages_finish (app->proxy, &messages, result, &error))
4519+ {
4520+ GVariantIter iter;
4521+ GVariant *message;
4522+
4523+ g_variant_iter_init (&iter, messages);
4524+ while ((message = g_variant_iter_next_value (&iter)))
4525+ {
4526+ im_application_list_message_added (app, message);
4527+ g_variant_unref (message);
4528+ }
4529+
4530+ g_variant_unref (messages);
4531+ }
4532+ else
4533+ {
4534+ g_warning ("could not fetch the list of messages: %s", error->message);
4535+ g_error_free (error);
4536+ }
4537+}
4538+
4539+static void
4540+im_application_list_unset_remote (Application *app)
4541+{
4542+ gboolean was_running;
4543+
4544+ was_running = app->proxy || app->cancellable;
4545+
4546+ if (app->cancellable)
4547+ {
4548+ g_cancellable_cancel (app->cancellable);
4549+ g_clear_object (&app->cancellable);
4550+ }
4551+ g_clear_object (&app->proxy);
4552+
4553+ /* clear actions by creating a new action group and overriding it in
4554+ * the muxer */
4555+ g_object_unref (app->source_actions);
4556+ g_object_unref (app->message_actions);
4557+ g_object_unref (app->message_sub_actions);
4558+ app->source_actions = g_simple_action_group_new ();
4559+ app->message_actions = g_simple_action_group_new ();
4560+ app->message_sub_actions = g_action_muxer_new ();
4561+ g_action_muxer_insert (app->actions, "src", G_ACTION_GROUP (app->source_actions));
4562+ g_action_muxer_insert (app->actions, "msg", G_ACTION_GROUP (app->message_actions));
4563+ g_action_muxer_insert (app->actions, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
4564+
4565+ im_application_list_update_draws_attention (app->list);
4566+
4567+ if (was_running)
4568+ g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
4569+}
4570+
4571+static void
4572+im_application_list_app_vanished (GDBusConnection *connection,
4573+ const gchar *name,
4574+ gpointer user_data)
4575+{
4576+ Application *app = user_data;
4577+
4578+ im_application_list_unset_remote (app);
4579+}
4580+
4581+static void
4582+im_application_list_proxy_created (GObject *source_object,
4583+ GAsyncResult *result,
4584+ gpointer user_data)
4585+{
4586+ Application *app = user_data;
4587+ GError *error = NULL;
4588+
4589+ app->proxy = indicator_messages_application_proxy_new_finish (result, &error);
4590+ if (!app->proxy)
4591+ {
4592+ if (error->code != G_IO_ERROR_CANCELLED)
4593+ g_warning ("could not create application proxy: %s", error->message);
4594+ g_error_free (error);
4595+ return;
4596+ }
4597+
4598+ indicator_messages_application_call_list_sources (app->proxy, app->cancellable,
4599+ im_application_list_sources_listed, app);
4600+ indicator_messages_application_call_list_messages (app->proxy, app->cancellable,
4601+ im_application_list_messages_listed, app);
4602+
4603+ g_signal_connect_swapped (app->proxy, "source-added", G_CALLBACK (im_application_list_source_added), app);
4604+ g_signal_connect_swapped (app->proxy, "source-changed", G_CALLBACK (im_application_list_source_changed), app);
4605+ g_signal_connect_swapped (app->proxy, "source-removed", G_CALLBACK (im_application_list_source_removed), app);
4606+ g_signal_connect_swapped (app->proxy, "message-added", G_CALLBACK (im_application_list_message_added), app);
4607+ g_signal_connect_swapped (app->proxy, "message-removed", G_CALLBACK (im_application_list_message_removed), app);
4608+
4609+ g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (G_DBUS_PROXY (app->proxy)),
4610+ g_dbus_proxy_get_name (G_DBUS_PROXY (app->proxy)),
4611+ G_BUS_NAME_WATCHER_FLAGS_NONE,
4612+ NULL, im_application_list_app_vanished,
4613+ app, NULL);
4614+}
4615+
4616+void
4617+im_application_list_set_remote (ImApplicationList *list,
4618+ const gchar *id,
4619+ GDBusConnection *connection,
4620+ const gchar *unique_bus_name,
4621+ const gchar *object_path)
4622+{
4623+ Application *app;
4624+
4625+ g_return_if_fail (IM_IS_APPLICATION_LIST (list));
4626+
4627+ app = im_application_list_lookup (list, id);
4628+ if (!app)
4629+ {
4630+ g_warning ("'%s' is not a registered application", id);
4631+ return;
4632+ }
4633+
4634+ if (app->cancellable)
4635+ {
4636+ gchar *name_owner = NULL;
4637+
4638+ if (app->proxy)
4639+ name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy));
4640+ g_warning ("replacing '%s' at %s with %s", id, name_owner, unique_bus_name);
4641+
4642+ im_application_list_unset_remote (app);
4643+
4644+ g_free (name_owner);
4645+ }
4646+
4647+ app->cancellable = g_cancellable_new ();
4648+ indicator_messages_application_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE,
4649+ unique_bus_name, object_path, app->cancellable,
4650+ im_application_list_proxy_created, app);
4651+}
4652+
4653+GActionGroup *
4654+im_application_list_get_action_group (ImApplicationList *list)
4655+{
4656+ g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
4657+
4658+ return G_ACTION_GROUP (list->muxer);
4659+}
4660
4661=== added file 'src/im-application-list.h'
4662--- src/im-application-list.h 1970-01-01 00:00:00 +0000
4663+++ src/im-application-list.h 2013-04-26 16:57:25 +0000
4664@@ -0,0 +1,52 @@
4665+/*
4666+ * Copyright 2012 Canonical Ltd.
4667+ *
4668+ * This program is free software: you can redistribute it and/or modify it
4669+ * under the terms of the GNU General Public License version 3, as published
4670+ * by the Free Software Foundation.
4671+ *
4672+ * This program is distributed in the hope that it will be useful, but
4673+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4674+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4675+ * PURPOSE. See the GNU General Public License for more details.
4676+ *
4677+ * You should have received a copy of the GNU General Public License along
4678+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4679+ *
4680+ * Authors:
4681+ * Lars Uebernickel <lars.uebernickel@canonical.com>
4682+ */
4683+
4684+#ifndef __IM_APPLICATION_LIST_H__
4685+#define __IM_APPLICATION_LIST_H__
4686+
4687+#include <gio/gio.h>
4688+
4689+#define IM_TYPE_APPLICATION_LIST (im_application_list_get_type ())
4690+#define IM_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationList))
4691+#define IM_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_APPLICATION_LIST, ImApplicationListClass))
4692+#define IM_IS_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_APPLICATION_LIST))
4693+#define IM_IS_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_APPLICATION_LIST))
4694+#define IM_APPLICATION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationListClass))
4695+
4696+typedef struct _ImApplicationList ImApplicationList;
4697+
4698+GType im_application_list_get_type (void);
4699+
4700+ImApplicationList * im_application_list_new (void);
4701+
4702+void im_application_list_add (ImApplicationList *list,
4703+ const gchar *desktop_id);
4704+
4705+void im_application_list_remove (ImApplicationList *list,
4706+ const gchar *id);
4707+
4708+void im_application_list_set_remote (ImApplicationList *list,
4709+ const gchar *id,
4710+ GDBusConnection *connection,
4711+ const gchar *unique_bus_name,
4712+ const gchar *object_path);
4713+
4714+GActionGroup * im_application_list_get_action_group (ImApplicationList *list);
4715+
4716+#endif
4717
4718=== added file 'src/im-phone-menu.c'
4719--- src/im-phone-menu.c 1970-01-01 00:00:00 +0000
4720+++ src/im-phone-menu.c 2013-04-26 16:57:25 +0000
4721@@ -0,0 +1,331 @@
4722+/*
4723+ * Copyright 2012 Canonical Ltd.
4724+ *
4725+ * This program is free software: you can redistribute it and/or modify it
4726+ * under the terms of the GNU General Public License version 3, as published
4727+ * by the Free Software Foundation.
4728+ *
4729+ * This program is distributed in the hope that it will be useful, but
4730+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4731+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4732+ * PURPOSE. See the GNU General Public License for more details.
4733+ *
4734+ * You should have received a copy of the GNU General Public License along
4735+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4736+ *
4737+ * Authors:
4738+ * Lars Uebernickel <lars.uebernickel@canonical.com>
4739+ */
4740+
4741+#include "im-phone-menu.h"
4742+
4743+#include <string.h>
4744+
4745+typedef GObjectClass ImPhoneMenuClass;
4746+
4747+struct _ImPhoneMenu
4748+{
4749+ GObject parent;
4750+
4751+ GMenu *toplevel_menu;
4752+ GMenu *message_section;
4753+ GMenu *source_section;
4754+
4755+};
4756+
4757+G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, G_TYPE_OBJECT);
4758+
4759+typedef void (*ImMenuForeachFunc) (GMenuModel *menu, gint pos);
4760+
4761+static void
4762+im_phone_menu_foreach_item_with_action (GMenuModel *menu,
4763+ const gchar *action,
4764+ ImMenuForeachFunc func)
4765+{
4766+ gint n_items;
4767+ gint i;
4768+
4769+ n_items = g_menu_model_get_n_items (menu);
4770+ for (i = 0; i < n_items; i++)
4771+ {
4772+ gchar *item_action;
4773+
4774+ g_menu_model_get_item_attribute (menu, i, G_MENU_ATTRIBUTE_ACTION, "s", &item_action);
4775+
4776+ if (g_str_equal (action, item_action))
4777+ func (menu, i);
4778+
4779+ g_free (item_action);
4780+ }
4781+}
4782+
4783+static void
4784+im_phone_menu_update_toplevel (ImPhoneMenu *menu)
4785+{
4786+ if (g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section)) ||
4787+ g_menu_model_get_n_items (G_MENU_MODEL (menu->source_section)))
4788+ {
4789+ if (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)) == 0)
4790+ {
4791+ GMenuItem *item;
4792+
4793+ g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->message_section));
4794+ g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->source_section));
4795+
4796+ item = g_menu_item_new ("Clear All", "remove-all");
4797+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.button");
4798+ g_menu_append_item (menu->toplevel_menu, item);
4799+
4800+ g_object_unref (item);
4801+ }
4802+ }
4803+ else
4804+ {
4805+ while (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)))
4806+ g_menu_remove (menu->toplevel_menu, 0);
4807+ }
4808+}
4809+
4810+static void
4811+im_phone_menu_dispose (GObject *object)
4812+{
4813+ ImPhoneMenu *menu = IM_PHONE_MENU (object);
4814+
4815+ g_clear_object (&menu->toplevel_menu);
4816+ g_clear_object (&menu->message_section);
4817+ g_clear_object (&menu->source_section);
4818+
4819+ G_OBJECT_CLASS (im_phone_menu_parent_class)->dispose (object);
4820+}
4821+
4822+static void
4823+im_phone_menu_finalize (GObject *object)
4824+{
4825+ G_OBJECT_CLASS (im_phone_menu_parent_class)->finalize (object);
4826+}
4827+
4828+static void
4829+im_phone_menu_class_init (ImPhoneMenuClass *klass)
4830+{
4831+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
4832+
4833+ object_class->dispose = im_phone_menu_dispose;
4834+ object_class->finalize = im_phone_menu_finalize;
4835+}
4836+
4837+static void
4838+im_phone_menu_init (ImPhoneMenu *menu)
4839+{
4840+ menu->toplevel_menu = g_menu_new ();
4841+ menu->message_section = g_menu_new ();
4842+ menu->source_section = g_menu_new ();
4843+
4844+ g_signal_connect_swapped (menu->message_section, "items-changed",
4845+ G_CALLBACK (im_phone_menu_update_toplevel), menu);
4846+ g_signal_connect_swapped (menu->source_section, "items-changed",
4847+ G_CALLBACK (im_phone_menu_update_toplevel), menu);
4848+
4849+ im_phone_menu_update_toplevel (menu);
4850+}
4851+
4852+ImPhoneMenu *
4853+im_phone_menu_new (void)
4854+{
4855+ return g_object_new (IM_TYPE_PHONE_MENU, NULL);
4856+}
4857+
4858+GMenuModel *
4859+im_phone_menu_get_model (ImPhoneMenu *menu)
4860+{
4861+ g_return_val_if_fail (IM_IS_PHONE_MENU (menu), NULL);
4862+
4863+ return G_MENU_MODEL (menu->toplevel_menu);
4864+}
4865+
4866+static gint64
4867+im_phone_menu_get_message_time (GMenuModel *model,
4868+ gint i)
4869+{
4870+ gint64 time;
4871+
4872+ g_menu_model_get_item_attribute (model, i, "x-canonical-time", "x", &time);
4873+
4874+ return time;
4875+}
4876+
4877+void
4878+im_phone_menu_add_message (ImPhoneMenu *menu,
4879+ const gchar *app_id,
4880+ const gchar *app_icon,
4881+ const gchar *id,
4882+ const gchar *iconstr,
4883+ const gchar *title,
4884+ const gchar *subtitle,
4885+ const gchar *body,
4886+ GVariant *actions,
4887+ gint64 time)
4888+{
4889+ GMenuItem *item;
4890+ gchar *action_name;
4891+ gint n_messages;
4892+ gint pos;
4893+
4894+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
4895+ g_return_if_fail (app_id);
4896+
4897+ action_name = g_strconcat (app_id, ".msg.", id, NULL);
4898+
4899+ item = g_menu_item_new (title, action_name);
4900+
4901+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.messageitem");
4902+ g_menu_item_set_attribute (item, "x-canonical-message-id", "s", id);
4903+ g_menu_item_set_attribute (item, "x-canonical-subtitle", "s", subtitle);
4904+ g_menu_item_set_attribute (item, "x-canonical-text", "s", body);
4905+ g_menu_item_set_attribute (item, "x-canonical-time", "x", time);
4906+
4907+ if (iconstr)
4908+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
4909+
4910+ if (app_icon)
4911+ g_menu_item_set_attribute (item, "x-canonical-app-icon", "s", app_icon);
4912+
4913+ if (actions)
4914+ g_menu_item_set_attribute (item, "x-canonical-message-actions", "v", actions);
4915+
4916+ n_messages = g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section));
4917+ pos = 0;
4918+ while (pos < n_messages &&
4919+ time < im_phone_menu_get_message_time (G_MENU_MODEL (menu->message_section), pos))
4920+ pos++;
4921+
4922+ g_menu_insert_item (menu->message_section, pos, item);
4923+
4924+ g_free (action_name);
4925+ g_object_unref (item);
4926+}
4927+
4928+void
4929+im_phone_menu_remove_message (ImPhoneMenu *menu,
4930+ const gchar *app_id,
4931+ const gchar *id)
4932+{
4933+ gchar *action_name;
4934+
4935+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
4936+ g_return_if_fail (app_id != NULL);
4937+
4938+ action_name = g_strconcat (app_id, ".msg.", id, NULL);
4939+ im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->message_section),
4940+ action_name,
4941+ (ImMenuForeachFunc) g_menu_remove);
4942+
4943+ g_free (action_name);
4944+}
4945+
4946+void
4947+im_phone_menu_add_source (ImPhoneMenu *menu,
4948+ const gchar *app_id,
4949+ const gchar *id,
4950+ const gchar *label,
4951+ const gchar *iconstr)
4952+{
4953+ GMenuItem *item;
4954+ gchar *action_name;
4955+
4956+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
4957+ g_return_if_fail (app_id != NULL);
4958+
4959+ action_name = g_strconcat (app_id, ".src.", id, NULL);
4960+
4961+ item = g_menu_item_new (label, action_name);
4962+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.sourceitem");
4963+
4964+ if (iconstr)
4965+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
4966+
4967+ g_menu_prepend_item (menu->source_section, item);
4968+
4969+ g_free (action_name);
4970+ g_object_unref (item);
4971+}
4972+
4973+void
4974+im_phone_menu_remove_source (ImPhoneMenu *menu,
4975+ const gchar *app_id,
4976+ const gchar *id)
4977+{
4978+ gchar *action_name;
4979+
4980+ g_return_if_fail (IM_IS_PHONE_MENU (menu));
4981+ g_return_if_fail (app_id != NULL);
4982+
4983+ action_name = g_strconcat (app_id, ".src.", id, NULL);
4984+ im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->source_section),
4985+ action_name,
4986+ (ImMenuForeachFunc) g_menu_remove);
4987+
4988+ g_free (action_name);
4989+}
4990+
4991+static void
4992+im_phone_menu_remove_all_for_app (GMenu *menu,
4993+ const gchar *app_id)
4994+{
4995+ gchar *prefix;
4996+ gint n_items;
4997+ gint i = 0;
4998+
4999+ prefix = g_strconcat (app_id, ".", NULL);
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches