/***************************************************************************** Gestionnaire de terminal Unix: screen.c (c) Pierre ADRIAANS 1994 *****************************************************************************/ #define _SCREEN_SOURCE_CODE_ #include "keyboard.h" #include "screen.h" int _NbreLig_,_NbreCol_, /* Definition courante de l'ecran */ _NbreWin_ = 0, /* Nbre de fenetres ouvertes */ _CursX_,_CursY_, /* Position du curseur */ _ActLig_, /* Fenetre d'affichage courante */ _ActCol_, _ActHeight_, _ActLength_, _ShadeH_, /* Nbre de lignes inf d'un ombrage de fenetre */ _ShadeL_, /* Nbre de colonnes a droite d'un ombrage de fen */ _ScreenType_, /* Type de terminal */ _IsInGraphic_ = 0; /* Temoin de mode graphique pour terminaux DEC */ char _CurrentAtt_, /* Attribut d'affichage courant */ _ShadeA_; /* Atribut d'ombrage */ /* Memoire video */ VideoEle_t *_VideoMemory_ = (VideoEle_t *)NULL; WinDesc_t *_ActWin_; /* Pointeur sur la fenetre active */ /* Macro de sauvegarde/restauration d'une eventuelle interruption systeme sur l'horloge. Elles ont pour but d'empecher les affichages de cette interruption (typiquement un affichage de l'heure toutes les secondes) d'interferer avec un rafraichissement d'ecran */ unsigned int ScrRemains; #ifdef SIGACT struct sigaction ScrOldAlrm,ScrNewAlrm; #define SaveAlrm() \ { ScrNewAlrm.sa_handler = SIG_IGN; \ sigemptyset(&ScrNewAlrm.sa_mask); \ ScrNewAlrm.sa_flags = 0; \ sigaction(SIGALRM,&ScrNewAlrm,&ScrOldAlrm); \ if(ScrOldAlrm.sa_handler != SIG_IGN) ScrRemains = alarm(0); \ else ScrRemains = 0; } #define RestoreAlrm() \ { sigaction(SIGALRM,&ScrOldAlrm,&ScrNewAlrm); \ if(ScrOldAlrm.sa_handler != SIG_IGN) alarm(ScrRemains); } #else void (*ScrAlrmFct)(int); #define SaveAlrm() \ { ScrAlrmFct = signal(SIGALRM,SIG_IGN); \ if(ScrAlrmFct != SIG_IGN) ScrRemains = alarm(0); \ else ScrRemains = 0; } #define RestoreAlrm() \ { signal(SIGALRM,ScrAlrmFct); \ if(ScrAlrmFct != SIG_IGN) alarm(ScrRemains); } #endif /***************************************************************************** Gestion de l'affichage sur terminal DEC *****************************************************************************/ /* Definition de la table de substitution */ VT_Table_t VT_Table[NB_EXT_CHAR] = { { PC_F_S_ULC , VT_F_S_ULC }, { PC_F_S_HO , VT_F_S_HO }, { PC_F_S_URC , VT_F_S_URC }, { PC_F_S_VE , VT_F_S_VE }, { PC_F_S_LLC , VT_F_S_LLC }, { PC_F_S_LRC , VT_F_S_LRC }, { PC_F_D_ULC , VT_F_D_ULC }, { PC_F_D_HO , VT_F_D_HO }, { PC_F_D_URC , VT_F_D_URC }, { PC_F_D_VE , VT_F_D_VE }, { PC_F_D_LLC , VT_F_D_LLC }, { PC_F_D_LRC , VT_F_D_LRC }, { PC_F_SSSS , VT_F_SSSS }, { PC_F_SDSD , VT_F_SDSD }, { PC_F_DSDS , VT_F_DSDS }, { PC_F_DDDD , VT_F_DDDD }, { PC_F_BSSS , VT_F_BSSS }, { PC_F_BDDD , VT_F_BDDD }, { PC_F_BSDS , VT_F_BSDS }, { PC_F_BDSD , VT_F_BDSD }, { PC_F_SBSS , VT_F_SBSS }, { PC_F_DBDD , VT_F_DBDD }, { PC_F_DBDS , VT_F_DBDS }, { PC_F_SBSD , VT_F_SBSD }, { PC_F_SSBS , VT_F_SSBS }, { PC_F_DDBD , VT_F_DDBD }, { PC_F_DSBS , VT_F_DSBS }, { PC_F_SDBD , VT_F_SDBD }, { PC_F_SSSB , VT_F_SSSB }, { PC_F_DDDB , VT_F_DDDB }, { PC_F_DSDB , VT_F_DSDB }, { PC_F_SDSB , VT_F_SDSB }, { PC_DESKTOP , VT_DESKTOP }, { PC_PLUS_MIN , VT_PLUS_MIN }, { PC_DEGREE , VT_DEGREE }, { PC_MINUS_EQ , VT_MINUS_EQ }, { PC_GREAT_EQ , VT_GREAT_EQ }, { PC_PI , VT_PI } }; /* Fonction renvoyant l'adresse de cette table */ VT_Table_t *GetVT_TableAdress(void) { return(VT_Table); } /***************************************************************************** VT_PutToScr() ------------------------------------------------------------------------------ Fonction de passage a l'ecran avec traitement des cadres DEC. Les caracteres graphiques PC sont utilises, mais la fonction cherche l'equivalant de ce code pour le terminal DEC dans la table de conversion FrTable, passe l'ecran en mode caractere graphiques si il ne l'est deja puis affiche le code correspondant. Cette tactique a ete employee pour permettre aux fenetres de se refermer: lors du retablissement de l'ecran present avant l'ouverture de la fenetre, la meme tactique peut etre employee, et des cadres de terminal peuvent etre restaures. Ce n'aurait ete possible autrement etant donne que des cadres sur terminal DEC ne sont pas des caracteres speciaux mais bien des caracteres classiques qui seront affiches comme des cadres si l'ecran se trouve dans un mode special. *****************************************************************************/ void VT_PutToScr(char c) { char Temp[2]; unsigned char C; int i; C = (unsigned char)c; if(C < 128) { if(_IsInGraphic_) { SWITCH_TEXT; _IsInGraphic_ = 0; } putchar(C); } else { for(i = 0; i> 4; B_Color = Tmp; T_Color = (unsigned char)Att - (B_Color << 4); if(B_Color == 10) printf("%c[%dm%c[%dm",27,G_NORMAL,27,T_Color); else { if(T_Color <= WHITE) printf("%c[%dm%c[%d;%dm",27,G_NORMAL,27,T_Color + 30,B_Color + 40); else { printf("%c[%dm%c[%d;%dm",27,G_NORMAL,27,T_Color + 30 - 8,B_Color + 40); printf("%c[%dm",27,G_BOLD); } } } /***************************************************************************** FONCTIONS D'ENCAPSULATION *****************************************************************************/ void SetShading(int Length,int Height,char Attr) { _ShadeL_ = Length; _ShadeH_ = Height; _ShadeA_ = Attr; } void GetShading(int *Length,int *Height,char *Attr) { *Length = _ShadeL_; *Height = _ShadeH_; *Attr = _ShadeA_; } int GetScreenType(void) { return(_ScreenType_); } void GetScreenRes(int *NbLig,int *NbCol) { *NbLig = _NbreLig_; *NbCol = _NbreCol_; } void GetActiveWindow(int *Lig,int *Col,int *Height,int *Length) { *Lig = _ActLig_; *Col = _ActCol_; *Height = _ActHeight_; *Length = _ActLength_; } void SetActiveWindow(int Lig,int Col,int Height,int Length) { _ActLig_ = Lig; _ActCol_ = Col; _ActHeight_ = Height; _ActLength_ = Length; } void SetCurrentAtt(char NewAtt) { _CurrentAtt_ = NewAtt; SetAtt(NewAtt); } char GetCurrentAtt(void) { return(_CurrentAtt_); } void GotoXY(int Lig,int Col) { MoveCurs(Lig,Col); _CursX_ = Col; _CursY_ = Lig; } void SetXY(int Lig,int Col) { _CursX_ = Col; _CursY_ = Lig; } void GetXY(int *Lig,int *Col) { *Col = _CursX_; *Lig = _CursY_; } VideoEle_t *GetVideoMemoryAdress(void) { return(_VideoMemory_); } WinDesc_t *GetActWinDesc(void) { return(_ActWin_); } int GetNbreWin(void) { return(_NbreWin_); } /***************************************************************************** ClrScr() ------------------------------------------------------------------------------ Efface l'ecran *****************************************************************************/ void ClrScr(void) { WinDesc_t *Ptr; int i; SetCurrentAtt(PackAtt(NORMAL)); Cls(); /* Le curseur est replace en haut a gauche */ _CursX_ = 1; _CursY_ = 1; /* Fenetre active sur tout l'ecran */ _ActLig_ = 1; _ActCol_ = 1; _ActHeight_ = _NbreLig_; _ActLength_ = _NbreCol_; /* Rectifier la memoire video */ for(i=0;i<(_NbreLig_ * _NbreCol_);i++) { _VideoMemory_[i].Code = ' '; _VideoMemory_[i].Attr = PackAtt(NORMAL); } /* Eliminer tous les descripteurs */ while(_NbreWin_ > 0) { free(_ActWin_->Buffer); Ptr = _ActWin_; _ActWin_ = _ActWin_->Prec; free(Ptr); _NbreWin_--; } fflush(stdout); } /***************************************************************************** ClrZone() ------------------------------------------------------------------------------ Efface une zone d'ecran ecran dans un attribut *****************************************************************************/ void ClrZone(int Lig,int Col,int Height,int Length,char Attr) { int i; char *Buf = (char *)NULL; if(Length > _NbreCol_ || Height > _NbreLig_) return; Buf = (char *)malloc(Length + 1); if(Buf == (char *)NULL) raise(SIGME); memset(Buf,' ',Length); Buf[Length] = 0; for(i=0;iAttr; if(NewAtt != OldAtt) SetAtt(NewAtt); OldAtt = NewAtt; PutToScr(Buf->Code); _VideoMemory_[Offset].Code = Buf->Code; _VideoMemory_[Offset].Attr = Buf->Attr; } } MoveCurs(_CursY_,_CursX_); SetAtt(_CurrentAtt_); fflush(stdout); UnlockKbd(); RestoreAlrm(); } } /***************************************************************************** SaveScreen() ------------------------------------------------------------------------------ Sauve un ecran et renvoie un pointeur sur le buffer *****************************************************************************/ VideoEle_t *SaveScreen(void) { VideoEle_t *Temp; Temp = AllocateVideoBuffer(_NbreLig_,_NbreCol_); SaveZone(1,1,_NbreLig_,_NbreCol_,Temp); return(Temp); } /***************************************************************************** RestoreScreen() ------------------------------------------------------------------------------ Reataure l'ecran sauve dans Buffer *****************************************************************************/ void RestoreScreen(VideoEle_t *Buffer) { PutZone(1,1,_NbreLig_,_NbreCol_,Buffer); } /***************************************************************************** ScrollUpWin() ------------------------------------------------------------------------------ Scrolle le contenu de la fenetre de coord Lig,Col sur une hauteur Height et une largeur Length de NbreRows lignes vers le haut en rajoutant des lignes vides en dessous *****************************************************************************/ void ScrollUpWin(int Lig,int Col,int Height,int Length,int NbreRows) { VideoEle_t *Buffer; int Line, /* La ligne d'affichage courante */ cpt, /* Compteur de tours fonction du nbre de rangs a scroller */ j, /* Compteur de caractere pour chaque ligne */ OffsetVid; /* Offset video d'affichage courant */ char OldAtt = -1; /* Precedent attribut */ SaveAlrm(); LockKbd(); /* Premiere partie: deplacer vers le bas les lignes deja presentes, et ce en utilisant les fonctions de sauvegarde/restauration de parties d'ecran */ /* S'allouer un buffer */ Buffer = AllocateVideoBuffer(Height,Length); /* Sauver la zone a scroller */ SaveZone(Lig,Col,Height,Length,Buffer); /* La replacer au meme endroit, mais en rognant NbreRows lignes au sommet et en hauteur totale */ PutZone(Lig,Col,Height-NbreRows,Length,Buffer + (Length * NbreRows)); /* On a plus besoin du buffer */ free(Buffer); /* Deuxieme partie: ajouter NbreRows lignes vides en dessous des lignes qu'on vient de scroller, et ce dans l'attribut d'affichage courant */ for(Line = Lig + Height - NbreRows,cpt = 0; cpt < NbreRows; cpt++,Line++) { /* Inserer une ligne vide a la ligne Height */ MoveCurs(Line,Col); SetAtt(_CurrentAtt_); for(OffsetVid = VidMemOffset(Line,Col),j=0; j= _ShadeH_) { if(Attr != _ShadeA_) SetAtt(_ShadeA_); for(j=0;j<_ShadeL_;j++,Nbre++) { ch = GetChar(Lig+i,Col+Length+j); if((ch == C_DESKTOP) && (GetAtt(Lig+i,Col+Length+j) == PackAtt(NORMAL))) ch = ' '; PutToScr(ch); _VideoMemory_[Nbre].Code = ch; _VideoMemory_[Nbre].Attr = _ShadeA_; } if(Attr != _ShadeA_) SetAtt(Attr); } } /* Ligne du bas */ MoveCurs(Lig+i,Col); for(Nbre = VidMemOffset(Lig+i,Col),k = 0; Bottom[k]; k++,Nbre++) { PutToScr(Bottom[k]); _VideoMemory_[Nbre].Code = Bottom[k]; _VideoMemory_[Nbre].Attr = Attr; } /* S'il faut ombrer, ombrons */ if(Shaded == SHADED) { SetAtt(_ShadeA_); for(j=0;j<_ShadeL_;j++,Nbre++) { ch = GetChar(Lig+i,Col+Length+j); if((ch == C_DESKTOP) && (GetAtt(Lig+i,Col+Length+j) == PackAtt(NORMAL))) ch = ' '; PutToScr(ch); _VideoMemory_[Nbre].Code = ch; _VideoMemory_[Nbre].Attr = _ShadeA_; } /* Ombre inferieure: ShadeH lignes et Length colonnes */ for(i=0; i<_ShadeH_; i++,Nbre++) { MoveCurs(Lig+Height+i,Col+_ShadeL_); for(j=0,Nbre = VidMemOffset(Lig+Height+i,Col+_ShadeL_); jBuffer = AllocateVideoBuffer(Height+_ShadeH_,Length+_ShadeL_); else Ptr->Buffer = AllocateVideoBuffer(Height,Length); _NbreWin_++; Ptr->Attr = Attr; Ptr->CurrentAtt = _CurrentAtt_; Ptr->Lig = Lig; Ptr->Col = Col; Ptr->Height = Height; Ptr->Length = Length; Ptr->ActLig = _ActLig_; Ptr->ActCol = _ActCol_; Ptr->ActHeight = _ActHeight_; Ptr->ActLength = _ActLength_; Ptr->CursY = _CursY_; Ptr->CursX = _CursX_; Ptr->Prec = _ActWin_; Ptr->Shaded = Shaded; if(Shaded == SHADED) SaveZone(Lig,Col,Height+_ShadeH_,Length+_ShadeL_,Ptr->Buffer); else SaveZone(Lig,Col,Height,Length,Ptr->Buffer); _ActWin_ = Ptr; PaintWin(Lig,Col,Height,Length,Attr,Framed,Shaded); _ActLig_ = Lig+1; _ActCol_ = Col+2; _ActHeight_ = Height-2; _ActLength_ = Length-4; _CurrentAtt_ = Attr; GotoXY(_ActLig_,_ActCol_); SetAtt(Attr); fflush(stdout); return(0); } /***************************************************************************** CloseWin() ------------------------------------------------------------------------------ Referme la derniere fenetre ouverte et retablit ce qui se trouvait en dessous avant son ouverture. L'ancienne fenetre active est retablie et le curseur est replace a la position qu'il occupait avant l'ouverture de la fenetre. *****************************************************************************/ void CloseWin(void) { WinDesc_t *Ptr; if(_NbreWin_ > 0) { if(_ActWin_->Shaded == SHADED) PutZone(_ActWin_->Lig,_ActWin_->Col,(_ActWin_->Height)+_ShadeH_, (_ActWin_->Length)+_ShadeL_,_ActWin_->Buffer); else PutZone(_ActWin_->Lig,_ActWin_->Col,_ActWin_->Height,_ActWin_->Length, _ActWin_->Buffer); free(_ActWin_->Buffer); GotoXY(_ActWin_->CursY,_ActWin_->CursX); _ActLig_ = _ActWin_->ActLig; _ActCol_ = _ActWin_->ActCol; _ActHeight_ = _ActWin_->ActHeight; _ActLength_ = _ActWin_->ActLength; _CurrentAtt_ = _ActWin_->CurrentAtt; SetAtt(_CurrentAtt_); Ptr = _ActWin_; _ActWin_ = _ActWin_->Prec; free(Ptr); _NbreWin_--; fflush(stdout); } } /***************************************************************************** Window() ------------------------------------------------------------------------------ Idem Borland: reaffecte la fenetre active, l'efface dans l'attribut courant et positionne le curseur dans le coin superieur gauche. *****************************************************************************/ void Window(int Lig,int Col,int Height,int Length) { SetActiveWindow(Lig,Col,Height,Length); ClrZone(Lig,Col,Height,Length,_CurrentAtt_); GotoXY(Lig,Col); fflush(stdout); } /***************************************************************************** DrawDesktop() ------------------------------------------------------------------------------ Input: attribut du centre du desktop Process: Dessin d'un fond d'ecran typique applications en mode texte. Le caractere utilise pour remplir le fond est defini dans frames.h (DESKTOP_CHAR) en fonction du type de terminal. Tous les descripteurs de fenetres sont liberes, la fenetre active est retablie a tout l'ecran, l' attribut d'affichage repasse a NORMAL et le curseur est replace dans le coin superieur gauche de l'ecran. *****************************************************************************/ void DrawDesktop(char AttBar,char AttCenter) { WinDesc_t *Ptr; char *Str = (char *)NULL; int i; /* Fenetre active sur tout l'ecran */ _ActLig_ = 1; _ActCol_ = 1; _ActHeight_ = _NbreLig_; _ActLength_ = _NbreCol_; /* Eliminer tous les descripteurs */ GotoXY(1,1); while(_NbreWin_ > 0) { free(_ActWin_->Buffer); Ptr = _ActWin_; _ActWin_ = _ActWin_->Prec; free(Ptr); _NbreWin_--; } /* Dessiner le desktop */ Str = (char *)malloc(_NbreCol_ + 1); if(Str == (char *)NULL) raise(SIGME); if(_ScreenType_ == TEXT_SCREEN) for(i=0;i<_NbreCol_; i+= 2) { Str[i] = '('; Str[i+1] = ')'; } else for(i=0;i<_NbreCol_;i++) Str[i] = C_DESKTOP; Str[i] = 0; ClrZone(1,1,1,_NbreCol_,AttBar); for(i=2;i