pman_main.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 787 行 · 第 1/2 页
ERL
787 行
%% ``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(pman_main).%% Main process and window-export([init/2]).-record(state, {win, % GS top window frame, % GS top frame grid, % GS process info grid size, % int() No. of displayed procs w, % int() Window width h, % int() Window height hide_system=false, % bool() Auto-hide system procs hide_new=false, % bool() Auto-hide new processes hide_modules, % ordset() Excluded modules hide_all=[], % [{node(), bool()}] Hide all hide_pids=[], % [{node(), Ordset}] Processes % explicitly to hide, per node show_pids=[], % [{node(), Ordset}] Processes % explicitly to show, per node shown_pids=[], % [{node(), Ordset}] Processes % actually shown, per node node, % node() Current node nodes=[], % [node()] All known nodes focus=1, % int() Grid line with focus focus_pid=undefined, % pid() | undefined Proc in focus noshell, % bool() Noshell mode on options}). % term() Trace options settings-include("pman_win.hrl").-define(REFRESH_TIME,5000).-define(REQUIRES_FOCUS, % List of menus that should ['Trace Process', % be disabled if no process 'Kill', % is in focus 'Hide Selected Process', 'Module']).%%--Process init and loop-----------------------------------------------init(PidCaller, OSModuleExcluded) -> process_flag(trap_exit, true), %% Monitor all nodes in a distributed system case is_alive() of %% We have a distributed system true -> net_kernel:monitor_nodes(true); %% No distribution false -> ignore end, Nodes = [node()|nodes()], %% Create the main window %% For some extremely strange reason, the frame must be resized %% or the grid won't be visible... GridSize = length(processes()) + 61, {Window, Grid, Frame, Visible, W, H} = pman_win:pman_window(GridSize, OSModuleExcluded, Nodes), gse:resize(Frame, ?WIN_WIDTH, ?WIN_HEIGHT-?MENU_HEIGHT), Noshell = case pman_shell:find_shell() of noshell -> true; _ -> false end, State1 = #state{win=Window, frame=Frame, grid=Grid, size=Visible, w=W, h=H, hide_modules=OSModuleExcluded, node=node(), noshell=Noshell}, State2 = lists:foldl(fun(Node, State) -> add_node(Node, State) end, State1, Nodes), State3 = refresh(State2), %% Notify caller that the process appears %% to have been started. PidCaller ! {initialization_complete, self()}, %% Initiate a 'catch all' trace pattern so call tracing works erlang:trace_pattern({'_', '_', '_'}, true, [local]), %% Read default options file Options = restore_options(State3), loop(State3#state{options=Options}).add_node(Node, State) -> pman_win:add_menu(node, [Node], "Show"), State#state{hide_all=nl_update(Node, false, State#state.hide_all), hide_pids=nl_update(Node, [], State#state.hide_pids), show_pids=nl_update(Node, [], State#state.show_pids), shown_pids=nl_update(Node, [], State#state.shown_pids), nodes=[Node|State#state.nodes]}.%% Restore saved options from default filerestore_options(State)-> File = options_file(), case pman_options:read_from_file(File) of {ok, Options} -> Options; {error, ReasonStr, DefOptions} -> Parent = State#state.win, Msg = io_lib:format( "Problems reading default option file~n~s:~n~s", [File, ReasonStr]), tool_utils:notify(Parent, Msg), DefOptions end.options_file() -> {ok, [[Home]]} = init:get_argument(home), filename:join([Home, ".erlang_tools", "pman.opts"]).loop(State) -> receive {nodeup, Node} -> case nl_exists(Node, State#state.hide_all) of true -> pman_win:add_menu(node, [Node], "Show"), loop(State#state{nodes=[Node|State#state.nodes]}); false -> loop(add_node(Node, State)) end; {nodedown, Node} -> pman_win:remove_menu([Node]), Msg = io_lib:format("Node~n~p~ndown.", [Node]), spawn_link(tool_utils, notify, [State#state.win, Msg]), %% We remove Node from the list of nodes but not from %% the other lists of State, in case Node reappears later Nodes = lists:delete(Node, State#state.nodes), State2 = State#state{nodes=Nodes}, %% If it was the shown node that went down, %% change overview to this node if Node==State#state.node -> State3 = execute_cmd({node,node()}, State2, [], []), loop(State3); true -> loop(State2) end; %% Ignore EXIT signals from help processes {'EXIT', _Pid, _Reason} -> loop(State); %% GS events {gs, _Obj, _Event, _Data, _Args} = Cmd -> case gs_cmd(Cmd, State) of stop -> exit(topquit); State2 -> loop(State2) end after ?REFRESH_TIME -> State2 = refresh(State), loop(State2) end.%% gs_cmd(Event, State) -> stop | State'gs_cmd(Event, State) -> case Event of %% --- Window manager commands --- %% Window is moved or resized {gs, _, configure, _Data, Args} -> configure(Args, State); %% Window closed, stop Pman {gs, _, destroy, _, _} -> stop; %% --- Dynamic commands --- %% Click in any object where the GS Data field is a 2-tuple {gs, _, click, Data, Args} when is_tuple(Data), size(Data)==2 -> execute_cmd(Data, State, [], Args); %% Single click in the grid sets focus to selected process {gs, _, click, {pidfunc,_,_}, [_,Row|_]} when is_integer(Row) -> focus(Row, State); %% Double click in the grid starts tracing of selected process {gs, _, doubleclick, {pidfunc,_,_}, [_Col,Row| _]} when is_integer(Row) -> execute_cmd('Trace Process', State, [], []); %% Click in named GS objects {gs, Cmd, click, Data, Args} when is_atom(Cmd); is_atom(element(1, Cmd)) -> execute_cmd(Cmd, State, Data, Args); %% --- Keyboard accelerator commands --- %% Move focus up and down {gs, _, keypress, [], ['Up',_,0,0]} -> execute_cmd(focus_previous, State, [], []); {gs, _, keypress, [], ['Down',_,0,0]} -> execute_cmd(focus_next, State, [], []); %% Other keyboard shortcuts {gs, _, keypress, [], ['Return',_,0,0]} -> execute_cmd('Trace Process', State, [], []); {gs, _, keypress, [], [Key,_,0,1]} -> execute_cmd(shortcut(Key), State, [], []); %% Ignore all other GS events _Other -> State end.%% Keyboard shortcuts%% File menushortcut(o) -> 'Default Options';shortcut(e) -> 'Exit';shortcut(z) -> 'Exit';%% View menushortcut(i) -> 'Hide All';shortcut(u) -> 'Hide Modules';shortcut(d) -> 'Hide Selected Process';shortcut(m) -> 'Module';shortcut(r) -> 'Refresh';%% Trace menushortcut(k) -> 'Kill';shortcut(t) -> 'Trace Process';shortcut(s) -> 'Trace Shell';%% Help menushortcut(h) -> 'Help';%% Keyboard command onlyshortcut(l) -> 'All Links';%% Process grid traversalshortcut(p) -> focus_previous;shortcut(n) -> focus_next;shortcut(_) -> dummy.%% configure([W,H,X,Y|_], State) -> State'%% Window has been moved or resizedconfigure([W,H|_], State) -> if W==State#state.w, H==State#state.h -> ignore; true -> gse:resize(State#state.frame, W, H-?MENU_HEIGHT), Grid = State#state.grid, case abs(W - gs:read(Grid,width) - 6) of 0 -> ok; %% Avoid refreshing width if possible _Anything -> Cols = pman_win:calc_columnwidths(W-6), gs:config(Grid, Cols) end, pman_win:configwin(Grid, W, H) end, State.%% focus(Row, State) -> State'%% Row = int() Grid row%% User has selected a row in the grid.%% Row==1 means header row.focus(Row, State) -> Pid = case get_pid_in_focus(Row, State#state.grid) of {true, {pidfunc,Pid0,_}} -> pman_win:change_colour(State#state.grid, State#state.focus, Row), enable_pid_actions(), Pid0; false -> disable_pid_actions(), undefined end, State#state{focus=Row, focus_pid=Pid}.%% get_pid_in_focus(Row, Grid) -> {true, Data} | false%% Data = {pidfunc, Pid, Func}%% Func = {Mod,Name,Arity} | term()%% Return the data associated with the process in focus if there is one,get_pid_in_focus(1, _Grid) -> false;get_pid_in_focus(Row, Grid) -> case gs:read(Grid, {obj_at_row,Row}) of undefined -> false; GridLine -> Data = gs:read(GridLine, data), {true, Data} end.%% execute_cmd(Cmd, State, Data, Args) -> stop | State'%% Checkbutton "Hide System Processes"execute_cmd('Hide System', State, _Data, Args) -> [_Text, _Group, Bool|_Rest] = Args, State2 = State#state{hide_system=Bool}, refresh(State2);%% Checkbutton "Auto-Hide New"execute_cmd('Auto Hide New', State, _Data, Args ) -> [_Text, _Group, Bool|_Rest] = Args, refresh(State#state{hide_new=Bool});%% File->Options...execute_cmd('Default Options', State, _Data, _Args) -> OldOptions = State#state.options, NewOptions = pman_options:dialog(State#state.win, "Default Trace Options", OldOptions), case NewOptions of {error, _Reason} -> State; Options -> State#state{options=Options} end;%% File->Save Options%% Save the set default options to the user's option fileexecute_cmd('Save Options', State, _Data, _Args)-> Options = State#state.options, File = options_file(), Parent = State#state.win, case pman_options:save_to_file(Options, File) of ok -> tool_utils:notify(Parent, "Options saved to\n" ++ File); {error, ReasonStr} -> Msg = io_lib:format("Could not save options to~n~s:~n~s", [File, ReasonStr]), tool_utils:notify(Parent, Msg) end, State;%% File->Exit%% Exit the applicationexecute_cmd('Exit', _State, _Data, _Args) -> stop;%% View->Hide All Processesexecute_cmd('Hide All', State, _Data, _Args) -> Node = State#state.node, HideAll = nl_update(Node, true, State#state.hide_all), ShowPids = nl_del_all(State#state.node, State#state.show_pids), State2 = State#state{hide_all=HideAll, show_pids=ShowPids}, refresh(State2, true);%% View->Hide modules...%% Opens a dialog where the user can select from a list of %% the loaded modules.%% The selected module is added to the list of hidden modules.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?