1*105093fdSIngo Weinhold /*
2*105093fdSIngo Weinhold * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3*105093fdSIngo Weinhold * Distributed under the terms of the MIT License.
4*105093fdSIngo Weinhold */
5*105093fdSIngo Weinhold
6*105093fdSIngo Weinhold
7*105093fdSIngo Weinhold #include "TerminalRoster.h"
8*105093fdSIngo Weinhold
9*105093fdSIngo Weinhold #include <stdio.h>
10*105093fdSIngo Weinhold
11*105093fdSIngo Weinhold #include <new>
12*105093fdSIngo Weinhold
13*105093fdSIngo Weinhold #include <Looper.h>
14*105093fdSIngo Weinhold #include <Roster.h>
15*105093fdSIngo Weinhold #include <String.h>
16*105093fdSIngo Weinhold
17*105093fdSIngo Weinhold #include <AutoLocker.h>
18*105093fdSIngo Weinhold
19*105093fdSIngo Weinhold #include "TermConst.h"
20*105093fdSIngo Weinhold
21*105093fdSIngo Weinhold
22*105093fdSIngo Weinhold static const bigtime_t kAppsRunningCheckInterval = 1000000;
23*105093fdSIngo Weinhold
24*105093fdSIngo Weinhold
25*105093fdSIngo Weinhold // #pragma mark - Info
26*105093fdSIngo Weinhold
27*105093fdSIngo Weinhold
28*105093fdSIngo Weinhold /*! Creates an Info with the given \a id and \a team ID.
29*105093fdSIngo Weinhold \c workspaces is set to 0 and \c minimized to \c true.
30*105093fdSIngo Weinhold */
Info(int32 id,team_id team)31*105093fdSIngo Weinhold TerminalRoster::Info::Info(int32 id, team_id team)
32*105093fdSIngo Weinhold :
33*105093fdSIngo Weinhold id(id),
34*105093fdSIngo Weinhold team(team),
35*105093fdSIngo Weinhold workspaces(0),
36*105093fdSIngo Weinhold minimized(true)
37*105093fdSIngo Weinhold {
38*105093fdSIngo Weinhold }
39*105093fdSIngo Weinhold
40*105093fdSIngo Weinhold
41*105093fdSIngo Weinhold /*! Create an Info and initializes its data from \a archive.
42*105093fdSIngo Weinhold */
Info(const BMessage & archive)43*105093fdSIngo Weinhold TerminalRoster::Info::Info(const BMessage& archive)
44*105093fdSIngo Weinhold {
45*105093fdSIngo Weinhold if (archive.FindInt32("id", &id) != B_OK)
46*105093fdSIngo Weinhold id = -1;
47*105093fdSIngo Weinhold if (archive.FindInt32("team", &team) != B_OK)
48*105093fdSIngo Weinhold team = -1;
49*105093fdSIngo Weinhold if (archive.FindUInt32("workspaces", &workspaces) != B_OK)
50*105093fdSIngo Weinhold workspaces = 0;
51*105093fdSIngo Weinhold if (archive.FindBool("minimized", &minimized) != B_OK)
52*105093fdSIngo Weinhold minimized = true;
53*105093fdSIngo Weinhold }
54*105093fdSIngo Weinhold
55*105093fdSIngo Weinhold
56*105093fdSIngo Weinhold /*! Writes the Info's data into fields of \a archive.
57*105093fdSIngo Weinhold The const BMessage& constructor can restore an identical Info from it.
58*105093fdSIngo Weinhold */
59*105093fdSIngo Weinhold status_t
Archive(BMessage & archive) const60*105093fdSIngo Weinhold TerminalRoster::Info::Archive(BMessage& archive) const
61*105093fdSIngo Weinhold {
62*105093fdSIngo Weinhold status_t error;
63*105093fdSIngo Weinhold if ((error = archive.AddInt32("id", id)) != B_OK
64*105093fdSIngo Weinhold || (error = archive.AddInt32("team", team)) != B_OK
65*105093fdSIngo Weinhold || (error = archive.AddUInt32("workspaces", workspaces)) != B_OK
66*105093fdSIngo Weinhold || (error = archive.AddBool("minimized", minimized)) != B_OK) {
67*105093fdSIngo Weinhold return error;
68*105093fdSIngo Weinhold }
69*105093fdSIngo Weinhold
70*105093fdSIngo Weinhold return B_OK;
71*105093fdSIngo Weinhold }
72*105093fdSIngo Weinhold
73*105093fdSIngo Weinhold
74*105093fdSIngo Weinhold /*! Compares two Infos.
75*105093fdSIngo Weinhold Infos are considered equal, iff all data members are.
76*105093fdSIngo Weinhold */
77*105093fdSIngo Weinhold bool
operator ==(const Info & other) const78*105093fdSIngo Weinhold TerminalRoster::Info::operator==(const Info& other) const
79*105093fdSIngo Weinhold {
80*105093fdSIngo Weinhold return id == other.id && team == other.team
81*105093fdSIngo Weinhold && workspaces == other.workspaces && minimized == other.minimized;
82*105093fdSIngo Weinhold }
83*105093fdSIngo Weinhold
84*105093fdSIngo Weinhold
85*105093fdSIngo Weinhold // #pragma mark - TerminalRoster
86*105093fdSIngo Weinhold
87*105093fdSIngo Weinhold
88*105093fdSIngo Weinhold /*! Creates a TerminalRoster.
89*105093fdSIngo Weinhold Most methods cannot be used until Register() has been invoked.
90*105093fdSIngo Weinhold */
TerminalRoster()91*105093fdSIngo Weinhold TerminalRoster::TerminalRoster()
92*105093fdSIngo Weinhold :
93*105093fdSIngo Weinhold BHandler("terminal roster"),
94*105093fdSIngo Weinhold fLock("terminal roster"),
95*105093fdSIngo Weinhold fClipboard(TERM_SIGNATURE),
96*105093fdSIngo Weinhold fInfos(10, true),
97*105093fdSIngo Weinhold fOurInfo(NULL),
98*105093fdSIngo Weinhold fLastCheckedTime(0),
99*105093fdSIngo Weinhold fListener(NULL),
100*105093fdSIngo Weinhold fInfosUpdated(false)
101*105093fdSIngo Weinhold {
102*105093fdSIngo Weinhold }
103*105093fdSIngo Weinhold
104*105093fdSIngo Weinhold
105*105093fdSIngo Weinhold /*! Locks the object.
106*105093fdSIngo Weinhold Also makes sure the roster list is reasonably up-to-date.
107*105093fdSIngo Weinhold */
108*105093fdSIngo Weinhold bool
Lock()109*105093fdSIngo Weinhold TerminalRoster::Lock()
110*105093fdSIngo Weinhold {
111*105093fdSIngo Weinhold // lock
112*105093fdSIngo Weinhold bool locked = fLock.Lock();
113*105093fdSIngo Weinhold if (!locked)
114*105093fdSIngo Weinhold return false;
115*105093fdSIngo Weinhold
116*105093fdSIngo Weinhold // make sure we're registered
117*105093fdSIngo Weinhold if (fOurInfo == NULL) {
118*105093fdSIngo Weinhold fLock.Unlock();
119*105093fdSIngo Weinhold return false;
120*105093fdSIngo Weinhold }
121*105093fdSIngo Weinhold
122*105093fdSIngo Weinhold // If the check interval has passed, make sure all infos still have running
123*105093fdSIngo Weinhold // teams.
124*105093fdSIngo Weinhold bigtime_t now = system_time();
125*105093fdSIngo Weinhold if (fLastCheckedTime + kAppsRunningCheckInterval) {
126*105093fdSIngo Weinhold bool needsUpdate = false;
127*105093fdSIngo Weinhold for (int32 i = 0; const Info* info = TerminalAt(i); i++) {
128*105093fdSIngo Weinhold if (!_TeamIsRunning(info->team)) {
129*105093fdSIngo Weinhold needsUpdate = true;
130*105093fdSIngo Weinhold break;
131*105093fdSIngo Weinhold }
132*105093fdSIngo Weinhold }
133*105093fdSIngo Weinhold
134*105093fdSIngo Weinhold if (needsUpdate) {
135*105093fdSIngo Weinhold AutoLocker<BClipboard> clipboardLocker(fClipboard);
136*105093fdSIngo Weinhold if (clipboardLocker.IsLocked()) {
137*105093fdSIngo Weinhold if (_UpdateInfos(true) == B_OK)
138*105093fdSIngo Weinhold _UpdateClipboard();
139*105093fdSIngo Weinhold }
140*105093fdSIngo Weinhold } else
141*105093fdSIngo Weinhold fLastCheckedTime = now;
142*105093fdSIngo Weinhold }
143*105093fdSIngo Weinhold
144*105093fdSIngo Weinhold return true;
145*105093fdSIngo Weinhold }
146*105093fdSIngo Weinhold
147*105093fdSIngo Weinhold
148*105093fdSIngo Weinhold /*! Unlocks the object.
149*105093fdSIngo Weinhold As a side effect the listener will be notified, if the terminal list has
150*105093fdSIngo Weinhold changed in any way.
151*105093fdSIngo Weinhold */
152*105093fdSIngo Weinhold void
Unlock()153*105093fdSIngo Weinhold TerminalRoster::Unlock()
154*105093fdSIngo Weinhold {
155*105093fdSIngo Weinhold if (fOurInfo != NULL && fInfosUpdated) {
156*105093fdSIngo Weinhold // the infos have changed -- notify our listener
157*105093fdSIngo Weinhold _NotifyListener();
158*105093fdSIngo Weinhold }
159*105093fdSIngo Weinhold
160*105093fdSIngo Weinhold fLock.Unlock();
161*105093fdSIngo Weinhold }
162*105093fdSIngo Weinhold
163*105093fdSIngo Weinhold
164*105093fdSIngo Weinhold /*! Registers a terminal with the roster and establishes a link.
165*105093fdSIngo Weinhold
166*105093fdSIngo Weinhold The object attaches itself to the supplied \a looper and will receive
167*105093fdSIngo Weinhold updates via messaging (obviously the looper must run (not necessarily
168*105093fdSIngo Weinhold right now) for this to work).
169*105093fdSIngo Weinhold
170*105093fdSIngo Weinhold \param teamID The team ID of this team.
171*105093fdSIngo Weinhold \param looper A looper the object can attach itself to.
172*105093fdSIngo Weinhold \return \c B_OK, if successful, another error code otherwise.
173*105093fdSIngo Weinhold */
174*105093fdSIngo Weinhold status_t
Register(team_id teamID,BLooper * looper)175*105093fdSIngo Weinhold TerminalRoster::Register(team_id teamID, BLooper* looper)
176*105093fdSIngo Weinhold {
177*105093fdSIngo Weinhold AutoLocker<BLocker> locker(fLock);
178*105093fdSIngo Weinhold
179*105093fdSIngo Weinhold if (fOurInfo != NULL) {
180*105093fdSIngo Weinhold // already registered
181*105093fdSIngo Weinhold return B_BAD_VALUE;
182*105093fdSIngo Weinhold }
183*105093fdSIngo Weinhold
184*105093fdSIngo Weinhold // lock the clipboard
185*105093fdSIngo Weinhold AutoLocker<BClipboard> clipboardLocker(fClipboard);
186*105093fdSIngo Weinhold if (!clipboardLocker.IsLocked())
187*105093fdSIngo Weinhold return B_BAD_VALUE;
188*105093fdSIngo Weinhold
189*105093fdSIngo Weinhold // get the current infos from the clipboard
190*105093fdSIngo Weinhold status_t error = _UpdateInfos(true);
191*105093fdSIngo Weinhold if (error != B_OK)
192*105093fdSIngo Weinhold return error;
193*105093fdSIngo Weinhold
194*105093fdSIngo Weinhold // find an unused ID
195*105093fdSIngo Weinhold int32 id = 0;
196*105093fdSIngo Weinhold for (int32 i = 0; const Info* info = TerminalAt(i); i++) {
197*105093fdSIngo Weinhold if (info->id > id)
198*105093fdSIngo Weinhold break;
199*105093fdSIngo Weinhold id++;
200*105093fdSIngo Weinhold }
201*105093fdSIngo Weinhold
202*105093fdSIngo Weinhold // create our own info
203*105093fdSIngo Weinhold fOurInfo = new(std::nothrow) Info(id, teamID);
204*105093fdSIngo Weinhold if (fOurInfo == NULL)
205*105093fdSIngo Weinhold return B_NO_MEMORY;
206*105093fdSIngo Weinhold
207*105093fdSIngo Weinhold // insert it
208*105093fdSIngo Weinhold if (!fInfos.BinaryInsert(fOurInfo, &_CompareInfos)) {
209*105093fdSIngo Weinhold delete fOurInfo;
210*105093fdSIngo Weinhold fOurInfo = NULL;
211*105093fdSIngo Weinhold return B_NO_MEMORY;
212*105093fdSIngo Weinhold }
213*105093fdSIngo Weinhold
214*105093fdSIngo Weinhold // update the clipboard
215*105093fdSIngo Weinhold error = _UpdateClipboard();
216*105093fdSIngo Weinhold if (error != B_OK) {
217*105093fdSIngo Weinhold fInfos.MakeEmpty(true);
218*105093fdSIngo Weinhold fOurInfo = NULL;
219*105093fdSIngo Weinhold return error;
220*105093fdSIngo Weinhold }
221*105093fdSIngo Weinhold
222*105093fdSIngo Weinhold // add ourselves to the looper and start watching
223*105093fdSIngo Weinhold looper->AddHandler(this);
224*105093fdSIngo Weinhold
225*105093fdSIngo Weinhold be_roster->StartWatching(this, B_REQUEST_QUIT);
226*105093fdSIngo Weinhold fClipboard.StartWatching(this);
227*105093fdSIngo Weinhold
228*105093fdSIngo Weinhold // Update again in case we've missed a update message sent before we were
229*105093fdSIngo Weinhold // listening.
230*105093fdSIngo Weinhold _UpdateInfos(false);
231*105093fdSIngo Weinhold
232*105093fdSIngo Weinhold return B_OK;
233*105093fdSIngo Weinhold }
234*105093fdSIngo Weinhold
235*105093fdSIngo Weinhold
236*105093fdSIngo Weinhold /*! Unregisters the terminal from the roster and closes the link.
237*105093fdSIngo Weinhold
238*105093fdSIngo Weinhold Basically undoes all effects of Register().
239*105093fdSIngo Weinhold */
240*105093fdSIngo Weinhold void
Unregister()241*105093fdSIngo Weinhold TerminalRoster::Unregister()
242*105093fdSIngo Weinhold {
243*105093fdSIngo Weinhold AutoLocker<BLocker> locker(fLock);
244*105093fdSIngo Weinhold if (!locker.IsLocked())
245*105093fdSIngo Weinhold return;
246*105093fdSIngo Weinhold
247*105093fdSIngo Weinhold // stop watching and remove ourselves from the looper
248*105093fdSIngo Weinhold be_roster->StartWatching(this);
249*105093fdSIngo Weinhold fClipboard.StartWatching(this);
250*105093fdSIngo Weinhold
251*105093fdSIngo Weinhold Looper()->RemoveHandler(this);
252*105093fdSIngo Weinhold
253*105093fdSIngo Weinhold // lock the clipboard and get the current infos
254*105093fdSIngo Weinhold AutoLocker<BClipboard> clipboardLocker(fClipboard);
255*105093fdSIngo Weinhold if (!clipboardLocker.IsLocked() || _UpdateInfos(false) != B_OK)
256*105093fdSIngo Weinhold return;
257*105093fdSIngo Weinhold
258*105093fdSIngo Weinhold // remove our info and update the clipboard
259*105093fdSIngo Weinhold fInfos.RemoveItem(fOurInfo);
260*105093fdSIngo Weinhold fOurInfo = NULL;
261*105093fdSIngo Weinhold
262*105093fdSIngo Weinhold _UpdateClipboard();
263*105093fdSIngo Weinhold }
264*105093fdSIngo Weinhold
265*105093fdSIngo Weinhold
266*105093fdSIngo Weinhold /*! Returns the ID assigned to this terminal when it was registered.
267*105093fdSIngo Weinhold */
268*105093fdSIngo Weinhold int32
ID() const269*105093fdSIngo Weinhold TerminalRoster::ID() const
270*105093fdSIngo Weinhold {
271*105093fdSIngo Weinhold return fOurInfo != NULL ? fOurInfo->id : -1;
272*105093fdSIngo Weinhold }
273*105093fdSIngo Weinhold
274*105093fdSIngo Weinhold
275*105093fdSIngo Weinhold /*! Updates this terminal's window status.
276*105093fdSIngo Weinhold All other running terminals will be notified, if the status changed.
277*105093fdSIngo Weinhold
278*105093fdSIngo Weinhold \param minimized \c true, if the window is minimized.
279*105093fdSIngo Weinhold \param workspaces The window's workspaces mask.
280*105093fdSIngo Weinhold */
281*105093fdSIngo Weinhold void
SetWindowInfo(bool minimized,uint32 workspaces)282*105093fdSIngo Weinhold TerminalRoster::SetWindowInfo(bool minimized, uint32 workspaces)
283*105093fdSIngo Weinhold {
284*105093fdSIngo Weinhold AutoLocker<TerminalRoster> locker(this);
285*105093fdSIngo Weinhold if (!locker.IsLocked())
286*105093fdSIngo Weinhold return;
287*105093fdSIngo Weinhold
288*105093fdSIngo Weinhold if (minimized == fOurInfo->minimized && workspaces == fOurInfo->workspaces)
289*105093fdSIngo Weinhold return;
290*105093fdSIngo Weinhold
291*105093fdSIngo Weinhold fOurInfo->minimized = minimized;
292*105093fdSIngo Weinhold fOurInfo->workspaces = workspaces;
293*105093fdSIngo Weinhold fInfosUpdated = true;
294*105093fdSIngo Weinhold
295*105093fdSIngo Weinhold // lock the clipboard and get the current infos
296*105093fdSIngo Weinhold AutoLocker<BClipboard> clipboardLocker(fClipboard);
297*105093fdSIngo Weinhold if (!clipboardLocker.IsLocked() || _UpdateInfos(false) != B_OK)
298*105093fdSIngo Weinhold return;
299*105093fdSIngo Weinhold
300*105093fdSIngo Weinhold // update the clipboard to make our change known to the others
301*105093fdSIngo Weinhold _UpdateClipboard();
302*105093fdSIngo Weinhold }
303*105093fdSIngo Weinhold
304*105093fdSIngo Weinhold
305*105093fdSIngo Weinhold /*! Overriden to handle update messages.
306*105093fdSIngo Weinhold */
307*105093fdSIngo Weinhold void
MessageReceived(BMessage * message)308*105093fdSIngo Weinhold TerminalRoster::MessageReceived(BMessage* message)
309*105093fdSIngo Weinhold {
310*105093fdSIngo Weinhold switch (message->what) {
311*105093fdSIngo Weinhold case B_SOME_APP_QUIT:
312*105093fdSIngo Weinhold {
313*105093fdSIngo Weinhold BString signature;
314*105093fdSIngo Weinhold if (message->FindString("be:signature", &signature) != B_OK
315*105093fdSIngo Weinhold || signature != TERM_SIGNATURE) {
316*105093fdSIngo Weinhold break;
317*105093fdSIngo Weinhold }
318*105093fdSIngo Weinhold // fall through
319*105093fdSIngo Weinhold }
320*105093fdSIngo Weinhold
321*105093fdSIngo Weinhold case B_CLIPBOARD_CHANGED:
322*105093fdSIngo Weinhold {
323*105093fdSIngo Weinhold // lock ourselves and the clipboard and update the infos
324*105093fdSIngo Weinhold AutoLocker<TerminalRoster> locker(this);
325*105093fdSIngo Weinhold AutoLocker<BClipboard> clipboardLocker(fClipboard);
326*105093fdSIngo Weinhold if (clipboardLocker.IsLocked()) {
327*105093fdSIngo Weinhold _UpdateInfos(false);
328*105093fdSIngo Weinhold
329*105093fdSIngo Weinhold if (fInfosUpdated)
330*105093fdSIngo Weinhold _NotifyListener();
331*105093fdSIngo Weinhold }
332*105093fdSIngo Weinhold
333*105093fdSIngo Weinhold break;
334*105093fdSIngo Weinhold }
335*105093fdSIngo Weinhold
336*105093fdSIngo Weinhold default:
337*105093fdSIngo Weinhold BHandler::MessageReceived(message);
338*105093fdSIngo Weinhold break;
339*105093fdSIngo Weinhold }
340*105093fdSIngo Weinhold }
341*105093fdSIngo Weinhold
342*105093fdSIngo Weinhold
343*105093fdSIngo Weinhold /*! Updates the terminal info list from the clipboard.
344*105093fdSIngo Weinhold
345*105093fdSIngo Weinhold \param checkApps If \c true, it is checked for each found info whether the
346*105093fdSIngo Weinhold respective team is still running. If not, the info is removed from the
347*105093fdSIngo Weinhold list (though not from the clipboard).
348*105093fdSIngo Weinhold \return \c B_OK, if the update went fine, another error code otherwise. When
349*105093fdSIngo Weinhold an error occurs the object state will still be consistent, but might no
350*105093fdSIngo Weinhold longer be up-to-date.
351*105093fdSIngo Weinhold */
352*105093fdSIngo Weinhold status_t
_UpdateInfos(bool checkApps)353*105093fdSIngo Weinhold TerminalRoster::_UpdateInfos(bool checkApps)
354*105093fdSIngo Weinhold {
355*105093fdSIngo Weinhold BMessage* data = fClipboard.Data();
356*105093fdSIngo Weinhold
357*105093fdSIngo Weinhold // find out how many infos we can expect
358*105093fdSIngo Weinhold type_code type;
359*105093fdSIngo Weinhold int32 count;
360*105093fdSIngo Weinhold status_t error = data->GetInfo("teams", &type, &count);
361*105093fdSIngo Weinhold if (error != B_OK)
362*105093fdSIngo Weinhold count = 0;
363*105093fdSIngo Weinhold
364*105093fdSIngo Weinhold // create an info list from the message
365*105093fdSIngo Weinhold InfoList infos(10, true);
366*105093fdSIngo Weinhold for (int32 i = 0; i < count; i++) {
367*105093fdSIngo Weinhold // get the team's message
368*105093fdSIngo Weinhold BMessage teamData;
369*105093fdSIngo Weinhold error = data->FindMessage("teams", i, &teamData);
370*105093fdSIngo Weinhold if (error != B_OK)
371*105093fdSIngo Weinhold return error;
372*105093fdSIngo Weinhold
373*105093fdSIngo Weinhold // create the info
374*105093fdSIngo Weinhold Info* info = new(std::nothrow) Info(teamData);
375*105093fdSIngo Weinhold if (info == NULL)
376*105093fdSIngo Weinhold return B_NO_MEMORY;
377*105093fdSIngo Weinhold if (info->id < 0 || info->team < 0
378*105093fdSIngo Weinhold || infos.BinarySearchByKey(info->id, &_CompareIDInfo) != NULL
379*105093fdSIngo Weinhold || (checkApps && !_TeamIsRunning(info->team))) {
380*105093fdSIngo Weinhold // invalid/duplicate info -- skip
381*105093fdSIngo Weinhold delete info;
382*105093fdSIngo Weinhold fInfosUpdated = true;
383*105093fdSIngo Weinhold continue;
384*105093fdSIngo Weinhold }
385*105093fdSIngo Weinhold
386*105093fdSIngo Weinhold // add it to the list
387*105093fdSIngo Weinhold if (!infos.BinaryInsert(info, &_CompareInfos)) {
388*105093fdSIngo Weinhold delete info;
389*105093fdSIngo Weinhold return B_NO_MEMORY;
390*105093fdSIngo Weinhold }
391*105093fdSIngo Weinhold }
392*105093fdSIngo Weinhold
393*105093fdSIngo Weinhold // update the current info list from the infos we just read
394*105093fdSIngo Weinhold int32 oldIndex = 0;
395*105093fdSIngo Weinhold int32 newIndex = 0;
396*105093fdSIngo Weinhold while (oldIndex < fInfos.CountItems() || newIndex < infos.CountItems()) {
397*105093fdSIngo Weinhold Info* oldInfo = fInfos.ItemAt(oldIndex);
398*105093fdSIngo Weinhold Info* newInfo = infos.ItemAt(newIndex);
399*105093fdSIngo Weinhold
400*105093fdSIngo Weinhold if (oldInfo == NULL || (newInfo != NULL && oldInfo->id > newInfo->id)) {
401*105093fdSIngo Weinhold // new info is not in old list -- transfer it
402*105093fdSIngo Weinhold if (!fInfos.AddItem(newInfo, oldIndex++))
403*105093fdSIngo Weinhold return B_NO_MEMORY;
404*105093fdSIngo Weinhold infos.RemoveItemAt(newIndex);
405*105093fdSIngo Weinhold fInfosUpdated = true;
406*105093fdSIngo Weinhold } else if (newInfo == NULL || oldInfo->id < newInfo->id) {
407*105093fdSIngo Weinhold // old info is not in new list -- delete it, unless it's our own
408*105093fdSIngo Weinhold if (oldInfo == fOurInfo) {
409*105093fdSIngo Weinhold oldIndex++;
410*105093fdSIngo Weinhold } else {
411*105093fdSIngo Weinhold delete fInfos.RemoveItemAt(oldIndex);
412*105093fdSIngo Weinhold fInfosUpdated = true;
413*105093fdSIngo Weinhold }
414*105093fdSIngo Weinhold } else {
415*105093fdSIngo Weinhold // info is in both lists -- update the old info, unless it's our own
416*105093fdSIngo Weinhold if (oldInfo != fOurInfo) {
417*105093fdSIngo Weinhold if (*oldInfo != *newInfo) {
418*105093fdSIngo Weinhold *oldInfo = *newInfo;
419*105093fdSIngo Weinhold fInfosUpdated = true;
420*105093fdSIngo Weinhold }
421*105093fdSIngo Weinhold }
422*105093fdSIngo Weinhold
423*105093fdSIngo Weinhold oldIndex++;
424*105093fdSIngo Weinhold newIndex++;
425*105093fdSIngo Weinhold }
426*105093fdSIngo Weinhold }
427*105093fdSIngo Weinhold
428*105093fdSIngo Weinhold if (checkApps)
429*105093fdSIngo Weinhold fLastCheckedTime = system_time();
430*105093fdSIngo Weinhold
431*105093fdSIngo Weinhold return B_OK;
432*105093fdSIngo Weinhold }
433*105093fdSIngo Weinhold
434*105093fdSIngo Weinhold
435*105093fdSIngo Weinhold /*! Updates the clipboard with the object's terminal info list.
436*105093fdSIngo Weinhold
437*105093fdSIngo Weinhold \return \c B_OK, if the update went fine, another error code otherwise. When
438*105093fdSIngo Weinhold an error occurs the object state will still be consistent, but might no
439*105093fdSIngo Weinhold longer be in sync with the clipboard.
440*105093fdSIngo Weinhold */
441*105093fdSIngo Weinhold status_t
_UpdateClipboard()442*105093fdSIngo Weinhold TerminalRoster::_UpdateClipboard()
443*105093fdSIngo Weinhold {
444*105093fdSIngo Weinhold // get the clipboard data message
445*105093fdSIngo Weinhold BMessage* data = fClipboard.Data();
446*105093fdSIngo Weinhold if (data == NULL)
447*105093fdSIngo Weinhold return B_BAD_VALUE;
448*105093fdSIngo Weinhold
449*105093fdSIngo Weinhold // clear the message and add all infos
450*105093fdSIngo Weinhold data->MakeEmpty();
451*105093fdSIngo Weinhold
452*105093fdSIngo Weinhold for (int32 i = 0; const Info* info = TerminalAt(i); i++) {
453*105093fdSIngo Weinhold BMessage teamData;
454*105093fdSIngo Weinhold status_t error = info->Archive(teamData);
455*105093fdSIngo Weinhold if (error != B_OK
456*105093fdSIngo Weinhold || (error = data->AddMessage("teams", &teamData)) != B_OK) {
457*105093fdSIngo Weinhold fClipboard.Revert();
458*105093fdSIngo Weinhold return error;
459*105093fdSIngo Weinhold }
460*105093fdSIngo Weinhold }
461*105093fdSIngo Weinhold
462*105093fdSIngo Weinhold // commit the changes
463*105093fdSIngo Weinhold status_t error = fClipboard.Commit();
464*105093fdSIngo Weinhold if (error != B_OK) {
465*105093fdSIngo Weinhold fClipboard.Revert();
466*105093fdSIngo Weinhold return error;
467*105093fdSIngo Weinhold }
468*105093fdSIngo Weinhold
469*105093fdSIngo Weinhold return B_OK;
470*105093fdSIngo Weinhold }
471*105093fdSIngo Weinhold
472*105093fdSIngo Weinhold
473*105093fdSIngo Weinhold /*! Notifies the listener, if something has changed.
474*105093fdSIngo Weinhold */
475*105093fdSIngo Weinhold void
_NotifyListener()476*105093fdSIngo Weinhold TerminalRoster::_NotifyListener()
477*105093fdSIngo Weinhold {
478*105093fdSIngo Weinhold if (!fInfosUpdated)
479*105093fdSIngo Weinhold return;
480*105093fdSIngo Weinhold
481*105093fdSIngo Weinhold if (fListener != NULL)
482*105093fdSIngo Weinhold fListener->TerminalInfosUpdated(this);
483*105093fdSIngo Weinhold
484*105093fdSIngo Weinhold fInfosUpdated = false;
485*105093fdSIngo Weinhold }
486*105093fdSIngo Weinhold
487*105093fdSIngo Weinhold
488*105093fdSIngo Weinhold /*static*/ int
_CompareInfos(const Info * a,const Info * b)489*105093fdSIngo Weinhold TerminalRoster::_CompareInfos(const Info* a, const Info* b)
490*105093fdSIngo Weinhold {
491*105093fdSIngo Weinhold return a->id - b->id;
492*105093fdSIngo Weinhold }
493*105093fdSIngo Weinhold
494*105093fdSIngo Weinhold
495*105093fdSIngo Weinhold /*static*/ int
_CompareIDInfo(const int32 * id,const Info * info)496*105093fdSIngo Weinhold TerminalRoster::_CompareIDInfo(const int32* id, const Info* info)
497*105093fdSIngo Weinhold {
498*105093fdSIngo Weinhold return *id - info->id;
499*105093fdSIngo Weinhold }
500*105093fdSIngo Weinhold
501*105093fdSIngo Weinhold
502*105093fdSIngo Weinhold bool
_TeamIsRunning(team_id teamID)503*105093fdSIngo Weinhold TerminalRoster::_TeamIsRunning(team_id teamID)
504*105093fdSIngo Weinhold {
505*105093fdSIngo Weinhold // we are running for sure
506*105093fdSIngo Weinhold if (fOurInfo != NULL && fOurInfo->team == teamID)
507*105093fdSIngo Weinhold return true;
508*105093fdSIngo Weinhold
509*105093fdSIngo Weinhold team_info info;
510*105093fdSIngo Weinhold return get_team_info(teamID, &info) == B_OK;
511*105093fdSIngo Weinhold }
512*105093fdSIngo Weinhold
513*105093fdSIngo Weinhold
514*105093fdSIngo Weinhold // #pragma mark - Listener
515*105093fdSIngo Weinhold
516*105093fdSIngo Weinhold
~Listener()517*105093fdSIngo Weinhold TerminalRoster::Listener::~Listener()
518*105093fdSIngo Weinhold {
519*105093fdSIngo Weinhold }
520