root/src/apps/processcontroller/ThreadBarMenu.cpp
/*
 * Copyright 2000, Georges-Edouard Berenger. All rights reserved.
 * Distributed under the terms of the MIT License.
 */

#include "ThreadBarMenu.h"

#include "PriorityMenu.h"
#include "ProcessController.h"
#include "ThreadBarMenuItem.h"

#include <stdlib.h>
#include <stdio.h>

#define EXTRA 20


ThreadBarMenu::ThreadBarMenu(const char *title, team_id team, int32 threadCount)
        : BMenu(title),
        fThreadsRecCount(threadCount + EXTRA),
        fTeam(team)
{
        SetFont(be_plain_font);
        fThreadsRec = (ThreadRec*) malloc(sizeof(ThreadRec) * fThreadsRecCount);
        Init();
        fRound = 0;     // for syslog
        AddNew();
}


ThreadBarMenu::~ThreadBarMenu()
{
        free(fThreadsRec);
        if (gCurrentThreadBarMenu == this)
                gCurrentThreadBarMenu = NULL;
}


void
ThreadBarMenu::Init()
{
        int k = 0;
        while (k < fThreadsRecCount)
                fThreadsRec[k++].thread = -1;
        fRound = 1;
}


void
ThreadBarMenu::Reset(team_id team)
{
        fTeam = team;
        RemoveItems(0, CountItems(), true);
        Init();
}


void
ThreadBarMenu::AttachedToWindow()
{
        BMenu::AttachedToWindow();
}


void
ThreadBarMenu::Draw(BRect r)
{
        gCurrentThreadBarMenu = this;
        BMenu::Draw(r);
}


void
ThreadBarMenu::AddNew()
{
        thread_info     info;
        int32 cookie = 0;
        int32 k = 0;
        while (get_next_thread_info(fTeam, &cookie, &info) == B_OK) {
                int     lastk = k;
                while (k < fThreadsRecCount && fThreadsRec[k].thread != info.thread)
                        k++;
                if (k == fThreadsRecCount) {
                        k = 0;
                        while (k < lastk && fThreadsRec[k].thread != info.thread)
                                k++;
                        if (k == lastk)
                                k = fThreadsRecCount; // flag that the search didn't work.
                }
                if (k == fThreadsRecCount) {
//                      printf("*** Thread %d %s/%s, user %lld, kernel %lld\n", info.thread, info.name, info.user_time, info.kernel_time);
                        // this is a new thread...
                        k = 0;
                        while (k < fThreadsRecCount && !(fThreadsRec[k].thread == -1 || fThreadsRec[k].last_round+1 < fRound))
                                k++;
                        if (k == fThreadsRecCount) {
                                fThreadsRecCount += EXTRA;
                                fThreadsRec = (ThreadRec*) realloc(fThreadsRec, sizeof(ThreadRec)*fThreadsRecCount);
                                lastk = k;
                                while (lastk < fThreadsRecCount)
                                        fThreadsRec[lastk++].thread = -1;
                        }
                        fThreadsRec[k].thread = info.thread;
                        BMessage* kill_thread = new BMessage('KlTh');
                        kill_thread->AddInt32("thread", info.thread);

                        PriorityMenu* prio = new PriorityMenu(info.thread, info.priority);
                        prio->SetFont(be_plain_font);
                        ThreadBarMenuItem* threadbarmenuitem = new ThreadBarMenuItem(info.name, info.thread, prio, kill_thread);
                        threadbarmenuitem->SetTarget(gPCView);
                        AddItem(threadbarmenuitem);
                }
                fThreadsRec[k].last_round = fRound;
        }
        fRound++;
}


void
ThreadBarMenu::Update()
{
        AddNew();
        int32 k, del;
        del = -1;
        ThreadBarMenuItem *item;

        for (k = 0; (item = (ThreadBarMenuItem*) ItemAt(k)) != NULL; k++) {
                item->BarUpdate();
                item->DrawBar(false);
                if (item->fKernel < 0) {
                        if (del < 0)
                                del = k;
                } else if (del >= 0) {
                        RemoveItems(del, k-del, true);
                        k = del;
                        del = -1;
                }
        }
        if (del >= 0)
                RemoveItems(del, k-del, true);
}