1/*
2 * Copyright 2009-2021, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Weirauch, dev@m-phasis.de
7 */
8
9
10#include "DeskbarReplicant.h"
11
12#include <Alert.h>
13#include <Application.h>
14#include <Bitmap.h>
15#include <Catalog.h>
16#include <Deskbar.h>
17#include <IconUtils.h>
18#include <MenuItem.h>
19#include <Message.h>
20#include <PopUpMenu.h>
21#include <Resources.h>
22#include <Roster.h>
23#include <String.h>
24
25#include <bluetoothserver_p.h>
26
27
28extern "C" _EXPORT BView *instantiate_deskbar_item(float maxWidth, float maxHeight);
29status_t our_image(image_info& image);
30
31const uint32 kMsgOpenBluetoothPreferences = 'obtp';
32const uint32 kMsgQuitBluetoothServer = 'qbts';
33
34const char* kDeskbarItemName = "BluetoothServerReplicant";
35const char* kClassName = "DeskbarReplicant";
36
37
38#undef B_TRANSLATION_CONTEXT
39#define B_TRANSLATION_CONTEXT "BluetoothReplicant"
40
41
42//	#pragma mark -
43
44
45DeskbarReplicant::DeskbarReplicant(BRect frame, int32 resizingMode)
46	: BView(frame, kDeskbarItemName, resizingMode,
47		B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_FRAME_EVENTS)
48{
49	_Init();
50}
51
52
53DeskbarReplicant::DeskbarReplicant(BMessage* archive)
54	: BView(archive)
55{
56	_Init();
57}
58
59
60DeskbarReplicant::~DeskbarReplicant()
61{
62}
63
64
65void
66DeskbarReplicant::_Init()
67{
68	fIcon = NULL;
69
70	image_info info;
71	if (our_image(info) != B_OK)
72		return;
73
74	BFile file(info.name, B_READ_ONLY);
75	if (file.InitCheck() < B_OK)
76		return;
77
78	BResources resources(&file);
79	if (resources.InitCheck() < B_OK)
80		return;
81
82	size_t size;
83	const void* data = resources.LoadResource(B_VECTOR_ICON_TYPE,
84		"tray_icon", &size);
85	if (data != NULL) {
86		BBitmap* icon = new BBitmap(Bounds(), B_RGBA32);
87		if (icon->InitCheck() == B_OK
88			&& BIconUtils::GetVectorIcon((const uint8 *)data,
89				size, icon) == B_OK) {
90			fIcon = icon;
91		} else
92			delete icon;
93	}
94}
95
96
97DeskbarReplicant *
98DeskbarReplicant::Instantiate(BMessage* archive)
99{
100	if (!validate_instantiation(archive, kClassName))
101		return NULL;
102
103	return new DeskbarReplicant(archive);
104}
105
106
107status_t
108DeskbarReplicant::Archive(BMessage* archive, bool deep) const
109{
110	status_t status = BView::Archive(archive, deep);
111	if (status == B_OK)
112		status = archive->AddString("add_on", BLUETOOTH_SIGNATURE);
113	if (status == B_OK)
114		status = archive->AddString("class", kClassName);
115
116	return status;
117}
118
119
120void
121DeskbarReplicant::AttachedToWindow()
122{
123	BView::AttachedToWindow();
124	AdoptParentColors();
125
126	if (ViewUIColor() == B_NO_COLOR)
127		SetLowColor(ViewColor());
128	else
129		SetLowUIColor(ViewUIColor());
130}
131
132
133void
134DeskbarReplicant::Draw(BRect updateRect)
135{
136	if (!fIcon) {
137		/* At least display something... */
138		rgb_color lowColor = LowColor();
139		SetLowColor(0, 113, 187, 255);
140		FillRoundRect(Bounds().InsetBySelf(3.f, 0.f), 5.f, 7.f, B_SOLID_LOW);
141		SetLowColor(lowColor);
142	} else {
143		SetDrawingMode(B_OP_ALPHA);
144		DrawBitmap(fIcon);
145		SetDrawingMode(B_OP_COPY);
146	}
147}
148
149
150void
151DeskbarReplicant::MessageReceived(BMessage* msg)
152{
153	switch (msg->what) {
154		case kMsgOpenBluetoothPreferences:
155			be_roster->Launch(BLUETOOTH_APP_SIGNATURE);
156			break;
157
158		case kMsgQuitBluetoothServer:
159			_QuitBluetoothServer();
160			break;
161
162		default:
163			BView::MessageReceived(msg);
164	}
165}
166
167
168void
169DeskbarReplicant::MouseDown(BPoint where)
170{
171	BPoint point;
172	uint32 buttons;
173	GetMouse(&point, &buttons);
174	if (!(buttons & B_SECONDARY_MOUSE_BUTTON)) {
175		return;
176	}
177
178	BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
179
180	menu->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS),
181		new BMessage(kMsgOpenBluetoothPreferences)));
182
183	// TODO show list of known/paired devices
184
185	menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
186		new BMessage(kMsgQuitBluetoothServer)));
187
188	menu->SetTargetForItems(this);
189	ConvertToScreen(&point);
190	menu->Go(point, true, true, true);
191
192	delete menu;
193}
194
195
196void
197DeskbarReplicant::_QuitBluetoothServer()
198{
199	if (!be_roster->IsRunning(BLUETOOTH_SIGNATURE)) {
200		// The server isn't running, so remove ourself
201		BDeskbar deskbar;
202		deskbar.RemoveItem(kDeskbarItemName);
203
204		return;
205	}
206	status_t status = BMessenger(BLUETOOTH_SIGNATURE).SendMessage(
207		B_QUIT_REQUESTED);
208	if (status < B_OK) {
209		_ShowErrorAlert(B_TRANSLATE("Stopping the Bluetooth server failed."),
210			status);
211	}
212}
213
214
215void
216DeskbarReplicant::_ShowErrorAlert(BString msg, status_t status)
217{
218	BString error = B_TRANSLATE("Error: %status%");
219	error.ReplaceFirst("%status%", strerror(status));
220	msg << "\n\n" << error;
221	BAlert* alert = new BAlert(B_TRANSLATE("Bluetooth error"), msg.String(),
222		B_TRANSLATE("OK"));
223	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
224	alert->Go(NULL);
225}
226
227
228//	#pragma mark -
229
230
231extern "C" _EXPORT BView *
232instantiate_deskbar_item(float maxWidth, float maxHeight)
233{
234	return new DeskbarReplicant(BRect(0, 0, maxHeight - 1, maxHeight - 1),
235		B_FOLLOW_NONE);
236}
237
238
239//	#pragma mark -
240
241
242status_t
243our_image(image_info& image)
244{
245	int32 cookie = 0;
246	while (get_next_image_info(B_CURRENT_TEAM, &cookie, &image) == B_OK) {
247		if ((char *)our_image >= (char *)image.text
248			&& (char *)our_image <= (char *)image.text + image.text_size)
249			return B_OK;
250	}
251
252	return B_ERROR;
253}
254