%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
%%
%% 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 online 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.
%%
%% %CopyrightEnd%
%%
-module(dbg_ui_winman).
-behaviour(gen_server).
-compile([{nowarn_deprecated_function,{gs,config,2}},
{nowarn_deprecated_function,{gs,destroy,1}},
{nowarn_deprecated_function,{gs,menu,3}},
{nowarn_deprecated_function,{gs,menubutton,3}},
{nowarn_deprecated_function,{gs,menuitem,3}}]).
%% External exports
-export([start/0]).
-export([insert/2, is_started/1,
clear_process/1,
raise/1,
windows_menu/1, update_windows_menu/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(win, {owner, % pid()
title, % string()
win % gsobj()
}).
-record(state, {wins=[] % [#win{}]
}).
%%====================================================================
%% External exports
%%====================================================================
%%--------------------------------------------------------------------
%% start()
%%--------------------------------------------------------------------
start() ->
gen_server:start({local,?MODULE}, ?MODULE, [], []).
%%--------------------------------------------------------------------
%% insert(Title, Win)
%% Title = string()
%% Win = gsobj()
%%--------------------------------------------------------------------
insert(Title, Win) ->
gen_server:cast(?MODULE, {insert, self(), Title, Win}).
%%--------------------------------------------------------------------
%% is_started(Title) -> true | false
%% Title = string()
%%--------------------------------------------------------------------
is_started(Title) ->
case gen_server:call(?MODULE, {is_started, Title}, infinity) of
{true, Win} ->
raise(Win),
true;
false ->
false
end.
%%--------------------------------------------------------------------
%% clear_process(Title)
%% Title = string()
%%--------------------------------------------------------------------
clear_process(Title) ->
gen_server:cast(?MODULE, {clear_process, Title}).
%%--------------------------------------------------------------------
%% raise(Win)
%% Win = gsobj()
%%--------------------------------------------------------------------
raise(Win) ->
gs:config(Win, [raise, {iconify, false}, {setfocus, true}]).
%%--------------------------------------------------------------------
%% windows_menu(MenuBar)
%% MenuBar = gsobj()
%%--------------------------------------------------------------------
windows_menu(MenuBar) ->
gs:menubutton('WindowsMenuBtn', MenuBar,
[{label,{text," Windows "}},
{font, dbg_ui_win:font(normal)}]),
gs:menu('WindowsMenu', 'WindowsMenuBtn', []).
%%--------------------------------------------------------------------
%% update_windows_menu(Data)
%% Data = {New, Old}
%% New = Old = list()
%%--------------------------------------------------------------------
update_windows_menu([MonInfo|Infos]) ->
gs:destroy('WindowsMenu'),
gs:menu('WindowsMenu', 'WindowsMenuBtn', []),
menuitem(MonInfo),
gs:menuitem(separator, 'WindowsMenu', [{itemtype, separator}]),
lists:foreach(fun(Info) -> menuitem(Info) end, Infos).
menuitem({Title, Win}) ->
gs:menuitem(Title, 'WindowsMenu', [{label, {text,Title}},
{font, dbg_ui_win:font(normal)},
{data, {dbg_ui_winman,Win}}]).
%%====================================================================
%% gen_server callbacks
%%====================================================================
init(_Arg) ->
process_flag(trap_exit, true),
{ok, #state{}}.
handle_call({is_started, Title}, _From, State) ->
Reply = case lists:keyfind(Title, #win.title, State#state.wins) of
false -> false;
Win -> {true, Win#win.win}
end,
{reply, Reply, State}.
handle_cast({insert, Pid, Title, Win}, State) ->
link(Pid),
Wins = State#state.wins ++ [#win{owner=Pid, title=Title, win=Win}],
inform_all(Wins),
{noreply, State#state{wins=Wins}};
handle_cast({clear_process, Title}, State) ->
OldWins = State#state.wins,
Wins = case lists:keyfind(Title, #win.title, OldWins) of
#win{owner=Pid} ->
Msg = {dbg_ui_winman, destroy},
Pid ! Msg,
lists:keydelete(Title, #win.title, OldWins);
false ->
OldWins
end,
{noreply, State#state{wins=Wins}}.
handle_info({'EXIT', Pid, _Reason}, State) ->
[Mon | _Wins] = State#state.wins,
if
Pid =:= Mon#win.owner -> {stop, normal, State};
true ->
Wins2 = lists:keydelete(Pid, #win.owner, State#state.wins),
inform_all(Wins2),
{noreply, State#state{wins=Wins2}}
end.
terminate(_Reason, State) ->
delete_all(State#state.wins),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%====================================================================
%% Internal functions
%%====================================================================
inform_all(Wins) ->
Infos = lists:map(fun(#win{title=Title, win=Win}) -> {Title, Win} end,
Wins),
Msg = {dbg_ui_winman, update_windows_menu, Infos},
lists:foreach(fun(#win{owner=Pid}) -> Pid ! Msg end, Wins).
delete_all(Wins) ->
Msg = {dbg_ui_winman, destroy},
lists:foreach(fun(#win{owner=Pid}) -> Pid ! Msg end, Wins).