aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/observer/src/observer_lib.erl26
-rw-r--r--lib/observer/src/observer_pro_wx.erl22
-rw-r--r--lib/observer/src/observer_procinfo.erl644
-rw-r--r--lib/observer/src/observer_sys_wx.erl17
-rw-r--r--lib/observer/src/observer_wx.erl34
5 files changed, 261 insertions, 482 deletions
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index b36aaa7541..8bc79ffddd 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -21,7 +21,7 @@
-export([get_wx_parent/1,
display_info_dialog/1,
interval_dialog/4, start_timer/1, stop_timer/1,
- display_info/2, update_info/2, to_str/1,
+ display_info/2, fill_info/2, update_info/2, to_str/1,
create_menus/3, create_menu_item/3,
create_attrs/0
]).
@@ -117,6 +117,22 @@ display_info(Frame, Info) ->
wxWindow:setSizerAndFit(Panel, Sizer),
{Panel, Sizer, InfoFs}.
+fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) ->
+ [{Str, get_value(Key, Data)} | fill_info(Rest, Data)];
+fill_info([{Str, {Format, Key}}|Rest], Data)
+ when is_atom(Key); is_function(Key), is_atom(Format) ->
+ [{Str, {Format, get_value(Key,Data)}} | fill_info(Rest, Data)];
+fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) ->
+ [{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
+fill_info([{Str,Attrib,SubStructure}|Rest], Data) ->
+ [{Str, Attrib, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
+fill_info([], _) -> [].
+
+get_value(Key, Data) when is_atom(Key) ->
+ proplists:get_value(Key,Data);
+get_value(Fun, Data) when is_function(Fun) ->
+ Fun(Data).
+
update_info([Fields|Fs], [{_Header, SubStructure}| Rest]) ->
update_info2(Fields, SubStructure),
update_info(Fs, Rest);
@@ -154,9 +170,9 @@ to_str({time_ms, MS}) ->
true -> integer_to_list(S) ++ " Secs"
end;
-to_str({A, B}) ->
+to_str({A, B}) when is_atom(A), is_atom(B) ->
lists:concat([A, ":", B]);
-to_str({M,F,A}) ->
+to_str({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
lists:concat([M, ":", F, "/", A]);
to_str(Value) when is_list(Value) ->
case lists:all(fun(X) -> is_integer(X) end, Value) of
@@ -172,8 +188,8 @@ to_str(Pid) when is_pid(Pid) ->
pid_to_list(Pid);
to_str(No) when is_integer(No) ->
integer_to_list(No);
-to_str(ShouldNotGetHere) ->
- erlang:error({?MODULE, to_str, ShouldNotGetHere}).
+to_str(Term) ->
+ io_lib:format("~w", [Term]).
create_menus(Menus, MenuBar, Type) ->
Add = fun({Tag, Ms}, Index) ->
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index 8e3e28caec..4bc6da6476 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -233,14 +233,14 @@ dump_to_file(Parent, FileName, Holder) ->
wxDialog:destroy(MD)
end.
-start_procinfo(_Node, undefined, _Frame, Opened) ->
+start_procinfo(undefined, _Frame, Opened) ->
Opened;
-start_procinfo(Node, Pid, Frame, Opened) ->
+start_procinfo(Pid, Frame, Opened) ->
case lists:member(Pid, Opened) of
true ->
Opened;
false ->
- observer_procinfo:start(Node, Pid, Frame, self()),
+ observer_procinfo:start(Pid, Frame, self()),
[Pid | Opened]
end.
@@ -356,23 +356,21 @@ handle_event(#wx{id=?ID_KILL},
{noreply, State#state{sel={Ids,Pids}}};
-handle_event(#wx{id=?ID_PROC},
+handle_event(#wx{id = ?ID_PROC},
#state{panel=Panel,
popup_menu=Pop,
- holder=Holder,
sel={_, [Pid|_]},
procinfo_menu_pids=Opened}=State) ->
wxWindow:show(Pop, [{show, false}]),
- Node = call(Holder, {get_node, self()}),
- Opened2 = start_procinfo(Node, Pid, Panel, Opened),
+ Opened2 = start_procinfo(Pid, Panel, Opened),
{noreply, State#state{procinfo_menu_pids=Opened2}};
-handle_event(#wx{id=?ID_TRACEMENU},
+handle_event(#wx{id = ?ID_TRACEMENU},
#state{holder=Holder,
popup_menu=Pop,
trace_options=Options,
match_specs=MatchSpecs,
- sel=Pids,
+ sel={_, Pids},
tracemenu_opened=false,
panel=Panel}=State) ->
wxWindow:show(Pop, [{show, false}]),
@@ -471,15 +469,13 @@ handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}},
handle_event(#wx{event=#wxList{type=command_list_item_activated}},
#state{panel=Panel, procinfo_menu_pids=Opened,
- holder=Holder,
sel={_, [Pid|_]}}=State)
when Pid =/= undefined ->
- Node = call(Holder, {get_node, self()}),
- Opened2=start_procinfo(Node, Pid, Panel, Opened),
+ Opened2 = start_procinfo(Pid, Panel, Opened),
{noreply, State#state{procinfo_menu_pids=Opened2}};
handle_event(Event, State) ->
- io:format("~p~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
+ io:format("~p:~p: handle event ~p\n", [?MODULE, ?LINE, Event]),
{noreply, State}.
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 6414a26ec9..2600109161 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -20,7 +20,7 @@
-behaviour(wx_object).
--export([start/4]).
+-export([start/3]).
-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
handle_call/3, handle_info/2]).
@@ -28,452 +28,78 @@
-include_lib("wx/include/wx.hrl").
-include("observer_defs.hrl").
--define(CLOSE, 601).
--define(REFRESH, 602).
+-define(REFRESH, 601).
-define(SELECT_ALL, 603).
-define(ID_NOTEBOOK, 604).
--record(procinfo_state, {parent,
- frame,
- node,
- pid,
- module,
- procinfo_stc,
- modinfo_stc,
- modcode_stc,
- checklistbox,
- current_view, % proc_info::atom | module_info::atom | module_code::atom
- itemlist = [{backtrace, false},
- {binary, false},
- {catchlevel, false},
- {current_function, false},
- {dictionary, false},
- {error_handler, true},
- {garbage_collection, true},
- {group_leader, true},
- {heap_size, true},
- {initial_call, false},
- {last_calls, false},
- {links, true},
- {memory, false},
- {message_queue_len, true},
- {messages, false},
- {monitored_by, false},
- {monitors, false},
- {priority, true},
- {reductions, false},
- {registered_name, false},
- {sequential_trace_token, false},
- {stack_size, false},
- {status, false},
- {suspending, false},
- {total_heap_size, false},
- {trace, false},
- {trap_exit,true}]
- }).
-
-
-
-
-start(Node, Process, ParentFrame, Parent) ->
- wx_object:start(?MODULE, [Node, Process, ParentFrame, Parent], []).
+-record(state, {parent,
+ frame,
+ pid,
+ pages=[]
+ }).
+
+-record(worker, {panel, callback}).
+
+start(Process, ParentFrame, Parent) ->
+ wx_object:start(?MODULE, [Process, ParentFrame, Parent], []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-init([Node, Process, ParentFrame, Parent]) ->
+init([Pid, ParentFrame, Parent]) ->
try
- State = #procinfo_state{parent = Parent,
- node = Node,
- pid = Process,
- current_view = proc_info
- },
- ItemList = State#procinfo_state.itemlist,
- Name = case observer_wx:try_rpc(Node, erlang, process_info, [Process, registered_name]) of
- [] ->
- undefined;
- {registered_name, M} ->
- M
- end,
- {initial_call, {Module, _, _}} = observer_wx:try_rpc(Node, erlang, process_info, [Process, initial_call]),
- {Frame, ProcStc, CheckListBox, ModInfoStc, ModCodeStc} = setup(ParentFrame, Node, Process, ItemList, Module, Name),
- {Frame, State#procinfo_state{frame = Frame,
- module = Module,
- procinfo_stc = ProcStc,
- modinfo_stc = ModInfoStc,
- modcode_stc = ModCodeStc,
- checklistbox = CheckListBox}}
+ Title=case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, registered_name]) of
+ [] -> io_lib:format("~p",[Pid]);
+ {registered_name, Registered} -> atom_to_list(Registered)
+ end,
+ Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title],
+ [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {800,700}}]),
+ MenuBar = wxMenuBar:new(),
+ create_menus(MenuBar),
+ wxFrame:setMenuBar(Frame, MenuBar),
+
+ Notebook = wxNotebook:new(Frame, ?ID_NOTEBOOK, [{style, ?wxBK_DEFAULT}]),
+
+ ProcessPage = init_panel(Notebook, "Process Information", Pid, fun init_process_page/2),
+ MessagePage = init_panel(Notebook, "Messages", Pid, fun init_message_page/2),
+ DictPage = init_panel(Notebook, "Dictionary", Pid, fun init_dict_page/2),
+ StackPage = init_panel(Notebook, "Stack Trace", Pid, fun init_stack_page/2),
+
+ wxFrame:connect(Frame, close_window),
+ wxMenu:connect(Frame, command_menu_selected),
+ %% wxNotebook:connect(Notebook, command_notebook_page_changed, [{skip,true}]),
+ wxFrame:show(Frame),
+ {Frame, #state{parent=Parent,
+ pid=Pid,
+ frame=Frame,
+ pages=[ProcessPage,MessagePage,DictPage,StackPage]
+ }}
catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(ParentFrame, Node),
- {stop, badrpc, #procinfo_state{parent = Parent,
- pid = Process}}
+ observer_wx:return_to_localnode(ParentFrame, node(Pid)),
+ {stop, badrpc, #state{parent=Parent, pid=Pid}};
+ Error:Reason ->
+ io:format("~p:~p: ~p ~p~n ~p~n",
+ [?MODULE, ?LINE, Error, Reason, erlang:get_stacktrace()])
end.
-
-setup(ParentFrame, Node, Pid, ItemList, Module, Name) ->
- Title = case Name of
- undefined ->
- atom_to_list(Node) ++ ":" ++ atom_to_list(Module);
- Name ->
- atom_to_list(Node) ++ ":" ++ atom_to_list(Name)
- end,
- Frame = wxFrame:new(ParentFrame, ?wxID_ANY, Title,
- [{style, ?wxDEFAULT_FRAME_STYLE},
- {size, {900,900}}]),
- Panel = wxPanel:new(Frame, []),
- MainSz = wxBoxSizer:new(?wxHORIZONTAL),
- Notebook = wxNotebook:new(Panel, ?ID_NOTEBOOK, [{style, ?wxBK_DEFAULT}]),
- wxNotebook:connect(Notebook, command_notebook_page_changed),
- {CodePanel, CheckListBox, CodeStc} = create_procinfo_page(Notebook, Node, Pid, ItemList),
- {ModInfoPanel, ModInfoStc} = create_page(Notebook, Node, Module, module_info),
- {ModCodePanel, ModCodeStc} = create_page(Notebook, Node, Module, module_code),
- wxNotebook:addPage(Notebook, CodePanel, "Process information", []),
- wxNotebook:addPage(Notebook, ModInfoPanel, "Module information", []),
- wxNotebook:addPage(Notebook, ModCodePanel, "Module code", []),
- MenuBar = wxMenuBar:new(),
- create_menus(MenuBar),
- wxWindow:setSizer(Panel, MainSz),
- wxSizer:add(MainSz, Notebook, [{flag, ?wxEXPAND}, {proportion, 1}]),
- wxFrame:setMenuBar(Frame, MenuBar),
- wxFrame:show(Frame),
- wxFrame:connect(Frame, close_window),
- wxMenu:connect(Frame, command_menu_selected),
- {Frame, CodeStc, CheckListBox, ModInfoStc, ModCodeStc}.
-
-
-create_procinfo_page(Notebook, Node, Pid, ItemList) ->
- Panel = wxPanel:new(Notebook),
- MainSz = wxBoxSizer:new(?wxHORIZONTAL),
- CheckSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "View"}]),
- BtnSz = wxBoxSizer:new(?wxHORIZONTAL),
-
- Stc = create_styled_txtctrl(Panel, proc_info),
- Txt = get_formatted_values(Node, Pid, ItemList),
- set_text(Stc, Txt, text),
- Choices = [atom_to_list(Tag) || {Tag, _} <- ItemList],
- CheckListBox = wxCheckListBox:new(Panel, ?wxID_ANY, [{choices, Choices},
- {style, ?wxLB_EXTENDED},
- {style, ?wxLB_SORT},
- {style, ?wxLB_NEEDED_SB}]),
- check_boxes(CheckListBox, ItemList),
- wxCheckListBox:connect(CheckListBox, command_checklistbox_toggled),
-
- SelAllBtn = wxButton:new(Panel, ?SELECT_ALL, [{label, "Select all"}]),
- DeSelAllBtn = wxButton:new(Panel, ?SELECT_ALL, [{label, "Deselect all"}]),
-
- wxButton:connect(SelAllBtn, command_button_clicked, [{userData, true}]),
- wxButton:connect(DeSelAllBtn, command_button_clicked, [{userData, false}]),
- wxWindow:setSizer(Panel, MainSz),
- wxSizer:add(MainSz, Stc, [{proportion, 1}, {flag, ?wxEXPAND}]),
- wxSizer:add(CheckSz, CheckListBox, [{proportion, 1}]),
- wxSizer:add(BtnSz, SelAllBtn),
- wxSizer:add(BtnSz, DeSelAllBtn),
- wxSizer:add(CheckSz, BtnSz),
- wxSizer:add(MainSz, CheckSz, [{flag, ?wxEXPAND}]),
- {Panel, CheckListBox, Stc}.
-
-create_page(Notebook, Node, Module, What) ->
- Panel = wxPanel:new(Notebook, []),
- Sizer = wxBoxSizer:new(?wxVERTICAL),
- Stc = create_styled_txtctrl(Panel, What),
- {Sort, Txt} = case What of
- module_info ->
- {text, get_formatted_modinfo(Node, Module)};
- module_code ->
- case get_src_file(Node, Module) of
- {ok, File} ->
- {file, File};
- error->
- {text, "Error! Could not read sourcefile"}
- end
- end,
- set_text(Stc, Txt, Sort),
- wxWindow:setSizer(Panel, Sizer),
- wxSizer:add(Sizer, Stc, [{flag, ?wxEXPAND}, {proportion, 1}]),
- {Panel, Stc}.
-
-create_menus(MenuBar) ->
- Menus = [{"File", [#create_menu{id = ?CLOSE, text = "Close"}]},
- {"View", [#create_menu{id = ?REFRESH, text = "Refresh"}]}],
- observer_lib:create_menus(Menus, MenuBar, new_window).
-
-check_boxes(CheckListBox, Bool, all) ->
- lists:foreach(fun(Index) ->
- wxCheckListBox:check(CheckListBox, Index, [{check, Bool}])
- end,
- lists:seq(0, wxControlWithItems:getCount(CheckListBox))).
-check_boxes(CheckListBox, ItemList) ->
- lists:foldl(fun({_, Bool}, Index) ->
- wxCheckListBox:check(CheckListBox, Index, [{check, Bool}]),
- Index+1
- end,
- 0, ItemList).
-
-create_styled_txtctrl(Parent, View) ->
- FixedFont = wxFont:new(11, ?wxFONTFAMILY_TELETYPE, ?wxFONTSTYLE_NORMAL, ?wxNORMAL,[]),
- Stc = wxStyledTextCtrl:new(Parent),
- wxStyledTextCtrl:styleClearAll(Stc),
- wxStyledTextCtrl:styleSetFont(Stc, ?wxSTC_STYLE_DEFAULT, FixedFont),
- wxStyledTextCtrl:setLexer(Stc, ?wxSTC_LEX_ERLANG),
- wxStyledTextCtrl:setMarginType(Stc, 2, ?wxSTC_MARGIN_NUMBER),
- W = wxStyledTextCtrl:textWidth(Stc, ?wxSTC_STYLE_LINENUMBER, "9"),
- wxStyledTextCtrl:setMarginWidth(Stc, 2, W*3),
-
- wxStyledTextCtrl:setSelectionMode(Stc, ?wxSTC_SEL_LINES),
- wxStyledTextCtrl:setUseHorizontalScrollBar(Stc, false),
-
- Styles = [{?wxSTC_ERLANG_DEFAULT, {0,0,0}},
- {?wxSTC_ERLANG_COMMENT, {160,53,35}},
- {?wxSTC_ERLANG_VARIABLE, {150,100,40}},
- {?wxSTC_ERLANG_NUMBER, {5,5,100}},
- {?wxSTC_ERLANG_KEYWORD, {130,40,172}},
- {?wxSTC_ERLANG_STRING, {170,45,132}},
- {?wxSTC_ERLANG_OPERATOR, {30,0,0}},
- {?wxSTC_ERLANG_ATOM, {0,0,0}},
- {?wxSTC_ERLANG_FUNCTION_NAME, {64,102,244}},
- {?wxSTC_ERLANG_CHARACTER,{236,155,172}},
- {?wxSTC_ERLANG_MACRO, {40,144,170}},
- {?wxSTC_ERLANG_RECORD, {40,100,20}},
- {?wxSTC_ERLANG_SEPARATOR,{0,0,0}},
- {?wxSTC_ERLANG_NODE_NAME,{0,0,0}}],
- SetStyle = fun({Style, Color}) ->
- wxStyledTextCtrl:styleSetFont(Stc, Style, FixedFont),
- wxStyledTextCtrl:styleSetForeground(Stc, Style, Color)
- end,
- [SetStyle(Style) || Style <- Styles],
-
- KeyWords = case View of
- proc_info ->
- get_procinfo_keywords();
- module_info ->
- get_modinfo_keywords();
- module_code ->
- get_erl_keywords()
- end,
- wxStyledTextCtrl:setKeyWords(Stc, 0, KeyWords),
- Stc.
-
-get_erl_keywords() ->
- L = ["after","begin","case","try","cond","catch","andalso","orelse",
- "end","fun","if","let","of","query","receive","when","bnot","not",
- "div","rem","band","and","bor","bxor","bsl","bsr","or","xor"],
- lists:flatten([K ++ " "|| K <- L] ++ [0]).
-get_procinfo_keywords() ->
- L = ["backtrace","binary","catchlevel","current_function","dictionary",
- "error_handler","garbage_collection","group_leader", "heap_size",
- "initial_call","last_calls","links","memory","message_queue_len",
- "messages","monitored_by","monitors", "priority","reductions",
- "registered_name", "sequential_trace_token","stack_size","status",
- "suspending", "total_heap_size","trace","trap_exit"],
- lists:flatten([K ++ " "|| K <- L] ++ [0]).
-get_modinfo_keywords() ->
- L = ["exports", "imports", "attributes", "compile"],
- lists:flatten([K ++ " "|| K <- L] ++ [0]).
-
-get_formatted_values(Node, Process, ItemList) ->
- TagList = [Tag || {Tag, Bool} <- ItemList, Bool =:= true],
- Values = observer_wx:try_rpc(Node, erlang, process_info, [Process, TagList]),
- lists:flatten(format_value(Values, [])).
-
-format_value([], Acc) ->
- lists:reverse(Acc);
-format_value([{backtrace, Bin} | T], Acc) ->
- format_value(T, [io_lib:format("{backtrace,~s}~n", [binary_to_list(Bin)]) | Acc]);
-format_value([H|T], Acc) ->
- format_value(T, [io_lib:format("~p~n", [H]) | Acc]).
-
-get_formatted_modinfo(Node, Module) ->
- Info = observer_wx:try_rpc(Node, Module, module_info, []),
- lists:flatten([io_lib:format("~p~n", [I]) || I <- Info]).
-get_src_remote(Node, Module) ->
- case observer_wx:try_rpc(Node, filename, find_src, [Module]) of
- {error, _} ->
- error;
- {SrcFile, _} ->
- case observer_wx:try_rpc(Node, file, read_file_info, [SrcFile ++ ".erl"]) of
- {error, _} ->
- error;
- {ok, _} ->
- {ok, SrcFile ++ ".erl"}
- end
- end.
-
-get_src_local(Module) ->
- case filename:find_src(Module) of
- {error, _} ->
- error;
- {SrcFile, _} ->
- case file:read_file_info(SrcFile ++ ".erl") of
- {error, _} ->
- error;
- {ok, _} ->
- {ok, SrcFile ++ ".erl"}
- end
- end.
-
-get_src_file(Node, Module) ->
- case get_src_remote(Node, Module) of
- {ok, SrcFile} ->
- {ok, SrcFile};
- error ->
- get_src_local(Module)
- end.
-
-
-set_text(Stc, Text, text) ->
- wxStyledTextCtrl:setReadOnly(Stc, false),
- wxStyledTextCtrl:setText(Stc, Text),
- wxStyledTextCtrl:setReadOnly(Stc, true);
-set_text(Stc, File, file) ->
- wxStyledTextCtrl:setReadOnly(Stc, false),
- wxStyledTextCtrl:loadFile(Stc, File),
- wxStyledTextCtrl:setReadOnly(Stc, true).
-
-update_procinfo_page(Stc, Node, Process, ItemList) ->
- Txt = get_formatted_values(Node, Process, ItemList),
- set_text(Stc, Txt, text).
-update_modinfo_page(Stc, Node, Module) ->
- Txt = get_formatted_modinfo(Node, Module),
- set_text(Stc, Txt, text).
-update_modcode_page(Stc, Node, Module) ->
- case get_src_file(Node, Module) of
- {ok, File} ->
- set_text(Stc, File, file);
- error ->
- set_text(Stc, "Error! Could not read sourcefile", text)
- end.
+init_panel(Notebook, Str, Pid, Fun) ->
+ Panel = wxPanel:new(Notebook),
+ Sizer = wxBoxSizer:new(?wxHORIZONTAL),
+ {Window,Callback} = Fun(Panel, Pid),
+ wxSizer:add(Sizer, Window, [{flag, ?wxEXPAND bor ?wxALL}, {proportion, 1}, {border, 5}]),
+ wxPanel:setSizer(Panel, Sizer),
+ true = wxNotebook:addPage(Notebook, Panel, Str),
+ #worker{panel=Panel, callback=Callback}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Callbacks%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-handle_event(#wx{event = #wxClose{type = close_window}},
- State) ->
+handle_event(#wx{event=#wxClose{type=close_window}}, State) ->
{stop, shutdown, State};
-handle_event(#wx{id = ?CLOSE,
- event = #wxCommand{type = command_menu_selected}},
- State) ->
+handle_event(#wx{id=?wxID_CLOSE, event=#wxCommand{type=command_menu_selected}}, State) ->
{stop, shutdown, State};
-handle_event(#wx{id = ?REFRESH,
- event = #wxCommand{type = command_menu_selected}},
- #procinfo_state{current_view = Current,
- frame = Frame,
- node = Node,
- pid = Pid,
- procinfo_stc = Stc,
- itemlist = ItemList} = State) when Current =:= proc_info ->
- try
- update_procinfo_page(Stc, Node, Pid, ItemList),
- {noreply, State}
- catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(Frame, Node),
- {stop, badrpc, State}
- end;
-
-handle_event(#wx{id = ?REFRESH,
- event = #wxCommand{type = command_menu_selected}},
- #procinfo_state{current_view = Current,
- frame = Frame,
- node = Node,
- modinfo_stc = Stc,
- module = Module} = State) when Current =:= module_info ->
- try
- update_modinfo_page(Stc, Node, Module),
- {noreply, State}
- catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(Frame, Node),
- {stop, badrpc, State}
- end;
-
-handle_event(#wx{id = ?REFRESH,
- event = #wxCommand{type = command_menu_selected}},
- #procinfo_state{current_view = Current,
- modcode_stc = Stc,
- frame = Frame,
- node = Node,
- module = Module} = State) when Current =:= module_code ->
- try
- update_modcode_page(Stc, Node, Module),
- {noreply, State}
- catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(Frame, Node),
- {stop, badrpc, State}
- end;
-
-
-handle_event(#wx{obj = Notebook, id = ?ID_NOTEBOOK,
- event = #wxNotebook{type = command_notebook_page_changed}},
- #procinfo_state{frame = Frame,
- module = Module,
- procinfo_stc = ProcStc,
- modcode_stc = CodeStc,
- modinfo_stc = ModInfoStc,
- node = Node,
- pid = Pid,
- itemlist = ItemList} = State) ->
- try
- Current = case observer_wx:check_page_title(Notebook) of
- "Process information" ->
- update_procinfo_page(ProcStc, Node, Pid, ItemList),
- proc_info;
- "Module information" ->
- update_modinfo_page(ModInfoStc, Node, Module),
- module_info;
- "Module code" ->
- update_modcode_page(CodeStc, Node, Module),
- module_code
- end,
- {noreply, State#procinfo_state{current_view = Current}}
- catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(Frame, Node),
- {stop, badrpc, State}
- end;
-
-handle_event(#wx{event = #wxCommand{type = command_checklistbox_toggled,
- commandInt = Index},
- obj = CheckListbox},
- #procinfo_state{frame = Frame,
- node = Node,
- pid = Process,
- procinfo_stc = Stc,
- itemlist = ItemList} = State) ->
- try
- {Tag, _} = lists:nth(Index+1, ItemList),
- ItemList2 = case wxCheckListBox:isChecked(CheckListbox, Index) of
- true ->
- lists:keyreplace(Tag, 1, ItemList, {Tag, true});
- false ->
- lists:keyreplace(Tag, 1, ItemList, {Tag, false})
- end,
- Txt = get_formatted_values(Node, Process, ItemList2),
- set_text(Stc, Txt, text),
- {noreply, State#procinfo_state{itemlist = ItemList2}}
-
- catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(Frame, Node),
- {stop, badrpc, State}
- end;
-
-handle_event(#wx{id = ?SELECT_ALL,
- event = #wxCommand{type = command_button_clicked},
- userData = Bool},
- #procinfo_state{frame = Frame,
- node = Node,
- pid = Process,
- itemlist = ItemList,
- procinfo_stc = Stc,
- checklistbox = CheckListBox} = State) ->
- try
- check_boxes(CheckListBox, Bool, all),
- ItemList2 = lists:keymap(fun(_) ->
- Bool
- end,
- 2, ItemList),
- Txt = get_formatted_values(Node, Process, ItemList2),
- set_text(Stc, Txt, text),
- {noreply, State#procinfo_state{itemlist = ItemList2}}
- catch error:{badrpc, _} ->
- observer_wx:return_to_localnode(Frame, Node),
- {stop, badrpc, State}
- end;
+handle_event(#wx{id=?REFRESH}, #state{pages=Pages}=State) ->
+ [(W#worker.callback)() || W <- Pages],
+ {noreply, State};
handle_event(Event, State) ->
io:format("~p: ~p, Handle event: ~p~n", [?MODULE, ?LINE, Event]),
@@ -491,18 +117,158 @@ handle_cast(Cast, State) ->
io:format("~p ~p: Got cast ~p~n", [?MODULE, ?LINE, Cast]),
{noreply, State}.
-terminate(Reason, #procinfo_state{parent = Parent,
- pid = Pid,
- frame = Frame}) ->
- io:format("~p terminating. Reason: ~p~n", [?MODULE, Reason]),
+terminate(_Reason, #state{parent=Parent,pid=Pid,frame=Frame}) ->
Parent ! {procinfo_menu_closed, Pid},
case Frame of
- undefined ->
- ok;
- _ ->
- wxFrame:destroy(Frame)
+ undefined -> ok;
+ _ -> wxFrame:destroy(Frame)
end,
ok.
code_change(_, _, State) ->
{stop, not_yet_implemented, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+init_process_page(Panel, Pid) ->
+ Fields = process_info_fields(Pid),
+ {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields),
+ {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}.
+
+init_text_page(Parent) ->
+ Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY,
+ Text = wxTextCtrl:new(Parent, ?wxID_ANY, [{style, Style}]),
+ Font = observer_wx:get_attrib({font, modern}),
+ Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]),
+ true = wxTextCtrl:setDefaultStyle(Text, Attr),
+ wxTextAttr:destroy(Attr),
+ Text.
+
+init_message_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Format = fun(Message, Number) ->
+ {io_lib:format("~-4.w ~p~n", [Number, Message]),
+ Number+1}
+ end,
+ Update = fun() ->
+ {messages,RawMessages} =
+ observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]),
+ {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ case Messages =:= [] of
+ true ->
+ wxTextCtrl:writeText(Text, "No messages");
+ false ->
+ wxTextCtrl:writeText(Text, Messages)
+ end
+ end,
+ Update(),
+ {Text, Update}.
+
+init_dict_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Update = fun() ->
+ {dictionary,RawDict} =
+ observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]),
+ Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ wxTextCtrl:writeText(Text, Dict)
+ end,
+ Update(),
+ {Text, Update}.
+
+init_stack_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Format = fun({Mod, Fun, Arg, Info}) ->
+ Str = io_lib:format("~w:~w/~w", [Mod,Fun,Arg]),
+ case Info of
+ [{file,File},{line,Line}] ->
+ io_lib:format("~-45.s ~s:~w~n", [Str,File,Line]);
+ _ ->
+ [Str,$\n]
+ end
+ end,
+ Update = fun() ->
+ {current_stacktrace,RawBt} =
+ observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, current_stacktrace]),
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ [wxTextCtrl:writeText(Text, Format(Entry)) || Entry <- RawBt]
+ end,
+ Update(),
+ {Text, Update}.
+
+create_menus(MenuBar) ->
+ Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]},
+ {"View", [#create_menu{id=?REFRESH, text="Refresh\tCtrl-R"}]}],
+ observer_lib:create_menus(Menus, MenuBar, new_window).
+
+process_info_fields(Pid) ->
+ RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]),
+ Struct = [{"Overview",
+ [{"Initial Call", initial_call},
+ {"Current Function", current_function},
+ {"Registered Name", registered_name},
+ {"Status", status},
+ {"Message Queue Len",message_queue_len},
+ {"Priority", priority},
+ {"Trap Exit", trap_exit},
+ {"Reductions", reductions},
+ {"Binary", binary},
+ {"Last Calls", last_calls},
+ {"Catch Level", catchlevel},
+ {"Trace", trace},
+ {"Suspending", suspending},
+ {"Sequential Trace Token", sequential_trace_token},
+ {"Error Handler", error_handler}]},
+ {"Connections",
+ [{"Group Leader", group_leader},
+ {"Links", links},
+ {"Monitors", monitors},
+ {"Monitored by", monitored_by}]},
+ {"Memory and Garbage Collection", right,
+ [{"Memory", {bytes, memory}},
+ {"Stack and Heaps", {bytes, total_heap_size}},
+ {"Heap Size", {bytes, heap_size}},
+ {"Stack Size", {bytes, stack_size}},
+ {"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}},
+ {"GC FullSweep After", get_gc_info(fullsweep_after)}
+ ]}],
+ observer_lib:fill_info(Struct, RawInfo).
+
+item_list() ->
+ [ %% backtrace,
+ binary,
+ catchlevel,
+ current_function,
+ %% dictionary,
+ error_handler,
+ garbage_collection,
+ group_leader,
+ heap_size,
+ initial_call,
+ last_calls,
+ links,
+ memory,
+ message_queue_len,
+ %% messages,
+ monitored_by,
+ monitors,
+ priority,
+ reductions,
+ registered_name,
+ sequential_trace_token,
+ stack_size,
+ status,
+ suspending,
+ total_heap_size,
+ trace,
+ trap_exit].
+
+get_gc_info(Arg) ->
+ fun(Data) ->
+ GC = proplists:get_value(garbage_collection, Data),
+ proplists:get_value(Arg, GC)
+ end.
diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl
index 5bc5fd49f6..36aa226bd1 100644
--- a/lib/observer/src/observer_sys_wx.erl
+++ b/lib/observer/src/observer_sys_wx.erl
@@ -59,8 +59,10 @@ init2([Notebook, Parent]) ->
{Info, Stat} = info_fields(),
Panel = wxPanel:new(Notebook),
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
- {FPanel0, _FSizer0, Fields0} = observer_lib:display_info(Panel, fill_info(Info, SysInfo)),
- {FPanel1, _FSizer1, Fields1} = observer_lib:display_info(Panel, fill_info(Stat, SysInfo)),
+ {FPanel0, _FSizer0, Fields0} =
+ observer_lib:display_info(Panel, observer_lib:fill_info(Info, SysInfo)),
+ {FPanel1, _FSizer1, Fields1} =
+ observer_lib:display_info(Panel, observer_lib:fill_info(Stat, SysInfo)),
wxSizer:add(Sizer, FPanel0, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxLEFT},
{proportion, 1}, {border, 5}]),
wxSizer:add(Sizer, FPanel1, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxRIGHT},
@@ -81,7 +83,8 @@ update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer}) ->
try
SysInfo = observer_wx:try_rpc(Node, ?MODULE, sys_info, []),
{Info, Stat} = info_fields(),
- observer_lib:update_info(Fields, fill_info(Info, SysInfo) ++ fill_info(Stat, SysInfo)),
+ observer_lib:update_info(Fields, observer_lib:fill_info(Info, SysInfo) ++
+ observer_lib:fill_info(Stat, SysInfo)),
wxSizer:layout(Sizer)
catch E:R ->
io:format("~p:~p ~p~n",[E,R, erlang:get_stacktrace()])
@@ -124,14 +127,6 @@ info_fields() ->
],
{Info, Stat}.
-fill_info([{Str, Key}|Rest], Data) when is_atom(Key) ->
- [{Str, proplists:get_value(Key,Data)} | fill_info(Rest, Data)];
-fill_info([{Str,SubStructure}|Rest], Data) ->
- [{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
-fill_info([{Str,Attrib,SubStructure}|Rest], Data) ->
- [{Str, Attrib, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
-fill_info([], _) -> [].
-
%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
handle_info(refresh_interval, #sys_wx_state{panel = Panel,
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 4688e271ee..b39b34c240 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -20,8 +20,8 @@
-behaviour(wx_object).
-export([start/0]).
--export([create_menus/2, create_txt_dialog/4, try_rpc/4,
- return_to_localnode/2]).
+-export([create_menus/2, get_attrib/1,
+ create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
handle_call/3, handle_info/2, check_page_title/1]).
@@ -62,6 +62,9 @@ start() ->
create_menus(Object, Menus) when is_list(Menus) ->
wx_object:call(Object, {create_menus, Menus}).
+get_attrib(What) ->
+ wx_object:call(observer, {get_attrib, What}).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -79,6 +82,7 @@ init(_Args) ->
wxFrame:show(Frame),
net_kernel:monitor_nodes(true),
process_flag(trap_exit, true),
+ register(observer, self()),
{Frame, UpdState}.
setup(#state{frame = Frame} = State) ->
@@ -133,16 +137,19 @@ setup(#state{frame = Frame} = State) ->
node = node(),
nodes = Nodes
},
+ %% Create resources which we don't want to duplicate
+ SysFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT),
+ SysFontSize = wxFont:getPointSize(SysFont),
+ Modern = wxFont:new(SysFontSize, ?wxFONTFAMILY_MODERN, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
+ put({font, modern}, Modern),
UpdState.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%Callbacks
-handle_event(#wx{obj = Notebook, id = ?ID_NOTEBOOK,
- event = Ev = #wxNotebook{type = command_notebook_page_changing}},
- #state{active_tab=Previous, node=Node, notebook = Notebook} = State) ->
- io:format("Command notebook changed ~p ~n", [Ev]),
+handle_event(#wx{event=#wxNotebook{type=command_notebook_page_changing}},
+ #state{active_tab=Previous, node=Node} = State) ->
Pid = get_active_pid(State),
Previous ! not_active,
Pid ! {active, Node},
@@ -232,8 +239,7 @@ handle_event(Event, State) ->
Pid ! Event,
{noreply, State}.
-handle_cast(Cast, State) ->
- io:format("~p:~p: Got cast ~p~n", [?MODULE, ?LINE, Cast]),
+handle_cast(_Cast, State) ->
{noreply, State}.
handle_call({create_menus, TabMenus}, _From,
@@ -244,8 +250,10 @@ handle_call({create_menus, TabMenus}, _From,
end),
{reply, ok, State#state{menus=TabMenus}};
-handle_call(Msg, _From, State) ->
- io:format("~p~p: Got Call ~p~n",[?MODULE, ?LINE, Msg]),
+handle_call({get_attrib, Attrib}, _From, State) ->
+ {reply, get(Attrib), State};
+
+handle_call(_Msg, _From, State) ->
{reply, ok, State}.
handle_info({nodeup, _Node}, State) ->
@@ -265,13 +273,11 @@ handle_info({nodedown, Node},
create_txt_dialog(Frame, Msg, "Node down", ?wxICON_EXCLAMATION),
{noreply, State3};
-handle_info(Info, State) ->
- io:format("~p, ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]),
+handle_info(_Info, State) ->
{noreply, State}.
-terminate(Reason, #state{frame = Frame}) ->
+terminate(_Reason, #state{frame = Frame}) ->
wxFrame:destroy(Frame),
- io:format("~p terminating. Reason: ~p~n", [?MODULE, Reason]),
ok.
code_change(_, _, State) ->