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 + -
显示快捷键?