X-Git-Url: http://gitweb.hugovil.com/?a=blobdiff_plain;f=src%2Fwmnotify.c;h=8847a24af7fad7db68362a45951813ceb8c02081;hb=a6c4c0c8d8224cdc455f0d184e91d0cf881f0077;hp=b2c7b272e88c753cb4f180d92136a64ddeb022f1;hpb=36eddd2c06ce9b09c83102353deb213e065e901d;p=dockapps%2Fwmnotify.git diff --git a/src/wmnotify.c b/src/wmnotify.c index b2c7b27..8847a24 100644 --- a/src/wmnotify.c +++ b/src/wmnotify.c @@ -53,416 +53,450 @@ #include "wmnotify.h" -/* Set in DoubleClick() to stop the new mail animation when the mail client is - opened. */ -static bool animation_stop = false; +/* + * Set in DoubleClick() to stop the new mail animation when the mail client is + * opened. + */ +static bool animation_stop; static int animation_image = MAILBOX_FULL; -/* Set in response to signal sent by SingleClick() to force mail check. Also set to true at - * startup to force initial check. */ +/* + * Set in response to signal sent by SingleClick() to force mail check. Also set + * to true at startup to force initial check. + */ static bool manual_check = true; /* Used to signal TimerThread to quit. Inactive for now. */ -static bool quit = false; +static bool quit; -static int double_click_notif = false; +static int double_click_notif; /* TimerThread ID */ static pthread_t timer_thread; -inline void -ErrorLocation( const char *file, int line ) +inline void ErrorLocation(const char *file, int line) { - fprintf( stderr, " Error in file \"%s\" at line #%d\n", file, line ); + fprintf(stderr, " Error in file \"%s\" at line #%d\n", file, + line); } -void * -xmalloc( size_t size, const char *filename, int line_number ) +void *xmalloc(size_t size, const char *filename, int line_number) { - void *value; + void *value; - value = malloc( size ); - - if( value == NULL ) { - perror( PACKAGE ); - ErrorLocation( filename, line_number ); - exit( EXIT_FAILURE ); - } + value = malloc(size); - return value; + if (value == NULL) { + perror(PACKAGE); + ErrorLocation(filename, line_number); + exit(EXIT_FAILURE); + } + + return value; } -static void -DisplayOpenedEmptyMailbox( void ) +static void DisplayOpenedEmptyMailbox(void) { - /* Opened and empty mailbox image */ - copyXPMArea( MAILBOX_OPENED_EMPTY_SRC_X, MAILBOX_OPENED_EMPTY_SRC_Y, - MAILBOX_SIZE_X, MAILBOX_SIZE_Y, MAILBOX_DEST_X, MAILBOX_DEST_Y ); - RedrawWindow(); + /* Opened and empty mailbox image */ + copyXPMArea(MAILBOX_OPENED_EMPTY_SRC_X, MAILBOX_OPENED_EMPTY_SRC_Y, + MAILBOX_SIZE_X, MAILBOX_SIZE_Y, MAILBOX_DEST_X, + MAILBOX_DEST_Y); + RedrawWindow(); } -static void -DisplayOpenedFullMailbox( void ) +static void DisplayOpenedFullMailbox(void) { - /* Full mailbox image */ - copyXPMArea( MAILBOX_OPENED_FULL_SRC_X, MAILBOX_OPENED_FULL_SRC_Y, - MAILBOX_SIZE_X, MAILBOX_SIZE_Y, - MAILBOX_DEST_X, MAILBOX_DEST_Y ); - RedrawWindow(); + /* Full mailbox image */ + copyXPMArea(MAILBOX_OPENED_FULL_SRC_X, MAILBOX_OPENED_FULL_SRC_Y, + MAILBOX_SIZE_X, MAILBOX_SIZE_Y, + MAILBOX_DEST_X, MAILBOX_DEST_Y); + RedrawWindow(); } -static void -DisplayClosedMailbox( void ) +static void DisplayClosedMailbox(void) { - /* Opened mailbox image */ - copyXPMArea( MAILBOX_CLOSED_SRC_X, MAILBOX_CLOSED_SRC_Y, - MAILBOX_SIZE_X, MAILBOX_SIZE_Y, - MAILBOX_DEST_X, MAILBOX_DEST_Y ); - RedrawWindow(); + /* Opened mailbox image */ + copyXPMArea(MAILBOX_CLOSED_SRC_X, MAILBOX_CLOSED_SRC_Y, + MAILBOX_SIZE_X, MAILBOX_SIZE_Y, + MAILBOX_DEST_X, MAILBOX_DEST_Y); + RedrawWindow(); } -static void -DisplayExecuteCommandNotification( void ) +static void DisplayExecuteCommandNotification(void) { - /* Visual notification that the double-click was catched. */ - copyXPMArea( EXEC_CMD_IMG_SRC_X, EXEC_CMD_IMG_SRC_Y, - MAILBOX_SIZE_X, MAILBOX_SIZE_Y, MAILBOX_DEST_X, MAILBOX_DEST_Y ); - RedrawWindow(); + /* Visual notification that the double-click was catched. */ + copyXPMArea(EXEC_CMD_IMG_SRC_X, EXEC_CMD_IMG_SRC_Y, + MAILBOX_SIZE_X, MAILBOX_SIZE_Y, MAILBOX_DEST_X, + MAILBOX_DEST_Y); + RedrawWindow(); } -static void -ExecuteCommand( char *argv[] ) +static void ExecuteCommand(char *argv[]) { - pid_t pid; - char *msg; - - /* No command defined, this is not an error. */ - if( argv[0] == NULL ) { - return; - } - - pid = fork(); /* fork a child process. */ - - if( pid < 0) { - perror( PACKAGE ); - ErrorLocation( __FILE__, __LINE__ ); - exit( EXIT_FAILURE ); - } - else if( pid == 0 ) { /* Child process */ - /* When execvp() is successful, it doesn't return; otherwise, it returns - -1 and sets errno. */ - (void) execvp( argv[0], argv ); - - msg = strerror( errno ); - fprintf( stderr, "%s: The external mail program couldn't be started.\n", - PACKAGE); - fprintf( stderr, "Check your path or your configuration file for errors.\n" - ); - fprintf( stderr, "%s: \"%s\"\n", msg, argv[0] ); - exit( EXIT_FAILURE ); - } + pid_t pid; + char *msg; + + /* No command defined, this is not an error. */ + if (argv[0] == NULL) + return; + + pid = fork(); /* fork a child process. */ + + if (pid < 0) { + perror(PACKAGE); + ErrorLocation(__FILE__, __LINE__); + exit(EXIT_FAILURE); + } else if (pid == 0) { /* Child process */ + /* + * When execvp() is successful, it doesn't return; otherwise, it + * returns -1 and sets errno. + */ + (void) execvp(argv[0], argv); + + msg = strerror(errno); + fprintf(stderr, + "%s: The external mail program couldn't be started.\n", + PACKAGE); + fprintf(stderr, + "Check your path or your configuration file for errors.\n"); + fprintf(stderr, "%s: \"%s\"\n", msg, argv[0]); + exit(EXIT_FAILURE); + } } /* single-click --> Checking mail */ -static void -SingleClick( void ) +static void SingleClick(void) { - int status; - - if( wmnotify_infos.debug ) { - printf( "%s: SingleClick() Entry\n", PACKAGE ); - } - - /* Sending a signal to awake the TimerThread() thread. */ - status = pthread_kill( timer_thread, SIGUSR1 ); - if( status != EXIT_SUCCESS ) { - fprintf( stderr, "%s: pthread_kill() error (%d)\n", PACKAGE, status ); - ErrorLocation( __FILE__, __LINE__ ); - exit( EXIT_FAILURE ); - } - - if( wmnotify_infos.debug ) { - printf( "%s: SingleClick() Exit\n", PACKAGE ); - } + int status; + + if (wmnotify_infos.debug) + printf("%s: SingleClick() Entry\n", PACKAGE); + + /* Sending a signal to awake the TimerThread() thread. */ + status = pthread_kill(timer_thread, SIGUSR1); + if (status != EXIT_SUCCESS) { + fprintf(stderr, "%s: pthread_kill() error (%d)\n", PACKAGE, + status); + ErrorLocation(__FILE__, __LINE__); + exit(EXIT_FAILURE); + } + + if (wmnotify_infos.debug) + printf("%s: SingleClick() Exit\n", PACKAGE); } /* Double-click --> Starting external mail client. */ -static void -DoubleClick( void ) +static void DoubleClick(void) { - int status; - - if( wmnotify_infos.mail_client_argv[0] != NULL ) { - /* Starting external mail client. */ - ExecuteCommand( wmnotify_infos.mail_client_argv ); - - double_click_notif = true; - - /* Sending a signal to awake the TimerThread() thread. This was previously - done with a mutex variable (animation_stop), but this caused a bug when the - following sequence was encountered: - -The user double-click to start the external mail client - -A new E-mail is received shortly after that - -The user exit the external mail client - -The user manually check for new E-mail - -The audio notification sound is played, but no animation image is - displayed. - This was because setting the mutex variable 'animation_stop' didn't - awakened the TimerThread(), but single-clicking awakened it. Since the - 'animation_stop' variable was still set to true, no animation occured. */ - status = pthread_kill( timer_thread, SIGUSR2 ); - if( status != EXIT_SUCCESS ) { - fprintf( stderr, "%s: pthread_kill() error (%d)\n", PACKAGE, status ); - ErrorLocation( __FILE__, __LINE__ ); - exit( EXIT_FAILURE ); - } - - DisplayExecuteCommandNotification(); - sleep(1); - DisplayClosedMailbox(); - - double_click_notif = false; - } - else { - fprintf( stderr, "%s: Warning: No email-client defined.\n", PACKAGE ); - } + int status; + + if (wmnotify_infos.mail_client_argv[0] != NULL) { + /* Starting external mail client. */ + ExecuteCommand(wmnotify_infos.mail_client_argv); + + double_click_notif = true; + + /* + * Sending a signal to awake the TimerThread() thread. This was + * previously done with a mutex variable (animation_stop), but + * this caused a bug when the following sequence was + * encountered: + * -The user double-click to start the external mail client + * -A new E-mail is received shortly after that + * -The user exit the external mail client + * -The user manually check for new E-mail + * -The audio notification sound is played, but no animation + * image is displayed. + * This was because setting the mutex variable 'animation_stop' + * didn't awakened the TimerThread(), but single-clicking + * awakened it. Since the 'animation_stop' variable was still + * set to true, no animation occured. + */ + status = pthread_kill(timer_thread, SIGUSR2); + if (status != EXIT_SUCCESS) { + fprintf(stderr, "%s: pthread_kill() error (%d)\n", + PACKAGE, status); + ErrorLocation(__FILE__, __LINE__); + exit(EXIT_FAILURE); + } + + DisplayExecuteCommandNotification(); + sleep(1); + DisplayClosedMailbox(); + + double_click_notif = false; + } else { + fprintf(stderr, "%s: Warning: No email-client defined.\n", + PACKAGE); + } } -static void -CatchChildTerminationSignal( int signal ) +static void CatchChildTerminationSignal(int signal) { - switch( signal ) { - case SIGCHLD: - /* Wait for Mail Client child process termination. Child enters zombie - state: process is dead and most resources are released, but process - descriptor remains until parent reaps exit status via wait. */ - - /* The WNOHANG option prevents the call to waitpid from suspending execution - of the caller. */ - (void) waitpid( 0, NULL, WNOHANG ); - break; - default: - fprintf( stderr, "%s: Unregistered signal received, exiting.\n", PACKAGE ); - exit( EXIT_FAILURE ); - } + switch (signal) { + case SIGCHLD: + /* + * Wait for Mail Client child process termination. Child enters + * zombie state: process is dead and most resources are + * released, but process descriptor remains until parent reaps + * exit status via wait. + */ + + /* + * The WNOHANG option prevents the call to waitpid from + * suspending execution of the caller. + */ + (void) waitpid(0, NULL, WNOHANG); + break; + default: + fprintf(stderr, + "%s: Unregistered signal received, exiting.\n", + PACKAGE); + exit(EXIT_FAILURE); + } } -static void -CatchTimerSignal( int signal ) +static void CatchTimerSignal(int signal) { - switch( signal ) { - case SIGUSR1: - /* Catching the signal sent by the SingleClick() function. */ - manual_check = true; - break; - case SIGUSR2: - /* Catching the signal sent by the DoubleClick() function. */ - animation_stop = true; - break; - default: - fprintf( stderr, "%s: CatchTimerSignal(): unknown signal (%d)\n", PACKAGE, - signal ); - ErrorLocation( __FILE__, __LINE__ ); - exit( EXIT_FAILURE ); - } + switch (signal) { + case SIGUSR1: + /* Catching the signal sent by the SingleClick() function. */ + manual_check = true; + break; + case SIGUSR2: + /* Catching the signal sent by the DoubleClick() function. */ + animation_stop = true; + break; + default: + fprintf(stderr, + "%s: CatchTimerSignal(): unknown signal (%d)\n", + PACKAGE, signal); + ErrorLocation(__FILE__, __LINE__); + exit(EXIT_FAILURE); + } } -static void -NewMailAnimation( void ) +static void NewMailAnimation(void) { - if( animation_image == MAILBOX_FULL ) { - DisplayOpenedFullMailbox(); - animation_image = MAILBOX_CLOSED; - if( wmnotify_infos.debug ) { - printf( "%s: NewMailAnimation() MAILBOX_FULL.\n", PACKAGE ); - } - } - else { - DisplayClosedMailbox(); - animation_image = MAILBOX_FULL; - if( wmnotify_infos.debug ) { - printf( "%s: NewMailAnimation() MAILBOX_CLOSED.\n", PACKAGE ); - } - } + if (animation_image == MAILBOX_FULL) { + DisplayOpenedFullMailbox(); + animation_image = MAILBOX_CLOSED; + if (wmnotify_infos.debug) { + printf("%s: NewMailAnimation() MAILBOX_FULL.\n", + PACKAGE); + } + } else { + DisplayClosedMailbox(); + animation_image = MAILBOX_FULL; + if (wmnotify_infos.debug) { + printf("%s: NewMailAnimation() MAILBOX_CLOSED.\n", + PACKAGE); + } + } } /* We display the opened mailbox image only when doing a manual check. */ -static int -CheckForNewMail( bool manual_check ) +static int CheckForNewMail(bool manual_check) { - int new_messages; - - if( manual_check == true ) { - DisplayOpenedEmptyMailbox(); - } - - if( wmnotify_infos.protocol == POP3_PROTOCOL ) { - new_messages = POP3_CheckForNewMail(); - } - else if( wmnotify_infos.protocol == IMAP4_PROTOCOL ) { - new_messages = IMAP4_CheckForNewMail(); - } - else { - ErrorLocation( __FILE__, __LINE__ ); - exit( EXIT_FAILURE ); - } - - if( ( manual_check == true ) && ( new_messages > 0 ) ) { - animation_image = MAILBOX_FULL; - } - - return new_messages; -} + int new_messages; + + if (manual_check == true) + DisplayOpenedEmptyMailbox(); + + if (wmnotify_infos.protocol == POP3_PROTOCOL) { + new_messages = POP3_CheckForNewMail(); + } else if (wmnotify_infos.protocol == IMAP4_PROTOCOL) { + new_messages = IMAP4_CheckForNewMail(); + } else { + ErrorLocation(__FILE__, __LINE__); + exit(EXIT_FAILURE); + } + if ((manual_check == true) && (new_messages > 0)) + animation_image = MAILBOX_FULL; + + return new_messages; +} -static void * -TimerThread( /*@unused@*/ void *arg ) +static void check_audio_notification(bool *animation_running) { - int new_messages = 0; - int counter = -1; - bool animation_running = false; - - /* For catching the signal SIGUSR1. This signal is sent by the main program thread when the - * user is issuing a single-click to manually check for new mails. */ - (void) signal( SIGUSR1, CatchTimerSignal ); - - /* For catching the signal SIGUSR2. This signal is sent by the main program thread when the - * user is issuing a double-click to start ther external mail client. */ - (void) signal( SIGUSR2, CatchTimerSignal ); - - while( quit == false ) { - if( wmnotify_infos.debug ) { - printf( "%s: Timer thread iteration.\n", PACKAGE ); - } - if( ( manual_check == true ) || ( counter == 0 ) ) { - new_messages = CheckForNewMail( manual_check ); - manual_check = false; - - if( wmnotify_infos.debug ) { - printf( "%s: new messages = %d.\n", PACKAGE, new_messages ); - } - - if( new_messages > 0 ) { - /* Checking if audio notification was already produced. */ - if( animation_running == false ) { - /* Audible notification, if requested in configuration file. */ - if( wmnotify_infos.audible_notification != false ) { - if( strlen( wmnotify_infos.audiofile ) != 0 ) { + /* + * Checking if audio notification was already + * produced. + */ + if (*animation_running == false) { + /* Audible notification, if requested in configuration file. */ + if (wmnotify_infos.audible_notification) { + if (strlen(wmnotify_infos.audiofile) != 0) { #if defined(HAVE_SNDFILE) - PlayAudioFile( wmnotify_infos.audiofile, wmnotify_infos.volume ); + PlayAudioFile(wmnotify_infos.audiofile, + wmnotify_infos.volume); #endif - } - else { - AudibleBeep(); - } - } - - animation_running = true; - } - /* Number of times to execute timer loop before checking again for new mails when the - * animation is running (when the animation is running, we sleep for - * NEW_MAIL_ANIMATION_DURATION instead of wmnotify_infos.mail_check_interval). We set - * the check interval to 30 seconds because we want the new mail condition to be - * removed as soon as possible when the new messages are checked. */ - counter = 30 * 1000000 / NEW_MAIL_ANIMATION_DURATION; - } - } - - if( ( animation_stop == true ) || ( new_messages <= 0 ) ) { - if( wmnotify_infos.debug ) { - if( animation_stop != false ) { - printf( "%s: animation_stop is true\n", PACKAGE ); + } else { + AudibleBeep(); + } + } + + *animation_running = true; } - } - animation_running = false; - animation_stop = false; - if( double_click_notif == false ) { - /* Before exiting, be sure to put NO MAIL image back in place... */ - DisplayClosedMailbox(); - } - } - - /* If sleep() returns because the requested time has elapsed, the value returned will be - * 0. If sleep() returns because of premature arousal due to delivery of a signal, the - * return value will be the "unslept" amount (the requested time minus the time actually - * slept) in seconds. */ - - if( animation_running == false ) { - (void) sleep( wmnotify_infos.mail_check_interval ); - counter = 0; - } - else { - NewMailAnimation(); - (void) usleep( NEW_MAIL_ANIMATION_DURATION ); - counter--; - } - - if( wmnotify_infos.debug ) { - printf( "%s: counter = %d\n", PACKAGE, counter ); - } - } /* end while */ - - if( wmnotify_infos.debug ) { - printf( "%s: Error, TimerThread() exited abnormally\n", PACKAGE ); - } - - /* This code is never reached for now, because quit is always false. */ - pthread_exit( NULL ); +} + +static void *TimerThread(void *arg) +{ + int new_messages = 0; + int counter = -1; + bool animation_running = false; + + /* + * For catching the signal SIGUSR1. This signal is sent by the main + * program thread when the user is issuing a single-click to manually + * check for new mails. + */ + (void) signal(SIGUSR1, CatchTimerSignal); + + /* + * For catching the signal SIGUSR2. This signal is sent by the main + * program thread when the user is issuing a double-click to start their + * external mail client. + */ + (void) signal(SIGUSR2, CatchTimerSignal); + + while (quit == false) { + if (wmnotify_infos.debug) + printf("%s: Timer thread iteration.\n", PACKAGE); + + if ((manual_check == true) || (counter == 0)) { + new_messages = CheckForNewMail(manual_check); + manual_check = false; + + if (wmnotify_infos.debug) { + printf("%s: new messages = %d.\n", PACKAGE, + new_messages); + } + + if (new_messages > 0) { + check_audio_notification(&animation_running); + + /* + * Number of times to execute timer loop before + * checking again for new mails when the + * animation is running (when the animation is + * running, we sleep for + * NEW_MAIL_ANIMATION_DURATION instead of + * wmnotify_infos.mail_check_interval). We set + * the check interval to 30 seconds because we + * want the new mail condition to be removed as + * soon as possible when the new messages are + * checked. + */ + counter = 30 * 1000000 / + NEW_MAIL_ANIMATION_DURATION; + } + } + + if ((animation_stop == true) || (new_messages <= 0)) { + if (wmnotify_infos.debug) { + if (animation_stop != false) { + printf + ("%s: animation_stop is true\n", + PACKAGE); + } + } + animation_running = false; + animation_stop = false; + if (double_click_notif == false) { + /* + * Before exiting, be sure to put NO MAIL image + * back in place. + */ + DisplayClosedMailbox(); + } + } + + /* + * If sleep() returns because the requested time has elapsed, + * the value returned will be 0. If sleep() returns because of + * premature arousal due to delivery of a signal, the return + * value will be the "unslept" amount (the requested time minus + * the time actually slept) in seconds. + */ + if (animation_running == false) { + (void) sleep(wmnotify_infos.mail_check_interval); + counter = 0; + } else { + NewMailAnimation(); + (void) usleep(NEW_MAIL_ANIMATION_DURATION); + counter--; + } + + if (wmnotify_infos.debug) + printf("%s: counter = %d\n", PACKAGE, counter); + } /* end while */ + + if (wmnotify_infos.debug) + printf("%s: Error, TimerThread() exited abnormally\n", PACKAGE); + + /* This code is never reached for now, because quit is always false. */ + pthread_exit(NULL); } /******************************************************************************* * Main function ******************************************************************************/ -int -main( int argc, char *argv[] ) +int main(int argc, char *argv[]) { - int status; - - /* Initialization */ - ParseCommandLineOptions( argc, argv ); - - /* Reading configuration options from configuration file. */ - ConfigurationFileInit(); - - /* For catching the termination signal SIGCHLD when the external mail client - program is terminated, thus permitting removing zombi processes... */ - (void) signal( SIGCHLD, CatchChildTerminationSignal ); - - /* Initialize callback function pointers. */ - ProcessXlibEventsInit( SingleClick, DoubleClick ); - - /* Initializing and creating a DockApp window. */ - InitDockAppWindow( argc, argv, wmnotify_xpm, wmnotify_infos.display_arg, - wmnotify_infos.geometry_arg ); - - /* Starting thread for periodically checking for new mail. */ - status = pthread_create( &timer_thread, NULL, TimerThread, NULL ); - if( status != 0 ) { - fprintf( stderr, "%s: Thread creation failed (%d)\n", PACKAGE, status ); - ErrorLocation( __FILE__, __LINE__ ); - exit( EXIT_FAILURE ); - } - - /* Main loop, processing X Events */ - ProcessXlibEvents(); - - /* This code is never reached for now. */ - fprintf( stderr, "%s: Program exit\n", PACKAGE ); - - exit( EXIT_SUCCESS ); + int status; + + /* Initialization */ + ParseCommandLineOptions(argc, argv); + + /* Reading configuration options from configuration file. */ + ConfigurationFileInit(); + + /* + * For catching the termination signal SIGCHLD when the external mail + * client program is terminated, thus permitting removing zombi + * processes... + */ + (void) signal(SIGCHLD, CatchChildTerminationSignal); + + /* Initialize callback function pointers. */ + ProcessXlibEventsInit(SingleClick, DoubleClick); + + /* Initializing and creating a DockApp window. */ + InitDockAppWindow(argc, argv, wmnotify_xpm, + wmnotify_infos.display_arg, + wmnotify_infos.geometry_arg); + + /* Starting thread for periodically checking for new mail. */ + status = pthread_create(&timer_thread, NULL, TimerThread, NULL); + if (status != 0) { + fprintf(stderr, "%s: Thread creation failed (%d)\n", + PACKAGE, status); + ErrorLocation(__FILE__, __LINE__); + exit(EXIT_FAILURE); + } + + /* Main loop, processing X Events */ + ProcessXlibEvents(); + + /* This code is never reached for now. */ + fprintf(stderr, "%s: Program exit\n", PACKAGE); + + exit(EXIT_SUCCESS); }