2017-09-01 12:24:32 +00:00
/*
2017-09-07 20:00:08 +00:00
* meli - bin . rs
2017-09-01 12:24:32 +00:00
*
2018-07-16 12:26:06 +00:00
* Copyright 2017 - 2018 Manos Pitsidianakis
2017-09-07 20:00:08 +00:00
*
2017-09-01 12:24:32 +00:00
* This file is part of meli .
*
* meli 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 , either version 3 of the License , or
* ( at your option ) any later version .
*
* meli 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 meli . If not , see < http ://www.gnu.org/licenses/>.
* /
2018-07-18 07:42:52 +00:00
/*! This crate contains the frontend stuff of the application. The application entry way on `src / bin.rs` creates an event loop and passes input to the `ui` module.
The mail handling stuff is done in the ` melib ` crate which includes all backend needs . The split is done to theoretically be able to create different frontends with the same innards .
* /
2018-08-05 09:14:26 +00:00
use std ::alloc ::System ;
#[ global_allocator ]
static GLOBAL : System = System ;
2019-04-04 11:21:52 +00:00
use ui ;
2018-07-16 08:08:04 +00:00
2018-07-11 15:58:57 +00:00
pub use melib ::* ;
2018-08-06 19:20:34 +00:00
pub use ui ::* ;
2017-09-01 12:24:32 +00:00
2018-07-16 10:36:28 +00:00
#[ macro_use ]
extern crate chan ;
2019-04-04 11:21:52 +00:00
use chan_signal ;
2018-07-16 10:36:28 +00:00
use chan_signal ::Signal ;
2019-04-04 11:21:52 +00:00
use nix ;
2018-07-24 10:28:15 +00:00
2017-07-23 11:01:17 +00:00
fn main ( ) {
2018-07-21 08:20:13 +00:00
/* Lock all stdio outs */
2018-07-24 10:28:15 +00:00
//let _stdout = stdout();
//let mut _stdout = _stdout.lock();
2018-07-11 14:07:51 +00:00
/*
2019-03-14 10:19:25 +00:00
let _stderr = stderr ( ) ;
let mut _stderr = _stderr . lock ( ) ;
* /
2018-07-11 14:07:51 +00:00
2018-07-16 12:26:06 +00:00
/* Catch SIGWINCH to handle terminal resizing */
2018-07-16 10:36:28 +00:00
let signal = chan_signal ::notify ( & [ Signal ::WINCH ] ) ;
2018-07-16 12:26:06 +00:00
/* Create the application State. This is the 'System' part of an ECS architecture */
2018-08-16 13:32:47 +00:00
let mut state = State ::new ( ) ;
let receiver = state . receiver ( ) ;
2018-07-11 14:07:51 +00:00
2018-10-14 16:49:16 +00:00
let worker_receiver = state . worker_receiver ( ) ;
2018-07-16 12:26:06 +00:00
/* Register some reasonably useful interfaces */
2019-04-10 19:01:02 +00:00
let menu = Box ::new ( AccountMenu ::new ( & state . context . accounts ) ) ;
2019-02-18 21:14:06 +00:00
let listing = listing ::Listing ::from ( IndexStyle ::Compact ) ;
2019-04-10 19:01:02 +00:00
let b = Box ::new ( listing ) ;
let window = Box ::new ( Tabbed ::new ( vec! [
2019-03-28 01:07:43 +00:00
Box ::new ( VSplit ::new ( menu , b , 90 , false ) ) ,
2019-03-14 10:19:25 +00:00
Box ::new ( AccountsPanel ::new ( & state . context ) ) ,
Box ::new ( ContactList ::default ( ) ) ,
] ) ) ;
2018-08-11 15:00:21 +00:00
2019-04-10 19:01:02 +00:00
let status_bar = Box ::new ( StatusBar ::new ( window ) ) ;
state . register_component ( status_bar ) ;
2018-07-13 15:38:57 +00:00
2019-04-10 19:01:02 +00:00
let xdg_notifications = Box ::new ( ui ::components ::notifications ::XDGNotifications { } ) ;
state . register_component ( xdg_notifications ) ;
state . register_component ( Box ::new (
2019-03-14 10:19:25 +00:00
ui ::components ::notifications ::NotificationFilter { } ,
2019-04-10 19:01:02 +00:00
) ) ;
2018-07-17 14:16:16 +00:00
2018-07-16 12:26:06 +00:00
/* Keep track of the input mode. See ui::UIMode for details */
2017-09-16 12:05:28 +00:00
' main : loop {
2018-07-14 18:41:38 +00:00
state . render ( ) ;
2017-07-23 11:01:17 +00:00
2017-09-16 12:05:28 +00:00
' inner : loop {
2019-04-10 19:01:02 +00:00
/* Check if any components have sent reply events to State. */
2018-07-20 09:44:04 +00:00
let events : Vec < UIEvent > = state . context . replies ( ) ;
2018-07-16 08:08:04 +00:00
for e in events {
state . rcv_event ( e ) ;
}
2018-10-14 16:49:16 +00:00
state . redraw ( ) ;
2018-07-21 08:20:13 +00:00
/* Poll on all channels. Currently we have the input channel for stdin, watching events and the signal watcher. */
2018-07-16 10:36:28 +00:00
chan_select! {
receiver . recv ( ) -> r = > {
match r . unwrap ( ) {
2018-07-24 10:28:15 +00:00
ThreadEvent ::Input ( Key ::Ctrl ( 'z' ) ) = > {
2018-08-07 12:01:15 +00:00
state . switch_to_main_screen ( ) ;
2018-07-24 10:28:15 +00:00
//_thread_handler.join().expect("Couldn't join on the associated thread");
let self_pid = nix ::unistd ::Pid ::this ( ) ;
nix ::sys ::signal ::kill ( self_pid , nix ::sys ::signal ::Signal ::SIGSTOP ) . unwrap ( ) ;
2018-08-07 12:01:15 +00:00
state . switch_to_alternate_screen ( ) ;
2018-08-16 13:32:47 +00:00
state . restore_input ( ) ;
2018-07-24 10:28:15 +00:00
// BUG: thread sends input event after one received key
state . update_size ( ) ;
state . render ( ) ;
state . redraw ( ) ;
} ,
2018-07-16 10:36:28 +00:00
ThreadEvent ::Input ( k ) = > {
2018-07-21 08:20:13 +00:00
match state . mode {
2018-07-16 10:36:28 +00:00
UIMode ::Normal = > {
match k {
Key ::Char ( 'q' ) | Key ::Char ( 'Q' ) = > {
2018-07-17 14:16:16 +00:00
drop ( state ) ;
2018-07-16 10:36:28 +00:00
break 'main ;
} ,
2019-03-25 11:41:39 +00:00
Key ::Char ( ' ' ) = > {
2018-07-21 08:20:13 +00:00
state . mode = UIMode ::Execute ;
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ChangeMode ( UIMode ::Execute ) } ) ;
2018-07-16 10:36:28 +00:00
state . redraw ( ) ;
}
key = > {
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::Input ( key ) } ) ;
state . redraw ( ) ;
} ,
}
2018-07-14 22:27:13 +00:00
} ,
2019-02-25 09:11:56 +00:00
UIMode ::Insert = > {
match k {
Key ::Char ( '\n' ) | Key ::Esc = > {
state . mode = UIMode ::Normal ;
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ChangeMode ( UIMode ::Normal ) } ) ;
state . redraw ( ) ;
} ,
k = > {
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::InsertInput ( k ) } ) ;
state . redraw ( ) ;
} ,
}
}
2018-07-16 10:36:28 +00:00
UIMode ::Execute = > {
match k {
Key ::Char ( '\n' ) | Key ::Esc = > {
2018-07-21 08:20:13 +00:00
state . mode = UIMode ::Normal ;
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ChangeMode ( UIMode ::Normal ) } ) ;
2018-07-16 10:36:28 +00:00
state . redraw ( ) ;
} ,
2018-08-07 13:14:06 +00:00
k = > {
2018-07-16 10:36:28 +00:00
state . rcv_event ( UIEvent { id : 0 , event_type : UIEventType ::ExInput ( k ) } ) ;
state . redraw ( ) ;
} ,
}
2018-07-16 08:08:04 +00:00
} ,
2018-07-21 08:20:13 +00:00
UIMode ::Fork = > {
break 'inner ; // `goto` 'reap loop, and wait on child.
} ,
2018-07-14 22:27:13 +00:00
}
2018-07-13 15:38:57 +00:00
} ,
2018-09-05 13:08:11 +00:00
ThreadEvent ::RefreshMailbox ( event ) = > {
2018-09-12 12:10:19 +00:00
state . refresh_event ( * event ) ;
2018-07-17 14:16:16 +00:00
state . redraw ( ) ;
2018-07-16 10:36:28 +00:00
} ,
2018-08-06 10:33:10 +00:00
ThreadEvent ::UIEvent ( UIEventType ::ChangeMode ( f ) ) = > {
2018-07-21 08:20:13 +00:00
state . mode = f ;
2019-02-25 09:11:56 +00:00
if f = = UIMode ::Fork {
break 'inner ; // `goto` 'reap loop, and wait on child.
}
2018-07-21 08:20:13 +00:00
}
2018-08-06 10:33:10 +00:00
ThreadEvent ::UIEvent ( e ) = > {
2018-07-16 10:36:28 +00:00
state . rcv_event ( UIEvent { id : 0 , event_type : e } ) ;
state . render ( ) ;
2018-07-13 15:38:57 +00:00
} ,
2018-08-06 11:58:54 +00:00
ThreadEvent ::ThreadJoin ( id ) = > {
state . join ( id ) ;
} ,
2017-09-28 15:06:35 +00:00
}
2017-09-01 12:24:32 +00:00
} ,
2018-07-16 10:36:28 +00:00
signal . recv ( ) -> signal = > {
2018-07-21 08:20:13 +00:00
if state . mode ! = UIMode ::Fork {
if let Some ( Signal ::WINCH ) = signal {
state . update_size ( ) ;
state . render ( ) ;
state . redraw ( ) ;
}
2018-07-16 10:36:28 +00:00
}
2018-07-13 15:38:57 +00:00
} ,
2018-10-14 16:49:16 +00:00
worker_receiver . recv ( ) -> _ = > {
/* Some worker thread finished their job, acknowledge
* it and move on * /
} ,
2017-07-23 11:01:17 +00:00
}
2018-07-21 08:20:13 +00:00
} // end of 'inner
' reap : loop {
match state . try_wait_on_child ( ) {
Some ( true ) = > {
2018-08-16 13:32:47 +00:00
state . restore_input ( ) ;
2018-09-03 22:49:29 +00:00
state . switch_to_alternate_screen ( ) ;
2018-07-27 18:37:56 +00:00
}
2018-07-21 08:20:13 +00:00
Some ( false ) = > {
use std ::{ thread , time } ;
2018-07-21 14:29:29 +00:00
let ten_millis = time ::Duration ::from_millis ( 1500 ) ;
2018-07-21 08:20:13 +00:00
thread ::sleep ( ten_millis ) ;
2018-07-24 10:28:15 +00:00
2018-07-21 08:20:13 +00:00
continue 'reap ;
2018-07-27 18:37:56 +00:00
}
None = > {
2018-09-03 22:49:29 +00:00
state . mode = UIMode ::Normal ;
state . render ( ) ;
2018-07-27 18:37:56 +00:00
break 'reap ;
}
2018-07-21 08:20:13 +00:00
}
2017-07-23 11:01:17 +00:00
}
}
}