/*
elmo - ELectronic Mail Operator
Copyright (C) 2003, 2004 rzyjontko
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
----------------------------------------------------------------------
Discussion:
There are 2 kinds of windows:
1. Windows with non-configurable size and position.
These windows must be refreshed by the interface module on demand.
But you cannot switch to such a window, it cannot take focus.
2. Windows with configurable size.
These are all the windows, that the user would generally consider
as a window. They can be focused, consist of multiple WINDOW
objects and so on.
This module must keep the screen clean, and up to date. It must decide
which windows are visible, and draw them in the correct order.
*/
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#include <sys/types.h>
#include <signal.h>
#include "ecurses.h"
#include "interface.h"
#include "xmalloc.h"
#include "error.h"
#include "gettext.h"
#include "debug.h"
#include "status.h"
#include "topbar.h"
#include "cmd.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define HEAP_SIZE 8
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
struct frame {
struct frame *next;
WINDOW *win; /* window or NULL */
char *name; /* name displayed in statusbar */
int num; /* window id or -1 if it cannot get focus */
int hidden; /* if it is hidden */
void (*show) (void);
void (*draw) (void);
void (*set_focus) (void);
void (*unset_focus) (void);
};
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
/* This is used in signal handler to indicate that this error is being
handled (see info libc) */
static volatile sig_atomic_t error_indicator = 0;
/* I use heap to store numbers, that are assigned to windows, when they
are displayed. When window is being hidden, its number is inserted
in the heap. When window is being opened module assings the minimal
value from the heap. */
static int num_heap[HEAP_SIZE];
static int heap_count = 0;
static struct frame *visible_windows = NULL;
static struct frame *hidden_windows = NULL;
static struct frame *other_windows = NULL;
static struct frame *focused_window = NULL;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
/****************************************************************************
* HEAP FUNCTIONS
****************************************************************************/
static void
heap_exchange (int i, int j)
{
int tmp = num_heap[i];
num_heap[i] = num_heap[j];
num_heap[j] = tmp;
}
static void
heapify_up (void)
{
int i = heap_count;
int p;
while (1){
if (i == 1)
break;
p = i >> 1;
if (num_heap[i] >= num_heap[p])
break;
heap_exchange (i, p);
i = p;
}
}
static void
heapify_down (void)
{
int i = 1;
int l, r;
while (1){
if ((i << 1) >= heap_count)
break;
l = i << 1;
r = (i << 1) | 1;
if (num_heap[l] > num_heap[r])
l = r;
if (num_heap[i] <= num_heap[l])
break;
heap_exchange (i, l);
i = l;
}
}
static void
heap_insert (int i)
{
heap_count++;
num_heap[heap_count] = i;
heapify_up ();
}
static int
heap_extract_min (void)
{
int last = heap_count;
int ret = num_heap[1];
heap_count--;
num_heap[1] = num_heap[last];
num_heap[last] = -1;
heapify_down ();
return ret;
}
static void
heap_init (void)
{
int i;
for (i = 0; i < HEAP_SIZE; i++)
num_heap[i] = -1;
for (i = 1; i < HEAP_SIZE; i++)
heap_insert (i);
}
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static void
curses_cleanup (int signum)
{
if (error_indicator)
raise (signum);
error_indicator = 1;
/* cleanup code start */
endwin ();
/* cleanup code end */
signal (signum, SIG_DFL);
raise (signum);
}
static void
ncurses_setup (void)
{
signal (SIGTERM, curses_cleanup);
signal (SIGQUIT, curses_cleanup);
signal (SIGINT, curses_cleanup);
signal (SIGSEGV, curses_cleanup);
signal (SIGFPE, curses_cleanup);
signal (SIGABRT, curses_cleanup);
signal (SIGBUS, curses_cleanup);
if (! initscr ()){
error_critical (1, 0, _("ncurses: initialization failure"));
}
cbreak ();
noecho ();
nonl ();
curs_set (0);
if (has_colors ()){
start_color ();
}
}
static void
destroy_list (struct frame *list)
{
if (list == NULL)
return;
destroy_list (list->next);
xfree (list);
}
static struct frame *
list_rem_win (struct frame **list, WINDOW *win)
{
struct frame *result;
if (*list == NULL)
return NULL;
if ((*list)->win == win){
result = *list;
*list = (*list)->next;
return result;
}
return list_rem_win (& (*list)->next, win);
}
static struct frame *
list_find_win (struct frame *list, WINDOW *win)
{
if (list == NULL)
return NULL;
if (list->win == win)
return list;
return list_find_win (list->next, win);
}
static struct frame *
list_find_num (struct frame *list, int num)
{
if (list == NULL)
return NULL;
if (list->num == num)
return list;
return list_find_num (list->next, num);
}
static void
unfocus (void)
{
if (focused_window == NULL)
return;
if (focused_window->unset_focus)
focused_window->unset_focus ();
}
static int
list_find_min (struct frame *list, int i)
{
int x;
if (list == NULL)
return i;
x = list_find_min (list->next, i);
if (i == x){
return list->num;
}
else if (x > i){
if (list->num < x && list->num > i)
return list->num;
return x;
}
else {
if (list->num < x || list->num > i)
return list->num;
return x;
}
}
static int
list_find_max (struct frame *list, int i)
{
int x;
if (list == NULL)
return i;
x = list_find_min (list->next, i);
if (i == x){
return list->num;
}
else if (x < i){
if (list->num > x && list->num < i)
return list->num;
return x;
}
else {
if (list->num > x || list->num < i)
return list->num;
return x;
}
}
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
void
interface_free_resources (void)
{
destroy_list (visible_windows);
destroy_list (hidden_windows);
destroy_list (other_windows);
}
void
interface_setup (void)
{
error_indicator = 0;
heap_init ();
ncurses_setup ();
}
void
interface_post_setup (void)
{
interface_focus (1);
}
void
interface_redraw (void)
{
struct frame *list;
for (list = other_windows; list; list = list->next){
if (list->draw)
list->draw ();
else
touchwin (list->win);
if (list->show)
list->show ();
else
wnoutrefresh (list->win);
}
for (list = visible_windows; list; list = list->next){
if (list->draw)
list->draw ();
else
touchwin (list->win);
if (list->show)
list->show ();
else
wnoutrefresh (list->win);
}
if (focused_window->draw)
focused_window->draw ();
if (focused_window->show)
focused_window->show ();
}
void
interface_focus (int num)
{
struct frame *frame = list_find_num (visible_windows, num);
if (frame == NULL)
return;
if (focused_window && focused_window->num == num)
return;
unfocus ();
status_switch_window (frame->name, frame->num);
if (frame->set_focus)
frame->set_focus ();
focused_window = frame;
topbar_refresh ();
list_rem_win (& visible_windows, frame->win);
frame->next = visible_windows;
visible_windows = frame;
}
void
interface_next_window (void)
{
int i;
if (focused_window == NULL)
return;
i = list_find_min (visible_windows, focused_window->num);
if (i == focused_window->num)
return;
interface_focus (i);
}
void
interface_prev_window (void)
{
int i;
if (focused_window == NULL)
return;
i = list_find_max (visible_windows, focused_window->num);
if (i == focused_window->num)
return;
interface_focus (i);
}
void
interface_num_window (void)
{
int i = cmd_last_char ();
if (i < '0' || i > '9')
return;
interface_focus (i - '0');
}
/****************************************************************************
* WINDOW FUNCTIONS
****************************************************************************/
WINDOW *
window_create (char *name, int height, int width, int top, int left,
int focus)
{
struct frame *frame = xmalloc (sizeof (struct frame));
frame->show = NULL;
frame->draw = NULL;
frame->set_focus = NULL;
frame->unset_focus = NULL;
frame->name = name;
frame->num = -1;
frame->hidden = 1;
frame->win = newwin (height, width, top, left);
if (frame->win == NULL)
error_critical (1, 0, _("invalid window"));
if (focus){
frame->next = hidden_windows;
hidden_windows = frame;
}
else {
frame->next = other_windows;
other_windows = frame;
}
return frame->win;
}
void
window_set_functions (WINDOW *win, void (*show)(void), void (*draw)(void),
void (*set_focus)(void), void (*unset_focus)(void))
{
struct frame *frame = list_find_win (hidden_windows, win);
if (frame == NULL){
debug_msg (DEBUG_ERROR, "no frame found in window_set_funs");
return;
}
frame->show = show;
frame->draw = draw;
frame->set_focus = set_focus;
frame->unset_focus = unset_focus;
}
void
window_hide (WINDOW *win)
{
struct frame *frame = list_rem_win (& visible_windows, win);
if (frame == NULL)
return;
heap_insert (frame->num);
frame->num = -1;
frame->next = hidden_windows;
hidden_windows = frame;
if (visible_windows)
interface_focus (visible_windows->num);
interface_redraw ();
}
void
window_show (WINDOW *win)
{
struct frame *frame = list_rem_win (& hidden_windows, win);
if (frame == NULL){
frame = list_find_win (visible_windows, win);
if (frame)
interface_focus (frame->num);
return;
}
frame->num = heap_extract_min ();
frame->next = visible_windows;
visible_windows = frame;
interface_focus (frame->num);
}
int
window_addch (WINDOW *win, chtype c)
{
int ret;
if (win == NULL)
return ERR;
if (c == '\r' || c == '\n')
return ERR;
if (c == '\t')
c = ' ';
if (c < 32){
wattron (win, A_REVERSE);
ret = waddch (win, c + 64);
wattroff (win, A_REVERSE);
return ret;
}
waddch (win, c);
return OK;
}
int
window_addnstr (WINDOW *win, const char *str, int n)
{
int i = n;
if (win == NULL || str == NULL)
return 0;
while (i && *str){
if (window_addch (win, (unsigned char) *str) != ERR)
i--;
str++;
}
return n - i;
}
int
window_addnast (WINDOW *win, const char *str, int n)
{
int i = n;
if (win == NULL || str == NULL)
return 0;
while (i && *str){
if (window_addch (win, '*') != ERR)
i--;
str++;
}
return n - i;
}
int
window_addchnstr (WINDOW *win, const chtype *str, int n)
{
int i = n;
if (win == NULL || str == NULL)
return 0;
while (i && *str){
if (window_addch (win, *str) != ERR)
i--;
str++;
}
return n - i;
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE interface.c
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1