/* ARGSUSED */ static void new_time (XtPointer client_data, XtIntervalId *id) { ClockWidget w = (ClockWidget)client_data; Time_t now; struct tm *tm; if (!w->clock.transparent) if (w->clock.polys_valid) { paint_hands (w, XtWindow (w), w->clock.eraseGC, w->clock.eraseGC); check_jewel (w, XtWindow (w), w->clock.jewelGC); } (void) time (&now); tm = localtime (&now); if (tm->tm_hour >= 12) tm->tm_hour -= 12; w->clock.hour_angle = clock_to_angle ((((double) tm->tm_hour) + ((double) tm->tm_min) / 60.0) / 12.0); w->clock.minute_angle = clock_to_angle (((double) tm->tm_min) / 60.0); /* * add the timeout before painting the hands, that may * take a while and we'd like the clock to keep up * with time changes. */ w->clock.interval_id = XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w), (60 - tm->tm_sec) * 1000, new_time, client_data); compute_hands (w); if (w->clock.transparent) Resize ((Widget)w); else paint_hands (w, XtWindow (w), w->clock.minuteGC, w->clock.hourGC); } /* new_time */
void update_hands(PblTm *time) { struct HandPlacement new_placement; compute_hands(time, &new_placement); if (new_placement.hour_hand_index != current_placement.hour_hand_index) { current_placement.hour_hand_index = new_placement.hour_hand_index; layer_mark_dirty(&hour_layer); } if (new_placement.minute_hand_index != current_placement.minute_hand_index) { current_placement.minute_hand_index = new_placement.minute_hand_index; layer_mark_dirty(&minute_layer); } #ifdef SHOW_SECOND_HAND if (new_placement.second_hand_index != current_placement.second_hand_index) { current_placement.second_hand_index = new_placement.second_hand_index; layer_mark_dirty(&second_layer); } #endif // SHOW_SECOND_HAND #ifdef ENABLE_HOUR_BUZZER if (new_placement.hour_buzzer != current_placement.hour_buzzer) { current_placement.hour_buzzer = new_placement.hour_buzzer; vibes_short_pulse(); } #endif #ifdef MAKE_CHRONOGRAPH #ifdef SHOW_CHRONO_MINUTE_HAND if (new_placement.chrono_minute_hand_index != current_placement.chrono_minute_hand_index) { current_placement.chrono_minute_hand_index = new_placement.chrono_minute_hand_index; layer_mark_dirty(&chrono_minute_layer); } #endif // SHOW_CHRONO_MINUTE_HAND #ifdef SHOW_CHRONO_SECOND_HAND if (new_placement.chrono_second_hand_index != current_placement.chrono_second_hand_index) { current_placement.chrono_second_hand_index = new_placement.chrono_second_hand_index; layer_mark_dirty(&chrono_second_layer); } #endif // SHOW_CHRONO_SECOND_HAND #endif // MAKE_CHRONOGRAPH #ifdef SHOW_DAY_CARD if (new_placement.day_index != current_placement.day_index) { current_placement.day_index = new_placement.day_index; layer_mark_dirty(&day_layer); } #endif // SHOW_DAY_CARD #ifdef SHOW_DATE_CARD if (new_placement.date_value != current_placement.date_value) { current_placement.date_value = new_placement.date_value; layer_mark_dirty(&date_layer); } #endif // SHOW_DATE_CARD }
// Called at program start to bootstrap everything. void handle_init() { app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "handle_init"); // Record the fallback font pointer so we can identify if this one // is accidentally returned from fonts_load_custom_font(). fallback_font = fonts_get_system_font(FONT_KEY_FONT_FALLBACK); load_config(); #ifdef MAKE_CHRONOGRAPH load_chrono_data(); #endif // MAKE_CHRONOGRAPH app_message_register_inbox_received(receive_config_handler); app_message_register_inbox_dropped(dropped_config_handler); #define INBOX_MESSAGE_SIZE 200 #define OUTBOX_MESSAGE_SIZE 50 #ifndef NDEBUG uint32_t inbox_max = app_message_inbox_size_maximum(); uint32_t outbox_max = app_message_outbox_size_maximum(); app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "available message space %u, %u", (unsigned int)inbox_max, (unsigned int)outbox_max); if (inbox_max > INBOX_MESSAGE_SIZE) { inbox_max = INBOX_MESSAGE_SIZE; } if (outbox_max > OUTBOX_MESSAGE_SIZE) { outbox_max = OUTBOX_MESSAGE_SIZE; } app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "app_message_open(%u, %u)", (unsigned int)inbox_max, (unsigned int)outbox_max); AppMessageResult open_result = app_message_open(inbox_max, outbox_max); app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "open_result = %d", open_result); #else // NDEBUG app_message_open(INBOX_MESSAGE_SIZE, OUTBOX_MESSAGE_SIZE); #endif // NDEBUG time_t now = time(NULL); struct tm *startup_time = localtime(&now); date_numeric_font = fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD); create_objects(); compute_hands(startup_time, ¤t_placement); apply_config(); }
void handle_init(AppContextRef ctx) { PblTm time; int i; (void)ctx; window_init(&window, WATCH_NAME); window_set_fullscreen(&window, true); window_stack_push(&window, true /* Animated */); get_time(&time); compute_hands(&time, ¤t_placement); resource_init_current_app(&APP_RESOURCES); bmp_init_container(RESOURCE_ID_CLOCK_FACE, &clock_face_container); layer_add_child(&window.layer, &clock_face_container.layer.layer); #ifdef SHOW_DAY_CARD layer_init(&day_layer, GRect(DAY_CARD_X - 15, DAY_CARD_Y - 8, 31, 19)); day_layer.update_proc = &day_layer_update_callback; layer_add_child(&window.layer, &day_layer); #endif // SHOW_DAY_CARD #ifdef SHOW_DATE_CARD layer_init(&date_layer, GRect(DATE_CARD_X - 15, DATE_CARD_Y - 8, 31, 19)); date_layer.update_proc = &date_layer_update_callback; layer_add_child(&window.layer, &date_layer); #endif // SHOW_DATE_CARD // Init all of the hands, taking care to arrange them in the correct // stacking order. for (i = 0; stacking_order[i] != STACKING_ORDER_DONE; ++i) { switch (stacking_order[i]) { case STACKING_ORDER_HOUR: layer_init(&hour_layer, window.layer.frame); hour_layer.update_proc = &hour_layer_update_callback; layer_add_child(&window.layer, &hour_layer); break; case STACKING_ORDER_MINUTE: layer_init(&minute_layer, window.layer.frame); minute_layer.update_proc = &minute_layer_update_callback; layer_add_child(&window.layer, &minute_layer); break; case STACKING_ORDER_SECOND: #ifdef SHOW_SECOND_HAND layer_init(&second_layer, window.layer.frame); second_layer.update_proc = &second_layer_update_callback; layer_add_child(&window.layer, &second_layer); #endif // SHOW_SECOND_HAND break; case STACKING_ORDER_CHRONO_MINUTE: #ifdef SHOW_CHRONO_MINUTE_HAND layer_init(&chrono_minute_layer, window.layer.frame); chrono_minute_layer.update_proc = &chrono_minute_layer_update_callback; layer_add_child(&window.layer, &chrono_minute_layer); #endif // SHOW_CHRONO_MINUTE_HAND break; case STACKING_ORDER_CHRONO_SECOND: #ifdef SHOW_CHRONO_SECOND_HAND layer_init(&chrono_second_layer, window.layer.frame); chrono_second_layer.update_proc = &chrono_second_layer_update_callback; layer_add_child(&window.layer, &chrono_second_layer); #endif // SHOW_CHRONO_SECOND_HAND break; } } #ifdef MAKE_CHRONOGRAPH window_set_click_config_provider(&window, (ClickConfigProvider)stopped_click_config_provider); #endif // MAKE_CHRONOGRAPH }
// Called once per epoch (e.g. once per second, or once per minute) to // compute the new positions for all of the hands on the watch based // on the current time. This does not actually draw the hands; it // only computes which position each hand should hold, and it marks // the appropriate layers dirty, to eventually redraw the hands that // have moved since the last call. void update_hands(struct tm *time) { struct HandPlacement new_placement = current_placement; compute_hands(time, &new_placement); if (new_placement.hour_hand_index != current_placement.hour_hand_index) { current_placement.hour_hand_index = new_placement.hour_hand_index; layer_mark_dirty(hour_layer); } if (new_placement.minute_hand_index != current_placement.minute_hand_index) { current_placement.minute_hand_index = new_placement.minute_hand_index; layer_mark_dirty(minute_layer); } if (new_placement.second_hand_index != current_placement.second_hand_index) { current_placement.second_hand_index = new_placement.second_hand_index; layer_mark_dirty(second_layer); } if (new_placement.hour_buzzer != current_placement.hour_buzzer) { current_placement.hour_buzzer = new_placement.hour_buzzer; if (config.hour_buzzer) { // The hour has changed; ring the buzzer if it's enabled. vibes_short_pulse(); } } // Make sure the sweep timer is fast enough to capture the second // hand. sweep_timer_ms = 1000; if (config.sweep_seconds) { sweep_timer_ms = sweep_seconds_ms; } #ifdef MAKE_CHRONOGRAPH update_chrono_hands(&new_placement); #endif // MAKE_CHRONOGRAPH // If any of the date window properties changes, update all of the // date windows. (We cheat and only check the fastest changing // element, and the date value just in case someone's playing games // with the clock.) if (new_placement.ampm_value != current_placement.ampm_value || new_placement.date_value != current_placement.date_value) { current_placement.day_index = new_placement.day_index; current_placement.month_index = new_placement.month_index; current_placement.date_value = new_placement.date_value; current_placement.year_value = new_placement.year_value; current_placement.ampm_value = new_placement.ampm_value; // Shorthand for the below for loop. This achieves the same thing. layer_mark_dirty(clock_face_layer); /* for (int i = 0; i < NUM_DATE_WINDOWS; ++i) { layer_mark_dirty(date_window_layers[i]); } */ } #ifdef SUPPORT_MOON // Also check the lunar phase, in a separate check from the other // date windows, so it doesn't necessarily have to wait till // midnight to flip over to the next phase. if (new_placement.lunar_phase != current_placement.lunar_phase) { current_placement.lunar_phase = new_placement.lunar_phase; bwd_destroy(&moon_bitmap); layer_mark_dirty(clock_face_layer); } #endif // SUPPORT_MOON }