Permalink
Browse files

Improve framework for handling screen resizes between views.

This uses the same technique as version types.  When a screen is
destroyed, we leave a forwarding pointer to the new screen.  When we
return to a caller which has a copy of the old screen, it can then
fast-forward to the latest version of the screen, and adapt to a new
screen size as necessary.
  • Loading branch information...
1 parent d88f772 commit 5cfa8e7f87bdf3f8b1d4037f0a7d7ae62c1dc4a0 @wangp committed Jun 17, 2012
Showing with 101 additions and 57 deletions.
  1. +9 −10 compose.m
  2. +9 −9 index_view.m
  3. +3 −4 recall.m
  4. +69 −17 screen.m
  5. +11 −17 thread_pager.m
View
@@ -158,11 +158,11 @@
MaybeOldDraft, Transition, !IO)
;
MaybeSubject = no,
- Transition = screen_ok(not_sent, no_change)
+ Transition = screen_transition(not_sent, no_change)
)
;
MaybeTo = no,
- Transition = screen_ok(not_sent, no_change)
+ Transition = screen_transition(not_sent, no_change)
).
:- pred get_from(string::out, io::di, io::uo) is det.
@@ -217,7 +217,7 @@
CommandResult = error(Error),
string.append_list(["Error running notmuch: ",
io.error_message(Error)], Warning),
- Transition = screen_ok(not_sent, set_warning(Warning))
+ Transition = screen_transition(not_sent, set_warning(Warning))
).
:- pred set_headers_for_direct_reply(string::in, string::in,
@@ -319,7 +319,7 @@
CallRes = error(Error),
string.append_list(["Error running notmuch: ",
io.error_message(Error)], Warning),
- Transition = screen_ok(not_sent, set_warning(Warning))
+ Transition = screen_transition(not_sent, set_warning(Warning))
).
:- pred first_text_part(list(part)::in, string::out, list(part)::out)
@@ -377,16 +377,16 @@
;
ResParse = error(Error),
io.error_message(Error, Msg),
- Transition = screen_ok(not_sent, set_warning(Msg))
+ Transition = screen_transition(not_sent, set_warning(Msg))
)
;
ResEdit = error(Msg),
- Transition = screen_ok(not_sent, set_warning(Msg))
+ Transition = screen_transition(not_sent, set_warning(Msg))
)
;
ResFilename = error(Error),
Msg = io.error_message(Error),
- Transition = screen_ok(not_sent, set_warning(Msg))
+ Transition = screen_transition(not_sent, set_warning(Msg))
).
:- pred call_editor(string::in, call_res::out, io::di, io::uo) is det.
@@ -589,16 +589,15 @@
MaybeOldDraft, Transition, !IO)
;
Action = leave(Sent, TransitionMessage),
- Transition = screen_maybe_destroyed(Sent, TransitionMessage)
+ Transition = screen_transition(Sent, TransitionMessage)
).
:- pred resize_staging_screen(screen::in, screen::out, staging_info::in,
pager_info::in, pager_info::out, io::di, io::uo) is det.
resize_staging_screen(Screen0, Screen, StagingInfo, PagerInfo0, PagerInfo,
!IO) :-
- destroy_screen(Screen0, !IO),
- create_screen(Screen, !IO),
+ replace_screen_for_resize(Screen0, Screen, !IO),
get_cols(Screen, Cols),
split_panels(Screen, _HeaderPanels, _AttachmentPanels, _MaybeSepPanel,
PagerPanels),
View
@@ -294,7 +294,8 @@
index_loop_no_draw(Screen, !.IndexInfo, !IO)
;
Action = resize,
- recreate_screen(Screen, NewScreen, !IndexInfo, !IO),
+ replace_screen_for_resize(Screen, NewScreen, !IO),
+ recreate_screen(NewScreen, !IndexInfo),
index_loop(NewScreen, !.IndexInfo, !IO)
;
Action = open_pager(ThreadId),
@@ -1461,12 +1462,9 @@
%-----------------------------------------------------------------------------%
-:- pred recreate_screen(screen::in, screen::out,
- index_info::in, index_info::out, io::di, io::uo) is det.
+:- pred recreate_screen(screen::in, index_info::in, index_info::out) is det.
-recreate_screen(Screen0, Screen, !IndexInfo, !IO) :-
- destroy_screen(Screen0, !IO),
- create_screen(Screen, !IO),
+recreate_screen(Screen, !IndexInfo) :-
% Keep cursor visible.
Scrollable0 = !.IndexInfo ^ i_scrollable,
( get_cursor(Scrollable0, Cursor) ->
@@ -1482,11 +1480,13 @@
io::di, io::uo) is det.
handle_screen_transition(!Screen, Transition, T, !Info, !IO) :-
+ Transition = screen_transition(T, MessageUpdate),
+ fast_forward_screen(!Screen, Resized, !IO),
(
- Transition = screen_ok(T, MessageUpdate)
+ Resized = yes,
+ recreate_screen(!.Screen, !Info)
;
- Transition = screen_maybe_destroyed(T, MessageUpdate),
- recreate_screen(!Screen, !Info, !IO)
+ Resized = no
),
update_message(!.Screen, MessageUpdate, !IO).
View
@@ -66,7 +66,7 @@
Message = "No postponed messages."
),
MaybeSelected = no,
- Transition = screen_ok(MaybeSelected, set_warning(Message))
+ Transition = screen_transition(MaybeSelected, set_warning(Message))
;
Ids = [_ | _],
time(Time, !IO),
@@ -76,7 +76,7 @@
Info = recall_info(Scrollable),
update_message(Screen, clear_message, !IO),
recall_screen_loop(Screen, MaybeSelected, Info, _Info, !IO),
- Transition = screen_maybe_destroyed(MaybeSelected, no_change)
+ Transition = screen_transition(MaybeSelected, no_change)
).
:- pred make_recall_line(tm::in, message_id::in, recall_line::out,
@@ -148,8 +148,7 @@
;
KeyCode = code(key_resize)
->
- destroy_screen(Screen, !IO),
- create_screen(NewScreen, !IO),
+ replace_screen_for_resize(Screen, NewScreen, !IO),
recall_screen_loop(NewScreen, MaybeSelected, !Info, !IO)
;
recall_screen_loop(Screen, MaybeSelected, !Info, !IO)
View
@@ -23,14 +23,21 @@
; set_prompt(string).
:- type screen_transition(T)
- ---> screen_ok(T, message_update)
- ; screen_maybe_destroyed(T, message_update).
- % The screen may have been destroyed during a call and must
- % be recreated by the caller.
+ ---> screen_transition(T, message_update).
+ % The caller needs to account for the screen being resized
+ % during the call.
+
+:- type screen_resized
+ ---> yes
+ ; no.
:- pred create_screen(screen::uo, io::di, io::uo) is det.
-:- pred destroy_screen(screen::in, io::di, io::uo) is det.
+:- pred replace_screen_for_resize(screen::in, screen::out, io::di, io::uo)
+ is det.
+
+:- pred fast_forward_screen(screen::in, screen::out, screen_resized::out,
+ io::di, io::uo) is det.
:- pred get_cols(screen::in, int::out) is det.
@@ -90,17 +97,23 @@
:- import_module string_util.
-:- type screen == mutvar(real_screen).
+:- type screen == mutvar(screen_version).
-:- type real_screen
+:- type screen_version
---> screen(
rows :: int,
cols :: int,
main_panels :: list(panel),
bar_panel :: panel,
msgentry_panel :: panel
)
- ; destroyed_screen.
+ ; forward_screen(
+ % This version of the screen is obsolete,
+ % replaced by a forwarding pointer.
+ old_rows :: int,
+ old_cols :: int,
+ fwd_screen :: screen
+ ).
:- inst real_screen
---> screen(ground, ground, ground, ground, ground).
@@ -132,19 +145,58 @@ impure new_mutvar(RealScreen, Screen)
%-----------------------------------------------------------------------------%
-destroy_screen(Screen, !IO) :-
+replace_screen_for_resize(Screen0, Screen, !IO) :-
promise_pure (
- impure get_mutvar(Screen, RealScreen),
+ impure destroy_screen(Screen0, OldRows, OldCols, !IO),
+ create_screen(Screen, !IO),
+ % Replace Screen0 by a forwarding pointer.
+ impure set_mutvar(Screen0, forward_screen(OldRows, OldCols, Screen))
+ ).
+
+:- impure pred destroy_screen(screen::in, int::out, int::out, io::di, io::uo)
+ is det.
+
+destroy_screen(Screen, OldRows, OldCols, !IO) :-
+ impure get_mutvar(Screen, ScreenVersion),
+ (
+ ScreenVersion = screen(OldRows, OldCols, MainPanels, BarPanel,
+ MsgEntryPanel),
+ % impure set_mutvar(Screen, destroyed_screen),
+ list.foldl(panel.delete, [BarPanel, MsgEntryPanel | MainPanels], !IO)
+ ;
+ ScreenVersion = forward_screen(_, _, _),
+ unexpected($module, $pred, "screen already destroyed")
+ ).
+
+%-----------------------------------------------------------------------------%
+
+fast_forward_screen(Screen0, Screen, Resized, !IO) :-
+ promise_pure (
+ impure get_mutvar(Screen0, ScreenVersion),
(
- RealScreen = screen(_, _, MainPanels, BarPanel, MsgEntryPanel),
- impure set_mutvar(Screen, destroyed_screen),
- list.foldl(panel.delete, [BarPanel, MsgEntryPanel | MainPanels],
- !IO)
+ ScreenVersion = screen(_, _, _, _, _),
+ Screen = Screen0,
+ Resized = no
;
- RealScreen = destroyed_screen
+ ScreenVersion = forward_screen(OldRows, OldCols, Screen1),
+ impure fast_forward_screen_2(Screen1, Screen, Rows, Cols),
+ Resized = ( Rows = OldRows, Cols = OldCols -> yes ; no )
)
).
+:- impure pred fast_forward_screen_2(screen::in, screen::out,
+ int::out, int::out) is det.
+
+fast_forward_screen_2(Screen0, Screen, Rows, Cols) :-
+ impure get_mutvar(Screen0, ScreenVersion),
+ (
+ ScreenVersion = screen(Rows, Cols, _, _, _),
+ Screen = Screen0
+ ;
+ ScreenVersion = forward_screen(_, _, Screen1),
+ impure fast_forward_screen_2(Screen1, Screen, Rows, Cols)
+ ).
+
%-----------------------------------------------------------------------------%
get_cols(Screen, Cols) :-
@@ -172,15 +224,15 @@ impure set_mutvar(Screen, destroyed_screen),
get_real_screen(Screen, RealScreen),
MsgEntryPanel = RealScreen ^ msgentry_panel.
-:- pred get_real_screen(screen::in, real_screen::out(real_screen)) is det.
+:- pred get_real_screen(screen::in, screen_version::out(real_screen)) is det.
get_real_screen(Screen, RealScreen) :-
promise_pure (
impure get_mutvar(Screen, RealScreen),
(
RealScreen = screen(_, _, _, _, _)
;
- RealScreen = destroyed_screen,
+ RealScreen = forward_screen(_, _, _),
unexpected($module, $pred, "screen already destroyed")
)
).
View
@@ -164,7 +164,7 @@
update_message(Screen, set_info(Msg), !IO),
thread_pager_loop(Screen, Info1, Info, !IO),
get_effects(Info, Effects),
- Transition = screen_maybe_destroyed(Effects, no_change),
+ Transition = screen_transition(Effects, no_change),
CommonHistory = Info ^ tp_common_history.
:- pred reopen_thread_pager(screen::in,
@@ -306,10 +306,11 @@
Line = LineB
).
-:- pred resize_thread_pager(int::in, int::in,
+:- pred resize_thread_pager(screen::in,
thread_pager_info::in, thread_pager_info::out) is det.
-resize_thread_pager(Rows, _Cols, !Info) :-
+resize_thread_pager(Screen, !Info) :-
+ get_rows_cols(Screen, Rows, _Cols),
Scrollable0 = !.Info ^ tp_scrollable,
compute_num_rows(Rows, Scrollable0, NumThreadRows, NumPagerRows),
( get_cursor(Scrollable0, Cursor) ->
@@ -546,26 +547,18 @@
%-----------------------------------------------------------------------------%
-:- pred recreate_screen(screen::in, screen::out,
- thread_pager_info::in, thread_pager_info::out, io::di, io::uo) is det.
-
-recreate_screen(Screen0, Screen, !Info, !IO) :-
- destroy_screen(Screen0, !IO),
- create_screen(Screen, !IO),
- get_rows_cols(Screen, Rows, Cols),
- resize_thread_pager(Rows, Cols, !Info).
-
:- pred handle_screen_transition(screen::in, screen::out,
screen_transition(T)::in, T::out,
thread_pager_info::in, thread_pager_info::out, io::di, io::uo) is det.
handle_screen_transition(Screen0, Screen, Transition, T, !Info, !IO) :-
+ Transition = screen_transition(T, MessageUpdate),
+ fast_forward_screen(Screen0, Screen, Resized, !IO),
(
- Transition = screen_ok(T, MessageUpdate),
- Screen = Screen0
+ Resized = yes,
+ resize_thread_pager(Screen, !Info)
;
- Transition = screen_maybe_destroyed(T, MessageUpdate),
- recreate_screen(Screen0, Screen, !Info, !IO)
+ Resized = no
),
update_message(Screen, MessageUpdate, !IO).
@@ -594,7 +587,8 @@
thread_pager_loop(Screen, !Info, !IO)
;
Action = resize,
- recreate_screen(Screen, NewScreen, !Info, !IO),
+ replace_screen_for_resize(Screen, NewScreen, !IO),
+ resize_thread_pager(NewScreen, !Info),
thread_pager_loop(NewScreen, !Info, !IO)
;
Action = start_reply(Message, ReplyKind),

0 comments on commit 5cfa8e7

Please sign in to comment.