int main(int argc, char* argv[]) {
    parse_options(argc, argv);
    // Daemonize, unless we're passed -d
    if(daemonize) {
	pid_t pid = fork();
	if(pid < 0) {
	    fprintf(stderr, "Fork failed with %d\n", pid);
	} else if(pid > 0) {
	    return EXIT_SUCCESS; // child has forked off correctly, we terminate immediately.
	}
    }

    // we will be sent a USR1 by acpid when the power adapter is plugged/unplugged. at that point we reread its state.
    // this approach saves us from having to poll that every few seconds to see if it's changed
    // (one of the few places where it's practical to avoid polling)
    signal(SIGUSR1, refresh_adapter_state);

    XScreenSaverInfo* info = XScreenSaverAllocInfo();
    info->idle = 0; // ensure this is initialised since we'll calculate on it shortly
    Display* display = XOpenDisplay(0);
    if(display == NULL) {
        fprintf(stderr, "Couldn't connect to X display\n");
        return EXIT_FAILURE;
    }

    // do some initial updates to make sure everything's been read at first
    // this will set the initial brightness values for us as well
    refresh_adapter_state();
    update_light_sensor();

    // NB. ideally we would use select() or something to wait for the applesmc sysfs entry
    //     to change, but it doesn't seem to work. Not sure that's possible on this kind of hardware sensor?

    while(1) {
        // we've just gone idle. wait in 2 second chunks to keep checking the light sensor
        int i;
	for(i = 0; i < time_before_dim * 1000 - info->idle; i += 2000) {
	    sleep(2);
	    update_light_sensor();
	    dprintf("Time until dimming planned to begin: %ld\n", time_before_dim - info->idle/1000 - i/1000);
	}
	// now check the idle time again
        XScreenSaverQueryInfo(display, DefaultRootWindow(display), info);
	if(info->idle < time_before_dim*1000) {
	    // we must have been woken in between. go back to waiting.
	    continue;
	}

	// here we have waited the requisite amount of time. dim the display.
	dprintf("Dimming display\n");
	if(!continuous_dim_backlight(display, info)) {
	    wait_for_event(display, info);
	}
	// once we get here, we are undimming because something's happened
	is_dimmed = 0;
	adjust_brightness(1.0);
    }
}
void property_update(void *inContext)
{
  int num = 0;
  app_context_t * app_context = (app_context_t*)inContext;
  
  while(1)
  {
    mico_thread_sleep(1);
    if(!app_context->appStatus.arrayentStatus.isCloudConnected){
      continue;
    }
    
    switch(num)
    {
    case 0:
      update_dht11_sensor();
      break;
    case 1:
      update_light_sensor();
      break;
    case 2:
      update_infrared_sensor();
      break;
    }
    num++;
    if(num == 3)num = 0;
  }
}
void update_property(void *inContext){
  int num = 0;
  while(1)
  {
    switch(num)
    {
    case 0:
      update_dht11_sensor();
      break;
    case 1:
      update_light_sensor();
      break;
    case 2:
      update_infrared_sensor();
      break;
    }
    num++;
    if(num == 3)num = 0;
  }
}
// Waits until the user moves mouse or presses a key
void wait_for_event(Display* display, XScreenSaverInfo* info) {
    // waiting until something happens
    // currently just doing polling, not sure how possible it is to get notified of this event by X
    // it's not hard to get mouse/keyboard events for your window but I don't think you can get *any* such event
    // TODO: is there a different approach? could we hook into devices in /dev or something? may not be worth going down that rabbit hole though...
    struct timespec tm_remaining = { 0, 0 };
    struct timespec half_second = { 0, 500000000 }; // this is about the longest period that still feels reasonably responsive when undimming the screen
    unsigned long last_idle;
    int locked_screen = 0;
    do {
        last_idle = info->idle;
        nanosleep(&half_second, &tm_remaining);
        XScreenSaverQueryInfo(display, DefaultRootWindow(display), info);
	update_light_sensor();

	// now lock screen if we've gone over the threshold - but obviously only the first time
	// slimlock checks itself if it's already running, but we don't want to spawn new slimlock
	// processes every second if they're not going to do anything!
	if(!locked_screen && info->idle >= lock_delay_ms) {
	    lock_screen();
	    locked_screen = 1;
	}
    } while(info->idle >= last_idle);
}