Add countdown functionality with same modes as the
[stopish] / src / stopish.c
1 //      stopish.c
2 //
3 //      Copyright 2010 Michael Cronenworth <mike@cchtml.com>
4 //
5 //      This program is free software; you can redistribute it and/or modify
6 //      it under the terms of the GNU General Public License as published by
7 //      the Free Software Foundation; either version 2 of the License, or
8 //      (at your option) any later version.
9 //
10 //      This program is distributed in the hope that it will be useful,
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //      GNU General Public License for more details.
14 //
15 //      You should have received a copy of the GNU General Public License
16 //      along with this program; if not, write to the Free Software
17 //      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 //      MA 02110-1301, USA.
19
20 #include <string.h>
21 #include <stdlib.h>
22 #include <sys/time.h>
23 #include <gtk/gtk.h>
24 #include <hildon/hildon.h>
25 #include <dbus/dbus.h>
26 #include <mce/mode-names.h>
27 #include <mce/dbus-names.h>
28 #define MCE_SIGNAL_MATCH "type='signal'," \
29         "interface='" MCE_SIGNAL_IF   "'," \
30         "member='" MCE_DEVICE_ORIENTATION_SIG "'"
31
32 #include "stopish.h"
33
34 // Application data struct
35 typedef struct _AppData AppData;
36 struct _AppData {
37     GtkWindow *main_window;
38     GtkWindow *countdown_window;
39     osso_context_t *osso_context;
40     DBusConnection *system_bus;
41 };
42
43
44 static AppData appdata;
45 static int stopishMode = STOPISH_MODE_START;
46 static int stopishOrientation = STOPISH_LANDSCAPE;
47 static int stopishType = STOPISH_TYPE_STOPWATCH;
48
49
50 //Prototypes
51 gint dbus_callback( const gchar *interface, const gchar *method,
52                         GArray *arguments, gpointer data, osso_rpc_t *retval );
53 static void main_menu( GtkWindow *window );
54 static void change_type_cb( GtkButton* button, gpointer data );
55 static void close_cb( GtkButton* button, gpointer data );
56 static void accelerometer_enable( void );
57 static void accelerometer_disable( void );
58 static DBusHandlerResult mce_filter_func( DBusConnection * connection,
59                                           DBusMessage * message,
60                                           void *data );
61
62
63 int main( int argc, char *argv[] )
64 {
65     osso_return_t ret;
66     HildonProgram *program;
67
68     appdata.osso_context = osso_initialize( "com.nokia.stopish",
69                                             PACKAGE_VERSION, TRUE, NULL );
70     if ( appdata.osso_context == NULL ) {
71         fprintf( stderr, "osso_initialize failed.\n" );
72         exit( 1 );
73     }
74
75     // initialize Hildonized GTK libraries
76     hildon_gtk_init( &argc, &argv );
77     program = hildon_program_get_instance(  );
78
79     // create main window
80     appdata.main_window = stopish_stopwatch_new(  );
81
82     // attach signals to main window
83     g_signal_connect( G_OBJECT( appdata.main_window ), "destroy",
84                       G_CALLBACK( close_cb ), appdata.main_window );
85     g_signal_connect( G_OBJECT( appdata.main_window ), "focus-in-event",
86                       G_CALLBACK( stopish_focus_in_cb ), NULL );
87     g_signal_connect( G_OBJECT( appdata.main_window ), "focus-out-event",
88                       G_CALLBACK( stopish_focus_out_cb ), NULL );
89
90     // setup main menu
91     main_menu( appdata.main_window );
92
93     hildon_program_add_window( program, HILDON_WINDOW( appdata.main_window ) );
94
95     // Connect to session bus, add a match rule, install filter callback
96     appdata.system_bus = osso_get_sys_dbus_connection( appdata.osso_context );
97     if ( appdata.system_bus ) {
98         dbus_bus_add_match( appdata.system_bus, MCE_SIGNAL_MATCH, NULL );
99         dbus_connection_add_filter( appdata.system_bus,
100                                     mce_filter_func,
101                                     NULL, NULL );
102     }
103     else
104         g_printerr( "ERROR: Cannot connect to system dbus.\n" );
105
106     ret = osso_rpc_set_default_cb_f( appdata.osso_context,
107                                      dbus_callback, appdata.main_window );
108     if ( ret != OSSO_OK ) {
109         fprintf( stderr, "osso_rpc_set_default_cb_f failed: %d.\n", ret );
110         exit( 1 );
111     }
112
113     gtk_main(  );
114
115     return 0;
116 }
117
118
119 gint dbus_callback( const gchar *interface, const gchar *method,
120                     GArray *arguments, gpointer data, osso_rpc_t *retval )
121 {
122     //printf( "stopish dbus: %s, %s\n", interface, method );
123
124     if ( !strcmp( method, "top_application" ) )
125         gtk_window_present( GTK_WINDOW( data ) );
126
127     retval->type = DBUS_TYPE_INVALID;
128
129     return OSSO_OK;
130 }
131
132
133 void stopish_about_cb( GtkButton* button, gpointer data )
134 {
135     GdkPixbuf *logo;
136     GError *error;
137     GtkWidget *dialog;
138     char *authors[2];
139
140     authors[0] = strdup( "Michael Cronenworth" );
141     authors[1] = NULL;
142
143     dialog = gtk_about_dialog_new(  );
144
145     gtk_about_dialog_set_program_name( GTK_ABOUT_DIALOG( dialog ),
146                                        "Stopish" );
147     gtk_about_dialog_set_version( GTK_ABOUT_DIALOG( dialog ),
148                                   STOPISH_VERSION_STR );
149     gtk_about_dialog_set_authors( GTK_ABOUT_DIALOG( dialog ),
150                                   ( const char ** ) authors );
151     logo = gdk_pixbuf_new_from_file( "/usr/share/icons/hicolor/40x40/hildon/stopish.png",
152                                      &error );
153     gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG( dialog ),
154                                logo );
155
156     gtk_dialog_run( GTK_DIALOG( dialog ) );
157
158     gtk_widget_destroy( dialog );
159     free( authors[0] );
160 }
161
162
163 int stopish_get_mode( void )
164 {
165     return stopishMode;
166 }
167
168
169 void stopish_set_mode( int newMode )
170 {
171     stopishMode = newMode;
172 }
173
174
175 int stopish_get_type( void )
176 {
177     return stopishType;
178 }
179
180
181 void stopish_set_type( int newType )
182 {
183     stopishType = newType;
184 }
185
186
187 int stopish_get_orientation( void )
188 {
189     return stopishOrientation;
190 }
191
192
193 gboolean stopish_focus_in_cb( GtkWidget *widget, GdkEventFocus *event,
194                               gpointer data )
195 {
196     // enable accelerometer hardware for portrait mode support
197     accelerometer_enable(  );
198
199     return FALSE;
200 }
201
202
203 gboolean stopish_focus_out_cb( GtkWidget *widget, GdkEventFocus *event,
204                                gpointer data )
205 {
206     // disable accelerometer for battery savings
207     accelerometer_disable(  );
208
209     return FALSE;
210 }
211
212
213 static void main_menu( GtkWindow *window )
214 {
215     HildonAppMenu *menu;
216     GtkWidget *button, *radio;
217
218     menu = ( HildonAppMenu * ) hildon_app_menu_new(  );
219
220     button = gtk_button_new_with_label( "Countdown" );
221     g_signal_connect_after( G_OBJECT( button ), "clicked",
222                             G_CALLBACK( change_type_cb ), NULL );
223     hildon_app_menu_append( menu, GTK_BUTTON( button ) );
224
225     button = gtk_button_new_with_label( "About" );
226     g_signal_connect_after( G_OBJECT( button ), "clicked",
227                             G_CALLBACK( stopish_about_cb ), NULL );
228     hildon_app_menu_append( menu, GTK_BUTTON( button ) );
229
230     // Hour preference
231     radio = gtk_radio_button_new_with_label( NULL, "Hour" );
232     gtk_toggle_button_set_mode( GTK_TOGGLE_BUTTON( radio ), FALSE );
233     g_signal_connect_after( G_OBJECT( radio ), "clicked",
234                             G_CALLBACK( stopish_stopwatch_perf_timer_hour ), NULL );
235     hildon_app_menu_add_filter( menu, GTK_BUTTON( radio ) );
236
237     // Minute preference
238     radio = gtk_radio_button_new_with_label_from_widget( GTK_RADIO_BUTTON( radio ), "Minute" );
239     gtk_toggle_button_set_mode( GTK_TOGGLE_BUTTON ( radio ), FALSE );
240     g_signal_connect_after( G_OBJECT( radio ), "clicked",
241                             G_CALLBACK( stopish_stopwatch_perf_timer_minute ), NULL );
242     hildon_app_menu_add_filter( menu, GTK_BUTTON( radio ) );
243
244     // default to minute
245     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio ), TRUE );
246
247     gtk_widget_show_all( GTK_WIDGET( menu ) );
248
249     hildon_window_set_app_menu( HILDON_WINDOW( window ), menu );
250 }
251
252
253 static void change_type_cb( GtkButton* button, gpointer data )
254 {
255     stopish_stopwatch_reset(  );
256     stopishType = STOPISH_TYPE_COUNTDOWN;
257     stopish_countdown_new(  );
258 }
259
260
261 static void close_cb( GtkButton* button, gpointer data )
262 {
263     // disable accelerometer for battery savings
264     accelerometer_disable(  );
265
266     // destroy main window and exit gtk main loop
267     gtk_widget_destroy( GTK_WIDGET( data ) );
268     gtk_main_quit(  );
269 }
270
271
272 static void accelerometer_enable( void )
273 {
274     if ( osso_rpc_run_system( appdata.osso_context, MCE_SERVICE,
275                               MCE_REQUEST_PATH, MCE_REQUEST_IF,
276                               "req_accelerometer_enable", NULL,
277                               DBUS_TYPE_INVALID ) != OSSO_OK ) {
278         g_printerr("WARN: Cannot enable accelerometers\n");
279     }
280 }
281
282
283 static void accelerometer_disable( void )
284 {
285     if ( osso_rpc_run_system( appdata.osso_context, MCE_SERVICE,
286                               MCE_REQUEST_PATH, MCE_REQUEST_IF,
287                               "req_accelerometer_disable", NULL,
288                               DBUS_TYPE_INVALID ) != OSSO_OK ) {
289         g_printerr("WARN: Cannot disable accelerometers\n");
290     }
291 }
292
293
294 static DBusHandlerResult mce_filter_func( DBusConnection * connection,
295                                           DBusMessage * message,
296                                           void *data )
297 {
298     DBusMessageIter iter;
299     char *rotation = NULL;
300
301     if ( dbus_message_is_signal( message, MCE_SIGNAL_IF,
302                                  MCE_DEVICE_ORIENTATION_SIG ) ) {
303         // here if we received an orientation dbus signal
304         if ( dbus_message_iter_init( message, &iter ) ) {
305             dbus_message_iter_get_basic( &iter, &rotation );
306
307             // Rotate main window
308             if ( !strcmp( rotation, MCE_ORIENTATION_PORTRAIT ) ) {
309                 hildon_gtk_window_set_portrait_flags( GTK_WINDOW( appdata.main_window ),
310                                                       HILDON_PORTRAIT_MODE_REQUEST );
311                 if ( stopishType == STOPISH_TYPE_STOPWATCH )
312                     stopish_stopwatch_label_timer_portrait(  );
313                 else
314                     stopish_countdown_label_timer_portrait(  );
315                 stopishOrientation = STOPISH_PORTRAIT;
316             }
317             else {
318                 hildon_gtk_window_set_portrait_flags( GTK_WINDOW( appdata.main_window ),
319                                                       ~HILDON_PORTRAIT_MODE_REQUEST );
320                 if ( stopishType == STOPISH_TYPE_STOPWATCH )
321                     stopish_stopwatch_label_timer_landscape(  );
322                 else
323                     stopish_countdown_label_timer_landscape(  );
324                 stopishOrientation = STOPISH_LANDSCAPE;
325             }
326         }
327         else
328             g_printerr( "ERROR: dbus_message_iter_init() failed.\n" );
329     }
330
331     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
332 }