From 5584462be1c6dce1990a9031c0e43a89e758a263 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Mon, 20 Feb 2012 12:51:37 +0100 Subject: [observer] Add fallback drawing to raster api (wxDC) Sigh, seems that Suse-11 does not default deliver wxWidgets with wxGRAPHICS_CONTEXT enabled, add fallback to use wxDC again. --- lib/observer/src/observer_app_wx.erl | 95 +++++++++++++--------- lib/observer/src/observer_perf_wx.erl | 147 +++++++++++++++++++++++++--------- 2 files changed, 168 insertions(+), 74 deletions(-) diff --git a/lib/observer/src/observer_app_wx.erl b/lib/observer/src/observer_app_wx.erl index cb5f8c1259..900fba911a 100644 --- a/lib/observer/src/observer_app_wx.erl +++ b/lib/observer/src/observer_app_wx.erl @@ -27,6 +27,12 @@ -include_lib("wx/include/wx.hrl"). -include("observer_defs.hrl"). +%% Import drawing wrappers +-import(observer_perf_wx, [haveGC/1, + setPen/2, setFont/3, setBrush/2, + strokeLine/5, strokeLines/2, drawRoundedRectangle/6, + drawText/4, getTextExtent/2]). + -record(state, { parent, @@ -37,7 +43,8 @@ current, app, sel, - appmon + appmon, + usegc = false }). -record(paint, {font, pen, brush, sel, links}). @@ -102,8 +109,11 @@ init([Notebook, Parent]) -> wxPanel:connect(DrawingArea, left_dclick), wxPanel:connect(DrawingArea, right_down), - %% DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), - DefFont = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL), + UseGC = haveGC(DrawingArea), + Font = case UseGC of + true -> wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT); + false -> wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_NORMAL) + end, SelCol = wxSystemSettings:getColour(?wxSYS_COLOUR_HIGHLIGHT), GreyBrush = wxBrush:new({230,230,240}), SelBrush = wxBrush:new(SelCol), @@ -113,7 +123,8 @@ init([Notebook, Parent]) -> panel =Panel, apps_w=Apps, app_w =DrawingArea, - paint=#paint{font = DefFont, + usegc = UseGC, + paint=#paint{font = Font, pen = wxPen:new({80,80,80}, [{width, 2}]), brush= GreyBrush, sel = SelBrush, @@ -218,16 +229,23 @@ handle_event(Event, _State) -> %%%%%%%%%% handle_sync_event(#wx{event = #wxPaint{}},_, - #state{app_w=DA, app=App, sel=Sel, paint=Paint}) -> + #state{app_w=DA, app=App, sel=Sel, paint=Paint, usegc=UseGC}) -> %% PaintDC must be created in a callback to work on windows. DC = wxPaintDC:new(DA), - GC = ?wxGC:create(DC), - %% Argh must handle scrolling when using ?wxGC - {Sx,Sy} = wxScrolledWindow:calcScrolledPosition(DA, {0,0}), - ?wxGC:translate(GC, Sx,Sy), + GC = case UseGC of + true -> + GC0 = ?wxGC:create(DC), + %% Argh must handle scrolling when using ?wxGC + {Sx,Sy} = wxScrolledWindow:calcScrolledPosition(DA, {0,0}), + ?wxGC:translate(GC0, Sx,Sy), + GC0; + false -> + wxScrolledWindow:doPrepareDC(DA,DC), + DC + end, %% Nothing is drawn until wxPaintDC is destroyed. - draw(GC, App, Sel, Paint), - ?wxGC:destroy(GC), + draw({UseGC, GC}, App, Sel, Paint), + UseGC andalso ?wxGC:destroy(GC), wxPaintDC:destroy(DC), ok. %%%%%%%%%% @@ -274,12 +292,17 @@ handle_info({delivery, _Pid, app, _Curr, {[], [], [], []}}, {noreply, State#state{app=undefined, sel=undefined}}; handle_info({delivery, Pid, app, Curr, AppData}, - State = #state{panel=Panel, appmon=Pid, current=Curr, + State = #state{panel=Panel, appmon=Pid, current=Curr, usegc=UseGC, app_w=AppWin, paint=#paint{font=Font}}) -> - GC = ?wxGC:create(AppWin), - ?wxGC:setFont(GC, Font, {0,0,0}), - App = build_tree(AppData, {GC,Font}), - ?wxGC:destroy(GC), + GC = if UseGC -> ?wxGC:create(AppWin); + true -> wxWindowDC:new(AppWin) + end, + FontW = {UseGC, GC}, + setFont(FontW, Font, {0,0,0}), + App = build_tree(AppData, FontW), + if UseGC -> ?wxGC:destroy(GC); + true -> wxWindowDC:destroy(GC) + end, setup_scrollbar(AppWin, App), wxWindow:refresh(Panel), wxWindow:layout(Panel), @@ -374,11 +397,11 @@ locate_box(From, []) -> {false, From}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -build_tree({Root, P2Name, Links, XLinks0}, Font) -> +build_tree({Root, P2Name, Links, XLinks0}, FontW) -> Fam = sofs:relation_to_family(sofs:relation(Links)), Name2P = gb_trees:from_orddict(lists:sort([{Name,Pid} || {Pid,Name} <- P2Name])), Lookup = gb_trees:from_orddict(sofs:to_external(Fam)), - {_, Tree0} = build_tree2(Root, Lookup, Name2P, Font), + {_, Tree0} = build_tree2(Root, Lookup, Name2P, FontW), {Tree, Dim} = calc_tree_size(Tree0), Fetch = fun({From, To}, Acc) -> try {value, ToPid} = gb_trees:lookup(To, Name2P), @@ -391,18 +414,18 @@ build_tree({Root, P2Name, Links, XLinks0}, Font) -> XLinks = lists:foldl(Fetch, [], XLinks0), #app{ptree=Tree, dim=Dim, links=XLinks}. -build_tree2(Root, Tree0, N2P, Font) -> +build_tree2(Root, Tree0, N2P, FontW) -> case gb_trees:lookup(Root, Tree0) of - none -> {Tree0, {box(Root, N2P, Font), []}}; + none -> {Tree0, {box(Root, N2P, FontW), []}}; {value, Children} -> Tree1 = gb_trees:delete(Root, Tree0), {Tree, CHs} = lists:foldr(fun("port " ++_, Acc) -> Acc; %% Skip ports (Child,{T0, Acc}) -> - {T, C} = build_tree2(Child, T0, N2P, Font), + {T, C} = build_tree2(Child, T0, N2P, FontW), {T, [C|Acc]} end, {Tree1, []}, Children), - {Tree, {box(Root, N2P, Font), CHs}} + {Tree, {box(Root, N2P, FontW), CHs}} end. calc_tree_size(Tree) -> @@ -447,12 +470,12 @@ middle([{#box{y=Y0},_}|List], _) -> {#box{y=Y1},_} = lists:last(List), (Y0+Y1) div 2. -box(Str0, N2P, {Win,_Font}) -> +box(Str0, N2P, FontW) -> Pid = gb_trees:get(Str0, N2P), Str = if hd(Str0) =:= $< -> lists:append(io_lib:format("~w", [Pid])); true -> Str0 end, - {TW,TH, _, _} = ?wxGC:getTextExtent(Win, Str), + {TW,TH} = getTextExtent(FontW, Str), Data = #str{text=Str, x=?BX_HE, y=?BY_HE, pid=Pid}, %% Add pid #box{w=round(TW)+?BX_E, h=round(TH)+?BY_E, s1=Data}. @@ -473,30 +496,30 @@ draw(_DC, undefined, _, _) -> ok; draw(DC, #app{dim={_W,_H}, ptree=Tree, links=Links}, Sel, #paint{font=Font, pen=Pen, brush=Brush, links=LPen, sel=SelBrush}) -> - ?wxGC:setPen(DC, LPen), + setPen(DC, LPen), [draw_xlink(Link, DC) || Link <- Links], - ?wxGC:setPen(DC, Pen), + setPen(DC, Pen), %% ?wxGC:drawRectangle(DC, 2,2, _W-2,_H-2), %% DEBUG - ?wxGC:setBrush(DC, Brush), - ?wxGC:setFont(DC, Font, {0,0,0}), + setBrush(DC, Brush), + setFont(DC, Font, {0,0,0}), draw_tree(Tree, root, DC), case Sel of undefined -> ok; {#box{x=X,y=Y,w=W,h=H,s1=Str1}, _} -> - ?wxGC:setBrush(DC, SelBrush), - ?wxGC:drawRoundedRectangle(DC, X-1,Y-1, W+2,H+2, 8.0), + setBrush(DC, SelBrush), + drawRoundedRectangle(DC, X-1,Y-1, W+2,H+2, 8.0), draw_str(DC, Str1, X, Y) end. draw_tree({Box=#box{x=X,y=Y,w=W,h=H,s1=Str1}, Chs}, Parent, DC) -> - ?wxGC:drawRoundedRectangle(DC, X,Y, W,H, 8.0), + drawRoundedRectangle(DC, X,Y, W,H, 8.0), draw_str(DC, Str1, X, Y), Dot = case Chs of [] -> ok; [{#box{x=CX0},_}|_] -> CY = Y+(H div 2), CX = CX0-(?BB_X div 2), - ?wxGC:strokeLine(DC, X+W, CY, CX, CY), + strokeLine(DC, X+W, CY, CX, CY), {CX, CY} end, draw_link(Parent, Box, DC), @@ -506,9 +529,9 @@ draw_link({CX,CY}, #box{x=X,y=Y0,h=H}, DC) -> Y = Y0+(H div 2), case Y =:= CY of true -> - ?wxGC:strokeLine(DC, CX, CY, X, CY); + strokeLine(DC, CX, CY, X, CY); false -> - ?wxGC:strokeLines(DC, [{CX, CY}, {CX, Y}, {X,Y}]) + strokeLines(DC, [{CX, CY}, {CX, Y}, {X,Y}]) end; draw_link(_, _, _) -> ok. @@ -527,8 +550,8 @@ draw_xlink(X0, Y00, X1, Y11, BH, DC) -> {Y0,Y1} = if Y00 < Y11 -> {Y00+BH-6, Y11+6}; true -> {Y00+6, Y11+BH-6} end, - ?wxGC:strokeLines(DC, [{X0,Y0}, {X0+5,Y0}, {X1-5,Y1}, {X1,Y1}]). + strokeLines(DC, [{X0,Y0}, {X0+5,Y0}, {X1-5,Y1}, {X1,Y1}]). draw_str(DC, #str{x=Sx,y=Sy, text=Text}, X, Y) -> - ?wxGC:drawText(DC, Text, X+Sx,Y+Sy); + drawText(DC, Text, X+Sx,Y+Sy); draw_str(_, _, _, _) -> ok. diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl index 96e433cbf2..c4659d1ea1 100644 --- a/lib/observer/src/observer_perf_wx.erl +++ b/lib/observer/src/observer_perf_wx.erl @@ -23,6 +23,12 @@ -export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, handle_event/2, handle_sync_event/3, handle_cast/2]). +%% Drawing wrappers for DC and GC areas +-export([haveGC/1, + setPen/2, setFont/3, setBrush/2, + strokeLine/5, strokeLines/2, drawRoundedRectangle/6, + drawText/4, getTextExtent/2]). + -behaviour(wx_object). -include_lib("wx/include/wx.hrl"). -include("observer_defs.hrl"). @@ -36,7 +42,8 @@ data = {0, queue:new()}, panel, paint, - appmon + appmon, + usegc = false }). -define(wxGC, wxGraphicsContext). @@ -76,11 +83,18 @@ init([Notebook, Parent]) -> wxPanel:connect(IO, paint, [callback]), wxPanel:connect(MEM, paint, [callback]), - % DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), - %% DefSize = wxFont:getPointSize(DefFont), - %% DefFamily = wxFont:getFamily(DefFont), - %% Font = wxFont:new(DefSize, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD), - Font = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD), + UseGC = haveGC(Panel), + Font = case UseGC of + true -> + %% Def font is really small when using Graphics contexts for some reason + %% Hardcode it + wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD); + false -> + DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT), + DefSize = wxFont:getPointSize(DefFont), + DefFamily = wxFont:getFamily(DefFont), + wxFont:new(DefSize, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD) + end, SmallFont = wxFont:new(10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL), BlackPen = wxPen:new({0,0,0}, [{width, 2}]), Pens = [wxPen:new(Col, [{width, 2}]) || Col <- tuple_to_list(colors())], @@ -88,6 +102,7 @@ init([Notebook, Parent]) -> {Panel, #state{parent=Parent, panel =Panel, windows = {CPU, MEM, IO}, + usegc=UseGC, paint=#paint{font = Font, small = SmallFont, pen = ?wxGREY_PEN, @@ -112,7 +127,7 @@ handle_event(Event, _State) -> %%%%%%%%%% handle_sync_event(#wx{obj=Panel, event = #wxPaint{}},_, #state{active=Active, offset=Offset, paint=Paint, - windows=Windows, data=Data}) -> + windows=Windows, data=Data, usegc=UseGC}) -> %% PaintDC must be created in a callback to work on windows. %% Sigh workaround bug on MacOSX (Id in paint event is always 0) %% Panel = element(Id, Windows), @@ -121,14 +136,17 @@ handle_sync_event(#wx{obj=Panel, event = #wxPaint{}},_, Panel =:= element(?IO_W, Windows) -> ?IO_W end, DC = wxPaintDC:new(Panel), - GC = ?wxGC:create(DC), + GC = case UseGC of + true -> ?wxGC:create(DC); + false -> DC + end, %% Nothing is drawn until wxPaintDC is destroyed. try - draw(Offset, Id, GC, Panel, Paint, Data, Active) + draw(Offset, Id, {UseGC, GC}, Panel, Paint, Data, Active) catch _:Err -> io:format("Internal error ~p ~p~n",[Err, erlang:get_stacktrace()]) end, - ?wxGC:destroy(GC), + UseGC andalso ?wxGC:destroy(GC), wxPaintDC:destroy(DC), ok. %%%%%%%%%% @@ -269,8 +287,8 @@ draw(Offset, Id, DC, Panel, Paint=#paint{pens=Pens, small=Small}, Data, Active) _ -> Draw = fun(N) -> Lines = make_lines(Hs, Start, N, {X0,Max*HS,Last}, Y0, WS, HS), - ?wxGC:setPen(DC, element(1+ ((N-1) rem tuple_size(Pens)), Pens)), - ?wxGC:strokeLines(DC, Lines), + setPen(DC, element(1+ ((N-1) rem tuple_size(Pens)), Pens)), + strokeLines(DC, Lines), N+1 end, [Draw(I) || I <- lists:seq(NoGraphs, 1, -1)] @@ -278,8 +296,8 @@ draw(Offset, Id, DC, Panel, Paint=#paint{pens=Pens, small=Small}, Data, Active) case Active of false -> NotActive = "Service not available", - ?wxGC:setFont(DC, Small, {0,0,0}), - ?wxGC:drawText(DC, NotActive, X0 + 100, element(2,Size) div 2); + setFont(DC, Small, {0,0,0}), + drawText(DC, NotActive, X0 + 100, element(2,Size) div 2); true -> ignore end, @@ -363,9 +381,9 @@ draw_borders(Type, NoGraphs, DC, {W,H}, Max, Str2 = observer_lib:to_str(MaxUnit div 2), Str3 = observer_lib:to_str(0), - ?wxGC:setFont(DC, Font, {0,0,0}), - {TW,TH,_,_} = ?wxGC:getTextExtent(DC, Str1), - {SpaceW, _,_,_} = ?wxGC:getTextExtent(DC, "W"), + setFont(DC, Font, {0,0,0}), + {TW,TH} = getTextExtent(DC, Str1), + {SpaceW, _} = getTextExtent(DC, "W"), GraphX0 = ?BW+TW+?BW, GraphX1 = W-?BW*4, @@ -383,50 +401,50 @@ draw_borders(Type, NoGraphs, DC, {W,H}, Max, ScaleW = GraphW / 60, ScaleH = GraphH / Max, - ?wxGC:setFont(DC, Small, {0,0,0}), + setFont(DC, Small, {0,0,0}), Align = fun(Str, Y) -> - {StrW, _, _, _} = ?wxGC:getTextExtent(DC, Str), - ?wxGC:drawText(DC, Str, GraphX0 - StrW - ?BW, Y) + {StrW, _} = getTextExtent(DC, Str), + drawText(DC, Str, GraphX0 - StrW - ?BW, Y) end, Align(Str1, MaxTextY), Align(Str2, GraphY50 - (TH / 2)), Align(Str3, GraphY1 - (TH / 2) + 1), - ?wxGC:setPen(DC, Pen), + setPen(DC, Pen), DrawSecs = fun(Secs, Pos) -> Str = [observer_lib:to_str(Secs)|" s"], X = GraphX0+Pos, - ?wxGC:drawText(DC, Str, X-SpaceW, SecondsY), - ?wxGC:strokeLine(DC, X, GraphY0, X, GraphY1+5), + drawText(DC, Str, X-SpaceW, SecondsY), + strokeLine(DC, X, GraphY0, X, GraphY1+5), Pos + 10*ScaleW end, lists:foldl(DrawSecs, 0, lists:seq(60,0, -10)), - ?wxGC:strokeLine(DC, GraphX0-3, GraphY25, GraphX1, GraphY25), - ?wxGC:strokeLine(DC, GraphX0-3, GraphY50, GraphX1, GraphY50), - ?wxGC:strokeLine(DC, GraphX0-3, GraphY75, GraphX1, GraphY75), + strokeLine(DC, GraphX0-3, GraphY25, GraphX1, GraphY25), + strokeLine(DC, GraphX0-3, GraphY50, GraphX1, GraphY50), + strokeLine(DC, GraphX0-3, GraphY75, GraphX1, GraphY75), - ?wxGC:setPen(DC, Pen2), - ?wxGC:strokeLines(DC, [{GraphX0, GraphY0-1}, {GraphX0, GraphY1+1}, - {GraphX1, GraphY1+1}, {GraphX1, GraphY0-1}, - {GraphX0, GraphY0-1}]), + setPen(DC, Pen2), + strokeLines(DC, [{GraphX0, GraphY0-1}, {GraphX0, GraphY1+1}, + {GraphX1, GraphY1+1}, {GraphX1, GraphY0-1}, + {GraphX0, GraphY0-1}]), - ?wxGC:setFont(DC, Font, {0,0,0}), + setFont(DC, Font, {0,0,0}), case Type of - ?RQ_W -> ?wxGC:drawText(DC, "Scheduler Utilization (%) ", TopTextX,?BH); - ?MEM_W -> ?wxGC:drawText(DC, "Memory Usage " ++ Unit, TopTextX,?BH); - ?IO_W -> ?wxGC:drawText(DC, "IO Usage " ++ Unit, TopTextX,?BH) + ?RQ_W -> drawText(DC, "Scheduler Utilization (%) ", TopTextX,?BH); + ?MEM_W -> drawText(DC, "Memory Usage " ++ Unit, TopTextX,?BH); + ?IO_W -> drawText(DC, "IO Usage " ++ Unit, TopTextX,?BH) end, Text = fun(X,Y, Str, PenId) -> if PenId == 0 -> - ?wxGC:setFont(DC, Font, {0,0,0}); + setFont(DC, Font, {0,0,0}); PenId > 0 -> Id = 1 + ((PenId-1) rem tuple_size(colors())), - ?wxGC:setFont(DC, Font, element(Id, colors())) + setFont(DC, Font, element(Id, colors())) end, - ?wxGC:drawText(DC, Str, X, Y), - {StrW, _, _, _} = ?wxGC:getTextExtent(DC, Str), + drawText(DC, Str, X, Y), + {StrW, _} = getTextExtent(DC, Str), StrW + X + SpaceW end, case Type of @@ -483,3 +501,56 @@ colors() -> {240, 200, 80}, {140, 2, 140}, {100, 200, 240}, {100, 240, 100} }. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% wxDC and ?wxGC wrappers + +haveGC(Win) -> + try + GC = ?wxGC:create(Win), + ?wxGC:destroy(GC), + true + catch _:_ -> false + end. + +setPen({false, DC}, Pen) -> + wxDC:setPen(DC, Pen); +setPen({true, GC}, Pen) -> + ?wxGC:setPen(GC, Pen). + +setFont({false, DC}, Font, Color) -> + wxDC:setTextForeground(DC, Color), + wxDC:setFont(DC, Font); +setFont({true, GC}, Font, Color) -> + ?wxGC:setFont(GC, Font, Color). + +setBrush({false, DC}, Brush) -> + wxDC:setBrush(DC, Brush); +setBrush({true, GC}, Brush) -> + ?wxGC:setBrush(GC, Brush). + +strokeLine({false, DC}, X0, Y0, X1, Y1) -> + wxDC:drawLine(DC, {round(X0), round(Y0)}, {round(X1), round(Y1)}); +strokeLine({true, GC}, X0, Y0, X1, Y1) -> + ?wxGC:strokeLine(GC, X0, Y0, X1, Y1). + +strokeLines({false, DC}, Lines) -> + wxDC:drawLines(DC, [{round(X), round(Y)} || {X,Y} <- Lines]); +strokeLines({true, GC}, Lines) -> + ?wxGC:strokeLines(GC, Lines). + +drawRoundedRectangle({false, DC}, X0, Y0, X1, Y1, R) -> + wxDC:drawRoundedRectangle(DC, {round(X0), round(Y0)}, {round(X1), round(Y1)}, round(R)); +drawRoundedRectangle({true, GC}, X0, Y0, X1, Y1, R) -> + ?wxGC:drawRoundedRectangle(GC, X0, Y0, X1, Y1, R). + +drawText({false, DC}, Str, X, Y) -> + wxDC:drawText(DC, Str, {round(X),round(Y)}); +drawText({true, GC}, Str, X, Y) -> + ?wxGC:drawText(GC, Str, X, Y). + +getTextExtent({false, DC}, Str) -> + wxDC:getTextExtent(DC, Str); +getTextExtent({true, GC}, Str) -> + {W,H,_,_} = ?wxGC:getTextExtent(GC, Str), + {W,H}. -- cgit v1.2.3