87 Commits
0.1.1 ... 0.2.4

Author SHA1 Message Date
Johannes H. Jensen
1cba177277 0.2.4 release. 2008-08-28 00:51:49 +02:00
Johannes H. Jensen
fe74f4b470 Store alarms in a global GConf directory: /apps/alarm-clock (LP: #261877) 2008-08-27 17:19:03 +02:00
Johannes H. Jensen
ba8b925263 Remove old checkbox code. 2008-08-27 16:05:37 +02:00
Johannes H. Jensen
18d6a2f889 0.2.3 bugfix release. 2008-06-25 18:21:22 +02:00
Johannes H. Jensen
51515f9d51 When an alarm is added, connect alarm_triggered so notifications are displayed (LP: #240728)
Remove timer and stop player on alarm dispose.
2008-06-19 01:19:59 +02:00
Johannes H. Jensen
f4467d6fcb 0.2.2 bugfix release. 2008-05-12 14:33:42 +02:00
Johannes H. Jensen
e894d16dcd Put tests in check_PROGRAMS to prevent compilation when invoking 'make all' (LP: #229443) 2008-05-12 14:06:50 +02:00
Johannes H. Jensen
06e42b795a Removed tests from 'make all'. They can still be run inside src/tests. (LP: #229443) 2008-05-12 13:52:33 +02:00
Johannes H. Jensen
7853beed51 Removed tests from 'make all'. They can still be run inside src/tests 2008-05-12 13:40:42 +02:00
Johannes H. Jensen
3fed8fef09 Fixed a compilation bug. 2008-05-07 15:21:34 +02:00
Johannes H. Jensen
285e11f525 0.2.1 release. 2008-05-07 00:26:07 +02:00
Johannes H. Jensen
61c1e9cc18 Added copyright information to all test programs. 2008-05-07 00:12:09 +02:00
Johannes H. Jensen
e1269f3523 Automatically stop the alarm sound player after 20 minutes. 2008-05-06 22:59:45 +02:00
Johannes H. Jensen
ea5cc8f7b7 Set nofification bubble to never expire. 2008-05-06 22:36:05 +02:00
Johannes H. Jensen
743756fdae Fixed some issues 'make distclean'. 2008-05-05 23:31:20 +02:00
Johannes H. Jensen
d4741b78ac Set default snooze time to 9 minutes. 2008-05-02 00:12:51 +02:00
Johannes H. Jensen
27c0fc602c Fixed title of preferences to confirm to the new name: Alarm Clock. 2008-05-01 19:26:13 +02:00
Johannes H. Jensen
69709fb8f5 Edit alarm dialog no longer resizable. 2008-05-01 19:10:39 +02:00
Johannes H. Jensen
a4c36e0ece Added copyright information at the top of each source file. 2008-05-01 17:39:45 +02:00
Johannes H. Jensen
bb2a9def01 At last the 0.2 release! 2008-05-01 17:18:57 +02:00
Johannes H. Jensen
5adec50d5a New snooze icon. Thanks to Lasse Gullvåg Sætre!
Panel icon now reflects the type of the upcoming alarm.
2008-05-01 16:33:59 +02:00
Johannes H. Jensen
33b23ba2dc Snooze icon added in code. 2008-04-29 23:27:55 +02:00
Johannes H. Jensen
fd9d59d9b7 list-alarms resizing. 2008-04-29 17:56:15 +02:00
Johannes H. Jensen
2834c64c01 Clear & snooze actions added to Notification. 2008-04-29 17:36:35 +02:00
Johannes H. Jensen
57001316c6 Snooze working.
Notification now displaying the proper icon according to the alarm type.
2008-04-29 17:04:35 +02:00
Johannes H. Jensen
543d2ed170 Fixed a bug where the upcoming alarm would not get properly selected. 2008-04-29 09:31:05 +02:00
Johannes H. Jensen
8e89e4d224 Snooze working. Only the snooze UI elements remaining. 2008-04-29 01:01:57 +02:00
Johannes H. Jensen
c0a6696e81 Transition to "time". Seems to be working nicely now. 2008-04-29 00:08:12 +02:00
Johannes H. Jensen
70f601b8db Makefile.decl for GTest setup. 2008-04-28 23:50:12 +02:00
Johannes H. Jensen
91e1abef6c Refactoring alarm so both clock/timers store their time in the "time" property.
Replacing the "time" property with "timestamp" which enables us to update it for snoozing without affecting clock/timer settings.
tests/test_alarm completely rewritten to use the new GTest API.
2008-04-28 23:47:42 +02:00
Johannes H. Jensen
af2f81cf9f Fixed a bug where alarm_bind_weak_ref() would try to disconnect a signal handler from a finalized object. 2008-04-23 19:41:30 +02:00
Johannes H. Jensen
a1477db0e3 "More renaming to Alarm Clock.\nSchema for repeat property added." 2008-04-21 01:25:57 +02:00
Johannes H. Jensen
2cdac632a8 Renaming to Alarm Clock 2008-04-27 00:06:53 +02:00
Johannes H. Jensen
aa08618e2f Renaming to Alarm Clock 2008-04-27 00:03:15 +02:00
Johannes H. Jensen
112e548a46 Fixed repeat alarm system. Should work as expected now. 2008-04-20 20:09:36 +00:00
Johannes H. Jensen
1b5f5e03b7 Fixed a bug with AlarmRepeat where the repeat timestamp was wrongly calculated.
Week now starts on SUN=0 and ends on SAT=6 to be more compatible with mktime.
2008-04-20 16:08:07 +00:00
Johannes H. Jensen
e1752eaa6e Alarm repetition implemented!
Usability problem: What should happen if user changes repeat settings while the alarm repetition is running?
2008-04-12 15:35:19 +00:00
Johannes H. Jensen
28c66aa9be Fixed THE bug where the applet would segfault if the AlarmSettingsDialog was freed when the dialog was closed. This was due to the fact that the previous signal handlers (notify on alarm) were never disconnected and were passed the old dialog struct when the alarm was changed. This is now fixed both in the dialog and alarm_bind() 2008-04-05 21:38:02 +00:00
Johannes H. Jensen
78b4aa0d45 alarm.c: Alarm "repeat" property implemented.
edit-alarm.c: Interface updated to handle the new "repeat" property.
2008-04-05 00:16:40 +00:00
Johannes H. Jensen
98ed6dbba7 alarm.c: Added the "player_changed" signal.
alarms-list.c: Added an icon to indicate that the alarm is playing a sound.
ui.c: Added a more descriptive tooltip.
2008-04-03 10:56:54 +00:00
Johannes H. Jensen
e05caf5f10 alarm_applet_clear_alarms() implemented. 2008-04-02 23:40:04 +00:00
Johannes H. Jensen
ba806d4f5f alarm.c: Fixed a bug where the alarm time would not get updated on TIMER alarms if the alarm was already active when the timer property got updated.
alarm-applet: Added tooltips to applet.
2008-04-02 23:18:40 +00:00
Johannes H. Jensen
105d2b11ad alarm.c: Fixed a bug where the "time" field would not get updated if an alarm is active and the type changes from clock to timer.
Added upcoming alarm feature to the alarm label.
2008-04-02 22:15:07 +00:00
Johannes H. Jensen
a480a2e4a8 Fixed a bug where associated schemas would prevent an alarm from getting deleted. 2008-03-31 22:48:00 +00:00
Johannes H. Jensen
2b8c04280e Schemas now applied properly to applet & alarms. 2008-03-31 22:33:09 +00:00
Johannes H. Jensen
6cf92670b6 Applet is now properly destroyed when it is removed from the panel.
The apps list is now successfully loaded at startup.
AlarmApplet struct is now allocated and filled with 0's instead of assigning each field to NULL.
2008-03-31 21:28:16 +00:00
Johannes H. Jensen
407c7631f6 Added a destroy function for alarm_applet.
Unfortunately this is never called because I can't figure out which signal is emmited when the applet is removed from the panel.
2008-03-30 22:21:49 +00:00
Johannes H. Jensen
a7c0df948f alarm-list: Callback args are now free'd properly 2008-03-30 21:43:48 +00:00
Johannes H. Jensen
6c6388bfb9 Fixed a bug which caused a segfault where alarm_clear() would try to free a non-existing notify object.
Minor cleanups.
2008-03-27 18:51:51 +00:00
Johannes H. Jensen
369e2578c2 alarms-list.c: Fixed a bug where the timer callback would not get removed when the list alarms dialog closes.
alarm.c: Fixed a bug where the alarm timer would not get started if the alarm was active in gconf.
2008-03-25 15:50:17 +00:00
Johannes H. Jensen
9074f16c91 Fixed a bug where the notification bubble object would be tried freed when it doesn't exist. 2008-03-25 15:27:13 +00:00
Johannes H. Jensen
f9d18cb06a Renamed all GConf-mapped properties to have underscores (_) instead of dashes (-) to confirm to GConf policies. 2008-03-25 15:23:09 +00:00
Johannes H. Jensen
c31f071fd1 Notification bubble implemented. 2008-03-25 15:19:05 +00:00
Johannes H. Jensen
6e99356159 Adding an alarm now assigns the sound-file and command properties to the first one found in the stock sounds / apps list. 2008-03-25 14:54:16 +00:00
Johannes H. Jensen
59fdf79417 Fixed a bug where a double g_error_free() would occur. 2008-03-24 23:31:22 +00:00
Johannes H. Jensen
ae023bfc42 MAJOR code cleanup.
- Removed all old stuff
- Replaced various (non-working) functions with stubs.
2008-03-24 23:14:43 +00:00
Johannes H. Jensen
04e40d3a54 Will now close any open AlarmSettingsDialog if the referenced alarm is deleted.
Will now present an already open AlarmSettingsDialog instead of creating a new one.
list_alarms_update(): Fixed a bug where the alarm_changed notify handler would not get disconnected.
2008-03-24 00:19:22 +00:00
Johannes H. Jensen
0724799e44 alarm-applet.glade: Set a desired width of the GtkScrolledWindow which contains the alarms list.
alarms-list.c: Added notification handler for all alarms which then notifies of model change.
2008-03-23 23:16:32 +00:00
Johannes H. Jensen
4880f57e67 Alarm add & delete redesigned.
- Delete now works properly.
- External add & deletes now supported.
- Alarm references controlled properly.
2008-03-23 21:55:18 +00:00
Johannes H. Jensen
6b28b67690 Add alarm now updates list of alarms.
Delete alarm does not yet update the list properly.
2008-03-22 15:42:04 +00:00
Johannes H. Jensen
742c77ce2c App/command notification implemented & tested. 2008-03-20 18:22:36 +00:00
Johannes H. Jensen
6f3338fc69 Sound notification now implemented in GUI.
alarm.c: Added alarm_clear() for stopping an active MediaPlayer.
2008-03-12 20:28:28 +00:00
Johannes H. Jensen
2b5a146198 Getting closer.
In progress: Stock sounds & sounds combo box.
2008-03-12 01:44:18 +00:00
Johannes H. Jensen
84d21e4a30 Missing libgnomeui header inclusion which resulted in segfaults on gnome_icon_lookup on 64bit systems. 2008-03-12 01:40:16 +00:00
Johannes H. Jensen
b6db0c8d86 2008-03-11 20:34:02 +00:00
Johannes H. Jensen
894558fc30 Sometimes segfaults on alarm_time(r)_changed.
- Typically when multiple settings dialogs have been created / destroyed.
2008-02-25 23:02:57 +00:00
Johannes H. Jensen
738bff8d53 First part of the add alarm dialog in a working state. 2008-02-25 21:46:50 +00:00
Johannes H. Jensen
ed8666b3b6 Better 16x16 icon.
GLADE updated to include scrollarea and treeview.
2008-02-18 21:54:24 +00:00
Johannes H. Jensen
0fed7c5f3b New timer icon! 2008-02-18 20:22:07 +00:00
Johannes H. Jensen
af70650f3c List-alarms dialog response implemented.
The activate check box now only updates the alarm time if it's of type CLOCK. Setting the "active" property of a TIMER will update this automatically. 
- Is this what we want? What about the cases when there was a timer running while the computer shut down?
2008-02-18 00:21:39 +00:00
Johannes H. Jensen
2d7bb40e26 2 utility functions added to Alarm:
- alarm_set_time() for generating a timestamp in the future given hour, min, sec.
- alarm_update_time() which updates the current time to one in the future according to the hour, min and secs in the previous one.
2008-02-17 23:03:22 +00:00
Johannes H. Jensen
89a4dd8f23 Mockup timer icon added.
Alarm list dialog in the making.
2008-02-17 22:07:44 +00:00
Johannes H. Jensen
fabac6dfb8 Edit-alarm dialog in the making.
glade_view tool for quickly viewing glade files.
2008-01-28 05:23:26 +00:00
Johannes H. Jensen
2afcc3e8a7 Code commenting. 2008-01-28 03:48:15 +00:00
Johannes H. Jensen
f60be4c6b2 Fixed a bug where the show_label setting would not take affect on startup. 2008-01-28 03:47:35 +00:00
Johannes H. Jensen
faba8f2149 Test utilities added.
Alarm type TIMER will update the "time" property when activated to the current time + the value of the "timer" property.
2008-01-23 19:21:12 +00:00
Johannes H. Jensen
6712ba6883 Added the "timer" property for storing the settings of the timer alarm type. 2008-01-22 14:07:32 +00:00
Johannes H. Jensen
87bd83a71d Command notification implemented & tested. 2008-01-13 23:34:25 +00:00
Johannes H. Jensen
07b302531e Error signal implemented & tested.
Sound notification implemented & tested.
2008-01-13 23:28:23 +00:00
Johannes H. Jensen
328f01b306 Alarm timer implemented & tested. 2008-01-12 23:17:35 +00:00
Johannes H. Jensen
49d0837167 "alarm" signal implemented and tested. 2008-01-11 19:54:31 +00:00
Johannes H. Jensen
2a2fbb2fb4 alarm_get_list implemented. 2008-01-05 01:52:42 +00:00
Johannes H. Jensen
b0eae59421 Alarm class not fully functional. 2008-01-05 00:53:58 +00:00
Johannes H. Jensen
d288bc863b configure.ac: Added GConf library version check
alarm.[ch]: New alarm API - supports multiple alarms.
2008-01-02 02:54:38 +00:00
Johannes H. Jensen
5140c5c7fb 2007-12-27 05:57:32 +00:00
Johannes H. Jensen
fc7ee5accd Support different panel orientations and sizes. 2007-12-27 05:23:43 +00:00
Johannes H. Jensen
00a70db00b New icons! Thanks to Lasse Gullvåg Sætre. 2007-12-26 23:33:20 +00:00
69 changed files with 8324 additions and 4104 deletions

View File

@@ -1,2 +1,3 @@
Johannes H. Jensen <joh@deworks.net>
Artwork by Lasse Gullvåg Sætre <lassegs@gmail.com>

339
COPYING Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

211
ChangeLog
View File

@@ -1,211 +0,0 @@
2007-12-26 14:48 joh
* src/prefs.c: Preferences Dialog:
- Add tooltip which explains why the notification bubble
check-box is disabled when libnotify isn't present.
2007-12-26 14:44 joh
* src/Makefile.am, src/alarm-gconf.c, src/alarm.schemas: More
robust handling of GConf settings.
Provide more sensible GConf defaults.
2007-12-26 03:33 joh
* AUTHORS, README, src/Makefile.am, src/alarm-applet.c,
src/alarm-gconf.c, src/alarm-gconf.h, src/player.c, src/prefs.c,
src/ui.c, src/ui/alarm-applet.glade: - Added a more robust system
for handling gconf keys. This fixes a bug which causes the applet
to crash if the schema isn't installed.
- Fixed a bug where the command entry would be unsensitive even
if a custom command is set in gconf.
- Set window icons to the dialogs in alarm-applet.glade
2007-12-24 02:32 joh
* src/alarm-applet.h, src/ui.c: Add About dialog.
2007-12-24 01:29 joh
* Makefile.am, src/Makefile.am, src/tests/Makefile.am: make dist
work
2007-12-24 00:41 joh
* src/alarm-applet.c, src/alarm-gconf.c, src/ui.c, src/ui.h: Add
tooltip.
2007-12-24 00:18 joh
* config.h.in, configure.ac, src/Makefile.am, src/alarm-applet.c,
src/alarm-applet.h, src/alarm-gconf.c, src/prefs.c, src/ui.c,
src/ui.h: Add support for notification bubbles with libnotify.
2007-12-21 19:41 joh
* src/alarm-applet.c, src/alarm-applet.h, src/alarm-gconf.c,
src/prefs.c, src/ui.c: prefs.c:
- Added hard-coded command-map for apps. Should ideally be in
some XML file.
- Added app-detection to the app-combo
2007-12-21 10:24 joh
* src/alarm-applet.c, src/ui.c, src/ui.h: ui.c: Add support for
panel background.
2007-12-21 10:14 joh
* src/alarm-applet.c, src/alarm-applet.h, src/prefs.c, src/prefs.h,
src/ui.c, src/ui.h: Some more code migration.
2007-12-21 10:03 joh
* src/Makefile.am, src/alarm-applet.c, src/alarm-applet.h,
src/prefs.c, src/prefs.h, src/ui.c, src/ui.h, src/util.c,
src/util.h: UI and Preferences code moved to ui.c and prefs.c
2007-12-15 01:12 joh
* src/Makefile.am, src/alarm-applet.c, src/alarm-applet.h,
src/alarm-gconf.c, src/alarm-gconf.h: alarm-applet.c: GConf
abstracted to alarm-gconf.c
2007-12-14 22:29 joh
* src/Makefile.am, src/alarm-applet.c, src/alarm-applet.h:
alarm-applet.c: Use list-entry.o
2007-12-14 14:28 joh
* src/Makefile.am, src/alarm-applet.c, src/alarm-applet.h,
src/list-entry.c, src/list-entry.h, src/tests/Makefile.am,
src/tests/test_list_entry.c, src/tests/test_util.c, src/util.c,
src/util.h: Utilities and AlarmListEntry moved to separate
modules.
alarm-applet.c: Use util.o
2007-12-07 17:14 joh
* src/tests/Makefile.am:
2007-12-07 17:13 joh
* configure.ac, src/Makefile.am, src/test_player.c, src/tests,
src/tests/test_player.c: Move tests to src/tests
2007-12-05 02:47 joh
* src/Makefile.am, src/alarm-applet.c, src/alarm-applet.h,
src/player.h, src/spec.txt: alarm-applet.c:
- Modified to use MediaPlayer.
- ( More modularization coming up )
2007-12-05 02:05 joh
* src/Makefile.am: Linking per-binary added.
2007-12-05 02:01 joh
* src/Makefile.am: Updated to compile test_player
2007-12-05 02:00 joh
* src/test_player.c: Simple test program for the media player.
2007-12-05 02:00 joh
* src/player.c, src/player.h: Media player abstraction!
2007-12-03 00:18 joh
* src/alarm-applet.c, src/alarm-applet.h,
src/icons/alarm-clock.svg, src/ui/alarm-applet.glade,
src/ui/alarm-applet.glade.bak, src/ui/alarm-applet.gladep,
src/ui/alarm-applet.gladep.bak: Added a test app-list. Should
parse from gnome-default-applications.xml in the future.
- Fixed a bug due to Glade adding an empty text renderer to the
app-combo.
2007-12-02 00:11 joh
* ., src: svn:ignore updated.
2007-12-02 00:10 joh
* src/icons/alarm-clock.36.png, src/icons/alarm-clock.48.png,
src/icons/alarm-clock.64.png: Extra icon sizes.
2007-12-02 00:09 joh
* src/Makefile.am, src/alarm-applet.c, src/alarm-applet.h,
src/icons/alarm-clock.16.png, src/icons/alarm-clock.22.png,
src/icons/alarm-clock.24.png, src/icons/alarm-clock.32.png,
src/icons/alarm-clock.svg: icons:
- SVG size updated to contain the entire icon.
alarm-applet.c:
- Removed redundant GtkIconTheme pointer.
2007-12-01 19:34 joh
* src/alarm-applet.c: alarm-applet.c:
- destroy_cb bug fixed: Invalid signal handler for "destroy"
signal. Was casting the GtkObject to AlarmApplet. DUH!
2007-12-01 18:38 joh
* src/GNOME_AlarmApplet.server.in, src/Makefile.am,
src/alarm-applet.c, src/alarm-applet.h, src/icons,
src/icons/alarm-clock.16.png, src/icons/alarm-clock.22.png,
src/icons/alarm-clock.24.png, src/icons/alarm-clock.32.png,
src/icons/alarm-clock.svg: Makefile.am:
- Icons added for installation.
alarm-clock.c:
- Checks for valid gconf settings added to gconf callbacks.
- BUG: Crashes on destroy_cb()
2007-11-29 22:52 joh
* AUTHORS, ChangeLog, Makefile.am, NEWS, README, autogen.sh, m4,
m4/ac-define-dir.m4, m4/acinclude.m4, src/Makefile,
src/Makefile.old: Working autotoolized.
2007-11-29 22:44 joh
* config.h.in, configure.ac, src/GNOME_AlarmApplet.server,
src/GNOME_AlarmApplet.server.in, src/Makefile, src/Makefile.am,
src/Makefile.old, src/alarm-applet.c, src/alarm-applet.h,
src/alarm.schemas, src/ui, ui: Code reorganization.
2007-11-28 22:40 joh
* Makefile.am, config.h.in, configure.ac, src/Makefile.am:
Autoconfig stuff, not working yet.
2007-11-28 18:23 joh
* ., src: svn:ignores
2007-11-28 18:19 joh
* src/alarm-applet.h: alarm-applet.h:
- Use /usr/share/sounds for standard sounds directory.
2007-11-27 20:21 joh
* branches, tags, ., src, src/GNOME_AlarmApplet.server,
src/Makefile, src/alarm-applet.c, src/alarm-applet.h,
src/alarm.schemas, src/spec.txt, ui, ui/alarm-applet.glade,
ui/alarm-applet.glade.bak, ui/alarm-applet.gladep,
ui/alarm-applet.gladep.bak: Initial import.
- Timer works, timestamp based.
- GConf works, although second notification often is redundant.
- Different labels works.
- Notification by sound works.
- Custom sounds works.
- TODO:
- Notification by commands
- Standard application list (Rhythmbox, etc.)
- Notification bubble (libnotify)

2
INSTALL Normal file
View File

@@ -0,0 +1,2 @@
Please see the README file for installation instructions.

View File

@@ -1,5 +1,5 @@
SUBDIRS = src
DIST_SUBDIRS = src \
src/tests
include $(top_srcdir)/Makefile.decl
EXTRA_DIST = autogen.sh
SUBDIRS = src
EXTRA_DIST += autogen.sh

57
Makefile.decl Normal file
View File

@@ -0,0 +1,57 @@
# Alarm Clock
GTESTER = gtester # for non-GLIB packages
GTESTER_REPORT = gtester-report # for non-GLIB package
# initialize variables for unconditional += appending
EXTRA_DIST =
TEST_PROGS =
### testing rules
# test: run all tests in cwd and subdirs
test: ${TEST_PROGS}
@test -z "${TEST_PROGS}" || ${GTESTER} --verbose ${TEST_PROGS}
@ for subdir in $(SUBDIRS) . ; do \
test "$$subdir" = "." -o "$$subdir" = "po" || \
( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
done
# test-report: run tests in subdirs and generate report
# perf-report: run tests in subdirs with -m perf and generate report
# full-report: like test-report: with -m perf and -m slow
test-report perf-report full-report: ${TEST_PROGS}
@test -z "${TEST_PROGS}" || { \
case $@ in \
test-report) test_options="-k";; \
perf-report) test_options="-k -m=perf";; \
full-report) test_options="-k -m=perf -m=slow";; \
esac ; \
if test -z "$$GTESTER_LOGDIR" ; then \
${GTESTER} --verbose $$test_options -o test-report.xml ${TEST_PROGS} ; \
elif test -n "${TEST_PROGS}" ; then \
${GTESTER} --verbose $$test_options -o `mktemp "$$GTESTER_LOGDIR/log-XXXXXX"` ${TEST_PROGS} ; \
fi ; \
}
@ ignore_logdir=true ; \
if test -z "$$GTESTER_LOGDIR" ; then \
GTESTER_LOGDIR=`mktemp -d "\`pwd\`/.testlogs-XXXXXX"`; export GTESTER_LOGDIR ; \
ignore_logdir=false ; \
fi ; \
for subdir in $(SUBDIRS) . ; do \
test "$$subdir" = "." -o "$$subdir" = "po" || \
( cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $? ; \
done ; \
$$ignore_logdir || { \
echo '<?xml version="1.0"?>' > $@.xml ; \
echo '<report-collection>' >> $@.xml ; \
for lf in `ls -L "$$GTESTER_LOGDIR"/.` ; do \
sed '1,1s/^<?xml\b[^>?]*?>//' <"$$GTESTER_LOGDIR"/"$$lf" >> $@.xml ; \
done ; \
echo >> $@.xml ; \
echo '</report-collection>' >> $@.xml ; \
rm -rf "$$GTESTER_LOGDIR"/ ; \
${GTESTER_REPORT} --version 2>/dev/null 1>&2 ; test "$$?" != 0 || ${GTESTER_REPORT} $@.xml >$@.html ; \
}
.PHONY: test test-report perf-report full-report
# run make test as part of make check
check-local: test

14
README
View File

@@ -1,4 +1,4 @@
GNOME Alarm Applet
Alarm Clock
=================
This package contains an applet for use with the GNOME panel. Therefore, it
@@ -29,8 +29,8 @@ Installation
Unpackage with:
tar zxvf alarm-applet-<VERSION>.tar.gz'
cd alarm-applet-<VERSION>
tar zxvf alarm-clock-<VERSION>.tar.gz
cd alarm-clock-<VERSION>
Compile with the usual:
@@ -38,3 +38,11 @@ Compile with the usual:
./configure --prefix=/usr
make
make install
Note: It's important that you install into /usr so the BONOBO .server file is
placed under a directory which gnome-panel can recognize.
If you would like to install to another prefix, you need to move
AlarmClock.server to the bonobo server directory afterwards (usually
/usr/lib/bonobo/servers).

View File

@@ -4,12 +4,12 @@
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="GNOME Alarm Applet"
PKG_NAME="Alarm Clock"
(test -f $srcdir/configure.ac \
&& test -f $srcdir/src/alarm-applet.c) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level alarm-applet directory"
echo " top-level alarm-clock directory"
exit 1
}

View File

@@ -1,10 +1,10 @@
dnl ***************************************************************************
dnl *** configure.ac for ALARM-APPLET ***
dnl *** configure.ac for ALARM-CLOCK ***
dnl ***************************************************************************
AC_INIT([GNOME Alarm Applet], [0.1.1],
[Johannes H. Jensen <joh@deworks.net>],
[alarm-applet])
AC_INIT([Alarm Clock], [0.2.4],
[Johannes H. Jensen <joh@pseudoberries.com>],
[alarm-clock])
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE
@@ -13,7 +13,7 @@ AC_CONFIG_MACRO_DIR(m4)
AM_MAINTAINER_MODE
dnl ***************************************************************************
dnl *** Minimum library versions for ALARM-APPLET ***
dnl *** Minimum library versions for ALARM-CLOCK ***
dnl ***************************************************************************
GLIB_REQUIRED=2.13.0
@@ -29,12 +29,9 @@ GNOME_ICON_THEME_REQUIRED=2.15.91
LIBNOTIFY_REQUIRED=0.3.2
dnl LIBXML_REQUIRED=2.5.0
dnl LIBNOTIFY_REQUIRED=0.3.2
dnl ***************************************************************************
GNOME_INIT
AC_PROG_CC
AC_PROG_INSTALL
@@ -44,7 +41,7 @@ PKG_PROG_PKG_CONFIG([0.19])
GNOME_COMPILE_WARNINGS
dnl ***************************************************************************
dnl *** Use pkg-config to check for dependancies ***
dnl *** Use pkg-config to check for dependencies ***
dnl ***************************************************************************
dnl -- check for glib/gobject (required) --------------------------------------
@@ -62,6 +59,11 @@ PKG_CHECK_MODULES(GNOME_VFS, [gnome-vfs-2.0 >= $GNOME_VFS_REQUIRED])
AC_SUBST(GNOME_VFS_CFLAGS)
AC_SUBST(GNOME_VFS_LIBS)
dnl -- check for gconf (required) -----------------------------------------
PKG_CHECK_MODULES(GCONF, [gconf-2.0 >= $GCONF_REQUIRED])
AC_SUBST(GCONF_CFLAGS)
AC_SUBST(GCONF_LIBS)
dnl -- check for libglade (required) ------------------------------------------
PKG_CHECK_MODULES(LIBGLADE, libglade-2.0 >= $LIBGLADE_REQUIRED)
AC_SUBST(LIBGLADE_CFLAGS)
@@ -127,7 +129,7 @@ iconsdir="${datadir}/icons"
AC_SUBST(iconsdir)
pixmapsdir="${datadir}/pixmaps"
AC_SUBST(pixmapsdir)
pkgdatadir="${datadir}/alarm-applet"
pkgdatadir="${datadir}/alarm-clock"
AC_SUBST(pkgdatadir)
gladedir="${pkgdatadir}/glade"
AC_SUBST(gladedir)
@@ -148,3 +150,16 @@ AC_CONFIG_FILES([Makefile
src/Makefile
src/tests/Makefile])
AC_OUTPUT
dnl ***************************************************************************
dnl *** Show summary ***
dnl ***************************************************************************
echo
echo "*************************************************"
echo
echo "Configure summary:"
echo " Notifications (libnotify): $HAVE_LIBNOTIFY"
echo
echo "*************************************************"
echo

View File

@@ -1,17 +1,17 @@
<oaf_info>
<oaf_server iid="OAFIID:GNOME_AlarmApplet_Factory" type="exe"
location="@BINDIR@/alarm-applet">
<oaf_server iid="OAFIID:AlarmClock_Factory" type="exe"
location="@BINDIR@/alarm-clock-applet">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:Bonobo/GenericFactory:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Alarm Applet Factory"/>
<oaf_attribute name="description" type="string" value="Factory to create the alarm applet"/>
<oaf_attribute name="name" type="string" value="Alarm Clock Factory"/>
<oaf_attribute name="description" type="string" value="Factory to create the alarm clock applet"/>
</oaf_server>
<oaf_server iid="OAFIID:GNOME_AlarmApplet" type="factory"
location="OAFIID:GNOME_AlarmApplet_Factory">
<oaf_server iid="OAFIID:AlarmClock" type="factory"
location="OAFIID:AlarmClock_Factory">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>

View File

@@ -1,3 +1,7 @@
include $(top_srcdir)/Makefile.decl
SUBDIRS = . tests
INCLUDES = \
-I. \
-I$(srcdir) \
@@ -9,17 +13,20 @@ INCLUDES = \
$(LIBNOTIFY_CFLAGS) \
-I$(includedir)
bin_PROGRAMS = alarm-applet
bin_PROGRAMS = alarm-clock-applet
alarm_applet_SOURCES = alarm-applet.c alarm-applet.h \
alarm_clock_applet_SOURCES = alarm-applet.c alarm-applet.h \
player.c player.h \
util.c util.h \
list-entry.c list-entry.h \
alarm-gconf.c alarm-gconf.h \
ui.c ui.h \
prefs.c prefs.h
prefs.c prefs.h \
alarms-list.c alarms-list.h \
edit-alarm.c edit-alarm.h \
alarm.c alarm.h
alarm_applet_LDADD = \
alarm_clock_applet_LDADD = \
$(GLIB_LIBS) \
$(GNOME_LIBS2_LIBS) \
$(GNOME_APPLETS_LIBS) \
@@ -28,14 +35,14 @@ alarm_applet_LDADD = \
$(LIBNOTIFY_LIBS)
serverdir = $(libdir)/bonobo/servers
server_in_files = GNOME_AlarmApplet.server.in
server_in_files = AlarmClock.server.in
server_DATA = $(server_in_files:.server.in=.server)
$(server_DATA): $(server_in_files)
sed -e "s|\@BINDIR\@|$(bindir)|" $< > $@
uidir = $(gladedir)
ui_DATA = ui/alarm-applet.glade
ui_DATA = ui/alarm-clock.glade
icons = \
icons/alarm-clock.svg \
@@ -45,7 +52,22 @@ icons = \
icons/alarm-clock.32.png \
icons/alarm-clock.36.png \
icons/alarm-clock.48.png \
icons/alarm-clock.64.png
icons/alarm-clock.64.png \
icons/alarm-timer.svg \
icons/alarm-timer.16.png \
icons/alarm-timer.22.png \
icons/alarm-timer.24.png \
icons/alarm-timer.32.png \
icons/alarm-timer.36.png \
icons/alarm-timer.48.png \
icons/alarm-timer.64.png \
icons/alarm-snooze.16.png \
icons/alarm-snooze.22.png \
icons/alarm-snooze.24.png \
icons/alarm-snooze.32.png \
icons/alarm-snooze.36.png \
icons/alarm-snooze.48.png \
icons/alarm-snooze.64.png
gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
@@ -84,7 +106,7 @@ uninstall-icons:
done
schemasdir = @GCONF_SCHEMA_FILE_DIR@
schemas_in_files = alarm.schemas.in
schemas_in_files = alarm-clock.schemas.in
schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
CLEANFILES = $(server_DATA)
@@ -117,9 +139,7 @@ uninstall-local: uninstall-schemas uninstall-icons uninstall-data
#@INTLTOOL_SERVER_RULE@
EXTRA_DIST = $(server_in_files) \
EXTRA_DIST += $(server_in_files) \
$(schemas_DATA) \
$(icons) \
$(ui_DATA) \
tests/*.c \
tests/Makefile.am
$(ui_DATA)

View File

@@ -1,5 +1,31 @@
/*
* alarm-applet.c -- Alarm Clock applet bootstrap
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include "alarm-applet.h"
#include "alarm.h"
#include "edit-alarm.h"
/*
* DEFINTIIONS {{
*/
@@ -11,298 +37,509 @@ GHashTable *app_command_map = NULL;
* }} DEFINTIIONS
*/
/**
* Player error
*/
static void
player_error_cb (MediaPlayer *player, GError *err, AlarmApplet *applet)
{
gchar *uri;
uri = media_player_get_uri (player);
g_critical ("Could not play '%s': %s", err->message);
g_free (uri);
if (applet->preferences_dialog)
display_error_dialog ("Could not play", err->message, GTK_WINDOW (applet->preferences_dialog));
}
static void
player_state_cb (MediaPlayer *player, MediaPlayerState state, AlarmApplet *applet)
{
if (state == MEDIA_PLAYER_STOPPED) {
if (player == applet->player)
applet->player = NULL;
else if (player == applet->preview_player)
applet->preview_player = NULL;
g_debug ("Freeing media player %p", player);
media_player_free (player);
}
}
static void
player_preview_state_cb (MediaPlayer *player, MediaPlayerState state, AlarmApplet *applet)
{
const gchar *stock;
if (state == MEDIA_PLAYER_PLAYING)
stock = "gtk-media-stop";
else
stock = "gtk-media-play";
// Set stock
gtk_button_set_label (GTK_BUTTON (applet->pref_notify_sound_preview), stock);
player_state_cb (player, state, applet);
}
/**
* Play sound via gstreamer
*/
void
player_start (AlarmApplet *applet)
{
if (applet->player == NULL)
applet->player = media_player_new (get_sound_file (applet),
applet->notify_sound_loop,
player_state_cb, applet,
player_error_cb, applet);
media_player_set_uri (applet->player, get_sound_file (applet));
media_player_start (applet->player);
g_debug ("player_start...");
}
void
player_preview_start (AlarmApplet *applet)
{
if (applet->preview_player == NULL)
applet->preview_player = media_player_new (get_sound_file (applet),
FALSE,
player_preview_state_cb, applet,
player_error_cb, applet);
media_player_set_uri (applet->preview_player, get_sound_file (applet));
media_player_start (applet->preview_player);
g_debug ("preview_start...");
}
/*
* }} Media player
* Snooze any running (read: playing sound) alarms.
*/
/*
* TIMER {{
*/
void
trigger_alarm (AlarmApplet *applet)
alarm_applet_snooze_alarms (AlarmApplet *applet)
{
g_debug("ALARM: %s", applet->alarm_message);
GList *l;
Alarm *a;
alarm_gconf_set_started (applet, FALSE);
g_debug ("Snoozing alarms...");
applet->alarm_triggered = TRUE;
switch (applet->notify_type) {
case NOTIFY_SOUND:
// Start sound playback
player_start (applet);
break;
case NOTIFY_COMMAND:
// Start app
g_debug ("START APP");
command_run (applet->notify_command);
break;
default:
g_debug ("NOTIFICATION TYPE %d Not yet implemented.", applet->notify_type);
// Loop through alarms and snooze all of 'em
for (l = applet->alarms; l; l = l->next) {
a = ALARM (l->data);
alarm_snooze (a);
}
update_tooltip (applet);
#ifdef HAVE_LIBNOTIFY
if (applet->notify_bubble) {
display_notification (applet);
}
#endif
}
void
clear_alarm (AlarmApplet *applet)
{
alarm_gconf_set_started (applet, FALSE);
applet->alarm_triggered = FALSE;
timer_remove (applet);
update_label (applet);
update_tooltip (applet);
// Stop playback if present.
if (applet->player && applet->player->state == MEDIA_PLAYER_PLAYING)
media_player_stop (applet->player);
// Close notification if present.
#ifdef HAVE_LIBNOTIFY
if (applet->notify) {
close_notification (applet);
alarm_applet_notification_close (applet);
}
#endif
}
static gboolean
timer_update (AlarmApplet *applet)
/*
* Clear any running (read: playing sound) alarms.
*/
void
alarm_applet_clear_alarms (AlarmApplet *applet)
{
time_t now;
GList *l;
Alarm *a;
time (&now);
g_debug ("Clearing alarms...");
if (now >= applet->alarm_time) {
trigger_alarm (applet);
// Remove callback
return FALSE;
} else if (applet->alarm_time - now <= 10) {
g_debug ("%2d...", (int)(applet->alarm_time - now));
// Loop through alarms and clear all of 'em
for (l = applet->alarms; l; l = l->next) {
a = ALARM (l->data);
alarm_clear (a);
}
if (applet->show_label && applet->label_type == LABEL_TYPE_REMAIN) {
update_label (applet);
// Close notification if present.
#ifdef HAVE_LIBNOTIFY
if (applet->notify) {
alarm_applet_notification_close (applet);
}
#endif
}
/*
* Sounds list {{
*/
// Load sounds into list
// TODO: Refactor to use a GHashTable with string hash
void
alarm_applet_sounds_load (AlarmApplet *applet)
{
Alarm *alarm;
AlarmListEntry *entry;
GList *l, *l2;
gboolean found;
//g_assert (applet->alarms);
// Free old list
if (applet->sounds != NULL)
alarm_list_entry_list_free (&(applet->sounds));
// Load stock sounds
applet->sounds = alarm_list_entry_list_new ("file://" ALARM_SOUNDS_DIR,
supported_sound_mime_types);
// Load custom sounds from alarms
for (l = applet->alarms; l != NULL; l = l->next) {
alarm = ALARM (l->data);
found = FALSE;
for (l2 = applet->sounds; l2 != NULL; l2 = l2->next) {
entry = (AlarmListEntry *)l2->data;
if (strcmp (alarm->sound_file, entry->data) == 0) {
// FOUND
found = TRUE;
break;
}
}
// Keep callback
return TRUE;
if (!found) {
// Add to list
entry = alarm_list_entry_new_file (alarm->sound_file, NULL, NULL);
if (entry) {
applet->sounds = g_list_append (applet->sounds, entry);
}
}
}
}
void
timer_start (AlarmApplet *applet)
// Notify callback for changes to an alarm's sound_file
static void
alarm_sound_file_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
g_debug ("timer_start");
Alarm *alarm = ALARM (object);
AlarmApplet *applet = (AlarmApplet *)data;
// Remove old timer, if any
timer_remove (applet);
g_debug ("alarm_sound_file_changed: #%d", alarm->id);
applet->timer_id = g_timeout_add_seconds (1, (GSourceFunc) timer_update, applet);
// Reload sounds list
alarm_applet_sounds_load (applet);
}
void
timer_remove (AlarmApplet *applet)
{
if (applet->timer_id > 0) {
g_source_remove (applet->timer_id);
applet->timer_id = 0;
/*
* }} Sounds list
*/
/*
* Apps list {{
*/
static gchar *
gnome_da_xml_get_string (const xmlNode *parent, const gchar *val_name)
{
const gchar * const *sys_langs;
xmlChar *node_lang;
xmlNode *element;
gchar *ret_val = NULL;
xmlChar *xml_val_name;
gint len;
gint i;
g_return_val_if_fail (parent != NULL, ret_val);
g_return_val_if_fail (parent->children != NULL, ret_val);
g_return_val_if_fail (val_name != NULL, ret_val);
#if GLIB_CHECK_VERSION (2, 6, 0)
sys_langs = g_get_language_names ();
#endif
xml_val_name = xmlCharStrdup (val_name);
len = xmlStrlen (xml_val_name);
for (element = parent->children; element != NULL; element = element->next) {
if (!xmlStrncmp (element->name, xml_val_name, len)) {
node_lang = xmlNodeGetLang (element);
if (node_lang == NULL) {
ret_val = (gchar *) xmlNodeGetContent (element);
} else {
for (i = 0; sys_langs[i] != NULL; i++) {
if (!strcmp (sys_langs[i], node_lang)) {
ret_val = (gchar *) xmlNodeGetContent (element);
/* since sys_langs is sorted from most desirable to
* least desirable, exit at first match
*/
break;
}
}
}
xmlFree (node_lang);
}
}
xmlFree (xml_val_name);
return ret_val;
}
static const gchar *
get_app_command (const gchar *app)
{
// TODO: Shouldn't be a global variable
if (app_command_map == NULL) {
app_command_map = g_hash_table_new (g_str_hash, g_str_equal);
/* `rhythmbox-client --play' doesn't actually start playing unless
* Rhythmbox is already running. Sounds like a Bug. */
g_hash_table_insert (app_command_map,
"rhythmbox", "rhythmbox-client --play");
g_hash_table_insert (app_command_map,
"banshee", "banshee --play");
// Note that totem should already be open with a file for this to work.
g_hash_table_insert (app_command_map,
"totem", "totem --play");
// Muine crashes and doesn't seem to have any play command
/*g_hash_table_insert (app_command_map,
"muine", "muine");*/
}
return g_hash_table_lookup (app_command_map, app);
}
// Load stock apps into list
void
alarm_applet_apps_load (AlarmApplet *applet)
{
AlarmListEntry *entry;
gchar *filename, *name, *icon, *command;
xmlDoc *xml_doc;
xmlNode *root, *section, *element;
gchar *executable;
const gchar *tmp;
if (applet->apps != NULL)
alarm_list_entry_list_free (&(applet->apps));
// We'll get the default media players from g-d-a.xml
// from gnome-control-center
filename = g_build_filename (DATADIR,
"gnome-control-center",
"gnome-default-applications.xml",
NULL);
if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
g_critical ("Could not find %s.", filename);
return;
}
xml_doc = xmlParseFile (filename);
if (!xml_doc) {
g_warning ("Could not load %s.", filename);
return;
}
root = xmlDocGetRootElement (xml_doc);
for (section = root->children; section != NULL; section = section->next) {
if (!xmlStrncmp (section->name, "media-players", 13)) {
for (element = section->children; element != NULL; element = element->next) {
if (!xmlStrncmp (element->name, "media-player", 12)) {
executable = gnome_da_xml_get_string (element, "executable");
if (is_executable_valid (executable)) {
name = gnome_da_xml_get_string (element, "name");
icon = gnome_da_xml_get_string (element, "icon-name");
// Lookup executable in app command map
tmp = get_app_command (executable);
if (tmp)
command = g_strdup (tmp);
else {
// Fall back to command specified in XML
command = gnome_da_xml_get_string (element, "command");
}
g_debug ("LOAD-APPS: Adding '%s': %s [%s]", name, command, icon);
entry = alarm_list_entry_new (name, command, icon);
g_free (name);
g_free (command);
g_free (icon);
applet->apps = g_list_append (applet->apps, entry);
}
if (executable)
g_free (executable);
}
}
}
}
g_free (filename);
// entry = alarm_list_entry_new("Rhythmbox Music Player", "rhythmbox", "rhythmbox");
// applet->apps = g_list_append (applet->apps, entry);
}
/*
* Alarm signals {{
*/
/*
* Find the soonest-to-trigger upcoming alarm
*/
static void
alarm_applet_upcoming_alarm_update (AlarmApplet *applet)
{
GList *l;
Alarm *a;
applet->upcoming_alarm = NULL;
/* Loop through alarms looking for all active upcoming alarms and locate
* the one which will trigger sooner.
*/
for (l = applet->alarms; l; l = l->next) {
a = ALARM (l->data);
if (!a->active) continue;
if (!applet->upcoming_alarm || a->timestamp < applet->upcoming_alarm->timestamp) {
// This alarm is most recent
applet->upcoming_alarm = a;
}
}
}
/*
* }} TIMER
* Callback for when an alarm is activated / deactivated.
* We use this to update our closest upcoming alarm.
*/
static void
alarm_active_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
Alarm *alarm = ALARM (object);
AlarmApplet *applet = (AlarmApplet *)data;
g_debug ("alarm_active_changed: #%d to %d", alarm->id, alarm->active);
// Check if this was the upcoming alarm
if (!alarm->active) {
if (applet->upcoming_alarm == alarm) {
applet->upcoming_alarm = NULL;
alarm_applet_upcoming_alarm_update (applet);
alarm_applet_label_update (applet);
alarm_applet_icon_update (applet);
}
return;
}
if (!applet->upcoming_alarm || alarm->timestamp < applet->upcoming_alarm->timestamp) {
// We're next!
applet->upcoming_alarm = alarm;
alarm_applet_label_update (applet);
return;
}
}
/*
* Callback for when an alarm is triggered
* We show the notification bubble here if appropriate.
*/
static void
alarm_triggered (Alarm *alarm, gpointer data)
{
AlarmApplet *applet = (AlarmApplet *)data;
g_debug ("Alarm triggered: #%d", alarm->id);
if (alarm->notify_bubble) {
g_debug ("Alarm #%d NOTIFICATION DISPLAY", alarm->id);
alarm_applet_notification_display (applet, alarm);
}
}
/*
* }} Alarm signals
*/
/*
* Alarms list {{
*/
gboolean
set_sound_file (AlarmApplet *applet, const gchar *uri)
// TODO: Refactor to use a GHashTable instead
void
alarm_applet_alarms_load (AlarmApplet *applet)
{
AlarmListEntry *item, *p;
GnomeVFSResult result;
gchar *mime;
if (applet->alarms != NULL) {
GList *l;
guint pos, i;
gboolean valid;
if (uri == NULL || g_utf8_strlen(uri, 1) == 0)
return FALSE;
g_debug ("set_sound_file (%s)", uri);
item = alarm_list_entry_new_file (uri, &result, &mime);
if (item == NULL) {
g_debug ("Invalid sound file: %s", uri);
if (applet->preferences_dialog != NULL) {
gchar *message = g_strdup_printf ("Unable to open '%s': %s.", uri, gnome_vfs_result_to_string (result));
display_error_dialog("Invalid Sound File", message, GTK_WINDOW (applet->preferences_dialog));
g_free(message);
/* Free old alarm objects */
for (l = applet->alarms; l != NULL; l = l->next) {
g_object_unref (ALARM (l->data));
}
g_free(mime);
return FALSE;
/* Free list */
g_list_free (applet->alarms);
}
valid = FALSE;
for (i = 0; supported_sound_mime_types[i] != NULL; i++) {
if (strstr (mime, supported_sound_mime_types[i]) != NULL) {
// MATCH
//g_debug (" [ MATCH ]");
valid = TRUE;
break;
}
}
if (!valid) {
g_critical ("Invalid sound file '%s': MIME-type not supported: %s", uri, mime);
if (applet->preferences_dialog != NULL) {
gchar *message = g_strdup_printf ("The file '%s' is not a valid media file.", uri);
display_error_dialog("Invalid Sound File", message, GTK_WINDOW (applet->preferences_dialog));
g_free(message);
}
g_free (mime);
return FALSE;
}
g_free (mime);
// See if it's one of the already loaded files
for (l = applet->sounds, pos = 0; l != NULL; l = l->next, pos++) {
p = (AlarmListEntry *) l->data;
g_debug ("CHECK %s == %s", p->data, uri);
if (strcmp (p->data, uri) == 0) {
g_debug ("set_sound_file FOUND at pos %d", pos);
break;
}
}
g_debug ("After search, pos = %d vs length %d", pos, g_list_length (applet->sounds));
// If not, add it to the list
if (pos == g_list_length (applet->sounds)) {
g_debug ("Adding to list: %s %s %s", item->name, item->data, item->icon);
applet->sounds = g_list_append (applet->sounds, item);
}
applet->sound_pos = pos;
return TRUE;
/* Fetch list of alarms */
applet->alarms = alarm_get_list (ALARM_GCONF_DIR);
}
const gchar *
get_sound_file (AlarmApplet *applet)
void
alarm_applet_alarms_add (AlarmApplet *applet, Alarm *alarm)
{
AlarmListEntry *e;
e = (AlarmListEntry *) g_list_nth_data (applet->sounds, applet->sound_pos);
applet->alarms = g_list_append (applet->alarms, alarm);
g_debug ("get_sound_file returning %p", e);
g_signal_connect (alarm, "notify::sound-file", G_CALLBACK (alarm_sound_file_changed), applet);
g_signal_connect (alarm, "notify::active", G_CALLBACK (alarm_active_changed), applet);
g_signal_connect (alarm, "notify::time", G_CALLBACK (alarm_active_changed), applet);
return (const gchar *)e->data;
g_signal_connect (alarm, "alarm", G_CALLBACK (alarm_triggered), applet);
}
void
alarm_applet_alarms_remove (AlarmApplet *applet, Alarm *alarm)
{
/*
* Remove from list
*/
applet->alarms = g_list_remove (applet->alarms, alarm);
/*
* Clear list store. This will decrease the refcount of our alarms by 1.
*/
if (applet->list_alarms_store)
gtk_list_store_clear (applet->list_alarms_store);
g_debug ("alarm_applet_alarms_remove (..., %p): refcount = %d", alarm, G_OBJECT (alarm)->ref_count);
/*
* If this is the upcoming alarm, update it.
*/
if (applet->upcoming_alarm == alarm) {
alarm_applet_upcoming_alarm_update (applet);
}
/*
* Remove any signal handlers for this alarm instance.
*/
g_signal_handlers_disconnect_matched (alarm, 0, 0, 0, NULL, NULL, NULL);
/*
* Dereference alarm
*/
g_object_unref (alarm);
}
/*
* }} Alarms list
*/
void
alarm_applet_destroy (AlarmApplet *applet)
{
GList *l;
Alarm *a;
AlarmSettingsDialog *dialog;
g_debug ("AlarmApplet DESTROY");
// Remove any timers
if (applet->timer_id) {
g_source_remove (applet->timer_id);
}
// Destroy alarms list
if (applet->list_alarms_dialog) {
list_alarms_dialog_close (applet);
}
// Destroy preferences dialog
if (applet->preferences_dialog) {
gtk_widget_destroy (GTK_WIDGET (applet->preferences_dialog));
}
// Loop through all alarms and free like a mad man!
for (l = applet->alarms; l; l = l->next) {
a = ALARM (l->data);
// Check if a dialog is open for this alarm
dialog = (AlarmSettingsDialog *)g_hash_table_lookup (applet->edit_alarm_dialogs, (gconstpointer)a->id);
if (dialog) {
alarm_settings_dialog_close (dialog);
//g_free (dialog);
}
g_object_unref (a);
}
// Remove sounds list
if (applet->sounds) {
alarm_list_entry_list_free(&(applet->sounds));
}
// Remove apps list
if (applet->apps) {
alarm_list_entry_list_free(&(applet->apps));
}
if (app_command_map) {
g_hash_table_destroy (app_command_map);
app_command_map = NULL;
}
// Free GConf dir
g_free (applet->gconf_dir);
// Finally free the AlarmApplet struct itself
g_free (applet);
}
/*
@@ -315,78 +552,72 @@ alarm_applet_factory (PanelApplet *panelapplet,
gpointer data)
{
AlarmApplet *applet;
AlarmListEntry *item;
gchar *tmp;
if (strcmp (iid, "OAFIID:GNOME_AlarmApplet") != 0)
if (strcmp (iid, "OAFIID:AlarmClock") != 0)
return FALSE;
/* Initialize applet struct */
applet = g_new(AlarmApplet, 1);
applet->alarm_time = 0;
applet->alarm_message = NULL;
applet->started = FALSE;
applet->alarm_triggered = FALSE;
applet->timer_id = 0;
applet->player = NULL;
applet->preview_player = NULL;
applet->sounds = NULL;
applet->sound_pos = 0;
applet->apps = NULL;
/* Initialize applet struct,
* fill with zero's */
applet = g_new0 (AlarmApplet, 1);
applet->parent = panelapplet;
applet->set_alarm_dialog = NULL;
applet->preferences_dialog = NULL;
applet->edit_alarm_dialogs = g_hash_table_new (NULL, NULL);
/* Preferences (defaults).
* ...gconf_get_string can return NULL if the key is not found. We can't
* assume the schema provides the default values for strings. */
applet->show_label = TRUE;
applet->label_type = LABEL_TYPE_ALARM;
applet->notify_type = NOTIFY_SOUND;
applet->notify_sound_loop = TRUE;
applet->notify_bubble = TRUE;
applet->label_type = LABEL_TYPE_TIME;
/* Prepare */
/* Prepare applet */
panel_applet_add_preferences (applet->parent, ALARM_SCHEMA_DIR, NULL);
panel_applet_set_flags (PANEL_APPLET (panelapplet), PANEL_APPLET_EXPAND_MINOR);
// Load sounds list
load_stock_sounds_list (applet);
// Load applications list
load_app_list (applet);
applet->gconf_dir = panel_applet_get_preferences_key (applet->parent);
/* Set up gconf handlers */
setup_gconf (applet);
alarm_applet_gconf_init (applet);
/* Load gconf values */
load_gconf (applet);
alarm_applet_gconf_load (applet);
/* Load alarms */
alarm_applet_alarms_load (applet);
/* Find any upcoming active alarms */
alarm_applet_upcoming_alarm_update (applet);
/* Load sounds from alarms */
alarm_applet_sounds_load (applet);
/* Load apps for alarms */
alarm_applet_apps_load (applet);
/* Connect sound_file notify callback to all alarms */
alarm_signal_connect_list (applet->alarms, "notify::sound-file",
G_CALLBACK (alarm_sound_file_changed), applet);
/* Connect active & time notify callback to all alarms */
alarm_signal_connect_list (applet->alarms, "notify::active",
G_CALLBACK (alarm_active_changed), applet);
alarm_signal_connect_list (applet->alarms, "notify::time",
G_CALLBACK (alarm_active_changed), applet);
/* Connect alarm trigger notify to all alarms */
alarm_signal_connect_list (applet->alarms, "alarm",
G_CALLBACK (alarm_triggered), applet);
/* Set up properties menu */
menu_setup(applet);
alarm_applet_menu_init (applet);
/* Set up applet */
ui_setup (applet);
if (applet->started) {
// Start the timer!
update_label (applet);
update_tooltip (applet);
timer_start (applet);
}
g_debug ("GLADE DIR: %s", GNOME_GLADEDIR);
alarm_applet_ui_init (applet);
return TRUE;
}
PANEL_APPLET_BONOBO_FACTORY ("OAFIID:GNOME_AlarmApplet_Factory",
PANEL_APPLET_BONOBO_FACTORY ("OAFIID:AlarmClock_Factory",
PANEL_TYPE_APPLET,
"alarm_applet",
"alarm_clock",
VERSION,
alarm_applet_factory,
NULL);

View File

@@ -1,3 +1,26 @@
/*
* alarm-applet.h -- Alarm Clock applet bootstrap
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef ALARMAPPLET_H_
#define ALARMAPPLET_H_
@@ -29,15 +52,10 @@ typedef struct _AlarmApplet AlarmApplet;
gchar *supported_sound_mime_types[];
GHashTable *app_command_map;
void update_label (AlarmApplet *applet);
void timer_remove (AlarmApplet *applet);
gboolean set_sound_file (AlarmApplet *applet, const gchar *uri);
void timer_start (AlarmApplet *applet);
void clear_alarm (AlarmApplet *applet);
void set_alarm_dialog_populate (AlarmApplet *applet);
const gchar *get_sound_file (AlarmApplet *applet);
void player_preview_start (AlarmApplet *applet);
void alarm_applet_label_update (AlarmApplet *applet);
void alarm_applet_clear_alarms (AlarmApplet *applet);
#include "alarm.h"
#include "prefs.h"
#include "alarm-gconf.h"
#include "player.h"
@@ -45,11 +63,16 @@ void player_preview_start (AlarmApplet *applet);
#include "list-entry.h"
#include "ui.h"
#define ALARM_NAME "Alarm Clock Applet"
#define ALARM_NAME "Alarm Clock"
#define ALARM_ICON "alarm-clock"
#define ALARM_SCHEMA_DIR "/schemas/apps/alarm_applet/prefs"
#define ALARM_UI_XML GNOME_GLADEDIR "/alarm-applet.glade"
#define TIMER_ICON "alarm-timer"
#define SNOOZE_ICON "alarm-snooze"
#define ALARM_GCONF_DIR "/apps/alarm-clock"
#define ALARM_SCHEMA_DIR "/schemas/apps/alarm_clock/prefs"
#define ALARM_UI_XML GNOME_GLADEDIR "/alarm-clock.glade"
#define ALARM_SOUNDS_DIR GNOME_SOUNDSDIR
#define ALARM_DEF_LABEL _("No alarms")
#define ALARM_DEF_SNOOZE 9
#ifndef VERSION
#define VERSION "0.1"
@@ -57,87 +80,57 @@ void player_preview_start (AlarmApplet *applet);
typedef enum {
LABEL_TYPE_INVALID = 0,
LABEL_TYPE_ALARM,
LABEL_TYPE_TIME,
LABEL_TYPE_REMAIN,
} LabelType;
typedef enum {
NOTIFY_INVALID = 0,
NOTIFY_SOUND,
NOTIFY_COMMAND,
} NotifyType;
enum
{
PIXBUF_COL,
TEXT_COL,
N_COLUMNS
};
struct _AlarmApplet {
PanelApplet *parent;
PanelAppletOrient orient;
gchar *gconf_dir;
/* Panel UI */
GtkWidget *icon; /* alarm icon */
GtkWidget *label; /* clock label */
GtkWidget *box; /* packing box */
/* Alarm */
time_t alarm_time;
gchar *alarm_message;
gboolean started;
gboolean alarm_triggered;
guint timer_id;
guint timer_id; /* timer ID for updating the label */
/* Set-alarm */
GtkDialog *set_alarm_dialog;
GtkWidget *hour;
GtkWidget *minute;
GtkWidget *second;
GtkWidget *message;
/* Alarms */
GList *alarms;
Alarm *upcoming_alarm; /* Next upcoming alarm */
/* Sounds & apps list */
GList *sounds;
GList *apps;
/* List-alarms UI */
GtkDialog *list_alarms_dialog;
GtkListStore *list_alarms_store;
GtkTreeView *list_alarms_view;
GList *list_alarms_args;
/* Open edit alarm dialogs
* Hashed by ID */
GHashTable *edit_alarm_dialogs;
/* Preferences */
GtkDialog *preferences_dialog;
/* Notification */
#ifdef HAVE_LIBNOTIFY
NotifyNotification *notify;
#endif
/* Preferences */
GtkDialog *preferences_dialog;
/* Label */
GtkWidget *pref_label_show;
GtkWidget *pref_label_type_box;
GtkWidget *pref_label_type_alarm;
GtkWidget *pref_label_type_remaining;
/* Notification */
GtkWidget *pref_notify_sound;
GtkWidget *pref_notify_sound_box;
GtkWidget *pref_notify_sound_stock;
GtkWidget *pref_notify_sound_combo;
GtkWidget *pref_notify_sound_loop;
GtkWidget *pref_notify_sound_preview;
GtkWidget *pref_notify_app;
GtkWidget *pref_notify_app_box;
GtkWidget *pref_notify_app_combo;
GtkWidget *pref_notify_app_command_box;
GtkWidget *pref_notify_app_command_entry;
GtkWidget *pref_notify_bubble;
GtkWidget *pref_label_type_time;
GtkWidget *pref_label_type_remain;
/* Actual preferences data */
gboolean show_label;
LabelType label_type;
NotifyType notify_type;
gboolean notify_sound_loop;
gchar *notify_command;
gboolean notify_bubble;
GList *sounds;
guint stock_sounds; // Number of stock sounds
guint sound_pos; // Position of the current selected sound in the sounds list.
GList *apps;
/* MediaPlayer */
MediaPlayer *player;
MediaPlayer *preview_player;
/* GConf */
guint listeners [N_GCONF_PREFS];
@@ -146,6 +139,18 @@ struct _AlarmApplet {
static void set_alarm_time (AlarmApplet *applet, guint hour, guint minute, guint second);
//static void time_changed_cb (GtkSpinButton *spinbutton, gpointer data);
void alarm_applet_sounds_load (AlarmApplet *applet);
void alarm_applet_apps_load (AlarmApplet *applet);
void alarm_applet_alarms_load (AlarmApplet *applet);
void alarm_applet_alarms_add (AlarmApplet *applet, Alarm *alarm);
void alarm_applet_alarms_remove (AlarmApplet *applet, Alarm *alarm);
void alarm_applet_destroy (AlarmApplet *applet);
G_END_DECLS
#endif /*ALARMAPPLET_H_*/

View File

@@ -0,0 +1,51 @@
=head1 NAME
alarm-clock-applet - Alarm Clock applet for GNOME
=head1 SYNOPSIS
alarm-clock-applet
=head1 DESCRIPTION
Alarm Clock is a fully-featured alarm clock appelt for the GNOME panel.
It's easy to use yet powerful with support for multiple repeatable alarms,
as well as snoozing and a flexible notification system.
Two types of alarms are supported: Alarm Clocks and Timers.
Notification is done by either playing a sound or launching an application.
Please see http://alarm-clock.pseudoberries.com/ for more information.
=head1 OPTIONS
=over 8
=item B<--help>
Show help message
=item B<--version>
Displays information about the currently installed version and exists.
=head1 BUGS
Please report bugs at https://bugs.launchpad.net/alarm-clock/
=head1 AUTHORS
B<Alarm Clock> was written by Johannes H. Jensen <joh@pseudoberries.com>.
=head1 COPYRIGHT
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
On Debian GNU/Linux systems, the complete text of the GNU General
Public License can be found in `/usr/share/common-licenses/GPL'.
=cut

View File

@@ -2,42 +2,13 @@
<gconfschemafile>
<schemalist>
<schema>
<key>/schemas/apps/alarm_applet/prefs/alarm_time</key>
<owner>alarm-applet</owner>
<type>int</type>
<locale name="C">
<default>0</default>
<short>Alarm timestamp</short>
<long>The UNIX timestamp for the alarm.</long>
</locale>
</schema>
<!--
Applet specific:
-->
<schema>
<key>/schemas/apps/alarm_applet/prefs/message</key>
<owner>alarm-applet</owner>
<type>string</type>
<locale name="C">
<default>Alarm!</default>
<short>Message describing this alarm.</short>
<long>A short message which will be displayed when the alarm goes off.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/started</key>
<owner>alarm-applet</owner>
<type>bool</type>
<locale name="C">
<default>false</default>
<short>The running state of the alarm.</short>
<long>If true, indicates that the alarm is started.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/show_label</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/prefs/show_label</key>
<owner>alarm-clock</owner>
<type>bool</type>
<locale name="C">
<default>true</default>
@@ -48,22 +19,116 @@
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/label_type</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/prefs/label_type</key>
<owner>alarm-clock</owner>
<type>string</type>
<locale name="C">
<default>alarm-time</default>
<short>Type of label to display.</short>
<long>The type of label to display if show_label is true.
Can be either "alarm-time" for showing the current alarm time or
"remaining-time" for showing the time remaining until the alarm goes off.
Can be either "alarm-time" for showing the current alarm time of the
closest alarm (read: first one to trigger) or "remaining-time" for showing
the time remaining until the closest alarm goes off.
</long>
</locale>
</schema>
<!--
Alarm specific:
-->
<schema>
<key>/schemas/apps/alarm_applet/prefs/notify_type</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/alarm/type</key>
<owner>alarm-clock</owner>
<type>string</type>
<locale name="C">
<default>clock</default>
<short>Alarm type</short>
<long>The type of the alarm. Either "clock" for an alarm which triggers
at a specific time of day or "timer" for an alarm which triggers
after a specified period of time.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/timestamp</key>
<owner>alarm-clock</owner>
<type>int</type>
<locale name="C">
<default>0</default>
<short>Alarm timestamp</short>
<long>The UNIX timestamp for the alarm.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/time</key>
<owner>alarm-clock</owner>
<type>int</type>
<locale name="C">
<default>0</default>
<short>Alarm time</short>
<long>The time (GMT) for the alarm.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/message</key>
<owner>alarm-clock</owner>
<type>string</type>
<locale name="C">
<default>Alarm!</default>
<short>Message describing this alarm.</short>
<long>A short message which will be displayed when the alarm goes off.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/active</key>
<owner>alarm-clock</owner>
<type>bool</type>
<locale name="C">
<default>false</default>
<short>The running state of the alarm.</short>
<long>If true, indicates that the alarm is started.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/repeat</key>
<owner>alarm-clock</owner>
<type>list</type>
<list_type>string</list_type>
<locale name="C">
<default>[]</default>
<short>When to repeat the alarm.</short>
<long>Indicates which days to repeat the alarm. Only applicable for "clock" alarms.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/snooze</key>
<owner>alarm-clock</owner>
<type>int</type>
<locale name="C">
<default>0</default>
<short>Enable snoozing of alarm.</short>
<long>If non-zero, indicates that the alarm can be snoozed for the selected minutes.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/alarm_clock/alarm/notify_type</key>
<owner>alarm-clock</owner>
<type>string</type>
<locale name="C">
<default>sound</default>
@@ -77,8 +142,8 @@
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/sound_file</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/alarm/sound_file</key>
<owner>alarm-clock</owner>
<type>string</type>
<locale name="C">
<default></default>
@@ -88,8 +153,8 @@
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/sound_repeat</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/alarm/sound_repeat</key>
<owner>alarm-clock</owner>
<type>bool</type>
<locale name="C">
<default>TRUE</default>
@@ -99,8 +164,8 @@
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/command</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/alarm/command</key>
<owner>alarm-clock</owner>
<type>string</type>
<locale name="C">
<default>rhythmbox-client --play</default>
@@ -110,8 +175,8 @@
</schema>
<schema>
<key>/schemas/apps/alarm_applet/prefs/notify_bubble</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/alarm/notify_bubble</key>
<owner>alarm-clock</owner>
<type>bool</type>
<locale name="C">
<default>true</default>
@@ -122,8 +187,8 @@
<!--
<schema>
<key>/schemas/apps/alarm_applet/prefs/</key>
<owner>alarm-applet</owner>
<key>/schemas/apps/alarm_clock/prefs/</key>
<owner>alarm-clock</owner>
<type></type>
<locale name="C">
<default></default>

View File

@@ -1,7 +1,24 @@
/*
* alarm-gconf.c -- GConf routines
*
* ALARM APPLET Gconf callbacks and utilities.
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <time.h>
@@ -9,171 +26,24 @@
#include "alarm-applet.h"
#include "alarm-gconf.h"
#include "edit-alarm.h"
#include "alarm.h"
/*
* LabelType enum to GConf string value map
*/
GConfEnumStringPair label_type_enum_map [] = {
{ LABEL_TYPE_ALARM, "alarm-time" },
{ LABEL_TYPE_TIME, "alarm-time" },
{ LABEL_TYPE_REMAIN, "remaining-time" },
{ 0, NULL }
};
GConfEnumStringPair notify_type_enum_map [] = {
{ NOTIFY_SOUND, "sound" },
{ NOTIFY_COMMAND, "command" },
{ 0, NULL }
};
/*
* SETTERS {{
*/
/**
* Stores the alarm timestamp in gconf
*/
void
alarm_gconf_set_alarm (AlarmApplet *applet, guint hour, guint minute, guint second)
{
// Get timestamp
time_t timestamp = get_alarm_timestamp(hour, minute, second);
// Store in GConf
panel_applet_gconf_set_int (applet->parent, KEY_ALARMTIME, (gint)timestamp, NULL);
}
/**
* Stores the alarm message in gconf
*/
void
alarm_gconf_set_message (AlarmApplet *applet, const gchar *message)
{
g_debug ("set_alarm_message %s", message);
if (message == NULL)
return;
panel_applet_gconf_set_string (applet->parent, KEY_MESSAGE, message, NULL);
}
/**
* Sets started status of alarm in gconf
*/
void
alarm_gconf_set_started (AlarmApplet *applet, gboolean started)
{
// Store in GConf
panel_applet_gconf_set_bool (applet->parent, KEY_STARTED, started, NULL);
}
/*
* }} SETTERS
*/
/*
* GCONF CALLBACKS {{
*/
void
alarm_gconf_alarmtime_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("alarmtime_changed");
time_t value;
struct tm *tm;
if (!entry->value || entry->value->type != GCONF_VALUE_INT)
return;
value = (time_t) gconf_value_get_int (entry->value);
if (value < 0) {
g_debug ("[gconf] Invalid alarmtime: %d", value);
return;
}
if (applet->started) {
// We have already started, start timer
applet->alarm_time = value;
timer_start (applet);
} else {
// Fetch values
// We're only interested in the hour, minute and second fields
tm = localtime (&value);
applet->alarm_time = get_alarm_timestamp (tm->tm_hour, tm->tm_min, tm->tm_sec);
if (applet->set_alarm_dialog != NULL) {
set_alarm_dialog_populate (applet);
return;
}
}
update_label (applet);
}
void
alarm_gconf_message_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("message_changed");
const gchar *value;
if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
return;
value = gconf_value_get_string (entry->value);
if (applet->alarm_message != NULL) {
g_free (applet->alarm_message);
applet->alarm_message = NULL;
}
applet->alarm_message = g_strdup (value);
if (applet->set_alarm_dialog != NULL) {
set_alarm_dialog_populate (applet);
}
}
void
alarm_gconf_started_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("started_changed");
gboolean value;
time_t now;
if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
return;
value = gconf_value_get_bool (entry->value);
time (&now);
if (value && applet->alarm_time >= now) {
// Start timer
timer_start (applet);
applet->started = TRUE;
} else {
// Stop timer
timer_remove (applet);
applet->started = FALSE;
}
update_label (applet);
update_tooltip (applet);
}
void
alarm_gconf_show_label_changed (GConfClient *client,
alarm_applet_gconf_show_label_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
@@ -193,7 +63,7 @@ alarm_gconf_show_label_changed (GConfClient *client,
}
void
alarm_gconf_label_type_changed (GConfClient *client,
alarm_applet_gconf_label_type_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
@@ -209,10 +79,10 @@ alarm_gconf_label_type_changed (GConfClient *client,
if (tmp) {
if (!gconf_string_to_enum (label_type_enum_map, tmp, (gint *)&(applet->label_type))) {
// No match, set to default
applet->label_type = LABEL_TYPE_ALARM;
applet->label_type = DEF_LABEL_TYPE;
}
update_label (applet);
alarm_applet_label_update (applet);
}
if (applet->preferences_dialog != NULL) {
@@ -220,118 +90,104 @@ alarm_gconf_label_type_changed (GConfClient *client,
}
}
/*
* Triggered on global changes to our gconf preference dir.
* We do this because we're interested in the events where
* an alarm directory is either added or deleted externally.
*
* When this happens we update our list of alarms.
*/
void
alarm_gconf_notify_type_changed (GConfClient *client,
alarm_applet_gconf_global_change (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("notify_type_changed");
Alarm *a;
GString *str;
GList *l;
gchar *dir;
gint id, i, len;
gboolean found = FALSE;
const gchar *tmp;
//g_debug ("GLOBAL_change: %s", entry->key);
if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
return;
/*
* We're only interested in the first part of the key matching
* {applet_gconf_pref_dir}/{something}
*
* Here we extract {something}
*/
dir = ALARM_GCONF_DIR;
len = strlen (entry->key);
str = g_string_new ("");
tmp = gconf_value_get_string (entry->value);
if (tmp) {
if (!gconf_string_to_enum (notify_type_enum_map, tmp, (gint *)&(applet->notify_type))) {
// No match, set to default
applet->notify_type = NOTIFY_SOUND;
for (i = strlen(dir) + 1; i < len; i++) {
if (entry->key[i] == '/')
break;
str = g_string_append_c (str, entry->key[i]);
}
//g_debug ("\tEXTRACTED: %s", str->str);
// Check if the key is valid
id = alarm_gconf_dir_get_id (str->str);
if (id >= 0) {
// Valid, probably an alarm which has been removed
g_debug ("GLOBAL change ON alarm #%d", id);
// Check if the alarm exists in our alarms list
for (l = applet->alarms; l != NULL; l = l->next) {
a = ALARM (l->data);
if (a->id == id) {
// FOUND
found = TRUE;
break;
}
}
if (applet->preferences_dialog != NULL) {
pref_update_notify_type (applet);
}
}
if (found && entry->value == NULL) {
// DELETED ALARM
g_debug ("\tDELETE alarm #%d %p", id, a);
void
alarm_gconf_sound_file_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
return;
const gchar *value = gconf_value_get_string (entry->value);
g_debug ("sound_file_changed to %s", value);
if (set_sound_file (applet, value)) {
g_debug ("VALID file!");
/* If there's a settings dialog open for this
* alarm, destroy it.
*/
AlarmSettingsDialog *sdialog = g_hash_table_lookup (applet->edit_alarm_dialogs, (gconstpointer)a->id);
if (sdialog) {
alarm_settings_dialog_close (sdialog);
}
if (applet->preferences_dialog != NULL) {
pref_update_sound_file (applet);
/*
* Remove from list
*/
alarm_applet_alarms_remove (applet, a);
// Update view
if (applet->list_alarms_dialog)
list_alarms_update (applet);
} else if (!found && entry->value != NULL) {
// ADDED ALARM
/*
* Add to list
*/
a = alarm_new (ALARM_GCONF_DIR, id);
g_debug ("\tADD alarm #%d %p", id, a);
alarm_applet_alarms_add (applet, a);
// Update view
if (applet->list_alarms_dialog)
list_alarms_update (applet);
}
}
void
alarm_gconf_sound_loop_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("sound_loop_changed");
if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
return;
applet->notify_sound_loop = gconf_value_get_bool (entry->value);
if (applet->player)
applet->player->loop = applet->notify_sound_loop;
if (applet->preferences_dialog != NULL) {
pref_update_sound_loop (applet);
}
}
void
alarm_gconf_command_changed (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("[gconf] command_changed");
if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
return;
if (applet->notify_command)
g_free (applet->notify_command);
applet->notify_command = g_strdup (gconf_value_get_string (entry->value));
if (applet->preferences_dialog != NULL) {
g_debug ("gconf: CMD ENTRY HAS FOCUS? %d", GTK_WIDGET_HAS_FOCUS (applet->pref_notify_app_command_entry));
pref_update_command (applet);
}
}
void
alarm_gconf_notify_bubble_change (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
AlarmApplet *applet)
{
g_debug ("notify_bubble_changed");
#ifdef HAVE_LIBNOTIFY
if (!entry->value || entry->value->type != GCONF_VALUE_BOOL)
return;
applet->notify_bubble = gconf_value_get_bool (entry->value);
if (applet->preferences_dialog != NULL) {
pref_update_show_bubble (applet);
}
#endif
g_string_free (str, TRUE);
}
@@ -343,94 +199,38 @@ alarm_gconf_notify_bubble_change (GConfClient *client,
* Init
*/
void
setup_gconf (AlarmApplet *applet)
alarm_applet_gconf_init (AlarmApplet *applet)
{
GConfClient *client;
gchar *key;
client = gconf_client_get_default ();
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_ALARMTIME);
g_debug ("GCONFKEY: %s", key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_SHOW_LABEL);
applet->listeners [0] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_alarmtime_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_MESSAGE);
applet->listeners [1] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_message_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_STARTED);
applet->listeners [2] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_started_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_SHOW_LABEL);
applet->listeners [3] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_show_label_changed,
(GConfClientNotifyFunc) alarm_applet_gconf_show_label_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_LABEL_TYPE);
applet->listeners [4] =
applet->listeners [1] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_label_type_changed,
(GConfClientNotifyFunc) alarm_applet_gconf_label_type_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_NOTIFY_TYPE);
applet->listeners [5] =
/*
* Listen for changes to the alarms.
* We want to know when an alarm is added and removed.
*/
applet->listeners [2] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_notify_type_changed,
client, ALARM_GCONF_DIR,
(GConfClientNotifyFunc) alarm_applet_gconf_global_change,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_SOUND_FILE);
applet->listeners [6] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_sound_file_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_SOUND_LOOP);
applet->listeners [7] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_sound_loop_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_COMMAND);
applet->listeners [8] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_command_changed,
applet, NULL, NULL);
g_free (key);
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_NOTIFY_BUBBLE);
applet->listeners [9] =
gconf_client_notify_add (
client, key,
(GConfClientNotifyFunc) alarm_gconf_notify_bubble_change,
applet, NULL, NULL);
g_free (key);
}
@@ -441,9 +241,8 @@ setup_gconf (AlarmApplet *applet)
* Not only that, but if some error occurs while setting the
* defaults in gconf, we already have them copied locally. */
void
load_gconf (AlarmApplet *applet)
alarm_applet_gconf_load (AlarmApplet *applet)
{
AlarmListEntry *entry;
GConfClient *client;
GConfValue *value;
gchar *key;
@@ -451,31 +250,6 @@ load_gconf (AlarmApplet *applet)
client = gconf_client_get_default ();
// ALARM_TIME:
applet->alarm_time = panel_applet_gconf_get_int (applet->parent, KEY_ALARMTIME, NULL);
if (applet->alarm_time == 0) {
// Default to now + 5 mins
applet->alarm_time = DEF_ALARMTIME;
panel_applet_gconf_set_int (applet->parent, KEY_ALARMTIME, applet->alarm_time, NULL);
}
// STARTED: Defaults to 0 if key isn't found, so we can fetch started directly.
applet->started = panel_applet_gconf_get_bool (applet->parent, KEY_STARTED, NULL);
// MESSAGE:
// ..get_string() Returns NULL if key is not found. The empty string if a default is found.
tmp = panel_applet_gconf_get_string (applet->parent, KEY_MESSAGE, NULL);
if (tmp == NULL) {
applet->alarm_message = g_strdup (DEF_MESSAGE);
panel_applet_gconf_set_string (applet->parent, KEY_MESSAGE, DEF_MESSAGE, NULL);
} else {
applet->alarm_message = g_strdup (tmp);
}
// SHOW_LABEL:
key = panel_applet_gconf_get_full_key (PANEL_APPLET (applet->parent), KEY_SHOW_LABEL);
value = gconf_client_get (client, key, NULL);
@@ -498,75 +272,4 @@ load_gconf (AlarmApplet *applet)
panel_applet_gconf_set_string (applet->parent, KEY_LABEL_TYPE, gconf_enum_to_string (label_type_enum_map, DEF_LABEL_TYPE), NULL);
}
g_free(tmp);
// NOTIFY_TYPE:
tmp = panel_applet_gconf_get_string (applet->parent, KEY_NOTIFY_TYPE, NULL);
if (tmp == NULL || !gconf_string_to_enum (notify_type_enum_map, tmp, (gint *)&(applet->notify_type))) {
// Schema defaults not found or unable to map
applet->notify_type = DEF_NOTIFY_TYPE;
panel_applet_gconf_set_string (applet->parent, KEY_NOTIFY_TYPE, gconf_enum_to_string (notify_type_enum_map, DEF_NOTIFY_TYPE), NULL);
}
g_free(tmp);
// SOUND_FILE:
tmp = panel_applet_gconf_get_string (applet->parent, KEY_SOUND_FILE, NULL);
if (!set_sound_file (applet, tmp)) {
// Set it to the first stock sound
applet->sound_pos = 0;
if (g_list_length (applet->sounds) > 0) {
entry = applet->sounds->data;
panel_applet_gconf_set_string (applet->parent, KEY_SOUND_FILE, entry->data, NULL);
}
}
g_free(tmp);
// SOUD_LOOP
key = panel_applet_gconf_get_full_key (applet->parent, KEY_SOUND_LOOP);
value = gconf_client_get (client, key, NULL);
if (value == NULL) {
// Schema defaults not found
applet->notify_sound_loop = DEF_SOUND_LOOP;
panel_applet_gconf_set_bool (applet->parent, KEY_SOUND_LOOP, DEF_SOUND_LOOP, NULL);
} else {
applet->notify_sound_loop = gconf_value_get_bool (value);
gconf_value_free (value);
}
g_free (key);
// COMMAND:
applet->notify_command = panel_applet_gconf_get_string (applet->parent, KEY_COMMAND, NULL);
if (applet->notify_command == NULL) {
// Fall back to the first app
if (g_list_length (applet->apps) > 0) {
entry = applet->apps->data;
applet->notify_command = g_strdup (entry->data);
g_debug ("FIRST APP: %s", applet->notify_command);
} else {
// Failsafe
g_debug ("FAILSAFE CMD");
applet->notify_command = g_strdup (DEF_COMMAND);
}
// Update gconf
panel_applet_gconf_set_string (applet->parent, KEY_COMMAND, applet->notify_command, NULL);
}
// NOTIFY_BUBBLE:
key = panel_applet_gconf_get_full_key (applet->parent, KEY_NOTIFY_BUBBLE);
value = gconf_client_get (client, key, NULL);
if (value == NULL) {
// Schema defaults not found
applet->notify_bubble = DEF_NOTIFY_BUBBLE;
panel_applet_gconf_set_bool (applet->parent, KEY_NOTIFY_BUBBLE, DEF_NOTIFY_BUBBLE, NULL);
} else {
applet->notify_bubble = gconf_value_get_bool (value);
gconf_value_free (value);
}
g_free (key);
}

View File

@@ -1,3 +1,26 @@
/*
* alarm-gconf.h -- GConf routines
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef ALARM_GCONF_H_
#define ALARM_GCONF_H_
@@ -8,64 +31,28 @@
G_BEGIN_DECLS
/* GConf keys */
#define KEY_ALARMTIME "alarm_time"
#define KEY_MESSAGE "message"
#define KEY_STARTED "started"
/* Global GConf keys */
#define KEY_SHOW_LABEL "show_label"
#define KEY_LABEL_TYPE "label_type"
#define KEY_NOTIFY_TYPE "notify_type"
#define KEY_SOUND_FILE "sound_file"
#define KEY_SOUND_LOOP "sound_repeat"
#define KEY_COMMAND "command"
#define KEY_NOTIFY_BUBBLE "notify_bubble"
#define N_GCONF_PREFS 10
#define N_GCONF_PREFS 3 /* + global gconf listener */
/* Failsafe defaults for use when the schema isn't found
* or doesn't provide sensible defaults */
#define DEF_ALARMTIME (time (NULL) + 60 * 5)
#define DEF_MESSAGE "Alarm!"
#define DEF_SHOW_LABEL TRUE
#define DEF_LABEL_TYPE LABEL_TYPE_ALARM
#define DEF_NOTIFY_TYPE NOTIFY_SOUND
#define DEF_SOUND_FILE "" // Should default to first in stock sound list
#define DEF_SOUND_LOOP TRUE
#define DEF_COMMAND "" // Should default to first in app list
#define DEF_NOTIFY_BUBBLE TRUE
#define DEF_LABEL_TYPE LABEL_TYPE_TIME
/* We store enums as strings */
GConfEnumStringPair label_type_enum_map [];
GConfEnumStringPair notify_type_enum_map [];
/**
* Stores the alarm timestamp in gconf
*/
void
alarm_gconf_set_alarm (AlarmApplet *applet, guint hour, guint minute, guint second);
/**
* Stores the alarm message in gconf
*/
void
alarm_gconf_set_message (AlarmApplet *applet, const gchar *message);
/**
* Sets started status of alarm in gconf
*/
void
alarm_gconf_set_started (AlarmApplet *applet, gboolean started);
/*
* Init
*/
void
setup_gconf (AlarmApplet *applet);
alarm_applet_gconf_init (AlarmApplet *applet);
void
load_gconf (AlarmApplet *applet);
alarm_applet_gconf_load (AlarmApplet *applet);
G_END_DECLS

2164
src/alarm.c Normal file

File diff suppressed because it is too large Load Diff

259
src/alarm.h Normal file
View File

@@ -0,0 +1,259 @@
/*
* alarm.h -- Core alarm functionality
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef ALARM_H_
#define ALARM_H_
#include <glib-object.h>
#include <gconf/gconf-client.h>
#include "player.h"
G_BEGIN_DECLS
/*
* Utility macros
*/
#define TYPE_ALARM (alarm_get_type())
#define ALARM(object) \
(G_TYPE_CHECK_INSTANCE_CAST((object), TYPE_ALARM, Alarm))
#define ALARM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_ALARM, AlarmClass))
#define IS_ALARM(object) \
(G_TYPE_CHECK_INSTANCE_TYPE((object), TYPE_ALARM))
#define IS_ALARM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_ALARM))
#define ALARM_GET_CLASS(object) \
(G_TYPE_INSTANCE_GET_CLASS((object), TYPE_ALARM, AlarmClass))
/*
* Structure definitions
*/
typedef enum {
ALARM_TYPE_INVALID = 0,
ALARM_TYPE_CLOCK, /* Alarm at specific time */
ALARM_TYPE_TIMER /* Alarm in X mins */
} AlarmType;
typedef enum {
ALARM_REPEAT_NONE = 0,
ALARM_REPEAT_SUN = 1 << 0,
ALARM_REPEAT_MON = 1 << 1,
ALARM_REPEAT_TUE = 1 << 2,
ALARM_REPEAT_WED = 1 << 3,
ALARM_REPEAT_THU = 1 << 4,
ALARM_REPEAT_FRI = 1 << 5,
ALARM_REPEAT_SAT = 1 << 6,
} AlarmRepeat;
#define ALARM_REPEAT_WEEKDAYS (ALARM_REPEAT_MON | ALARM_REPEAT_TUE | ALARM_REPEAT_WED | ALARM_REPEAT_THU | ALARM_REPEAT_FRI)
#define ALARM_REPEAT_WEEKENDS (ALARM_REPEAT_SAT | ALARM_REPEAT_SUN)
#define ALARM_REPEAT_ALL (ALARM_REPEAT_WEEKDAYS | ALARM_REPEAT_WEEKENDS)
typedef enum {
ALARM_NOTIFY_INVALID = 0,
ALARM_NOTIFY_SOUND, /* Notification by sound */
ALARM_NOTIFY_COMMAND, /* Notification by command */
} AlarmNotifyType;
typedef struct _Alarm Alarm;
typedef struct _AlarmClass AlarmClass;
struct _Alarm {
GObject parent;
gchar *gconf_dir; /* GConf directory */
gint id; /* Alarm ID */
/* GConf mapped values */
AlarmType type;
time_t time; /* Time for alarm */
time_t timestamp; /* UNIX timestamp (local time) for running alarms */
gboolean active;
gchar *message;
AlarmRepeat repeat;
gint snooze;
AlarmNotifyType notify_type;
gchar *sound_file;
gboolean sound_loop;
gchar *command;
gboolean notify_bubble;
};
struct _AlarmClass {
GObjectClass parent;
/* Signals */
void (*alarm)(Alarm *alarm); /* Alarm triggered! */
void (*error)(Alarm *alarm, GError *err); /* An error occured */
void (*player_changed)(Alarm *alarm, MediaPlayerState state); /* Media player state changed */
};
/*
* Error codes
*/
#define ALARM_ERROR alarm_error_quark ()
typedef enum {
ALARM_ERROR_NONE,
ALARM_ERROR_PLAY, /* Error playing sound */
ALARM_ERROR_COMMAND /* Error launching command */
} AlarmErrorCode;
/*
* Failsafe defaults for the GConf-mapped properties for
* use when the schema isn't found or doesn't provide
* sensible defaults.
*/
#define ALARM_DEFAULT_TYPE ALARM_TYPE_CLOCK
#define ALARM_DEFAULT_TIME 0
#define ALARM_DEFAULT_TIMESTAMP 0
#define ALARM_DEFAULT_ACTIVE FALSE
#define ALARM_DEFAULT_MESSAGE "Alarm!"
#define ALARM_DEFAULT_REPEAT ALARM_REPEAT_NONE
#define ALARM_DEFAULT_SNOOZE 0
#define ALARM_DEFAULT_NOTIFY_TYPE ALARM_NOTIFY_SOUND
#define ALARM_DEFAULT_SOUND_FILE "" // Should default to first in stock sound list
#define ALARM_DEFAULT_SOUND_LOOP TRUE
#define ALARM_DEFAULT_COMMAND "" // Should default to first in app list
#define ALARM_DEFAULT_NOTIFY_BUBBLE TRUE
/*
* GConf settings
*/
#define ALARM_GCONF_DIR_PREFIX "alarm"
#define ALARM_GCONF_SCHEMA_DIR "/schemas/apps/alarm_clock/alarm"
/*
* Player backoff timeout.
* We will stop the player automatically after 20 minutes.
*/
#define ALARM_SOUND_TIMEOUT (60 * 20)
/*
* Function prototypes.
*/
/* used by ALARM_TYPE */
GType
alarm_get_type (void);
Alarm *
alarm_new (const gchar *gconf_dir, gint id);
guint
alarm_gen_id_dir (const gchar *gconf_dir);
guint
alarm_gen_id (Alarm *alarm);
gchar *
alarm_gconf_get_dir (Alarm *alarm);
gint
alarm_gconf_dir_get_id (const gchar *dir);
gchar *
alarm_gconf_get_full_key (Alarm *alarm, const gchar *key);
const gchar *
alarm_type_to_string (AlarmType type);
AlarmType
alarm_type_from_string (const gchar *type);
const gchar *
alarm_notify_type_to_string (AlarmNotifyType type);
AlarmNotifyType
alarm_notify_type_from_string (const gchar *type);
GList *
alarm_get_list (const gchar *gconf_dir);
void
alarm_signal_connect_list (GList *instances,
const gchar *detailed_signal,
GCallback c_handler,
gpointer data);
void
alarm_trigger (Alarm *alarm);
void
alarm_set_enabled (Alarm *alarm, gboolean enabled);
void
alarm_enable (Alarm *alarm);
void
alarm_clear (Alarm *alarm);
void
alarm_disable (Alarm *alarm);
void
alarm_delete (Alarm *alarm);
void
alarm_set_time (Alarm *alarm, guint hour, guint minute, guint second);
void
alarm_update_timestamp (Alarm *alarm);
void
alarm_update_timestamp_full (Alarm *alarm, gboolean include_today);
GQuark
alarm_error_quark (void);
void
alarm_error_trigger (Alarm *alarm, AlarmErrorCode code, const gchar *msg);
struct tm *
alarm_get_time (Alarm *alarm);
struct tm *
alarm_get_remain (Alarm *alarm);
const gchar *alarm_repeat_to_string (AlarmRepeat repeat);
AlarmRepeat alarm_repeat_from_string (const gchar *str);
AlarmRepeat alarm_repeat_from_list (GSList *list);
GSList *alarm_repeat_to_list (AlarmRepeat repeat);
gint alarm_wday_distance (gint wday1, gint wday2);
gboolean alarm_should_repeat (Alarm *alarm);
G_END_DECLS
#endif /*ALARM_H_*/

660
src/alarms-list.c Normal file
View File

@@ -0,0 +1,660 @@
/*
* alarms-list.d -- List alarms dialog
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include "alarms-list.h"
#include "edit-alarm.h"
static void
list_alarms_toggled_cb (GtkCellRendererToggle *cell_renderer,
gchar *path,
gpointer data)
{
GtkListStore *model = GTK_LIST_STORE (data);
GtkTreeIter iter;
Alarm *alarm;
gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (model), &iter, path);
gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &alarm, -1);
g_debug ("list_alarms_toggled %s: #%d", path, alarm->id);
alarm_set_enabled (alarm, !(alarm->active));
/*
* gtk_tree_model_get () will increase the reference count
* of the alarms each time it's called. We dereference it
* here so they can be properly freed later with g_object_unref()
*/
g_object_unref (alarm);
}
typedef struct _AlarmModelChangedArg {
GtkListStore *store;
GtkTreeIter iter;
Alarm *alarm;
} AlarmModelChangedArg;
static void
list_alarms_clear_args (AlarmApplet *applet)
{
GList *l;
AlarmModelChangedArg *arg;
/*
* Free old list of arguments
*/
for (l = applet->list_alarms_args; l; l = l->next) {
arg = (AlarmModelChangedArg *)l->data;
// Remove any callbacks
g_source_remove_by_user_data (arg);
// Free argument
g_free (arg);
}
g_list_free (applet->list_alarms_args);
applet->list_alarms_args = NULL;
}
static gboolean
list_alarms_update_timer (gpointer data)
{
AlarmModelChangedArg *arg = (AlarmModelChangedArg *)data;
GtkTreePath *path;
if (!GTK_IS_TREE_MODEL (arg->store)) {
// Dialog is closed, free args
g_free (arg);
return FALSE;
}
if (!arg->alarm->active)
return FALSE;
path = gtk_tree_model_get_path (GTK_TREE_MODEL (arg->store), &(arg->iter));
gtk_tree_model_row_changed (GTK_TREE_MODEL (arg->store), path, &(arg->iter));
gtk_tree_path_free (path);
}
static void
list_alarms_add_timer (AlarmModelChangedArg *arg)
{
g_source_remove_by_user_data (arg);
g_timeout_add_seconds (1, (GSourceFunc) list_alarms_update_timer, arg);
}
static void
alarm_model_changed (AlarmModelChangedArg *arg)
{
GtkTreePath *path;
// TODO: Only update on the actual fields we're interested?
path = gtk_tree_model_get_path (GTK_TREE_MODEL (arg->store), &(arg->iter));
gtk_tree_model_row_changed (GTK_TREE_MODEL (arg->store), path, &(arg->iter));
gtk_tree_path_free (path);
}
/*
* Callback for when an alarm changes
* Emits model-row-changed
*/
static void
alarm_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmModelChangedArg *arg = (AlarmModelChangedArg *)data;
Alarm *a = ALARM (object);
alarm_model_changed (arg);
// If alarm is active, update the view every second for remaining time
if (strcmp (param->name, "active") == 0 && a->active) {
list_alarms_add_timer (arg);
}
}
/*
* Callback for when the alarm player changes
*/
static void
alarm_player_changed (Alarm *a, MediaPlayerState state, gpointer data)
{
g_debug ("alarm_player_changed: %d", state);
alarm_model_changed ((AlarmModelChangedArg *)data);
}
/*
* Update list of alarms (VIEW)
*/
void
list_alarms_update (AlarmApplet *applet)
{
GtkListStore *store = applet->list_alarms_store;
GtkTreeIter iter;
GList *l = NULL, *args = NULL;
Alarm *a;
AlarmModelChangedArg *arg;
g_debug ("list_alarms_update ()");
g_assert (store);
/*
* Clear model
*/
gtk_list_store_clear (store);
/*
* Insert alarms
*/
for (l = applet->alarms; l; l = l->next) {
a = ALARM (l->data);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, 0, a, -1);
// Create arg
arg = g_new (AlarmModelChangedArg, 1);
arg->store = store;
arg->iter = iter;
arg->alarm = a;
// Append to argument list
args = g_list_append (args, arg);
// Disconnect old handlers, if any
g_signal_handlers_disconnect_matched (a, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, alarm_changed, NULL);
// Notify us of changes to the alarm
g_signal_connect (a, "notify", G_CALLBACK (alarm_changed), arg);
// Notify us of changes to the alarm player
g_signal_connect (a, "player_changed", G_CALLBACK (alarm_player_changed), arg);
// If alarm is active, update the view every second for remaining time
if (a->active) {
list_alarms_add_timer (arg);
}
g_print ("Alarm #%d (%p): %s [ref=%d]\n", a->id, a, a->message, G_OBJECT (a)->ref_count);
}
/* Clear old arguments */
list_alarms_clear_args (applet);
/* Update with new list of args */
applet->list_alarms_args = args;
}
static void
alarm_update_renderer (GtkTreeViewColumn *tree_column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
AlarmColumn col = (AlarmColumn)data;
Alarm *a;
time_t hour, min, sec, now;
struct tm *tm;
gchar *tmp;
gtk_tree_model_get (model, iter, 0, &a, -1);
switch (col) {
case TYPE_COLUMN:
if (a->type == ALARM_TYPE_TIMER) {
g_object_set (renderer, "icon-name", TIMER_ICON, NULL);
} else {
g_object_set (renderer, "icon-name", ALARM_ICON, NULL);
}
break;
case ACTIVE_COLUMN:
g_object_set (renderer, "active", a->active, NULL);
break;
case TIME_COLUMN:
/* If alarm is running (active), show remaining time */
if (a->active) {
tm = alarm_get_remain (a);
} else {
tm = alarm_get_time (a);
}
tmp = g_strdup_printf(_("%02d:%02d:%02d"), tm->tm_hour, tm->tm_min, tm->tm_sec);
g_object_set (renderer, "text", tmp, NULL);
g_free (tmp);
break;
case LABEL_COLUMN:
g_object_set (renderer, "text", a->message, NULL);
break;
case PLAYING_COLUMN:
if (alarm_is_playing (a)) {
g_object_set (renderer, "icon-name", "audio-volume-high", NULL);
} else {
g_object_set (renderer, "icon-name", NULL, NULL);
}
break;
default:
break;
}
/*
* gtk_tree_model_get () will increase the reference count
* of the alarms each time it's called. We dereference it
* here so they can be properly freed later with g_object_unref()
*/
g_object_unref (a);
//g_debug ("alarm_update_render: alarm #%d (%p), col %d, ref=%d", a->id, a, col, G_OBJECT (a)->ref_count);
}
static void
list_alarms_dialog_response_cb (GtkDialog *dialog,
gint rid,
AlarmApplet *applet)
{
list_alarms_dialog_close (applet);
}
static void
add_button_cb (GtkButton *button, gpointer data)
{
Alarm *alarm;
AlarmApplet *applet = (AlarmApplet *)data;
AlarmListEntry *entry;
/*
* Create new alarm, will fall back to defaults.
*/
alarm = alarm_new (ALARM_GCONF_DIR, -1);
/*
* Set first sound / app in list
*/
if (applet->sounds != NULL) {
entry = (AlarmListEntry *)applet->sounds->data;
g_object_set (alarm, "sound-file", entry->data, NULL);
}
if (applet->apps != NULL) {
entry = (AlarmListEntry *)applet->apps->data;
g_object_set (alarm, "command", entry->data, NULL);
}
// Add alarm to list of alarms
alarm_applet_alarms_add (applet, alarm);
// Show edit alarm dialog
display_edit_alarm_dialog (applet, alarm);
/*
* Update alarms list view
*/
list_alarms_update (applet);
}
static Alarm *
get_selected_alarm (AlarmApplet *applet)
{
GtkTreeSelection *selection;
GtkTreeIter iter;
GtkTreeModel *model;
Alarm *a;
g_assert (applet);
g_assert (applet->list_alarms_view);
/* Fetch selection */
selection = gtk_tree_view_get_selection (applet->list_alarms_view);
if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
/* No alarms selected */
g_debug ("get_selected_alarm: No alarms selected");
return NULL;
}
gtk_tree_model_get (model, &iter, 0, &a, -1);
/*
* gtk_tree_model_get () will increase the reference count
* of the alarms each time it's called. We dereference it
* here so they can be properly freed later with g_object_unref()
*/
g_object_unref (a);
return a;
}
static void
edit_button_cb (GtkButton *button, gpointer data)
{
AlarmApplet *applet = (AlarmApplet *)data;
Alarm *a = get_selected_alarm (applet);
if (!a) {
/* No alarms selected */
return;
}
// Clear any running alarms
alarm_clear (a);
display_edit_alarm_dialog (applet, a);
}
static void
delete_button_cb (GtkButton *button, gpointer data)
{
AlarmApplet *applet = (AlarmApplet *)data;
Alarm *a = get_selected_alarm (applet);
GtkWidget *dialog;
gint response;
if (!a) {
/* No alarms selected */
return;
}
// Clear any running alarms
alarm_clear (a);
dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (applet->list_alarms_dialog),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
_("<big><b>Delete alarm '%s'?</b></big>"),
a->message);
g_object_set (dialog,
"title", _("Delete Alarm?"),
"icon-name", ALARM_ICON,
NULL);
gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
_("Are you sure you want to delete\nalarm <b>#%d</b> labeled '<b>%s</b>'?"),
a->id, a->message);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
gtk_dialog_add_buttons(GTK_DIALOG (dialog),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT,
NULL);
response = gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
if (response == GTK_RESPONSE_ACCEPT) {
g_debug ("delete_button_cb: GTK_RESPONSE_ACCEPT");
/*
* Delete GCONF
*/
alarm_delete (a);
/* If there's a settings dialog open for this
* alarm, destroy it.
*/
AlarmSettingsDialog *sdialog = g_hash_table_lookup (applet->edit_alarm_dialogs, (gconstpointer)a->id);
if (sdialog) {
alarm_settings_dialog_close (sdialog);
}
/*
* Remove from applet list
*/
alarm_applet_alarms_remove (applet, a);
/*
* Fill store with alarms
*/
list_alarms_update (applet);
} else {
g_debug ("delete_button_cb: GTK_RESPONSE_CANCEL");
}
}
static void
list_alarm_selected_cb (GtkTreeView *view,
GtkTreePath *path,
GtkTreeViewColumn *column,
gpointer data)
{
GtkTreeIter iter;
GtkTreeModel *model;
Alarm *a;
AlarmApplet *applet = (AlarmApplet *)data;
model = gtk_tree_view_get_model (view);
if (!gtk_tree_model_get_iter (model, &iter, path)) {
g_warning ("Could not get iter.");
return;
}
gtk_tree_model_get (model, &iter, 0, &a, -1);
/*
* gtk_tree_model_get () will increase the reference count
* of the alarms each time it's called. We dereference it
* here so they can be properly freed later with g_object_unref()
*/
g_object_unref (a);
// Clear any running alarms
alarm_clear (a);
display_edit_alarm_dialog (applet, a);
}
void
list_alarms_dialog_close (AlarmApplet *applet)
{
GList *l;
Alarm *a;
g_assert (applet->list_alarms_dialog);
// Destroy dialog
gtk_widget_destroy (GTK_WIDGET (applet->list_alarms_dialog));
applet->list_alarms_dialog = NULL;
// Free list store
g_object_unref (applet->list_alarms_store);
applet->list_alarms_store = NULL;
/* g_object_unref (applet->list_alarms_view);*/
applet->list_alarms_view = NULL;
// Disconnect notify handlers
for (l = applet->alarms; l != NULL; l = l->next) {
a = ALARM (l->data);
g_signal_handlers_disconnect_matched (a, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, alarm_changed, NULL);
g_signal_handlers_disconnect_matched (a, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, alarm_player_changed, NULL);
}
/* Clear old arguments */
list_alarms_clear_args (applet);
}
void
list_alarms_dialog_display (AlarmApplet *applet)
{
if (applet->list_alarms_dialog != NULL) {
// Dialog already open.
gtk_window_present (GTK_WINDOW (applet->list_alarms_dialog));
return;
}
gchar *tmp;
GList *l; /* List of alarms */
Alarm *a;
GtkListStore *store;
GtkTreeView *view;
GtkTreeIter iter;
GdkPixbuf *type_alarm_icon, *type_timer_icon;
GtkCellRenderer *type_renderer, *active_renderer,
*time_renderer, *label_renderer,
*playing_renderer;
GtkTreeViewColumn *type_col, *active_col,
*time_col, *label_col,
*playing_col;
GladeXML *ui;
GtkButton *add_button, *edit_button, *delete_button;
/*
* Fetch widgets
*/
ui = glade_xml_new (ALARM_UI_XML, "list-alarms", NULL);
applet->list_alarms_dialog = GTK_DIALOG (glade_xml_get_widget (ui, "list-alarms"));
view = GTK_TREE_VIEW (glade_xml_get_widget (ui, "list-alarms-view"));
applet->list_alarms_view = view;
g_signal_connect (applet->list_alarms_dialog, "response",
G_CALLBACK (list_alarms_dialog_response_cb), applet);
// Buttons
add_button = GTK_BUTTON (glade_xml_get_widget (ui, "add-button"));
edit_button = GTK_BUTTON (glade_xml_get_widget (ui, "edit-button"));
delete_button = GTK_BUTTON (glade_xml_get_widget (ui, "delete-button"));
g_signal_connect (add_button, "clicked",
G_CALLBACK (add_button_cb), applet);
g_signal_connect (edit_button, "clicked",
G_CALLBACK (edit_button_cb), applet);
g_signal_connect (delete_button, "clicked",
G_CALLBACK (delete_button_cb), applet);
/*
* Create list store model
*/
store = gtk_list_store_new (1, TYPE_ALARM);
applet->list_alarms_store = store;
/*
* Fill store with alarms
*/
list_alarms_update (applet);
/*
* Create view cell renderers
*/
type_renderer = gtk_cell_renderer_pixbuf_new ();
active_renderer = gtk_cell_renderer_toggle_new ();
g_object_set (active_renderer,
/*"mode", GTK_CELL_RENDERER_MODE_EDITABLE,*/
"activatable", TRUE,
NULL);
g_signal_connect (active_renderer, "toggled", G_CALLBACK (list_alarms_toggled_cb), store);
time_renderer = gtk_cell_renderer_text_new ();
label_renderer = gtk_cell_renderer_text_new ();
g_object_set (label_renderer,
"weight", 1000,
"mode", GTK_CELL_RENDERER_MODE_EDITABLE,
NULL);
playing_renderer = gtk_cell_renderer_pixbuf_new ();
/*
* Create view columns
*/
type_col = gtk_tree_view_column_new_with_attributes(
_("Type"), type_renderer,
NULL);
gtk_tree_view_column_set_cell_data_func (type_col, type_renderer,
alarm_update_renderer,
TYPE_COLUMN, NULL);
active_col = gtk_tree_view_column_new_with_attributes(
_("Active"), active_renderer,
NULL);
gtk_tree_view_column_set_cell_data_func (active_col, active_renderer,
alarm_update_renderer,
ACTIVE_COLUMN, NULL);
time_col = gtk_tree_view_column_new_with_attributes(
_("Time"), time_renderer,
NULL);
gtk_tree_view_column_set_cell_data_func(time_col, time_renderer,
alarm_update_renderer,
TIME_COLUMN, NULL);
label_col = gtk_tree_view_column_new_with_attributes(
_("Label"), label_renderer,
NULL);
gtk_tree_view_column_set_cell_data_func(label_col, label_renderer,
alarm_update_renderer,
LABEL_COLUMN, NULL);
playing_col = gtk_tree_view_column_new_with_attributes(
_("Playing"), playing_renderer,
NULL);
gtk_tree_view_column_set_cell_data_func (playing_col, playing_renderer,
alarm_update_renderer,
PLAYING_COLUMN, NULL);
/*
* Set up tree view
*/
gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
gtk_tree_view_append_column (view, type_col);
gtk_tree_view_append_column (view, active_col);
gtk_tree_view_append_column (view, time_col);
gtk_tree_view_append_column (view, label_col);
gtk_tree_view_append_column (view, playing_col);
/*
* Set up signal handlers
*/
g_signal_connect (view, "row-activated", G_CALLBACK (list_alarm_selected_cb), applet);
// TODO: Calculate a good initial size for the window
//gtk_container_add (GTK_CONTAINER (list_alarms_box), GTK_WIDGET (view));
//gtk_box_pack_start_defaults (GTK_BOX (list_alarms_scrol), GTK_WIDGET (view));
gtk_widget_show_all (GTK_WIDGET (applet->list_alarms_dialog));
}

49
src/alarms-list.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* alarms-list.h -- List alarms dialog
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef ALARMSLIST_H_
#define ALARMSLIST_H_
#include "alarm-applet.h"
#include "alarm.h"
typedef enum {
TYPE_COLUMN,
ACTIVE_COLUMN,
TIME_COLUMN,
LABEL_COLUMN,
PLAYING_COLUMN,
ALARMS_N_COLUMNS
} AlarmColumn;
void
list_alarms_dialog_display (AlarmApplet *applet);
void
list_alarms_dialog_close (AlarmApplet *applet);
void
list_alarms_update (AlarmApplet *applet);
#endif /*ALARMSLIST_H_*/

926
src/edit-alarm.c Normal file
View File

@@ -0,0 +1,926 @@
/*
* edit-alarm.c -- Alarm settings dialog
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include "edit-alarm.h"
#include "alarm-applet.h"
#include "alarm.h"
#include "player.h"
#include <glib.h>
#include <glib-object.h>
#include <gtk/gtk.h>
static void
alarm_settings_update_time (AlarmSettingsDialog *dialog);
static void
time_changed_cb (GtkSpinButton *spinbutton, gpointer data);
static void
sound_combo_changed_cb (GtkComboBox *combo, AlarmSettingsDialog *dialog);
static void
app_combo_changed_cb (GtkComboBox *combo, AlarmSettingsDialog *dialog);
#define REPEAT_LABEL _("<b>T_rigger alarm:</b> %s")
/*
* Utility functions
*/
static GtkWidget *
create_img_label (const gchar *label_text, const gchar *icon_name)
{
gchar *tmp;
tmp = g_strdup_printf ("<b>%s</b>", label_text);
GdkPixbuf *icon;
GtkWidget *img, *label, *spacer; // TODO: Ugly with spacer
GtkWidget *hbox;
icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
icon_name,
24,
0, NULL);
img = gtk_image_new_from_pixbuf(icon);
label = g_object_new (GTK_TYPE_LABEL,
"label", tmp,
"use-markup", TRUE,
"xalign", 0.0,
NULL);
hbox = g_object_new (GTK_TYPE_HBOX, "spacing", 6, NULL);
spacer = g_object_new (GTK_TYPE_LABEL, "label", "", NULL);
gtk_box_pack_start_defaults (GTK_BOX (hbox), spacer);
gtk_box_pack_start(GTK_BOX (hbox), img, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX (hbox), label, FALSE, FALSE, 0);
spacer = g_object_new (GTK_TYPE_LABEL, "label", "", NULL);
gtk_box_pack_start_defaults (GTK_BOX (hbox), spacer);
g_free (tmp);
return hbox;
}
/*
* Utility functions for updating various parts of the settings dialog.
*/
static void
alarm_settings_update_type (AlarmSettingsDialog *dialog)
{
if (dialog->alarm->type == ALARM_TYPE_CLOCK) {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->clock_toggle), TRUE);
gtk_widget_set_sensitive(dialog->repeat_expand, TRUE);
} else {
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->timer_toggle), TRUE);
gtk_widget_set_sensitive(dialog->repeat_expand, FALSE);
}
}
static void
alarm_settings_update_time (AlarmSettingsDialog *dialog)
{
struct tm *tm;
tm = alarm_get_time(dialog->alarm);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->hour_spin), tm->tm_hour);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->min_spin), tm->tm_min);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->sec_spin), tm->tm_sec);
}
static void
alarm_settings_update_repeat (AlarmSettingsDialog *dialog)
{
AlarmRepeat r;
gint i;
gboolean check;
gchar *label;
/*
* Update check boxes
*/
for (r = ALARM_REPEAT_SUN, i = 0; r <= ALARM_REPEAT_SAT; r = 1 << ++i) {
check = (dialog->alarm->repeat & r) != 0;
// Activate the appropriate widget
g_object_set (dialog->repeat_check[i], "active", check, NULL);
}
/*
* Update fancy expander label
*/
if (dialog->alarm->repeat == ALARM_REPEAT_NONE) {
// NO REPEAT
label = g_strdup_printf (REPEAT_LABEL, _("Once"));
} else if (dialog->alarm->repeat == ALARM_REPEAT_WEEKDAYS) {
// REPEAT WEEKDAYS
label = g_strdup_printf (REPEAT_LABEL, _("Weekdays"));
} else if (dialog->alarm->repeat == ALARM_REPEAT_WEEKENDS) {
// REPEAT WEEKENDS
label = g_strdup_printf (REPEAT_LABEL, _("Weekends"));
} else if (dialog->alarm->repeat == ALARM_REPEAT_ALL) {
// REPEAT WEEK
label = g_strdup_printf (REPEAT_LABEL, _("Every day"));
} else {
// CUSTOM
label = g_strdup_printf (REPEAT_LABEL, _("Custom"));
}
g_object_set (dialog->repeat_label, "label", label, NULL);
g_free (label);
}
static void
alarm_settings_update_snooze (AlarmSettingsDialog *dialog)
{
g_object_set (dialog->snooze_spin, "value", (gdouble)dialog->alarm->snooze, NULL);
g_object_set (dialog->snooze_check, "active", dialog->alarm->snooze > 0, NULL);
}
static void
alarm_settings_update_notify_type (AlarmSettingsDialog *dialog)
{
// Enable selected
switch (dialog->alarm->notify_type) {
case ALARM_NOTIFY_COMMAND:
g_object_set (dialog->notify_app_radio, "active", TRUE, NULL);
g_object_set (dialog->notify_app_box, "sensitive", TRUE, NULL);
// Disable others
g_object_set (dialog->notify_sound_box, "sensitive", FALSE, NULL);
break;
default:
// NOTIFY_SOUND
g_object_set (dialog->notify_sound_radio, "active", TRUE, NULL);
g_object_set (dialog->notify_sound_box, "sensitive", TRUE, NULL);
// Disable others
g_object_set (dialog->notify_app_box, "sensitive", FALSE, NULL);
break;
}
}
static void
alarm_settings_update_sound (AlarmSettingsDialog *dialog)
{
AlarmListEntry *item;
GList *l;
guint pos, len, combo_len;
gint sound_pos = -1;
g_debug ("alarm_settings_update_sound (%p): sound_combo: %p, applet: %p, sounds: %p", dialog, dialog->notify_sound_combo, dialog->applet, dialog->applet->sounds);
/* Fill sounds list */
fill_combo_box (GTK_COMBO_BOX (dialog->notify_sound_combo),
dialog->applet->sounds, _("Select sound file..."));
// Look for the selected sound file
for (l = dialog->applet->sounds, pos = 0; l != NULL; l = l->next, pos++) {
item = (AlarmListEntry *)l->data;
if (strcmp (item->data, dialog->alarm->sound_file) == 0) {
// Match!
sound_pos = pos;
gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->notify_sound_combo), pos);
break;
}
}
}
static void
alarm_settings_update_app (AlarmSettingsDialog *dialog)
{
AlarmListEntry *item;
GList *l;
guint pos, len, combo_len;
gboolean custom = FALSE;
g_debug ("alarm_settings_update_app (%p): app_combo: %p, applet: %p, apps: %p", dialog, dialog->notify_app_combo, dialog->applet, dialog->applet->apps);
g_debug ("alarm_settings_update_app setting entry to %s", dialog->alarm->command);
/* Fill apps list */
fill_combo_box (GTK_COMBO_BOX (dialog->notify_app_combo),
dialog->applet->apps, _("Custom command..."));
// Look for the selected command
len = g_list_length (dialog->applet->apps);
for (l = dialog->applet->apps, pos = 0; l != NULL; l = l->next, pos++) {
item = (AlarmListEntry *)l->data;
if (strcmp (item->data, dialog->alarm->command) == 0) {
// Match!
break;
}
}
/* Only change sensitivity of the command entry if user
* isn't typing a custom command there already. */
if (pos >= len) {
// Custom command
pos += 1;
custom = TRUE;
}
g_debug ("CMD ENTRY HAS FOCUS? %d", GTK_WIDGET_HAS_FOCUS (dialog->notify_app_command_entry));
if (!GTK_WIDGET_HAS_FOCUS (dialog->notify_app_command_entry))
g_object_set (dialog->notify_app_command_entry, "sensitive", custom, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->notify_app_combo), pos);
}
static void
alarm_settings_update (AlarmSettingsDialog *dialog)
{
Alarm *alarm = ALARM (dialog->alarm);
g_object_set (dialog->label_entry, "text", alarm->message, NULL);
g_object_set (dialog->notify_sound_loop_check, "active", alarm->sound_loop, NULL);
g_object_set (dialog->notify_app_command_entry, "text", dialog->alarm->command, NULL);
g_object_set (dialog->notify_bubble_check, "active", alarm->notify_bubble, NULL);
alarm_settings_update_type (dialog);
alarm_settings_update_time (dialog);
alarm_settings_update_repeat (dialog);
alarm_settings_update_snooze (dialog);
alarm_settings_update_notify_type (dialog);
alarm_settings_update_sound (dialog);
alarm_settings_update_app (dialog);
}
/*
* Alarm object callbacks
*/
static void
alarm_type_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
alarm_settings_update_type (dialog);
}
static void
alarm_time_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
/* Only interesting if alarm is a CLOCK */
if (dialog->alarm->type != ALARM_TYPE_CLOCK)
return;
alarm_settings_update_time (dialog);
}
static void
alarm_repeat_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
alarm_settings_update_repeat (dialog);
}
static void
alarm_snooze_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
alarm_settings_update_snooze (dialog);
}
static void
alarm_timer_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
/* Only interesting if alarm is a TIMER */
if (dialog->alarm->type != ALARM_TYPE_TIMER)
return;
alarm_settings_update_time (dialog);
}
static void
alarm_notify_type_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
alarm_settings_update_notify_type (dialog);
}
static void
alarm_settings_sound_file_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
g_debug ("alarm_settings_sound_file_changed (%p)", data);
// Block sound combo signals to prevent infinite loop
// because the "changed" signal will be emitted when we
// change the combo box tree model.
g_signal_handlers_block_matched (dialog->notify_sound_combo,
G_SIGNAL_MATCH_FUNC,
0, 0, NULL, sound_combo_changed_cb, NULL);
// Update UI
alarm_settings_update_sound (dialog);
// Unblock combo signals
g_signal_handlers_unblock_matched (dialog->notify_sound_combo,
G_SIGNAL_MATCH_FUNC,
0, 0, NULL, sound_combo_changed_cb, NULL);
}
static void
alarm_sound_repeat_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
g_debug ("alarm_sound_repeat_changed to: %d", dialog->alarm->sound_loop);
}
static void
alarm_settings_command_changed (GObject *object,
GParamSpec *param,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
g_debug ("alarm_settings_command_changed (%p)", data);
// Block sound combo signals to prevent infinite loop
// because the "changed" signal will be emitted when we
// change the combo box tree model.
g_signal_handlers_block_matched (dialog->notify_app_combo,
G_SIGNAL_MATCH_FUNC,
0, 0, NULL, app_combo_changed_cb, NULL);
// Update UI
alarm_settings_update_app (dialog);
// Unblock combo signals
g_signal_handlers_unblock_matched (dialog->notify_app_combo,
G_SIGNAL_MATCH_FUNC,
0, 0, NULL, app_combo_changed_cb, NULL);
}
/*
* GUI utils
*/
static void
open_sound_file_chooser (AlarmSettingsDialog *dialog)
{
GtkWidget *chooser;
chooser = gtk_file_chooser_dialog_new (_("Select sound file..."),
GTK_WINDOW (dialog->dialog),
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (chooser), dialog->alarm->sound_file);
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT) {
gchar *uri;
uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (chooser));
g_debug ("RESPONSE ACCEPT: %s", uri);
g_object_set (dialog->alarm, "sound_file", uri, NULL);
g_free (uri);
} else {
g_debug ("RESPONSE CANCEL");
alarm_settings_update_sound (dialog);
}
gtk_widget_destroy (chooser);
}
/*
* GUI callbacks
*/
static void
type_toggle_cb (GtkToggleButton *toggle, gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
GtkWidget *toggle2 = (GTK_WIDGET (toggle) == dialog->clock_toggle) ? dialog->timer_toggle : dialog->clock_toggle;
gboolean toggled = gtk_toggle_button_get_active(toggle);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle2), !toggled);
if (GTK_WIDGET (toggle) == dialog->clock_toggle && toggled) {
g_object_set (dialog->alarm, "type", ALARM_TYPE_CLOCK, NULL);
} else {
g_object_set (dialog->alarm, "type", ALARM_TYPE_TIMER, NULL);
}
time_changed_cb (GTK_SPIN_BUTTON (dialog->hour_spin), dialog);
}
static void
time_changed_cb (GtkSpinButton *spinbutton, gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
guint hour, min, sec;
hour = gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->hour_spin));
min = gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->min_spin));
sec = gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->sec_spin));
alarm_set_time (dialog->alarm, hour, min, sec);
}
static void
repeat_changed_cb (GtkToggleButton *togglebutton,
gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
const gchar *name;
AlarmRepeat rep, new_rep;
gboolean active;
/* The check buttons have the same name as the 3 letter
* string representation of the day.
*/
name = gtk_widget_get_name (GTK_WIDGET (togglebutton));
rep = alarm_repeat_from_string (name);
active = gtk_toggle_button_get_active (togglebutton);
if (active)
// Add rep
new_rep = dialog->alarm->repeat | rep;
else
// Remove rep
new_rep = dialog->alarm->repeat & ~rep;
g_object_set (dialog->alarm, "repeat", new_rep, NULL);
}
static void
snooze_changed_cb (GtkSpinButton *spinbutton, gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
g_object_set (dialog->alarm, "snooze", (gint)gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->snooze_spin)), NULL);
}
static void
snooze_check_changed_cb (GtkToggleButton *togglebutton, gpointer data)
{
AlarmSettingsDialog *dialog = (AlarmSettingsDialog *)data;
if (gtk_toggle_button_get_active (togglebutton) && dialog->alarm->snooze == 0) {
g_object_set (dialog->alarm, "snooze", ALARM_DEF_SNOOZE, NULL);
} else if (!gtk_toggle_button_get_active (togglebutton) && dialog->alarm->snooze > 0) {
g_object_set (dialog->alarm, "snooze", 0, NULL);
}
}
static void
notify_type_changed_cb (GtkToggleButton *togglebutton,
AlarmSettingsDialog *dialog)
{
const gchar *name = gtk_widget_get_name (GTK_WIDGET (togglebutton));
gboolean value = gtk_toggle_button_get_active (togglebutton);
if (!value) {
// Not checked, not interested
return;
}
g_debug ("notify_type_changed: %s", name);
if (strcmp (name, "app-radio") == 0) {
g_object_set (dialog->alarm, "notify_type", ALARM_NOTIFY_COMMAND, NULL);
} else {
g_object_set (dialog->alarm, "notify_type", ALARM_NOTIFY_SOUND, NULL);
}
alarm_settings_update_notify_type (dialog);
}
static void
sound_combo_changed_cb (GtkComboBox *combo,
AlarmSettingsDialog *dialog)
{
g_debug ("SOUND Combo_changed");
GtkTreeModel *model;
AlarmListEntry *item;
guint current_index, len, combo_len;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->notify_sound_combo));
combo_len = gtk_tree_model_iter_n_children (model, NULL);
current_index = gtk_combo_box_get_active (combo);
len = g_list_length (dialog->applet->sounds);
g_debug ("Current index: %d, n sounds: %d", current_index, len);
if (current_index < 0)
// None selected
return;
if (current_index >= len) {
// Select sound file
g_debug ("Open SOUND file chooser...");
open_sound_file_chooser (dialog);
return;
}
// Valid file selected, update alarm
item = (AlarmListEntry *) g_list_nth_data (dialog->applet->sounds, current_index);
g_object_set (dialog->alarm, "sound_file", item->data, NULL);
}
static void
app_combo_changed_cb (GtkComboBox *combo,
AlarmSettingsDialog *dialog)
{
g_debug ("APP Combo_changed");
if (GTK_WIDGET_HAS_FOCUS (dialog->notify_app_command_entry)) {
g_debug (" ---- Skipping because command_entry has focus!");
return;
}
GtkTreeModel *model;
AlarmListEntry *item;
guint current_index, len, combo_len;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->notify_app_combo));
combo_len = gtk_tree_model_iter_n_children (model, NULL);
current_index = gtk_combo_box_get_active (combo);
len = g_list_length (dialog->applet->apps);
if (current_index < 0)
// None selected
return;
if (current_index >= len) {
// Custom command
g_debug ("CUSTOM command selected...");
g_object_set (dialog->notify_app_command_entry, "sensitive", TRUE, NULL);
gtk_widget_grab_focus (dialog->notify_app_command_entry);
return;
}
g_object_set (dialog->notify_app_command_entry, "sensitive", FALSE, NULL);
item = (AlarmListEntry *) g_list_nth_data (dialog->applet->apps, current_index);
g_object_set (dialog->alarm, "command", item->data, NULL);
}
/*
* Preview player {{
*/
static void
preview_player_state_cb (MediaPlayer *player, MediaPlayerState state, AlarmSettingsDialog *dialog)
{
const gchar *stock;
if (state == MEDIA_PLAYER_PLAYING) {
stock = "gtk-media-stop";
} else {
stock = "gtk-media-play";
g_debug ("AlarmSettingsDialog: Freeing media player %p", player);
media_player_free (player);
dialog->player = NULL;
}
// Set stock
gtk_button_set_label (GTK_BUTTON (dialog->notify_sound_preview), stock);
}
void
preview_sound_cb (GtkButton *button,
AlarmSettingsDialog *dialog)
{
if (dialog->player && dialog->player->state == MEDIA_PLAYER_PLAYING) {
// Stop preview player
media_player_stop (dialog->player);
} else {
// Start preview player
if (dialog->player == NULL)
dialog->player = media_player_new (dialog->alarm->sound_file,
dialog->alarm->sound_loop,
preview_player_state_cb, dialog,
media_player_error_cb, dialog->dialog);
g_debug ("AlarmSettingsDialog: preview_start...");
media_player_start (dialog->player);
}
}
/*
* }} Preview player
*/
void
alarm_settings_dialog_close (AlarmSettingsDialog *dialog)
{
g_hash_table_remove (dialog->applet->edit_alarm_dialogs, dialog->alarm->id);
gtk_widget_destroy (GTK_WIDGET (dialog->dialog));
if (dialog->player) {
if (dialog->player->state == MEDIA_PLAYER_STOPPED) {
media_player_free (dialog->player);
} else {
media_player_stop (dialog->player);
}
}
/* Remove alarm notify handlers! This would otherwise cause segfaults as
* the callbacks would look for a non-existant dialog struct.
*/
g_signal_handlers_disconnect_matched (dialog->alarm, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dialog);
// TODO: Why does this cause segfaults once the UI is reused?
Alarm *a = dialog->alarm;
g_debug ("FREE AlarmSettingsDialog %p alarm is %p", dialog, a);
g_free (dialog);
g_debug ("\talarm is %p", a);
}
static void
alarm_settings_dialog_response_cb (GtkDialog *dialog,
gint rid,
AlarmSettingsDialog *settings_dialog)
{
alarm_settings_dialog_close (settings_dialog);
}
/*
* Dialog creation
*
* TODO: A bug exists which somehow causes some widgets to become NULL
* and thus crashes the program. Investigate further.
*/
static AlarmSettingsDialog *
alarm_settings_dialog_new (Alarm *alarm, AlarmApplet *applet)
{
AlarmSettingsDialog *dialog;
GtkWidget *clock_content, *timer_content, *snooze_label;
AlarmRepeat r;
gint i;
GladeXML *ui = glade_xml_new (ALARM_UI_XML, "edit-alarm", NULL);
/* Init */
dialog = g_new0 (AlarmSettingsDialog, 1);
dialog->applet = applet;
dialog->alarm = alarm;
dialog->player = NULL;
dialog->dialog = glade_xml_get_widget (ui, "edit-alarm");
g_debug ("NEW AlarmSettingsDialog %p for alarm #%d", dialog, alarm->id);
g_debug ("\talarm is %p");
/* Response from dialog */
g_signal_connect (dialog->dialog, "response",
G_CALLBACK (alarm_settings_dialog_response_cb), dialog);
/*
* TYPE TOGGLE BUTTONS
*/
dialog->clock_toggle = glade_xml_get_widget (ui, "toggle-clock");
clock_content = create_img_label ("Alarm Clock", "alarm-clock");
dialog->timer_toggle = glade_xml_get_widget (ui, "toggle-timer");
timer_content = create_img_label ("Timer", "alarm-timer");
gtk_container_add (GTK_CONTAINER (dialog->clock_toggle), clock_content);
gtk_widget_show_all (GTK_WIDGET (dialog->clock_toggle));
gtk_container_add (GTK_CONTAINER (dialog->timer_toggle), timer_content);
gtk_widget_show_all (GTK_WIDGET (dialog->timer_toggle));
/*
* GENERAL SETTINGS
*/
dialog->label_entry = glade_xml_get_widget (ui, "label-entry");
gtk_widget_grab_focus (dialog->label_entry);
dialog->hour_spin = glade_xml_get_widget (ui, "hour-spin");
dialog->min_spin = glade_xml_get_widget (ui, "minute-spin");
dialog->sec_spin = glade_xml_get_widget (ui, "second-spin");
/*
* REPEAT SETTINGS
*/
dialog->repeat_expand = glade_xml_get_widget (ui, "repeat-expand");
dialog->repeat_label = glade_xml_get_widget (ui, "repeat-label");
/* The check buttons have the same name as the 3 letter
* string representation of the day.
*/
for (r = ALARM_REPEAT_SUN, i = 0; r <= ALARM_REPEAT_SAT; r = 1 << ++i) {
dialog->repeat_check[i] = glade_xml_get_widget (ui, alarm_repeat_to_string (r));
}
/*
* SNOOZE SETTINGS
*/
dialog->snooze_check = glade_xml_get_widget (ui, "snooze-check");
dialog->snooze_spin = glade_xml_get_widget (ui, "snooze-spin");
snooze_label = gtk_bin_get_child (GTK_BIN (dialog->snooze_check));
g_object_set (G_OBJECT (snooze_label), "use-markup", TRUE, NULL);
/*
* NOTIFY SETTINGS
*/
dialog->notify_sound_radio = glade_xml_get_widget (ui, "sound-radio");
dialog->notify_sound_box = glade_xml_get_widget (ui, "sound-box");
dialog->notify_sound_combo = glade_xml_get_widget (ui, "sound-combo");
dialog->notify_sound_preview = glade_xml_get_widget (ui, "sound-play");
dialog->notify_sound_loop_check = glade_xml_get_widget (ui, "sound-loop-check");
dialog->notify_app_radio = glade_xml_get_widget (ui, "app-radio");
dialog->notify_app_box = glade_xml_get_widget (ui, "app-box");
dialog->notify_app_combo = glade_xml_get_widget (ui, "app-combo");
dialog->notify_app_command_box = glade_xml_get_widget (ui, "app-command-box");
dialog->notify_app_command_entry = glade_xml_get_widget (ui, "app-command-entry");
dialog->notify_bubble_check = glade_xml_get_widget (ui, "notify-bubble-check");
/*
* Load apps list
*/
alarm_applet_apps_load (applet);
/*
* Populate widgets
*/
alarm_settings_update (dialog);
/* Got libnotify? */
#ifndef HAVE_LIBNOTIFY
g_object_set (dialog->notify_bubble_check, "sensitive", FALSE, NULL);
gtk_widget_set_tooltip_text (GTK_WIDGET (dialog->notify_bubble_check), _("This feature requires libnotify to be installed"));
#endif
/*
* Bind widgets
*/
alarm_bind (alarm, "message", dialog->label_entry, "text");
alarm_bind (alarm, "sound-repeat", dialog->notify_sound_loop_check, "active");
alarm_bind (alarm, "command", dialog->notify_app_command_entry, "text");
alarm_bind (alarm, "notify-bubble", dialog->notify_bubble_check, "active");
/*
* Special widgets require special attention!
*/
/* type */
g_signal_connect (alarm, "notify::type", G_CALLBACK (alarm_type_changed), dialog);
g_signal_connect (dialog->clock_toggle, "toggled", G_CALLBACK (type_toggle_cb), dialog);
g_signal_connect (dialog->timer_toggle, "toggled", G_CALLBACK (type_toggle_cb), dialog);
/* time/timer */
g_signal_connect (alarm, "notify::time", G_CALLBACK (alarm_time_changed), dialog);
g_signal_connect (alarm, "notify::timer", G_CALLBACK (alarm_timer_changed), dialog);
g_signal_connect (dialog->hour_spin, "value-changed", G_CALLBACK (time_changed_cb), dialog);
g_signal_connect (dialog->min_spin, "value-changed", G_CALLBACK (time_changed_cb), dialog);
g_signal_connect (dialog->sec_spin, "value-changed", G_CALLBACK (time_changed_cb), dialog);
/* repeat */
g_signal_connect (alarm, "notify::repeat", G_CALLBACK (alarm_repeat_changed), dialog);
for (i = 0; i < 7; i++)
g_signal_connect (dialog->repeat_check[i], "toggled", G_CALLBACK (repeat_changed_cb), dialog);
/* snooze */
g_signal_connect (alarm, "notify::snooze", G_CALLBACK (alarm_snooze_changed), dialog);
g_signal_connect (dialog->snooze_spin, "value-changed", G_CALLBACK (snooze_changed_cb), dialog);
g_signal_connect (dialog->snooze_check, "toggled", G_CALLBACK (snooze_check_changed_cb), dialog);
/* notify type */
g_signal_connect (alarm, "notify::notify-type", G_CALLBACK (alarm_notify_type_changed), dialog);
g_signal_connect (dialog->notify_sound_radio, "toggled", G_CALLBACK (notify_type_changed_cb), dialog);
g_signal_connect (dialog->notify_app_radio, "toggled", G_CALLBACK (notify_type_changed_cb), dialog);
/* sound file */
g_signal_connect (alarm, "notify::sound-file",
G_CALLBACK (alarm_settings_sound_file_changed), dialog);
g_signal_connect (dialog->notify_sound_combo, "changed",
G_CALLBACK (sound_combo_changed_cb), dialog);
g_signal_connect (dialog->notify_sound_preview, "clicked",
G_CALLBACK (preview_sound_cb), dialog);
/* app / command */
g_signal_connect (alarm, "notify::command",
G_CALLBACK (alarm_settings_command_changed), dialog);
g_signal_connect (dialog->notify_app_combo, "changed",
G_CALLBACK (app_combo_changed_cb), dialog);
/*g_signal_connect (dialog->notify_app_command_entry, "changed",
G_CALLBACK (app_command_changed_cb), dialog);*/
g_object_unref (ui);
return dialog;
}
void
display_edit_alarm_dialog (AlarmApplet *applet, Alarm *alarm)
{
AlarmSettingsDialog *dialog;
// Check if a dialog is already open for this alarm
dialog = (AlarmSettingsDialog *)g_hash_table_lookup (applet->edit_alarm_dialogs, alarm->id);
if (dialog) {
// Already open
gtk_window_present (GTK_WINDOW (dialog->dialog));
return;
}
dialog = alarm_settings_dialog_new (alarm, applet);
g_hash_table_insert (applet->edit_alarm_dialogs, alarm->id, dialog);
}

77
src/edit-alarm.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* edit-alarm.h -- Alarm settings dialog
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef EDITALARM_H_
#define EDITALARM_H_
#include "alarm-applet.h"
#include "alarm.h"
#include "player.h"
typedef struct _AlarmSettingsDialog {
AlarmApplet *applet;
Alarm *alarm;
/* Media player for previews */
MediaPlayer *player;
GtkWidget *dialog;
GtkWidget *clock_toggle, *timer_toggle;
GtkWidget *label_entry;
GtkWidget *hour_spin, *min_spin, *sec_spin;
/* Repeat */
GtkWidget *repeat_expand;
GtkWidget *repeat_label;
GtkWidget *repeat_check[7]; /* Mon, tue, ..., sun check boxes */
/* Snooze */
GtkWidget *snooze_check;
GtkWidget *snooze_spin;
/* Notification */
GtkWidget *notify_sound_radio;
GtkWidget *notify_sound_box;
GtkWidget *notify_sound_stock;
GtkWidget *notify_sound_combo;
GtkWidget *notify_sound_loop_check;
GtkWidget *notify_sound_preview;
GtkWidget *notify_app_radio;
GtkWidget *notify_app_box;
GtkWidget *notify_app_combo;
GtkWidget *notify_app_command_box;
GtkWidget *notify_app_command_entry;
GtkWidget *notify_bubble_check;
} AlarmSettingsDialog;
void
display_edit_alarm_dialog (AlarmApplet *applet, Alarm *alarm);
void
alarm_settings_dialog_close (AlarmSettingsDialog *dialog);
#endif /*EDITALARM_H_*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 985 B

After

Width:  |  Height:  |  Size: 906 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:ns="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
@@ -9,509 +10,219 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48"
height="48"
width="22"
height="22"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.45.1"
version="1.0"
sodipodi:docbase="/home/joh/workspace/alarm-applet/src/icons"
sodipodi:docname="alarm-clock.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/joh/workspace/alarm-applet/src/icons/alarm-clock.64.png"
inkscape:export-xdpi="113.91"
inkscape:export-ydpi="113.91">
inkscape:export-xdpi="261.82001"
inkscape:export-ydpi="261.82001"
sodipodi:docname="alarm22x22.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:docbase="/home/joh/Pictures">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient2911">
id="linearGradient14243">
<stop
style="stop-color:white;stop-opacity:1;"
id="stop14245"
offset="0"
id="stop2913" />
style="stop-color:#82828a;stop-opacity:1;" />
<stop
style="stop-color:white;stop-opacity:0;"
id="stop14247"
offset="1"
id="stop2915" />
style="stop-color:#e3e3e4;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient14208">
<stop
id="stop14210"
offset="0"
style="stop-color:#e1e1e3;stop-opacity:0.37755102" />
<stop
id="stop14212"
offset="1"
style="stop-color:#cccccf;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient14183">
<stop
style="stop-color:#f6d4d3;stop-opacity:1;"
offset="0"
id="stop14185" />
<stop
style="stop-color:#cccccf;stop-opacity:0;"
offset="1"
id="stop14187" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2903">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop2905" />
<stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop2907" />
</linearGradient>
<linearGradient
id="linearGradient2879">
<stop
style="stop-color:#c8cec3;stop-opacity:1;"
offset="0"
id="stop2881" />
<stop
style="stop-color:white;stop-opacity:1;"
offset="1"
id="stop2883" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2871">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop2873" />
<stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop2875" />
</linearGradient>
<linearGradient
id="linearGradient2852">
<stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop2854" />
<stop
id="stop2816"
offset="0.79518074"
style="stop-color:black;stop-opacity:0.49803922;" />
<stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2856" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2842">
<stop
style="stop-color:#2e3436;stop-opacity:1;"
offset="0"
id="stop2844" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop2846" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2826">
<stop
style="stop-color:#2e3436;stop-opacity:1;"
offset="0"
id="stop2828" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop2830" />
</linearGradient>
<linearGradient
id="linearGradient2804">
<stop
style="stop-color:#eeeeec;stop-opacity:1"
offset="0"
id="stop2806" />
<stop
style="stop-color:#2e3436;stop-opacity:1"
offset="1"
id="stop2808" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2792">
<stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop2794" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop2796" />
</linearGradient>
<linearGradient
id="linearGradient2778">
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="0"
id="stop2780" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop2782" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2852"
id="radialGradient2858"
cx="15.77732"
cy="17.018175"
fx="15.77732"
fy="17.018175"
r="13.479223"
xlink:href="#linearGradient14183"
id="linearGradient14369"
x1="11"
y1="12"
x2="11"
y2="4"
gradientUnits="userSpaceOnUse" />
<radialGradient
<filter
inkscape:collect="always"
xlink:href="#linearGradient2778"
id="radialGradient1956"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.715326,0,-1.462351e-6,1.368654,-5.935835,-2.694826)"
cx="7.7312818"
cy="6.9224148"
fx="7.7312818"
fy="6.9224148"
r="13.979223" />
<linearGradient
id="filter14553"
x="-0.085090909"
width="1.1701818"
y="-0.468"
height="1.936">
<feGaussianBlur
inkscape:collect="always"
xlink:href="#linearGradient2826"
id="linearGradient1958"
gradientUnits="userSpaceOnUse"
x1="5.1105971"
y1="25.434898"
x2="-1.1694173"
y2="4.5554562" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2792"
id="radialGradient1960"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.57113,1.6738e-6,0,2.461325,-24.47562,-35.11938)"
cx="16.962406"
cy="23.891157"
fx="16.962406"
fy="23.891157"
r="14.065099" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2842"
id="linearGradient1962"
gradientUnits="userSpaceOnUse"
x1="6.76405"
y1="6.6889873"
x2="31.357225"
y2="40.581764" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2871"
id="linearGradient2877"
x1="7.5693855"
y1="5.3379612"
x2="21.276642"
y2="35.818893"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2879"
id="linearGradient2885"
x1="12.584041"
y1="7.911427"
x2="14.316957"
y2="14.703617"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2804"
id="radialGradient2893"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.320612,0,-1.917177e-6,1.657106,-20.62529,-9.557977)"
cx="15.617997"
cy="14.602325"
fx="15.617997"
fy="14.602325"
r="0.99436891" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2903"
id="linearGradient2909"
x1="24.3125"
y1="20"
x2="17.9375"
y2="28.4375"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2911"
id="linearGradient2917"
x1="18.75"
y1="21.0625"
x2="28"
y2="26.125"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2778"
id="radialGradient4166"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.715326,0,-1.462351e-6,1.368654,-5.935835,-2.694826)"
cx="12.65834"
cy="16.440453"
fx="12.65834"
fy="16.440453"
r="13.979223" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2826"
id="linearGradient4168"
gradientUnits="userSpaceOnUse"
x1="5.1105971"
y1="25.434898"
x2="-1.1694173"
y2="4.5554562" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2778"
id="radialGradient5223"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.715326,0,-1.462351e-6,1.368654,-5.935835,-2.694826)"
cx="12.65834"
cy="16.440453"
fx="12.65834"
fy="16.440453"
r="13.979223" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2826"
id="linearGradient5225"
gradientUnits="userSpaceOnUse"
x1="5.1105971"
y1="25.434898"
x2="-1.1694173"
y2="4.5554562" />
stdDeviation="0.39"
id="feGaussianBlur14555" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10000"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6105561"
inkscape:cx="22.74523"
inkscape:cy="24.268112"
inkscape:zoom="11.313708"
inkscape:cx="19.149622"
inkscape:cy="11.39696"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
gridempspacing="2"
gridspacingx="0.5px"
gridspacingy="0.5px"
inkscape:window-width="1024"
inkscape:window-height="693"
inkscape:window-x="0"
inkscape:window-y="49"
inkscape:showpageshadow="false"
width="48px"
height="49px"
borderlayer="true"
showborder="true"
gridtolerance="10000"
inkscape:grid-points="true"
inkscape:grid-bbox="false"
inkscape:guide-bbox="true"
showguides="true">
<sodipodi:guide
orientation="horizontal"
position="24.925514"
id="guide1964" />
<sodipodi:guide
orientation="vertical"
position="24.041631"
id="guide1966" />
width="24px"
height="24px"
inkscape:snap-bbox="true"
inkscape:snap-guide="true"
inkscape:window-width="1680"
inkscape:window-height="1022"
inkscape:window-x="1680"
inkscape:window-y="28">
<inkscape:grid
type="xygrid"
id="grid2293" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<ns:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</ns:Work>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Lapo Calamandrei</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Clock</dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
<dc:subject>
<rdf:Bag>
<rdf:li>clock</rdf:li>
<rdf:li>time</rdf:li>
<rdf:li>date</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires
rdf:resource="http://web.resource.org/cc/SourceCode" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Livello 1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g1902"
transform="translate(8.5,10)"
style="opacity:0.2">
<path
sodipodi:nodetypes="ccccc"
id="path1898"
d="M 15,14 L 23,7 L 17,16 L 13,18 L 15,14 z "
style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
id="path1900"
d="M 15,16 L 21,20 L 17,14 L 13,12 L 15,16 z "
style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<path
sodipodi:type="arc"
style="opacity:1;fill:url(#radialGradient2858);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2850"
sodipodi:cx="15.77732"
sodipodi:cy="17.018175"
sodipodi:rx="13.479223"
sodipodi:ry="13.479223"
d="M 29.256543 17.018175 A 13.479223 13.479223 0 1 1 2.2980967,17.018175 A 13.479223 13.479223 0 1 1 29.256543 17.018175 z"
transform="matrix(-1.683737,0,0,1.696129,50.76034,-4.50252)" />
style="opacity:1;fill:#7c1f00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999987;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path13556"
sodipodi:cx="9"
sodipodi:cy="8.5"
sodipodi:rx="7"
sodipodi:ry="6.5"
d="M 16,8.5 A 7,6.5 0 1 1 2,8.5 A 7,6.5 0 1 1 16,8.5 z"
transform="matrix(1.1428572,0,0,1.2307694,0.7142841,0.5384597)" />
<path
transform="matrix(-0.9795916,0,0,1.0549449,19.816323,2.0329675)"
d="M 16,8.5 A 7,6.5 0 1 1 2,8.5 A 7,6.5 0 1 1 16,8.5 z"
sodipodi:ry="6.5"
sodipodi:rx="7"
sodipodi:cy="8.5"
sodipodi:cx="9"
id="path14135"
style="opacity:1;fill:#e6b6b6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999987;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:type="arc" />
<path
sodipodi:type="arc"
style="fill:url(#radialGradient1956);fill-opacity:1;stroke:url(#linearGradient1958);stroke-width:0.62724388;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path1862"
sodipodi:cx="15.77732"
sodipodi:cy="17.018175"
sodipodi:rx="13.479223"
sodipodi:ry="13.479223"
d="M 29.256543 17.018175 A 13.479223 13.479223 0 1 1 2.2980967,17.018175 A 13.479223 13.479223 0 1 1 29.256543 17.018175 z"
transform="matrix(1.595047,0,0,1.593506,-1.165574,-4.097785)" />
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999987;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path14137"
sodipodi:cx="9"
sodipodi:cy="8.5"
sodipodi:rx="7"
sodipodi:ry="6.5"
d="M 16,8.5 A 7,6.5 0 1 1 2,8.5 A 7,6.5 0 1 1 16,8.5 z"
transform="matrix(0.8571426,0,0,-0.9230768,3.2857148,18.846151)" />
<path
style="fill:#7c1f00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 2,8 C 3,5 5,3 8,2 C 7,2 4.181818,-1.4545454 1.363636,1.3636364 C -1.454546,4.1818177 2,7 2,8 z"
id="path14167"
sodipodi:nodetypes="ccsc" />
<path
sodipodi:nodetypes="cccs"
id="path14169"
d="M 2,2 C 4,0 6,2 6,2 C 4.40625,2.515625 2.642857,4.3571429 2,6 C 2,6 0,4 2,2 z"
style="fill:#e6b6b6;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:export-filename="/home/lasse/Bilder/alarm-applet/path14231.png"
inkscape:export-xdpi="98.18"
inkscape:export-ydpi="98.18" />
<path
style="opacity:0.26530612;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 21.051798,0.6490485 C 22.051798,0.6490485 22.047682,0.4239611 22.797682,1.1739611 C 23.547682,1.9239611 23.499371,1.9750874 23.499371,2.9750874 C 23.499371,3.9750874 23.129138,4.5 23.129138,4.5 C 23.129138,4.5 22.584944,3.7361359 22.084944,2.9861359 C 21.584944,2.2361359 21.084944,1.9861359 21.084944,1.9861359 L 19.814148,0.9529903 C 19.814148,0.9529903 20.051798,0.6490485 21.051798,0.6490485 z"
id="path14223"
sodipodi:nodetypes="czzczccz" />
<path
style="fill:#ea8686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 2.4545455,2.5656566 C 3.7272727,1.2929293 5,2.5656566 5,2.5656566 C 3.9857955,2.8937816 2.8636363,4.0656566 2.4545455,5.1111111 C 2.4545455,5.1111111 1.1818182,3.8383838 2.4545455,2.5656566 z"
id="path14225"
sodipodi:nodetypes="cccs" />
<path
sodipodi:nodetypes="ccsc"
id="path14229"
d="M 20,8 C 19,5 17,3 14,2 C 15,2 17.818182,-1.4545454 20.636364,1.3636364 C 23.454546,4.1818177 20,7 20,8 z"
style="fill:#7c1f00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#e6b6b6;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 20,2 C 18,0 16,2 16,2 C 17.59375,2.515625 19.357143,4.3571429 20,6 C 20,6 22,4 20,2 z"
id="path14231"
sodipodi:nodetypes="cccs"
inkscape:export-xdpi="98.18"
inkscape:export-ydpi="98.18" />
<path
sodipodi:nodetypes="cccs"
id="path14233"
d="M 19.545454,2.5656566 C 18.272727,1.2929293 17,2.5656566 17,2.5656566 C 18.014204,2.8937816 19.136364,4.0656566 19.545454,5.1111111 C 19.545454,5.1111111 20.818182,3.8383838 19.545454,2.5656566 z"
style="fill:#ea8686;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="opacity:0.50510204000000003;fill:url(#linearGradient14369);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999987;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 11,3 C 6.584,3 3,6.584 3,11 C 3,11.042399 2.999342,11.082757 3,11.125 C 5.708614,11.673234 8.758674,12 12,12 C 14.45675,12 16.793821,11.793385 18.96875,11.46875 C 18.97796,11.311644 19,11.159403 19,11 C 19,6.584 15.416,3 11,3 z"
id="path14358" />
<path
style="opacity:1;fill:#4a4a4a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999987;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 7,7.6953378 L 10.47669,13.102663 L 11.558155,12.407325 L 13.110164,8.8778033 L 11.915149,8.3564448 L 10.710712,11.089289 L 8.0814646,7 L 7,7.6953378 z"
id="rect14175" />
<path
sodipodi:type="arc"
style="fill:url(#radialGradient1960);fill-opacity:1;stroke:url(#linearGradient1962);stroke-width:0.72860712;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2752"
sodipodi:cx="15.77732"
sodipodi:cy="17.018175"
sodipodi:rx="13.479223"
sodipodi:ry="13.479223"
d="M 29.256543 17.018175 A 13.479223 13.479223 0 1 1 2.2980967,17.018175 A 13.479223 13.479223 0 1 1 29.256543 17.018175 z"
transform="matrix(1.372483,0,0,1.372483,2.345902,-0.357151)" />
style="opacity:1;fill:#000000;fill-opacity:0.16969697;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999987;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter14553)"
id="path14487"
sodipodi:cx="11.5"
sodipodi:cy="20"
sodipodi:rx="5.5"
sodipodi:ry="1"
d="M 17,20 A 5.5,1 0 1 1 6,20 A 5.5,1 0 1 1 17,20 z" />
<path
style="opacity:0.2;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 35.5,13 L 24.28125,23.28125 L 20.5,21 L 22.90625,25 L 20.5,29 L 24.375,26.6875 L 32.5,33 L 26.28125,25 L 35.5,13 z "
id="path1970"
sodipodi:nodetypes="ccccccccc" />
<path
sodipodi:type="arc"
style="fill:none;fill-opacity:1.0;stroke:url(#linearGradient2885);stroke-width:0.2239774;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2790"
sodipodi:cx="14"
sodipodi:cy="10.75"
sodipodi:rx="3.5625"
sodipodi:ry="4.3125"
d="M 17.5625 10.75 A 3.5625 4.3125 0 1 1 10.4375,10.75 A 3.5625 4.3125 0 1 1 17.5625 10.75 z"
transform="matrix(4.912278,0,0,4.057969,-44.77189,-20.62317)" />
<g
id="g2897"
transform="translate(4,0)">
<path
sodipodi:nodetypes="ccccc"
id="path2802"
d="M 19,24 L 28,31 L 21,22 L 16,19 L 19,24 z "
style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cccc"
id="path2895"
d="M 28,31 L 21,22 L 16,19 L 28,31 z "
style="fill:url(#linearGradient2917);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.3" />
</g>
<path
style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 23,22 L 35,11 L 25,24 L 20,27 L 23,22 z "
id="path2800"
style="fill:#7c1f00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300007;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
d="M 6.3749842,17 L 8.0000004,18 L 7.0000002,20.000001 L 5,20 L 6.3749842,17 z"
id="rect14431"
sodipodi:nodetypes="ccccc" />
<path
style="fill:url(#linearGradient2909);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.3"
d="M 23,22 L 35,11 L 20,27 L 23,22 z "
id="path2887"
sodipodi:nodetypes="cccc" />
<path
sodipodi:type="arc"
style="fill:url(#radialGradient2893);fill-opacity:1;stroke:black;stroke-width:0.57145953;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2901"
sodipodi:cx="16.197165"
sodipodi:cy="15.16202"
sodipodi:rx="0.99436891"
sodipodi:ry="0.92807764"
d="M 17.191533 15.16202 A 0.99436891 0.92807764 0 1 1 15.202796,15.16202 A 0.99436891 0.92807764 0 1 1 17.191533 15.16202 z"
transform="matrix(1.022222,0,0,1.078416,7.44119,6.649885)" />
<path
sodipodi:type="arc"
style="fill:url(#radialGradient2893);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2786"
sodipodi:cx="16.197165"
sodipodi:cy="15.16202"
sodipodi:rx="0.99436891"
sodipodi:ry="0.92807764"
d="M 17.191533 15.16202 A 0.99436891 0.92807764 0 1 1 15.202796,15.16202 A 0.99436891 0.92807764 0 1 1 17.191533 15.16202 z"
transform="matrix(1.022222,0,0,1.078416,7.44119,6.649885)" />
<path
sodipodi:type="arc"
style="fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2812"
sodipodi:cx="15.5"
sodipodi:cy="14.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 16 14.5 A 0.5 0.5 0 1 1 15,14.5 A 0.5 0.5 0 1 1 16 14.5 z"
transform="translate(8,8)" />
<path
sodipodi:type="arc"
style="fill:none;fill-opacity:1.0;stroke:url(#linearGradient2877);stroke-width:0.65695292;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:0.6"
id="path2865"
sodipodi:cx="15.77732"
sodipodi:cy="17.018175"
sodipodi:rx="13.479223"
sodipodi:ry="13.479223"
d="M 29.256543 17.018175 A 13.479223 13.479223 0 1 1 2.2980967,17.018175 A 13.479223 13.479223 0 1 1 29.256543 17.018175 z"
transform="matrix(1.522916,0,0,1.521443,-2.753783e-2,-2.871404)" />
<path
sodipodi:type="arc"
style="fill:url(#radialGradient4166);fill-opacity:1;stroke:url(#linearGradient4168);stroke-width:1.56844664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4164"
sodipodi:cx="15.77732"
sodipodi:cy="17.018175"
sodipodi:rx="13.479223"
sodipodi:ry="13.479223"
d="M 29.256543,17.018175 A 13.479223,13.479223 0 1 1 2.2980967,17.018174 L 15.77732,17.018175 z"
transform="matrix(-0.4510505,0.4510505,-0.4506147,-0.4506147,22.634332,5.799999)"
sodipodi:start="0"
sodipodi:end="3.1415927" />
<path
sodipodi:end="3.1415927"
sodipodi:start="0"
transform="matrix(0.4510505,0.4510505,0.4506147,-0.4506147,25.444803,5.8004615)"
d="M 29.256543,17.018175 A 13.479223,13.479223 0 1 1 2.2980967,17.018174 L 15.77732,17.018175 z"
sodipodi:ry="13.479223"
sodipodi:rx="13.479223"
sodipodi:cy="17.018175"
sodipodi:cx="15.77732"
id="path5217"
style="fill:url(#radialGradient5223);fill-opacity:1;stroke:url(#linearGradient5225);stroke-width:1.56844664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:type="arc" />
sodipodi:nodetypes="ccccc"
id="path14485"
d="M 15.625016,17 L 14,18 L 15,20.000001 L 17,20 L 15.625016,17 z"
style="fill:#7c1f00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300007;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

129
src/icons/alarm-snooze.svg Normal file
View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
id="svg2383"
sodipodi:version="0.32"
inkscape:version="0.46"
inkscape:export-filename="/home/knegil/Desktop/moon2.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="moon.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs2385">
<linearGradient
id="linearGradient3203">
<stop
id="stop3205"
offset="0"
style="stop-color:#efd4c3;stop-opacity:1;" />
<stop
id="stop3207"
offset="1"
style="stop-color:#8b7e4b;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3175">
<stop
style="stop-color:#e9e9af;stop-opacity:1;"
offset="0"
id="stop3177" />
<stop
style="stop-color:#b3a571;stop-opacity:1;"
offset="1"
id="stop3179" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="16 : 8 : 1"
inkscape:persp3d-origin="8 : 5.3333333 : 1"
id="perspective2391" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3203"
id="linearGradient3256"
gradientUnits="userSpaceOnUse"
x1="4.4711633"
y1="14.434529"
x2="15.620915"
y2="7.744678"
gradientTransform="matrix(0.8968809,0,0,0.8968809,0.9898992,5.3945751e-2)" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.197802"
inkscape:cx="9.6734839"
inkscape:cy="8"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
gridtolerance="10000"
inkscape:window-width="820"
inkscape:window-height="719"
inkscape:window-x="456"
inkscape:window-y="48">
<inkscape:grid
type="xygrid"
id="grid3163"
visible="true"
enabled="true" />
</sodipodi:namedview>
<metadata
id="metadata2388">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:#483e37;fill-rule:evenodd;stroke:none;stroke-width:0.96020454;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 8 0.96875 C 5.8422845 0.96875 3.925761 1.9923796 2.65625 3.5625 C 5.6578221 3.8093887 8 5.6834266 8 8 C 7.9999996 10.316573 5.6578221 12.190611 2.65625 12.4375 C 3.9259274 13.99652 5.8511468 15 8 15 C 11.820183 15 14.90625 11.871679 14.90625 8 C 14.90625 4.1283205 11.820183 0.96875001 8 0.96875 z "
id="path3169" />
<path
style="fill:url(#linearGradient3256);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96020454000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 8 2 C 6.6868063 2 5.4883426 2.4397499 4.5 3.15625 C 7.0874518 3.7114441 9 5.6712501 9 8 C 9.0000002 10.32875 7.0874518 12.288556 4.5 12.84375 C 5.4883426 13.56025 6.6868064 14 8 14 C 11.312 14 14 11.312 14 8 C 14 4.6879999 11.312 2.0000001 8 2 z "
id="path3173" />
<path
style="fill:#e9ddaf;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96020454000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 8 3 C 7.47215 3 6.9777785 3.0981689 6.5 3.25 C 8.5204097 3.8920572 10 5.76785 10 8 C 9.9999998 10.23215 8.5204098 12.107943 6.5 12.75 C 6.9777785 12.901831 7.47215 13 8 13 C 10.76 13 13 10.76 13 8 C 13 5.2400001 10.76 3.0000001 8 3 z "
id="path3199" />
<path
style="fill:none;fill-rule:evenodd;stroke:#ab9a91;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.69421487999999998"
d="M 10.28028,7.3865807 C 9.4228586,9.4517267 13,9 13,9"
id="path3183" />
<path
id="path3185"
d="M 8,5 C 8.798882,7.0884897 11.083661,4.2992638 11.083661,4.2992638"
style="opacity:0.25206612;fill:none;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:none;fill-rule:evenodd;stroke:#b5a79e;stroke-width:0.83043544999999985px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.83057851000000005"
d="M 10.167824,10.854943 C 9.9159795,13.332317 12,12 12,12"
id="path3187" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

230
src/icons/alarm-timer.svg Normal file
View File

@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:ns="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.45.1"
version="1.0"
inkscape:export-filename="/home/joh/workspace/alarm-applet/src/icons/alarm-timer.64.png"
inkscape:export-xdpi="240"
inkscape:export-ydpi="240"
sodipodi:docname="alarm-timer.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:docbase="/home/joh/workspace/alarm-applet/src/icons">
<defs
id="defs4">
<linearGradient
id="linearGradient3869">
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="0"
id="stop3871" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop3873" />
</linearGradient>
<linearGradient
id="linearGradient3849">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3851" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3853" />
</linearGradient>
<linearGradient
id="linearGradient14183">
<stop
style="stop-color:#d3def6;stop-opacity:1;"
offset="0"
id="stop14185" />
<stop
style="stop-color:#cccccf;stop-opacity:0;"
offset="1"
id="stop14187" />
</linearGradient>
<filter
inkscape:collect="always"
id="filter14553"
x="-0.085090909"
width="1.1701818"
y="-0.468"
height="1.936">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.39"
id="feGaussianBlur14555" />
</filter>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="-50 : 600 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="700 : 600 : 1"
inkscape:persp3d-origin="300 : 400 : 1"
id="perspective10" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient14183"
id="linearGradient3906"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2222223,0,0,1.2222223,-1.4444447,-3.729167)"
x1="11"
y1="12"
x2="11"
y2="4" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="2"
guidetolerance="10"
objecttolerance="3"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="16.498328"
inkscape:cy="13.789888"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="809"
inkscape:window-height="672"
inkscape:window-x="787"
inkscape:window-y="266">
<inkscape:grid
type="xygrid"
id="grid2388"
enabled="true"
visible="true" />
<sodipodi:guide
orientation="1,0"
position="11.932427,17.614535"
id="guide3879" />
<sodipodi:guide
orientation="0,1"
position="10.480333,12.94258"
id="guide3881" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<ns:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:date />
<dc:creator>
<ns:Agent>
<dc:title />
</ns:Agent>
</dc:creator>
<dc:rights>
<ns:Agent>
<dc:title />
</ns:Agent>
</dc:rights>
<dc:publisher>
<ns:Agent>
<dc:title />
</ns:Agent>
</dc:publisher>
<dc:identifier />
<dc:source />
<dc:relation />
<dc:language />
<dc:subject>
<rdf:Bag />
</dc:subject>
<dc:coverage />
<dc:description />
<dc:contributor>
<ns:Agent>
<dc:title />
</ns:Agent>
</dc:contributor>
<ns:license
rdf:resource="" />
</ns:Work>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
style="opacity:1">
<path
sodipodi:type="arc"
style="opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999990;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path13556"
sodipodi:cx="9"
sodipodi:cy="8.5"
sodipodi:rx="6.8868685"
sodipodi:ry="6.447474"
d="M 15.886868,8.5 A 6.8868685,6.447474 0 1 1 2.1131315,8.5 A 6.8868685,6.447474 0 1 1 15.886868,8.5 z"
transform="matrix(1.4520388,0,0,1.5509951,-1.068349,-2.1834581)" />
<path
transform="matrix(-1.2740762,0,0,1.3720822,23.38522,-0.6626996)"
d="M 16,8.5 A 7,6.5 0 1 1 2,8.5 A 7,6.5 0 1 1 16,8.5 z"
sodipodi:ry="6.5"
sodipodi:rx="7"
sodipodi:cy="8.5"
sodipodi:cx="9"
id="path14135"
style="opacity:1;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300006999999990;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:type="arc" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300007;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 11,4 C 7.8525266,4.4081711 5.3504664,6.8639268 4.90625,10 L 7,10 L 7,12 L 4.90625,12 C 5.3504663,15.136073 7.8525265,17.591829 11,18 L 11,16 L 13,16 L 13,18 C 16.072182,17.531113 18.468343,15.082221 18.90625,12 L 17,12 L 17,10 L 18.90625,10 C 18.468343,6.9177793 16.072182,4.4688871 13,4 L 13,6 L 11,6 L 11,4 z"
id="path14137"
sodipodi:nodetypes="ccccccccccccccccc" />
<path
style="opacity:0.50510206;fill:url(#linearGradient3906);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.70300007;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 12,-0.062500028 C 6.6026661,-0.062500028 2,4.5401664 2,9.9375 C 4.3239417,11.038401 8.666364,11.881708 12,11.9375 C 15,11.9375 20.226445,11.179618 22,9.9375 C 22,4.5401664 17.397333,-0.062500028 12,-0.062500028 z"
id="path14358"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#3465a4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:8.79800033999999980;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 17,6 C 16.263819,5.1002226 11.09375,8.25 11.09375,8.25 C 10.984378,8.2833251 10.886923,8.329239 10.78125,8.375 L 10.65625,8.4375 L 10.625,8.4375 C 10.363324,8.5680415 10.096324,8.7273044 9.875,8.9375 C 8.6860357,10.066681 8.6823341,11.937785 9.84375,13.09375 C 11.005166,14.249715 12.904786,14.254181 14.09375,13.125 C 14.37291,12.859877 14.599687,12.576673 14.75,12.25 C 14.753799,12.241743 14.746283,12.227034 14.75,12.21875 L 14.78125,12.1875 C 14.794026,12.157854 14.80077,12.123712 14.8125,12.09375 C 14.8125,12.09375 17.5625,6.6875 17,6 z"
id="path3893"
sodipodi:nodetypes="cccccsssscccc" />
<path
sodipodi:type="arc"
style="opacity:1;fill:#000000;fill-opacity:0.16969694;fill-rule:nonzero;stroke:none;stroke-width:7.70300007;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter14553)"
id="path14487"
sodipodi:cx="11.5"
sodipodi:cy="20"
sodipodi:rx="5.5"
sodipodi:ry="1"
d="M 17,20 A 5.5,1 0 1 1 6,20 A 5.5,1 0 1 1 17,20 z"
transform="matrix(1.2727273,0,0,1,-2.7626329,1.8105964)" />
</g>
<g
inkscape:groupmode="layer"
id="layer2" />
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -1,12 +1,31 @@
/*
* ALARM APPLET List Entry
* list-entry.c -- Simple data structure to hold name, data and icon.
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <string.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <libgnomevfs/gnome-vfs.h>
#include <libgnomeui/libgnomeui.h>
#include "list-entry.h"
#include "util.h"
@@ -69,7 +88,7 @@ alarm_list_entry_new_file (const gchar *uri, GnomeVFSResult *ret, gchar **mime_r
*ret = result;
if (result != GNOME_VFS_OK) {
g_critical ("Could not open uri: %s", uri);
g_warning ("Could not open uri: %s", uri);
return NULL;
}

View File

@@ -1,3 +1,26 @@
/*
* list-entry.h -- Simple data structure to hold name, data and icon.
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef LISTENTRY_H_
#define LISTENTRY_H_

View File

@@ -1,6 +1,24 @@
/**
* ALARM APPLET Media player
/*
* player.c - Simple media player based on GStreamer
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <gst/gst.h>

View File

@@ -1,3 +1,26 @@
/*
* player.h - Simple media player based on GStreamer
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef PLAYER_H_
#define PLAYER_H_
@@ -14,7 +37,16 @@ typedef enum {
typedef struct _MediaPlayer MediaPlayer;
/*
* Callback for when the media player's state changes.
*/
typedef void (*MediaPlayerStateChangeCallback) (MediaPlayer *player, MediaPlayerState state, gpointer data);
/*
* Callback for when an error occurs in the media player.
* The error details is put in the error argument. This value
* should _never_ be freed in the callback!
*/
typedef void (*MediaPlayerErrorHandler) (MediaPlayer *player, GError *error, gpointer data);
struct _MediaPlayer {

View File

@@ -1,3 +1,26 @@
/*
* prefs.c -- Alarm Clock global preferences
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include "prefs.h"
void
@@ -7,26 +30,6 @@ preferences_dialog_response_cb (GtkDialog *dialog,
{
g_debug ("Preferences Response: %s", (rid == GTK_RESPONSE_CLOSE) ? "Close" : "Unknown");
// Store info & start timer
/*hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (applet->hour));
minute = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (applet->minute));
second = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (applet->second));
set_alarm_time (applet, hour, minute, second);
// Store message
g_object_get (applet->message, "text", &message, NULL);
g_debug ("response message %p", message);
set_alarm_message (applet, message);
g_free (message);
update_label (applet);
timer_start (applet);*/
if (applet->preview_player) {
media_player_stop (applet->preview_player);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
applet->preferences_dialog = NULL;
}
@@ -42,149 +45,48 @@ void
pref_update_label_type (AlarmApplet *applet)
{
switch (applet->label_type) {
case LABEL_TYPE_REMAIN:
g_object_set (applet->pref_label_type_remaining, "active", TRUE, NULL);
case LABEL_TYPE_TIME:
g_object_set (applet->pref_label_type_time, "active", TRUE, NULL);
break;
default:
// LABEL_TYPE_ALARM
g_object_set (applet->pref_label_type_alarm, "active", TRUE, NULL);
// LABEL_TYPE_TOTAL
g_object_set (applet->pref_label_type_remain, "active", TRUE, NULL);
break;
}
}
void
pref_update_notify_type (AlarmApplet *applet)
static void
pref_label_show_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
// Enable selected
switch (applet->notify_type) {
case NOTIFY_COMMAND:
g_object_set (applet->pref_notify_app, "active", TRUE, NULL);
g_object_set (applet->pref_notify_app_box, "sensitive", TRUE, NULL);
gboolean value = gtk_toggle_button_get_active (togglebutton);
// Disable others
g_object_set (applet->pref_notify_sound_box, "sensitive", FALSE, NULL);
break;
default:
// NOTIFY_SOUND
g_object_set (applet->pref_notify_sound, "active", TRUE, NULL);
g_object_set (applet->pref_notify_sound_box, "sensitive", TRUE, NULL);
// Disable others
g_object_set (applet->pref_notify_app_box, "sensitive", FALSE, NULL);
break;
}
panel_applet_gconf_set_bool (applet->parent, KEY_SHOW_LABEL, value, NULL);
}
void
pref_update_sound_file (AlarmApplet *applet)
{
AlarmListEntry *item;
GtkTreeModel *model = NULL;
GtkTreeIter iter;
GtkTreePath *path;
GtkIconTheme *theme;
GdkPixbuf *pixbuf;
GList *l;
guint pos, len, combo_len;
/*if (applet->notify_sound_file == NULL) {
g_debug ("pref_update_sound_file IS NULL or EMPTY");
// Select first in list
gtk_combo_box_set_active (GTK_COMBO_BOX (applet->pref_notify_sound_combo), 0);
static void
pref_label_type_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
const gchar *name = gtk_widget_get_name (GTK_WIDGET (togglebutton));
gboolean value = gtk_toggle_button_get_active (togglebutton);
const gchar *kval;
if (!value) {
// Not checked, not interested
return;
}*/
model = gtk_combo_box_get_model (GTK_COMBO_BOX (applet->pref_notify_sound_combo));
combo_len = gtk_tree_model_iter_n_children (model, NULL);
len = g_list_length (applet->sounds);
pos = len;
// Check if our list in model is up-to-date
// We will only detect changes in size
// Separator + Select sound file ... takes 2 spots
if (len > combo_len - 2) {
// Add new items
theme = gtk_icon_theme_get_default ();
pos = combo_len - 2;
for (l = g_list_nth (applet->sounds, pos); l != NULL; l = l->next, pos++) {
item = (AlarmListEntry *) l->data;
g_debug ("Adding %s to combo...", item->name);
pixbuf = gtk_icon_theme_load_icon (theme, item->icon, 22, 0, NULL);
gtk_list_store_insert (GTK_LIST_STORE (model), &iter, pos);
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
PIXBUF_COL, pixbuf,
TEXT_COL, item->name,
-1);
//item->icon_path = gtk_tree_model_get_string_from_iter (model, &iter);
if (pixbuf)
g_object_unref (pixbuf);
}
}
gtk_combo_box_set_active (GTK_COMBO_BOX (applet->pref_notify_sound_combo), applet->sound_pos);
g_debug ("set_row_sep_func to %d", pos);
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (applet->pref_notify_sound_combo),
is_separator, GINT_TO_POINTER (pos), NULL);
}
void
pref_update_sound_loop (AlarmApplet *applet)
{
g_object_set (applet->pref_notify_sound_loop, "active", applet->notify_sound_loop, NULL);
}
void
pref_update_command (AlarmApplet *applet)
{
guint pos, len;
GList *l;
gchar *tmp;
AlarmListEntry *item;
gboolean custom = FALSE;
g_debug ("pref_update_command setting entry to %s", applet->notify_command);
g_object_set (applet->pref_notify_app_command_entry, "text", applet->notify_command, NULL);
// Check if the command is in our list.
len = g_list_length (applet->apps);
for (pos = 0, l = applet->apps; l; l = l->next, pos++) {
item = (AlarmListEntry *) l->data;
if (strcmp (item->data, applet->notify_command) == 0) {
// FOUND
break;
if (strcmp (name, "time-radio") == 0) {
kval = gconf_enum_to_string (label_type_enum_map, LABEL_TYPE_TIME);
panel_applet_gconf_set_string (applet->parent, KEY_LABEL_TYPE, kval, NULL);
} else {
kval = gconf_enum_to_string (label_type_enum_map, LABEL_TYPE_REMAIN);
panel_applet_gconf_set_string (applet->parent, KEY_LABEL_TYPE, kval, NULL);
}
}
/* Only change sensitivity of the command entry if user
* isn't typing a custom command there already. */
if (pos >= len) {
// Custom command
pos += 1;
custom = TRUE;
}
g_debug ("CMD ENTRY HAS FOCUS? %d", GTK_WIDGET_HAS_FOCUS (applet->pref_notify_app_command_entry));
if (!GTK_WIDGET_HAS_FOCUS (applet->pref_notify_app_command_entry))
g_object_set (applet->pref_notify_app_command_entry, "sensitive", custom, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (applet->pref_notify_app_combo), pos);
}
void
pref_update_show_bubble (AlarmApplet *applet)
{
g_object_set (applet->pref_notify_bubble, "active", applet->notify_bubble, NULL);
}
void
@@ -202,48 +104,12 @@ preferences_dialog_display (AlarmApplet *applet)
applet->preferences_dialog = GTK_DIALOG (glade_xml_get_widget (ui, "preferences"));
applet->pref_label_show = glade_xml_get_widget (ui, "show-label");
applet->pref_label_type_box = glade_xml_get_widget (ui, "label-type-box");
applet->pref_label_type_alarm = glade_xml_get_widget (ui, "alarm-time");
applet->pref_label_type_remaining = glade_xml_get_widget (ui, "remain-time");
applet->pref_notify_sound = glade_xml_get_widget (ui, "play-sound");
applet->pref_notify_sound_box = glade_xml_get_widget (ui, "play-sound-box");
applet->pref_notify_sound_combo = glade_xml_get_widget (ui, "sound-combo");
applet->pref_notify_sound_preview = glade_xml_get_widget (ui, "sound-play");
applet->pref_notify_sound_loop = glade_xml_get_widget (ui, "sound-loop");
applet->pref_notify_app = glade_xml_get_widget (ui, "start-app");
applet->pref_notify_app_box = glade_xml_get_widget (ui, "app-box");
applet->pref_notify_app_combo = glade_xml_get_widget (ui, "app-combo");
applet->pref_notify_app_command_box = glade_xml_get_widget (ui, "app-command-box");
applet->pref_notify_app_command_entry = glade_xml_get_widget (ui, "app-command");
applet->pref_notify_bubble = glade_xml_get_widget (ui, "notify-bubble");
// Load sounds list
load_stock_sounds_list (applet);
// Fill stock sounds
fill_combo_box (GTK_COMBO_BOX (applet->pref_notify_sound_combo),
applet->sounds, _("Select sound file..."));
// Load applications list
load_app_list (applet);
// Fill apps
fill_combo_box (GTK_COMBO_BOX (applet->pref_notify_app_combo),
applet->apps, _("Custom command..."));
applet->pref_label_type_time = glade_xml_get_widget (ui, "time-radio");
applet->pref_label_type_remain = glade_xml_get_widget (ui, "remain-radio");
// Update UI
pref_update_label_show (applet);
pref_update_label_type (applet);
pref_update_notify_type (applet);
pref_update_sound_file (applet);
pref_update_sound_loop (applet);
pref_update_command (applet);
#ifdef HAVE_LIBNOTIFY
pref_update_show_bubble (applet);
#else
g_object_set (applet->pref_notify_bubble, "sensitive", FALSE, NULL);
gtk_widget_set_tooltip_text (GTK_WIDGET (applet->pref_notify_bubble), _("This feature requires libnotify to be installed"));
#endif
// Set response and connect signal handlers
@@ -254,435 +120,12 @@ preferences_dialog_display (AlarmApplet *applet)
g_signal_connect (applet->pref_label_show, "toggled",
G_CALLBACK (pref_label_show_changed_cb), applet);
g_signal_connect (applet->pref_label_type_alarm, "toggled",
g_signal_connect (applet->pref_label_type_time, "toggled",
G_CALLBACK (pref_label_type_changed_cb), applet);
g_signal_connect (applet->pref_label_type_remaining, "toggled",
g_signal_connect (applet->pref_label_type_remain, "toggled",
G_CALLBACK (pref_label_type_changed_cb), applet);
// Notification
g_signal_connect (applet->pref_notify_sound, "toggled",
G_CALLBACK (pref_notify_type_changed_cb), applet);
g_signal_connect (applet->pref_notify_app, "toggled",
G_CALLBACK (pref_notify_type_changed_cb), applet);
g_signal_connect (applet->pref_notify_sound_combo, "changed",
G_CALLBACK (pref_notify_sound_combo_changed_cb), applet);
g_signal_connect (applet->pref_notify_sound_preview, "clicked",
G_CALLBACK (pref_play_sound_cb), applet);
g_signal_connect (applet->pref_notify_sound_loop, "toggled",
G_CALLBACK (pref_notify_sound_loop_changed_cb), applet);
g_signal_connect (applet->pref_notify_app_combo, "changed",
G_CALLBACK (pref_notify_app_combo_changed_cb), applet);
g_signal_connect (applet->pref_notify_app_command_entry, "changed",
G_CALLBACK (pref_notify_app_command_changed_cb), applet);
// Bubble
#ifdef HAVE_LIBNOTIFY
g_signal_connect (applet->pref_notify_bubble, "toggled",
G_CALLBACK (pref_notify_bubble_changed_cb), applet);
#endif
// Show it all
gtk_widget_show_all (GTK_WIDGET (applet->preferences_dialog));
}
void
pref_label_show_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
gboolean value = gtk_toggle_button_get_active (togglebutton);
panel_applet_gconf_set_bool (applet->parent, KEY_SHOW_LABEL, value, NULL);
}
void
pref_label_type_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
const gchar *name = gtk_widget_get_name (GTK_WIDGET (togglebutton));
gboolean value = gtk_toggle_button_get_active (togglebutton);
const gchar *kval;
if (!value) {
// Not checked, not interested
return;
}
if (strcmp (name, "remain-time") == 0) {
kval = gconf_enum_to_string (label_type_enum_map, LABEL_TYPE_REMAIN);
panel_applet_gconf_set_string (applet->parent, KEY_LABEL_TYPE, kval, NULL);
} else {
kval = gconf_enum_to_string (label_type_enum_map, LABEL_TYPE_ALARM);
panel_applet_gconf_set_string (applet->parent, KEY_LABEL_TYPE, kval, NULL);
}
}
void
pref_notify_type_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
const gchar *name = gtk_widget_get_name (GTK_WIDGET (togglebutton));
gboolean value = gtk_toggle_button_get_active (togglebutton);
const gchar *kval;
if (!value) {
// Not checked, not interested
return;
}
if (strcmp (name, "start-app") == 0) {
kval = gconf_enum_to_string (notify_type_enum_map, NOTIFY_COMMAND);
panel_applet_gconf_set_string (applet->parent, KEY_NOTIFY_TYPE, kval, NULL);
} else {
kval = gconf_enum_to_string (notify_type_enum_map, NOTIFY_SOUND);
panel_applet_gconf_set_string (applet->parent, KEY_NOTIFY_TYPE, kval, NULL);
}
}
void
pref_open_sound_file_chooser (AlarmApplet *applet)
{
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new (_("Select sound file..."),
GTK_WINDOW (applet->preferences_dialog),
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (dialog), get_sound_file (applet));
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
gchar *uri;
uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
g_debug ("RESPONSE ACCEPT: %s", uri);
panel_applet_gconf_set_string (applet->parent, KEY_SOUND_FILE, uri, NULL);
g_free (uri);
} else {
g_debug ("RESPONSE CANCEL");
pref_update_sound_file (applet);
}
gtk_widget_destroy (dialog);
}
void
pref_notify_sound_combo_changed_cb (GtkComboBox *combo,
AlarmApplet *applet)
{
g_debug ("Combo_changed");
GtkTreeModel *model;
AlarmListEntry *item;
guint current_index, len, combo_len;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (applet->pref_notify_sound_combo));
combo_len = gtk_tree_model_iter_n_children (model, NULL);
current_index = gtk_combo_box_get_active (combo);
len = g_list_length (applet->sounds);
g_debug ("Current index: %d, n sounds: %d, sound index: %d", current_index, len, applet->sound_pos);
if (current_index < 0)
// None selected
return;
if (current_index >= len) {
// Select sound file
g_debug ("Open SOUND file chooser...");
pref_open_sound_file_chooser (applet);
return;
}
item = (AlarmListEntry *) g_list_nth_data (applet->sounds, current_index);
panel_applet_gconf_set_string (applet->parent, KEY_SOUND_FILE, item->data, NULL);
}
void
pref_notify_sound_loop_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
gboolean value = gtk_toggle_button_get_active (togglebutton);
panel_applet_gconf_set_bool (applet->parent, KEY_SOUND_LOOP, value, NULL);
}
void
pref_play_sound_cb (GtkButton *button,
AlarmApplet *applet)
{
if (applet->preview_player && applet->preview_player->state == MEDIA_PLAYER_PLAYING) {
// Stop preview player
media_player_stop (applet->preview_player);
} else {
// Start preview player
player_preview_start (applet);
}
}
void
pref_notify_app_combo_changed_cb (GtkComboBox *combo,
AlarmApplet *applet)
{
g_debug ("APP Combo_changed");
if (GTK_WIDGET_HAS_FOCUS (applet->pref_notify_app_command_entry)) {
g_debug (" ---- Skipping because command_entry has focus!");
return;
}
GtkTreeModel *model;
AlarmListEntry *item;
guint current_index, len, combo_len;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (applet->pref_notify_app_combo));
combo_len = gtk_tree_model_iter_n_children (model, NULL);
current_index = gtk_combo_box_get_active (combo);
len = g_list_length (applet->apps);
if (current_index < 0)
// None selected
return;
if (current_index >= len) {
// Select sound file
g_debug ("CUSTOM command selected...");
g_object_set (applet->pref_notify_app_command_entry, "sensitive", TRUE, NULL);
gtk_widget_grab_focus (applet->pref_notify_app_command_entry);
return;
}
g_object_set (applet->pref_notify_app_command_entry, "sensitive", FALSE, NULL);
item = (AlarmListEntry *) g_list_nth_data (applet->apps, current_index);
panel_applet_gconf_set_string (applet->parent, KEY_COMMAND, item->data, NULL);
}
void
pref_notify_app_command_changed_cb (GtkEditable *editable,
AlarmApplet *applet)
{
const gchar *value = gtk_entry_get_text (GTK_ENTRY (editable));
panel_applet_gconf_set_string (applet->parent, KEY_COMMAND, value, NULL);
}
void
pref_notify_bubble_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet)
{
gboolean value = gtk_toggle_button_get_active (togglebutton);
panel_applet_gconf_set_bool (applet->parent, KEY_NOTIFY_BUBBLE, value, NULL);
}
// Load stock sounds into list
void
load_stock_sounds_list (AlarmApplet *applet)
{
AlarmListEntry *entry, *new_entry;
GList *new, *l;
guint i, new_stock_len;
//if (applet->sounds != NULL)
// alarm_file_entry_list_free (&(applet->sounds));
new = alarm_list_entry_list_new ("file://" ALARM_SOUNDS_DIR,
supported_sound_mime_types);
new_stock_len = g_list_length (new);
// Add custom entries if present
if (g_list_length (applet->sounds) > applet->stock_sounds) {
l = g_list_nth (applet->sounds, applet->stock_sounds);
for (; l; l = l->next) {
entry = (AlarmListEntry *) l->data;
new_entry = alarm_list_entry_new (entry->name, entry->data, entry->icon);
new = g_list_append (new, new_entry);
}
}
alarm_list_entry_list_free(&(applet->sounds));
// Free old stock sounds
/*for (l = applet->sounds, i = 0; l && i < applet->stock_sounds; l = l->next, i++) {
alarm_file_entry_free ((AlarmFileEntry *)l->data);
}
g_list_free (applet->sounds);*/
// Update stock length and sounds
applet->sounds = new;
applet->stock_sounds = new_stock_len;
}
static gchar *
gnome_da_xml_get_string (const xmlNode *parent, const gchar *val_name)
{
const gchar * const *sys_langs;
xmlChar *node_lang;
xmlNode *element;
gchar *ret_val = NULL;
xmlChar *xml_val_name;
gint len;
gint i;
g_return_val_if_fail (parent != NULL, ret_val);
g_return_val_if_fail (parent->children != NULL, ret_val);
g_return_val_if_fail (val_name != NULL, ret_val);
#if GLIB_CHECK_VERSION (2, 6, 0)
sys_langs = g_get_language_names ();
#endif
xml_val_name = xmlCharStrdup (val_name);
len = xmlStrlen (xml_val_name);
for (element = parent->children; element != NULL; element = element->next) {
if (!xmlStrncmp (element->name, xml_val_name, len)) {
node_lang = xmlNodeGetLang (element);
if (node_lang == NULL) {
ret_val = (gchar *) xmlNodeGetContent (element);
} else {
for (i = 0; sys_langs[i] != NULL; i++) {
if (!strcmp (sys_langs[i], node_lang)) {
ret_val = (gchar *) xmlNodeGetContent (element);
/* since sys_langs is sorted from most desirable to
* least desirable, exit at first match
*/
break;
}
}
}
xmlFree (node_lang);
}
}
xmlFree (xml_val_name);
return ret_val;
}
static const gchar *
get_app_command (const gchar *app)
{
// TODO: Shouldn't be a global variable
if (app_command_map == NULL) {
app_command_map = g_hash_table_new (g_str_hash, g_str_equal);
/* `rhythmbox-client --play' doesn't actually start playing unless
* Rhythmbox is already running. Sounds like a Bug. */
g_hash_table_insert (app_command_map,
"rhythmbox", "rhythmbox-client --play");
g_hash_table_insert (app_command_map,
"banshee", "banshee --play");
// Note that totem should already be open with a file for this to work.
g_hash_table_insert (app_command_map,
"totem", "totem --play");
// Muine crashes and doesn't seem to have any play command
/*g_hash_table_insert (app_command_map,
"muine", "muine");*/
}
return g_hash_table_lookup (app_command_map, app);
}
// Load stock apps into list
void
load_app_list (AlarmApplet *applet)
{
AlarmListEntry *entry;
gchar *filename, *name, *icon, *command;
xmlDoc *xml_doc;
xmlNode *root, *section, *element;
gchar *executable;
const gchar *tmp;
if (applet->apps != NULL)
alarm_list_entry_list_free (&(applet->apps));
// We'll get the default media players from g-d-a.xml
// from gnome-control-center
filename = g_build_filename (DATADIR,
"gnome-control-center",
"gnome-default-applications.xml",
NULL);
if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
g_critical ("Could not find %s.", filename);
return;
}
xml_doc = xmlParseFile (filename);
if (!xml_doc) {
g_warning ("Could not load %s.", filename);
return;
}
root = xmlDocGetRootElement (xml_doc);
for (section = root->children; section != NULL; section = section->next) {
if (!xmlStrncmp (section->name, "media-players", 13)) {
for (element = section->children; element != NULL; element = element->next) {
if (!xmlStrncmp (element->name, "media-player", 12)) {
executable = gnome_da_xml_get_string (element, "executable");
if (is_executable_valid (executable)) {
name = gnome_da_xml_get_string (element, "name");
icon = gnome_da_xml_get_string (element, "icon-name");
// Lookup executable in app command map
tmp = get_app_command (executable);
if (tmp)
command = g_strdup (tmp);
else {
// Fall back to command specified in XML
command = gnome_da_xml_get_string (element, "command");
}
g_debug ("LOAD-APPS: Adding '%s': %s [%s]", name, command, icon);
entry = alarm_list_entry_new (name, command, icon);
g_free (name);
g_free (command);
g_free (icon);
applet->apps = g_list_append (applet->apps, entry);
}
if (executable)
g_free (executable);
}
}
}
}
g_free (filename);
// entry = alarm_list_entry_new("Rhythmbox Music Player", "rhythmbox", "rhythmbox");
// applet->apps = g_list_append (applet->apps, entry);
}

View File

@@ -1,12 +1,33 @@
/*
* prefs.h -- Alarm Clock global preferences
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef PREFS_H_
#define PREFS_H_
#include "alarm-applet.h"
void
preferences_dialog_response_cb (GtkDialog *dialog,
gint rid,
AlarmApplet *applet);
preferences_dialog_display (AlarmApplet *applet);
void
pref_update_label_show (AlarmApplet *applet);
@@ -14,67 +35,4 @@ pref_update_label_show (AlarmApplet *applet);
void
pref_update_label_type (AlarmApplet *applet);
void
pref_update_notify_type (AlarmApplet *applet);
void
pref_update_sound_file (AlarmApplet *applet);
void
pref_update_sound_loop (AlarmApplet *applet);
void
pref_update_command (AlarmApplet *applet);
void
pref_update_show_bubble (AlarmApplet *applet);
void
preferences_dialog_display (AlarmApplet *applet);
void
pref_label_show_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet);
void
pref_label_type_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet);
void
pref_notify_type_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet);
void
pref_open_sound_file_chooser (AlarmApplet *applet);
void
pref_notify_sound_combo_changed_cb (GtkComboBox *combo,
AlarmApplet *applet);
void
pref_notify_sound_loop_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet);
void
pref_play_sound_cb (GtkButton *button,
AlarmApplet *applet);
void
pref_notify_app_combo_changed_cb (GtkComboBox *combo,
AlarmApplet *applet);
void
pref_notify_app_command_changed_cb (GtkEditable *editable,
AlarmApplet *applet);
void
pref_notify_bubble_changed_cb (GtkToggleButton *togglebutton,
AlarmApplet *applet);
void
load_stock_sounds_list (AlarmApplet *applet);
void
load_app_list (AlarmApplet *applet);
#endif /*PREFS_H_*/

View File

@@ -1,3 +1,5 @@
include $(top_srcdir)/Makefile.decl
INCLUDES = \
-I. \
-I$(srcdir) \
@@ -6,10 +8,13 @@ INCLUDES = \
$(GST_CFLAGS) \
$(GNOME_LIBS2_CFLAGS) \
$(GLIB_CFLAGS) \
$(GCONF_CFLAGS) \
-I$(includedir) \
-I$(top_srcdir)/src
bin_PROGRAMS = test_player test_list_entry test_util
check_PROGRAMS = $(TEST_PROGS)
TEST_PROGS += test_alarm test_player test_list_entry test_util test_alarm glade_view test_gconf_recursive
test_player_SOURCES = $(top_srcdir)/src/player.c $(top_srcdir)/src/player.h test_player.c
test_player_LDADD = \
@@ -29,3 +34,26 @@ test_list_entry_LDADD = \
test_util_SOURCES = $(top_srcdir)/src/util.c $(top_srcdir)/src/util.h test_util.c
test_util_LDADD = \
$(GLIB_LIBS)
test_alarm_SOURCES = \
$(top_srcdir)/src/alarm.c \
$(top_srcdir)/src/player.c \
test_alarm.c
test_alarm_LDADD = \
$(GLIB_LIBS) \
$(GCONF_LIBS) \
$(GST_LIBS)
test_alarm_cpp:
cpp $(INCLUDES) test_alarm.c
glade_view_SOURCES = glade_view.c
glade_view_LDADD = \
$(GLIB_LIBS) \
$(LIBGLADE_LIBS)
test_gconf_recursive_SOURCES = test_gconf_recursive.c
test_gconf_recursive_LDADD = \
$(GLIB_LIBS) \
$(GCONF_LIBS)

58
src/tests/glade_view.c Normal file
View File

@@ -0,0 +1,58 @@
/*
* glade_view.c -- Test utility for running a glade file.
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <gtk/gtk.h>
#include <glade/glade.h>
int main (int argc, char **argv)
{
gchar *file, *root = NULL;
GladeXML *ui;
gtk_init (&argc, &argv);
if (argc < 2) {
g_printerr ("Usage: %s <glade-file> [root]\n", argv[0]);
return 1;
}
file = argv[1];
if (argc > 2)
root = argv[2];
ui = glade_xml_new (file, root, NULL);
if (!ui) {
g_printerr ("Could not open '%s'. Exiting.\n", file);
return 1;
}
GtkWidget *checkbox = glade_xml_get_widget(ui, "snooze-check");
/* you can't do this from glade */
GtkWidget *checkbox_label = gtk_bin_get_child (GTK_BIN (checkbox));
g_object_set (G_OBJECT (checkbox_label), "use_markup", TRUE, NULL);
gtk_main();
return 0;
}

540
src/tests/test_alarm.c Normal file
View File

@@ -0,0 +1,540 @@
/*
* test_alarm.c -- Alarm test suite
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include "alarm.h"
#include <time.h>
#include <glib.h>
#include <string.h>
#define GCONF_DIR "/apps/alarm-clock"
/* Fixture */
typedef struct {
Alarm *alarm;
} AlarmFixture;
static int state = 0;
/*
* TEST FIXTURE setup
*
* Called before each test case
*/
static void
alarm_fixture_setup (AlarmFixture *fix,
gconstpointer test_data)
{
fix->alarm = alarm_new (GCONF_DIR, 0);
g_assert (fix->alarm != NULL);
}
/*
* TEST FIXTURE teardown
*
* Called after each test case
*/
static void
alarm_fixture_teardown (AlarmFixture *fix,
gconstpointer test_data)
{
g_assert (fix->alarm != NULL);
alarm_delete (fix->alarm);
g_object_unref (fix->alarm);
}
/*
* TEST: Alarm properties
*
* 1. Will set properties and verify them
* 2. Will try to load properties from GConf and verify them
*/
static void
test_alarm_props (AlarmFixture *fix,
gconstpointer test_data)
{
Alarm *alarm = fix->alarm;
// g_object_set (alarm, "gconf-dir", "bar", NULL); // Shouldn't work
g_object_set (alarm,
"id", 0,
"type", ALARM_TYPE_TIMER,
"time", 1234,
"timestamp", 5678,
"active", FALSE,
"message", "Wakety zooom!",
"repeat", ALARM_REPEAT_MON | ALARM_REPEAT_WED,
"snooze", 12,
"notify_type", ALARM_NOTIFY_COMMAND,
"sound_file", "file:///foo/bar",
"sound_repeat", FALSE,
"command", "wiggle-your-toe --arg",
"notify_bubble", TRUE,
NULL);
/* Verify properties */
g_assert_cmpstr (alarm->gconf_dir, ==, GCONF_DIR);
g_assert_cmpint (alarm->id, ==, 0);
g_assert_cmpint (alarm->type, ==, ALARM_TYPE_TIMER);
g_assert_cmpint (alarm->time, ==, 1234);
g_assert_cmpint (alarm->timestamp, ==, 5678);
g_assert_cmpint (alarm->active, ==, FALSE);
g_assert_cmpstr (alarm->message, ==, "Wakety zooom!");
g_assert_cmpint (alarm->repeat, ==, ALARM_REPEAT_MON | ALARM_REPEAT_WED);
g_assert_cmpint (alarm->snooze, ==, 12);
g_assert_cmpint (alarm->notify_type, ==, ALARM_NOTIFY_COMMAND);
g_assert_cmpstr (alarm->sound_file, ==, "file:///foo/bar");
g_assert_cmpint (alarm->sound_loop, ==, FALSE);
g_assert_cmpstr (alarm->command, ==, "wiggle-your-toe --arg");
g_assert_cmpint (alarm->notify_bubble, ==, TRUE);
/* Unref alarm */
g_object_unref (fix->alarm);
/* Load settings from GConf */
fix->alarm = alarm = alarm_new (GCONF_DIR, 0);
/* Verify properties */
g_assert_cmpstr (alarm->gconf_dir, ==, GCONF_DIR);
g_assert_cmpint (alarm->id, ==, 0);
g_assert_cmpint (alarm->type, ==, ALARM_TYPE_TIMER);
g_assert_cmpint (alarm->time, ==, 1234);
g_assert_cmpint (alarm->timestamp, ==, 5678);
g_assert_cmpint (alarm->active, ==, FALSE);
g_assert_cmpstr (alarm->message, ==, "Wakety zooom!");
g_assert_cmpint (alarm->repeat, ==, ALARM_REPEAT_MON | ALARM_REPEAT_WED);
g_assert_cmpint (alarm->snooze, ==, 12);
g_assert_cmpint (alarm->notify_type, ==, ALARM_NOTIFY_COMMAND);
g_assert_cmpstr (alarm->sound_file, ==, "file:///foo/bar");
g_assert_cmpint (alarm->sound_loop, ==, FALSE);
g_assert_cmpstr (alarm->command, ==, "wiggle-your-toe --arg");
g_assert_cmpint (alarm->notify_bubble, ==, TRUE);
}
/*
* TEST: AlarmType
*/
static void
test_alarm_type (AlarmFixture *fix,
gconstpointer test_data)
{
// alarm_type_to_string ()
g_assert (alarm_type_to_string (ALARM_TYPE_INVALID) == NULL);
g_assert_cmpstr (alarm_type_to_string (ALARM_TYPE_CLOCK), ==, "clock");
g_assert_cmpstr (alarm_type_to_string (ALARM_TYPE_TIMER), ==, "timer");
// alarm_type_from_string ()
g_assert_cmpint (alarm_type_from_string ("invalid"), ==, ALARM_TYPE_INVALID);
g_assert_cmpint (alarm_type_from_string ("clock"), ==, ALARM_TYPE_CLOCK);
g_assert_cmpint (alarm_type_from_string ("timer"), ==, ALARM_TYPE_TIMER);
}
/*
* TEST: AlarmNotifyType
*/
static void
test_alarm_notify_type (AlarmFixture *fix,
gconstpointer test_data)
{
// alarm_notify_type_to_string ()
g_assert (alarm_notify_type_to_string (ALARM_NOTIFY_INVALID) == NULL);
g_assert_cmpstr (alarm_notify_type_to_string (ALARM_NOTIFY_SOUND), ==, "sound");
g_assert_cmpstr (alarm_notify_type_to_string (ALARM_NOTIFY_COMMAND), ==, "command");
// alarm_notify_type_from_string ()
g_assert_cmpint (alarm_notify_type_from_string ("invalid"), ==, ALARM_NOTIFY_INVALID);
g_assert_cmpint (alarm_notify_type_from_string ("sound"), ==, ALARM_NOTIFY_SOUND);
g_assert_cmpint (alarm_notify_type_from_string ("command"), ==, ALARM_NOTIFY_COMMAND);
}
/*
* TEST: Alarm list
*/
static void
test_alarm_list (AlarmFixture *fix,
gconstpointer test_data)
{
GList *list = NULL, *l;
guint i = 0;
Alarm *a, *a1, *a2, *a3;
// Initialize with some dummy alarms
a = alarm_new (GCONF_DIR, 3); g_object_unref (a);
a = alarm_new (GCONF_DIR, 5); g_object_unref (a);
a = alarm_new (GCONF_DIR, 8); g_object_unref (a);
a = alarm_new (GCONF_DIR, 123); g_object_unref (a);
// Get list
list = alarm_get_list (GCONF_DIR);
for (l = list; l; l = l->next, i++) {
int eq;
switch (i) {
case 0:
eq = 3;
break;
case 1:
eq = 5;
break;
case 2:
eq = 8;
break;
case 3:
eq = 123;
break;
default:
g_assert_not_reached ();
break;
}
a = ALARM (l->data);
g_assert_cmpint (a->id, ==, eq);
alarm_delete (a);
g_object_unref (a);
}
g_list_free (list);
}
/*
* Alarm signal handler
*/
static void
test_alarm_signal_alarm (Alarm *a, gchar *data)
{
//g_print ("ALARM on %p! Data: %s\n", a, data);
g_assert_cmpstr (data, ==, "the data");
state = 1;
}
/*
* Error signal handler
*/
static void
test_alarm_signal_error (Alarm *a, GError *err, gchar *data)
{
//g_print ("ERROR on %p! Message: %s, Code: %d, Data: %s", a, err->message, err->code, data);
g_assert_cmpint (a->id, ==, 0);
g_assert_cmpstr (err->message, ==, "Something bad happened");
g_assert_cmpint (err->code, ==, 123);
g_assert_cmpstr (data, ==, "the error data");
state = 2;
}
/*
* TEST: Alarm signals
*
* 1. Test "alarm" signal
* 2. Test "error" signal
*/
static void
test_alarm_signals (AlarmFixture *fix,
gconstpointer test_data)
{
Alarm *alarm = fix->alarm;
state = 0;
g_object_set (alarm,
"notify_type", ALARM_NOTIFY_COMMAND,
"command", "echo",
NULL);
// Test alarm signals
g_signal_connect (alarm, "alarm",
G_CALLBACK (test_alarm_signal_alarm),
"the data");
alarm_trigger (alarm);
g_assert_cmpint (state, ==, 1);
// Test error signals
g_signal_connect (alarm, "error", G_CALLBACK (test_alarm_signal_error),
"the error data");
alarm_error_trigger (alarm, 123, "Something bad happened");
g_assert_cmpint (state, ==, 2);
}
/*
* Callback function for stopping the GMainLoop
*/
static gboolean
stop_loop (GMainLoop *loop)
{
g_main_loop_quit (loop);
return FALSE;
}
/*
* TEST: Notify types
*
* 1. Test SOUND notification
* 2. Test COMMAND notification
*/
static void
test_alarm_notify (AlarmFixture *fix,
gconstpointer test_data)
{
Alarm *alarm = fix->alarm;
GMainLoop *loop = g_main_loop_new (g_main_context_default(), FALSE);
//
// Test SOUND notification
//
g_object_set (alarm,
"notify_type", ALARM_NOTIFY_SOUND,
"sound_file", "file:///usr/share/sounds/generic.wav",
"sound_repeat", FALSE,
NULL);
alarm_trigger (alarm);
//
// Test COMMAND notification
//
g_object_set (alarm,
"notify_type", ALARM_NOTIFY_COMMAND,
"command", "ls -a",
NULL);
alarm_trigger (alarm);
// We need to run the main loop for a couple of seconds
// so the player error/state callbacks get the alarm
// instance while it's still alive.
g_timeout_add (2000, stop_loop, loop); // Stop loop after 2 secs
g_main_loop_run (loop);
}
/*
* Callback for alarm signal.
* Will set state to the current timestamp.
*/
static void
test_alarm_timers_alarm (Alarm *a, gchar *data)
{
g_debug ("test_alarm_timers_ALARM");
state = time (NULL);
}
/*
* TEST: Alarm timers
*
* 1. Test alarm CLOCK setting time to 5 seconds from now.
* 2. Test alarm TIMER setting time to 3 seconds.
*/
static void
test_alarm_timers (AlarmFixture *fix,
gconstpointer test_data)
{
Alarm *alarm = fix->alarm;
time_t now = time(NULL);
struct tm *tm;
GMainLoop *loop = g_main_loop_new (g_main_context_default(), FALSE);
// Alarm signal handler
g_signal_connect (alarm, "alarm",
G_CALLBACK (test_alarm_timers_alarm),
"the data");
//
// Test CLOCK 5sec from now
//
now = time (NULL);
tm = localtime (&now);
//g_debug ("TEST SET %d => %d:%d:%d", now, tm->tm_hour, tm->tm_min, tm->tm_sec + 5);
alarm_set_time (alarm, tm->tm_hour, tm->tm_min, tm->tm_sec + 5);
g_object_set (alarm,
"type", ALARM_TYPE_CLOCK,
"notify_type", ALARM_NOTIFY_COMMAND,
"command", "echo CMDALARM",
NULL);
alarm_enable (alarm);
state = 0;
g_timeout_add (6000, stop_loop, loop); // Stop loop after 6 secs
g_main_loop_run (loop);
g_assert_cmpint (state - now, ==, 5);
//
// Test TIMER 3sec
//
g_object_set (alarm,
"type", ALARM_TYPE_TIMER,
"time", 3,
NULL);
alarm_enable (alarm);
state = 0;
now = time (NULL);
g_timeout_add (4000, stop_loop, loop); // Stop loop after 4 secs
g_main_loop_run (loop);
g_assert_cmpint (state - now, ==, 3);
}
/*
* TEST: AlarmRepeat
*/
static void
test_alarm_repeat (AlarmFixture *fix,
gconstpointer test_data)
{
AlarmRepeat r, rep;
const gchar *str;
gint i, wnow, wday;
GSList *list, *l;
struct tm *tm;
time_t now;
time (&now);
//
// Test single repeats to string and back again
//
g_print ("SINGLE:\n");
for (r = ALARM_REPEAT_SUN, i = 1; r <= ALARM_REPEAT_SAT; r = 1 << ++i) {
str = alarm_repeat_to_string (r);
rep = alarm_repeat_from_string (str);
g_assert_cmpint (r, ==, rep);
}
//
// Test repeat to list
//
// NONE
rep = ALARM_REPEAT_NONE;
list = alarm_repeat_to_list (rep);
g_assert (NULL == list);
rep = alarm_repeat_from_list (list);
g_assert_cmpint (rep, ==, ALARM_REPEAT_NONE);
// MULTIPLE
rep = ALARM_REPEAT_MON | ALARM_REPEAT_WED | ALARM_REPEAT_FRI;
list = alarm_repeat_to_list (rep);
GString *s = g_string_new ("");
for (l = list; l; l = l->next) {
s = g_string_append (s, (gchar *)l->data);
}
g_assert_cmpstr (s->str, ==, "monwedfri");
g_string_free (s, TRUE);
r = alarm_repeat_from_list (list);
g_assert_cmpint (r, ==, rep);
// Should free data as well but we're lazy
g_slist_free (list);
}
/*
* TEST: alarm_bind
*/
static void
test_alarm_bind (AlarmFixture *fix,
gconstpointer test_data)
{
Alarm *alarm = fix->alarm;
Alarm *alarm2 = alarm_new (GCONF_DIR, 1);
alarm_bind (alarm, "command", G_OBJECT (alarm2), "message");
g_object_set (alarm, "command", "wickid!", NULL);
g_assert_cmpstr (alarm->command, ==, alarm2->message);
alarm_delete (alarm2);
g_object_unref (alarm2);
}
/*
* Run them tests!
*/
int main (int argc, char **argv)
{
g_type_init();
g_test_init(&argc, &argv, NULL);
// Alarm primitives
g_test_add ("/alarm/type", AlarmFixture, 0, NULL, test_alarm_type, NULL);
g_test_add ("/alarm/nofity_type", AlarmFixture, 0, NULL, test_alarm_notify_type, NULL);
g_test_add ("/alarm/list", AlarmFixture, 0, NULL, test_alarm_list, NULL);
g_test_add ("/alarm/repeat", AlarmFixture, 0, NULL, test_alarm_repeat, NULL);
// Full system tests
g_test_add ("/alarm/props", AlarmFixture, 0, alarm_fixture_setup, test_alarm_props, alarm_fixture_teardown);
g_test_add ("/alarm/signal", AlarmFixture, 0, alarm_fixture_setup, test_alarm_signals, alarm_fixture_teardown);
g_test_add ("/alarm/notify", AlarmFixture, 0, alarm_fixture_setup, test_alarm_notify, alarm_fixture_teardown);
g_test_add ("/alarm/bind", AlarmFixture, 0, alarm_fixture_setup, test_alarm_bind, alarm_fixture_teardown);
g_test_add ("/alarm/timers", AlarmFixture, 0, alarm_fixture_setup, test_alarm_timers, alarm_fixture_teardown);
return g_test_run ();
}

View File

@@ -0,0 +1,74 @@
/*
* test_gconf_recursive.c -- Test utility for recursively unsetting a gconf dir.
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <glib.h>
#include <gconf/gconf-client.h>
static void
notify (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
gpointer user_data)
{
g_debug ("notify (%p, %d, %p, %p)", client, cnxn_id, entry, user_data);
if (entry) {
g_debug ("\t%s = %p", entry->key, entry->value);
}
}
int main(void)
{
GConfClient *client;
GError *err = NULL;
gboolean result;
GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
client = gconf_client_get_default();
gconf_client_add_dir (client, "/apps/atest",
GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
gconf_client_notify_add (client, "/apps/atest", notify, NULL, NULL, NULL);
result = gconf_client_recursive_unset (client, "/apps/atest/foo", GCONF_UNSET_INCLUDING_SCHEMA_NAMES, &err);
g_debug ("result: %d", result);
g_debug ("err: %p", err);
gconf_client_suggest_sync (client, &err);
g_debug ("result: %d", result);
g_debug ("err: %p", err);
g_main_loop_run (loop);
//result = gconf_client_unset (client, "/apps/atest/fooz", &err);
//result = gconf_client_
/*g_debug ("result: %d", result);
g_debug ("err: %p", err);*/
return 0;
}

