xref: /haiku/src/apps/networkstatus/NetworkStatusView.cpp (revision 96fbe0f747c875841f13add3da288fb64ff38766)
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 <NetworkDevice.h>
415fe97f21SAxel Dörfler #include <NetworkInterface.h>
425fe97f21SAxel Dörfler #include <NetworkRoster.h>
43f01106c3SAxel Dörfler #include <PopUpMenu.h>
44f01106c3SAxel Dörfler #include <Resources.h>
45d5ba07a3SAxel Dörfler #include <Roster.h>
46f01106c3SAxel Dörfler #include <String.h>
47f01106c3SAxel Dörfler #include <TextView.h>
48f01106c3SAxel Dörfler 
49195981bbSAxel Dörfler #include "NetworkStatus.h"
50195981bbSAxel Dörfler #include "NetworkStatusIcons.h"
515fe97f21SAxel Dörfler #include "RadioView.h"
523ca00ffdSAxel Dörfler #include "WirelessNetworkMenuItem.h"
53195981bbSAxel Dörfler 
54f01106c3SAxel Dörfler 
55546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
56546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "NetworkStatusView"
57757e7059SAdrien Destugues 
58757e7059SAdrien Destugues 
59f01106c3SAxel Dörfler static const char *kStatusDescriptions[] = {
602ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("Unknown"),
612ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("No link"),
622ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("No stateful configuration"),
632ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("Configuring"),
642ee8f3f6SSiarzhuk Zharski 	B_TRANSLATE("Ready")
65f01106c3SAxel Dörfler };
66f01106c3SAxel Dörfler 
67efafab64SAxel Dörfler extern "C" _EXPORT BView *instantiate_deskbar_item(float maxWidth, float maxHeight);
68f01106c3SAxel Dörfler 
69f01106c3SAxel Dörfler 
70f01106c3SAxel Dörfler const uint32 kMsgShowConfiguration = 'shcf';
71c1502c9aSStephan Aßmus const uint32 kMsgOpenNetworkPreferences = 'onwp';
722e1a6286SAxel Dörfler const uint32 kMsgJoinNetwork = 'join';
73f01106c3SAxel Dörfler 
74f01106c3SAxel Dörfler const uint32 kMinIconWidth = 16;
75f01106c3SAxel Dörfler const uint32 kMinIconHeight = 16;
76f01106c3SAxel Dörfler 
77195981bbSAxel Dörfler 
78195981bbSAxel Dörfler //	#pragma mark -
79f01106c3SAxel Dörfler 
80f01106c3SAxel Dörfler 
81aba4cb20SMichael Lotz static bool
82aba4cb20SMichael Lotz signal_strength_compare(const wireless_network &a,
83aba4cb20SMichael Lotz 	const wireless_network &b)
84aba4cb20SMichael Lotz {
85aba4cb20SMichael Lotz 	if (a.signal_strength == b.signal_strength)
86aba4cb20SMichael Lotz 		return strcmp(a.name, b.name) > 0;
87aba4cb20SMichael Lotz 	return a.signal_strength > b.signal_strength;
88aba4cb20SMichael Lotz }
89aba4cb20SMichael Lotz 
90aba4cb20SMichael Lotz 
91aba4cb20SMichael Lotz //	#pragma mark -
92aba4cb20SMichael Lotz 
93aba4cb20SMichael Lotz 
94f01106c3SAxel Dörfler NetworkStatusView::NetworkStatusView(BRect frame, int32 resizingMode,
95f01106c3SAxel Dörfler 		bool inDeskbar)
96f01106c3SAxel Dörfler 	: BView(frame, kDeskbarItemName, resizingMode,
9747102c07SX512 		B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_FRAME_EVENTS),
985c46b171SRene Gollent 	fInDeskbar(inDeskbar)
99f01106c3SAxel Dörfler {
100f01106c3SAxel Dörfler 	_Init();
101f01106c3SAxel Dörfler 
102f01106c3SAxel Dörfler 	if (!inDeskbar) {
103f01106c3SAxel Dörfler 		// we were obviously added to a standard window - let's add a dragger
104f01106c3SAxel Dörfler 		frame.OffsetTo(B_ORIGIN);
105f01106c3SAxel Dörfler 		frame.top = frame.bottom - 7;
106f01106c3SAxel Dörfler 		frame.left = frame.right - 7;
107f01106c3SAxel Dörfler 		BDragger* dragger = new BDragger(frame, this,
108f01106c3SAxel Dörfler 			B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
109f01106c3SAxel Dörfler 		AddChild(dragger);
110f01106c3SAxel Dörfler 	} else
111f01106c3SAxel Dörfler 		_Update();
112f01106c3SAxel Dörfler }
113f01106c3SAxel Dörfler 
114f01106c3SAxel Dörfler 
115f01106c3SAxel Dörfler NetworkStatusView::NetworkStatusView(BMessage* archive)
116d5ba07a3SAxel Dörfler 	: BView(archive),
117d5ba07a3SAxel Dörfler 	fInDeskbar(false)
118f01106c3SAxel Dörfler {
119d5ba07a3SAxel Dörfler 	app_info info;
120d5ba07a3SAxel Dörfler 	if (be_app->GetAppInfo(&info) == B_OK
121d5ba07a3SAxel Dörfler 		&& !strcasecmp(info.signature, "application/x-vnd.Be-TSKB"))
122d5ba07a3SAxel Dörfler 		fInDeskbar = true;
123d5ba07a3SAxel Dörfler 
124f01106c3SAxel Dörfler 	_Init();
125f01106c3SAxel Dörfler }
126f01106c3SAxel Dörfler 
127f01106c3SAxel Dörfler 
128f01106c3SAxel Dörfler NetworkStatusView::~NetworkStatusView()
129f01106c3SAxel Dörfler {
130f01106c3SAxel Dörfler }
131f01106c3SAxel Dörfler 
132f01106c3SAxel Dörfler 
133f01106c3SAxel Dörfler void
134f01106c3SAxel Dörfler NetworkStatusView::_Init()
135f01106c3SAxel Dörfler {
136f01106c3SAxel Dörfler 	for (int i = 0; i < kStatusCount; i++) {
137e58807edSAlexander von Gluck IV 		fTrayIcons[i] = NULL;
138e58807edSAlexander von Gluck IV 		fNotifyIcons[i] = NULL;
139f01106c3SAxel Dörfler 	}
140f01106c3SAxel Dörfler 
141f01106c3SAxel Dörfler 	_UpdateBitmaps();
142f01106c3SAxel Dörfler }
143f01106c3SAxel Dörfler 
144f01106c3SAxel Dörfler 
145f01106c3SAxel Dörfler void
146f01106c3SAxel Dörfler NetworkStatusView::_UpdateBitmaps()
147f01106c3SAxel Dörfler {
148f01106c3SAxel Dörfler 	for (int i = 0; i < kStatusCount; i++) {
149e58807edSAlexander von Gluck IV 		delete fTrayIcons[i];
150e58807edSAlexander von Gluck IV 		delete fNotifyIcons[i];
151e58807edSAlexander von Gluck IV 		fTrayIcons[i] = NULL;
152e58807edSAlexander von Gluck IV 		fNotifyIcons[i] = NULL;
153f01106c3SAxel Dörfler 	}
154f01106c3SAxel Dörfler 
155f01106c3SAxel Dörfler 	image_info info;
156f01106c3SAxel Dörfler 	if (our_image(info) != B_OK)
157f01106c3SAxel Dörfler 		return;
158f01106c3SAxel Dörfler 
159f01106c3SAxel Dörfler 	BFile file(info.name, B_READ_ONLY);
160f01106c3SAxel Dörfler 	if (file.InitCheck() < B_OK)
161f01106c3SAxel Dörfler 		return;
162f01106c3SAxel Dörfler 
163f01106c3SAxel Dörfler 	BResources resources(&file);
164f01106c3SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU
165f01106c3SAxel Dörfler 	if (resources.InitCheck() < B_OK)
166f01106c3SAxel Dörfler 		return;
167f01106c3SAxel Dörfler #endif
168f01106c3SAxel Dörfler 
169f01106c3SAxel Dörfler 	for (int i = 0; i < kStatusCount; i++) {
170f01106c3SAxel Dörfler 		const void* data = NULL;
171f01106c3SAxel Dörfler 		size_t size;
172f01106c3SAxel Dörfler 		data = resources.LoadResource(B_VECTOR_ICON_TYPE,
173f01106c3SAxel Dörfler 			kNetworkStatusNoDevice + i, &size);
174f01106c3SAxel Dörfler 		if (data != NULL) {
175e58807edSAlexander von Gluck IV 			// Scale main tray icon
176e58807edSAlexander von Gluck IV 			BBitmap* trayIcon = new BBitmap(Bounds(), B_RGBA32);
177e58807edSAlexander von Gluck IV 			if (trayIcon->InitCheck() == B_OK
178f01106c3SAxel Dörfler 				&& BIconUtils::GetVectorIcon((const uint8 *)data,
179e58807edSAlexander von Gluck IV 					size, trayIcon) == B_OK) {
180e58807edSAlexander von Gluck IV 				fTrayIcons[i] = trayIcon;
181f01106c3SAxel Dörfler 			} else
182e58807edSAlexander von Gluck IV 				delete trayIcon;
183e58807edSAlexander von Gluck IV 
184e58807edSAlexander von Gluck IV 			// Scale notification icon
185e58807edSAlexander von Gluck IV 			BBitmap* notifyIcon = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
186e58807edSAlexander von Gluck IV 			if (notifyIcon->InitCheck() == B_OK
187e58807edSAlexander von Gluck IV 				&& BIconUtils::GetVectorIcon((const uint8 *)data,
188e58807edSAlexander von Gluck IV 					size, notifyIcon) == B_OK) {
189e58807edSAlexander von Gluck IV 				fNotifyIcons[i] = notifyIcon;
190e58807edSAlexander von Gluck IV 			} else
191e58807edSAlexander von Gluck IV 				delete notifyIcon;
192f01106c3SAxel Dörfler 		}
193f01106c3SAxel Dörfler 	}
194f01106c3SAxel Dörfler }
195f01106c3SAxel Dörfler 
196f01106c3SAxel Dörfler 
197f01106c3SAxel Dörfler void
198f01106c3SAxel Dörfler NetworkStatusView::_Quit()
199f01106c3SAxel Dörfler {
200f01106c3SAxel Dörfler 	if (fInDeskbar) {
201f01106c3SAxel Dörfler 		BDeskbar deskbar;
202f01106c3SAxel Dörfler 		deskbar.RemoveItem(kDeskbarItemName);
203f01106c3SAxel Dörfler 	} else
204f01106c3SAxel Dörfler 		be_app->PostMessage(B_QUIT_REQUESTED);
205f01106c3SAxel Dörfler }
206f01106c3SAxel Dörfler 
207f01106c3SAxel Dörfler 
208f01106c3SAxel Dörfler NetworkStatusView*
209f01106c3SAxel Dörfler NetworkStatusView::Instantiate(BMessage* archive)
210f01106c3SAxel Dörfler {
211f01106c3SAxel Dörfler 	if (!validate_instantiation(archive, "NetworkStatusView"))
212f01106c3SAxel Dörfler 		return NULL;
213f01106c3SAxel Dörfler 
214f01106c3SAxel Dörfler 	return new NetworkStatusView(archive);
215f01106c3SAxel Dörfler }
216f01106c3SAxel Dörfler 
217f01106c3SAxel Dörfler 
218f01106c3SAxel Dörfler status_t
219f01106c3SAxel Dörfler NetworkStatusView::Archive(BMessage* archive, bool deep) const
220f01106c3SAxel Dörfler {
221f01106c3SAxel Dörfler 	status_t status = BView::Archive(archive, deep);
222f01106c3SAxel Dörfler 	if (status == B_OK)
223f01106c3SAxel Dörfler 		status = archive->AddString("add_on", kSignature);
224f01106c3SAxel Dörfler 	if (status == B_OK)
225f01106c3SAxel Dörfler 		status = archive->AddString("class", "NetworkStatusView");
226f01106c3SAxel Dörfler 
227f01106c3SAxel Dörfler 	return status;
228f01106c3SAxel Dörfler }
229f01106c3SAxel Dörfler 
230f01106c3SAxel Dörfler 
231f01106c3SAxel Dörfler void
232f01106c3SAxel Dörfler NetworkStatusView::AttachedToWindow()
233f01106c3SAxel Dörfler {
234f01106c3SAxel Dörfler 	BView::AttachedToWindow();
235f01106c3SAxel Dörfler 
236485a9ea0SX512 	SetViewColor(B_TRANSPARENT_COLOR);
237f01106c3SAxel Dörfler 
238195981bbSAxel Dörfler 	start_watching_network(
239195981bbSAxel Dörfler 		B_WATCH_NETWORK_INTERFACE_CHANGES | B_WATCH_NETWORK_LINK_CHANGES, this);
240f01106c3SAxel Dörfler 
241f01106c3SAxel Dörfler 	_Update();
242f01106c3SAxel Dörfler }
243f01106c3SAxel Dörfler 
244f01106c3SAxel Dörfler 
245f01106c3SAxel Dörfler void
246f01106c3SAxel Dörfler NetworkStatusView::DetachedFromWindow()
247f01106c3SAxel Dörfler {
248195981bbSAxel Dörfler 	stop_watching_network(this);
249f01106c3SAxel Dörfler }
250f01106c3SAxel Dörfler 
251f01106c3SAxel Dörfler 
252f01106c3SAxel Dörfler void
253f01106c3SAxel Dörfler NetworkStatusView::MessageReceived(BMessage* message)
254f01106c3SAxel Dörfler {
255f01106c3SAxel Dörfler 	switch (message->what) {
256195981bbSAxel Dörfler 		case B_NETWORK_MONITOR:
257f01106c3SAxel Dörfler 			_Update();
258f01106c3SAxel Dörfler 			break;
259f01106c3SAxel Dörfler 
260f01106c3SAxel Dörfler 		case kMsgShowConfiguration:
261f01106c3SAxel Dörfler 			_ShowConfiguration(message);
262f01106c3SAxel Dörfler 			break;
263f01106c3SAxel Dörfler 
264c1502c9aSStephan Aßmus 		case kMsgOpenNetworkPreferences:
2653b41ad86SStephan Aßmus 			_OpenNetworksPreferences();
2663b41ad86SStephan Aßmus 			break;
2673b41ad86SStephan Aßmus 
2682e1a6286SAxel Dörfler 		case kMsgJoinNetwork:
2692e1a6286SAxel Dörfler 		{
2702e1a6286SAxel Dörfler 			const char* deviceName;
2712e1a6286SAxel Dörfler 			const char* name;
2726c7caf44SAxel Dörfler 			BNetworkAddress address;
2732e1a6286SAxel Dörfler 			if (message->FindString("device", &deviceName) == B_OK
2746c7caf44SAxel Dörfler 				&& message->FindString("name", &name) == B_OK
2756c7caf44SAxel Dörfler 				&& message->FindFlat("address", &address) == B_OK) {
2762e1a6286SAxel Dörfler 				BNetworkDevice device(deviceName);
2776c7caf44SAxel Dörfler 				status_t status = device.JoinNetwork(address);
2782e1a6286SAxel Dörfler 				if (status != B_OK) {
2792e1a6286SAxel Dörfler 					BString text
2802e1a6286SAxel Dörfler 						= B_TRANSLATE("Could not join wireless network:\n");
2812e1a6286SAxel Dörfler 					text << strerror(status);
2822e1a6286SAxel Dörfler 					BAlert* alert = new BAlert(name, text.String(),
2832e1a6286SAxel Dörfler 						B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL,
2842e1a6286SAxel Dörfler 						B_STOP_ALERT);
285aed35104SHumdinger 					alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
2862e1a6286SAxel Dörfler 					alert->Go(NULL);
2872e1a6286SAxel Dörfler 				}
2882e1a6286SAxel Dörfler 			}
2892e1a6286SAxel Dörfler 			break;
2902e1a6286SAxel Dörfler 		}
2912e1a6286SAxel Dörfler 
292f01106c3SAxel Dörfler 		case B_ABOUT_REQUESTED:
293f01106c3SAxel Dörfler 			_AboutRequested();
294f01106c3SAxel Dörfler 			break;
295f01106c3SAxel Dörfler 
296f01106c3SAxel Dörfler 		case B_QUIT_REQUESTED:
297f01106c3SAxel Dörfler 			_Quit();
298f01106c3SAxel Dörfler 			break;
299f01106c3SAxel Dörfler 
300f01106c3SAxel Dörfler 		default:
301f01106c3SAxel Dörfler 			BView::MessageReceived(message);
302ab05d368Ssushilhub 			break;
303f01106c3SAxel Dörfler 	}
304f01106c3SAxel Dörfler }
305f01106c3SAxel Dörfler 
306f01106c3SAxel Dörfler 
307f01106c3SAxel Dörfler void
308f01106c3SAxel Dörfler NetworkStatusView::FrameResized(float width, float height)
309f01106c3SAxel Dörfler {
310f01106c3SAxel Dörfler 	_UpdateBitmaps();
311d5ba07a3SAxel Dörfler 	Invalidate();
312f01106c3SAxel Dörfler }
313f01106c3SAxel Dörfler 
314f01106c3SAxel Dörfler 
315f01106c3SAxel Dörfler void
316f01106c3SAxel Dörfler NetworkStatusView::Draw(BRect updateRect)
317f01106c3SAxel Dörfler {
3185c46b171SRene Gollent 	int32 status = kStatusUnknown;
3195c46b171SRene Gollent 	for (std::map<BString, int32>::const_iterator it
3205c46b171SRene Gollent 		= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); ++it) {
3215c46b171SRene Gollent 		if (it->second > status)
3225c46b171SRene Gollent 			status = it->second;
3235c46b171SRene Gollent 	}
3245c46b171SRene Gollent 
3255c46b171SRene Gollent 	if (fTrayIcons[status] == NULL)
326f01106c3SAxel Dörfler 		return;
327f01106c3SAxel Dörfler 
328f01106c3SAxel Dörfler 	SetDrawingMode(B_OP_ALPHA);
3295c46b171SRene Gollent 	DrawBitmap(fTrayIcons[status]);
330f01106c3SAxel Dörfler 	SetDrawingMode(B_OP_COPY);
331f01106c3SAxel Dörfler }
332f01106c3SAxel Dörfler 
333f01106c3SAxel Dörfler 
334f01106c3SAxel Dörfler void
335f01106c3SAxel Dörfler NetworkStatusView::_ShowConfiguration(BMessage* message)
336f01106c3SAxel Dörfler {
337f01106c3SAxel Dörfler 	const char* name;
338f01106c3SAxel Dörfler 	if (message->FindString("interface", &name) != B_OK)
339f01106c3SAxel Dörfler 		return;
340f01106c3SAxel Dörfler 
3418897f278SStefano Ceccherini 	BNetworkInterface networkInterface(name);
3428897f278SStefano Ceccherini 	if (!networkInterface.Exists())
343f01106c3SAxel Dörfler 		return;
344f01106c3SAxel Dörfler 
3452ee8f3f6SSiarzhuk Zharski 	BString text(B_TRANSLATE("%ifaceName information:\n"));
3462ee8f3f6SSiarzhuk Zharski 	text.ReplaceFirst("%ifaceName", name);
347757e7059SAdrien Destugues 
348f01106c3SAxel Dörfler 	size_t boldLength = text.Length();
349f01106c3SAxel Dörfler 
350b81d67edSJeremy Visser 	int32 numAddrs = networkInterface.CountAddresses();
351b81d67edSJeremy Visser 	for (int32 i = 0; i < numAddrs; i++) {
352b81d67edSJeremy Visser 		BNetworkInterfaceAddress address;
353b81d67edSJeremy Visser 		networkInterface.GetAddressAt(i, address);
354b81d67edSJeremy Visser 		switch (address.Address().Family()) {
355b81d67edSJeremy Visser 			case AF_INET:
356b81d67edSJeremy Visser 				text << "\n" << B_TRANSLATE("IPv4 Address: ")
357b81d67edSJeremy Visser 					<< address.Address().ToString()
358b81d67edSJeremy Visser 					<< "\n" << B_TRANSLATE("Broadcast: ")
359b81d67edSJeremy Visser 					<< address.Broadcast().ToString()
360b81d67edSJeremy Visser 					<< "\n" << B_TRANSLATE("Netmask: ")
361b81d67edSJeremy Visser 					<< address.Mask().ToString()
362b81d67edSJeremy Visser 					<< "\n";
363b81d67edSJeremy Visser 				break;
364b81d67edSJeremy Visser 			case AF_INET6:
365b81d67edSJeremy Visser 				text << "\n" << B_TRANSLATE("IPv6 Address: ")
366*96fbe0f7SAdrien Destugues 					<< address.Address().ToString()
367*96fbe0f7SAdrien Destugues 					<< "/" << address.Mask().PrefixLength()
368b81d67edSJeremy Visser 					<< "\n";
369b81d67edSJeremy Visser 				break;
370b81d67edSJeremy Visser 			default:
371b81d67edSJeremy Visser 				break;
372b81d67edSJeremy Visser 		}
373b81d67edSJeremy Visser 	}
374f01106c3SAxel Dörfler 
375757e7059SAdrien Destugues 	BAlert* alert = new BAlert(name, text.String(), B_TRANSLATE("OK"));
376aed35104SHumdinger 	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
377f01106c3SAxel Dörfler 	BTextView* view = alert->TextView();
378f01106c3SAxel Dörfler 	BFont font;
379f01106c3SAxel Dörfler 
380f01106c3SAxel Dörfler 	view->SetStylable(true);
381f01106c3SAxel Dörfler 	view->GetFont(&font);
382f01106c3SAxel Dörfler 	font.SetFace(B_BOLD_FACE);
383f01106c3SAxel Dörfler 	view->SetFontAndColor(0, boldLength, &font);
384f01106c3SAxel Dörfler 
385f01106c3SAxel Dörfler 	alert->Go(NULL);
386f01106c3SAxel Dörfler }
387f01106c3SAxel Dörfler 
388f01106c3SAxel Dörfler 
389f01106c3SAxel Dörfler void
390f01106c3SAxel Dörfler NetworkStatusView::MouseDown(BPoint point)
391f01106c3SAxel Dörfler {
392f01106c3SAxel Dörfler 	BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
393a31688d2SAxel Dörfler 	menu->SetAsyncAutoDestruct(true);
394f01106c3SAxel Dörfler 	menu->SetFont(be_plain_font);
3955c46b171SRene Gollent 	BString wifiInterface;
3965c46b171SRene Gollent 	BNetworkDevice wifiDevice;
397f01106c3SAxel Dörfler 
3985fe97f21SAxel Dörfler 	// Add interfaces
3995fe97f21SAxel Dörfler 
4005c46b171SRene Gollent 	for (std::map<BString, int32>::const_iterator it
4015c46b171SRene Gollent 		= fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); ++it) {
4025c46b171SRene Gollent 		const BString& name = it->first;
403f01106c3SAxel Dörfler 
404f01106c3SAxel Dörfler 		BString label = name;
405f01106c3SAxel Dörfler 		label += ": ";
406f01106c3SAxel Dörfler 		label += kStatusDescriptions[
407f01106c3SAxel Dörfler 			_DetermineInterfaceStatus(name.String())];
408f01106c3SAxel Dörfler 
409f01106c3SAxel Dörfler 		BMessage* info = new BMessage(kMsgShowConfiguration);
410f01106c3SAxel Dörfler 		info->AddString("interface", name.String());
411f01106c3SAxel Dörfler 		menu->AddItem(new BMenuItem(label.String(), info));
4125c46b171SRene Gollent 
4135c46b171SRene Gollent 		// We only show the networks of the first wireless device we find.
4145c46b171SRene Gollent 		if (wifiInterface.IsEmpty()) {
4155c46b171SRene Gollent 			wifiDevice.SetTo(name);
4165c46b171SRene Gollent 			if (wifiDevice.IsWireless())
4175c46b171SRene Gollent 				wifiInterface = name;
4185c46b171SRene Gollent 		}
419f01106c3SAxel Dörfler 	}
420f01106c3SAxel Dörfler 
4215c46b171SRene Gollent 	if (!fInterfaceStatuses.empty())
422f01106c3SAxel Dörfler 		menu->AddSeparatorItem();
4235fe97f21SAxel Dörfler 
4245fe97f21SAxel Dörfler 	// Add wireless networks, if any
4255fe97f21SAxel Dörfler 
4265c46b171SRene Gollent 	if (!wifiInterface.IsEmpty()) {
427440d0e61SAxel Dörfler 		std::set<BNetworkAddress> associated;
428440d0e61SAxel Dörfler 		BNetworkAddress address;
429440d0e61SAxel Dörfler 		uint32 cookie = 0;
4305c46b171SRene Gollent 		while (wifiDevice.GetNextAssociatedNetwork(cookie, address) == B_OK)
431440d0e61SAxel Dörfler 			associated.insert(address);
432440d0e61SAxel Dörfler 
433440d0e61SAxel Dörfler 		cookie = 0;
434aba4cb20SMichael Lotz 		wireless_network network;
435aba4cb20SMichael Lotz 		typedef std::vector<wireless_network> WirelessNetworkVector;
436aba4cb20SMichael Lotz 		WirelessNetworkVector wirelessNetworks;
437aba4cb20SMichael Lotz 		while (wifiDevice.GetNextNetwork(cookie, network) == B_OK)
438aba4cb20SMichael Lotz 			wirelessNetworks.push_back(network);
439aba4cb20SMichael Lotz 
440aba4cb20SMichael Lotz 		std::sort(wirelessNetworks.begin(), wirelessNetworks.end(),
441aba4cb20SMichael Lotz 			signal_strength_compare);
442aba4cb20SMichael Lotz 
443aba4cb20SMichael Lotz 		int32 count = 0;
444aba4cb20SMichael Lotz 		for (WirelessNetworkVector::iterator it = wirelessNetworks.begin();
445aba4cb20SMichael Lotz 				it != wirelessNetworks.end(); it++) {
446aba4cb20SMichael Lotz 			wireless_network &network = *it;
447aba4cb20SMichael Lotz 
4482e1a6286SAxel Dörfler 			BMessage* message = new BMessage(kMsgJoinNetwork);
4495c46b171SRene Gollent 			message->AddString("device", wifiInterface);
4502e1a6286SAxel Dörfler 			message->AddString("name", network.name);
4516c7caf44SAxel Dörfler 			message->AddFlat("address", &network.address);
4522e1a6286SAxel Dörfler 
453440d0e61SAxel Dörfler 			BMenuItem* item = new WirelessNetworkMenuItem(network.name,
4545bb799c2SPrzemysław Buczkowski 				network.signal_strength, network.authentication_mode, message);
455440d0e61SAxel Dörfler 			menu->AddItem(item);
456440d0e61SAxel Dörfler 			if (associated.find(network.address) != associated.end())
457440d0e61SAxel Dörfler 				item->SetMarked(true);
458440d0e61SAxel Dörfler 
4595fe97f21SAxel Dörfler 			count++;
4605fe97f21SAxel Dörfler 		}
4615fe97f21SAxel Dörfler 		if (count == 0) {
4625fe97f21SAxel Dörfler 			BMenuItem* item = new BMenuItem(
4635fe97f21SAxel Dörfler 				B_TRANSLATE("<no wireless networks found>"), NULL);
4645fe97f21SAxel Dörfler 			item->SetEnabled(false);
4655fe97f21SAxel Dörfler 			menu->AddItem(item);
4665fe97f21SAxel Dörfler 		}
4675fe97f21SAxel Dörfler 		menu->AddSeparatorItem();
4685fe97f21SAxel Dörfler 	}
4695fe97f21SAxel Dörfler 
470757e7059SAdrien Destugues 	menu->AddItem(new BMenuItem(B_TRANSLATE(
471757e7059SAdrien Destugues 		"Open network preferences" B_UTF8_ELLIPSIS),
472c1502c9aSStephan Aßmus 		new BMessage(kMsgOpenNetworkPreferences)));
4733b41ad86SStephan Aßmus 
4745fe97f21SAxel Dörfler 	if (fInDeskbar) {
475757e7059SAdrien Destugues 		menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
476757e7059SAdrien Destugues 			new BMessage(B_QUIT_REQUESTED)));
4775fe97f21SAxel Dörfler 	}
478f01106c3SAxel Dörfler 	menu->SetTargetForItems(this);
479f01106c3SAxel Dörfler 
480f01106c3SAxel Dörfler 	ConvertToScreen(&point);
481a31688d2SAxel Dörfler 	menu->Go(point, true, true, true);
482f01106c3SAxel Dörfler }
483f01106c3SAxel Dörfler 
484f01106c3SAxel Dörfler 
485f01106c3SAxel Dörfler void
486f01106c3SAxel Dörfler NetworkStatusView::_AboutRequested()
487f01106c3SAxel Dörfler {
48831535ac6SAdrien Destugues 	BAboutWindow* window = new BAboutWindow(
48931535ac6SAdrien Destugues 		B_TRANSLATE_SYSTEM_NAME("NetworkStatus"), kSignature);
490fd19c736SAdrien Destugues 
491730a45eeSJohn Scipione 	const char* authors[] = {
492730a45eeSJohn Scipione 		"Axel Dörfler",
493730a45eeSJohn Scipione 		"Hugo Santos",
494730a45eeSJohn Scipione 		NULL
495730a45eeSJohn Scipione 	};
496f01106c3SAxel Dörfler 
497fd19c736SAdrien Destugues 	window->AddCopyright(2007, "Haiku, Inc.");
498fd19c736SAdrien Destugues 	window->AddAuthors(authors);
499fd19c736SAdrien Destugues 
500fd19c736SAdrien Destugues 	window->Show();
501f01106c3SAxel Dörfler }
502f01106c3SAxel Dörfler 
503f01106c3SAxel Dörfler 
504f01106c3SAxel Dörfler int32
5055c46b171SRene Gollent NetworkStatusView::_DetermineInterfaceStatus(
5065c46b171SRene Gollent 	const BNetworkInterface& interface)
507f01106c3SAxel Dörfler {
5085fe97f21SAxel Dörfler 	uint32 flags = interface.Flags();
509f01106c3SAxel Dörfler 
510cb7833c7SPhilippe Houdoin 	if ((flags & IFF_LINK) == 0)
511cb7833c7SPhilippe Houdoin 		return kStatusNoLink;
512cb7833c7SPhilippe Houdoin 	if ((flags & (IFF_UP | IFF_LINK | IFF_CONFIGURING)) == IFF_LINK)
513cb7833c7SPhilippe Houdoin 		return kStatusLinkNoConfig;
5144a531db1SPhilippe Houdoin 	if ((flags & IFF_CONFIGURING) == IFF_CONFIGURING)
515cb7833c7SPhilippe Houdoin 		return kStatusConnecting;
516cb7833c7SPhilippe Houdoin 	if ((flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK))
517cb7833c7SPhilippe Houdoin 		return kStatusReady;
518f01106c3SAxel Dörfler 
519cb7833c7SPhilippe Houdoin 	return kStatusUnknown;
520f01106c3SAxel Dörfler }
521f01106c3SAxel Dörfler 
522f01106c3SAxel Dörfler 
523f01106c3SAxel Dörfler void
524f01106c3SAxel Dörfler NetworkStatusView::_Update(bool force)
525f01106c3SAxel Dörfler {
5265fe97f21SAxel Dörfler 	BNetworkRoster& roster = BNetworkRoster::Default();
5275fe97f21SAxel Dörfler 	BNetworkInterface interface;
5285fe97f21SAxel Dörfler 	uint32 cookie = 0;
5295fe97f21SAxel Dörfler 
5305fe97f21SAxel Dörfler 	while (roster.GetNextInterface(&cookie, interface) == B_OK) {
5315fe97f21SAxel Dörfler 		if ((interface.Flags() & IFF_LOOPBACK) == 0) {
5325c46b171SRene Gollent 			int32 oldStatus = kStatusUnknown;
5335c46b171SRene Gollent 			if (fInterfaceStatuses.find(interface.Name())
5345c46b171SRene Gollent 				!= fInterfaceStatuses.end()) {
5355c46b171SRene Gollent 				oldStatus = fInterfaceStatuses[interface.Name()];
536f01106c3SAxel Dörfler 			}
5375c46b171SRene Gollent 			int32 status = _DetermineInterfaceStatus(interface);
5385c46b171SRene Gollent 			if (oldStatus != status) {
539b44d24c0SAlexander von Gluck IV 				BNotification notification(B_INFORMATION_NOTIFICATION);
540b44d24c0SAlexander von Gluck IV 				notification.SetGroup(B_TRANSLATE("Network Status"));
541b44d24c0SAlexander von Gluck IV 				notification.SetTitle(interface.Name());
542b44d24c0SAlexander von Gluck IV 				notification.SetMessageID(interface.Name());
5435c46b171SRene Gollent 				notification.SetIcon(fNotifyIcons[status]);
5445c46b171SRene Gollent 				if (status == kStatusConnecting
5455c46b171SRene Gollent 					|| (status == kStatusReady
5465c46b171SRene Gollent 						&& oldStatus == kStatusConnecting)
5475c46b171SRene Gollent 					|| (status == kStatusNoLink
5485c46b171SRene Gollent 						&& oldStatus == kStatusReady)
5495c46b171SRene Gollent 					|| (status == kStatusNoLink
5505c46b171SRene Gollent 						&& oldStatus == kStatusConnecting)) {
55143c68287SAlexander von Gluck IV 					// A significant state change, raise notification.
5525c46b171SRene Gollent 					notification.SetContent(kStatusDescriptions[status]);
553b44d24c0SAlexander von Gluck IV 					notification.Send();
554b44d24c0SAlexander von Gluck IV 				}
555f01106c3SAxel Dörfler 				Invalidate();
556f01106c3SAxel Dörfler 			}
5575c46b171SRene Gollent 			fInterfaceStatuses[interface.Name()] = status;
5585c46b171SRene Gollent 		}
5595c46b171SRene Gollent 	}
560b44d24c0SAlexander von Gluck IV }
561f01106c3SAxel Dörfler 
562f01106c3SAxel Dörfler 
5633b41ad86SStephan Aßmus void
5643b41ad86SStephan Aßmus NetworkStatusView::_OpenNetworksPreferences()
5653b41ad86SStephan Aßmus {
566195981bbSAxel Dörfler 	status_t status = be_roster->Launch("application/x-vnd.Haiku-Network");
56746cac7f7SAlexandre Deckner 	if (status != B_OK && status != B_ALREADY_RUNNING) {
568757e7059SAdrien Destugues 		BString errorMessage(B_TRANSLATE("Launching the network preflet "
569757e7059SAdrien Destugues 			"failed.\n\nError: "));
570195981bbSAxel Dörfler 		errorMessage << strerror(status);
5713b41ad86SStephan Aßmus 		BAlert* alert = new BAlert("launch error", errorMessage.String(),
572757e7059SAdrien Destugues 			B_TRANSLATE("OK"));
573aed35104SHumdinger 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
574195981bbSAxel Dörfler 
575195981bbSAxel Dörfler 		// asynchronous alert in order to not block replicant host application
5763b41ad86SStephan Aßmus 		alert->Go(NULL);
5773b41ad86SStephan Aßmus 	}
5783b41ad86SStephan Aßmus }
5793b41ad86SStephan Aßmus 
5803b41ad86SStephan Aßmus 
581f01106c3SAxel Dörfler //	#pragma mark -
582f01106c3SAxel Dörfler 
583f01106c3SAxel Dörfler 
584f01106c3SAxel Dörfler extern "C" _EXPORT BView *
585efafab64SAxel Dörfler instantiate_deskbar_item(float maxWidth, float maxHeight)
586f01106c3SAxel Dörfler {
587efafab64SAxel Dörfler 	return new NetworkStatusView(BRect(0, 0, maxHeight - 1, maxHeight - 1),
58866eba86fSAxel Dörfler 		B_FOLLOW_LEFT | B_FOLLOW_TOP, true);
589f01106c3SAxel Dörfler }
590