3 // Copyright 2009 Michael Cronenworth <mike@cchtml.com>
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.
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.
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.
25 #include <hildon/hildon.h>
26 #include <dbus/dbus.h>
27 #include <mce/mode-names.h>
28 #include <mce/dbus-names.h>
29 #define MCE_SIGNAL_MATCH "type='signal'," \
30 "interface='" MCE_SIGNAL_IF "'," \
31 "member='" MCE_DEVICE_ORIENTATION_SIG "'"
35 // Application data struct
36 typedef struct _AppData AppData;
38 GtkWindow *main_window;
39 osso_context_t *osso_context;
40 DBusConnection *system_bus;
43 static AppData appdata;
44 static GtkWidget *timerLabel = NULL;
45 static GtkWidget *timerHistoryLabel1 = NULL;
46 static GtkWidget *timerHistoryLabel2 = NULL;
47 static GtkWidget *timerHistoryLabel3 = NULL;
48 static GtkWidget *timerHistoryLabel4 = NULL;
49 static GSList *historyList = NULL;
50 static int stopishMode = STOPISH_MODE_START;
51 static int timerHandle = -1;
54 gint dbus_callback( const gchar *interface, const gchar *method,
55 GArray *arguments, gpointer data, osso_rpc_t *retval );
56 static GtkWindow *stopish_new( void );
57 static void start_cb( GtkButton* button, gpointer data );
58 static void reset_cb( GtkButton* button, gpointer data );
59 static void close_cb( GtkButton* button, gpointer data );
60 static gboolean focus_in_cb( GtkWidget *widget, GdkEventFocus *event,
62 static gboolean focus_out_cb( GtkWidget *widget, GdkEventFocus *event,
64 static void accelerometer_enable( void );
65 static void accelerometer_disable( void );
66 static DBusHandlerResult mce_filter_func( DBusConnection * connection,
67 DBusMessage * message,
71 int main( int argc, char *argv[] )
74 HildonProgram *program;
76 appdata.osso_context = osso_initialize( "com.nokia.stopish",
77 PACKAGE_VERSION, TRUE, NULL );
78 if ( appdata.osso_context == NULL ) {
79 fprintf( stderr, "osso_initialize failed.\n" );
83 // initialize Hildonized GTK libraries
84 hildon_gtk_init( &argc, &argv );
85 program = hildon_program_get_instance( );
88 appdata.main_window = stopish_new( );
89 hildon_program_add_window( program, HILDON_WINDOW( appdata.main_window ) );
91 // Connect to session bus, add a match rule, install filter callback
92 appdata.system_bus = osso_get_sys_dbus_connection( appdata.osso_context );
93 if ( appdata.system_bus ) {
94 dbus_bus_add_match( appdata.system_bus, MCE_SIGNAL_MATCH, NULL );
95 dbus_connection_add_filter( appdata.system_bus,
100 g_printerr( "ERROR: Cannot connect to system dbus.\n" );
102 ret = osso_rpc_set_default_cb_f( appdata.osso_context,
103 dbus_callback, appdata.main_window );
104 if ( ret != OSSO_OK ) {
105 fprintf( stderr, "osso_rpc_set_default_cb_f failed: %d.\n", ret );
115 gint dbus_callback( const gchar *interface, const gchar *method,
116 GArray *arguments, gpointer data, osso_rpc_t *retval )
118 //printf( "stopish dbus: %s, %s\n", interface, method );
120 if ( !strcmp( method, "top_application" ) )
121 gtk_window_present( GTK_WINDOW( data ) );
123 retval->type = DBUS_TYPE_INVALID;
129 int stopish_get_mode( void )
135 static GtkWindow *stopish_new( void )
137 GtkWidget *window, *button, *button0, *label;
138 GtkWidget *vBoxMain, *vBox0, *hBox0;
140 window = hildon_stackable_window_new( );
142 gtk_container_set_border_width( GTK_CONTAINER( window ), 20 );
144 gtk_window_set_title( GTK_WINDOW( window ), "Stopish" );
146 // attach signals to main window
147 g_signal_connect( G_OBJECT( window ), "destroy",
148 G_CALLBACK( close_cb ), window );
149 g_signal_connect( G_OBJECT( window ), "focus-in-event",
150 G_CALLBACK( focus_in_cb ), NULL );
151 g_signal_connect( G_OBJECT( window ), "focus-out-event",
152 G_CALLBACK( focus_out_cb ), NULL );
154 vBoxMain = gtk_vbox_new( FALSE, 10 );
157 label = gtk_label_new( NULL );
158 gtk_container_add( GTK_CONTAINER( vBoxMain ), label );
161 vBox0 = gtk_vbox_new( FALSE, 5 );
164 timerLabel = gtk_label_new( NULL );
165 gtk_label_set_markup( GTK_LABEL( timerLabel ),
166 "<span font_family=\"monospace\" "
167 "size=\"70000\" weight=\"ultrabold\">"
168 "00:00:00.0</span>" );
169 gtk_container_add( GTK_CONTAINER( vBox0 ), timerLabel );
172 timerHistoryLabel1 = gtk_label_new( NULL );
173 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel1 ),
174 "<span size=\"large\"> </span>" );
175 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel1, FALSE, FALSE, 0 );
176 timerHistoryLabel2 = gtk_label_new( NULL );
177 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel2, FALSE, FALSE, 0 );
178 timerHistoryLabel3 = gtk_label_new( NULL );
179 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel3 ),
180 "<span size=\"small\"> </span>" );
181 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel3, FALSE, FALSE, 0 );
182 timerHistoryLabel4 = gtk_label_new( NULL );
183 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel4 ),
184 "<span size=\"x-small\"> </span>" );
185 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel4, FALSE, FALSE, 0 );
187 gtk_container_add( GTK_CONTAINER( vBoxMain ), vBox0 );
190 label = gtk_label_new( NULL );
191 gtk_container_add( GTK_CONTAINER( vBoxMain ), label );
194 hBox0 = gtk_hbox_new( FALSE, 15 );
195 gtk_widget_set_size_request( hBox0, -1, 80 );
197 // start/pause stopwatch button
198 button = hildon_button_new_with_text( HILDON_SIZE_HALFSCREEN_WIDTH,
199 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
201 button0 = hildon_button_new_with_text( HILDON_SIZE_HALFSCREEN_WIDTH,
202 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
204 g_signal_connect( G_OBJECT( button ), "clicked",
205 G_CALLBACK( start_cb ), button0 );
206 gtk_container_add( GTK_CONTAINER( hBox0 ), button );
209 gtk_widget_set_sensitive( button0, FALSE );
210 g_signal_connect( G_OBJECT( button0 ), "clicked",
211 G_CALLBACK( reset_cb ), button );
212 gtk_container_add( GTK_CONTAINER( hBox0 ), button0 );
214 gtk_box_pack_start( GTK_BOX( vBoxMain ), hBox0, FALSE, FALSE, 0 );
216 gtk_container_add( GTK_CONTAINER( window ), vBoxMain );
218 gtk_widget_show_all( window );
220 return GTK_WINDOW( window );
224 static void start_cb( GtkButton* button, gpointer data )
226 if ( stopishMode == STOPISH_MODE_START ) {
227 // set label text and add timer handle
228 gtk_button_set_label( button, "Pause" );
229 stopishMode = STOPISH_MODE_PAUSE;
230 stopish_set_time_start( stopish_current_time( ) );
231 timerHandle = g_timeout_add( 100, stopish_timeout_cb, timerLabel );
233 else if ( stopishMode == STOPISH_MODE_RESUME ) {
235 gtk_button_set_label( button, "Pause" );
236 stopishMode = STOPISH_MODE_PAUSE;
237 stopish_timer_resume( );
238 timerHandle = g_timeout_add( 100, stopish_timeout_cb, timerLabel );
241 // pause timer, remove timeout
242 gtk_button_set_label( button, "Resume" );
243 stopishMode = STOPISH_MODE_RESUME;
244 g_source_remove( timerHandle );
245 stopish_timer_save( );
248 // allow user to reset timer
249 gtk_widget_set_sensitive( GTK_WIDGET( data ), TRUE );
253 static void reset_cb( GtkButton* button, gpointer data )
257 char formatString[128];
259 if ( stopishMode == STOPISH_MODE_RESUME )
260 stopish_timer_resume( );
262 // set label text and remove timer handle
263 gtk_button_set_label( GTK_BUTTON( data ), "Start" );
264 stopishMode = STOPISH_MODE_START;
265 gtk_label_set_markup( GTK_LABEL( timerLabel ),
266 "<span font_family=\"monospace\" "
267 "size=\"70000\" weight=\"ultrabold\">"
268 "00:00:00.0</span>" );
269 g_source_remove( timerHandle );
271 // add current time to history
272 historyList = g_slist_prepend( historyList,
273 ( gpointer ) stopish_get_time_string( ) );
274 sprintf( formatString, "<span size=\"large\">%s</span>",
275 ( char * ) historyList->data );
276 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel1 ),
278 tempList = historyList;
279 tempList = g_slist_next( tempList );
281 gtk_label_set_text( GTK_LABEL( timerHistoryLabel2 ),
282 ( char * ) tempList->data );
284 tempList = g_slist_next( tempList );
286 sprintf( formatString, "<span size=\"small\">%s</span>",
287 ( char * ) tempList->data );
288 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel3 ),
291 tempList = g_slist_next( tempList );
293 sprintf( formatString, "<span size=\"x-small\">%s</span>",
294 ( char * ) tempList->data );
295 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel4 ),
299 // remove the history time after the 4th
300 tempList = g_slist_next( tempList );
302 tempString = tempList->data;
303 historyList = g_slist_remove( historyList, tempList->data );
308 stopish_set_time_start( 0 );
310 // disallow user to reset timer
311 gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE );
315 static void close_cb( GtkButton* button, gpointer data )
317 // disable accelerometer for battery savings
318 accelerometer_disable( );
320 // destroy main window and exit gtk main loop
321 gtk_widget_destroy( GTK_WIDGET( data ) );
326 static gboolean focus_in_cb( GtkWidget *widget, GdkEventFocus *event,
329 // enable accelerometer hardware for portrait mode support
330 accelerometer_enable( );
336 static gboolean focus_out_cb( GtkWidget *widget, GdkEventFocus *event,
339 // disable accelerometer for battery savings
340 accelerometer_disable( );
346 static void accelerometer_enable( void )
348 if ( osso_rpc_run_system( appdata.osso_context, MCE_SERVICE,
349 MCE_REQUEST_PATH, MCE_REQUEST_IF,
350 "req_accelerometer_enable", NULL,
351 DBUS_TYPE_INVALID ) != OSSO_OK ) {
352 g_printerr("WARN: Cannot enable accelerometers\n");
357 static void accelerometer_disable( void )
359 if ( osso_rpc_run_system( appdata.osso_context, MCE_SERVICE,
360 MCE_REQUEST_PATH, MCE_REQUEST_IF,
361 "req_accelerometer_disable", NULL,
362 DBUS_TYPE_INVALID ) != OSSO_OK ) {
363 g_printerr("WARN: Cannot disable accelerometers\n");
368 static DBusHandlerResult mce_filter_func( DBusConnection * connection,
369 DBusMessage * message,
372 DBusMessageIter iter;
373 char *rotation = NULL;
375 if ( dbus_message_is_signal( message, MCE_SIGNAL_IF,
376 MCE_DEVICE_ORIENTATION_SIG ) ) {
377 // here if we received an orientation dbus signal
378 if ( dbus_message_iter_init( message, &iter ) ) {
379 dbus_message_iter_get_basic( &iter, &rotation );
381 // Rotate main window
382 if ( !strcmp( rotation, MCE_ORIENTATION_PORTRAIT ) )
383 hildon_gtk_window_set_portrait_flags( GTK_WINDOW( appdata.main_window ),
384 HILDON_PORTRAIT_MODE_REQUEST );
386 hildon_gtk_window_set_portrait_flags( GTK_WINDOW( appdata.main_window ),
387 ~HILDON_PORTRAIT_MODE_REQUEST );
390 g_printerr( "ERROR: dbus_message_iter_init() failed.\n" );
393 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;