xref: /haiku/src/apps/networkstatus/NetworkStatusView.cpp (revision 2710b4f5d4251c5cf88c82b0114ea99b0ef46d22)
1f01106c3SAxel Dörfler /*
26c7caf44SAxel Dörfler  * Copyright 2006-2013, Haiku, Inc. All rights reserved.
3f01106c3SAxel Dörfler  * Distributed under the terms of the MIT License.
4f01106c3SAxel Dörfler  *
5f01106c3SAxel Dörfler  * Authors:
63b41ad86SStephan Aßmus  *		Dario Casalinuovo
7937ca113SRene Gollent  *		Axel Dörfler, axeld@pinc-software.de
85c46b171SRene Gollent  *		Rene Gollent, rene@gollent.com
9937ca113SRene Gollent  *		Hugo Santos, hugosantos@gmail.com
10f01106c3SAxel Dörfler  */
11f01106c3SAxel Dörfler 
12f01106c3SAxel Dörfler 
13f01106c3SAxel Dörfler #include "NetworkStatusView.h"
14f01106c3SAxel Dörfler 
15aba4cb20SMichael Lotz #include <algorithm>
16440d0e61SAxel Dörfler #include <set>
17aba4cb20SMichael Lotz #include <vector>
18440d0e61SAxel Dörfler 
19195981bbSAxel Dörfler #include <arpa/inet.h>
20195981bbSAxel Dörfler #include <net/if.h>
21195981bbSAxel Dörfler #include <stdio.h>
22195981bbSAxel Dörfler #include <stdlib.h>
233aeed660SJérôme Duval #include <strings.h>
24195981bbSAxel Dörfler #include <sys/socket.h>
25195981bbSAxel Dörfler #include <sys/sockio.h>
26195981bbSAxel Dörfler #include <unistd.h>
27f01106c3SAxel Dörfler 
28730a45eeSJohn Scipione #include <AboutWindow.h>
29f01106c3SAxel Dörfler #include <Alert.h>
30f01106c3SAxel Dörfler #include <Application.h>
31757e7059SAdrien Destugues #include <Catalog.h>
32f01106c3SAxel Dörfler #include <Bitmap.h>
33f01106c3SAxel Dörfler #include <Deskbar.h>
34f01106c3SAxel Dörfler #include <Dragger.h>
35f01106c3SAxel Dörfler #include <Drivers.h>
36f01106c3SAxel Dörfler #include <IconUtils.h>
37757e7059SAdrien Destugues #include <Locale.h>
38f01106c3SAxel Dörfler #include <MenuItem.h>
39f01106c3SAxel Dörfler #include <MessageRunner.h>
405fe97f21SAxel Dörfler #include <NetworkInterface.h>
415fe97f21SAxel Dörfler #include <NetworkRoster.h>
42f01106c3SAxel Dörfler #include <PopUpMenu.h>
43f01106c3SAxel Dörfler #include <Resources.h>
44d5ba07a3SAxel Dörfler #include <Roster.h>
45f01106c3SAxel Dörfler #include <String.h>
46f01106c3SAxel Dörfler #include <TextView.h>
47f01106c3SAxel Dörfler 
48195981bbSAxel Dörfler #include "NetworkStatus.h"
49195981bbSAxel Dörfler #include "NetworkStatusIcons.h"
505fe97f21SAxel Dörfler #include "RadioView.h"
513ca00ffdSAxel Dörfler #include "WirelessNetworkMenuItem.h"
52195981bbSAxel Dörfler 
53f01106c3SAxel Dörfler 
54546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
55546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "NetworkStatusView"
56757e7059SAdrien Destugues 
57757e7059SAdrien Destugues 
58f01106c3SAxel Dörfler static const char *kStatusDescriptions[] = {
592ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("Unknown"),
602ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("No link"),
612ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("No stateful configuration"),
622ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("Configuring"),
632ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("Ready")
64f01106c3SAxel Dörfler };
65f01106c3SAxel Dörfler 
66efafab64SAxel Dörfler extern "C" _EXPORT BView *instantiate_deskbar_item(float maxWidth, float maxHeight);
67f01106c3SAxel Dörfler 
68f01106c3SAxel Dörfler 
69f01106c3SAxel Dörfler const uint32 kMsgShowConfiguration = 'shcf';
70c1502c9aSStephan Aßmus const uint32 kMsgOpenNetworkPreferences = 'onwp';
712e1a6286SAxel Dörfler const uint32 kMsgJoinNetwork = 'join';
72f01106c3SAxel Dörfler 
73f01106c3SAxel Dörfler const uint32 kMinIconWidth = 16;
74f01106c3SAxel Dörfler const uint32 kMinIconHeight = 16;
75f01106c3SAxel Dörfler 
76195981bbSAxel Dörfler 
7702ad9218SJohn Scipione //	#pragma mark - NetworkStatusView
78aba4cb20SMichael Lotz 
79aba4cb20SMichael Lotz 
NetworkStatusView(BRect frame,int32 resizingMode,bool inDeskbar)80f01106c3SAxel Dörfler NetworkStatusView::NetworkStatusView(BRect frame, int32 resizingMode,
81f01106c3SAxel Dörfler 		bool inDeskbar)
82f01106c3SAxel Dörfler 	: BView(frame, kDeskbarItemName, resizingMode,
8347102c07SX512 		B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_FRAME_EVENTS),
845c46b171SRene Gollent 	fInDeskbar(inDeskbar)
85f01106c3SAxel Dörfler {
86f01106c3SAxel Dörfler 	_Init();
87f01106c3SAxel Dörfler 
88f01106c3SAxel Dörfler 	if (!inDeskbar) {
89f01106c3SAxel Dörfler 		// we were obviously added to a standard window - let's add a dragger
90f01106c3SAxel Dörfler 		frame.OffsetTo(B_ORIGIN);
91f01106c3SAxel Dörfler 		frame.top = frame.bottom - 7;
92f01106c3SAxel Dörfler 		frame.left = frame.right - 7;
93f01106c3SAxel Dörfler 		BDragger* dragger = new BDragger(frame, this,
94f01106c3SAxel Dörfler 			B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
95f01106c3SAxel Dörfler 		AddChild(dragger);
96f01106c3SAxel Dörfler 	} else
97f01106c3SAxel Dörfler 		_Update();
98f01106c3SAxel Dörfler }
99f01106c3SAxel Dörfler 
100f01106c3SAxel Dörfler 
NetworkStatusView(BMessage * archive)101f01106c3SAxel Dörfler NetworkStatusView::NetworkStatusView(BMessage* archive)
102d5ba07a3SAxel Dörfler 	: BView(archive),
103d5ba07a3SAxel Dörfler 	fInDeskbar(false)
104f01106c3SAxel Dörfler {
105d5ba07a3SAxel Dörfler 	app_info info;
106d5ba07a3SAxel Dörfler 	if (be_app->GetAppInfo(&info) == B_OK
107d5ba07a3SAxel Dörfler 		&& !strcasecmp(info.signature, "application/x-vnd.Be-TSKB"))
108d5ba07a3SAxel Dörfler 		fInDeskbar = true;
109d5ba07a3SAxel Dörfler 
110f01106c3SAxel Dörfler 	_Init();
111f01106c3SAxel Dörfler }
112f01106c3SAxel Dörfler 
113f01106c3SAxel Dörfler 
~NetworkStatusView()114f01106c3SAxel Dörfler NetworkStatusView::~NetworkStatusView()
115f01106c3SAxel Dörfler {
116f01106c3SAxel Dörfler }
117f01106c3SAxel Dörfler 
118f01106c3SAxel Dörfler 
119f01106c3SAxel Dörfler void
_Init()120f01106c3SAxel Dörfler NetworkStatusView::_Init()
121f01106c3SAxel Dörfler {
122f01106c3SAxel Dörfler 	for (int i = 0; i < kStatusCount; i++) {
123e58807edSAlexander von Gluck IV 		fTrayIcons[i] = NULL;
124e58807edSAlexander von Gluck IV 		fNotifyIcons[i] = NULL;
125f01106c3SAxel Dörfler 	}
126f01106c3SAxel Dörfler 
127f01106c3SAxel Dörfler 	_UpdateBitmaps();
128f01106c3SAxel Dörfler }
129f01106c3SAxel Dörfler 
130f01106c3SAxel Dörfler 
131f01106c3SAxel Dörfler void
_UpdateBitmaps()132f01106c3SAxel Dörfler NetworkStatusView::_UpdateBitmaps()
133f01106c3SAxel Dörfler {
134f01106c3SAxel Dörfler 	for (int i = 0; i < kStatusCount; i++) {
135e58807edSAlexander von Gluck IV 		delete fTrayIcons[i];
136e58807edSAlexander von Gluck IV 		delete fNotifyIcons[i];
137e58807edSAlexander von Gluck IV 		fTrayIcons[i] = NULL;
138e58807edSAlexander von Gluck IV 		fNotifyIcons[i] = NULL;
139f01106c3SAxel Dörfler 	}
140f01106c3SAxel Dörfler 
141f01106c3SAxel Dörfler 	image_info info;
142f01106c3SAxel Dörfler 	if (our_image(info) != B_OK)
143f01106c3SAxel Dörfler 		return;
144f01106c3SAxel Dörfler 
145f01106c3SAxel Dörfler 	BFile file(info.name, B_READ_ONLY);
146f01106c3SAxel Dörfler 	if (file.InitCheck() < B_OK)
147f01106c3SAxel Dörfler 		return;
148f01106c3SAxel Dörfler 
149f01106c3SAxel Dörfler 	BResources resources(&file);
150f01106c3SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU
151f01106c3SAxel Dörfler 	if (resources.InitCheck() < B_OK)
152f01106c3SAxel Dörfler 		return;
153f01106c3SAxel Dörfler #endif
154f01106c3SAxel Dörfler 
155f01106c3SAxel Dörfler 	for (int i = 0; i < kStatusCount; i++) {
156f01106c3SAxel Dörfler 		const void* data = NULL;
157f01106c3SAxel Dörfler 		size_t size;
158f01106c3SAxel Dörfler 		data = resources.LoadResource(B_VECTOR_ICON_TYPE,
159f01106c3SAxel Dörfler 			kNetworkStatusNoDevice + i, &size);
160f01106c3SAxel Dörfler 		if (data != NULL) {
161e58807edSAlexander von Gluck IV 			// Scale main tray icon
162e58807edSAlexander von Gluck IV 			BBitmap* trayIcon = new BBitmap(Bounds(), B_RGBA32);
163e58807edSAlexander von Gluck IV 			if (trayIcon->InitCheck() == B_OK
164f01106c3SAxel Dörfler 				&& BIconUtils::GetVectorIcon((const uint8 *)data,
165e58807edSAlexander von Gluck IV 					size, trayIcon) == B_OK) {
166e58807edSAlexander von Gluck IV 				fTrayIcons[i] = trayIcon;
167f01106c3SAxel Dörfler 			} else
168e58807edSAlexander von Gluck IV 				delete trayIcon;
169e58807edSAlexander von Gluck IV 
170e58807edSAlexander von Gluck IV 			// Scale notification icon
171e58807edSAlexander von Gluck IV 			BBitmap* notifyIcon = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
172e58807edSAlexander von Gluck IV 			if (notifyIcon->InitCheck() == B_OK
173e58807edSAlexander von Gluck IV 				&& BIconUtils::GetVectorIcon((const uint8 *)data,
174e58807edSAlexander von Gluck IV 					size, notifyIcon) == B_OK) {
175e58807edSAlexander von Gluck IV 				fNotifyIcons[i] = notifyIcon;
176e58807edSAlexander von Gluck IV 			} else
177e58807edSAlexander von Gluck IV 				delete notifyIcon;
178f01106c3SAxel Dörfler 		}
179f01106c3SAxel Dörfler 	}
180f01106c3SAxel Dörfler }
181f01106c3SAxel Dörfler 
182f01106c3SAxel Dörfler 
183f01106c3SAxel Dörfler void
_Quit()184f01106c3SAxel Dörfler NetworkStatusView::_Quit()
185f01106c3SAxel Dörfler {
186f01106c3SAxel Dörfler 	if (fInDeskbar) {
187f01106c3SAxel Dörfler 		BDeskbar deskbar;
188f01106c3SAxel Dörfler 		deskbar.RemoveItem(kDeskbarItemName);
189f01106c3SAxel Dörfler 	} else
190f01106c3SAxel Dörfler 		be_app->PostMessage(B_QUIT_REQUESTED);
191f01106c3SAxel Dörfler }
192f01106c3SAxel Dörfler 
193f01106c3SAxel Dörfler 
194f01106c3SAxel Dörfler NetworkStatusView*
Instantiate(BMessage * archive)195f01106c3SAxel Dörfler NetworkStatusView::Instantiate(BMessage* archive)
196f01106c3SAxel Dörfler {
197f01106c3SAxel Dörfler 	if (!validate_instantiation(archive, "NetworkStatusView"))
198f01106c3SAxel Dörfler 		return NULL;
199f01106c3SAxel Dörfler 
200f01106c3SAxel Dörfler 	return new NetworkStatusView(archive);
201f01106c3SAxel Dörfler }
202f01106c3SAxel Dörfler 
203f01106c3SAxel Dörfler 
204f01106c3SAxel Dörfler status_t
Archive(BMessage * archive,bool deep) const205f01106c3SAxel Dörfler NetworkStatusView::Archive(BMessage* archive, bool deep) const
206f01106c3SAxel Dörfler {
207f01106c3SAxel Dörfler 	status_t status = BView::Archive(archive, deep);
208f01106c3SAxel Dörfler 	if (status == B_OK)
209f01106c3SAxel Dörfler 		status = archive->AddString("add_on", kSignature);
210f01106c3SAxel Dörfler 	if (status == B_OK)
211f01106c3SAxel Dörfler 		status = archive->AddString("class", "NetworkStatusView");
212f01106c3SAxel Dörfler 
213f01106c3SAxel Dörfler 	return status;
214f01106c3SAxel Dörfler }
215f01106c3SAxel Dörfler 
216f01106c3SAxel Dörfler 
217f01106c3SAxel Dörfler void
AttachedToWindow()218f01106c3SAxel Dörfler NetworkStatusView::AttachedToWindow()
219f01106c3SAxel Dörfler {
220f01106c3SAxel Dörfler 	BView::AttachedToWindow();
221f01106c3SAxel Dörfler 
222485a9ea0SX512 	SetViewColor(B_TRANSPARENT_COLOR);
223f01106c3SAxel Dörfler 
224195981bbSAxel Dörfler 	start_watching_network(
225195981bbSAxel Dörfler 		B_WATCH_NETWORK_INTERFACE_CHANGES | B_WATCH_NETWORK_LINK_CHANGES, this);
226f01106c3SAxel Dörfler 
227f01106c3SAxel Dörfler 	_Update();
228f01106c3SAxel Dörfler }
229f01106c3SAxel Dörfler 
230f01106c3SAxel Dörfler 
231f01106c3SAxel Dörfler void
DetachedFromWindow()232f01106c3SAxel Dörfler NetworkStatusView::DetachedFromWindow()
233f01106c3SAxel Dörfler {
234195981bbSAxel Dörfler 	stop_watching_network(this);
235f01106c3SAxel Dörfler }
236f01106c3SAxel Dörfler 
237f01106c3SAxel Dörfler 
238f01106c3SAxel Dörfler void
MessageReceived(BMessage * message)239f01106c3SAxel Dörfler NetworkStatusView::MessageReceived(BMessage* message)
240f01106c3SAxel Dörfler {
241f01106c3SAxel Dörfler 	switch (message->what) {
242195981bbSAxel Dörfler 		case B_NETWORK_MONITOR:
243f01106c3SAxel Dörfler 			_Update();
244f01106c3SAxel Dörfler 			break;
245f01106c3SAxel Dörfler 
246f01106c3SAxel Dörfler 		case kMsgShowConfiguration:
247f01106c3SAxel Dörfler 			_ShowConfiguration(message);
248f01106c3SAxel Dörfler 			break;
249f01106c3SAxel Dörfler 
250c1502c9aSStephan Aßmus 		case kMsgOpenNetworkPreferences:
2513b41ad86SStephan Aßmus 			_OpenNetworksPreferences();
2523b41ad86SStephan Aßmus 			break;
2533b41ad86SStephan Aßmus 
2542e1a6286SAxel Dörfler 		case kMsgJoinNetwork:
2552e1a6286SAxel Dörfler 		{
2562e1a6286SAxel Dörfler 			const char* deviceName;
2572e1a6286SAxel Dörfler 			const char* name;
2586c7caf44SAxel Dörfler 			BNetworkAddress address;
2592e1a6286SAxel Dörfler 			if (message->FindString("device", &deviceName) == B_OK
2606c7caf44SAxel Dörfler 				&& message->FindString("name", &name) == B_OK
2616c7caf44SAxel Dörfler 				&& message->FindFlat("address", &address) == B_OK) {
2622e1a6286SAxel Dörfler 				BNetworkDevice device(deviceName);
2636c7caf44SAxel Dörfler 				status_t status = device.JoinNetwork(address);
2642e1a6286SAxel Dörfler 				if (status != B_OK) {
2652e1a6286SAxel Dörfler 					BString text
2662e1a6286SAxel Dörfler 						= B_TRANSLATE("Could not join wireless network:\n");
2672e1a6286SAxel Dörfler 					text << strerror(status);
2682e1a6286SAxel Dörfler 					BAlert* alert = new BAlert(name, text.String(),
2692e1a6286SAxel Dörfler 						B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL,
2702e1a6286SAxel Dörfler 						B_STOP_ALERT);
271aed35104SHumdinger 					alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
2722e1a6286SAxel Dörfler 					alert->Go(NULL);
2732e1a6286SAxel Dörfler 				}
2742e1a6286SAxel Dörfler 			}
2752e1a6286SAxel Dörfler 			break;
2762e1a6286SAxel Dörfler 		}
2772e1a6286SAxel Dörfler 
278f01106c3SAxel Dörfler 		case B_ABOUT_REQUESTED:
279f01106c3SAxel Dörfler 			_AboutRequested();
280f01106c3SAxel Dörfler 			break;
281f01106c3SAxel Dörfler 
282f01106c3SAxel Dörfler 		case B_QUIT_REQUESTED:
283f01106c3SAxel Dörfler 			_Quit();
284f01106c3SAxel Dörfler 			break;
285f01106c3SAxel Dörfler 
286f01106c3SAxel Dörfler 		default:
287f01106c3SAxel Dörfler 			BView::MessageReceived(message);
288ab05d368Ssushilhub 			break;
289f01106c3SAxel Dörfler 	}
290f01106c3SAxel Dörfler }
291f01106c3SAxel Dörfler 
292f01106c3SAxel Dörfler 
293f01106c3SAxel Dörfler void
FrameResized(float width,float height)294f01106c3SAxel Dörfler NetworkStatusView::FrameResized(float width, float height)
295f01106c3SAxel Dörfler {
296f01106c3SAxel Dörfler 	_UpdateBitmaps();
297d5ba07a3SAxel Dörfler 	Invalidate();
298f01106c3SAxel Dörfler }
299f01106c3SAxel Dörfler 
300f01106c3SAxel Dörfler 
301f01106c3SAxel Dörfler void
Draw(BRect updateRect)302f01106c3SAxel Dörfler NetworkStatusView::Draw(BRect updateRect)
303f01106c3SAxel Dörfler {
3045c46b171SRene Gollent 	int32 status = kStatusUnknown;
3055c46b171SRene Gollent 	for (std::map<BString, int32>::const_iterator it
3065c46b171SRene Gollent 		= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); ++it) {
3075c46b171SRene Gollent 		if (it->second > status)
3085c46b171SRene Gollent 			status = it->second;
3095c46b171SRene Gollent 	}
3105c46b171SRene Gollent 
3115c46b171SRene Gollent 	if (fTrayIcons[status] == NULL)
312f01106c3SAxel Dörfler 		return;
313f01106c3SAxel Dörfler 
314f01106c3SAxel Dörfler 	SetDrawingMode(B_OP_ALPHA);
3155c46b171SRene Gollent 	DrawBitmap(fTrayIcons[status]);
316f01106c3SAxel Dörfler 	SetDrawingMode(B_OP_COPY);
317f01106c3SAxel Dörfler }
318f01106c3SAxel Dörfler 
319f01106c3SAxel Dörfler 
320f01106c3SAxel Dörfler void
_ShowConfiguration(BMessage * message)321f01106c3SAxel Dörfler NetworkStatusView::_ShowConfiguration(BMessage* message)
322f01106c3SAxel Dörfler {
323f01106c3SAxel Dörfler 	const char* name;
324f01106c3SAxel Dörfler 	if (message->FindString("interface", &name) != B_OK)
325f01106c3SAxel Dörfler 		return;
326f01106c3SAxel Dörfler 
3278897f278SStefano Ceccherini 	BNetworkInterface networkInterface(name);
3288897f278SStefano Ceccherini 	if (!networkInterface.Exists())
329f01106c3SAxel Dörfler 		return;
330f01106c3SAxel Dörfler 
3312ee8f3f6SSiarzhuk Zharski 	BString text(B_TRANSLATE("%ifaceName information:\n"));
3322ee8f3f6SSiarzhuk Zharski 	text.ReplaceFirst("%ifaceName", name);
333757e7059SAdrien Destugues 
334f01106c3SAxel Dörfler 	size_t boldLength = text.Length();
335f01106c3SAxel Dörfler 
336b81d67edSJeremy Visser 	int32 numAddrs = networkInterface.CountAddresses();
337b81d67edSJeremy Visser 	for (int32 i = 0; i < numAddrs; i++) {
338b81d67edSJeremy Visser 		BNetworkInterfaceAddress address;
339b81d67edSJeremy Visser 		networkInterface.GetAddressAt(i, address);
340b81d67edSJeremy Visser 		switch (address.Address().Family()) {
341b81d67edSJeremy Visser 			case AF_INET:
3428ff235aaSHumdinger 				text << "\n" << B_TRANSLATE("IPv4 address:") << " "
343b81d67edSJeremy Visser 					<< address.Address().ToString()
3448ff235aaSHumdinger 					<< "\n" << B_TRANSLATE("Broadcast:") << " "
345b81d67edSJeremy Visser 					<< address.Broadcast().ToString()
3468ff235aaSHumdinger 					<< "\n" << B_TRANSLATE("Netmask:") << " "
347b81d67edSJeremy Visser 					<< address.Mask().ToString()
348b81d67edSJeremy Visser 					<< "\n";
349b81d67edSJeremy Visser 				break;
350b81d67edSJeremy Visser 			case AF_INET6:
3518ff235aaSHumdinger 				text << "\n" << B_TRANSLATE("IPv6 address:") << " "
35296fbe0f7SAdrien Destugues 					<< address.Address().ToString()
35396fbe0f7SAdrien Destugues 					<< "/" << address.Mask().PrefixLength()
354b81d67edSJeremy Visser 					<< "\n";
355b81d67edSJeremy Visser 				break;
356b81d67edSJeremy Visser 			default:
357b81d67edSJeremy Visser 				break;
358b81d67edSJeremy Visser 		}
359b81d67edSJeremy Visser 	}
360f01106c3SAxel Dörfler 
361757e7059SAdrien Destugues 	BAlert* alert = new BAlert(name, text.String(), B_TRANSLATE("OK"));
362aed35104SHumdinger 	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
363f01106c3SAxel Dörfler 	BTextView* view = alert->TextView();
364f01106c3SAxel Dörfler 	BFont font;
365f01106c3SAxel Dörfler 
366f01106c3SAxel Dörfler 	view->SetStylable(true);
367f01106c3SAxel Dörfler 	view->GetFont(&font);
368f01106c3SAxel Dörfler 	font.SetFace(B_BOLD_FACE);
369f01106c3SAxel Dörfler 	view->SetFontAndColor(0, boldLength, &font);
370f01106c3SAxel Dörfler 
371f01106c3SAxel Dörfler 	alert->Go(NULL);
372f01106c3SAxel Dörfler }
373f01106c3SAxel Dörfler 
374f01106c3SAxel Dörfler 
375f01106c3SAxel Dörfler void
MouseDown(BPoint point)376f01106c3SAxel Dörfler NetworkStatusView::MouseDown(BPoint point)
377f01106c3SAxel Dörfler {
378f01106c3SAxel Dörfler 	BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
379a31688d2SAxel Dörfler 	menu->SetAsyncAutoDestruct(true);
380f01106c3SAxel Dörfler 	menu->SetFont(be_plain_font);
3815c46b171SRene Gollent 	BString wifiInterface;
38202ad9218SJohn Scipione 	BNetworkDevice device;
383f01106c3SAxel Dörfler 
38402ad9218SJohn Scipione 	if (!fInterfaceStatuses.empty()) {
3855c46b171SRene Gollent 		for (std::map<BString, int32>::const_iterator it
38602ad9218SJohn Scipione 				= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end();
38702ad9218SJohn Scipione 				++it) {
3885c46b171SRene Gollent 			const BString& name = it->first;
389f01106c3SAxel Dörfler 
39002ad9218SJohn Scipione 			// we only show network of the first wireless device we find
3915c46b171SRene Gollent 			if (wifiInterface.IsEmpty()) {
39202ad9218SJohn Scipione 				device.SetTo(name);
39302ad9218SJohn Scipione 				if (device.IsWireless())
3945c46b171SRene Gollent 					wifiInterface = name;
3955c46b171SRene Gollent 			}
396f01106c3SAxel Dörfler 		}
39702ad9218SJohn Scipione 	}
398f01106c3SAxel Dörfler 
39902ad9218SJohn Scipione 	// Add wireless networks, if any, first so that we can sort the menu
4005fe97f21SAxel Dörfler 
4015c46b171SRene Gollent 	if (!wifiInterface.IsEmpty()) {
402440d0e61SAxel Dörfler 		std::set<BNetworkAddress> associated;
403440d0e61SAxel Dörfler 		BNetworkAddress address;
404440d0e61SAxel Dörfler 		uint32 cookie = 0;
40502ad9218SJohn Scipione 		while (device.GetNextAssociatedNetwork(cookie, address) == B_OK)
406440d0e61SAxel Dörfler 			associated.insert(address);
407440d0e61SAxel Dörfler 
408*b2c77ad2SAugustin Cavalier 		uint32 networksCount = 0;
409*b2c77ad2SAugustin Cavalier 		wireless_network* networks = NULL;
410*b2c77ad2SAugustin Cavalier 		device.GetNetworks(networks, networksCount);
411*b2c77ad2SAugustin Cavalier 		for (uint32 i = 0; i < networksCount; i++) {
412*b2c77ad2SAugustin Cavalier 			const wireless_network& network = networks[i];
4132e1a6286SAxel Dörfler 			BMessage* message = new BMessage(kMsgJoinNetwork);
4145c46b171SRene Gollent 			message->AddString("device", wifiInterface);
4152e1a6286SAxel Dörfler 			message->AddString("name", network.name);
4166c7caf44SAxel Dörfler 			message->AddFlat("address", &network.address);
4172e1a6286SAxel Dörfler 
41802ad9218SJohn Scipione 			BMenuItem* item = new WirelessNetworkMenuItem(network, message);
419440d0e61SAxel Dörfler 			menu->AddItem(item);
420440d0e61SAxel Dörfler 			if (associated.find(network.address) != associated.end())
421440d0e61SAxel Dörfler 				item->SetMarked(true);
4225fe97f21SAxel Dörfler 		}
423*b2c77ad2SAugustin Cavalier 		delete[] networks;
42402ad9218SJohn Scipione 
425*b2c77ad2SAugustin Cavalier 		if (networksCount == 0) {
4265fe97f21SAxel Dörfler 			BMenuItem* item = new BMenuItem(
4275fe97f21SAxel Dörfler 				B_TRANSLATE("<no wireless networks found>"), NULL);
4285fe97f21SAxel Dörfler 			item->SetEnabled(false);
4295fe97f21SAxel Dörfler 			menu->AddItem(item);
43002ad9218SJohn Scipione 		} else
43102ad9218SJohn Scipione 			menu->SortItems(WirelessNetworkMenuItem::CompareSignalStrength);
43202ad9218SJohn Scipione 
4335fe97f21SAxel Dörfler 		menu->AddSeparatorItem();
4345fe97f21SAxel Dörfler 	}
4355fe97f21SAxel Dörfler 
43602ad9218SJohn Scipione 	// add action menu items
43702ad9218SJohn Scipione 
438757e7059SAdrien Destugues 	menu->AddItem(new BMenuItem(B_TRANSLATE(
439757e7059SAdrien Destugues 		"Open network preferences" B_UTF8_ELLIPSIS),
440c1502c9aSStephan Aßmus 		new BMessage(kMsgOpenNetworkPreferences)));
4413b41ad86SStephan Aßmus 
4425fe97f21SAxel Dörfler 	if (fInDeskbar) {
443757e7059SAdrien Destugues 		menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
444757e7059SAdrien Destugues 			new BMessage(B_QUIT_REQUESTED)));
4455fe97f21SAxel Dörfler 	}
44602ad9218SJohn Scipione 
44702ad9218SJohn Scipione 	// Add wired interfaces to top of menu
44802ad9218SJohn Scipione 	if (!fInterfaceStatuses.empty()) {
44902ad9218SJohn Scipione 		int32 wiredCount = 0;
45002ad9218SJohn Scipione 		for (std::map<BString, int32>::const_iterator it
45102ad9218SJohn Scipione 				= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end();
45202ad9218SJohn Scipione 				++it) {
45302ad9218SJohn Scipione 			const BString& name = it->first;
45402ad9218SJohn Scipione 
45502ad9218SJohn Scipione 			BString label = name;
45602ad9218SJohn Scipione 			label += ": ";
45702ad9218SJohn Scipione 			label += kStatusDescriptions[
45802ad9218SJohn Scipione 				_DetermineInterfaceStatus(name.String())];
45902ad9218SJohn Scipione 
46002ad9218SJohn Scipione 			BMessage* info = new BMessage(kMsgShowConfiguration);
46102ad9218SJohn Scipione 			info->AddString("interface", name.String());
46202ad9218SJohn Scipione 			menu->AddItem(new BMenuItem(label.String(), info), wiredCount);
46302ad9218SJohn Scipione 			wiredCount++;
46402ad9218SJohn Scipione 		}
46502ad9218SJohn Scipione 
46602ad9218SJohn Scipione 		// add separator item between wired and wireless networks
46702ad9218SJohn Scipione 		// (or between wired networks and actions if no wireless found)
46802ad9218SJohn Scipione 		if (wiredCount > 0)
46902ad9218SJohn Scipione 			menu->AddItem(new BSeparatorItem(), wiredCount);
47002ad9218SJohn Scipione 	}
47102ad9218SJohn Scipione 
472f01106c3SAxel Dörfler 	menu->SetTargetForItems(this);
473f01106c3SAxel Dörfler 
474f01106c3SAxel Dörfler 	ConvertToScreen(&point);
475a31688d2SAxel Dörfler 	menu->Go(point, true, true, true);
476f01106c3SAxel Dörfler }
477f01106c3SAxel Dörfler 
478f01106c3SAxel Dörfler 
479f01106c3SAxel Dörfler void
_AboutRequested()480f01106c3SAxel Dörfler NetworkStatusView::_AboutRequested()
481f01106c3SAxel Dörfler {
48231535ac6SAdrien Destugues 	BAboutWindow* window = new BAboutWindow(
48331535ac6SAdrien Destugues 		B_TRANSLATE_SYSTEM_NAME("NetworkStatus"), kSignature);
484fd19c736SAdrien Destugues 
485730a45eeSJohn Scipione 	const char* authors[] = {
486730a45eeSJohn Scipione 		"Axel Dörfler",
487730a45eeSJohn Scipione 		"Hugo Santos",
488730a45eeSJohn Scipione 		NULL
489730a45eeSJohn Scipione 	};
490f01106c3SAxel Dörfler 
491fd19c736SAdrien Destugues 	window->AddCopyright(2007, "Haiku, Inc.");
492fd19c736SAdrien Destugues 	window->AddAuthors(authors);
493fd19c736SAdrien Destugues 
494fd19c736SAdrien Destugues 	window->Show();
495f01106c3SAxel Dörfler }
496f01106c3SAxel Dörfler 
497f01106c3SAxel Dörfler 
498f01106c3SAxel Dörfler int32
_DetermineInterfaceStatus(const BNetworkInterface & interface)4995c46b171SRene Gollent NetworkStatusView::_DetermineInterfaceStatus(
5005c46b171SRene Gollent 	const BNetworkInterface& interface)
501f01106c3SAxel Dörfler {
5025fe97f21SAxel Dörfler 	uint32 flags = interface.Flags();
503f01106c3SAxel Dörfler 
504cb7833c7SPhilippe Houdoin 	if ((flags & IFF_LINK) == 0)
505cb7833c7SPhilippe Houdoin 		return kStatusNoLink;
506cb7833c7SPhilippe Houdoin 	if ((flags & (IFF_UP | IFF_LINK | IFF_CONFIGURING)) == IFF_LINK)
507cb7833c7SPhilippe Houdoin 		return kStatusLinkNoConfig;
5084a531db1SPhilippe Houdoin 	if ((flags & IFF_CONFIGURING) == IFF_CONFIGURING)
509cb7833c7SPhilippe Houdoin 		return kStatusConnecting;
510cb7833c7SPhilippe Houdoin 	if ((flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK))
511cb7833c7SPhilippe Houdoin 		return kStatusReady;
512f01106c3SAxel Dörfler 
513cb7833c7SPhilippe Houdoin 	return kStatusUnknown;
514f01106c3SAxel Dörfler }
515f01106c3SAxel Dörfler 
516f01106c3SAxel Dörfler 
517f01106c3SAxel Dörfler void
_Update(bool force)518f01106c3SAxel Dörfler NetworkStatusView::_Update(bool force)
519f01106c3SAxel Dörfler {
5205fe97f21SAxel Dörfler 	BNetworkRoster& roster = BNetworkRoster::Default();
5215fe97f21SAxel Dörfler 	BNetworkInterface interface;
5225fe97f21SAxel Dörfler 	uint32 cookie = 0;
523702ff421SJavier Steinaker 	std::set<BString> currentInterfaces;
5245fe97f21SAxel Dörfler 
5255fe97f21SAxel Dörfler 	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
5265fe97f21SAxel Dörfler 		if ((interface.Flags() & IFF_LOOPBACK) == 0) {
527702ff421SJavier Steinaker 			currentInterfaces.insert((BString)interface.Name());
5285c46b171SRene Gollent 			int32 oldStatus = kStatusUnknown;
5295c46b171SRene Gollent 			if (fInterfaceStatuses.find(interface.Name())
5305c46b171SRene Gollent 				!= fInterfaceStatuses.end()) {
5315c46b171SRene Gollent 				oldStatus = fInterfaceStatuses[interface.Name()];
532f01106c3SAxel Dörfler 			}
5335c46b171SRene Gollent 			int32 status = _DetermineInterfaceStatus(interface);
5345c46b171SRene Gollent 			if (oldStatus != status) {
535b44d24c0SAlexander von Gluck IV 				BNotification notification(B_INFORMATION_NOTIFICATION);
536b44d24c0SAlexander von Gluck IV 				notification.SetGroup(B_TRANSLATE("Network Status"));
537b44d24c0SAlexander von Gluck IV 				notification.SetTitle(interface.Name());
538b44d24c0SAlexander von Gluck IV 				notification.SetMessageID(interface.Name());
5395c46b171SRene Gollent 				notification.SetIcon(fNotifyIcons[status]);
5405c46b171SRene Gollent 				if (status == kStatusConnecting
5415c46b171SRene Gollent 					|| (status == kStatusReady
5425c46b171SRene Gollent 						&& oldStatus == kStatusConnecting)
5435c46b171SRene Gollent 					|| (status == kStatusNoLink
5445c46b171SRene Gollent 						&& oldStatus == kStatusReady)
5455c46b171SRene Gollent 					|| (status == kStatusNoLink
5465c46b171SRene Gollent 						&& oldStatus == kStatusConnecting)) {
54743c68287SAlexander von Gluck IV 					// A significant state change, raise notification.
5485c46b171SRene Gollent 					notification.SetContent(kStatusDescriptions[status]);
549b44d24c0SAlexander von Gluck IV 					notification.Send();
550b44d24c0SAlexander von Gluck IV 				}
551f01106c3SAxel Dörfler 				Invalidate();
552f01106c3SAxel Dörfler 			}
5535c46b171SRene Gollent 			fInterfaceStatuses[interface.Name()] = status;
5545c46b171SRene Gollent 		}
5555c46b171SRene Gollent 	}
556702ff421SJavier Steinaker 
557702ff421SJavier Steinaker 	// Check every element in fInterfaceStatuses against our current interface
558702ff421SJavier Steinaker 	// list. If it's not there, then the interface is not present anymore and
559702ff421SJavier Steinaker 	// should be removed from fInterfaceStatuses.
560702ff421SJavier Steinaker 	std::map<BString, int32>::iterator it = fInterfaceStatuses.begin();
561702ff421SJavier Steinaker 	while (it != fInterfaceStatuses.end()) {
562702ff421SJavier Steinaker 		std::map<BString, int32>::iterator backupIt = it;
563702ff421SJavier Steinaker 		if (currentInterfaces.find(it->first) == currentInterfaces.end())
564702ff421SJavier Steinaker 			fInterfaceStatuses.erase(it);
565702ff421SJavier Steinaker 		it = ++backupIt;
566702ff421SJavier Steinaker 	}
567b44d24c0SAlexander von Gluck IV }
568f01106c3SAxel Dörfler 
569f01106c3SAxel Dörfler 
5703b41ad86SStephan Aßmus void
_OpenNetworksPreferences()5713b41ad86SStephan Aßmus NetworkStatusView::_OpenNetworksPreferences()
5723b41ad86SStephan Aßmus {
573195981bbSAxel Dörfler 	status_t status = be_roster->Launch("application/x-vnd.Haiku-Network");
57446cac7f7SAlexandre Deckner 	if (status != B_OK && status != B_ALREADY_RUNNING) {
575757e7059SAdrien Destugues 		BString errorMessage(B_TRANSLATE("Launching the network preflet "
576757e7059SAdrien Destugues 			"failed.\n\nError: "));
577195981bbSAxel Dörfler 		errorMessage << strerror(status);
5783b41ad86SStephan Aßmus 		BAlert* alert = new BAlert("launch error", errorMessage.String(),
579757e7059SAdrien Destugues 			B_TRANSLATE("OK"));
580aed35104SHumdinger 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
581195981bbSAxel Dörfler 
582195981bbSAxel Dörfler 		// asynchronous alert in order to not block replicant host application
5833b41ad86SStephan Aßmus 		alert->Go(NULL);
5843b41ad86SStephan Aßmus 	}
5853b41ad86SStephan Aßmus }
5863b41ad86SStephan Aßmus 
5873b41ad86SStephan Aßmus 
588f01106c3SAxel Dörfler //	#pragma mark -
589f01106c3SAxel Dörfler 
590f01106c3SAxel Dörfler 
591f01106c3SAxel Dörfler extern "C" _EXPORT BView *
instantiate_deskbar_item(float maxWidth,float maxHeight)592efafab64SAxel Dörfler instantiate_deskbar_item(float maxWidth, float maxHeight)
593f01106c3SAxel Dörfler {
594efafab64SAxel Dörfler 	return new NetworkStatusView(BRect(0, 0, maxHeight - 1, maxHeight - 1),
59566eba86fSAxel Dörfler 		B_FOLLOW_LEFT | B_FOLLOW_TOP, true);
596f01106c3SAxel Dörfler }
597