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
=== added file 'COPYING.GPLv3'
--- COPYING.GPLv3 1970-01-01 00:00:00 +0000
+++ COPYING.GPLv3 2013-04-26 16:57:25 +0000
@@ -0,0 +1,674 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 3, 29 June 2007
3
4 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5 Everyone is permitted to copy and distribute verbatim copies
6 of this license document, but changing it is not allowed.
7
8 Preamble
9
10 The GNU General Public License is a free, copyleft license for
11software and other kinds of works.
12
13 The licenses for most software and other practical works are designed
14to take away your freedom to share and change the works. By contrast,
15the GNU General Public License is intended to guarantee your freedom to
16share and change all versions of a program--to make sure it remains free
17software for all its users. We, the Free Software Foundation, use the
18GNU General Public License for most of our software; it applies also to
19any other work released this way by its authors. You can apply it to
20your programs, too.
21
22 When we speak of free software, we are referring to freedom, not
23price. Our General Public Licenses are designed to make sure that you
24have the freedom to distribute copies of free software (and charge for
25them if you wish), that you receive source code or can get it if you
26want it, that you can change the software or use pieces of it in new
27free programs, and that you know you can do these things.
28
29 To protect your rights, we need to prevent others from denying you
30these rights or asking you to surrender the rights. Therefore, you have
31certain responsibilities if you distribute copies of the software, or if
32you modify it: responsibilities to respect the freedom of others.
33
34 For example, if you distribute copies of such a program, whether
35gratis or for a fee, you must pass on to the recipients the same
36freedoms that you received. You must make sure that they, too, receive
37or can get the source code. And you must show them these terms so they
38know their rights.
39
40 Developers that use the GNU GPL protect your rights with two steps:
41(1) assert copyright on the software, and (2) offer you this License
42giving you legal permission to copy, distribute and/or modify it.
43
44 For the developers' and authors' protection, the GPL clearly explains
45that there is no warranty for this free software. For both users' and
46authors' sake, the GPL requires that modified versions be marked as
47changed, so that their problems will not be attributed erroneously to
48authors of previous versions.
49
50 Some devices are designed to deny users access to install or run
51modified versions of the software inside them, although the manufacturer
52can do so. This is fundamentally incompatible with the aim of
53protecting users' freedom to change the software. The systematic
54pattern of such abuse occurs in the area of products for individuals to
55use, which is precisely where it is most unacceptable. Therefore, we
56have designed this version of the GPL to prohibit the practice for those
57products. If such problems arise substantially in other domains, we
58stand ready to extend this provision to those domains in future versions
59of the GPL, as needed to protect the freedom of users.
60
61 Finally, every program is threatened constantly by software patents.
62States should not allow patents to restrict development and use of
63software on general-purpose computers, but in those that do, we wish to
64avoid the special danger that patents applied to a free program could
65make it effectively proprietary. To prevent this, the GPL assures that
66patents cannot be used to render the program non-free.
67
68 The precise terms and conditions for copying, distribution and
69modification follow.
70
71 TERMS AND CONDITIONS
72
73 0. Definitions.
74
75 "This License" refers to version 3 of the GNU General Public License.
76
77 "Copyright" also means copyright-like laws that apply to other kinds of
78works, such as semiconductor masks.
79
80 "The Program" refers to any copyrightable work licensed under this
81License. Each licensee is addressed as "you". "Licensees" and
82"recipients" may be individuals or organizations.
83
84 To "modify" a work means to copy from or adapt all or part of the work
85in a fashion requiring copyright permission, other than the making of an
86exact copy. The resulting work is called a "modified version" of the
87earlier work or a work "based on" the earlier work.
88
89 A "covered work" means either the unmodified Program or a work based
90on the Program.
91
92 To "propagate" a work means to do anything with it that, without
93permission, would make you directly or secondarily liable for
94infringement under applicable copyright law, except executing it on a
95computer or modifying a private copy. Propagation includes copying,
96distribution (with or without modification), making available to the
97public, and in some countries other activities as well.
98
99 To "convey" a work means any kind of propagation that enables other
100parties to make or receive copies. Mere interaction with a user through
101a computer network, with no transfer of a copy, is not conveying.
102
103 An interactive user interface displays "Appropriate Legal Notices"
104to the extent that it includes a convenient and prominently visible
105feature that (1) displays an appropriate copyright notice, and (2)
106tells the user that there is no warranty for the work (except to the
107extent that warranties are provided), that licensees may convey the
108work under this License, and how to view a copy of this License. If
109the interface presents a list of user commands or options, such as a
110menu, a prominent item in the list meets this criterion.
111
112 1. Source Code.
113
114 The "source code" for a work means the preferred form of the work
115for making modifications to it. "Object code" means any non-source
116form of a work.
117
118 A "Standard Interface" means an interface that either is an official
119standard defined by a recognized standards body, or, in the case of
120interfaces specified for a particular programming language, one that
121is widely used among developers working in that language.
122
123 The "System Libraries" of an executable work include anything, other
124than the work as a whole, that (a) is included in the normal form of
125packaging a Major Component, but which is not part of that Major
126Component, and (b) serves only to enable use of the work with that
127Major Component, or to implement a Standard Interface for which an
128implementation is available to the public in source code form. A
129"Major Component", in this context, means a major essential component
130(kernel, window system, and so on) of the specific operating system
131(if any) on which the executable work runs, or a compiler used to
132produce the work, or an object code interpreter used to run it.
133
134 The "Corresponding Source" for a work in object code form means all
135the source code needed to generate, install, and (for an executable
136work) run the object code and to modify the work, including scripts to
137control those activities. However, it does not include the work's
138System Libraries, or general-purpose tools or generally available free
139programs which are used unmodified in performing those activities but
140which are not part of the work. For example, Corresponding Source
141includes interface definition files associated with source files for
142the work, and the source code for shared libraries and dynamically
143linked subprograms that the work is specifically designed to require,
144such as by intimate data communication or control flow between those
145subprograms and other parts of the work.
146
147 The Corresponding Source need not include anything that users
148can regenerate automatically from other parts of the Corresponding
149Source.
150
151 The Corresponding Source for a work in source code form is that
152same work.
153
154 2. Basic Permissions.
155
156 All rights granted under this License are granted for the term of
157copyright on the Program, and are irrevocable provided the stated
158conditions are met. This License explicitly affirms your unlimited
159permission to run the unmodified Program. The output from running a
160covered work is covered by this License only if the output, given its
161content, constitutes a covered work. This License acknowledges your
162rights of fair use or other equivalent, as provided by copyright law.
163
164 You may make, run and propagate covered works that you do not
165convey, without conditions so long as your license otherwise remains
166in force. You may convey covered works to others for the sole purpose
167of having them make modifications exclusively for you, or provide you
168with facilities for running those works, provided that you comply with
169the terms of this License in conveying all material for which you do
170not control copyright. Those thus making or running the covered works
171for you must do so exclusively on your behalf, under your direction
172and control, on terms that prohibit them from making any copies of
173your copyrighted material outside their relationship with you.
174
175 Conveying under any other circumstances is permitted solely under
176the conditions stated below. Sublicensing is not allowed; section 10
177makes it unnecessary.
178
179 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
181 No covered work shall be deemed part of an effective technological
182measure under any applicable law fulfilling obligations under article
18311 of the WIPO copyright treaty adopted on 20 December 1996, or
184similar laws prohibiting or restricting circumvention of such
185measures.
186
187 When you convey a covered work, you waive any legal power to forbid
188circumvention of technological measures to the extent such circumvention
189is effected by exercising rights under this License with respect to
190the covered work, and you disclaim any intention to limit operation or
191modification of the work as a means of enforcing, against the work's
192users, your or third parties' legal rights to forbid circumvention of
193technological measures.
194
195 4. Conveying Verbatim Copies.
196
197 You may convey verbatim copies of the Program's source code as you
198receive it, in any medium, provided that you conspicuously and
199appropriately publish on each copy an appropriate copyright notice;
200keep intact all notices stating that this License and any
201non-permissive terms added in accord with section 7 apply to the code;
202keep intact all notices of the absence of any warranty; and give all
203recipients a copy of this License along with the Program.
204
205 You may charge any price or no price for each copy that you convey,
206and you may offer support or warranty protection for a fee.
207
208 5. Conveying Modified Source Versions.
209
210 You may convey a work based on the Program, or the modifications to
211produce it from the Program, in the form of source code under the
212terms of section 4, provided that you also meet all of these conditions:
213
214 a) The work must carry prominent notices stating that you modified
215 it, and giving a relevant date.
216
217 b) The work must carry prominent notices stating that it is
218 released under this License and any conditions added under section
219 7. This requirement modifies the requirement in section 4 to
220 "keep intact all notices".
221
222 c) You must license the entire work, as a whole, under this
223 License to anyone who comes into possession of a copy. This
224 License will therefore apply, along with any applicable section 7
225 additional terms, to the whole of the work, and all its parts,
226 regardless of how they are packaged. This License gives no
227 permission to license the work in any other way, but it does not
228 invalidate such permission if you have separately received it.
229
230 d) If the work has interactive user interfaces, each must display
231 Appropriate Legal Notices; however, if the Program has interactive
232 interfaces that do not display Appropriate Legal Notices, your
233 work need not make them do so.
234
235 A compilation of a covered work with other separate and independent
236works, which are not by their nature extensions of the covered work,
237and which are not combined with it such as to form a larger program,
238in or on a volume of a storage or distribution medium, is called an
239"aggregate" if the compilation and its resulting copyright are not
240used to limit the access or legal rights of the compilation's users
241beyond what the individual works permit. Inclusion of a covered work
242in an aggregate does not cause this License to apply to the other
243parts of the aggregate.
244
245 6. Conveying Non-Source Forms.
246
247 You may convey a covered work in object code form under the terms
248of sections 4 and 5, provided that you also convey the
249machine-readable Corresponding Source under the terms of this License,
250in one of these ways:
251
252 a) Convey the object code in, or embodied in, a physical product
253 (including a physical distribution medium), accompanied by the
254 Corresponding Source fixed on a durable physical medium
255 customarily used for software interchange.
256
257 b) Convey the object code in, or embodied in, a physical product
258 (including a physical distribution medium), accompanied by a
259 written offer, valid for at least three years and valid for as
260 long as you offer spare parts or customer support for that product
261 model, to give anyone who possesses the object code either (1) a
262 copy of the Corresponding Source for all the software in the
263 product that is covered by this License, on a durable physical
264 medium customarily used for software interchange, for a price no
265 more than your reasonable cost of physically performing this
266 conveying of source, or (2) access to copy the
267 Corresponding Source from a network server at no charge.
268
269 c) Convey individual copies of the object code with a copy of the
270 written offer to provide the Corresponding Source. This
271 alternative is allowed only occasionally and noncommercially, and
272 only if you received the object code with such an offer, in accord
273 with subsection 6b.
274
275 d) Convey the object code by offering access from a designated
276 place (gratis or for a charge), and offer equivalent access to the
277 Corresponding Source in the same way through the same place at no
278 further charge. You need not require recipients to copy the
279 Corresponding Source along with the object code. If the place to
280 copy the object code is a network server, the Corresponding Source
281 may be on a different server (operated by you or a third party)
282 that supports equivalent copying facilities, provided you maintain
283 clear directions next to the object code saying where to find the
284 Corresponding Source. Regardless of what server hosts the
285 Corresponding Source, you remain obligated to ensure that it is
286 available for as long as needed to satisfy these requirements.
287
288 e) Convey the object code using peer-to-peer transmission, provided
289 you inform other peers where the object code and Corresponding
290 Source of the work are being offered to the general public at no
291 charge under subsection 6d.
292
293 A separable portion of the object code, whose source code is excluded
294from the Corresponding Source as a System Library, need not be
295included in conveying the object code work.
296
297 A "User Product" is either (1) a "consumer product", which means any
298tangible personal property which is normally used for personal, family,
299or household purposes, or (2) anything designed or sold for incorporation
300into a dwelling. In determining whether a product is a consumer product,
301doubtful cases shall be resolved in favor of coverage. For a particular
302product received by a particular user, "normally used" refers to a
303typical or common use of that class of product, regardless of the status
304of the particular user or of the way in which the particular user
305actually uses, or expects or is expected to use, the product. A product
306is a consumer product regardless of whether the product has substantial
307commercial, industrial or non-consumer uses, unless such uses represent
308the only significant mode of use of the product.
309
310 "Installation Information" for a User Product means any methods,
311procedures, authorization keys, or other information required to install
312and execute modified versions of a covered work in that User Product from
313a modified version of its Corresponding Source. The information must
314suffice to ensure that the continued functioning of the modified object
315code is in no case prevented or interfered with solely because
316modification has been made.
317
318 If you convey an object code work under this section in, or with, or
319specifically for use in, a User Product, and the conveying occurs as
320part of a transaction in which the right of possession and use of the
321User Product is transferred to the recipient in perpetuity or for a
322fixed term (regardless of how the transaction is characterized), the
323Corresponding Source conveyed under this section must be accompanied
324by the Installation Information. But this requirement does not apply
325if neither you nor any third party retains the ability to install
326modified object code on the User Product (for example, the work has
327been installed in ROM).
328
329 The requirement to provide Installation Information does not include a
330requirement to continue to provide support service, warranty, or updates
331for a work that has been modified or installed by the recipient, or for
332the User Product in which it has been modified or installed. Access to a
333network may be denied when the modification itself materially and
334adversely affects the operation of the network or violates the rules and
335protocols for communication across the network.
336
337 Corresponding Source conveyed, and Installation Information provided,
338in accord with this section must be in a format that is publicly
339documented (and with an implementation available to the public in
340source code form), and must require no special password or key for
341unpacking, reading or copying.
342
343 7. Additional Terms.
344
345 "Additional permissions" are terms that supplement the terms of this
346License by making exceptions from one or more of its conditions.
347Additional permissions that are applicable to the entire Program shall
348be treated as though they were included in this License, to the extent
349that they are valid under applicable law. If additional permissions
350apply only to part of the Program, that part may be used separately
351under those permissions, but the entire Program remains governed by
352this License without regard to the additional permissions.
353
354 When you convey a copy of a covered work, you may at your option
355remove any additional permissions from that copy, or from any part of
356it. (Additional permissions may be written to require their own
357removal in certain cases when you modify the work.) You may place
358additional permissions on material, added by you to a covered work,
359for which you have or can give appropriate copyright permission.
360
361 Notwithstanding any other provision of this License, for material you
362add to a covered work, you may (if authorized by the copyright holders of
363that material) supplement the terms of this License with terms:
364
365 a) Disclaiming warranty or limiting liability differently from the
366 terms of sections 15 and 16 of this License; or
367
368 b) Requiring preservation of specified reasonable legal notices or
369 author attributions in that material or in the Appropriate Legal
370 Notices displayed by works containing it; or
371
372 c) Prohibiting misrepresentation of the origin of that material, or
373 requiring that modified versions of such material be marked in
374 reasonable ways as different from the original version; or
375
376 d) Limiting the use for publicity purposes of names of licensors or
377 authors of the material; or
378
379 e) Declining to grant rights under trademark law for use of some
380 trade names, trademarks, or service marks; or
381
382 f) Requiring indemnification of licensors and authors of that
383 material by anyone who conveys the material (or modified versions of
384 it) with contractual assumptions of liability to the recipient, for
385 any liability that these contractual assumptions directly impose on
386 those licensors and authors.
387
388 All other non-permissive additional terms are considered "further
389restrictions" within the meaning of section 10. If the Program as you
390received it, or any part of it, contains a notice stating that it is
391governed by this License along with a term that is a further
392restriction, you may remove that term. If a license document contains
393a further restriction but permits relicensing or conveying under this
394License, you may add to a covered work material governed by the terms
395of that license document, provided that the further restriction does
396not survive such relicensing or conveying.
397
398 If you add terms to a covered work in accord with this section, you
399must place, in the relevant source files, a statement of the
400additional terms that apply to those files, or a notice indicating
401where to find the applicable terms.
402
403 Additional terms, permissive or non-permissive, may be stated in the
404form of a separately written license, or stated as exceptions;
405the above requirements apply either way.
406
407 8. Termination.
408
409 You may not propagate or modify a covered work except as expressly
410provided under this License. Any attempt otherwise to propagate or
411modify it is void, and will automatically terminate your rights under
412this License (including any patent licenses granted under the third
413paragraph of section 11).
414
415 However, if you cease all violation of this License, then your
416license from a particular copyright holder is reinstated (a)
417provisionally, unless and until the copyright holder explicitly and
418finally terminates your license, and (b) permanently, if the copyright
419holder fails to notify you of the violation by some reasonable means
420prior to 60 days after the cessation.
421
422 Moreover, your license from a particular copyright holder is
423reinstated permanently if the copyright holder notifies you of the
424violation by some reasonable means, this is the first time you have
425received notice of violation of this License (for any work) from that
426copyright holder, and you cure the violation prior to 30 days after
427your receipt of the notice.
428
429 Termination of your rights under this section does not terminate the
430licenses of parties who have received copies or rights from you under
431this License. If your rights have been terminated and not permanently
432reinstated, you do not qualify to receive new licenses for the same
433material under section 10.
434
435 9. Acceptance Not Required for Having Copies.
436
437 You are not required to accept this License in order to receive or
438run a copy of the Program. Ancillary propagation of a covered work
439occurring solely as a consequence of using peer-to-peer transmission
440to receive a copy likewise does not require acceptance. However,
441nothing other than this License grants you permission to propagate or
442modify any covered work. These actions infringe copyright if you do
443not accept this License. Therefore, by modifying or propagating a
444covered work, you indicate your acceptance of this License to do so.
445
446 10. Automatic Licensing of Downstream Recipients.
447
448 Each time you convey a covered work, the recipient automatically
449receives a license from the original licensors, to run, modify and
450propagate that work, subject to this License. You are not responsible
451for enforcing compliance by third parties with this License.
452
453 An "entity transaction" is a transaction transferring control of an
454organization, or substantially all assets of one, or subdividing an
455organization, or merging organizations. If propagation of a covered
456work results from an entity transaction, each party to that
457transaction who receives a copy of the work also receives whatever
458licenses to the work the party's predecessor in interest had or could
459give under the previous paragraph, plus a right to possession of the
460Corresponding Source of the work from the predecessor in interest, if
461the predecessor has it or can get it with reasonable efforts.
462
463 You may not impose any further restrictions on the exercise of the
464rights granted or affirmed under this License. For example, you may
465not impose a license fee, royalty, or other charge for exercise of
466rights granted under this License, and you may not initiate litigation
467(including a cross-claim or counterclaim in a lawsuit) alleging that
468any patent claim is infringed by making, using, selling, offering for
469sale, or importing the Program or any portion of it.
470
471 11. Patents.
472
473 A "contributor" is a copyright holder who authorizes use under this
474License of the Program or a work on which the Program is based. The
475work thus licensed is called the contributor's "contributor version".
476
477 A contributor's "essential patent claims" are all patent claims
478owned or controlled by the contributor, whether already acquired or
479hereafter acquired, that would be infringed by some manner, permitted
480by this License, of making, using, or selling its contributor version,
481but do not include claims that would be infringed only as a
482consequence of further modification of the contributor version. For
483purposes of this definition, "control" includes the right to grant
484patent sublicenses in a manner consistent with the requirements of
485this License.
486
487 Each contributor grants you a non-exclusive, worldwide, royalty-free
488patent license under the contributor's essential patent claims, to
489make, use, sell, offer for sale, import and otherwise run, modify and
490propagate the contents of its contributor version.
491
492 In the following three paragraphs, a "patent license" is any express
493agreement or commitment, however denominated, not to enforce a patent
494(such as an express permission to practice a patent or covenant not to
495sue for patent infringement). To "grant" such a patent license to a
496party means to make such an agreement or commitment not to enforce a
497patent against the party.
498
499 If you convey a covered work, knowingly relying on a patent license,
500and the Corresponding Source of the work is not available for anyone
501to copy, free of charge and under the terms of this License, through a
502publicly available network server or other readily accessible means,
503then you must either (1) cause the Corresponding Source to be so
504available, or (2) arrange to deprive yourself of the benefit of the
505patent license for this particular work, or (3) arrange, in a manner
506consistent with the requirements of this License, to extend the patent
507license to downstream recipients. "Knowingly relying" means you have
508actual knowledge that, but for the patent license, your conveying the
509covered work in a country, or your recipient's use of the covered work
510in a country, would infringe one or more identifiable patents in that
511country that you have reason to believe are valid.
512
513 If, pursuant to or in connection with a single transaction or
514arrangement, you convey, or propagate by procuring conveyance of, a
515covered work, and grant a patent license to some of the parties
516receiving the covered work authorizing them to use, propagate, modify
517or convey a specific copy of the covered work, then the patent license
518you grant is automatically extended to all recipients of the covered
519work and works based on it.
520
521 A patent license is "discriminatory" if it does not include within
522the scope of its coverage, prohibits the exercise of, or is
523conditioned on the non-exercise of one or more of the rights that are
524specifically granted under this License. You may not convey a covered
525work if you are a party to an arrangement with a third party that is
526in the business of distributing software, under which you make payment
527to the third party based on the extent of your activity of conveying
528the work, and under which the third party grants, to any of the
529parties who would receive the covered work from you, a discriminatory
530patent license (a) in connection with copies of the covered work
531conveyed by you (or copies made from those copies), or (b) primarily
532for and in connection with specific products or compilations that
533contain the covered work, unless you entered into that arrangement,
534or that patent license was granted, prior to 28 March 2007.
535
536 Nothing in this License shall be construed as excluding or limiting
537any implied license or other defenses to infringement that may
538otherwise be available to you under applicable patent law.
539
540 12. No Surrender of Others' Freedom.
541
542 If conditions are imposed on you (whether by court order, agreement or
543otherwise) that contradict the conditions of this License, they do not
544excuse you from the conditions of this License. If you cannot convey a
545covered work so as to satisfy simultaneously your obligations under this
546License and any other pertinent obligations, then as a consequence you may
547not convey it at all. For example, if you agree to terms that obligate you
548to collect a royalty for further conveying from those to whom you convey
549the Program, the only way you could satisfy both those terms and this
550License would be to refrain entirely from conveying the Program.
551
552 13. Use with the GNU Affero General Public License.
553
554 Notwithstanding any other provision of this License, you have
555permission to link or combine any covered work with a work licensed
556under version 3 of the GNU Affero General Public License into a single
557combined work, and to convey the resulting work. The terms of this
558License will continue to apply to the part which is the covered work,
559but the special requirements of the GNU Affero General Public License,
560section 13, concerning interaction through a network will apply to the
561combination as such.
562
563 14. Revised Versions of this License.
564
565 The Free Software Foundation may publish revised and/or new versions of
566the GNU General Public License from time to time. Such new versions will
567be similar in spirit to the present version, but may differ in detail to
568address new problems or concerns.
569
570 Each version is given a distinguishing version number. If the
571Program specifies that a certain numbered version of the GNU General
572Public License "or any later version" applies to it, you have the
573option of following the terms and conditions either of that numbered
574version or of any later version published by the Free Software
575Foundation. If the Program does not specify a version number of the
576GNU General Public License, you may choose any version ever published
577by the Free Software Foundation.
578
579 If the Program specifies that a proxy can decide which future
580versions of the GNU General Public License can be used, that proxy's
581public statement of acceptance of a version permanently authorizes you
582to choose that version for the Program.
583
584 Later license versions may give you additional or different
585permissions. However, no additional obligations are imposed on any
586author or copyright holder as a result of your choosing to follow a
587later version.
588
589 15. Disclaimer of Warranty.
590
591 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
600 16. Limitation of Liability.
601
602 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610SUCH DAMAGES.
611
612 17. Interpretation of Sections 15 and 16.
613
614 If the disclaimer of warranty and limitation of liability provided
615above cannot be given local legal effect according to their terms,
616reviewing courts shall apply local law that most closely approximates
617an absolute waiver of all civil liability in connection with the
618Program, unless a warranty or assumption of liability accompanies a
619copy of the Program in return for a fee.
620
621 END OF TERMS AND CONDITIONS
622
623 How to Apply These Terms to Your New Programs
624
625 If you develop a new program, and you want it to be of the greatest
626possible use to the public, the best way to achieve this is to make it
627free software which everyone can redistribute and change under these terms.
628
629 To do so, attach the following notices to the program. It is safest
630to attach them to the start of each source file to most effectively
631state the exclusion of warranty; and each file should have at least
632the "copyright" line and a pointer to where the full notice is found.
633
634 <one line to give the program's name and a brief idea of what it does.>
635 Copyright (C) <year> <name of author>
636
637 This program is free software: you can redistribute it and/or modify
638 it under the terms of the GNU General Public License as published by
639 the Free Software Foundation, either version 3 of the License, or
640 (at your option) any later version.
641
642 This program is distributed in the hope that it will be useful,
643 but WITHOUT ANY WARRANTY; without even the implied warranty of
644 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 GNU General Public License for more details.
646
647 You should have received a copy of the GNU General Public License
648 along with this program. If not, see <http://www.gnu.org/licenses/>.
649
650Also add information on how to contact you by electronic and paper mail.
651
652 If the program does terminal interaction, make it output a short
653notice like this when it starts in an interactive mode:
654
655 <program> Copyright (C) <year> <name of author>
656 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 This is free software, and you are welcome to redistribute it
658 under certain conditions; type `show c' for details.
659
660The hypothetical commands `show w' and `show c' should show the appropriate
661parts of the General Public License. Of course, your program's commands
662might be different; for a GUI interface, you would use an "about box".
663
664 You should also get your employer (if you work as a programmer) or school,
665if any, to sign a "copyright disclaimer" for the program, if necessary.
666For more information on this, and how to apply and follow the GNU GPL, see
667<http://www.gnu.org/licenses/>.
668
669 The GNU General Public License does not permit incorporating your program
670into proprietary programs. If your program is a subroutine library, you
671may consider it more useful to permit linking proprietary applications with
672the library. If this is what you want to do, use the GNU Lesser General
673Public License instead of this License. But first, please read
674<http://www.gnu.org/philosophy/why-not-lgpl.html>.
0675
=== modified file 'Makefile.am'
--- Makefile.am 2012-08-29 11:27:54 +0000
+++ Makefile.am 2013-04-26 16:57:25 +0000
@@ -1,5 +1,6 @@
11
2SUBDIRS = \2SUBDIRS = \
3 common \
3 src \4 src \
4 libmessaging-menu \5 libmessaging-menu \
5 data \6 data \
67
=== added directory 'common'
=== added file 'common/Makefile.am'
--- common/Makefile.am 1970-01-01 00:00:00 +0000
+++ common/Makefile.am 2013-04-26 16:57:25 +0000
@@ -0,0 +1,32 @@
1
2noinst_LTLIBRARIES = libmessaging-common.la
3
4indicator-messages-service.c: com.canonical.indicator.messages.service.xml
5 $(AM_V_GEN) gdbus-codegen \
6 --interface-prefix com.canonical.indicator.messages. \
7 --generate-c-code indicator-messages-service \
8 --c-namespace IndicatorMessages \
9 $^
10indicator-messages-service.h: indicator-messages-service.c
11
12indicator-messages-application.c: com.canonical.indicator.messages.application.xml
13 $(AM_V_GEN) gdbus-codegen \
14 --interface-prefix com.canonical.indicator.messages. \
15 --generate-c-code indicator-messages-application \
16 --c-namespace IndicatorMessages \
17 $^
18indicator-messages-application.h: indicator-messages-application.c
19
20BUILT_SOURCES = \
21 indicator-messages-service.c \
22 indicator-messages-service.h \
23 indicator-messages-application.c \
24 indicator-messages-application.h
25
26libmessaging_common_la_SOURCES = \
27 $(BUILT_SOURCES)
28
29libmessaging_common_la_CFLAGS = $(GIO_CFLAGS)
30libmessaging_common_la_LIBADD = $(GIO_LIBS)
31
32CLEANFILES = $(BUILT_SOURCES)
033
=== added file 'common/com.canonical.indicator.messages.application.xml'
--- common/com.canonical.indicator.messages.application.xml 1970-01-01 00:00:00 +0000
+++ common/com.canonical.indicator.messages.application.xml 2013-04-26 16:57:25 +0000
@@ -0,0 +1,39 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<node name="/">
3 <interface name="com.canonical.indicator.messages.application">
4 <method name="ListSources">
5 <arg type="a(sssuxsb)" name="sources" direction="out" />
6 </method>
7 <method name="ListMessages">
8 <arg type="a(sssssxaa{sv}b)" name="message" direction="out" />
9 </method>
10 <method name="ActivateSource">
11 <arg type="s" name="source_id" direction="in" />
12 </method>
13 <method name="ActivateMessage">
14 <arg type="s" name="message_id" direction="in" />
15 <arg type="s" name="action_id" direction="in" />
16 <arg type="av" name="parameter" direction="in" />
17 </method>
18 <method name="Dismiss">
19 <arg type="as" name="sources" direction="in" />
20 <arg type="as" name="messages" direction="in" />
21 </method>
22 <signal name="SourceAdded">
23 <arg type="u" name="position" direction="in" />
24 <arg type="(sssuxsb)" name="source" direction="in" />
25 </signal>
26 <signal name="SourceChanged">
27 <arg type="(sssuxsb)" name="source" direction="in" />
28 </signal>
29 <signal name="SourceRemoved">
30 <arg type="s" name="source_id" direction="in" />
31 </signal>
32 <signal name="MessageAdded">
33 <arg type="(sssssxaa{sv}b)" name="message" direction="in" />
34 </signal>
35 <signal name="MessageRemoved">
36 <arg type="s" name="message_id" direction="in" />
37 </signal>
38 </interface>
39</node>
040
=== renamed file 'src/messages-service.xml' => 'common/com.canonical.indicator.messages.service.xml'
=== modified file 'configure.ac'
--- configure.ac 2013-01-22 20:30:05 +0000
+++ configure.ac 2013-04-26 16:57:25 +0000
@@ -156,6 +156,7 @@
156AC_OUTPUT([156AC_OUTPUT([
157Makefile157Makefile
158src/Makefile158src/Makefile
159common/Makefile
159data/Makefile160data/Makefile
160data/icons/Makefile161data/icons/Makefile
161data/icons/16x16/Makefile162data/icons/16x16/Makefile
162163
=== modified file 'debian/changelog'
--- debian/changelog 2013-02-13 02:02:12 +0000
+++ debian/changelog 2013-04-26 16:57:25 +0000
@@ -1,3 +1,4 @@
1<<<<<<< TREE
1indicator-messages (12.10.6daily13.02.13-0ubuntu1) raring; urgency=low2indicator-messages (12.10.6daily13.02.13-0ubuntu1) raring; urgency=low
23
3 [ Jason Conti ]4 [ Jason Conti ]
@@ -33,6 +34,88 @@
33indicator-messages (12.10.6daily12.11.21.1-0ubuntu1) raring; urgency=low34indicator-messages (12.10.6daily12.11.21.1-0ubuntu1) raring; urgency=low
3435
35 [ Mathieu Trudel-Lapierre ]36 [ Mathieu Trudel-Lapierre ]
37=======
38indicator-messages (13.10.0phablet1) raring; urgency=low
39
40 * Version bump to not pull from archives
41
42 -- Sergio Schvezov <sergio.schvezov@canonical.com> Fri, 26 Apr 2013 13:53:53 -0300
43
44indicator-messages (12.10.6phablet1) quantal; urgency=low
45
46 * Adding guards for g_type_init
47
48 -- Sergio Schvezov <sergio.schvezov@canonical.com> Fri, 22 Mar 2013 17:23:45 -0300
49
50indicator-messages (12.10.6-0ubuntu1phablet9) quantal; urgency=low
51
52 * add "remove-all" signal to imapplicationlist (temporarily)
53
54 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 20 Dec 2012 18:49:50 +0100
55
56indicator-messages (12.10.6-0ubuntu1phablet8) quantal; urgency=low
57
58 * Make messaging_menu_app_remove_message() work for messages with a ref count of 1
59 * Make handling of multiple processes with the same desktop id more robust
60 * ImPhoneMenu: sort messages by time (fixes LP #1090266)
61 * Don't show message sources
62
63 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 17 Dec 2012 14:42:03 +0100
64
65indicator-messages (12.10.6-0ubuntu1phablet7) quantal; urgency=low
66
67 * Remove variant wrapper from 'parameter' argument of the "activate" signal
68
69 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Tue, 11 Dec 2012 14:28:15 +0100
70
71indicator-messages (12.10.6-0ubuntu1phablet6) quantal; urgency=low
72
73 * Don't show sources
74 * Always use the "messageitem" widget type for messages
75
76 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 10 Dec 2012 14:38:16 +0100
77
78indicator-messages (12.10.6-0ubuntu1phablet5) quantal; urgency=low
79
80 * Don't shorten the app id to seven characters (fixes LP #1086729)
81 * Add messaging_menu_app_get_message
82
83 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 06 Dec 2012 15:06:34 +0000
84
85indicator-messages (12.10.6-0ubuntu1phablet4) quantal; urgency=low
86
87 [Lars Uebernickel]
88 * Add the concept of actions to messages
89 * Stop using IndicatorService
90 * Reverse order of messages
91 * Expose symbolic application icon
92 * Change icon when there are any messages in the menu
93
94 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Tue, 04 Dec 2012 21:10:26 +0000
95
96indicator-messages (12.10.6-0ubuntu1phablet3) quantal; urgency=low
97
98 [Lars Uebernickel]
99 * expose root menu item of which the indicator menu is a submenu
100 * fix crash in im-application-list on arm
101
102 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Thu, 29 Nov 2012 21:44:19 +0100
103
104indicator-messages (12.10.6-0ubuntu1phablet2) quantal; urgency=low
105
106 [Lars Uebernickel]
107 * refactor messages-service.c
108 * notify applications about message and source activations
109 * add "Clear All" menu item
110 * allow dismissing of messages
111 * include application icons on message items
112
113 -- Lars Uebernickel <lars.uebernickel@ubuntu.com> Mon, 26 Nov 2012 22:19:51 +0100
114
115indicator-messages (12.10.6-0ubuntu1phablet1) quantal; urgency=low
116
117 [ Mathieu Trudel-Lapierre ]
118>>>>>>> MERGE-SOURCE
36 * debian/rules:119 * debian/rules:
37 - Use autogen.sh for dh_autoreconf.120 - Use autogen.sh for dh_autoreconf.
38 - Drop the override for dh_makeshlibs.121 - Drop the override for dh_makeshlibs.
@@ -45,10 +128,17 @@
45 - Clear the detail (count or time) of a source when another type of detail128 - Clear the detail (count or time) of a source when another type of detail
46 is set. (LP: #1071640)129 is set. (LP: #1071640)
47130
131<<<<<<< TREE
48 [ Automatic PS uploader ]132 [ Automatic PS uploader ]
49 * Automatic snapshot from revision 331133 * Automatic snapshot from revision 331
50134
51 -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Wed, 21 Nov 2012 10:41:37 +0000135 -- Automatic PS uploader <ps-jenkins@lists.canonical.com> Wed, 21 Nov 2012 10:41:37 +0000
136=======
137 [ Ricardo Mendoza ]
138 * Releasing upstream for phablet
139
140 -- Ricardo Mendoza <ricardo.mendoza@canonical.com> Tue, 20 Nov 2012 10:08:59 -0430
141>>>>>>> MERGE-SOURCE
52142
53indicator-messages (12.10.5-0ubuntu2) raring; urgency=low143indicator-messages (12.10.5-0ubuntu2) raring; urgency=low
54144
55145
=== modified file 'debian/libmessaging-menu0.symbols'
--- debian/libmessaging-menu0.symbols 2012-09-01 10:35:36 +0000
+++ debian/libmessaging-menu0.symbols 2013-04-26 16:57:25 +0000
@@ -1,9 +1,11 @@
1libmessaging-menu.so.0 libmessaging-menu0 #MINVER#1libmessaging-menu.so.0 libmessaging-menu0 #MINVER#
2 messaging_menu_app_append_message@Base 12.10.6-0ubuntu1phablet1
2 messaging_menu_app_append_source@Base 12.10.03 messaging_menu_app_append_source@Base 12.10.0
3 messaging_menu_app_append_source_with_count@Base 12.10.04 messaging_menu_app_append_source_with_count@Base 12.10.0
4 messaging_menu_app_append_source_with_string@Base 12.10.05 messaging_menu_app_append_source_with_string@Base 12.10.0
5 messaging_menu_app_append_source_with_time@Base 12.10.06 messaging_menu_app_append_source_with_time@Base 12.10.0
6 messaging_menu_app_draw_attention@Base 12.10.07 messaging_menu_app_draw_attention@Base 12.10.0
8 messaging_menu_app_get_message@Base 0replaceme
7 messaging_menu_app_get_type@Base 12.10.09 messaging_menu_app_get_type@Base 12.10.0
8 messaging_menu_app_has_source@Base 12.10.010 messaging_menu_app_has_source@Base 12.10.0
9 messaging_menu_app_insert_source@Base 12.10.011 messaging_menu_app_insert_source@Base 12.10.0
@@ -13,6 +15,8 @@
13 messaging_menu_app_new@Base 12.10.015 messaging_menu_app_new@Base 12.10.0
14 messaging_menu_app_register@Base 12.10.016 messaging_menu_app_register@Base 12.10.0
15 messaging_menu_app_remove_attention@Base 12.10.017 messaging_menu_app_remove_attention@Base 12.10.0
18 messaging_menu_app_remove_message@Base 12.10.6-0ubuntu1phablet1
19 messaging_menu_app_remove_message_by_id@Base 12.10.6-0ubuntu1phablet1
16 messaging_menu_app_remove_source@Base 12.10.020 messaging_menu_app_remove_source@Base 12.10.0
17 messaging_menu_app_set_source_count@Base 12.10.021 messaging_menu_app_set_source_count@Base 12.10.0
18 messaging_menu_app_set_source_icon@Base 12.10.222 messaging_menu_app_set_source_icon@Base 12.10.2
@@ -21,3 +25,14 @@
21 messaging_menu_app_set_source_time@Base 12.10.025 messaging_menu_app_set_source_time@Base 12.10.0
22 messaging_menu_app_set_status@Base 12.10.026 messaging_menu_app_set_status@Base 12.10.0
23 messaging_menu_app_unregister@Base 12.10.027 messaging_menu_app_unregister@Base 12.10.0
28 messaging_menu_message_add_action@Base 12.10.6-0ubuntu1phablet3
29 messaging_menu_message_get_body@Base 12.10.6-0ubuntu1phablet1
30 messaging_menu_message_get_draws_attention@Base 12.10.6-0ubuntu1phablet1
31 messaging_menu_message_get_icon@Base 12.10.6-0ubuntu1phablet1
32 messaging_menu_message_get_id@Base 12.10.6-0ubuntu1phablet1
33 messaging_menu_message_get_subtitle@Base 12.10.6-0ubuntu1phablet1
34 messaging_menu_message_get_time@Base 12.10.6-0ubuntu1phablet1
35 messaging_menu_message_get_title@Base 12.10.6-0ubuntu1phablet1
36 messaging_menu_message_get_type@Base 12.10.6-0ubuntu1phablet1
37 messaging_menu_message_new@Base 12.10.6-0ubuntu1phablet1
38 messaging_menu_message_set_draws_attention@Base 12.10.6-0ubuntu1phablet1
2439
=== added directory 'debian/source'
=== added file 'debian/source/format'
--- debian/source/format 1970-01-01 00:00:00 +0000
+++ debian/source/format 2013-04-26 16:57:25 +0000
@@ -0,0 +1,1 @@
11.0
02
=== modified file 'doc/reference/Makefile.am'
--- doc/reference/Makefile.am 2013-01-22 20:23:57 +0000
+++ doc/reference/Makefile.am 2013-04-26 16:57:25 +0000
@@ -11,8 +11,7 @@
11CFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.c11CFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.c
1212
13IGNORE_HFILES= \13IGNORE_HFILES= \
14 indicator-messages-service.h \14 indicator-messages-service.h
15 gtupleaction.h
1615
17INCLUDES=-I$(top_srcdir)/libmessaging-menu $(GIO_CFLAGS)16INCLUDES=-I$(top_srcdir)/libmessaging-menu $(GIO_CFLAGS)
18GTKDOC_LIBS=$(top_builddir)/libmessaging-menu/libmessaging-menu.la17GTKDOC_LIBS=$(top_builddir)/libmessaging-menu/libmessaging-menu.la
1918
=== modified file 'doc/reference/messaging-menu-docs.xml.in'
--- doc/reference/messaging-menu-docs.xml.in 2012-08-29 11:27:54 +0000
+++ doc/reference/messaging-menu-docs.xml.in 2013-04-26 16:57:25 +0000
@@ -18,7 +18,8 @@
1818
19 <chapter>19 <chapter>
20 <title>API Reference</title>20 <title>API Reference</title>
21 <xi:include href="xml/messaging-menu.xml"/>21 <xi:include href="xml/messaging-menu-app.xml" />
22 <xi:include href="xml/messaging-menu-message.xml" />
22 </chapter>23 </chapter>
2324
24 <chapter id="object-tree">25 <chapter id="object-tree">
2526
=== modified file 'libmessaging-menu/Makefile.am'
--- libmessaging-menu/Makefile.am 2012-09-01 08:27:34 +0000
+++ libmessaging-menu/Makefile.am 2013-04-26 16:57:25 +0000
@@ -4,36 +4,25 @@
4libmessaging_menu_ladir = $(includedir)/messaging-menu4libmessaging_menu_ladir = $(includedir)/messaging-menu
55
6libmessaging_menu_la_SOURCES = \6libmessaging_menu_la_SOURCES = \
7 messaging-menu.c \7 messaging-menu-app.c \
8 gtupleaction.c \8 messaging-menu-message.c
9 gtupleaction.h \
10 $(BUILT_SOURCES)
119
12libmessaging_menu_la_HEADERS = \10libmessaging_menu_la_HEADERS = \
13 messaging-menu.h11 messaging-menu-app.h \
12 messaging-menu.h \
13 messaging-menu-message.h
1414
15libmessaging_menu_la_LIBADD = $(GIO_LIBS)15libmessaging_menu_la_LIBADD = \
16 $(GIO_LIBS) \
17 $(top_builddir)/common/libmessaging-common.la
1618
17libmessaging_menu_la_CFLAGS = \19libmessaging_menu_la_CFLAGS = \
20 -I$(top_builddir)/common \
18 $(GIO_CFLAGS) \21 $(GIO_CFLAGS) \
19 -Wall22 -Wall
2023
21libmessaging_menu_la_LDFLAGS = -export-symbols-regex "^messaging_menu_.*"24libmessaging_menu_la_LDFLAGS = -export-symbols-regex "^messaging_menu_.*"
2225
23BUILT_SOURCES = \
24 indicator-messages-service.c \
25 indicator-messages-service.h
26
27CLEANFILES = $(BUILT_SOURCES)
28
29indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
30 $(AM_V_GEN) gdbus-codegen \
31 --interface-prefix com.canonical.indicator.messages. \
32 --generate-c-code indicator-messages-service \
33 --c-namespace IndicatorMessages \
34 $^
35indicator-messages-service.h: indicator-messages-service.c
36
37pkgconfigdir = $(libdir)/pkgconfig26pkgconfigdir = $(libdir)/pkgconfig
38pkgconfig_DATA = messaging-menu.pc27pkgconfig_DATA = messaging-menu.pc
3928
@@ -52,7 +41,11 @@
52MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS)41MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS)
53MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h"42MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h"
54MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la43MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la
55MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h44MessagingMenu_1_0_gir_FILES = \
45 messaging-menu-app.c \
46 messaging-menu-app.h \
47 messaging-menu-message.c \
48 messaging-menu-message.h
56MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu49MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu
57INTROSPECTION_GIRS += MessagingMenu-1.0.gir50INTROSPECTION_GIRS += MessagingMenu-1.0.gir
5851
@@ -62,5 +55,5 @@
62typelibdir = $(libdir)/girepository-1.055typelibdir = $(libdir)/girepository-1.0
63typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)56typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
6457
65CLEANFILES +=$(gir_DATA) $(typelib_DATA)58CLEANFILES = $(gir_DATA) $(typelib_DATA)
66endif59endif
6760
=== removed file 'libmessaging-menu/gtupleaction.c'
--- libmessaging-menu/gtupleaction.c 2012-08-20 21:09:54 +0000
+++ libmessaging-menu/gtupleaction.c 1970-01-01 00:00:00 +0000
@@ -1,354 +0,0 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "gtupleaction.h"
21
22typedef GObjectClass GTupleActionClass;
23
24struct _GTupleAction
25{
26 GObject parent;
27
28 gchar *name;
29 GVariantType *type;
30 gboolean enabled;
31
32 gsize n_children;
33 GVariant **children;
34};
35
36static void action_interface_init (GActionInterface *iface);
37
38G_DEFINE_TYPE_WITH_CODE (GTupleAction, g_tuple_action, G_TYPE_OBJECT,
39 G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_interface_init));
40
41enum
42{
43 PROP_0,
44 PROP_NAME,
45 PROP_PARAMETER_TYPE,
46 PROP_ENABLED,
47 PROP_STATE_TYPE,
48 PROP_STATE,
49 N_PROPERTIES
50};
51
52enum
53{
54 SIGNAL_ACTIVATE,
55 N_SIGNALS
56};
57
58static GParamSpec *properties[N_PROPERTIES];
59static guint signal_ids[N_SIGNALS];
60
61static const gchar *
62g_tuple_action_get_name (GAction *action)
63{
64 GTupleAction *tuple = G_TUPLE_ACTION (action);
65
66 return tuple->name;
67}
68
69static const GVariantType *
70g_tuple_action_get_parameter_type (GAction *action)
71{
72 return NULL;
73}
74
75static const GVariantType *
76g_tuple_action_get_state_type (GAction *action)
77{
78 GTupleAction *tuple = G_TUPLE_ACTION (action);
79
80 return tuple->type;
81}
82
83static GVariant *
84g_tuple_action_get_state_hint (GAction *action)
85{
86 return NULL;
87}
88
89static gboolean
90g_tuple_action_get_enabled (GAction *action)
91{
92 GTupleAction *tuple = G_TUPLE_ACTION (action);
93
94 return tuple->enabled;
95}
96
97static GVariant *
98g_tuple_action_get_state (GAction *action)
99{
100 GTupleAction *tuple = G_TUPLE_ACTION (action);
101 GVariant *result;
102
103 result = g_variant_new_tuple (tuple->children, tuple->n_children);
104 return g_variant_ref_sink (result);
105}
106
107static void
108g_tuple_action_set_state (GTupleAction *tuple,
109 GVariant *state)
110{
111 int i;
112
113 g_return_if_fail (g_variant_type_is_tuple (g_variant_get_type (state)));
114
115 if (tuple->type == NULL)
116 {
117 tuple->type = g_variant_type_copy (g_variant_get_type (state));
118 tuple->n_children = g_variant_n_children (state);
119 tuple->children = g_new0 (GVariant *, tuple->n_children);
120 }
121
122 for (i = 0; i < tuple->n_children; i++)
123 {
124 if (tuple->children[i])
125 g_variant_unref (tuple->children[i]);
126 tuple->children[i] = g_variant_get_child_value (state, i);
127 }
128
129 g_object_notify_by_pspec (G_OBJECT (tuple), properties[PROP_STATE]);
130}
131
132static void
133g_tuple_action_change_state (GAction *action,
134 GVariant *value)
135{
136 GTupleAction *tuple = G_TUPLE_ACTION (action);
137
138 g_return_if_fail (value != NULL);
139 g_return_if_fail (g_variant_is_of_type (value, tuple->type));
140
141 g_variant_ref_sink (value);
142
143 /* TODO add a change-state signal similar to GSimpleAction */
144 g_tuple_action_set_state (tuple, value);
145
146 g_variant_unref (value);
147}
148
149static void
150g_tuple_action_activate (GAction *action,
151 GVariant *parameter)
152{
153 GTupleAction *tuple = G_TUPLE_ACTION (action);
154
155 g_return_if_fail (parameter == NULL);
156
157 if (tuple->enabled)
158 g_signal_emit (tuple, signal_ids[SIGNAL_ACTIVATE], 0, NULL);
159}
160
161static void
162g_tuple_action_get_property (GObject *object,
163 guint prop_id,
164 GValue *value,
165 GParamSpec *pspec)
166{
167 GAction *action = G_ACTION (object);
168
169 switch (prop_id)
170 {
171 case PROP_NAME:
172 g_value_set_string (value, g_tuple_action_get_name (action));
173 break;
174
175 case PROP_PARAMETER_TYPE:
176 g_value_set_boxed (value, g_tuple_action_get_parameter_type (action));
177 break;
178
179 case PROP_ENABLED:
180 g_value_set_boolean (value, g_tuple_action_get_enabled (action));
181 break;
182
183 case PROP_STATE_TYPE:
184 g_value_set_boxed (value, g_tuple_action_get_state_type (action));
185 break;
186
187 case PROP_STATE:
188 g_value_take_variant (value, g_tuple_action_get_state (action));
189 break;
190
191 default:
192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193 }
194}
195
196static void
197g_tuple_action_set_property (GObject *object,
198 guint prop_id,
199 const GValue *value,
200 GParamSpec *pspec)
201{
202 GTupleAction *tuple = G_TUPLE_ACTION (object);
203
204 switch (prop_id)
205 {
206 case PROP_NAME:
207 tuple->name = g_value_dup_string (value);
208 g_object_notify_by_pspec (object, properties[PROP_NAME]);
209 break;
210
211 case PROP_ENABLED:
212 tuple->enabled = g_value_get_boolean (value);
213 g_object_notify_by_pspec (object, properties[PROP_ENABLED]);
214 break;
215
216 case PROP_STATE:
217 g_tuple_action_set_state (tuple, g_value_get_variant (value));
218 break;
219
220 default:
221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222 }
223}
224
225static void
226g_tuple_action_finalize (GObject *object)
227{
228 GTupleAction *tuple = G_TUPLE_ACTION (object);
229 int i;
230
231 g_free (tuple->name);
232 g_variant_type_free (tuple->type);
233
234 for (i = 0; i < tuple->n_children; i++)
235 g_variant_unref (tuple->children[i]);
236
237 g_free (tuple->children);
238
239 G_OBJECT_CLASS (g_tuple_action_parent_class)->finalize (object);
240}
241
242static void
243action_interface_init (GActionInterface *iface)
244{
245 iface->get_name = g_tuple_action_get_name;
246 iface->get_parameter_type = g_tuple_action_get_parameter_type;
247 iface->get_state_type = g_tuple_action_get_state_type;
248 iface->get_state_hint = g_tuple_action_get_state_hint;
249 iface->get_enabled = g_tuple_action_get_enabled;
250 iface->get_state = g_tuple_action_get_state;
251 iface->change_state = g_tuple_action_change_state;
252 iface->activate = g_tuple_action_activate;
253}
254
255static void
256g_tuple_action_class_init (GTupleActionClass *class)
257{
258 GObjectClass *object_class = G_OBJECT_CLASS (class);
259
260 object_class->get_property = g_tuple_action_get_property;
261 object_class->set_property = g_tuple_action_set_property;
262 object_class->finalize = g_tuple_action_finalize;
263
264 properties[PROP_NAME] = g_param_spec_string ("name",
265 "Name",
266 "The name of the action",
267 NULL,
268 G_PARAM_READWRITE |
269 G_PARAM_CONSTRUCT_ONLY |
270 G_PARAM_STATIC_STRINGS);
271
272 properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type",
273 "Parameter Type",
274 "The variant type passed to activate",
275 G_TYPE_VARIANT_TYPE,
276 G_PARAM_READABLE |
277 G_PARAM_STATIC_STRINGS);
278
279 properties[PROP_ENABLED] = g_param_spec_boolean ("enabled",
280 "Enabled",
281 "Whether the action can be activated",
282 TRUE,
283 G_PARAM_READWRITE |
284 G_PARAM_STATIC_STRINGS);
285
286 properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type",
287 "State Type",
288 "The variant type of the state, must be a tuple",
289 G_TYPE_VARIANT_TYPE,
290 G_PARAM_READABLE |
291 G_PARAM_STATIC_STRINGS);
292
293 properties[PROP_STATE] = g_param_spec_variant ("state",
294 "State",
295 "The state of the action",
296 G_VARIANT_TYPE_TUPLE,
297 NULL,
298 G_PARAM_READWRITE |
299 G_PARAM_STATIC_STRINGS);
300
301 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
302
303 signal_ids[SIGNAL_ACTIVATE] = g_signal_new ("activate",
304 G_TYPE_TUPLE_ACTION,
305 G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
306 0, NULL, NULL,
307 g_cclosure_marshal_VOID__VARIANT,
308 G_TYPE_NONE, 1,
309 G_TYPE_VARIANT);
310}
311
312static void
313g_tuple_action_init (GTupleAction *action)
314{
315 action->enabled = TRUE;
316}
317
318GTupleAction *
319g_tuple_action_new (const gchar *name,
320 GVariant *initial_state)
321{
322 const GVariantType *type;
323
324 g_return_val_if_fail (name != NULL, NULL);
325 g_return_val_if_fail (initial_state != NULL, NULL);
326
327 type = g_variant_get_type (initial_state);
328 g_return_val_if_fail (g_variant_type_is_tuple (type), NULL);
329
330 return g_object_new (G_TYPE_TUPLE_ACTION,
331 "name", name,
332 "state", initial_state,
333 NULL);
334}
335
336void
337g_tuple_action_set_child (GTupleAction *action,
338 gsize index,
339 GVariant *value)
340{
341 const GVariantType *type;
342
343 g_return_if_fail (G_IS_TUPLE_ACTION (action));
344 g_return_if_fail (index < action->n_children);
345 g_return_if_fail (value != NULL);
346
347 type = g_variant_get_type (value);
348 g_return_if_fail (g_variant_is_of_type (value, type));
349
350 g_variant_unref (action->children[index]);
351 action->children[index] = g_variant_ref_sink (value);
352
353 g_object_notify_by_pspec (G_OBJECT (action), properties[PROP_STATE]);
354}
3550
=== removed file 'libmessaging-menu/gtupleaction.h'
--- libmessaging-menu/gtupleaction.h 2012-06-28 14:07:17 +0000
+++ libmessaging-menu/gtupleaction.h 1970-01-01 00:00:00 +0000
@@ -1,40 +0,0 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __g_tuple_action_h__
21#define __g_tuple_action_h__
22
23#include <gio/gio.h>
24
25#define G_TYPE_TUPLE_ACTION (g_tuple_action_get_type ())
26#define G_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TUPLE_ACTION, GTupleAction))
27#define G_IS_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TUPLE_ACTION))
28
29typedef struct _GTupleAction GTupleAction;
30
31GType g_tuple_action_get_type (void) G_GNUC_CONST;
32
33GTupleAction * g_tuple_action_new (const gchar *name,
34 GVariant *initial_state);
35
36void g_tuple_action_set_child (GTupleAction *action,
37 gsize index,
38 GVariant *value);
39
40#endif
410
=== renamed file 'libmessaging-menu/messaging-menu.c' => 'libmessaging-menu/messaging-menu-app.c'
--- libmessaging-menu/messaging-menu.c 2013-02-12 19:41:16 +0000
+++ libmessaging-menu/messaging-menu-app.c 2013-04-26 16:57:25 +0000
@@ -17,10 +17,12 @@
17 * Lars Uebernickel <lars.uebernickel@canonical.com>17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */18 */
1919
20#include "messaging-menu.h"20#include "messaging-menu-app.h"
21#include "indicator-messages-service.h"21#include "indicator-messages-service.h"
22#include "indicator-messages-application.h"
2223
23#include <gio/gdesktopappinfo.h>24#include <gio/gdesktopappinfo.h>
25#include <string.h>
2426
25/**27/**
26 * SECTION:messaging-menu28 * SECTION:messaging-menu
@@ -102,14 +104,14 @@
102 int registered; /* -1 for unknown */104 int registered; /* -1 for unknown */
103 MessagingMenuStatus status;105 MessagingMenuStatus status;
104 gboolean status_set;106 gboolean status_set;
105 GSimpleActionGroup *source_actions;
106 GMenu *menu;
107 GDBusConnection *bus;107 GDBusConnection *bus;
108108
109 GHashTable *messages;
110 GList *sources;
111 IndicatorMessagesApplication *app_interface;
112
109 IndicatorMessagesService *messages_service;113 IndicatorMessagesService *messages_service;
110 guint watch_id;114 guint watch_id;
111 guint action_export_id;
112 guint menu_export_id;
113115
114 GCancellable *cancellable;116 GCancellable *cancellable;
115};117};
@@ -133,10 +135,61 @@
133135
134static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };136static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };
135137
138typedef struct
139{
140 gchar *id;
141 GIcon *icon;
142 gchar *label;
143
144 guint32 count;
145 gint64 time;
146 gchar *string;
147 gboolean draws_attention;
148} Source;
149
136static void global_status_changed (IndicatorMessagesService *service,150static void global_status_changed (IndicatorMessagesService *service,
137 const gchar *status_str,151 const gchar *status_str,
138 gpointer user_data);152 gpointer user_data);
139153
154/* in messaging-menu-message.c */
155GVariant * _messaging_menu_message_to_variant (MessagingMenuMessage *msg);
156
157static void
158source_free (gpointer data)
159{
160 Source *source = data;
161
162 if (source)
163 {
164 g_free (source->id);
165 g_clear_object (&source->icon);
166 g_free (source->label);
167 g_free (source->string);
168 g_slice_free (Source, source);
169 }
170}
171
172static GVariant *
173source_to_variant (Source *source)
174{
175 GVariant *v;
176 gchar *iconstr;
177
178 iconstr = source->icon ? g_icon_to_string (source->icon) : NULL;
179
180 v = g_variant_new ("(sssuxsb)", source->id,
181 source->label,
182 iconstr ? iconstr : "",
183 source->count,
184 source->time,
185 source->string ? source->string : "",
186 source->draws_attention);
187
188 g_free (iconstr);
189
190 return v;
191}
192
140static gchar *193static gchar *
141messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app)194messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app)
142{195{
@@ -155,18 +208,14 @@
155}208}
156209
157static void210static void
158export_menus_and_actions (GObject *source,211messaging_menu_app_got_bus (GObject *source,
159 GAsyncResult *res,212 GAsyncResult *res,
160 gpointer user_data)213 gpointer user_data)
161{214{
162 MessagingMenuApp *app = user_data;215 MessagingMenuApp *app = user_data;
163 GError *error = NULL;216 GError *error = NULL;
164 gchar *object_path;217 gchar *object_path;
165218
166 object_path = messaging_menu_app_get_dbus_object_path (app);
167 if (!object_path)
168 return;
169
170 app->bus = g_bus_get_finish (res, &error);219 app->bus = g_bus_get_finish (res, &error);
171 if (app->bus == NULL)220 if (app->bus == NULL)
172 {221 {
@@ -175,23 +224,13 @@
175 return;224 return;
176 }225 }
177226
178 app->action_export_id = g_dbus_connection_export_action_group (app->bus,227 object_path = messaging_menu_app_get_dbus_object_path (app);
179 object_path,
180 G_ACTION_GROUP (app->source_actions),
181 &error);
182 if (!app->action_export_id)
183 {
184 g_warning ("unable to export action group: %s", error->message);
185 g_clear_error (&error);
186 }
187228
188 app->menu_export_id = g_dbus_connection_export_menu_model (app->bus,229 if (object_path &&
189 object_path,230 !g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (app->app_interface),
190 G_MENU_MODEL (app->menu),231 app->bus, object_path, &error))
191 &error);
192 if (!app->menu_export_id)
193 {232 {
194 g_warning ("unable to export menu: %s", error->message);233 g_warning ("unable to export application interface: %s", error->message);
195 g_clear_error (&error);234 g_clear_error (&error);
196 }235 }
197236
@@ -214,7 +253,7 @@
214253
215 g_bus_get (G_BUS_TYPE_SESSION,254 g_bus_get (G_BUS_TYPE_SESSION,
216 app->cancellable,255 app->cancellable,
217 export_menus_and_actions,256 messaging_menu_app_got_bus,
218 app);257 app);
219}258}
220259
@@ -248,20 +287,6 @@
248{287{
249 MessagingMenuApp *app = MESSAGING_MENU_APP (object);288 MessagingMenuApp *app = MESSAGING_MENU_APP (object);
250289
251 if (app->bus)
252 {
253 if (app->action_export_id > 0)
254 g_dbus_connection_unexport_action_group (app->bus, app->action_export_id);
255
256 if (app->menu_export_id > 0)
257 g_dbus_connection_unexport_menu_model (app->bus, app->menu_export_id);
258
259 app->action_export_id = 0;
260 app->menu_export_id = 0;
261 g_object_unref (app->bus);
262 app->bus = NULL;
263 }
264
265 if (app->watch_id > 0)290 if (app->watch_id > 0)
266 {291 {
267 g_bus_unwatch_name (app->watch_id);292 g_bus_unwatch_name (app->watch_id);
@@ -283,9 +308,14 @@
283 g_clear_object (&app->messages_service);308 g_clear_object (&app->messages_service);
284 }309 }
285310
311 g_clear_pointer (&app->messages, g_hash_table_unref);
312
313 g_list_free_full (app->sources, source_free);
314 app->sources = NULL;
315
316 g_clear_object (&app->app_interface);
286 g_clear_object (&app->appinfo);317 g_clear_object (&app->appinfo);
287 g_clear_object (&app->source_actions);318 g_clear_object (&app->bus);
288 g_clear_object (&app->menu);
289319
290 G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object);320 G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object);
291}321}
@@ -416,6 +446,168 @@
416 }446 }
417}447}
418448
449static gboolean
450messaging_menu_app_list_sources (IndicatorMessagesApplication *app_interface,
451 GDBusMethodInvocation *invocation,
452 gpointer user_data)
453{
454 MessagingMenuApp *app = user_data;
455 GVariantBuilder builder;
456 GList *it;
457
458 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssuxsb)"));
459
460 for (it = app->sources; it; it = it->next)
461 g_variant_builder_add_value (&builder, source_to_variant (it->data));
462
463 indicator_messages_application_complete_list_sources (app_interface,
464 invocation,
465 g_variant_builder_end (&builder));
466
467 return TRUE;
468}
469
470static gint
471compare_source_id (gconstpointer a,
472 gconstpointer b)
473{
474 const Source *source = a;
475 const gchar *id = b;
476
477 return strcmp (source->id, id);
478}
479
480static gboolean
481messaging_menu_app_remove_source_internal (MessagingMenuApp *app,
482 const gchar *source_id)
483{
484 GList *node;
485
486 node = g_list_find_custom (app->sources, source_id, compare_source_id);
487 if (node)
488 {
489 source_free (node->data);
490 app->sources = g_list_delete_link (app->sources, node);
491 return TRUE;
492 }
493
494 return FALSE;
495}
496
497static gboolean
498messaging_menu_app_remove_message_internal (MessagingMenuApp *app,
499 const gchar *message_id)
500{
501 return g_hash_table_remove (app->messages, message_id);
502}
503
504static gboolean
505messaging_menu_app_activate_source (IndicatorMessagesApplication *app_interface,
506 GDBusMethodInvocation *invocation,
507 const gchar *source_id,
508 gpointer user_data)
509{
510 MessagingMenuApp *app = user_data;
511 GQuark q = g_quark_from_string (source_id);
512
513 /* Activate implies removing the source, no need for SourceRemoved */
514 if (messaging_menu_app_remove_source_internal (app, source_id))
515 g_signal_emit (app, signals[ACTIVATE_SOURCE], q, source_id);
516
517 indicator_messages_application_complete_activate_source (app_interface, invocation);
518
519 return TRUE;
520}
521
522static gboolean
523messaging_menu_app_list_messages (IndicatorMessagesApplication *app_interface,
524 GDBusMethodInvocation *invocation,
525 gpointer user_data)
526{
527 MessagingMenuApp *app = user_data;
528 GVariantBuilder builder;
529 GHashTableIter iter;
530 MessagingMenuMessage *message;
531
532 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssssxaa{sv}b)"));
533
534 g_hash_table_iter_init (&iter, app->messages);
535 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &message))
536 g_variant_builder_add_value (&builder, _messaging_menu_message_to_variant (message));
537
538 indicator_messages_application_complete_list_messages (app_interface,
539 invocation,
540 g_variant_builder_end (&builder));
541
542 return TRUE;
543}
544
545static gboolean
546messaging_menu_app_activate_message (IndicatorMessagesApplication *app_interface,
547 GDBusMethodInvocation *invocation,
548 const gchar *message_id,
549 const gchar *action_id,
550 GVariant *params,
551 gpointer user_data)
552{
553 MessagingMenuApp *app = user_data;
554 MessagingMenuMessage *msg;
555
556 msg = g_hash_table_lookup (app->messages, message_id);
557 if (msg)
558 {
559 if (*action_id)
560 {
561 gchar *signal;
562
563 signal = g_strconcat ("activate::", action_id, NULL);
564
565 if (g_variant_n_children (params))
566 {
567 GVariant *param;
568
569 g_variant_get_child (params, 0, "v", &param);
570 g_signal_emit_by_name (msg, signal, action_id, param);
571
572 g_variant_unref (param);
573 }
574 else
575 g_signal_emit_by_name (msg, signal, action_id, NULL);
576
577 g_free (signal);
578 }
579 else
580 g_signal_emit_by_name (msg, "activate", NULL, NULL);
581
582
583 /* Activate implies removing the message, no need for MessageRemoved */
584 messaging_menu_app_remove_message_internal (app, message_id);
585 }
586
587 indicator_messages_application_complete_activate_message (app_interface, invocation);
588
589 return TRUE;
590}
591
592static gboolean
593messaging_menu_app_dismiss (IndicatorMessagesApplication *app_interface,
594 GDBusMethodInvocation *invocation,
595 const gchar * const *sources,
596 const gchar * const *messages,
597 gpointer user_data)
598{
599 MessagingMenuApp *app = user_data;
600 const gchar * const *it;
601
602 for (it = sources; *it; it++)
603 messaging_menu_app_remove_source_internal (app, *it);
604
605 for (it = messages; *it; it++)
606 messaging_menu_app_remove_message_internal (app, *it);
607
608 return TRUE;
609}
610
419static void611static void
420messaging_menu_app_init (MessagingMenuApp *app)612messaging_menu_app_init (MessagingMenuApp *app)
421{613{
@@ -423,15 +615,21 @@
423 app->status_set = FALSE;615 app->status_set = FALSE;
424 app->bus = NULL;616 app->bus = NULL;
425617
426 app->action_export_id = 0;618 app->cancellable = g_cancellable_new ();
427 app->menu_export_id = 0;619
428620 app->app_interface = indicator_messages_application_skeleton_new ();
429 app->cancellable = g_cancellable_new ();621 g_signal_connect (app->app_interface, "handle-list-sources",
430622 G_CALLBACK (messaging_menu_app_list_sources), app);
431 app->source_actions = g_simple_action_group_new ();623 g_signal_connect (app->app_interface, "handle-activate-source",
432 app->menu = g_menu_new ();624 G_CALLBACK (messaging_menu_app_activate_source), app);
433625 g_signal_connect (app->app_interface, "handle-list-messages",
434 app->cancellable = g_cancellable_new ();626 G_CALLBACK (messaging_menu_app_list_messages), app);
627 g_signal_connect (app->app_interface, "handle-activate-message",
628 G_CALLBACK (messaging_menu_app_activate_message), app);
629 g_signal_connect (app->app_interface, "handle-dismiss",
630 G_CALLBACK (messaging_menu_app_dismiss), app);
631
632 app->messages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
435633
436 app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,634 app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
437 "com.canonical.indicator.messages",635 "com.canonical.indicator.messages",
@@ -604,49 +802,65 @@
604 g_signal_emit (app, signals[STATUS_CHANGED], 0, status);802 g_signal_emit (app, signals[STATUS_CHANGED], 0, status);
605}803}
606804
607static void805static Source *
608source_action_activated (GSimpleAction *action,806messaging_menu_app_lookup_source (MessagingMenuApp *app,
609 GVariant *parameter,807 const gchar *id)
610 gpointer user_data)808{
611{809 GList *node;
612 MessagingMenuApp *app = user_data;810
613 const gchar *name = g_action_get_name (G_ACTION (action));811 node = g_list_find_custom (app->sources, id, compare_source_id);
614 GQuark q = g_quark_from_string (name);812
615813 return node ? node->data : NULL;
616 messaging_menu_app_remove_source (app, name);814}
617815
618 g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name);816static Source *
619}817messaging_menu_app_get_source (MessagingMenuApp *app,
620818 const gchar *id)
621static void819{
622messaging_menu_app_insert_source_action (MessagingMenuApp *app,820 Source *source;
623 gint position,821
624 const gchar *id,822 source = messaging_menu_app_lookup_source (app, id);
625 GIcon *icon,823 if (!source)
626 const gchar *label,824 g_warning ("a source with id '%s' doesn't exist", id);
627 GVariant *state)825
628{826 return source;
629 GSimpleAction *action;827}
630 GMenuItem *menuitem;828
829static void
830messaging_menu_app_notify_source_changed (MessagingMenuApp *app,
831 Source *source)
832{
833 indicator_messages_application_emit_source_changed (app->app_interface,
834 source_to_variant (source));
835}
836
837static void
838messaging_menu_app_insert_source_internal (MessagingMenuApp *app,
839 gint position,
840 const gchar *id,
841 GIcon *icon,
842 const gchar *label,
843 guint count,
844 gint64 time,
845 const gchar *string)
846{
847 Source *source;
631848
632 g_return_if_fail (MESSAGING_MENU_IS_APP (app));849 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
633 g_return_if_fail (id != NULL);850 g_return_if_fail (id != NULL);
851 g_return_if_fail (label != NULL);
634852
635 if (g_simple_action_group_lookup (app->source_actions, id))853 if (messaging_menu_app_lookup_source (app, id))
636 {854 {
637 g_warning ("a source with id '%s' already exists", id);855 g_warning ("a source with id '%s' already exists", id);
638 return;856 return;
639 }857 }
640858
641 action = g_simple_action_new_stateful (id, NULL, state);859 source = g_slice_new0 (Source);
642 g_signal_connect (action, "activate",860 source->id = g_strdup (id);
643 G_CALLBACK (source_action_activated), app);861 source->label = g_strdup (label);
644 g_simple_action_group_insert (app->source_actions, G_ACTION (action));
645 g_object_unref (action);
646
647 menuitem = g_menu_item_new (label, id);
648 g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem");
649 if (icon)862 if (icon)
863<<<<<<< TREE
650 {864 {
651 gchar *iconstr = g_icon_to_string (icon);865 gchar *iconstr = g_icon_to_string (icon);
652 g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr);866 g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr);
@@ -721,6 +935,17 @@
721 g_simple_action_set_state (action, new_state);935 g_simple_action_set_state (action, new_state);
722936
723 g_variant_unref (state);937 g_variant_unref (state);
938=======
939 source->icon = g_object_ref (icon);
940 source->count = count;
941 source->time = time;
942 source->string = g_strdup (string);
943 app->sources = g_list_insert (app->sources, source, position);
944
945 indicator_messages_application_emit_source_added (app->app_interface,
946 position,
947 source_to_variant (source));
948>>>>>>> MERGE-SOURCE
724}949}
725950
726/**951/**
@@ -797,8 +1022,7 @@
797 const gchar *label,1022 const gchar *label,
798 guint count)1023 guint count)
799{1024{
800 messaging_menu_app_insert_source_action (app, position, id, icon, label,1025 messaging_menu_app_insert_source_internal (app, position, id, icon, label, count, 0, "");
801 g_variant_new ("(uxsb)", count, 0, "", FALSE));
802}1026}
8031027
804/**1028/**
@@ -852,8 +1076,7 @@
852 const gchar *label,1076 const gchar *label,
853 gint64 time)1077 gint64 time)
854{1078{
855 messaging_menu_app_insert_source_action (app, position, id, icon, label,1079 messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, time, "");
856 g_variant_new ("(uxsb)", 0, time, "", FALSE));
857}1080}
8581081
859/**1082/**
@@ -909,8 +1132,7 @@
909 const gchar *label,1132 const gchar *label,
910 const gchar *str)1133 const gchar *str)
911{1134{
912 messaging_menu_app_insert_source_action (app, position, id, icon, label,1135 messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, 0, str);
913 g_variant_new ("(uxsb)", 0, 0, str, FALSE));
914}1136}
9151137
916/**1138/**
@@ -950,34 +1172,11 @@
950messaging_menu_app_remove_source (MessagingMenuApp *app,1172messaging_menu_app_remove_source (MessagingMenuApp *app,
951 const gchar *source_id)1173 const gchar *source_id)
952{1174{
953 int n_items;
954 int i;
955
956 g_return_if_fail (MESSAGING_MENU_IS_APP (app));1175 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
957 g_return_if_fail (source_id != NULL);1176 g_return_if_fail (source_id != NULL);
9581177
959 if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL)1178 if (messaging_menu_app_remove_source_internal (app, source_id))
960 return;1179 indicator_messages_application_emit_source_removed (app->app_interface, source_id);
961
962 n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu));
963 for (i = 0; i < n_items; i++)
964 {
965 gchar *action;
966
967 if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i,
968 "action", "s", &action))
969 {
970 if (!g_strcmp0 (action, source_id))
971 {
972 g_menu_remove (app->menu, i);
973 break;
974 }
975
976 g_free (action);
977 }
978 }
979
980 g_simple_action_group_remove (app->source_actions, source_id);
981}1180}
9821181
983/**1182/**
@@ -994,46 +1193,7 @@
994 g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE);1193 g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE);
995 g_return_val_if_fail (source_id != NULL, FALSE);1194 g_return_val_if_fail (source_id != NULL, FALSE);
9961195
997 return g_simple_action_group_lookup (app->source_actions, source_id) != NULL;1196 return messaging_menu_app_lookup_source (app, source_id) != NULL;
998}
999
1000static GMenuItem *
1001g_menu_find_item_with_action (GMenu *menu,
1002 const gchar *action,
1003 gint *out_pos)
1004{
1005 gint i;
1006 gint n_elements;
1007 GMenuItem *item = NULL;
1008
1009 n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu));
1010
1011 for (i = 0; i < n_elements && item == NULL; i++)
1012 {
1013 GVariant *attr;
1014
1015 item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
1016 attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING);
1017
1018 if (!g_str_equal (action, g_variant_get_string (attr, NULL)))
1019 g_clear_object (&item);
1020
1021 g_variant_unref (attr);
1022 }
1023
1024 if (item && out_pos)
1025 *out_pos = i - 1;
1026
1027 return item;
1028}
1029
1030static void
1031g_menu_replace_item (GMenu *menu,
1032 gint pos,
1033 GMenuItem *item)
1034{
1035 g_menu_remove (menu, pos);
1036 g_menu_insert_item (menu, pos, item);
1037}1197}
10381198
1039/**1199/**
@@ -1049,21 +1209,19 @@
1049 const gchar *source_id,1209 const gchar *source_id,
1050 const gchar *label)1210 const gchar *label)
1051{1211{
1052 gint pos;1212 Source *source;
1053 GMenuItem *item;
10541213
1055 g_return_if_fail (MESSAGING_MENU_IS_APP (app));1214 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1056 g_return_if_fail (source_id != NULL);1215 g_return_if_fail (source_id != NULL);
1057 g_return_if_fail (label != NULL);1216 g_return_if_fail (label != NULL);
10581217
1059 item = g_menu_find_item_with_action (app->menu, source_id, &pos);1218 source = messaging_menu_app_get_source (app, source_id);
1060 if (item == NULL)1219 if (source)
1061 return;1220 {
10621221 g_free (source->label);
1063 g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label);1222 source->label = g_strdup (label);
1064 g_menu_replace_item (app->menu, pos, item);1223 messaging_menu_app_notify_source_changed (app, source);
10651224 }
1066 g_object_unref (item);
1067}1225}
10681226
1069/**1227/**
@@ -1079,33 +1237,19 @@
1079 const gchar *source_id,1237 const gchar *source_id,
1080 GIcon *icon)1238 GIcon *icon)
1081{1239{
1082 gint pos;1240 Source *source;
1083 GMenuItem *item;
10841241
1085 g_return_if_fail (MESSAGING_MENU_IS_APP (app));1242 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1086 g_return_if_fail (source_id != NULL);1243 g_return_if_fail (source_id != NULL);
10871244
1088 item = g_menu_find_item_with_action (app->menu, source_id, &pos);1245 source = messaging_menu_app_get_source (app, source_id);
1089 if (item == NULL)1246 if (source)
1090 return;1247 {
10911248 g_clear_object (&source->icon);
1092 if (icon)1249 if (icon)
1093 {1250 source->icon = g_object_ref (icon);
1094 gchar *iconstr;1251 messaging_menu_app_notify_source_changed (app, source);
10951252 }
1096 iconstr = g_icon_to_string (icon);
1097 g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
1098
1099 g_free (iconstr);
1100 }
1101 else
1102 {
1103 g_menu_item_set_attribute_value (item, "x-canonical-icon", NULL);
1104 }
1105
1106 g_menu_replace_item (app->menu, pos, item);
1107
1108 g_object_unref (item);
1109}1253}
11101254
1111/**1255/**
@@ -1120,7 +1264,17 @@
1120 const gchar *source_id,1264 const gchar *source_id,
1121 guint count)1265 guint count)
1122{1266{
1123 messaging_menu_app_set_source_action (app, source_id, count, 0, "");1267 Source *source;
1268
1269 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1270 g_return_if_fail (source_id != NULL);
1271
1272 source = messaging_menu_app_get_source (app, source_id);
1273 if (source)
1274 {
1275 source->count = count;
1276 messaging_menu_app_notify_source_changed (app, source);
1277 }
1124}1278}
11251279
1126/**1280/**
@@ -1136,7 +1290,17 @@
1136 const gchar *source_id,1290 const gchar *source_id,
1137 gint64 time)1291 gint64 time)
1138{1292{
1139 messaging_menu_app_set_source_action (app, source_id, 0, time, "");1293 Source *source;
1294
1295 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1296 g_return_if_fail (source_id != NULL);
1297
1298 source = messaging_menu_app_get_source (app, source_id);
1299 if (source)
1300 {
1301 source->time = time;
1302 messaging_menu_app_notify_source_changed (app, source);
1303 }
1140}1304}
11411305
1142/**1306/**
@@ -1152,7 +1316,18 @@
1152 const gchar *source_id,1316 const gchar *source_id,
1153 const gchar *str)1317 const gchar *str)
1154{1318{
1155 messaging_menu_app_set_source_action (app, source_id, 0, 0, str);1319 Source *source;
1320
1321 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1322 g_return_if_fail (source_id != NULL);
1323
1324 source = messaging_menu_app_get_source (app, source_id);
1325 if (source)
1326 {
1327 g_free (source->string);
1328 source->string = g_strdup (str);
1329 messaging_menu_app_notify_source_changed (app, source);
1330 }
1156}1331}
11571332
1158/**1333/**
@@ -1170,7 +1345,17 @@
1170messaging_menu_app_draw_attention (MessagingMenuApp *app,1345messaging_menu_app_draw_attention (MessagingMenuApp *app,
1171 const gchar *source_id)1346 const gchar *source_id)
1172{1347{
1173 messaging_menu_app_set_draws_attention (app, source_id, TRUE);1348 Source *source;
1349
1350 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1351 g_return_if_fail (source_id != NULL);
1352
1353 source = messaging_menu_app_get_source (app, source_id);
1354 if (source)
1355 {
1356 source->draws_attention = TRUE;
1357 messaging_menu_app_notify_source_changed (app, source);
1358 }
1174}1359}
11751360
1176/**1361/**
@@ -1191,5 +1376,135 @@
1191messaging_menu_app_remove_attention (MessagingMenuApp *app,1376messaging_menu_app_remove_attention (MessagingMenuApp *app,
1192 const gchar *source_id)1377 const gchar *source_id)
1193{1378{
1379<<<<<<< TREE
1194 messaging_menu_app_set_draws_attention (app, source_id, FALSE);1380 messaging_menu_app_set_draws_attention (app, source_id, FALSE);
1381=======
1382 Source *source;
1383
1384 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1385 g_return_if_fail (source_id != NULL);
1386
1387 source = messaging_menu_app_get_source (app, source_id);
1388 if (source)
1389 {
1390 source->draws_attention = FALSE;
1391 messaging_menu_app_notify_source_changed (app, source);
1392 }
1393}
1394
1395/**
1396 * messaging_menu_app_append_message:
1397 * @app: a #MessagingMenuApp
1398 * @msg: the #MessagingMenuMessage to append
1399 * @source_id: (allow-none): the source id to which @msg is added, or NULL
1400 * @notify: whether a notification bubble should be shown for this
1401 * message
1402 *
1403 * Appends @msg to the source with id @source_id of @app. The messaging
1404 * menu might not display this message immediately if other messages are
1405 * queued before this one.
1406 *
1407 * If @source_id has a count associated with it, that count will be
1408 * increased by one.
1409 *
1410 * If @source_id is %NULL, @msg won't be associated with a source.
1411 */
1412void
1413messaging_menu_app_append_message (MessagingMenuApp *app,
1414 MessagingMenuMessage *msg,
1415 const gchar *source_id,
1416 gboolean notify)
1417{
1418 const gchar *id;
1419
1420 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1421 g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
1422
1423 id = messaging_menu_message_get_id (msg);
1424
1425 if (g_hash_table_lookup (app->messages, id))
1426 {
1427 g_warning ("a message with id '%s' already exists", id);
1428 return;
1429 }
1430
1431 g_hash_table_insert (app->messages, g_strdup (id), g_object_ref (msg));
1432 indicator_messages_application_emit_message_added (app->app_interface,
1433 _messaging_menu_message_to_variant (msg));
1434
1435 if (source_id)
1436 {
1437 Source *source;
1438
1439 source = messaging_menu_app_get_source (app, source_id);
1440 if (source && source->count >= 0)
1441 {
1442 source->count++;
1443 messaging_menu_app_notify_source_changed (app, source);
1444 }
1445 }
1446}
1447
1448/**
1449 * messaging_menu_app_get_message:
1450 * @app: a #MessagingMenuApp
1451 * @id: id of the message to retrieve
1452 *
1453 * Retrieves the message with @id, that was added with
1454 * messaging_menu_app_append_message().
1455 *
1456 * Returns: (transfer none) (allow-none): the #MessagingMenuApp with
1457 * @id, or %NULL
1458 */
1459MessagingMenuMessage *
1460messaging_menu_app_get_message (MessagingMenuApp *app,
1461 const gchar *id)
1462{
1463 g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL);
1464 g_return_val_if_fail (id != NULL, NULL);
1465
1466 return g_hash_table_lookup (app->messages, id);
1467}
1468
1469/**
1470 * messaging_menu_app_remove_message:
1471 * @app: a #MessagingMenuApp
1472 * @msg: the #MessagingMenuMessage to remove
1473 *
1474 * Removes @msg from @app.
1475 *
1476 * If @source_id has a count associated with it, that count will be
1477 * decreased by one.
1478 */
1479void
1480messaging_menu_app_remove_message (MessagingMenuApp *app,
1481 MessagingMenuMessage *msg)
1482{
1483 /* take a ref of @msg here to make sure the pointer returned by
1484 * _get_id() is valid for the duration of remove_message_by_id. */
1485 g_object_ref (msg);
1486 messaging_menu_app_remove_message_by_id (app, messaging_menu_message_get_id (msg));
1487 g_object_unref (msg);
1488}
1489
1490/**
1491 * messaging_menu_app_remove_message_by_id:
1492 * @app: a #MessagingMenuApp
1493 * @id: the unique id of @msg
1494 *
1495 * Removes the message with the id @id from @app.
1496 *
1497 * If @source_id has a count associated with it, that count will be
1498 * decreased by one.
1499 */
1500void
1501messaging_menu_app_remove_message_by_id (MessagingMenuApp *app,
1502 const gchar *id)
1503{
1504 g_return_if_fail (MESSAGING_MENU_IS_APP (app));
1505 g_return_if_fail (id != NULL);
1506
1507 if (messaging_menu_app_remove_message_internal (app, id))
1508 indicator_messages_application_emit_message_removed (app->app_interface, id);
1509>>>>>>> MERGE-SOURCE
1195}1510}
11961511
=== renamed file 'libmessaging-menu/messaging-menu.h' => 'libmessaging-menu/messaging-menu-app.h'
--- libmessaging-menu/messaging-menu.h 2012-08-31 17:19:21 +0000
+++ libmessaging-menu/messaging-menu-app.h 2013-04-26 16:57:25 +0000
@@ -17,10 +17,11 @@
17 * Lars Uebernickel <lars.uebernickel@canonical.com>17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */18 */
1919
20#ifndef __messaging_menu_h__20#ifndef __messaging_menu_app_h__
21#define __messaging_menu_h__21#define __messaging_menu_app_h__
2222
23#include <gio/gio.h>23#include <gio/gio.h>
24#include "messaging-menu-message.h"
2425
25G_BEGIN_DECLS26G_BEGIN_DECLS
2627
@@ -143,6 +144,20 @@
143void messaging_menu_app_remove_attention (MessagingMenuApp *app,144void messaging_menu_app_remove_attention (MessagingMenuApp *app,
144 const gchar *source_id);145 const gchar *source_id);
145146
147void messaging_menu_app_append_message (MessagingMenuApp *app,
148 MessagingMenuMessage *msg,
149 const gchar *source_id,
150 gboolean notify);
151
152MessagingMenuMessage * messaging_menu_app_get_message (MessagingMenuApp *app,
153 const gchar *id);
154
155void messaging_menu_app_remove_message (MessagingMenuApp *app,
156 MessagingMenuMessage *msg);
157
158void messaging_menu_app_remove_message_by_id (MessagingMenuApp *app,
159 const gchar *id);
160
146G_END_DECLS161G_END_DECLS
147162
148#endif163#endif
149164
=== added file 'libmessaging-menu/messaging-menu-message.c'
--- libmessaging-menu/messaging-menu-message.c 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/messaging-menu-message.c 2013-04-26 16:57:25 +0000
@@ -0,0 +1,547 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "messaging-menu-message.h"
21
22typedef GObjectClass MessagingMenuMessageClass;
23
24struct _MessagingMenuMessage
25{
26 GObject parent;
27
28 gchar *id;
29 GIcon *icon;
30 gchar *title;
31 gchar *subtitle;
32 gchar *body;
33 gint64 time;
34 gboolean draws_attention;
35
36 GSList *actions;
37};
38
39G_DEFINE_TYPE (MessagingMenuMessage, messaging_menu_message, G_TYPE_OBJECT);
40
41enum
42{
43 PROP_0,
44 PROP_ID,
45 PROP_ICON,
46 PROP_TITLE,
47 PROP_SUBTITLE,
48 PROP_BODY,
49 PROP_TIME,
50 PROP_DRAWS_ATTENTION,
51 NUM_PROPERTIES
52};
53
54static GParamSpec *properties[NUM_PROPERTIES];
55
56typedef struct
57{
58 gchar *id;
59 gchar *label;
60 GVariantType *parameter_type;
61 GVariant *parameter_hint;
62} Action;
63
64static void
65action_free (gpointer data)
66{
67 Action *action = data;
68
69 g_free (action->id);
70 g_free (action->label);
71
72 if (action->parameter_type)
73 g_variant_type_free (action->parameter_type);
74
75 if (action->parameter_hint)
76 g_variant_unref (action->parameter_hint);
77
78 g_slice_free (Action, action);
79}
80
81static void
82messaging_menu_message_dispose (GObject *object)
83{
84 MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
85
86 g_clear_object (&msg->icon);
87
88 G_OBJECT_CLASS (messaging_menu_message_parent_class)->dispose (object);
89}
90
91static void
92messaging_menu_message_finalize (GObject *object)
93{
94 MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
95
96 g_free (msg->id);
97 g_free (msg->title);
98 g_free (msg->subtitle);
99 g_free (msg->body);
100
101 g_slist_free_full (msg->actions, action_free);
102 msg->actions = NULL;
103
104 G_OBJECT_CLASS (messaging_menu_message_parent_class)->finalize (object);
105}
106
107static void
108messaging_menu_message_get_property (GObject *object,
109 guint property_id,
110 GValue *value,
111 GParamSpec *pspec)
112{
113 MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
114
115 switch (property_id)
116 {
117 case PROP_ID:
118 g_value_set_string (value, msg->id);
119 break;
120
121 case PROP_ICON:
122 g_value_set_object (value, msg->icon);
123 break;
124
125 case PROP_TITLE:
126 g_value_set_string (value, msg->title);
127 break;
128
129 case PROP_SUBTITLE:
130 g_value_set_string (value, msg->subtitle);
131 break;
132
133 case PROP_BODY:
134 g_value_set_string (value, msg->body);
135
136 case PROP_TIME:
137 g_value_set_int64 (value, msg->time);
138 break;
139
140 case PROP_DRAWS_ATTENTION:
141 g_value_set_boolean (value, msg->draws_attention);
142 break;
143
144 default:
145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
146 }
147}
148
149static void
150messaging_menu_message_set_property (GObject *object,
151 guint property_id,
152 const GValue *value,
153 GParamSpec *pspec)
154{
155 MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
156
157 switch (property_id)
158 {
159 case PROP_ID:
160 msg->id = g_value_dup_string (value);
161 break;
162
163 case PROP_ICON:
164 msg->icon = g_value_dup_object (value);
165 break;
166
167 case PROP_TITLE:
168 msg->title = g_value_dup_string (value);
169 break;
170
171 case PROP_SUBTITLE:
172 msg->subtitle = g_value_dup_string (value);
173 break;
174
175 case PROP_BODY:
176 msg->body = g_value_dup_string (value);
177
178 case PROP_TIME:
179 msg->time = g_value_get_int64 (value);
180 break;
181
182 case PROP_DRAWS_ATTENTION:
183 messaging_menu_message_set_draws_attention (msg, g_value_get_boolean (value));
184 break;
185
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
188 }
189}
190
191static void
192messaging_menu_message_class_init (MessagingMenuMessageClass *klass)
193{
194 GObjectClass *object_class = G_OBJECT_CLASS (klass);
195
196 object_class->dispose = messaging_menu_message_dispose;
197 object_class->finalize = messaging_menu_message_finalize;
198 object_class->get_property = messaging_menu_message_get_property;
199 object_class->set_property = messaging_menu_message_set_property;
200
201 properties[PROP_ID] = g_param_spec_string ("id", "Id",
202 "Unique id of the message",
203 NULL,
204 G_PARAM_CONSTRUCT_ONLY |
205 G_PARAM_READWRITE |
206 G_PARAM_STATIC_STRINGS);
207
208 properties[PROP_ICON] = g_param_spec_object ("icon", "Icon",
209 "Icon of the message",
210 G_TYPE_ICON,
211 G_PARAM_CONSTRUCT_ONLY |
212 G_PARAM_READWRITE |
213 G_PARAM_STATIC_STRINGS);
214
215 properties[PROP_TITLE] = g_param_spec_string ("title", "Title",
216 "Title of the message",
217 NULL,
218 G_PARAM_CONSTRUCT_ONLY |
219 G_PARAM_READWRITE |
220 G_PARAM_STATIC_STRINGS);
221
222 properties[PROP_SUBTITLE] = g_param_spec_string ("subtitle", "Subtitle",
223 "Subtitle of the message",
224 NULL,
225 G_PARAM_CONSTRUCT_ONLY |
226 G_PARAM_READWRITE |
227 G_PARAM_STATIC_STRINGS);
228
229 properties[PROP_BODY] = g_param_spec_string ("body", "Body",
230 "First lines of the body of the message",
231 NULL,
232 G_PARAM_CONSTRUCT_ONLY |
233 G_PARAM_READWRITE |
234 G_PARAM_STATIC_STRINGS);
235
236 properties[PROP_TIME] = g_param_spec_int64 ("time", "Time",
237 "Time the message was sent, in microseconds", 0, G_MAXINT64, 0,
238 G_PARAM_CONSTRUCT_ONLY |
239 G_PARAM_READWRITE |
240 G_PARAM_STATIC_STRINGS);
241
242 properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention", "Draws attention",
243 "Whether the message should draw attention",
244 FALSE,
245 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
246
247 g_object_class_install_properties (klass, NUM_PROPERTIES, properties);
248
249 /**
250 * MessagingMenuMessage::activate:
251 * @msg: the #MessagingMenuMessage
252 * @action: (allow-none): the id of activated action, or %NULL
253 * @parameter: (allow-none): activation parameter, or %NULL
254 *
255 * Emitted when the user has activated the message. The message is
256 * immediately removed from the application's menu, handlers of this
257 * signal do not need to call messaging_menu_app_remove_message().
258 */
259 g_signal_new ("activate",
260 MESSAGING_MENU_TYPE_MESSAGE,
261 G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
262 0,
263 NULL, NULL,
264 g_cclosure_marshal_generic,
265 G_TYPE_NONE, 2,
266 G_TYPE_STRING,
267 G_TYPE_VARIANT);
268}
269
270static void
271messaging_menu_message_init (MessagingMenuMessage *self)
272{
273}
274
275/**
276 * messaging_menu_message_new:
277 * @id: unique id of the message
278 * @icon: (transfer full) (allow-none): a #GIcon representing the message
279 * @title: the title of the message
280 * @subtitle: (allow-none): the subtitle of the message
281 * @body: (allow-none): the message body
282 * @time: the time the message was received
283 *
284 * Creates a new #MessagingMenuMessage.
285 *
286 * Returns: (transfer full): a new #MessagingMenuMessage
287 */
288MessagingMenuMessage *
289messaging_menu_message_new (const gchar *id,
290 GIcon *icon,
291 const gchar *title,
292 const gchar *subtitle,
293 const gchar *body,
294 gint64 time)
295{
296 g_return_val_if_fail (id != NULL, NULL);
297 g_return_val_if_fail (title != NULL, NULL);
298
299 return g_object_new (MESSAGING_MENU_TYPE_MESSAGE,
300 "id", id,
301 "icon", icon,
302 "title", title,
303 "subtitle", subtitle,
304 "body", body,
305 "time", time,
306 NULL);
307}
308
309/**
310 * messaging_menu_message_get_id:
311 * @msg: a #MessagingMenuMessage
312 *
313 * Returns: the unique id of @msg
314 */
315const gchar *
316messaging_menu_message_get_id (MessagingMenuMessage *msg)
317{
318 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
319
320 return msg->id;
321}
322
323/**
324 * messaging_menu_message_get_icon:
325 * @msg: a #MessagingMenuMessage
326 *
327 * Returns: (transfer none): the icon of @msg
328 */
329GIcon *
330messaging_menu_message_get_icon (MessagingMenuMessage *msg)
331{
332 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
333
334 return msg->icon;
335}
336
337/**
338 * messaging_menu_message_get_title:
339 * @msg: a #MessagingMenuMessage
340 *
341 * Returns: the title of @msg
342 */
343const gchar *
344messaging_menu_message_get_title (MessagingMenuMessage *msg)
345{
346 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
347
348 return msg->title;
349}
350
351/**
352 * messaging_menu_message_get_subtitle:
353 * @msg: a #MessagingMenuMessage
354 *
355 * Returns: the subtitle of @msg
356 */
357const gchar *
358messaging_menu_message_get_subtitle (MessagingMenuMessage *msg)
359{
360 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
361
362 return msg->subtitle;
363}
364
365/**
366 * messaging_menu_message_get_body:
367 * @msg: a #MessagingMenuMessage
368 *
369 * Returns: the body of @msg
370 */
371const gchar *
372messaging_menu_message_get_body (MessagingMenuMessage *msg)
373{
374 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
375
376 return msg->body;
377}
378
379/**
380 * messaging_menu_message_get_time:
381 * @msg: a #MessagingMenuMessage
382 *
383 * Returns: the time at which @msg was received
384 */
385gint64
386messaging_menu_message_get_time (MessagingMenuMessage *msg)
387{
388 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), 0);
389
390 return msg->time;
391}
392
393/**
394 * messaging_menu_message_get_draws_attention:
395 * @msg: a #MessagingMenuMessage
396 *
397 * Returns: whether @msg is drawing attention
398 */
399gboolean
400messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg)
401{
402 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), FALSE);
403
404 return msg->draws_attention;
405}
406
407/**
408 * messaging_menu_message_set_draws_attention:
409 * @msg: a #MessagingMenuMessage
410 * @draws_attention: whether @msg should draw attention
411 *
412 * Sets whether @msg is drawing attention.
413 */
414void
415messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
416 gboolean draws_attention)
417{
418 g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
419
420 msg->draws_attention = draws_attention;
421 g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_DRAWS_ATTENTION]);
422}
423
424/**
425 * messaging_menu_message_add_action:
426 * @msg: a #MessagingMenuMessage
427 * @id: unique id of the action
428 * @label: (allow-none): label of the action
429 * @parameter_type: (allow-none): a #GVariantType
430 * @parameter_hint: (allow-none): a #GVariant suggesting a valid range
431 * for parameters
432 *
433 * Adds an action with @id and @label to @message. Actions are an
434 * alternative way for users to activate a message. Note that messages
435 * can still be activated without an action.
436 *
437 * If @parameter_type is non-%NULL, the action is able to receive user
438 * input in addition to simply activating the action. Currently, only
439 * string parameters are supported.
440 *
441 * A list of predefined parameters can be supplied as a #GVariant array
442 * of @parameter_type in @parameter_hint. If @parameter_hint is
443 * floating, it will be consumed.
444 *
445 * It is recommended to add at most two actions to a message.
446 */
447void
448messaging_menu_message_add_action (MessagingMenuMessage *msg,
449 const gchar *id,
450 const gchar *label,
451 const GVariantType *parameter_type,
452 GVariant *parameter_hint)
453{
454 Action *action;
455
456 g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
457 g_return_if_fail (id != NULL);
458
459 action = g_slice_new (Action);
460 action->id = g_strdup (id);
461 action->label = g_strdup (label);
462 action->parameter_type = parameter_type ? g_variant_type_copy (parameter_type) : NULL;
463 action->parameter_hint = parameter_hint ? g_variant_ref_sink (parameter_hint) : NULL;
464
465 msg->actions = g_slist_append (msg->actions, action);
466}
467
468static GVariant *
469action_to_variant (Action *action)
470{
471 GVariantBuilder builder;
472
473 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
474
475 g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string (action->id));
476
477 if (action->label)
478 g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (action->label));
479
480 if (action->parameter_type)
481 {
482 gchar *type = g_variant_type_dup_string (action->parameter_type);
483 g_variant_builder_add (&builder, "{sv}", "parameter-type", g_variant_new_signature (type));
484 g_free (type);
485 }
486
487 if (action->parameter_hint)
488 g_variant_builder_add (&builder, "{sv}", "parameter-hint", action->parameter_hint);
489
490 return g_variant_builder_end (&builder);
491}
492
493/*<internal>
494 * _messaging_menu_message_to_variant:
495 * @msg: a #MessagingMenuMessage
496 *
497 * Serializes @msg to a #GVariant of the form (sssssxaa{sv}b):
498 *
499 * id
500 * icon
501 * title
502 * subtitle
503 * body
504 * time
505 * array of action dictionaries
506 * draws_attention
507 *
508 * Returns: a new floating #GVariant instance
509 */
510GVariant *
511_messaging_menu_message_to_variant (MessagingMenuMessage *msg)
512{
513 GVariantBuilder builder;
514 GSList *it;
515
516 g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
517
518 g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sssssxaa{sv}b)"));
519
520 g_variant_builder_add (&builder, "s", msg->id);
521
522 if (msg->icon)
523 {
524 gchar *iconstr;
525
526 iconstr = g_icon_to_string (msg->icon);
527 g_variant_builder_add (&builder, "s", iconstr);
528
529 g_free (iconstr);
530 }
531 else
532 g_variant_builder_add (&builder, "s", "");
533
534 g_variant_builder_add (&builder, "s", msg->title ? msg->title : "");
535 g_variant_builder_add (&builder, "s", msg->subtitle ? msg->subtitle : "");
536 g_variant_builder_add (&builder, "s", msg->body ? msg->body : "");
537 g_variant_builder_add (&builder, "x", msg->time);
538
539 g_variant_builder_open (&builder, G_VARIANT_TYPE ("aa{sv}"));
540 for (it = msg->actions; it; it = it->next)
541 g_variant_builder_add_value (&builder, action_to_variant (it->data));
542 g_variant_builder_close (&builder);
543
544 g_variant_builder_add (&builder, "b", msg->draws_attention);
545
546 return g_variant_builder_end (&builder);
547}
0548
=== added file 'libmessaging-menu/messaging-menu-message.h'
--- libmessaging-menu/messaging-menu-message.h 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/messaging-menu-message.h 2013-04-26 16:57:25 +0000
@@ -0,0 +1,70 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __messaging_menu_message_h__
21#define __messaging_menu_message_h__
22
23#include <gio/gio.h>
24
25G_BEGIN_DECLS
26
27#define MESSAGING_MENU_TYPE_MESSAGE (messaging_menu_message_get_type ())
28#define MESSAGING_MENU_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessage))
29#define MESSAGING_MENU_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass))
30#define MESSAGING_MENU_IS_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MESSAGING_MENU_TYPE_MESSAGE))
31#define MESSAGING_MENU_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGING_MENU_TYPE_MESSAGE))
32#define MESSAGING_MENU_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass))
33
34typedef struct _MessagingMenuMessage MessagingMenuMessage;
35
36GType messaging_menu_message_get_type (void) G_GNUC_CONST;
37
38MessagingMenuMessage * messaging_menu_message_new (const gchar *id,
39 GIcon *icon,
40 const gchar *title,
41 const gchar *subtitle,
42 const gchar *body,
43 gint64 time);
44
45const gchar * messaging_menu_message_get_id (MessagingMenuMessage *msg);
46
47GIcon * messaging_menu_message_get_icon (MessagingMenuMessage *msg);
48
49const gchar * messaging_menu_message_get_title (MessagingMenuMessage *msg);
50
51const gchar * messaging_menu_message_get_subtitle (MessagingMenuMessage *msg);
52
53const gchar * messaging_menu_message_get_body (MessagingMenuMessage *msg);
54
55gint64 messaging_menu_message_get_time (MessagingMenuMessage *msg);
56
57gboolean messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg);
58
59void messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
60 gboolean draws_attention);
61
62void messaging_menu_message_add_action (MessagingMenuMessage *msg,
63 const gchar *id,
64 const gchar *label,
65 const GVariantType *parameter_type,
66 GVariant *parameter_hint);
67
68G_END_DECLS
69
70#endif
071
=== added file 'libmessaging-menu/messaging-menu.h'
--- libmessaging-menu/messaging-menu.h 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/messaging-menu.h 2013-04-26 16:57:25 +0000
@@ -0,0 +1,25 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __messaging_menu_h__
21#define __messaging_menu_h__
22
23#include "messaging-menu-app.h"
24
25#endif
026
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2012-09-03 13:37:23 +0000
+++ src/Makefile.am 2013-04-26 16:57:25 +0000
@@ -1,8 +1,5 @@
11
2BUILT_SOURCES =
3EXTRA_DIST =2EXTRA_DIST =
4CLEANFILES =
5DISTCLEANFILES =
63
7libexec_PROGRAMS = indicator-messages-service4libexec_PROGRAMS = indicator-messages-service
85
@@ -23,19 +20,20 @@
23 im-source-menu-item.h \20 im-source-menu-item.h \
24 ido-detail-label.c \21 ido-detail-label.c \
25 ido-detail-label.h \22 ido-detail-label.h \
26 indicator-messages-service.c \
27 indicator-messages-service.h
28 dbus-data.h23 dbus-data.h
29libmessaging_la_CFLAGS = \24libmessaging_la_CFLAGS = \
30 $(APPLET_CFLAGS) \25 $(APPLET_CFLAGS) \
31 $(COVERAGE_CFLAGS) \26 $(COVERAGE_CFLAGS) \
27 -I$(top_builddir)/common \
32 -Wall \28 -Wall \
33 -Wl,-Bsymbolic-functions \29 -Wl,-Bsymbolic-functions \
34 -Wl,-z,defs \30 -Wl,-z,defs \
35 -Wl,--as-needed \31 -Wl,--as-needed \
36 -Werror \32 -Werror \
37 -DG_LOG_DOMAIN=\"Indicator-Messages\"33 -DG_LOG_DOMAIN=\"Indicator-Messages\"
38libmessaging_la_LIBADD = $(APPLET_LIBS) -lm34libmessaging_la_LIBADD = \
35 $(top_builddir)/common/libmessaging-common.la \
36 $(APPLET_LIBS) -lm
39libmessaging_la_LDFLAGS = \37libmessaging_la_LDFLAGS = \
40 $(COVERAGE_LDFLAGS) \38 $(COVERAGE_LDFLAGS) \
41 -module -avoid-version39 -module -avoid-version
@@ -46,8 +44,6 @@
4644
47indicator_messages_service_SOURCES = \45indicator_messages_service_SOURCES = \
48 messages-service.c \46 messages-service.c \
49 indicator-messages-service.c \
50 indicator-messages-service.h \
51 app-section.c \47 app-section.c \
52 app-section.h \48 app-section.h \
53 dbus-data.h \49 dbus-data.h \
@@ -56,11 +52,16 @@
56 gsettingsstrv.c \52 gsettingsstrv.c \
57 gsettingsstrv.h \53 gsettingsstrv.h \
58 gmenuutils.c \54 gmenuutils.c \
59 gmenuutils.h55 gmenuutils.h \
56 im-phone-menu.c \
57 im-phone-menu.h \
58 im-application-list.c \
59 im-application-list.h
6060
61indicator_messages_service_CFLAGS = \61indicator_messages_service_CFLAGS = \
62 $(APPLET_CFLAGS) \62 $(APPLET_CFLAGS) \
63 $(COVERAGE_CFLAGS) \63 $(COVERAGE_CFLAGS) \
64 -I$(top_builddir)/common \
64 -Wall \65 -Wall \
65 -Wl,-Bsymbolic-functions \66 -Wl,-Bsymbolic-functions \
66 -Wl,-z,defs \67 -Wl,-z,defs \
@@ -69,26 +70,11 @@
69 -DG_LOG_DOMAIN=\"Indicator-Messages\"70 -DG_LOG_DOMAIN=\"Indicator-Messages\"
7071
71indicator_messages_service_LDADD = \72indicator_messages_service_LDADD = \
73 $(top_builddir)/common/libmessaging-common.la \
72 $(APPLET_LIBS)74 $(APPLET_LIBS)
7375
74indicator_messages_service_LDFLAGS = \76indicator_messages_service_LDFLAGS = \
75 $(COVERAGE_LDFLAGS)77 $(COVERAGE_LDFLAGS)
7678
77indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
78 $(AM_V_GEN) gdbus-codegen \
79 --interface-prefix com.canonical.indicator.messages. \
80 --generate-c-code indicator-messages-service \
81 --c-namespace IndicatorMessages \
82 $^
83indicator-messages-service.h: indicator-messages-service.c
84
85BUILT_SOURCES += \
86 indicator-messages-service.c \
87 indicator-messages-service.h
88
89EXTRA_DIST += \79EXTRA_DIST += \
90 messages-service.xml80 messages-service.xml
91
92CLEANFILES += \
93 $(BUILT_SOURCES)
94
9581
=== modified file 'src/app-section.c'
--- src/app-section.c 2013-04-22 08:45:52 +0000
+++ src/app-section.c 2013-04-26 16:57:25 +0000
@@ -34,6 +34,7 @@
34#include "dbus-data.h"34#include "dbus-data.h"
35#include "gmenuutils.h"35#include "gmenuutils.h"
36#include "gactionmuxer.h"36#include "gactionmuxer.h"
37#include "indicator-messages-application.h"
3738
38struct _AppSectionPrivate39struct _AppSectionPrivate
39{40{
@@ -42,11 +43,14 @@
4243
43 IndicatorDesktopShortcuts * ids;44 IndicatorDesktopShortcuts * ids;
4445
46 GCancellable *app_proxy_cancellable;
47 IndicatorMessagesApplication *app_proxy;
48
45 GMenu *menu;49 GMenu *menu;
46 GMenuModel *source_menu;50 GMenu *source_menu;
4751
48 GSimpleActionGroup *static_shortcuts;52 GSimpleActionGroup *static_shortcuts;
49 GActionGroup *source_actions;53 GSimpleActionGroup *source_actions;
50 GActionMuxer *muxer;54 GActionMuxer *muxer;
5155
52 gboolean draws_attention;56 gboolean draws_attention;
@@ -90,19 +94,6 @@
90 gpointer user_data);94 gpointer user_data);
91static void app_section_set_app_info (AppSection *self,95static void app_section_set_app_info (AppSection *self,
92 GDesktopAppInfo *appinfo);96 GDesktopAppInfo *appinfo);
93static gboolean any_action_draws_attention (GActionGroup *group,
94 const gchar *ignored_action);
95static void action_added (GActionGroup *group,
96 const gchar *action_name,
97 gpointer user_data);
98static void action_state_changed (GActionGroup *group,
99 const gchar *action_name,
100 GVariant *value,
101 gpointer user_data);
102static void action_removed (GActionGroup *group,
103 const gchar *action_name,
104 gpointer user_data);
105static gboolean action_draws_attention (GVariant *state);
106static void desktop_file_changed_cb (GFileMonitor *monitor,97static void desktop_file_changed_cb (GFileMonitor *monitor,
107 GFile *file,98 GFile *file,
108 GFile *other_file,99 GFile *other_file,
@@ -170,6 +161,7 @@
170app_section_init (AppSection *self)161app_section_init (AppSection *self)
171{162{
172 AppSectionPrivate *priv;163 AppSectionPrivate *priv;
164 GMenuItem *item;
173165
174 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,166 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
175 APP_SECTION_TYPE,167 APP_SECTION_TYPE,
@@ -179,10 +171,19 @@
179 priv->appinfo = NULL;171 priv->appinfo = NULL;
180172
181 priv->menu = g_menu_new ();173 priv->menu = g_menu_new ();
174
175 priv->source_menu = g_menu_new ();
176 item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->source_menu));
177 g_menu_item_set_attribute (item, "action-namespace", "s", "source");
178 g_menu_append_item (priv->menu, item);
179 g_object_unref (item);
180
182 priv->static_shortcuts = g_simple_action_group_new ();181 priv->static_shortcuts = g_simple_action_group_new ();
182 priv->source_actions = g_simple_action_group_new ();
183183
184 priv->muxer = g_action_muxer_new ();184 priv->muxer = g_action_muxer_new ();
185 g_action_muxer_insert (priv->muxer, NULL, G_ACTION_GROUP (priv->static_shortcuts));185 g_action_muxer_insert (priv->muxer, NULL, G_ACTION_GROUP (priv->static_shortcuts));
186 g_action_muxer_insert (priv->muxer, "source", G_ACTION_GROUP (priv->source_actions));
186187
187 priv->draws_attention = FALSE;188 priv->draws_attention = FALSE;
188189
@@ -249,32 +250,30 @@
249 AppSection * self = APP_SECTION(object);250 AppSection * self = APP_SECTION(object);
250 AppSectionPrivate * priv = self->priv;251 AppSectionPrivate * priv = self->priv;
251252
253 if (priv->app_proxy_cancellable) {
254 g_cancellable_cancel (priv->app_proxy_cancellable);
255 g_clear_object (&priv->app_proxy_cancellable);
256 }
257
252 if (priv->desktop_file_monitor) {258 if (priv->desktop_file_monitor) {
253 g_signal_handlers_disconnect_by_func (priv->desktop_file_monitor, desktop_file_changed_cb, self);259 g_signal_handlers_disconnect_by_func (priv->desktop_file_monitor, desktop_file_changed_cb, self);
254 g_clear_object (&priv->desktop_file_monitor);260 g_clear_object (&priv->desktop_file_monitor);
255 }261 }
256262
263 g_clear_object (&priv->app_proxy);
264
257 g_clear_object (&priv->menu);265 g_clear_object (&priv->menu);
266 g_clear_object (&priv->source_menu);
258 g_clear_object (&priv->static_shortcuts);267 g_clear_object (&priv->static_shortcuts);
268 g_clear_object (&priv->source_actions);
259269
260 if (priv->name_watch_id) {270 if (priv->name_watch_id) {
261 g_bus_unwatch_name (priv->name_watch_id);271 g_bus_unwatch_name (priv->name_watch_id);
262 priv->name_watch_id = 0;272 priv->name_watch_id = 0;
263 }273 }
264274
265 if (priv->source_actions) {
266 g_action_muxer_remove (priv->muxer, "source");
267 g_object_disconnect (priv->source_actions,
268 "any_signal::action-added", action_added, self,
269 "any_signal::action-state-changed", action_state_changed, self,
270 "any_signal::action-removed", action_removed, self,
271 NULL);
272 g_clear_object (&priv->source_actions);
273 }
274
275 g_clear_object (&priv->muxer);275 g_clear_object (&priv->muxer);
276276
277 g_clear_object (&priv->source_menu);
278 g_clear_object (&priv->ids);277 g_clear_object (&priv->ids);
279 g_clear_object (&priv->appinfo);278 g_clear_object (&priv->appinfo);
280279
@@ -430,6 +429,11 @@
430 g_free(name);429 g_free(name);
431 }430 }
432431
432 item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->source_menu));
433 g_menu_item_set_attribute (item, "action-namespace", "s", "source");
434 g_menu_append_item (priv->menu, item);
435 g_object_unref (item);
436
433 keyfile = g_file_new_for_path (g_desktop_app_info_get_filename (priv->appinfo));437 keyfile = g_file_new_for_path (g_desktop_app_info_get_filename (priv->appinfo));
434 g_file_load_contents_async (keyfile, NULL, keyfile_loaded, self);438 g_file_load_contents_async (keyfile, NULL, keyfile_loaded, self);
435439
@@ -571,39 +575,8 @@
571void575void
572app_section_clear_draws_attention (AppSection *self)576app_section_clear_draws_attention (AppSection *self)
573{577{
574 AppSectionPrivate * priv = self->priv;578 self->priv->draws_attention = FALSE;
575 gchar **action_names;579 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
576 gchar **it;
577
578 if (priv->source_actions == NULL)
579 return;
580
581 action_names = g_action_group_list_actions (priv->source_actions);
582
583 for (it = action_names; *it; it++) {
584 GVariant *state;
585
586 state = g_action_group_get_action_state (priv->source_actions, *it);
587 if (!state)
588 continue;
589
590 /* clear draws-attention while preserving other state */
591 if (action_draws_attention (state)) {
592 guint32 count;
593 gint64 time;
594 const gchar *str;
595 GVariant *new_state;
596
597 g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
598
599 new_state = g_variant_new ("(uxsb)", count, time, str, FALSE);
600 g_action_group_change_action_state (priv->source_actions, *it, new_state);
601 }
602
603 g_variant_unref (state);
604 }
605
606 g_strfreev (action_names);
607}580}
608581
609static void582static void
@@ -616,6 +589,230 @@
616 app_section_unset_object_path (self);589 app_section_unset_object_path (self);
617}590}
618591
592static void
593update_draws_attention (AppSection *self)
594{
595 AppSectionPrivate *priv = self->priv;
596 gchar **actions;
597 gchar **it;
598 gboolean draws_attention = FALSE;
599
600 actions = g_action_group_list_actions (G_ACTION_GROUP (priv->source_actions));
601
602 for (it = actions; *it; it++) {
603 GVariant *state;
604
605 state = g_action_group_get_action_state (G_ACTION_GROUP (priv->source_actions), *it);
606 if (state) {
607 gboolean b;
608 g_variant_get (state, "(uxsb)", NULL, NULL, NULL, &b);
609 draws_attention = b || draws_attention;
610 g_variant_unref (state);
611 }
612
613 if (draws_attention)
614 break;
615 }
616
617 if (draws_attention != priv->draws_attention) {
618 priv->draws_attention = draws_attention;
619 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
620 }
621
622 g_strfreev (actions);
623}
624
625static void
626remove_source (AppSection *self,
627 const gchar *id)
628{
629 AppSectionPrivate *priv = self->priv;
630 guint n_items;
631 guint i;
632
633 n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->source_menu));
634 for (i = 0; i < n_items; i++) {
635 gchar *action;
636 gboolean found = FALSE;
637
638 if (g_menu_model_get_item_attribute (G_MENU_MODEL (priv->source_menu), i,
639 G_MENU_ATTRIBUTE_ACTION, "s", &action)) {
640 found = g_str_equal (action, id);
641 g_free (action);
642 }
643
644 if (found) {
645 g_menu_remove (priv->source_menu, i);
646 break;
647 }
648 }
649
650 g_simple_action_group_remove (priv->source_actions, id);
651 update_draws_attention (self);
652}
653
654static void
655source_action_activated (GSimpleAction *action,
656 GVariant *parameter,
657 gpointer user_data)
658{
659 AppSection *self = APP_SECTION (user_data);
660 AppSectionPrivate *priv = APP_SECTION (user_data)->priv;
661
662 g_return_if_fail (priv->app_proxy != NULL);
663
664 indicator_messages_application_call_activate_source (priv->app_proxy,
665 g_action_get_name (G_ACTION (action)),
666 priv->app_proxy_cancellable,
667 NULL, NULL);
668
669 remove_source (self, g_action_get_name (G_ACTION (action)));
670}
671
672static void
673sources_listed (GObject *source_object,
674 GAsyncResult *result,
675 gpointer user_data)
676{
677 AppSection *self = user_data;
678 AppSectionPrivate *priv = self->priv;
679 GVariant *sources = NULL;
680 GError *error = NULL;
681 GVariantIter iter;
682 const gchar *id;
683 const gchar *label;
684 const gchar *iconstr;
685 guint32 count;
686 gint64 time;
687 const gchar *string;
688 gboolean draws_attention;
689
690 if (!indicator_messages_application_call_list_sources_finish (INDICATOR_MESSAGES_APPLICATION (source_object),
691 &sources, result, &error))
692 {
693 g_warning ("could not fetch the list of sources: %s", error->message);
694 g_error_free (error);
695 return;
696 }
697
698 g_menu_clear (priv->source_menu);
699 g_simple_action_group_clear (priv->source_actions);
700 priv->draws_attention = FALSE;
701
702 g_variant_iter_init (&iter, sources);
703 while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr,
704 &count, &time, &string, &draws_attention))
705 {
706 GVariant *state;
707 GSimpleAction *action;
708 GMenuItem *item;
709
710 state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
711 action = g_simple_action_new_stateful (id, NULL, state);
712 g_signal_connect (action, "activate", G_CALLBACK (source_action_activated), self);
713 g_simple_action_group_insert (priv->source_actions, G_ACTION (action));
714
715 item = g_menu_item_new (label, id);
716 g_menu_item_set_attribute (item, "x-canonical-type", "s", "ImSourceMenuItem");
717 g_menu_append_item (priv->source_menu, item);
718
719 priv->draws_attention = priv->draws_attention || draws_attention;
720
721 g_object_unref (item);
722 g_object_unref (action);
723 }
724
725 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
726
727 g_variant_unref (sources);
728}
729
730static void
731source_added (IndicatorMessagesApplication *app,
732 const gchar *id,
733 const gchar *label,
734 const gchar *iconstr,
735 guint count,
736 gint64 time,
737 const gchar *string,
738 gboolean draws_attention,
739 gpointer user_data)
740{
741 AppSection *self = user_data;
742 AppSectionPrivate *priv = self->priv;
743 GVariant *state;
744 GSimpleAction *action;
745
746 /* TODO put label and icon into the action as well */
747
748 state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
749 action = g_simple_action_new_stateful (id, NULL, state);
750
751 g_simple_action_group_insert (priv->source_actions, G_ACTION (action));
752
753 if (draws_attention && !priv->draws_attention) {
754 priv->draws_attention = TRUE;
755 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
756 }
757
758 g_object_unref (action);
759}
760static void
761source_changed (IndicatorMessagesApplication *app,
762 const gchar *id,
763 const gchar *label,
764 const gchar *iconstr,
765 guint count,
766 gint64 time,
767 const gchar *string,
768 gboolean draws_attention,
769 gpointer user_data)
770{
771 AppSection *self = user_data;
772 AppSectionPrivate *priv = self->priv;
773 GVariant *state;
774
775 /* TODO put label and icon into the action as well */
776
777 state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
778 g_action_group_change_action_state (G_ACTION_GROUP (priv->source_actions), id, state);
779
780 update_draws_attention (self);
781}
782
783static void
784source_removed (IndicatorMessagesApplication *app,
785 const gchar *id,
786 gpointer user_data)
787{
788 AppSection *self = user_data;
789
790 remove_source (self, id);
791}
792
793static void
794app_proxy_created (GObject *source_object,
795 GAsyncResult *result,
796 gpointer user_data)
797{
798 AppSectionPrivate *priv = APP_SECTION (user_data)->priv;
799 GError *error = NULL;
800
801 priv->app_proxy = indicator_messages_application_proxy_new_finish (result, &error);
802 if (!priv->app_proxy) {
803 g_warning ("could not create application proxy: %s", error->message);
804 g_error_free (error);
805 return;
806 }
807
808 indicator_messages_application_call_list_sources (priv->app_proxy, priv->app_proxy_cancellable,
809 sources_listed, user_data);
810
811 g_signal_connect (priv->app_proxy, "source-added", G_CALLBACK (source_added), user_data);
812 g_signal_connect (priv->app_proxy, "source-changed", G_CALLBACK (source_changed), user_data);
813 g_signal_connect (priv->app_proxy, "source-removed", G_CALLBACK (source_removed), user_data);
814}
815
619/*816/*
620 * app_section_set_object_path:817 * app_section_set_object_path:
621 * @self: an #AppSection818 * @self: an #AppSection
@@ -634,27 +831,20 @@
634 const gchar *object_path)831 const gchar *object_path)
635{832{
636 AppSectionPrivate *priv = self->priv;833 AppSectionPrivate *priv = self->priv;
637 GMenuItem *item;
638834
639 g_object_freeze_notify (G_OBJECT (self));835 g_object_freeze_notify (G_OBJECT (self));
640 app_section_unset_object_path (self);836 app_section_unset_object_path (self);
641837
642 priv->source_actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path));838 priv->app_proxy_cancellable = g_cancellable_new ();
643 g_action_muxer_insert (priv->muxer, "source", priv->source_actions);839 indicator_messages_application_proxy_new (bus,
644840 G_DBUS_PROXY_FLAGS_NONE,
645 priv->draws_attention = any_action_draws_attention (priv->source_actions, NULL);841 bus_name,
646 g_object_connect (priv->source_actions,842 object_path,
647 "signal::action-added", action_added, self,843 priv->app_proxy_cancellable,
648 "signal::action-state-changed", action_state_changed, self,844 app_proxy_created,
649 "signal::action-removed", action_removed, self,845 self);
650 NULL);846
651847 priv->draws_attention = FALSE;
652 priv->source_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path));
653
654 item = g_menu_item_new_section (NULL, priv->source_menu);
655 g_menu_item_set_attribute (item, "action-namespace", "s", "source");
656 g_menu_append_item (priv->menu, item);
657 g_object_unref (item);
658848
659 priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0,849 priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0,
660 NULL, application_vanished,850 NULL, application_vanished,
@@ -682,26 +872,19 @@
682{872{
683 AppSectionPrivate *priv = self->priv;873 AppSectionPrivate *priv = self->priv;
684874
875 if (priv->app_proxy_cancellable) {
876 g_cancellable_cancel (priv->app_proxy_cancellable);
877 g_clear_object (&priv->app_proxy_cancellable);
878 }
879 g_clear_object (&priv->app_proxy);
880
685 if (priv->name_watch_id) {881 if (priv->name_watch_id) {
686 g_bus_unwatch_name (priv->name_watch_id);882 g_bus_unwatch_name (priv->name_watch_id);
687 priv->name_watch_id = 0;883 priv->name_watch_id = 0;
688 }884 }
689885
690 if (priv->source_actions) {886 g_simple_action_group_clear (priv->source_actions);
691 g_object_disconnect (priv->source_actions,887 g_menu_clear (priv->source_menu);
692 "any_signal::action-added", action_added, self,
693 "any_signal::action-state-changed", action_state_changed, self,
694 "any_signal::action-removed", action_removed, self,
695 NULL);
696 g_clear_object (&priv->source_actions);
697 }
698
699 if (priv->source_menu) {
700 /* the last menu item points is linked to the app's menumodel */
701 gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu));
702 g_menu_remove (priv->menu, n_items -1);
703 g_clear_object (&priv->source_menu);
704 }
705888
706 priv->draws_attention = FALSE;889 priv->draws_attention = FALSE;
707 g_clear_pointer (&priv->chat_status, g_free);890 g_clear_pointer (&priv->chat_status, g_free);
@@ -715,85 +898,6 @@
715 "launch", g_variant_new_boolean (FALSE));898 "launch", g_variant_new_boolean (FALSE));
716}899}
717900
718static gboolean
719action_draws_attention (GVariant *state)
720{
721 gboolean attention;
722
723 if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")))
724 g_variant_get_child (state, 3, "b", &attention);
725 else
726 attention = FALSE;
727
728 return attention;
729}
730
731static gboolean
732any_action_draws_attention (GActionGroup *group,
733 const gchar *ignored_action)
734{
735 gchar **actions;
736 gchar **it;
737 gboolean attention = FALSE;
738
739 actions = g_action_group_list_actions (group);
740
741 for (it = actions; *it && !attention; it++) {
742 GVariant *state;
743
744 if (ignored_action && g_str_equal (ignored_action, *it))
745 continue;
746
747 state = g_action_group_get_action_state (group, *it);
748 if (state) {
749 attention = action_draws_attention (state);
750 g_variant_unref (state);
751 }
752 }
753
754 g_strfreev (actions);
755 return attention;
756}
757
758static void
759action_added (GActionGroup *group,
760 const gchar *action_name,
761 gpointer user_data)
762{
763 AppSection *self = user_data;
764 GVariant *state;
765
766 state = g_action_group_get_action_state (group, action_name);
767 if (state) {
768 self->priv->draws_attention |= action_draws_attention (state);
769 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
770 g_variant_unref (state);
771 }
772}
773
774static void
775action_state_changed (GActionGroup *group,
776 const gchar *action_name,
777 GVariant *value,
778 gpointer user_data)
779{
780 AppSection *self = user_data;
781
782 self->priv->draws_attention = any_action_draws_attention (group, NULL);
783 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
784}
785
786static void
787action_removed (GActionGroup *group,
788 const gchar *action_name,
789 gpointer user_data)
790{
791 AppSection *self = user_data;
792
793 self->priv->draws_attention = any_action_draws_attention (group, action_name);
794 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
795}
796
797gboolean901gboolean
798app_section_get_uses_chat_status (AppSection *self)902app_section_get_uses_chat_status (AppSection *self)
799{903{
800904
=== modified file 'src/dbus-data.h'
--- src/dbus-data.h 2012-08-21 09:40:47 +0000
+++ src/dbus-data.h 2013-04-26 16:57:25 +0000
@@ -1,9 +1,24 @@
1/*
2 * Copyright 2012-2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
116
2#ifndef __DBUS_DATA_H__17#ifndef __DBUS_DATA_H__
3#define __DBUS_DATA_H__ 118#define __DBUS_DATA_H__ 1
419
5#define INDICATOR_MESSAGES_DBUS_NAME "com.canonical.indicator.messages"20#define INDICATOR_MESSAGES_DBUS_NAME "com.canonical.indicator.messages"
6#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages/menu"21#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages"
722
8#define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service"23#define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service"
9#define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service"24#define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service"
1025
=== modified file 'src/gactionmuxer.c'
--- src/gactionmuxer.c 2012-06-04 21:43:56 +0000
+++ src/gactionmuxer.c 2013-04-26 16:57:25 +0000
@@ -483,3 +483,11 @@
483 g_clear_object (&muxer->global_actions);483 g_clear_object (&muxer->global_actions);
484}484}
485485
486GActionGroup *
487g_action_muxer_get_group (GActionMuxer *muxer,
488 const gchar *prefix)
489{
490 g_return_val_if_fail (G_IS_ACTION_MUXER (muxer), NULL);
491
492 return prefix ? g_hash_table_lookup (muxer->groups, prefix) : muxer->global_actions;
493}
486494
=== modified file 'src/gactionmuxer.h'
--- src/gactionmuxer.h 2012-06-03 06:33:31 +0000
+++ src/gactionmuxer.h 2013-04-26 16:57:25 +0000
@@ -40,5 +40,8 @@
40void g_action_muxer_remove (GActionMuxer *muxer,40void g_action_muxer_remove (GActionMuxer *muxer,
41 const gchar *prefix);41 const gchar *prefix);
4242
43GActionGroup * g_action_muxer_get_group (GActionMuxer *muxer,
44 const gchar *prefix);
45
43#endif46#endif
4447
4548
=== added file 'src/im-application-list.c'
--- src/im-application-list.c 1970-01-01 00:00:00 +0000
+++ src/im-application-list.c 2013-04-26 16:57:25 +0000
@@ -0,0 +1,880 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "im-application-list.h"
21
22#include "indicator-messages-application.h"
23#include "gactionmuxer.h"
24
25#include <gio/gdesktopappinfo.h>
26#include <string.h>
27
28typedef GObjectClass ImApplicationListClass;
29
30struct _ImApplicationList
31{
32 GObject parent;
33
34 GHashTable *applications;
35 GActionMuxer *muxer;
36};
37
38G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT);
39
40enum
41{
42 SOURCE_ADDED,
43 SOURCE_CHANGED,
44 SOURCE_REMOVED,
45 MESSAGE_ADDED,
46 MESSAGE_REMOVED,
47 APP_STOPPED,
48 REMOVE_ALL,
49 N_SIGNALS
50};
51
52static guint signals[N_SIGNALS];
53
54typedef struct
55{
56 ImApplicationList *list;
57 GDesktopAppInfo *info;
58 gchar *id;
59 IndicatorMessagesApplication *proxy;
60 GActionMuxer *actions;
61 GSimpleActionGroup *source_actions;
62 GSimpleActionGroup *message_actions;
63 GActionMuxer *message_sub_actions;
64 GCancellable *cancellable;
65} Application;
66
67static void
68application_free (gpointer data)
69{
70 Application *app = data;
71
72 if (!app)
73 return;
74
75 g_object_unref (app->info);
76 g_free (app->id);
77
78 if (app->cancellable)
79 {
80 g_cancellable_cancel (app->cancellable);
81 g_clear_object (&app->cancellable);
82 }
83
84 if (app->proxy)
85 g_object_unref (app->proxy);
86
87 if (app->actions)
88 {
89 g_object_unref (app->actions);
90 g_object_unref (app->source_actions);
91 g_object_unref (app->message_actions);
92 g_object_unref (app->message_sub_actions);
93 }
94
95 g_slice_free (Application, app);
96}
97
98static void
99im_application_list_source_removed (Application *app,
100 const gchar *id)
101{
102 g_simple_action_group_remove (app->source_actions, id);
103
104 g_signal_emit (app->list, signals[SOURCE_REMOVED], 0, app->id, id);
105}
106
107static void
108im_application_list_source_activated (GSimpleAction *action,
109 GVariant *parameter,
110 gpointer user_data)
111{
112 Application *app = user_data;
113 const gchar *source_id;
114
115 source_id = g_action_get_name (G_ACTION (action));
116
117 if (g_variant_get_boolean (parameter))
118 {
119 indicator_messages_application_call_activate_source (app->proxy,
120 source_id,
121 app->cancellable,
122 NULL, NULL);
123 }
124 else
125 {
126 const gchar *sources[] = { source_id, NULL };
127 const gchar *messages[] = { NULL };
128 indicator_messages_application_call_dismiss (app->proxy, sources, messages,
129 app->cancellable, NULL, NULL);
130 }
131
132 im_application_list_source_removed (app, source_id);
133}
134
135static guint
136g_action_group_get_n_actions (GActionGroup *group)
137{
138 guint len;
139 gchar **actions;
140
141 actions = g_action_group_list_actions (group);
142 len = g_strv_length (actions);
143
144 g_strfreev (actions);
145 return len;
146}
147
148static gboolean
149application_draws_attention (gpointer key,
150 gpointer value,
151 gpointer user_data)
152{
153 Application *app = value;
154
155 return (g_action_group_get_n_actions (G_ACTION_GROUP (app->source_actions)) +
156 g_action_group_get_n_actions (G_ACTION_GROUP (app->message_actions))) > 0;
157}
158
159static void
160im_application_list_update_draws_attention (ImApplicationList *list)
161{
162 const gchar *icon_name;
163 GVariant *state;
164 GActionGroup *main_actions;
165
166 if (g_hash_table_find (list->applications, application_draws_attention, NULL))
167 icon_name = "indicator-messages-new";
168 else
169 icon_name = "indicator-messages";
170
171 main_actions = g_action_muxer_get_group (list->muxer, NULL);
172 state = g_variant_new ("(sssb)", "", icon_name, "Messages", TRUE);
173 g_action_group_change_action_state (main_actions, "messages", state);
174}
175
176static void
177im_application_list_message_removed (Application *app,
178 const gchar *id)
179{
180 g_simple_action_group_remove (app->message_actions, id);
181 g_action_muxer_remove (app->message_sub_actions, id);
182
183 im_application_list_update_draws_attention (app->list);
184
185 g_signal_emit (app->list, signals[MESSAGE_REMOVED], 0, app->id, id);
186}
187
188static void
189im_application_list_message_activated (GSimpleAction *action,
190 GVariant *parameter,
191 gpointer user_data)
192{
193 Application *app = user_data;
194 const gchar *message_id;
195
196 message_id = g_action_get_name (G_ACTION (action));
197
198 if (g_variant_get_boolean (parameter))
199 {
200 indicator_messages_application_call_activate_message (app->proxy,
201 message_id,
202 "",
203 g_variant_new_array (G_VARIANT_TYPE_VARIANT, NULL, 0),
204 app->cancellable,
205 NULL, NULL);
206 }
207 else
208 {
209 const gchar *sources[] = { NULL };
210 const gchar *messages[] = { message_id, NULL };
211 indicator_messages_application_call_dismiss (app->proxy, sources, messages,
212 app->cancellable, NULL, NULL);
213 }
214
215 im_application_list_message_removed (app, message_id);
216}
217
218static void
219im_application_list_sub_message_activated (GSimpleAction *action,
220 GVariant *parameter,
221 gpointer user_data)
222{
223 Application *app = user_data;
224 const gchar *message_id;
225 const gchar *action_id;
226 GVariantBuilder builder;
227
228 message_id = g_object_get_data (G_OBJECT (action), "message");
229 action_id = g_action_get_name (G_ACTION (action));
230
231 g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
232 if (parameter)
233 g_variant_builder_add (&builder, "v", parameter);
234
235 indicator_messages_application_call_activate_message (app->proxy,
236 message_id,
237 action_id,
238 g_variant_builder_end (&builder),
239 app->cancellable,
240 NULL, NULL);
241
242 im_application_list_message_removed (app, message_id);
243}
244
245
246static void
247im_application_list_remove_all (GSimpleAction *action,
248 GVariant *parameter,
249 gpointer user_data)
250{
251 ImApplicationList *list = user_data;
252 GHashTableIter iter;
253 Application *app;
254
255 g_signal_emit (list, signals[REMOVE_ALL], 0);
256
257 g_hash_table_iter_init (&iter, list->applications);
258 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &app))
259 {
260 gchar **source_actions;
261 gchar **message_actions;
262 gchar **it;
263
264 source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
265 for (it = source_actions; *it; it++)
266 im_application_list_source_removed (app, *it);
267
268 message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
269 for (it = message_actions; *it; it++)
270 im_application_list_message_removed (app, *it);
271
272 indicator_messages_application_call_dismiss (app->proxy,
273 (const gchar * const *) source_actions,
274 (const gchar * const *) message_actions,
275 app->cancellable, NULL, NULL);
276
277 g_strfreev (source_actions);
278 g_strfreev (message_actions);
279 }
280}
281
282static void
283im_application_list_dispose (GObject *object)
284{
285 ImApplicationList *list = IM_APPLICATION_LIST (object);
286
287 g_clear_pointer (&list->applications, g_hash_table_unref);
288 g_clear_object (&list->muxer);
289
290 G_OBJECT_CLASS (im_application_list_parent_class)->dispose (object);
291}
292
293static void
294im_application_list_finalize (GObject *object)
295{
296 G_OBJECT_CLASS (im_application_list_parent_class)->finalize (object);
297}
298
299static void
300im_application_list_class_init (ImApplicationListClass *klass)
301{
302 GObjectClass *object_class = G_OBJECT_CLASS (klass);
303
304 object_class->dispose = im_application_list_dispose;
305 object_class->finalize = im_application_list_finalize;
306
307 signals[SOURCE_ADDED] = g_signal_new ("source-added",
308 IM_TYPE_APPLICATION_LIST,
309 G_SIGNAL_RUN_FIRST,
310 0,
311 NULL, NULL,
312 g_cclosure_marshal_generic,
313 G_TYPE_NONE,
314 4,
315 G_TYPE_STRING,
316 G_TYPE_STRING,
317 G_TYPE_STRING,
318 G_TYPE_STRING);
319
320 signals[SOURCE_CHANGED] = g_signal_new ("source-changed",
321 IM_TYPE_APPLICATION_LIST,
322 G_SIGNAL_RUN_FIRST,
323 0,
324 NULL, NULL,
325 g_cclosure_marshal_generic,
326 G_TYPE_NONE,
327 4,
328 G_TYPE_STRING,
329 G_TYPE_STRING,
330 G_TYPE_STRING,
331 G_TYPE_STRING);
332
333 signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
334 IM_TYPE_APPLICATION_LIST,
335 G_SIGNAL_RUN_FIRST,
336 0,
337 NULL, NULL,
338 g_cclosure_marshal_generic,
339 G_TYPE_NONE,
340 2,
341 G_TYPE_STRING,
342 G_TYPE_STRING);
343
344 signals[MESSAGE_ADDED] = g_signal_new ("message-added",
345 IM_TYPE_APPLICATION_LIST,
346 G_SIGNAL_RUN_FIRST,
347 0,
348 NULL, NULL,
349 g_cclosure_marshal_generic,
350 G_TYPE_NONE,
351 10,
352 G_TYPE_STRING,
353 G_TYPE_STRING,
354 G_TYPE_STRING,
355 G_TYPE_STRING,
356 G_TYPE_STRING,
357 G_TYPE_STRING,
358 G_TYPE_STRING,
359 G_TYPE_VARIANT,
360 G_TYPE_INT64,
361 G_TYPE_BOOLEAN);
362
363 signals[MESSAGE_REMOVED] = g_signal_new ("message-removed",
364 IM_TYPE_APPLICATION_LIST,
365 G_SIGNAL_RUN_FIRST,
366 0,
367 NULL, NULL,
368 g_cclosure_marshal_generic,
369 G_TYPE_NONE,
370 2,
371 G_TYPE_STRING,
372 G_TYPE_STRING);
373
374 signals[APP_STOPPED] = g_signal_new ("app-stopped",
375 IM_TYPE_APPLICATION_LIST,
376 G_SIGNAL_RUN_FIRST,
377 0,
378 NULL, NULL,
379 g_cclosure_marshal_VOID__OBJECT,
380 G_TYPE_NONE,
381 1,
382 G_TYPE_STRING);
383
384 signals[REMOVE_ALL] = g_signal_new ("remove-all",
385 IM_TYPE_APPLICATION_LIST,
386 G_SIGNAL_RUN_FIRST,
387 0,
388 NULL, NULL,
389 g_cclosure_marshal_VOID__VOID,
390 G_TYPE_NONE,
391 0);
392}
393
394static void
395im_application_list_init (ImApplicationList *list)
396{
397 const GActionEntry action_entries[] = {
398 { "messages", NULL, NULL, "('', 'indicator-messages', 'Messages', true)", NULL },
399 { "remove-all", im_application_list_remove_all }
400 };
401
402 GSimpleActionGroup *actions;
403
404 list->applications = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, application_free);
405
406 actions = g_simple_action_group_new ();
407 g_simple_action_group_add_entries (actions, action_entries, G_N_ELEMENTS (action_entries), list);
408
409 list->muxer = g_action_muxer_new ();
410 g_action_muxer_insert (list->muxer, NULL, G_ACTION_GROUP (actions));
411
412 g_object_unref (actions);
413}
414
415ImApplicationList *
416im_application_list_new (void)
417{
418 return g_object_new (IM_TYPE_APPLICATION_LIST, NULL);
419}
420
421static gchar *
422im_application_list_canonical_id (const gchar *id)
423{
424 gchar *str;
425 gchar *p;
426 int len;
427
428 len = strlen (id);
429 if (g_str_has_suffix (id, ".desktop"))
430 len -= 8;
431
432 str = g_strndup (id, len);
433
434 for (p = str; *p; p++)
435 {
436 if (*p == '.')
437 *p = '_';
438 }
439
440 return str;
441}
442
443static Application *
444im_application_list_lookup (ImApplicationList *list,
445 const gchar *desktop_id)
446{
447 gchar *id;
448 Application *app;
449
450 id = im_application_list_canonical_id (desktop_id);
451 app = g_hash_table_lookup (list->applications, id);
452
453 g_free (id);
454 return app;
455}
456
457void
458im_application_list_add (ImApplicationList *list,
459 const gchar *desktop_id)
460{
461 GDesktopAppInfo *info;
462 Application *app;
463 const gchar *id;
464
465 g_return_if_fail (IM_IS_APPLICATION_LIST (list));
466 g_return_if_fail (desktop_id != NULL);
467
468 if (im_application_list_lookup (list, desktop_id))
469 return;
470
471 info = g_desktop_app_info_new (desktop_id);
472 if (!info)
473 {
474 g_warning ("an application with id '%s' is not installed", desktop_id);
475 return;
476 }
477
478 id = g_app_info_get_id (G_APP_INFO (info));
479 g_return_if_fail (id != NULL);
480
481 app = g_slice_new0 (Application);
482 app->info = info;
483 app->id = im_application_list_canonical_id (id);
484 app->list = list;
485 app->actions = g_action_muxer_new ();
486 app->source_actions = g_simple_action_group_new ();
487 app->message_actions = g_simple_action_group_new ();
488 app->message_sub_actions = g_action_muxer_new ();
489
490 g_action_muxer_insert (app->actions, "src", G_ACTION_GROUP (app->source_actions));
491 g_action_muxer_insert (app->actions, "msg", G_ACTION_GROUP (app->message_actions));
492 g_action_muxer_insert (app->actions, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
493
494 g_hash_table_insert (list->applications, (gpointer) app->id, app);
495 g_action_muxer_insert (list->muxer, app->id, G_ACTION_GROUP (app->actions));
496}
497
498void
499im_application_list_remove (ImApplicationList *list,
500 const gchar *id)
501{
502 Application *app;
503
504 g_return_if_fail (IM_IS_APPLICATION_LIST (list));
505
506 app = im_application_list_lookup (list, id);
507 if (app)
508 {
509 if (app->proxy || app->cancellable)
510 g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
511
512 g_hash_table_remove (list->applications, id);
513 g_action_muxer_remove (list->muxer, id);
514 }
515}
516
517static void
518im_application_list_source_added (Application *app,
519 guint position,
520 GVariant *source)
521{
522 const gchar *id;
523 const gchar *label;
524 const gchar *iconstr;
525 guint32 count;
526 gint64 time;
527 const gchar *string;
528 gboolean draws_attention;
529 GVariant *state;
530 GSimpleAction *action;
531
532 g_variant_get (source, "(&s&s&sux&sb)",
533 &id, &label, &iconstr, &count, &time, &string, &draws_attention);
534
535 state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
536 action = g_simple_action_new_stateful (id, G_VARIANT_TYPE_BOOLEAN, state);
537 g_signal_connect (action, "activate", G_CALLBACK (im_application_list_source_activated), app);
538
539 g_simple_action_group_insert (app->source_actions, G_ACTION (action));
540
541 g_signal_emit (app->list, signals[SOURCE_ADDED], 0, app->id, id, label, iconstr);
542
543 g_object_unref (action);
544}
545
546static void
547im_application_list_source_changed (Application *app,
548 GVariant *source)
549{
550 const gchar *id;
551 const gchar *label;
552 const gchar *iconstr;
553 guint32 count;
554 gint64 time;
555 const gchar *string;
556 gboolean draws_attention;
557
558 g_variant_get (source, "(&s&s&sux&sb)",
559 &id, &label, &iconstr, &count, &time, &string, &draws_attention);
560
561 g_action_group_change_action_state (G_ACTION_GROUP (app->source_actions), id,
562 g_variant_new ("(uxsb)", count, time, string, draws_attention));
563
564 g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, app->id, id, label, iconstr);
565}
566
567static void
568im_application_list_sources_listed (GObject *source_object,
569 GAsyncResult *result,
570 gpointer user_data)
571{
572 Application *app = user_data;
573 GVariant *sources;
574 GError *error = NULL;
575
576 if (indicator_messages_application_call_list_sources_finish (app->proxy, &sources, result, &error))
577 {
578 GVariantIter iter;
579 GVariant *source;
580 guint i = 0;
581
582 g_variant_iter_init (&iter, sources);
583 while ((source = g_variant_iter_next_value (&iter)))
584 {
585 im_application_list_source_added (app, i++, source);
586 g_variant_unref (source);
587 }
588
589 g_variant_unref (sources);
590 }
591 else
592 {
593 g_warning ("could not fetch the list of sources: %s", error->message);
594 g_error_free (error);
595 }
596}
597
598static gchar *
599get_symbolic_app_icon_string (GIcon *icon)
600{
601 const gchar * const *names;
602 gchar *symbolic_name;
603 GIcon *symbolic_icon;
604 gchar *str;
605
606 if (!G_IS_THEMED_ICON (icon))
607 return NULL;
608
609 names = g_themed_icon_get_names (G_THEMED_ICON (icon));
610 if (!names || !names[0])
611 return NULL;
612
613 symbolic_icon = g_themed_icon_new_from_names ((gchar **) names, -1);
614
615 symbolic_name = g_strconcat (names[0], "-symbolic", NULL);
616 g_themed_icon_prepend_name (G_THEMED_ICON (symbolic_icon), symbolic_name);
617
618 str = g_icon_to_string (symbolic_icon);
619
620 g_free (symbolic_name);
621 g_object_unref (symbolic_icon);
622 return str;
623}
624
625static void
626im_application_list_message_added (Application *app,
627 GVariant *message)
628{
629 const gchar *id;
630 const gchar *iconstr;
631 const gchar *title;
632 const gchar *subtitle;
633 const gchar *body;
634 gint64 time;
635 GVariantIter *action_iter;
636 gboolean draws_attention;
637 GSimpleAction *action;
638 GIcon *app_icon;
639 gchar *app_iconstr = NULL;
640 GVariant *actions = NULL;
641
642 g_variant_get (message, "(&s&s&s&s&sxaa{sv}b)",
643 &id, &iconstr, &title, &subtitle, &body, &time, &action_iter, &draws_attention);
644
645 app_icon = g_app_info_get_icon (G_APP_INFO (app->info));
646 if (app_icon)
647 app_iconstr = get_symbolic_app_icon_string (app_icon);
648
649 action = g_simple_action_new (id, G_VARIANT_TYPE_BOOLEAN);
650 g_signal_connect (action, "activate", G_CALLBACK (im_application_list_message_activated), app);
651 g_simple_action_group_insert (app->message_actions, G_ACTION (action));
652
653 {
654 GVariant *entry;
655 GSimpleActionGroup *action_group;
656 GVariantBuilder actions_builder;
657
658 g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
659 action_group = g_simple_action_group_new ();
660
661 while ((entry = g_variant_iter_next_value (action_iter)))
662 {
663 const gchar *name;
664 GSimpleAction *action;
665 GVariant *label;
666 const gchar *type = NULL;
667 GVariant *hint;
668 GVariantBuilder dict_builder;
669 gchar *prefixed_name;
670
671 if (!g_variant_lookup (entry, "name", "&s", &name))
672 {
673 g_warning ("action dictionary for message '%s' is missing 'name' key", id);
674 continue;
675 }
676
677 label = g_variant_lookup_value (entry, "label", G_VARIANT_TYPE_STRING);
678 g_variant_lookup (entry, "parameter-type", "&g", &type);
679 hint = g_variant_lookup_value (entry, "parameter-hint", NULL);
680
681 action = g_simple_action_new (name, type ? G_VARIANT_TYPE (type) : NULL);
682 g_object_set_data_full (G_OBJECT (action), "message", g_strdup (id), g_free);
683 g_signal_connect (action, "activate", G_CALLBACK (im_application_list_sub_message_activated), app);
684 g_simple_action_group_insert (action_group, G_ACTION (action));
685
686 g_variant_builder_init (&dict_builder, G_VARIANT_TYPE ("a{sv}"));
687
688 prefixed_name = g_strjoin (".", app->id, "msg-actions", id, name, NULL);
689 g_variant_builder_add (&dict_builder, "{sv}", "name", g_variant_new_string (prefixed_name));
690
691 if (label)
692 {
693 g_variant_builder_add (&dict_builder, "{sv}", "label", label);
694 g_variant_unref (label);
695 }
696
697 if (type)
698 g_variant_builder_add (&dict_builder, "{sv}", "parameter-type", g_variant_new_string (type));
699
700 if (hint)
701 {
702 g_variant_builder_add (&dict_builder, "{sv}", "parameter-hint", hint);
703 g_variant_unref (hint);
704 }
705
706 g_variant_builder_add (&actions_builder, "a{sv}", &dict_builder);
707
708 g_object_unref (action);
709 g_variant_unref (entry);
710 g_free (prefixed_name);
711 }
712
713 g_action_muxer_insert (app->message_sub_actions, id, G_ACTION_GROUP (action_group));
714 actions = g_variant_builder_end (&actions_builder);
715
716 g_object_unref (action_group);
717 }
718
719 im_application_list_update_draws_attention (app->list);
720
721 g_signal_emit (app->list, signals[MESSAGE_ADDED], 0,
722 app->id, app_iconstr, id, iconstr, title,
723 subtitle, body, actions, time, draws_attention);
724
725 g_variant_iter_free (action_iter);
726 g_free (app_iconstr);
727 g_object_unref (action);
728}
729
730static void
731im_application_list_messages_listed (GObject *source_object,
732 GAsyncResult *result,
733 gpointer user_data)
734{
735 Application *app = user_data;
736 GVariant *messages;
737 GError *error = NULL;
738
739 if (indicator_messages_application_call_list_messages_finish (app->proxy, &messages, result, &error))
740 {
741 GVariantIter iter;
742 GVariant *message;
743
744 g_variant_iter_init (&iter, messages);
745 while ((message = g_variant_iter_next_value (&iter)))
746 {
747 im_application_list_message_added (app, message);
748 g_variant_unref (message);
749 }
750
751 g_variant_unref (messages);
752 }
753 else
754 {
755 g_warning ("could not fetch the list of messages: %s", error->message);
756 g_error_free (error);
757 }
758}
759
760static void
761im_application_list_unset_remote (Application *app)
762{
763 gboolean was_running;
764
765 was_running = app->proxy || app->cancellable;
766
767 if (app->cancellable)
768 {
769 g_cancellable_cancel (app->cancellable);
770 g_clear_object (&app->cancellable);
771 }
772 g_clear_object (&app->proxy);
773
774 /* clear actions by creating a new action group and overriding it in
775 * the muxer */
776 g_object_unref (app->source_actions);
777 g_object_unref (app->message_actions);
778 g_object_unref (app->message_sub_actions);
779 app->source_actions = g_simple_action_group_new ();
780 app->message_actions = g_simple_action_group_new ();
781 app->message_sub_actions = g_action_muxer_new ();
782 g_action_muxer_insert (app->actions, "src", G_ACTION_GROUP (app->source_actions));
783 g_action_muxer_insert (app->actions, "msg", G_ACTION_GROUP (app->message_actions));
784 g_action_muxer_insert (app->actions, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
785
786 im_application_list_update_draws_attention (app->list);
787
788 if (was_running)
789 g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
790}
791
792static void
793im_application_list_app_vanished (GDBusConnection *connection,
794 const gchar *name,
795 gpointer user_data)
796{
797 Application *app = user_data;
798
799 im_application_list_unset_remote (app);
800}
801
802static void
803im_application_list_proxy_created (GObject *source_object,
804 GAsyncResult *result,
805 gpointer user_data)
806{
807 Application *app = user_data;
808 GError *error = NULL;
809
810 app->proxy = indicator_messages_application_proxy_new_finish (result, &error);
811 if (!app->proxy)
812 {
813 if (error->code != G_IO_ERROR_CANCELLED)
814 g_warning ("could not create application proxy: %s", error->message);
815 g_error_free (error);
816 return;
817 }
818
819 indicator_messages_application_call_list_sources (app->proxy, app->cancellable,
820 im_application_list_sources_listed, app);
821 indicator_messages_application_call_list_messages (app->proxy, app->cancellable,
822 im_application_list_messages_listed, app);
823
824 g_signal_connect_swapped (app->proxy, "source-added", G_CALLBACK (im_application_list_source_added), app);
825 g_signal_connect_swapped (app->proxy, "source-changed", G_CALLBACK (im_application_list_source_changed), app);
826 g_signal_connect_swapped (app->proxy, "source-removed", G_CALLBACK (im_application_list_source_removed), app);
827 g_signal_connect_swapped (app->proxy, "message-added", G_CALLBACK (im_application_list_message_added), app);
828 g_signal_connect_swapped (app->proxy, "message-removed", G_CALLBACK (im_application_list_message_removed), app);
829
830 g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (G_DBUS_PROXY (app->proxy)),
831 g_dbus_proxy_get_name (G_DBUS_PROXY (app->proxy)),
832 G_BUS_NAME_WATCHER_FLAGS_NONE,
833 NULL, im_application_list_app_vanished,
834 app, NULL);
835}
836
837void
838im_application_list_set_remote (ImApplicationList *list,
839 const gchar *id,
840 GDBusConnection *connection,
841 const gchar *unique_bus_name,
842 const gchar *object_path)
843{
844 Application *app;
845
846 g_return_if_fail (IM_IS_APPLICATION_LIST (list));
847
848 app = im_application_list_lookup (list, id);
849 if (!app)
850 {
851 g_warning ("'%s' is not a registered application", id);
852 return;
853 }
854
855 if (app->cancellable)
856 {
857 gchar *name_owner = NULL;
858
859 if (app->proxy)
860 name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy));
861 g_warning ("replacing '%s' at %s with %s", id, name_owner, unique_bus_name);
862
863 im_application_list_unset_remote (app);
864
865 g_free (name_owner);
866 }
867
868 app->cancellable = g_cancellable_new ();
869 indicator_messages_application_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE,
870 unique_bus_name, object_path, app->cancellable,
871 im_application_list_proxy_created, app);
872}
873
874GActionGroup *
875im_application_list_get_action_group (ImApplicationList *list)
876{
877 g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
878
879 return G_ACTION_GROUP (list->muxer);
880}
0881
=== added file 'src/im-application-list.h'
--- src/im-application-list.h 1970-01-01 00:00:00 +0000
+++ src/im-application-list.h 2013-04-26 16:57:25 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#ifndef __IM_APPLICATION_LIST_H__
21#define __IM_APPLICATION_LIST_H__
22
23#include <gio/gio.h>
24
25#define IM_TYPE_APPLICATION_LIST (im_application_list_get_type ())
26#define IM_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationList))
27#define IM_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_APPLICATION_LIST, ImApplicationListClass))
28#define IM_IS_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_APPLICATION_LIST))
29#define IM_IS_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_APPLICATION_LIST))
30#define IM_APPLICATION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationListClass))
31
32typedef struct _ImApplicationList ImApplicationList;
33
34GType im_application_list_get_type (void);
35
36ImApplicationList * im_application_list_new (void);
37
38void im_application_list_add (ImApplicationList *list,
39 const gchar *desktop_id);
40
41void im_application_list_remove (ImApplicationList *list,
42 const gchar *id);
43
44void im_application_list_set_remote (ImApplicationList *list,
45 const gchar *id,
46 GDBusConnection *connection,
47 const gchar *unique_bus_name,
48 const gchar *object_path);
49
50GActionGroup * im_application_list_get_action_group (ImApplicationList *list);
51
52#endif
053
=== added file 'src/im-phone-menu.c'
--- src/im-phone-menu.c 1970-01-01 00:00:00 +0000
+++ src/im-phone-menu.c 2013-04-26 16:57:25 +0000
@@ -0,0 +1,331 @@
1/*
2 * Copyright 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lars Uebernickel <lars.uebernickel@canonical.com>
18 */
19
20#include "im-phone-menu.h"
21
22#include <string.h>
23
24typedef GObjectClass ImPhoneMenuClass;
25
26struct _ImPhoneMenu
27{
28 GObject parent;
29
30 GMenu *toplevel_menu;
31 GMenu *message_section;
32 GMenu *source_section;
33
34};
35
36G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, G_TYPE_OBJECT);
37
38typedef void (*ImMenuForeachFunc) (GMenuModel *menu, gint pos);
39
40static void
41im_phone_menu_foreach_item_with_action (GMenuModel *menu,
42 const gchar *action,
43 ImMenuForeachFunc func)
44{
45 gint n_items;
46 gint i;
47
48 n_items = g_menu_model_get_n_items (menu);
49 for (i = 0; i < n_items; i++)
50 {
51 gchar *item_action;
52
53 g_menu_model_get_item_attribute (menu, i, G_MENU_ATTRIBUTE_ACTION, "s", &item_action);
54
55 if (g_str_equal (action, item_action))
56 func (menu, i);
57
58 g_free (item_action);
59 }
60}
61
62static void
63im_phone_menu_update_toplevel (ImPhoneMenu *menu)
64{
65 if (g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section)) ||
66 g_menu_model_get_n_items (G_MENU_MODEL (menu->source_section)))
67 {
68 if (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)) == 0)
69 {
70 GMenuItem *item;
71
72 g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->message_section));
73 g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->source_section));
74
75 item = g_menu_item_new ("Clear All", "remove-all");
76 g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.button");
77 g_menu_append_item (menu->toplevel_menu, item);
78
79 g_object_unref (item);
80 }
81 }
82 else
83 {
84 while (g_menu_model_get_n_items (G_MENU_MODEL (menu->toplevel_menu)))
85 g_menu_remove (menu->toplevel_menu, 0);
86 }
87}
88
89static void
90im_phone_menu_dispose (GObject *object)
91{
92 ImPhoneMenu *menu = IM_PHONE_MENU (object);
93
94 g_clear_object (&menu->toplevel_menu);
95 g_clear_object (&menu->message_section);
96 g_clear_object (&menu->source_section);
97
98 G_OBJECT_CLASS (im_phone_menu_parent_class)->dispose (object);
99}
100
101static void
102im_phone_menu_finalize (GObject *object)
103{
104 G_OBJECT_CLASS (im_phone_menu_parent_class)->finalize (object);
105}
106
107static void
108im_phone_menu_class_init (ImPhoneMenuClass *klass)
109{
110 GObjectClass *object_class = G_OBJECT_CLASS (klass);
111
112 object_class->dispose = im_phone_menu_dispose;
113 object_class->finalize = im_phone_menu_finalize;
114}
115
116static void
117im_phone_menu_init (ImPhoneMenu *menu)
118{
119 menu->toplevel_menu = g_menu_new ();
120 menu->message_section = g_menu_new ();
121 menu->source_section = g_menu_new ();
122
123 g_signal_connect_swapped (menu->message_section, "items-changed",
124 G_CALLBACK (im_phone_menu_update_toplevel), menu);
125 g_signal_connect_swapped (menu->source_section, "items-changed",
126 G_CALLBACK (im_phone_menu_update_toplevel), menu);
127
128 im_phone_menu_update_toplevel (menu);
129}
130
131ImPhoneMenu *
132im_phone_menu_new (void)
133{
134 return g_object_new (IM_TYPE_PHONE_MENU, NULL);
135}
136
137GMenuModel *
138im_phone_menu_get_model (ImPhoneMenu *menu)
139{
140 g_return_val_if_fail (IM_IS_PHONE_MENU (menu), NULL);
141
142 return G_MENU_MODEL (menu->toplevel_menu);
143}
144
145static gint64
146im_phone_menu_get_message_time (GMenuModel *model,
147 gint i)
148{
149 gint64 time;
150
151 g_menu_model_get_item_attribute (model, i, "x-canonical-time", "x", &time);
152
153 return time;
154}
155
156void
157im_phone_menu_add_message (ImPhoneMenu *menu,
158 const gchar *app_id,
159 const gchar *app_icon,
160 const gchar *id,
161 const gchar *iconstr,
162 const gchar *title,
163 const gchar *subtitle,
164 const gchar *body,
165 GVariant *actions,
166 gint64 time)
167{
168 GMenuItem *item;
169 gchar *action_name;
170 gint n_messages;
171 gint pos;
172
173 g_return_if_fail (IM_IS_PHONE_MENU (menu));
174 g_return_if_fail (app_id);
175
176 action_name = g_strconcat (app_id, ".msg.", id, NULL);
177
178 item = g_menu_item_new (title, action_name);
179
180 g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.messageitem");
181 g_menu_item_set_attribute (item, "x-canonical-message-id", "s", id);
182 g_menu_item_set_attribute (item, "x-canonical-subtitle", "s", subtitle);
183 g_menu_item_set_attribute (item, "x-canonical-text", "s", body);
184 g_menu_item_set_attribute (item, "x-canonical-time", "x", time);
185
186 if (iconstr)
187 g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
188
189 if (app_icon)
190 g_menu_item_set_attribute (item, "x-canonical-app-icon", "s", app_icon);
191
192 if (actions)
193 g_menu_item_set_attribute (item, "x-canonical-message-actions", "v", actions);
194
195 n_messages = g_menu_model_get_n_items (G_MENU_MODEL (menu->message_section));
196 pos = 0;
197 while (pos < n_messages &&
198 time < im_phone_menu_get_message_time (G_MENU_MODEL (menu->message_section), pos))
199 pos++;
200
201 g_menu_insert_item (menu->message_section, pos, item);
202
203 g_free (action_name);
204 g_object_unref (item);
205}
206
207void
208im_phone_menu_remove_message (ImPhoneMenu *menu,
209 const gchar *app_id,
210 const gchar *id)
211{
212 gchar *action_name;
213
214 g_return_if_fail (IM_IS_PHONE_MENU (menu));
215 g_return_if_fail (app_id != NULL);
216
217 action_name = g_strconcat (app_id, ".msg.", id, NULL);
218 im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->message_section),
219 action_name,
220 (ImMenuForeachFunc) g_menu_remove);
221
222 g_free (action_name);
223}
224
225void
226im_phone_menu_add_source (ImPhoneMenu *menu,
227 const gchar *app_id,
228 const gchar *id,
229 const gchar *label,
230 const gchar *iconstr)
231{
232 GMenuItem *item;
233 gchar *action_name;
234
235 g_return_if_fail (IM_IS_PHONE_MENU (menu));
236 g_return_if_fail (app_id != NULL);
237
238 action_name = g_strconcat (app_id, ".src.", id, NULL);
239
240 item = g_menu_item_new (label, action_name);
241 g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.sourceitem");
242
243 if (iconstr)
244 g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
245
246 g_menu_prepend_item (menu->source_section, item);
247
248 g_free (action_name);
249 g_object_unref (item);
250}
251
252void
253im_phone_menu_remove_source (ImPhoneMenu *menu,
254 const gchar *app_id,
255 const gchar *id)
256{
257 gchar *action_name;
258
259 g_return_if_fail (IM_IS_PHONE_MENU (menu));
260 g_return_if_fail (app_id != NULL);
261
262 action_name = g_strconcat (app_id, ".src.", id, NULL);
263 im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->source_section),
264 action_name,
265 (ImMenuForeachFunc) g_menu_remove);
266
267 g_free (action_name);
268}
269
270static void
271im_phone_menu_remove_all_for_app (GMenu *menu,
272 const gchar *app_id)
273{
274 gchar *prefix;
275 gint n_items;
276 gint i = 0;
277
278 prefix = g_strconcat (app_id, ".", NULL);
279
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches