#include #include #include #include #include #include #include #include #include #include #include #include #include #include struct status{ Display *dpy; Window root; char status[256]; const char *time_format; unsigned int status_update_interval; }; struct sigaction *s_act = NULL; struct status *current_status_ptr = NULL; XTextProperty *status_props_ptr = NULL; void sighandler( int si_code, siginfo_t *si_info, void *si_adr ){ int exit_status = EXIT_SUCCESS; if ( si_code == SIGSEGV ){ fprintf( stderr, "error: SIGSEGV received: %s\n", strerror(errno) ); exit_status = EXIT_FAILURE; } else { fprintf( stdout, "Received signal %i, exiting\n", si_code ); } if ( current_status_ptr->dpy != NULL ){ if ( XCloseDisplay(current_status_ptr->dpy) == BadGC ) fputs( "XCloseDisplay returned BadGC error\n", stderr ); current_status_ptr->dpy = NULL; } memset( (void*)status_props_ptr, 0, sizeof(*status_props_ptr) ); free( s_act ); s_act = NULL; exit( exit_status ); } void update_status( struct status *status_info, XTextProperty *xprops ){ if ( status_info == NULL || xprops == NULL ) return; XSetTextProperty( status_info->dpy, status_info->root, xprops, XA_WM_NAME ); XSync( status_info->dpy, 0 ); return; } void status_update_loop( struct status *cstatus, XTextProperty *status_properties ){ if ( cstatus == NULL || status_properties == NULL ){ fputs( "error: status struct pointer is NULL\n", stderr ); return; } time_t current_time = 0; struct tm *time_info = NULL; while ( 1 ){ memset( (void*)&cstatus->status, 0, sizeof(cstatus->status) * sizeof(char) ); current_time = time( NULL ); time_info = localtime( (const time_t*)¤t_time ); if ( (status_properties->nitems = (unsigned long)strftime((char*)&cstatus->status, (sizeof(cstatus->status) * sizeof(char)) - 1, cstatus->time_format, time_info)) <= 0 ){ sleep( cstatus->status_update_interval ); continue; } update_status( cstatus, status_properties ); sleep( cstatus->status_update_interval ); } return; } int main( int argc, char **args ){ if ( argc < 5 ){ fprintf( stdout, "Usage: %s -i [update interval in seconds] -d [display] -f [time format]\n", args[0] ); exit( EXIT_SUCCESS ); } s_act = (struct sigaction*)calloc( 1, sizeof(struct sigaction) ); if ( s_act == NULL ){ perror( "sigaction struct allocation failed" ); exit( EXIT_FAILURE ); } if ( sigemptyset(&s_act->sa_mask) == -1 ){ perror( "failed to create empty sigset" ); free( s_act ); exit( EXIT_FAILURE ); } s_act->sa_flags = SA_SIGINFO; s_act->sa_sigaction = &sighandler; if ( sigaction(SIGABRT, (const struct sigaction*)s_act, NULL) == -1 ){ perror( "failed to set SIGABRT handler" ); free( s_act ); exit( EXIT_FAILURE ); } assert( sigaction(SIGSEGV, (const struct sigaction*)s_act, NULL) != -1 ); assert( sigaction(SIGINT, (const struct sigaction*)s_act, NULL) != -1 ); assert( sigaction(SIGTERM, (const struct sigaction*)s_act, NULL) != -1 ); assert( sigaction(SIGPIPE, (const struct sigaction*)s_act, NULL) != -1 ); struct status current_status = {0}; memset( (void*)¤t_status, 0, sizeof(struct status) ); XTextProperty status_props = { .value = (unsigned char*)¤t_status.status, .encoding = XA_STRING, .format = 8, .nitems = 0 }; const char *optstring = "i:d:f:"; int opt_char = 0; while ( (opt_char = getopt(argc, args, optstring)) != -1 ){ switch (opt_char){ case 'i': current_status.status_update_interval = (unsigned int)strtoull( optarg, NULL, 10 ); assert( errno == 0 ); break; case 'd': current_status.dpy = XOpenDisplay( (_Xconst char*)optarg ); assert( current_status.dpy != NULL ); break; case 'f': current_status.time_format = (const char*)optarg; assert( current_status.time_format != NULL && strlen(current_status.time_format) > 0 ); break; default: break; } } current_status.root = DefaultRootWindow( current_status.dpy ); current_status_ptr = ¤t_status; status_props_ptr = &status_props; status_update_loop( ¤t_status, &status_props ); exit( EXIT_SUCCESS ); }