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_widget_set_size_request( timerLabel, 700, -1 );
170 gtk_label_set_line_wrap( GTK_LABEL( timerLabel ), TRUE );
171 gtk_label_set_line_wrap_mode( GTK_LABEL( timerLabel ), PANGO_WRAP_CHAR );
172 gtk_misc_set_alignment( GTK_MISC( timerLabel ), 1.0f, 0.5f );
173 gtk_container_add( GTK_CONTAINER( vBox0 ), timerLabel );
176 timerHistoryLabel1 = gtk_label_new( NULL );
177 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel1 ),
178 "<span size=\"large\"> </span>" );
179 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel1, FALSE, FALSE, 0 );
180 timerHistoryLabel2 = gtk_label_new( NULL );
181 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel2, FALSE, FALSE, 0 );
182 timerHistoryLabel3 = gtk_label_new( NULL );
183 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel3 ),
184 "<span size=\"small\"> </span>" );
185 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel3, FALSE, FALSE, 0 );
186 timerHistoryLabel4 = gtk_label_new( NULL );
187 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel4 ),
188 "<span size=\"x-small\"> </span>" );
189 gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel4, FALSE, FALSE, 0 );
191 gtk_container_add( GTK_CONTAINER( vBoxMain ), vBox0 );
194 label = gtk_label_new( NULL );
195 gtk_container_add( GTK_CONTAINER( vBoxMain ), label );
198 hBox0 = gtk_hbox_new( FALSE, 15 );
199 gtk_widget_set_size_request( hBox0, -1, 80 );
201 // start/pause stopwatch button
202 button = hildon_button_new_with_text( HILDON_SIZE_HALFSCREEN_WIDTH,
203 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
205 button0 = hildon_button_new_with_text( HILDON_SIZE_HALFSCREEN_WIDTH,
206 HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
208 g_signal_connect( G_OBJECT( button ), "clicked",
209 G_CALLBACK( start_cb ), button0 );
210 gtk_container_add( GTK_CONTAINER( hBox0 ), button );
213 gtk_widget_set_sensitive( button0, FALSE );
214 g_signal_connect( G_OBJECT( button0 ), "clicked",
215 G_CALLBACK( reset_cb ), button );
216 gtk_container_add( GTK_CONTAINER( hBox0 ), button0 );
218 gtk_box_pack_start( GTK_BOX( vBoxMain ), hBox0, FALSE, FALSE, 0 );
220 gtk_container_add( GTK_CONTAINER( window ), vBoxMain );
222 gtk_widget_show_all( window );
224 return GTK_WINDOW( window );
228 static void start_cb( GtkButton* button, gpointer data )
230 if ( stopishMode == STOPISH_MODE_START ) {
231 // set label text and add timer handle
232 gtk_button_set_label( button, "Pause" );
233 stopishMode = STOPISH_MODE_PAUSE;
234 stopish_set_time_start( stopish_current_time( ) );
235 timerHandle = g_timeout_add( 100, stopish_timeout_cb, timerLabel );
237 else if ( stopishMode == STOPISH_MODE_RESUME ) {
239 gtk_button_set_label( button, "Pause" );
240 stopishMode = STOPISH_MODE_PAUSE;
241 stopish_timer_resume( );
242 timerHandle = g_timeout_add( 100, stopish_timeout_cb, timerLabel );
245 // pause timer, remove timeout
246 gtk_button_set_label( button, "Resume" );
247 stopishMode = STOPISH_MODE_RESUME;
248 g_source_remove( timerHandle );
249 stopish_timer_save( );
252 // allow user to reset timer
253 gtk_widget_set_sensitive( GTK_WIDGET( data ), TRUE );
257 static void reset_cb( GtkButton* button, gpointer data )
261 char formatString[128];
263 if ( stopishMode == STOPISH_MODE_RESUME )
264 stopish_timer_resume( );
266 // set label text and remove timer handle
267 gtk_button_set_label( GTK_BUTTON( data ), "Start" );
268 stopishMode = STOPISH_MODE_START;
269 gtk_label_set_markup( GTK_LABEL( timerLabel ),
270 "<span font_family=\"monospace\" "
271 "size=\"70000\" weight=\"ultrabold\">"
272 "00:00:00.0</span>" );
273 g_source_remove( timerHandle );
275 // add current time to history
276 historyList = g_slist_prepend( historyList,
277 ( gpointer ) stopish_get_time_string( ) );
278 sprintf( formatString, "<span size=\"large\">%s</span>",
279 ( char * ) historyList->data );
280 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel1 ),
282 tempList = historyList;
283 tempList = g_slist_next( tempList );
285 gtk_label_set_text( GTK_LABEL( timerHistoryLabel2 ),
286 ( char * ) tempList->data );
288 tempList = g_slist_next( tempList );
290 sprintf( formatString, "<span size=\"small\">%s</span>",
291 ( char * ) tempList->data );
292 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel3 ),
295 tempList = g_slist_next( tempList );
297 sprintf( formatString, "<span size=\"x-small\">%s</span>",
298 ( char * ) tempList->data );
299 gtk_label_set_markup( GTK_LABEL( timerHistoryLabel4 ),
303 // remove the history time after the 4th
304 tempList = g_slist_next( tempList );
306 tempString = tempList->data;
307 historyList = g_slist_remove( historyList, tempList->data );
312 stopish_set_time_start( 0 );
314 // disallow user to reset timer
315 gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE );
319 static void close_cb( GtkButton* button, gpointer data )
321 // disable accelerometer for battery savings
322 accelerometer_disable( );
324 // destroy main window and exit gtk main loop
325 gtk_widget_destroy( GTK_WIDGET( data ) );
330 static gboolean focus_in_cb( GtkWidget *widget, GdkEventFocus *event,
333 // enable accelerometer hardware for portrait mode support
334 accelerometer_enable( );
340 static gboolean focus_out_cb( GtkWidget *widget, GdkEventFocus *event,
343 // disable accelerometer for battery savings
344 accelerometer_disable( );
350 static void accelerometer_enable( void )
352 if ( osso_rpc_run_system( appdata.osso_context, MCE_SERVICE,
353 MCE_REQUEST_PATH, MCE_REQUEST_IF,
354 "req_accelerometer_enable", NULL,
355 DBUS_TYPE_INVALID ) != OSSO_OK ) {
356 g_printerr("WARN: Cannot enable accelerometers\n");
361 static void accelerometer_disable( void )
363 if ( osso_rpc_run_system( appdata.osso_context, MCE_SERVICE,
364 MCE_REQUEST_PATH, MCE_REQUEST_IF,
365 "req_accelerometer_disable", NULL,
366 DBUS_TYPE_INVALID ) != OSSO_OK ) {
367 g_printerr("WARN: Cannot disable accelerometers\n");
372 static DBusHandlerResult mce_filter_func( DBusConnection * connection,
373 DBusMessage * message,
376 DBusMessageIter iter;
377 char *rotation = NULL;
379 if ( dbus_message_is_signal( message, MCE_SIGNAL_IF,
380 MCE_DEVICE_ORIENTATION_SIG ) ) {
381 // here if we received an orientation dbus signal
382 if ( dbus_message_iter_init( message, &iter ) ) {
383 dbus_message_iter_get_basic( &iter, &rotation );
385 // Rotate main window
386 if ( !strcmp( rotation, MCE_ORIENTATION_PORTRAIT ) ) {
387 hildon_gtk_window_set_portrait_flags( GTK_WINDOW( appdata.main_window ),
388 HILDON_PORTRAIT_MODE_REQUEST );
389 gtk_widget_set_size_request( timerLabel, 400, -1 );
392 hildon_gtk_window_set_portrait_flags( GTK_WINDOW( appdata.main_window ),
393 ~HILDON_PORTRAIT_MODE_REQUEST );
394 gtk_widget_set_size_request( timerLabel, 700, -1 );
398 g_printerr( "ERROR: dbus_message_iter_init() failed.\n" );
401 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;