From 6892b596222bdc5b2c0757a8f6cc79bcf2691d1a Mon Sep 17 00:00:00 2001 From: Frederic Culot Date: Sun, 21 Mar 2010 10:17:03 +0000 Subject: Avoid concurrent screen refreshes. --- src/wins.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 6 deletions(-) (limited to 'src/wins.c') diff --git a/src/wins.c b/src/wins.c index 8cdd9da..cfe1050 100755 --- a/src/wins.c +++ b/src/wins.c @@ -1,4 +1,4 @@ -/* $calcurse: wins.c,v 1.31 2010/03/21 09:21:07 culot Exp $ */ +/* $calcurse: wins.c,v 1.32 2010/03/21 10:17:04 culot Exp $ */ /* * Calcurse - text-based organizer @@ -51,6 +51,74 @@ static unsigned sbarwidth; static enum win slctd_win; static int layout; +/* + * The screen_mutex mutex and wins_refresh(), wins_wrefresh(), wins_doupdate() + * functions are used to prevent concurrent updates of the screen. + * It was observed that the display could get screwed up when mulitple threads + * tried to refresh the screen at the same time. + * + * Note (2010-03-21): + * Since recent versions of ncurses (5.7), rudimentary support for threads are + * available (use_screen(), use_window() for instance - see curs_threads(3)), + * but to remain compatible with earlier versions, it was chosen to rely on a + * screen-level mutex instead. + */ +static pthread_mutex_t screen_mutex = PTHREAD_MUTEX_INITIALIZER; + +static unsigned +screen_acquire (void) +{ + if (pthread_mutex_lock (&screen_mutex) != 0) + return 0; + else + return 1; +} + +static void +screen_release (void) +{ + (void)pthread_mutex_unlock (&screen_mutex); +} + +int +wins_refresh (void) +{ + int rc; + + if (!screen_acquire ()) + return ERR; + rc = refresh (); + screen_release (); + + return rc; +} + +int +wins_wrefresh (WINDOW *win) +{ + int rc; + + if (!win || !screen_acquire ()) + return ERR; + rc = wrefresh (win); + screen_release (); + + return rc; +} + +int +wins_doupdate (void) +{ + int rc; + + if (!screen_acquire ()) + return ERR; + rc = doupdate (); + screen_release (); + + return rc; +} + /* Get the current layout. */ int wins_layout (void) @@ -236,7 +304,7 @@ wins_scrollwin_display (struct scrollwin *sw) wnoutrefresh (sw->win.p); pnoutrefresh (sw->pad.p, sw->first_visible_line, 0, sw->pad.y, sw->pad.x, sw->win.h - sw->pad.y + 1, sw->win.w - sw->win.x); - doupdate (); + wins_doupdate (); } void @@ -520,7 +588,7 @@ wins_update (void) if (notify_bar ()) notify_update_bar (); wmove (win[STA].p, 0, 0); - doupdate (); + wins_doupdate (); } /* Reset the screen, needed when resizing terminal for example. */ @@ -528,7 +596,7 @@ void wins_reset (void) { endwin (); - refresh (); + wins_refresh (); curs_set (0); wins_reinit (); wins_update (); @@ -559,13 +627,13 @@ wins_launch_external (const char *file, const char *cmd) endwin (); ui_mode = UI_CMDLINE; clear (); - refresh (); + wins_refresh (); (void)system (p); reset_prog_mode (); clearok (curscr, TRUE); curs_set (0); ui_mode = UI_CURSES; - refresh (); + wins_refresh (); if (notify_bar ()) notify_start_main_thread (); mem_free (p); -- cgit v1.2.3