dbg_ui_mon.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 744 行 · 第 1/2 页
ERL
744 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1,(the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(dbg_ui_mon).-include_lib("kernel/include/file.hrl").%% External exports-export([start/2, stop/0]).-define(TRACEWIN, ['Button Area', 'Evaluator Area', 'Bindings Area']).-define(BACKTRACE, 100).-record(pinfo, {pid, % pid() status % break | exit | idle | running | waiting }).-record(state, {mode, % local | global starter, % bool() 'true' if int was started by me gs, % term() Graphics system id win, % term() Monitor window data focus, % undefined | #pinfo{} Process in focus coords, % {X,Y} Mouse pointer position intdir, % string() Default dir pinfos, % [#pinfo{}] Debugged processes tracewin, % [Area] Areas shown in trace window backtrace, % integer() Number of call frames to fetch attach, % false | {Flags, Function} sfile, % default | string() Settings file changed % boolean() Settings have been changed }). %%====================================================================%% External exports%%====================================================================%%--------------------------------------------------------------------%% start(Mode, SFile) -> {ok, Pid} | {error, Reason}%% Mode = local | global%% SFile = string() | default Settings file%% Pid = pid()%% Reason = {already_started,Pid} | term()%%--------------------------------------------------------------------start(Mode, SFile) -> case whereis(?MODULE) of undefined -> CallingPid = self(), Pid = spawn(fun () -> init(CallingPid, Mode, SFile) end), receive {initialization_complete, Pid} -> {ok, Pid}; Error -> Error end; Pid -> {error, {already_started,Pid}} end.%%--------------------------------------------------------------------%% stop() -> ok%%--------------------------------------------------------------------stop() -> case whereis(?MODULE) of undefined -> ok; Pid -> Flag = process_flag(trap_exit, true), link(Pid), Pid ! stop, receive {'EXIT', Pid, stop} -> process_flag(trap_exit, Flag), ok end end.%%====================================================================%% Initialization%%====================================================================init(CallingPid, Mode, SFile) -> register(?MODULE, self()), %% Graphics system case catch dbg_ui_mon_win:init() of {'EXIT', Reason} -> CallingPid ! {error, Reason}; GS -> init2(CallingPid, Mode, SFile, GS) end.init2(CallingPid, Mode, SFile, GS) -> %% Start Int if necessary and subscribe to information from it Bool = case int:start() of {ok, _Int} -> true; {error, {already_started, _Int}} -> false end, int:subscribe(), %% Start other necessary stuff dbg_ui_winman:start(), % Debugger window manager %% Create monitor window Title = "Monitor", Win = dbg_ui_mon_win:create_win(GS, Title, menus()), Window = dbg_ui_mon_win:get_window(Win), dbg_ui_winman:insert(Title, Window), %% Initial process state State1 = #state{mode = Mode, starter = Bool, gs = GS, win = Win, focus = undefined, coords = {0,0}, intdir = element(2, file:get_cwd()), pinfos = [], sfile = SFile, changed = false }, State2 = init_options(?TRACEWIN, % Trace Window int:auto_attach(), % Auto Attach int:stack_trace(), % Stack Trace ?BACKTRACE, % Back Trace Size State1), State3 = init_contents(int:interpreted(), % Modules int:all_breaks(), % Breakpoints int:snapshot(), % Processes State2), %% Disable/enable functionality according to process in focus (none) gui_enable_functions(State3#state.focus), CallingPid ! {initialization_complete, self()}, if SFile==default -> loop(State3); true -> loop(load_settings(SFile, State3)) end.init_options(TraceWin, AutoAttach, StackTrace, BackTrace, State) -> lists:foreach(fun(Area) -> dbg_ui_mon_win:select(Area, true) end, TraceWin), case AutoAttach of false -> ignore; {Flags, _Function} -> dbg_ui_mon_win:show_option(State#state.win, auto_attach, Flags), lists:foreach(fun(Flag) -> dbg_ui_mon_win:select(map(Flag), true) end, Flags) end, dbg_ui_mon_win:show_option(State#state.win, stack_trace, StackTrace), dbg_ui_mon_win:select(map(StackTrace), true), dbg_ui_mon_win:show_option(State#state.win, back_trace, BackTrace), State#state{tracewin=TraceWin, backtrace=BackTrace}.init_contents(Mods, Breaks, Processes, State) -> Win2 = lists:foldl(fun(Mod, Win) -> dbg_ui_mon_win:add_module(Win,'Module',Mod) end, State#state.win, Mods), Win3 = lists:foldl(fun(Break, Win) -> dbg_ui_mon_win:add_break(Win,'Break',Break) end, Win2, Breaks), lists:foldl(fun(PidTuple, State0) -> int_cmd({new_process, PidTuple}, State0) end, State#state{win=Win3}, Processes).%%====================================================================%% Main loop and message handling%%====================================================================loop(State) -> receive stop -> gui_cmd(stopped, State); %% From the GUI GuiEvent when is_tuple(GuiEvent), element(1, GuiEvent)==gs -> Cmd = dbg_ui_mon_win:handle_event(GuiEvent,State#state.win), State2 = gui_cmd(Cmd, State), loop(State2); %% From the interpreter process {int, Cmd} -> State2 = int_cmd(Cmd, State), loop(State2); %% From the dbg_ui_interpret process {dbg_ui_interpret, Dir} -> loop(State#state{intdir=Dir}); %% From the dbg_ui_edit process {dbg_ui_edit, 'Backtrace:', BackTrace} -> dbg_ui_mon_win:show_option(State#state.win, back_trace, BackTrace), loop(State#state{backtrace=BackTrace}); %% From the dbg_ui_settings process {dbg_ui_settings, SFile, Action} -> State2 = case Action of load -> load_settings(SFile, State); save -> save_settings(SFile, State) end, loop(State2); %% From the dbg_ui_winman process (Debugger window manager) {dbg_ui_winman, update_windows_menu, Data} -> dbg_ui_winman:update_windows_menu(Data), loop(State) end.%%--Commands from the GUI---------------------------------------------%% Act upon a command from the GUI. In most cases, it is only necessary%% to call a relevant int-function. int will then report when the action%% has been taken.gui_cmd(ignore, State) -> State;gui_cmd(stopped, State) -> if State#state.starter==true -> int:stop(); true -> int:auto_attach(false) end, exit(stop);gui_cmd({coords, Coords}, State) -> State#state{coords=Coords};gui_cmd({shortcut, Key}, State) -> case shortcut(Key) of {always, Cmd} -> gui_cmd(Cmd, State); {if_enabled, Cmd} -> case dbg_ui_mon_win:is_enabled(Cmd) of true -> gui_cmd(Cmd, State); false -> State end; false -> State end;%% File Menugui_cmd('Load Settings...', State) -> Window = dbg_ui_mon_win:get_window(State#state.win), dbg_ui_settings:start(Window, State#state.coords, load, State#state.sfile), State;gui_cmd('Save Settings...', State) -> Window = dbg_ui_mon_win:get_window(State#state.win), dbg_ui_settings:start(Window, State#state.coords, save, State#state.sfile), State;gui_cmd('Exit', State) -> gui_cmd(stopped, State);%% Edit Menugui_cmd('Refresh', State) -> int:clear(), Win = dbg_ui_mon_win:clear_processes(State#state.win), gui_enable_functions(undefined), State2 = State#state{win=Win, focus=undefined, pinfos=[]}, lists:foldl(fun(PidTuple, S) -> int_cmd({new_process,PidTuple}, S) end, State2, int:snapshot());gui_cmd('Kill All', State) -> lists:foreach(fun(PInfo) -> case PInfo#pinfo.status of exit -> ignore; _Status -> exit(PInfo#pinfo.pid, kill) end end, State#state.pinfos), State;%% Module Menugui_cmd('Interpret...', State) -> dbg_ui_interpret:start(State#state.gs, State#state.coords, State#state.intdir, State#state.mode), State;gui_cmd('Delete All Modules', State) -> lists:foreach(fun(Mod) -> int:nn(Mod) end, int:interpreted()), State;gui_cmd({module, Mod, What}, State) -> case What of delete -> int:nn(Mod); view -> dbg_ui_view:start(State#state.gs, Mod) end, State;%% Process Menugui_cmd('Step', State) -> int:step((State#state.focus)#pinfo.pid), State;gui_cmd('Next', State) -> int:next((State#state.focus)#pinfo.pid), State;gui_cmd('Continue', State) -> int:continue((State#state.focus)#pinfo.pid), State;gui_cmd('Finish ', State) -> int:finish((State#state.focus)#pinfo.pid), State;gui_cmd('Attach', State) -> Pid = (State#state.focus)#pinfo.pid, case dbg_ui_winman:is_started(dbg_ui_trace:title(Pid)) of true -> ignore; false -> int:attach(Pid, trace_function(State)) end, State;gui_cmd('Kill', State) -> exit((State#state.focus)#pinfo.pid, kill), State;%% Break Menugui_cmd('Line Break...', State) -> dbg_ui_break:start(State#state.gs, State#state.coords, line), State;gui_cmd('Conditional Break...', State) -> dbg_ui_break:start(State#state.gs, State#state.coords, conditional), State;gui_cmd('Function Break...', State) -> dbg_ui_break:start(State#state.gs, State#state.coords, function), State;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?