View File

@@ -1,3 +1,26 @@
/*
* test_list_entry.c -- Test for AlarmListEntry
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <glib.h>
#include "list-entry.h"

View File

@@ -1,3 +1,26 @@
/*
* test_player.c -- Test utility for the MediaPlayer system.
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <glib.h>
#include "player.h"

View File

@@ -1,3 +1,26 @@
/*
* glade_util.c -- Test for alarm utilities.
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <time.h>
#include <glib.h>

614
src/ui.c
View File

@@ -1,5 +1,42 @@
/*
* ui.c - Alarm Clock applet UI routines
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <time.h>
#include <string.h>
#ifdef HAVE_LIBNOTIFY
#include <libnotify/notify.h>
#endif
#include "alarm-applet.h"
#include "ui.h"
#include "alarms-list.h"
enum
{
PIXBUF_COL,
TEXT_COL,
N_COLUMNS
};
void
display_error_dialog (const gchar *message, const gchar *secondary_text, GtkWindow *parent)
@@ -21,69 +58,80 @@ display_error_dialog (const gchar *message, const gchar *secondary_text, GtkWind
gtk_widget_destroy (dialog);
}
// TODO: Should display any triggered alarms / etc.
void
update_label (AlarmApplet *applet)
alarm_applet_label_update (AlarmApplet *applet)
{
gchar *tmp;
Alarm *a;
struct tm *tm;
guint hour, min, sec, now;
gchar *tmp;
if (applet->started) {
if (applet->label_type == LABEL_TYPE_REMAIN) {
now = time (NULL);
sec = applet->alarm_time - now;
min = sec / 60;
sec -= min * 60;
hour = min / 60;
min -= hour * 60;
tmp = g_strdup_printf(_("%02d:%02d:%02d"), hour, min, sec);
} else {
tm = localtime (&(applet->alarm_time));
tmp = g_strdup_printf(_("%02d:%02d:%02d"), tm->tm_hour, tm->tm_min, tm->tm_sec);
if (!applet->upcoming_alarm) {
// No upcoming alarms
g_object_set (applet->label, "label", ALARM_DEF_LABEL, NULL);
return;
}
a = applet->upcoming_alarm;
if (applet->label_type == LABEL_TYPE_REMAIN) {
/* Remaining time */
tm = alarm_get_remain (a);
} else {
/* Alarm time */
tm = alarm_get_time (a);
}
tmp = g_strdup_printf(_("%02d:%02d:%02d"), tm->tm_hour, tm->tm_min, tm->tm_sec);
g_object_set(applet->label, "label", tmp, NULL);
g_free(tmp);
} else if (applet->alarm_triggered) {
g_object_set(applet->label, "label", _("Alarm!"), NULL);
} else {
g_object_set(applet->label, "label", _("No alarm"), NULL);
}
}
// TODO: Refactor for more fancy tooltip with alarm summary.
void
update_tooltip (AlarmApplet *applet)
alarm_applet_update_tooltip (AlarmApplet *applet)
{
gchar *tiptext;
struct tm *tm;
struct tm *time, *remain;
GList *l;
Alarm *a;
GString *tip;
guint count = 0;
if (applet->started || applet->alarm_triggered) {
tm = localtime (&(applet->alarm_time));
tip = g_string_new ("");
// Find all active alarms
for (l = applet->alarms; l; l = l->next) {
a = ALARM (l->data);
if (!a->active) continue;
count++;
time = alarm_get_time (a);
remain = alarm_get_remain (a);
g_string_append_printf (tip, _("\n(%c) <b>%s</b> @%02d:%02d:%02d (-%02d:%02d:%02d)"), (a->type == ALARM_TYPE_TIMER) ? 'T' : 'A', a->message,
time->tm_hour, time->tm_min, time->tm_sec, remain->tm_hour, remain->tm_min, remain->tm_sec);
}
if (applet->alarm_triggered) {
tiptext = g_strdup_printf (_("Alarm at %02d:%02d:%02d\n%s"),
tm->tm_hour, tm->tm_min, tm->tm_sec,
applet->alarm_message);
} else if (applet->started) {
tiptext = g_strdup_printf (_("Alarm set to %02d:%02d:%02d\nMessage: %s"),
tm->tm_hour, tm->tm_min, tm->tm_sec,
applet->alarm_message);
if (count > 0) {
tip = g_string_prepend (tip, _("Active alarms:"));
} else {
// No alarm set or triggered
tiptext = g_strdup (_("Click to set alarm"));
tip = g_string_append (tip, _("No active alarms"));
}
gtk_widget_set_tooltip_text (GTK_WIDGET (applet->parent), tiptext);
tip = g_string_append (tip, _("\n\nClick to snooze alarms"));
tip = g_string_append (tip, _("\nDouble click to edit alarms"));
g_free (tiptext);
gtk_widget_set_tooltip_markup (GTK_WIDGET (applet->parent), tip->str);
g_string_free (tip, TRUE);
}
gboolean
static gboolean
is_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer sep_index)
{
GtkTreePath *path;
@@ -122,6 +170,8 @@ fill_combo_box (GtkComboBox *combo_box, GList *list, const gchar *custom_label)
model = GTK_TREE_MODEL (gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING));
gtk_combo_box_set_model (combo_box, model);
gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box));
renderer = gtk_cell_renderer_pixbuf_new ();
/* not all cells have a pixbuf, this prevents the combo box to shrink */
@@ -161,89 +211,6 @@ fill_combo_box (GtkComboBox *combo_box, GList *list, const gchar *custom_label)
-1);
}
void
set_alarm_dialog_response_cb (GtkDialog *dialog,
gint rid,
AlarmApplet *applet)
{
guint hour, minute, second;
gchar *message;
g_debug ("Set-Alarm Response: %s", (rid == GTK_RESPONSE_OK) ? "OK" : "Cancel");
if (rid == GTK_RESPONSE_OK) {
// Store info & start timer
hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (applet->hour));
minute = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (applet->minute));
second = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (applet->second));
g_object_get (applet->message, "text", &message, NULL);
alarm_gconf_set_started (applet, TRUE);
alarm_gconf_set_alarm (applet, hour, minute, second);
alarm_gconf_set_message (applet, message);
g_free (message);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
applet->set_alarm_dialog = NULL;
}
void
set_alarm_dialog_populate (AlarmApplet *applet)
{
if (applet->set_alarm_dialog == NULL)
return;
struct tm *tm;
/* Fill fields */
if (applet->alarm_time != 0) {
tm = localtime (&(applet->alarm_time));
g_object_set (applet->hour, "value", (gdouble)tm->tm_hour, NULL);
g_object_set (applet->minute, "value", (gdouble)tm->tm_min, NULL);
g_object_set (applet->second, "value", (gdouble)tm->tm_sec, NULL);
}
if (applet->alarm_message != NULL) {
g_object_set (applet->message, "text", applet->alarm_message, NULL);
}
}
void
display_set_alarm_dialog (AlarmApplet *applet)
{
if (applet->set_alarm_dialog != NULL) {
// Dialog already open.
gtk_window_present (GTK_WINDOW (applet->set_alarm_dialog));
return;
}
GladeXML *ui = glade_xml_new(ALARM_UI_XML, "set-alarm", NULL);
GtkWidget *ok_button;
/* Fetch widgets */
applet->set_alarm_dialog = GTK_DIALOG (glade_xml_get_widget (ui, "set-alarm"));
applet->hour = glade_xml_get_widget (ui, "hour");
applet->minute = glade_xml_get_widget (ui, "minute");
applet->second = glade_xml_get_widget (ui, "second");
applet->message = glade_xml_get_widget (ui, "message");
ok_button = glade_xml_get_widget (ui, "ok-button");
g_object_set (applet->set_alarm_dialog, "icon-name", ALARM_ICON, NULL);
set_alarm_dialog_populate (applet);
/* Set response and connect signal handlers */
/* TODO: Fix, this isn't working */
gtk_widget_grab_default (ok_button);
//gtk_dialog_set_default_response (applet->set_alarm_dialog, GTK_RESPONSE_OK);
g_signal_connect (applet->set_alarm_dialog, "response",
G_CALLBACK (set_alarm_dialog_response_cb), applet);
}
static gboolean
button_cb (GtkWidget *widget,
@@ -259,15 +226,16 @@ button_cb (GtkWidget *widget,
return FALSE;
}
/* TODO: if alarm is triggered { snooze } else */
if (applet->alarm_triggered) {
g_debug ("Stopping alarm!");
clear_alarm (applet);
if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
/* Double click: Open list alarms */
list_alarms_dialog_display (applet);
} else {
display_set_alarm_dialog (applet);
alarm_applet_snooze_alarms (applet);
}
/* Show edit alarms dialog */
//display_list_alarms_dialog (applet);
return TRUE;
}
@@ -315,52 +283,219 @@ applet_back_change (PanelApplet *a,
}
static void
destroy_cb (GtkObject *object, AlarmApplet *applet)
/* Taken from gnome-panel/button-widget.c */
void
alarm_applet_icon_update (AlarmApplet *applet)
{
if (applet->sounds != NULL) {
alarm_list_entry_list_free(&(applet->sounds));
static const gchar *prev_icon = ALARM_ICON;
GtkWidget *w;
GdkPixbuf *icon;
gint size, pbsize;
const gchar *icon_name = ALARM_ICON;
if (applet->upcoming_alarm && applet->upcoming_alarm->type == ALARM_TYPE_TIMER) {
icon_name = TIMER_ICON;
}
timer_remove (applet);
w = GTK_WIDGET (applet->parent);
if (app_command_map != NULL)
g_hash_table_destroy (app_command_map);
if (panel_applet_get_orient (applet->parent) == PANEL_APPLET_ORIENT_UP ||
panel_applet_get_orient (applet->parent) == PANEL_APPLET_ORIENT_DOWN)
size = w->allocation.height;
else
size = w->allocation.width;
if (size < 22)
size = 16;
else if (size < 24)
size = 22;
else if (size < 32)
size = 24;
else if (size < 48)
size = 32;
else if (size < 64)
size = 48;
else
size = 64;
// Reload icon only if the size is different.}
icon = gtk_image_get_pixbuf (GTK_IMAGE (applet->icon));
if (icon) {
if (IS_HORIZONTAL (applet->parent))
pbsize = gdk_pixbuf_get_height (icon);
else
pbsize = gdk_pixbuf_get_width (icon);
if (prev_icon == icon_name && pbsize == size) {
// Do nothing
//g_debug ("load_icon: Existing size the same.");
return;
}
}
g_debug ("Resizing icon to %dx%d...", size, size);
icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
icon_name,
size,
0, NULL);
if (icon == NULL) {
g_critical ("Icon not found.");
return;
}
g_object_set (applet->icon, "pixbuf", icon, NULL);
if (icon)
g_object_unref (icon);
prev_icon = icon_name;
}
static void
change_size_cb (GtkWidget *widget,
GtkAllocation *alloc,
AlarmApplet *applet)
{
alarm_applet_icon_update (applet);
}
static void
update_orient (AlarmApplet *applet)
{
const gchar *text;
int min_width;
gdouble new_angle;
gdouble angle;
gint width;
GtkWidget *box;
if (IS_HORIZONTAL (applet->parent) && ORIENT_IS_HORIZONTAL (applet->orient)) {
// Nothing to do, both old and new orientation is horizontal.
return;
}
/* Do we need to repack? */
if (IS_HORIZONTAL (applet->parent) != ORIENT_IS_HORIZONTAL (applet->orient)) {
g_debug ("update_orient: REPACK");
// Add new
if (IS_HORIZONTAL (applet->parent))
box = gtk_hbox_new(FALSE, 6);
else
box = gtk_vbox_new(FALSE, 6);
/* Keep children */
g_object_ref (applet->icon);
g_object_ref (applet->label);
/* Remove old */
gtk_container_remove (GTK_CONTAINER (applet->box), applet->icon);
gtk_container_remove (GTK_CONTAINER (applet->box), applet->label);
gtk_container_remove (GTK_CONTAINER (applet->parent), applet->box);
/* Pack */
gtk_box_pack_start_defaults(GTK_BOX (box), applet->icon);
gtk_box_pack_start_defaults(GTK_BOX (box), applet->label);
applet->box = box;
/* Add to container and show */
gtk_container_add (GTK_CONTAINER (applet->parent), box);
gtk_widget_show_all (GTK_WIDGET (applet->parent));
}
switch (panel_applet_get_orient (applet->parent)) {
case PANEL_APPLET_ORIENT_LEFT:
new_angle = 270;
break;
case PANEL_APPLET_ORIENT_RIGHT:
new_angle = 90;
break;
default:
new_angle = 0;
break;
}
angle = gtk_label_get_angle (GTK_LABEL (applet->label));
if (angle != new_angle) {
//unfix_size (cd);
gtk_label_set_angle (GTK_LABEL (applet->label), new_angle);
}
}
static void
orient_change_cb (PanelApplet *a,
PanelAppletOrient orient,
AlarmApplet *applet)
{
g_debug ("applet_orient_change");
update_orient (applet);
// Store new orientation
applet->orient = panel_applet_get_orient (applet->parent);
}
static void
unrealize_cb (GtkWidget *object, AlarmApplet *applet)
{
alarm_applet_destroy (applet);
}
#ifdef HAVE_LIBNOTIFY
static void
alarm_applet_notification_action_cb (NotifyNotification *notify,
gchar *action,
gpointer data)
{
Alarm *alarm = ALARM (data);
g_debug ("NOTIFY ACTION: %s", action);
if (strcmp (action, "clear") == 0) {
g_debug ("NOTIFY CLEAR #%d", alarm->id);
alarm_clear (alarm);
} else {
// "snooze"
g_debug ("NOTIFY SNOOZE #%d", alarm->id);
alarm_snooze (alarm);
}
}
#endif
/* Taken from the battery applet */
gboolean
display_notification (AlarmApplet *applet)
alarm_applet_notification_display (AlarmApplet *applet, Alarm *alarm)
{
#ifdef HAVE_LIBNOTIFY
GError *error = NULL;
GdkPixbuf *icon;
//GdkPixbuf *icon;
gboolean result;
const gchar *message;
const gchar *icon = (alarm->type == ALARM_TYPE_CLOCK) ? ALARM_ICON : TIMER_ICON;
if (!notify_is_initted () && !notify_init (_("Alarm Applet")))
return FALSE;
icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
ALARM_ICON,
48,
GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
message = alarm->message;
if (icon == NULL) {
g_critical ("Icon not found.");
applet->notify = notify_notification_new (_("Alarm!"), message, icon, GTK_WIDGET (applet->icon));
notify_notification_set_timeout (applet->notify, NOTIFY_EXPIRES_NEVER);
notify_notification_add_action (applet->notify, "clear", "Clear", alarm_applet_notification_action_cb, alarm, NULL);
if (alarm->snooze) {
notify_notification_add_action (applet->notify, "snooze", "Snooze", alarm_applet_notification_action_cb, alarm, NULL);
}
if (applet->alarm_message)
message = applet->alarm_message;
else
message = "";
applet->notify = notify_notification_new (_("Alarm!"), message, /* "battery" */ NULL, GTK_WIDGET (applet->icon));
/* XXX: it would be nice to pass this as a named icon */
notify_notification_set_icon_from_pixbuf (applet->notify, icon);
gdk_pixbuf_unref (icon);
result = notify_notification_show (applet->notify, &error);
if (error)
@@ -369,8 +504,6 @@ display_notification (AlarmApplet *applet)
g_error_free (error);
}
//g_object_unref (G_OBJECT (n));
return result;
#else
return FALSE;
@@ -378,7 +511,7 @@ display_notification (AlarmApplet *applet)
}
gboolean
close_notification (AlarmApplet *applet)
alarm_applet_notification_close (AlarmApplet *applet)
{
#ifdef HAVE_LIBNOTIFY
gboolean result;
@@ -397,63 +530,93 @@ close_notification (AlarmApplet *applet)
#endif
}
/*
* Updates label etc
*/
static gboolean
alarm_applet_ui_update (AlarmApplet *applet)
{
if (applet->show_label) {
alarm_applet_label_update (applet);
}
alarm_applet_update_tooltip (applet);
return TRUE;
}
void
ui_setup (AlarmApplet *applet)
alarm_applet_ui_init (AlarmApplet *applet)
{
GtkWidget *hbox;
GdkPixbuf *icon;
/* Set up PanelApplet signals */
g_signal_connect (G_OBJECT(applet->parent), "button-press-event",
G_CALLBACK(button_cb), applet);
g_signal_connect (G_OBJECT(applet->parent), "destroy",
G_CALLBACK(destroy_cb), applet);
g_signal_connect (G_OBJECT(applet->parent), "unrealize",
G_CALLBACK(unrealize_cb), applet);
g_signal_connect (G_OBJECT(applet->parent), "change_background",
g_signal_connect (G_OBJECT(applet->parent), "change-background",
G_CALLBACK (applet_back_change), applet);
/* Set up container hbox */
hbox = gtk_hbox_new(FALSE, 6);
g_signal_connect (G_OBJECT(applet->parent), "change-orient",
G_CALLBACK (orient_change_cb), applet);
g_signal_connect (G_OBJECT(applet->parent), "size-allocate",
G_CALLBACK (change_size_cb), applet);
/* Set up container box */
if (IS_HORIZONTAL (applet->parent))
applet->box = gtk_hbox_new(FALSE, 6);
else
applet->box = gtk_vbox_new(FALSE, 6);
/* Store orientation for future reference */
applet->orient = panel_applet_get_orient (applet->parent);
/* Set up icon and label */
icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
ALARM_ICON,
22,
0, NULL);
if (icon == NULL) {
g_critical ("Icon not found.");
}
applet->icon = gtk_image_new_from_pixbuf (icon);
if (icon)
g_object_unref (icon);
applet->icon = gtk_image_new ();
alarm_applet_icon_update (applet);
applet->label = g_object_new(GTK_TYPE_LABEL,
"label", _("No alarm"),
"label", ALARM_DEF_LABEL,
"use-markup", TRUE,
"visible", applet->show_label,
"no-show-all", TRUE, /* So gtk_widget_show_all() won't set visible to TRUE */
NULL);
/* Set up UI updater */
alarm_applet_ui_update (applet);
applet->timer_id = g_timeout_add_seconds (1, (GSourceFunc)alarm_applet_ui_update, applet);
/* Pack */
gtk_box_pack_start_defaults(GTK_BOX(hbox), applet->icon);
gtk_box_pack_start_defaults(GTK_BOX(hbox), applet->label);
gtk_box_pack_start_defaults(GTK_BOX (applet->box), applet->icon);
gtk_box_pack_start_defaults(GTK_BOX (applet->box), applet->label);
/* Update orientation */
update_orient (applet);
/* Add to container and show */
gtk_container_add (GTK_CONTAINER (applet->parent), hbox);
gtk_container_add (GTK_CONTAINER (applet->parent), applet->box);
gtk_widget_show_all (GTK_WIDGET (applet->parent));
update_tooltip (applet);
alarm_applet_update_tooltip (applet);
}
static void
menu_set_alarm_cb (BonoboUIComponent *component,
gpointer data,
menu_snooze_alarm_cb (BonoboUIComponent *component,
AlarmApplet *applet,
const gchar *cname)
{
AlarmApplet *applet = (AlarmApplet *)data;
display_set_alarm_dialog (applet);
g_debug("menu_snooze_alarm");
alarm_applet_snooze_alarms (applet);
}
static void
@@ -463,7 +626,16 @@ menu_clear_alarm_cb (BonoboUIComponent *component,
{
g_debug("menu_clear_alarm");
clear_alarm (applet);
alarm_applet_clear_alarms (applet);
}
static void
menu_list_alarms_cb (BonoboUIComponent *component,
gpointer data,
const gchar *cname)
{
AlarmApplet *applet = (AlarmApplet *)data;
list_alarms_dialog_display (applet);
}
static void
@@ -486,15 +658,15 @@ menu_about_cb (BonoboUIComponent *component,
g_debug("about_dialog");
static const gchar *const authors[] = {
"Johannes H. Jensen <joh@deworks.net>",
"Johannes H. Jensen <joh@pseudoberries.com>",
NULL
};
static const gchar *const documenters[] = {
"Johannes H. Jensen <joh@deworks.net>",
"Johannes H. Jensen <joh@pseudoberries.com>",
NULL
};
static const gchar *const artists[] = {
"Johannes H. Jensen <joh@deworks.net>",
"Lasse Gulvåg Sætre <lassegs@gmail.com>",
NULL
};
@@ -503,7 +675,7 @@ menu_about_cb (BonoboUIComponent *component,
"title", _("About " ALARM_NAME),
"version", VERSION,
"copyright", "\xC2\xA9 2007 Johannes H. Jensen",
"website", "http://joh.deworks.net/blog/?page_id=58",
"website", "http://alarm-clock.pseudoberries.com/",
"authors", authors,
"documenters", documenters,
"artists", artists,
@@ -511,22 +683,34 @@ menu_about_cb (BonoboUIComponent *component,
NULL);
}
/*
* Set up menu
*/
void
menu_setup (AlarmApplet *applet)
alarm_applet_menu_init (AlarmApplet *applet)
{
GtkIconInfo *info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default(), SNOOZE_ICON, 16, 0);
g_debug ("ICON: %s", gtk_icon_info_get_filename (info));
static const gchar *menu_xml =
"<popup name=\"button3\">\n"
" <menuitem name=\"Set Alarm Item\" "
" verb=\"SetAlarm\" "
" _label=\"_Set Alarm\" "
" pixtype=\"stock\" "
" pixname=\"gtk-apply\"/>\n"
" <menuitem name=\"Snooze Item\" "
" verb=\"SnoozeAlarm\" "
" _label=\"_Snooze alarms\" "
" pixtype=\"filename\" "
" pixname=\"%s\"/>\n"
" <menuitem name=\"Clear Item\" "
" verb=\"ClearAlarm\" "
" _label=\"_Clear alarm\" "
" _label=\"_Clear alarms\" "
" pixtype=\"stock\" "
" pixname=\"gtk-clear\"/>\n"
" <separator/>\n"
" <menuitem name=\"List Alarms\" "
" verb=\"ListAlarms\" "
" _label=\"_Edit Alarms\" "
" pixtype=\"stock\" "
" pixname=\"gtk-edit\"/>\n"
" <menuitem name=\"Preferences Item\" "
" verb=\"Preferences\" "
" _label=\"_Preferences...\"\n"
@@ -540,15 +724,43 @@ menu_setup (AlarmApplet *applet)
"</popup>\n";
static const BonoboUIVerb menu_verbs [] = {
BONOBO_UI_VERB ("SetAlarm", menu_set_alarm_cb),
BONOBO_UI_VERB ("SnoozeAlarm", menu_snooze_alarm_cb),
BONOBO_UI_VERB ("ClearAlarm", menu_clear_alarm_cb),
BONOBO_UI_VERB ("ListAlarms", menu_list_alarms_cb),
BONOBO_UI_VERB ("Preferences", menu_preferences_cb),
BONOBO_UI_VERB ("About", menu_about_cb),
BONOBO_UI_VERB_END
};
gchar *xml = g_strdup_printf (menu_xml, gtk_icon_info_get_filename (info));
panel_applet_setup_menu (PANEL_APPLET (applet->parent),
menu_xml,
xml,
menu_verbs,
applet);
g_free (xml);
gtk_icon_info_free (info);
}
/*
* An error callback for MediaPlayers
*/
void
media_player_error_cb (MediaPlayer *player, GError *err, GtkWindow *parent)
{
gchar *uri, *tmp;
uri = media_player_get_uri (player);
tmp = g_strdup_printf (_("%s: %s"), uri, err->message);
g_critical (_("Could not play '%s': %s"), uri, err->message);
display_error_dialog (_("Could not play"), tmp, parent);
g_free (tmp);
g_free (uri);
}

View File

@@ -1,3 +1,26 @@
/*
* ui.h - Alarm Clock applet UI routines
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef UI_H_
#define UI_H_
@@ -7,17 +30,21 @@
#include <libnotify/notify.h>
#endif
#define ORIENT_IS_HORIZONTAL(o) ((o) == PANEL_APPLET_ORIENT_UP || (o) == PANEL_APPLET_ORIENT_DOWN)
#define IS_HORIZONTAL(papplet) (ORIENT_IS_HORIZONTAL (panel_applet_get_orient (papplet)))
void
display_error_dialog (const gchar *message, const gchar *secondary_text, GtkWindow *parent);
void
update_label (AlarmApplet *applet);
alarm_applet_label_update (AlarmApplet *applet);
void
update_tooltip (AlarmApplet *applet);
alarm_applet_update_tooltip (AlarmApplet *applet);
gboolean
is_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer sep_index);
void
alarm_applet_icon_update (AlarmApplet *applet);
/*
* Shamelessly stolen from gnome-da-capplet.c
@@ -25,27 +52,19 @@ is_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer sep_index);
void
fill_combo_box (GtkComboBox *combo_box, GList *list, const gchar *custom_label);
void
set_alarm_dialog_response_cb (GtkDialog *dialog,
gint rid,
AlarmApplet *applet);
void
set_alarm_dialog_populate (AlarmApplet *applet);
void
display_set_alarm_dialog (AlarmApplet *applet);
gboolean
alarm_applet_notification_display (AlarmApplet *applet, Alarm *alarm);
gboolean
display_notification (AlarmApplet *applet);
gboolean
close_notification (AlarmApplet *applet);
alarm_applet_notification_close (AlarmApplet *applet);
void
ui_setup (AlarmApplet *applet);
alarm_applet_ui_init (AlarmApplet *applet);
void
menu_setup (AlarmApplet *applet);
alarm_applet_menu_init (AlarmApplet *applet);
void
media_player_error_cb (MediaPlayer *player, GError *err, GtkWindow *parent);
#endif /*UI_H_*/

View File

@@ -1,792 +0,0 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkDialog" id="preferences">
<property name="width_request">290</property>
<property name="title" translatable="yes">Alarm Preferences</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">False</property>
<property name="icon_name">alarm-clock</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="prefs-container">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="closebutton1">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-7</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="border_width">12</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="display-label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Display&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="display-alignment">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="display-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkCheckButton" id="show-label">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show _label</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="label-type-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="label-type-box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
<widget class="GtkRadioButton" id="alarm-time">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Alarm _time</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="remain-time">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">R_emaining time</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">alarm-time</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="notification-label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Notification&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="notification-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="notification-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkRadioButton" id="play-sound">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Play _sound</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="play-sound-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="play-sound-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkHBox" id="play-sound-inner-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkComboBox" id="sound-combo">
<property name="visible">True</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="sound-play">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-media-play</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="sound-loop">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Repea_t sound</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="start-app">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Start _Application</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">play-sound</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="app-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="app-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkComboBox" id="app-combo">
<property name="visible">True</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="app-command-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">12</property>
<child>
<widget class="GtkLabel" id="app-command-label">
<property name="visible">True</property>
<property name="label" translatable="yes">Co_mmand:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">app-command</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="app-command">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">●</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="notify-bubble">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show _notification bubble</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="set-alarm">
<property name="visible">True</property>
<property name="title" translatable="yes">Set Alarm</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">alarm-clock</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="cancelbutton1">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="ok-button">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-5</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table1">
<property name="border_width">6</property>
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<property name="homogeneous">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="label" translatable="yes">_Time:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label23">
<property name="visible">True</property>
<property name="label" translatable="yes">_Message:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">message</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkSpinButton" id="hour">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">1</property>
<property name="digits">0</property>
<property name="numeric">False</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
<property name="adjustment">0 0 23 1 10 10</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label24">
<property name="visible">True</property>
<property name="label" translatable="yes">:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="minute">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">1</property>
<property name="digits">0</property>
<property name="numeric">False</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
<property name="adjustment">0 0 59 1 10 10</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label25">
<property name="visible">True</property>
<property name="label" translatable="yes">:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="second">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">1</property>
<property name="digits">0</property>
<property name="numeric">False</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
<property name="adjustment">0 0 59 1 10 10</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="message">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">●</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@@ -1,791 +0,0 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkDialog" id="preferences">
<property name="width_request">290</property>
<property name="title" translatable="yes">Alarm Preferences</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="prefs-container">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="closebutton1">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-7</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="border_width">12</property>
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="display-label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Display&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="display-alignment">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="display-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkCheckButton" id="show-label">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show _label</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="label-type-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="label-type-box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
<widget class="GtkRadioButton" id="alarm-time">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Alarm _time</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="remain-time">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">R_emaining time</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">alarm-time</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="notification-label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Notification&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="notification-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="notification-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkRadioButton" id="play-sound">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Play _sound</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="play-sound-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="play-sound-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkHBox" id="play-sound-inner-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkComboBox" id="sound-combo">
<property name="visible">True</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="sound-play">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-media-play</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="sound-loop">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Repea_t sound</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="start-app">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Start _Application</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">play-sound</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="app-align">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkVBox" id="app-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkComboBox" id="app-combo">
<property name="visible">True</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="app-command-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">12</property>
<child>
<widget class="GtkLabel" id="app-command-label">
<property name="visible">True</property>
<property name="label" translatable="yes">Co_mmand:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">app-command</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="app-command">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">●</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="notify-bubble">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show _notification bubble</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="set-alarm">
<property name="visible">True</property>
<property name="title" translatable="yes">Set Alarm</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">stock_alarm</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="cancelbutton1">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="ok-button">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-5</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table1">
<property name="border_width">6</property>
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<property name="homogeneous">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="label" translatable="yes">_Time:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label23">
<property name="visible">True</property>
<property name="label" translatable="yes">_Message:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">message</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkSpinButton" id="hour">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">1</property>
<property name="digits">0</property>
<property name="numeric">False</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
<property name="adjustment">0 0 23 1 10 10</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label24">
<property name="visible">True</property>
<property name="label" translatable="yes">:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="minute">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">1</property>
<property name="digits">0</property>
<property name="numeric">False</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
<property name="adjustment">0 0 59 1 10 10</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label25">
<property name="visible">True</property>
<property name="label" translatable="yes">:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="second">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="climb_rate">1</property>
<property name="digits">0</property>
<property name="numeric">False</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
<property name="adjustment">0 0 59 1 10 10</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="message">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">●</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
<glade-project>
<name>Alarm Applet</name>
<program_name>alarm-applet</program_name>
<gnome_support>FALSE</gnome_support>
</glade-project>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
<glade-project>
<name>Alarm Applet</name>
<program_name>alarm-applet</program_name>
<gnome_support>FALSE</gnome_support>
</glade-project>

810
src/ui/alarm-clock.glade Normal file
View File

@@ -0,0 +1,810 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<glade-interface>
<widget class="GtkDialog" id="preferences">
<property name="width_request">290</property>
<property name="title" translatable="yes">Alarm Clock Preferences</property>
<property name="resizable">False</property>
<property name="icon_name">alarm-clock</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="prefs-container">
<property name="visible">True</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="display-label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Display&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="display-alignment">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="display-box">
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="show-label">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">Show a label with info about upcoming alarms</property>
<property name="label" translatable="yes">Show alarm _label</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="label-type-align">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="label-type-box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="spacing">2</property>
<child>
<widget class="GtkRadioButton" id="time-radio">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Alarm time</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="remain-radio">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Remaining time</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
<property name="group">time-radio</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="closebutton1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="response_id">-7</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="list-alarms">
<property name="visible">True</property>
<property name="title" translatable="yes">Alarms</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">alarm-clock</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<child>
<widget class="GtkHBox" id="list-alarms-box">
<property name="width_request">360</property>
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="border_width">5</property>
<property name="spacing">6</property>
<child>
<widget class="GtkScrolledWindow" id="list-alarms-scroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkTreeView" id="list-alarms-view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="headers_visible">False</property>
<property name="enable_search">False</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkVButtonBox" id="vbuttonbox1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_START</property>
<child>
<widget class="GtkButton" id="add-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-add</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="edit-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-edit</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="delete-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-delete</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area3">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="closebutton2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="response_id">-7</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="edit-alarm">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Edit alarm</property>
<property name="resizable">False</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">alarm-clock</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox4">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="height_request">36</property>
<property name="visible">True</property>
<property name="spacing">2</property>
<property name="homogeneous">True</property>
<child>
<widget class="GtkToggleButton" id="toggle-clock">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="response_id">0</property>
<child>
<placeholder/>
</child>
</widget>
</child>
<child>
<widget class="GtkToggleButton" id="toggle-timer">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="response_id">0</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<child>
<widget class="GtkSpinButton" id="hour-spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="adjustment">0 0 23 1 10 10</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;span size="xx-large"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="minute-spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="adjustment">0 0 59 1 10 10</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;span size="xx-large"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="second-spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="adjustment">0 0 59 1 10 10</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
</widget>
<packing>
<property name="position">5</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="label-entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="activates_default">True</property>
<property name="text" translatable="yes">Wake up sleepy head!</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Time:</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">hour-spin</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Label:</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">label-entry</property>
</widget>
<packing>
<property name="x_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">6</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkExpander" id="repeat-expand">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">24</property>
<child>
<widget class="GtkHBox" id="repeat-box">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkCheckButton" id="mon">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Mon</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
</child>
<child>
<widget class="GtkCheckButton" id="tue">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Tue</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="wed">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Wed</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="thu">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Thu</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="fri">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Fri</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">4</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="sat">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Sat</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">5</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="sun">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Sun</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">6</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="repeat-label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;T_rigger alarm:&lt;/b&gt;</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="snooze-box">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<widget class="GtkCheckButton" id="snooze-check">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Snoo_ze for:</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="snooze-spin">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="adjustment">0 0 99 1 10 10</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">minutes</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="notification-label2">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Notification&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="notification-align2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="notification-box">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkRadioButton" id="sound-radio">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Play _sound</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="play-sound-align2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="sound-box">
<property name="visible">True</property>
<child>
<widget class="GtkHBox" id="play-sound-inner-box2">
<property name="visible">True</property>
<child>
<widget class="GtkComboBox" id="sound-combo">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="sound-play">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-media-play</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkCheckButton" id="sound-loop-check">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Repea_t sound</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="app-radio">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Start _Application</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
<property name="group">sound-radio</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="app-align">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="app-box">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkComboBox" id="app-combo">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkHBox" id="app-command-box">
<property name="visible">True</property>
<property name="spacing">12</property>
<child>
<widget class="GtkLabel" id="app-command-label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Co_mmand:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">app-command-entry</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="app-command-entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="notify-bubble-check">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Show _notification bubble</property>
<property name="use_underline">True</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">6</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area4">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="close-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@@ -1,11 +1,30 @@
/*
* ALARM APPLET Utilities
* util.c -- Misc utilities
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#include <string.h>
#include <time.h>
#include <glib.h>
#include <glib-object.h>
#include "util.h"
/**
@@ -101,3 +120,4 @@ is_executable_valid (gchar *executable)
return FALSE;
}

View File

@@ -1,6 +1,24 @@
/*
* ALARM APPLET Utilities
* util.h -- Misc utilities
*
* Copyright (C) 2007-2008 Johannes H. Jensen <joh@pseudoberries.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Johannes H. Jensen <joh@pseudoberries.com>
*/
#ifndef UTIL_H_