Skip to content

Commit

Permalink
Do not crash on stale hotkeys
Browse files Browse the repository at this point in the history
Hotkeys could have been created in ancient version of Wings or
in a plug-in that is now disabled. It is annyoying to get a
crash dump if you use a stale hotkey.

Therefore, if a command that is initiatied by a hotkey fails
in any way, show a dialog box asking the user what to do.
In the dialog box we allow the user to ignore the error or to
delete the offending hotkey. (We do not give a "Crash Dump"
dump button, because it seems strange to generate a crash
dump later than the actual error occurred.)

To handle the related problem that repeating a command may
cause a crash because a plug-in has been disabled, have the
plug-in manager delete the last repeatable command (so that
it cannot be repeated) if any plug-in was enabled or disabled.

Handle stale hotkeys in Tweak mode in the same way.

AutoUV does not yet handle stale hotkeys.
  • Loading branch information
bjorng committed Jun 13, 2009
1 parent d3e8251 commit 6f9cd6a
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 72 deletions.
3 changes: 3 additions & 0 deletions NOTES-1.1
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
turning on/off multisampling if the OpenGL implementation does
not support it. [bjorng]

- If a command executed through a hotkey causes an error,
a dialog box with some help will be shown. [bjorng]

--- 1.1.2 --------------------------------------------------------------------
- Select Similar Normals with the option Connected Faces Only and
a selection comprising multiple objects would cause a crash.
Expand Down
77 changes: 46 additions & 31 deletions plugins_src/commands/wpc_tweak.erl
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ handle_tweak_event0(#keyboard{unicode=C}=Ev, #tweak{tmode=wait,st=St0}=T) ->
next ->
keep;
Action ->
handle_tweak_event2({action,Action},T#tweak{st=St})
handle_tweak_event2({action,Action}, Ev, T#tweak{st=St})
end;
T1 -> update_tweak_handler(T1)
end;
Expand Down Expand Up @@ -493,19 +493,19 @@ handle_tweak_event1(#mousebutton{button=3,state=?SDL_RELEASED,x=X,y=Y},
end;

handle_tweak_event1(Ev,T) ->
handle_tweak_event2(Ev,T).
handle_tweak_event2(Ev, none, T).

handle_tweak_event2(init_opengl, #tweak{st=St}) ->
handle_tweak_event2(init_opengl, _, #tweak{st=St}) ->
wings:init_opengl(St),
keep;
handle_tweak_event2(quit=Ev, T) ->
handle_tweak_event2(quit=Ev, _, T) ->
wings_wm:later(Ev),
exit_tweak(T);

handle_tweak_event2({current_state,St}, T) ->
handle_tweak_event2({current_state,St}, _, T) ->
update_tweak_handler(T#tweak{st=St});

handle_tweak_event2({new_state,St1}, #tweak{st=St0}=T) ->
handle_tweak_event2({new_state,St1}, _, #tweak{st=St0}=T) ->
St2 = clear_temp_sel(St1),
St3 = wings_undo:save(St0, St2),
St = case St3 of
Expand All @@ -514,13 +514,13 @@ handle_tweak_event2({new_state,St1}, #tweak{st=St0}=T) ->
end,
update_tweak_handler(T#tweak{st=St});

handle_tweak_event2({action,Action}, #tweak{tmode=wait,st=#st{}=St0}=T) ->
handle_tweak_event2({action,Action}, Ev, #tweak{tmode=wait,st=#st{}=St0}=T) ->
Hs = wings_pref:get_value(hilite_select),
case Action of
{view,highlight_aim} ->
{Cmd,_} = wings:highlight_aim_setup(St0),
St = wings_view:command(Cmd,St0),
do_cmd(Cmd, T#tweak{st=St});
do_cmd(Cmd, Ev, T#tweak{st=St});
{edit,undo_toggle} ->
St = wings_u:caption(wings_undo:undo_toggle(clear_temp_sel(St0))),
update_tweak_handler(T#tweak{st=St});
Expand All @@ -539,24 +539,23 @@ handle_tweak_event2({action,Action}, #tweak{tmode=wait,st=#st{}=St0}=T) ->
{select,all}=Cmd when Hs -> hotkey_select_setup(Cmd,T);
{select, C}=Cmd when C==vertex;C==edge;C==face;C==body ->
St = clear_temp_sel(St0),
do_cmd(Cmd,T#tweak{st=St});
do_cmd(Cmd, Ev, T#tweak{st=St});
{select, {adjacent,_}}=Cmd ->
St = clear_temp_sel(St0),
do_cmd(Cmd,T#tweak{st=St});
do_cmd(Cmd, Ev, T#tweak{st=St});
{file,_}=Cmd ->
St = clear_temp_sel(St0),
do_cmd(Cmd,T#tweak{st=St});
do_cmd(Cmd, Ev, T#tweak{st=St});
keep -> keep;
Cmd ->
do_cmd(Cmd, T)
Cmd -> do_cmd(Cmd, Ev, T)
end;
handle_tweak_event2(close, _) ->
handle_tweak_event2(close, _, _) ->
% Close a second geometry window
Active = wings_wm:this(),
wings_wm:delete({object,Active}),
delete;

handle_tweak_event2(_, _) ->
handle_tweak_event2(_, _, _) ->
keep.

%%%%
Expand Down Expand Up @@ -612,21 +611,21 @@ remember_mode(#tweak{magnet=Mag,mag_type=MagType,mag_r=MagR,
st=#st{selmode=Mode,sh=Sh}}) ->
wpa:pref_set(?MODULE, sel_mode, {Mode,Sh,Mag,MagType,MagR}).

do_cmd({tools, {tweak,false}}, #tweak{st=St}=T) ->
do_cmd({tools, {tweak,false}}, _, #tweak{st=St}=T) ->
exit_tweak(T#tweak{st=clear_temp_sel(St)});

do_cmd({tools, {tweak,true}}, #tweak{st=St}=T) ->
do_cmd({tools, {tweak,true}}, _, #tweak{st=St}=T) ->
wings_plugin:command({tools, {tweak,true}}, St),
exit_tweak(T#tweak{st=clear_temp_sel(St)});

do_cmd(Cmd, #tweak{st=#st{}=St0}=T) ->
do_cmd(Cmd, Ev, #tweak{st=#st{}=St0}=T) ->
St1 = remember_command(Cmd, St0),
case wings_plugin:command(Cmd,St1) of
next -> do_wings_cmd(Cmd,T);
next -> do_wings_cmd(Cmd, Ev, T);
Result -> process_cmd_response(Result,T)
end.

do_wings_cmd({view,Cmd}, #tweak{st=#st{}=St0}=T) ->
do_wings_cmd({view,Cmd}, _, #tweak{st=#st{}=St0}=T) ->
case wings_view:command(Cmd,St0) of
#st{}=St ->
St1 = clear_temp_sel(St),
Expand All @@ -635,15 +634,15 @@ do_wings_cmd({view,Cmd}, #tweak{st=#st{}=St0}=T) ->
Other
end;

do_wings_cmd(Cmd, #tweak{st=#st{}=St0}=T) ->
do_wings_cmd(Cmd, Ev, #tweak{st=#st{}=St0}=T) ->
St1 = remember_command(Cmd, St0),
Result = cmd_type(Cmd, St1),
Result = cmd_type(Cmd, Ev, St1),
process_cmd_response(Result,T).

process_cmd_response(Result,T) ->
case Result of
{save_state,St} ->
handle_tweak_event2({new_state,St}, T);
handle_tweak_event2({new_state,St}, none, T);
#st{}=St ->
update_tweak_handler(T#tweak{st=St});
{drag,Drag} ->
Expand All @@ -659,19 +658,35 @@ process_cmd_response(Result,T) ->
wings:save_windows(),
exit(normal);
{replace,Ev} ->
handle_tweak_event2(Ev, T);
handle_tweak_event2(Ev, none, T);
Other ->
Other
end.

cmd_type({select, Cmd}, St) -> wings_sel_cmd:command(Cmd, St#st{temp_sel=none});
cmd_type(Cmd, St) -> wings:command(Cmd, St).
cmd_type({select,Cmd}, _, St) ->
wings_sel_cmd:command(Cmd, St#st{temp_sel=none});
cmd_type(Cmd, Ev, St) ->
case Ev of
none ->
wings:command(Cmd, St);
_ ->
%% The command was obtained through a hotkey, which for all
%% we know may be from an ancient version Wings or for a
%% plug-in that has been disabled.
try
wings:command(Cmd, St)
catch
error:_ ->
wings_hotkey:handle_error(Ev, Cmd),
St#st{repeatable=ignore}
end
end.

hotkey_select_setup(Cmd,#tweak{st=St0}=T) ->
{_,X,Y} = wings_wm:local_mouse_state(),
case wings_pick:do_pick(X, Y, St0) of
{add,_,St} -> do_cmd(Cmd,T#tweak{st=St});
_Other -> do_cmd(Cmd, T)
{add,_,St} -> do_cmd(Cmd, none, T#tweak{st=St});
_Other -> do_cmd(Cmd, none, T)
end.

remember_command({C,_}=Cmd, St) when C =:= vertex; C =:= edge;
Expand Down Expand Up @@ -708,7 +723,7 @@ end_drag(#tweak{st=St0,ox=X,oy=Y}=T) ->
wings_io:ungrab(X,Y),
St = wings_dl:map(fun end_drag/2, St0),
help(T),
handle_tweak_event2({new_state,St},T#tweak{tmode=wait}).
handle_tweak_event2({new_state,St}, none, T#tweak{tmode=wait}).

end_drag(#dlo{src_we=#we{id=Id},drag=#drag{}}=D0, #st{shapes=Shs0}=St0) ->
#dlo{src_we=We} = D = wings_draw:join(D0),
Expand Down Expand Up @@ -767,14 +782,14 @@ end_pick(true, #tweak{st=#st{selmode=Selmode}=St0,ox=X,oy=Y}=T0) ->
end,
T = T0#tweak{st=St0,tmode=wait},
help(T),
handle_tweak_event2({new_state,St},T);
handle_tweak_event2({new_state,St}, none, T);

end_pick(false, #tweak{st=St0,ox=X,oy=Y}=T) ->
wings_wm:release_focus(),
wings_io:ungrab(X,Y),
St = wings_dl:map(fun end_pick_1/2, St0),
help(T),
handle_tweak_event2({new_state,St},T#tweak{tmode=wait}).
handle_tweak_event2({new_state,St}, none, T#tweak{tmode=wait}).

end_pick_1(#dlo{mirror=M,ns=Ns,proxy_data=Pd,src_we=We},St0) ->
{#dlo{ns=Ns,mirror=M,proxy_data=Pd,src_we=We},St0}.
Expand Down
83 changes: 53 additions & 30 deletions src/wings.erl
Original file line number Diff line number Diff line change
Expand Up @@ -317,13 +317,13 @@ handle_event_2(Ev, St) -> handle_event_3(Ev, St).

handle_event_3(#keyboard{}=Ev, St0) ->
case do_hotkey(Ev, St0) of
next -> keep;
{Cmd,St} -> do_command(Cmd, St)
next -> keep;
{Cmd,St} -> do_command(Cmd, Ev, St)
end;
handle_event_3({action,Callback}, _) when is_function(Callback) ->
Callback();
handle_event_3({action,Cmd}, St) ->
do_command(Cmd, St);
do_command(Cmd, none, St);
handle_event_3({vec_command,Command,St}, _) when is_function(Command) ->
%% Use to execute command with vector arguments (see wings_vec.erl).
command_response(Command(), none, St);
Expand All @@ -346,8 +346,8 @@ handle_event_3(redraw, St) ->
main_loop_noredraw(St);
handle_event_3(quit, St) ->
case wings_wm:this() of
geom -> do_command({file,quit}, St);
_ -> keep
geom -> do_command({file,quit}, none, St);
_ -> keep
end;
handle_event_3({new_state,St}, St0) ->
save_state(St0, St);
Expand Down Expand Up @@ -470,14 +470,47 @@ highlight_sel_style({view,frame}) -> temporary;

highlight_sel_style(_) -> none.

do_command(Cmd, St0) ->
do_command(Cmd, Event, St0) ->
St = remember_command(Cmd, St0),
{replace,
fun(Ev) -> handle_event(Ev, St) end,
fun() -> raw_command(Cmd, none, St) end}.
fun() -> raw_command(Cmd, none, Event, St) end}.

raw_command(Cmd, Args, St) ->
command_response(do_command_1(Cmd, St), Args, St).
raw_command(Cmd, Args, none, St).

raw_command(Cmd, Args, Event, St) ->
command_response(raw_command_1(Cmd, Event, St), Args, St).

raw_command_1(Cmd, Event, St0) ->
case wings_plugin:command(Cmd, St0#st{last_cmd=Cmd}) of
next ->
%% Time the command if command timing is enabled,
%% or just execute the command.
Execute = fun() ->
execute_command(Cmd, Event, St0)
end,
wings_develop:time_command(Execute, Cmd);
St0 -> St0;
#st{}=St -> {save_state,St};
Other -> Other
end.

execute_command(Cmd, none, St) ->
%% The command was obtained directly from a menu.
%% It it not allowed to fail.
command(Cmd, St);
execute_command(Cmd, Ev, St) ->
%% The command was obtained through a hotkey, which for all
%% we know may be from an ancient version Wings or for a
%% plug-in that has been disabled.
try
command(Cmd, St)
catch
error:_ ->
wings_hotkey:handle_error(Ev, Cmd),
St#st{repeatable=ignore}
end.

command_response(#st{}=St, _, _) ->
main_loop(clear_temp_sel(St));
Expand Down Expand Up @@ -505,16 +538,6 @@ command_response(quit, _, _) ->
save_windows(),
exit(normal).

do_command_1(Cmd, St0) ->
case wings_plugin:command(Cmd, St0#st{last_cmd=Cmd}) of
next ->
%% Time the command if command timing is enabled.
wings_develop:time_command(fun command/2, Cmd, St0);
St0 -> St0;
#st{}=St -> {save_state,St};
Other -> Other
end.

remember_command({C,_}=Cmd, St) when C =:= vertex; C =:= edge;
C =:= face; C =:= body ->
St#st{repeatable=Cmd,ask_args=none,drag_args=none};
Expand Down Expand Up @@ -592,28 +615,28 @@ command_1({file,Command}, St) ->
command_1({edit,repeat}, #st{sel=[]}=St) -> St;
command_1({edit,repeat}, #st{selmode=Mode,repeatable=Cmd0}=St) ->
case repeatable(Mode, Cmd0) of
no -> keep;
Cmd when is_tuple(Cmd) -> raw_command(Cmd, none, St)
no -> keep;
Cmd when is_tuple(Cmd) -> raw_command(Cmd, true, St)
end;
command_1({edit,repeat}, St) -> St;
command_1({edit,repeat_args}, #st{sel=[]}=St) -> St;
command_1({edit,repeat_args}, #st{selmode=Mode,repeatable=Cmd0,
ask_args=AskArgs}=St) ->
ask_args=AskArgs}=St) ->
case repeatable(Mode, Cmd0) of
no -> keep;
Cmd1 when is_tuple(Cmd1) ->
Cmd = replace_ask(Cmd1, AskArgs),
raw_command(Cmd, none, St)
no -> keep;
Cmd1 when is_tuple(Cmd1) ->
Cmd = replace_ask(Cmd1, AskArgs),
raw_command(Cmd, none, St)
end;
command_1({edit,repeat_args}, St) -> St;
command_1({edit,repeat_drag}, #st{sel=[]}=St) -> St;
command_1({edit,repeat_drag}, #st{selmode=Mode,repeatable=Cmd0,
ask_args=AskArgs,drag_args=DragArgs}=St) ->
ask_args=AskArgs,drag_args=DragArgs}=St) ->
case repeatable(Mode, Cmd0) of
no -> keep;
Cmd1 when is_tuple(Cmd1) ->
Cmd = replace_ask(Cmd1, AskArgs),
raw_command(Cmd, DragArgs, St)
no -> keep;
Cmd1 when is_tuple(Cmd1) ->
Cmd = replace_ask(Cmd1, AskArgs),
raw_command(Cmd, DragArgs, St)
end;
command_1({edit,repeat_drag}, St) -> St;
command_1({edit,purge_undo}, St) ->
Expand Down
8 changes: 4 additions & 4 deletions src/wings_develop.erl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

-module(wings_develop).
-export([init/0,menu/1,command/2,
time_command/3,gl_error_check/1]).
time_command/2,gl_error_check/1]).

-include("wings.hrl").

Expand Down Expand Up @@ -58,15 +58,15 @@ command(print_scene_size, St) ->
io:format("The current scene is using ~p words\n", [Words]),
keep.

time_command(CmdFun, Cmd, St) ->
time_command(CmdFun, Cmd) ->
case wings_pref:get_value(develop_time_commands, false) of
false ->
Res = CmdFun(Cmd, St),
Res = CmdFun(),
gl_error_check(Cmd),
Res;
true ->
Before = erlang:now(),
Res = CmdFun(Cmd, St),
Res = CmdFun(),
After = erlang:now(),
Time = timer:now_diff(After, Before),
Str = format_time(Time),
Expand Down
Loading

0 comments on commit 6f9cd6a

Please sign in to comment.