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