static char rcsid[] = "@(#)$Id: context.c,v 1.10 2006/04/09 07:37:37 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.10 $ $State: Exp $ * * Author: Kari Hurtta *****************************************************************************/ #include "def_screen.h" DEBUG_VAR(Debug,__FILE__,"screen"); struct menu_context ROOT_MENU = { MENU_CONTEXT_magic, &CURSES_ROUTINES, /* menu_draw_routine */ NULL, NULL, /* subpages, container */ 0,0, /* lines, columns */ 0,0, /* changed, redraw */ 0, /* modes */ 0,0, /* row,col */ NULL, /* dummy */ NULL /* prev */, NULL /* next */ }; struct menu_context COOKED_MENU = { MENU_CONTEXT_magic, &CURSES_ROUTINES, /* menu_draw_routine */ NULL, NULL, /* subpages, container */ 0,0, /* lines, columns */ 0,0, /* changed, redraw */ 0, /* modes */ 0,0, /* row,col */ NULL, /* dummy */ NULL /* prev */, NULL /* next */ }; struct menu_context * default_context = &COOKED_MENU; struct menu_context * new_menu_type(T) struct menu_draw_routine *T; { struct menu_context *ret = safe_malloc(sizeof (*ret)); if (MENU_DRAW_magic != T->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"new_menu_type", "Bad routine magic number",0); /* bzero is defined hdrs/defs.h */ bzero((void *)ret,sizeof (*ret)); ret->magic = MENU_CONTEXT_magic; ret->routine = T; ret->subpages = NULL; ret->container = NULL; ret->lines = 0; ret->columns = 0; ret->changed = 0; ret->redraw = 0; ret->modes = 0; ret->row = 0; ret->col = 0; ret->u.dummy = NULL; T->wra_init(ret); return ret; } struct menu_context * new_menu_context() { struct menu_context *ret = new_menu_type(&CURSES_ROUTINES); /* Take data from root menu */ ret->lines = ROOT_MENU.lines; ret->columns = ROOT_MENU.columns; ret->changed = ROOT_MENU.changed; ret->redraw = ROOT_MENU.redraw; ret->modes = ROOT_MENU.modes; ret->row = ROOT_MENU.row; ret->col = ROOT_MENU.col; /* chain to list */ ret->next_menu = ROOT_MENU.next_menu; ROOT_MENU.next_menu = ret; ret->prev_menu = &ROOT_MENU; if (ret->next_menu) ret->next_menu->prev_menu = ret; if (default_context == &COOKED_MENU) { DPRINT(Debug,1, (&Debug, "new_menu_context: On COOKED MENU, not changing default context\n")); } else { default_context = ret; DPRINT(Debug,9, (&Debug, "new_menu_context: default context to %p\n", default_context)); Syncronize(default_context); } return ret; } void erase_menu_context(ptr) struct menu_context **ptr; { struct menu_subpages *list, *next = NULL; if ((*ptr)->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "Bad type magic number",0); if (&ROOT_MENU == *ptr) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "attempt to erase root menu",0); if (&COOKED_MENU == *ptr) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "attempt to erase cooked menu",0); if (MENU_DRAW_magic != (*ptr)->routine->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "Bad routine magic number",0); EndSyncronize(*ptr); if ((*ptr)->container) detach_subpage(*ptr); if ((*ptr)->subpages) { DPRINT(Debug,1, (&Debug, "erase_menu_context: %p: WARNING: subpages not erased / detached\n", *ptr)); for (list = (*ptr)->subpages; list; list = next) { if (MENU_CONTAINER_magic != list->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "Bad subpage type magic number",0); if (list->parent != *ptr) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "Bad parent pointer on subpage",0); next = list->next; if (list->subpage) { if (list != list->subpage->container) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "Bad container pointer on subpage",0); /* Reset congtainer pointer so that erase menu content do not call detach_subpage() */ list->subpage->container = NULL; erase_menu_context( & (list->subpage) ); } list->prev = NULL; list->next = NULL; list->magic = 0; /* Invalidate */ free(list); } (*ptr)->subpages = NULL; } if (default_context == (*ptr)) { default_context = (*ptr)->prev_menu; DPRINT(Debug,9, (&Debug, "erase_menu_context: default context to %p\n", default_context)); } if (!default_context) panic("SCREEN PANIC",__FILE__,__LINE__,"erase_menu_context", "no default content",0); Syncronize(default_context); if ((*ptr)->next_menu) (*ptr)->next_menu->prev_menu = (*ptr)->prev_menu; if ((*ptr)->prev_menu) (*ptr)->prev_menu->next_menu = (*ptr)->next_menu; (*ptr)->routine->wra_free(*ptr); if ((*ptr)->u.dummy) { DPRINT(Debug,1, (&Debug, "erase_menu_context: Data not free'ed\n")); } (*ptr)->magic = 0; /* Invalidate */ free(*ptr); *ptr = NULL; } void attach_subpage(parent,subpage, first_line, last_line) struct menu_context *parent; struct menu_context *subpage; /* absolute screen cordinates */ int first_line, last_line; { struct menu_subpages * X; if (MENU_CONTEXT_magic != parent->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"attach_subpage", "Bad parent type magic number",0); if (MENU_CONTEXT_magic != subpage->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"attach_subpage", "Bad subpage type magic number",0); X = safe_malloc(sizeof (*X)); /* bzero is defined hdrs/defs.h */ bzero((void *)X,sizeof (*X)); X->magic = MENU_CONTAINER_magic; X->location.first_line = first_line; X->location.last_line = last_line; X->location.gone_out = 0; subpage->lines = last_line - first_line + 1; subpage->columns = parent->columns; subpage->redraw = 1; subpage->container = X; X->subpage = subpage; X->parent = parent; X->next = parent->subpages; X->prev = NULL; if (parent->subpages) { if (parent->subpages->prev) panic("SCREEN PANIC",__FILE__,__LINE__,"attach_subpage", "parent's subpage list do not point to first item",0); parent->subpages->prev = X; } parent->subpages = X; } extern void detach_subpage(subpage) struct menu_context *subpage; { if (MENU_CONTEXT_magic != subpage->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad subpage type magic number",0); if (MENU_CONTAINER_magic != subpage->container->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad container type magic number",0); if (MENU_CONTEXT_magic != subpage->container->parent->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad parent type magic number",0); if (subpage->container->subpage != subpage) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad subpage of container",0); /* Remove from list */ if (subpage->container->prev) { if (subpage->container != subpage->container->prev->next) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad prev of container",0); subpage->container->prev->next = subpage->container->next; } else { if (subpage->container != subpage->container->parent->subpages) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad subpages of parent",0); subpage->container->parent->subpages = subpage->container->next; } if (subpage->container->next) { if (subpage->container != subpage->container->next->prev) panic("SCREEN PANIC",__FILE__,__LINE__,"detach_subpage", "Bad next of container",0); subpage->container->next->prev = subpage->container->prev; } subpage->container->subpage = NULL; subpage->container->magic = 0; /* Invalidate */ free(subpage->container); subpage->container = NULL; } static struct menu_context * get_root_menu P_((struct menu_context *ptr, int *pending_redraw)); static struct menu_context * get_root_menu(ptr,pending_redraw) struct menu_context *ptr; int *pending_redraw; { struct menu_context *pptr = ptr; while (pptr->container) { if (MENU_CONTAINER_magic != pptr->container->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"get_root_menu", "Bad subpage container type magic number",0); pptr = pptr->container->parent; if (pptr->redraw) (*pending_redraw) ++; if (pptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"get_root_menu", "Bad parent type magic number",0); } if (pptr != default_context) { DPRINT(Debug,7, (&Debug, "get_root_menu(%p): root %p is not default context %p\n", ptr,pptr,default_context)); } return pptr; } int menu_resized(ptr) struct menu_context *ptr; { if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_resized", "Bad type magic number",0); check_changes(); if (ptr->changed) { struct menu_subpages *list, *next = NULL; if (MENU_DRAW_magic != ptr->routine->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_resized", "Bad routine magic number",0); ptr->routine->wra_resized(ptr); /* Turn changed flag for subpages ... */ for (list = ptr->subpages; list; list = list->next) { if (MENU_CONTAINER_magic != list->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_resized", "Bad subpage container type magic number",0); if (list->parent != ptr) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_resized", "Bad parent pointer on subpage",0); if (list->subpage) { if (MENU_CONTEXT_magic != list->subpage->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_resized", "Bad subpage type magic number",0); list->subpage->changed = 1; } } return 1; } return 0; } void menu_get_sizes(ptr,lines,columns) struct menu_context *ptr; int *lines; int *columns; { if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_get_sizes", "Bad type magic number",0); *lines = ptr->lines; *columns = ptr->columns; } int menu_need_redraw(ptr) struct menu_context *ptr; { struct menu_context *pptr; int pending_redraw = 0; if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_need_redraw", "Bad type magic number",0); check_changes(); /* Check parents */ pptr = get_root_menu(ptr,&pending_redraw); if (pending_redraw) { DPRINT(Debug,7, (&Debug, "menu_need_redraw(%p): pending redraw on parent\n", ptr)); ptr->redraw = 1; } if (pptr->routine != &CURSES_ROUTINES) { DPRINT(Debug,1, (&Debug, "menu_need_redraw(%p): ERROR -- parent %p not main manu (not connected) -- quiting%s\n", ptr,pptr, ptr->redraw ? " (returning redraw)": "")); return ptr->redraw; } if (pptr != default_context) { DPRINT(Debug,9, (&Debug, "menu_need_redraw: default context to %p (redraw needed)\n", pptr)); default_context = pptr; Syncronize(default_context); pptr->redraw = 1; ptr->redraw = 1; } if (ptr->redraw) { struct menu_subpages *list; int r; if (MENU_DRAW_magic != ptr->routine->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_need_redraw", "Bad routine magic number",0); /* Reset ptr->redraw .... */ ptr->routine->wra_reset_redraw(ptr); /* Turn redraw flag for subpages ... */ for (list = ptr->subpages; list; list = list->next) { if (MENU_CONTAINER_magic != list->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_need_redraw", "Bad subpage container type magic number",0); if (list->parent != ptr) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_need_redraw", "Bad parent pointer on subpage",0); if (list->subpage) menu_trigger_redraw(list->subpage); } r = ptr->routine->wra_do_redraw(ptr); if (r) { DPRINT(Debug,7, (&Debug, "menu_need_redraw(%p): redraw done\n", ptr)); } else { DPRINT(Debug,7, (&Debug, "menu_need_redraw(%p): returning redraw\n", ptr)); return 1; } } return 0; } /* Call refresh routines of children */ void menu_redraw_children(ptr) struct menu_context *ptr; { struct menu_subpages *list; if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_redraw_children", "Bad type magic number",0); for (list = ptr->subpages; list; list = list->next) { if (MENU_CONTAINER_magic != list->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_redraw_children", "Bad subpage container type magic number",0); if (list->parent != ptr) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_redraw_children", "Bad parent pointer on subpage",0); if (list->subpage) { struct menu_context *ptr1 = list->subpage; int r; if (ptr1->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_redraw_children", "Bad type magic number",0); if (MENU_DRAW_magic != ptr1->routine->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_redraw_children", "Bad routine magic number",0); r = ptr1->routine->wra_do_redraw(ptr1); if (r) { DPRINT(Debug,7, (&Debug, "menu_redraw_children(%p): %p: redraw done\n", ptr,ptr1)); } else ptr1->redraw = 1; } } } void menu_trigger_redraw(ptr) struct menu_context *ptr; { struct menu_context *pptr; int pending_redraw = 0; int r; if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_trigger_redraw", "Bad type magic number",0); DPRINT(Debug,7, (&Debug, "menu_trigger_redraw(%p): triggering redraw\n", ptr)); if (MENU_DRAW_magic != ptr->routine->magic) panic("SCREEN PANIC",__FILE__,__LINE__,"menu_trigger_redraw", "Bad routine magic number",0); /* Check parents */ pptr = get_root_menu(ptr,&pending_redraw); if (pptr == default_context) { /* Is active */ if (pending_redraw) { DPRINT(Debug,7, (&Debug, "menu_trigger_redraw(%p): pending redraw on parent\n", ptr)); ptr->redraw = 1; } else { r = ptr->routine->wra_do_redraw(ptr); if (r) { DPRINT(Debug,7, (&Debug, "menu_trigger_redraw(%p): redraw done\n", ptr)); } else ptr->redraw = 1; } } else { DPRINT(Debug,7, (&Debug, "menu_trigger_redraw(%p): parent %p not active\n", ptr,pptr)); ptr->redraw = 1; } } static VOLATILE int resize_screen = 0; /** SIGWINCH occured? **/ static VOLATILE int redraw_screen = 0; /** Elm suspended? **/ /* called from signal handler */ void menu_context_resize() { resize_screen = 1; redraw_screen = 1; ROOT_MENU.changed = 1; /* Indicate that ROOT_MENU is invalid not really needed */ } /* called from signal handler */ void menu_context_redraw() { redraw_screen = 1; ROOT_MENU.redraw = 1; /* not really needed */ } void set_root_menu(lines,columns) int lines; int columns; { int size = 0; if (lines != ROOT_MENU.lines && -1 != lines) { ROOT_MENU.lines = lines; COOKED_MENU.lines = lines; size ++; } if (columns != ROOT_MENU.columns && -1 != columns) { ROOT_MENU.columns = columns; COOKED_MENU.columns = columns; size++; } if (size) { struct menu_context *ptr; for (ptr = ROOT_MENU.next_menu; ptr; ptr = ptr->next_menu) { if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"set_root_menu", "Bad type magic number",0); ptr->changed = 1; } } } void check_changes() { if (resize_screen || redraw_screen) { int size = resize_screen; int draw = redraw_screen; struct menu_context *ptr; int lines, columns; resize_screen = 0; redraw_screen = 0; /* Real lines .. not lines-1 !!! */ cur_ScreenSize(&lines,&columns); if (lines > 0 && columns > 0) { /* Check that is size changed when Elm ME+ was suspended */ if (lines != ROOT_MENU.lines || columns != ROOT_MENU.columns) size++; ROOT_MENU.lines = lines; ROOT_MENU.columns = columns; ROOT_MENU.changed = 0; /* Values valid */ COOKED_MENU.lines = lines; COOKED_MENU.columns = columns; } else { DPRINT(Debug,1, (&Debug, "check_changes: cur_ScreenSize returned bad sizes: lines=%d columns=%d\n", lines,columns)); } if (size && default_context == &COOKED_MENU) COOKED_MENU.changed = 1; ROOT_MENU.redraw = draw; /* ? ? ? */ if (draw && default_context == &COOKED_MENU) COOKED_MENU.redraw = 1; for (ptr = ROOT_MENU.next_menu; ptr; ptr = ptr->next_menu) { if (ptr->magic != MENU_CONTEXT_magic) panic("SCREEN PANIC",__FILE__,__LINE__,"check_changes", "Bad type magic number",0); if (size) ptr->changed = 1; if (draw) ptr->redraw = 1; } } } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */