void
GPMMainDirector::BuildWindow()
{
// begin JXLayout

	JXWindow* window = new JXWindow(this, 530,350, "");
	assert( window != NULL );

	JXMenuBar* menuBar =
		new JXMenuBar(window,
					JXWidget::kHElastic, JXWidget::kFixedTop, 0,0, 540,30);
	assert( menuBar != NULL );

	itsToolBar =
		new JXToolBar(GPMGetPrefsManager(), kGPMMainToolBarID, menuBar, 540, 250, window,
					JXWidget::kHElastic, JXWidget::kVElastic, 0,30, 530,300);
	assert( itsToolBar != NULL );

	itsFullCmdDisplay =
		new JXStaticText("", kJFalse, kJTrue, NULL, window,
					JXWidget::kHElastic, JXWidget::kFixedBottom, 0,330, 530,20);
	assert( itsFullCmdDisplay != NULL );

// end JXLayout

	window->SetTitle("Drakon Process Manager");
	window->SetCloseAction(JXWindow::kQuitApp);
	window->SetWMClass(GPMGetWMClassInstance(), GPMGetMainWindowClass());

	JXImage* image = new JXImage(GetDisplay(), gpm_main_window_icon);
	assert( image != NULL );
	window->SetIcon(image);

	// system stats

	itsSystemStats =
		new GPMSystemStats(itsProcessList, itsToolBar->GetWidgetEnclosure(),
					   JXWidget::kHElastic, JXWidget::kFixedTop,
					   0,kStatusMargin, 100,kStatusHeight);
	assert( itsSystemStats != NULL );
	itsSystemStats->FitToEnclosure(kJTrue, kJFalse);

	// tab group

	itsTabGroup =
		new JXTabGroup(itsToolBar->GetWidgetEnclosure(),
					   JXWidget::kHElastic, JXWidget::kVElastic,
					   0,0, 100,100);
	assert( itsTabGroup != NULL );
	itsTabGroup->FitToEnclosure();
	ListenTo(itsTabGroup->GetCardEnclosure());

	const JCoordinate statusHeight = kStatusHeight + 2*kStatusMargin;
	itsTabGroup->AdjustSize(0, -statusHeight);
	itsTabGroup->Move(0, statusHeight);

	JXWidgetSet* listTab = itsTabGroup->AppendTab("List");
	JXWidgetSet* treeTab = itsTabGroup->AppendTab("Tree");

	// list view

	JXScrollbarSet* scrollbarSet =
		new JXScrollbarSet(listTab, JXWidget::kHElastic, JXWidget::kVElastic,
						   0,0, 100,100);
	assert( scrollbarSet != NULL );
	scrollbarSet->FitToEnclosure();

	const JCoordinate kHeaderHeight	= 25;
	const JCoordinate tableHeight   = scrollbarSet->GetScrollEnclosure()->GetBoundsHeight() - kHeaderHeight;

	itsProcessTable =
		new GPMProcessTable(itsProcessList, itsFullCmdDisplay,
			scrollbarSet, scrollbarSet->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kVElastic,
			0,kHeaderHeight, 100,tableHeight);
	assert( itsProcessTable != NULL );
	itsProcessTable->FitToEnclosure(kJTrue, kJFalse);

	GPMListHeaderWidget* tableHeader =
		new GPMListHeaderWidget(itsProcessTable, itsProcessList,
			scrollbarSet, scrollbarSet->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kFixedTop,
			0,0, 100,kHeaderHeight);
	assert( tableHeader != NULL );
	tableHeader->FitToEnclosure(kJTrue, kJFalse);

	// tree view

	scrollbarSet =
		new JXScrollbarSet(treeTab, JXWidget::kHElastic, JXWidget::kVElastic,
						   0,0, 100,100);
	assert( scrollbarSet != NULL );
	scrollbarSet->FitToEnclosure();

	JNamedTreeList* treeList = new JNamedTreeList(itsProcessList->GetProcessTree());
	assert( treeList != NULL );

	itsProcessTree =
		new GPMProcessTreeList(itsProcessList, treeList, itsFullCmdDisplay,
			scrollbarSet, scrollbarSet->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kVElastic,
			0,kHeaderHeight, 100,tableHeight);
	assert( itsProcessTree != NULL );
	itsProcessTree->FitToEnclosure(kJTrue, kJFalse);

	GPMTreeHeaderWidget* treeHeader =
		new GPMTreeHeaderWidget(itsProcessTree, itsProcessList,
			scrollbarSet, scrollbarSet->GetScrollEnclosure(),
			JXWidget::kHElastic, JXWidget::kFixedTop,
			0,0, 100,kHeaderHeight);
	assert( treeHeader != NULL );
	treeHeader->FitToEnclosure(kJTrue, kJFalse);

	itsProcessTable->SetDefaultRowHeight(itsProcessTree->GetDefaultRowHeight());

	// focus hocus pocus

	window->UnregisterFocusWidget(itsFullCmdDisplay);
	window->RegisterFocusWidget(itsFullCmdDisplay);

	// menus

	itsFileMenu = menuBar->AppendTextMenu(kFileMenuTitleStr);
	itsFileMenu->SetMenuItems(kFileMenuStr);
	itsFileMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsFileMenu);

	itsProcessMenu = menuBar->AppendTextMenu(kProcessMenuTitleStr);
	itsProcessMenu->SetMenuItems(kProcessMenuStr, "GPMProcessTable");
	ListenTo(itsProcessMenu);

	itsProcessMenu->SetItemImage(kShowAllCmd, JXPM(gpm_all_processes));
	itsProcessMenu->SetItemImage(kEndCmd, JXPM(gpm_stop));
	itsProcessMenu->SetItemImage(kKillCmd, JXPM(jx_edit_clear));
	itsProcessMenu->SetItemImage(kPauseCmd, JXPM(gpm_pause));
	itsProcessMenu->SetItemImage(kContinueCmd, JXPM(gpm_cont));
	itsProcessMenu->SetItemImage(kReNiceCmd, JXPM(gpm_slow));

	itsPrefsMenu = menuBar->AppendTextMenu(kPrefsMenuTitleStr);
	itsPrefsMenu->SetMenuItems(kPrefsMenuStr);
	itsPrefsMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsPrefsMenu);

	itsHelpMenu = menuBar->AppendTextMenu(kHelpMenuTitleStr);
	itsHelpMenu->SetMenuItems(kHelpMenuStr);
	itsHelpMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsHelpMenu);

	itsHelpMenu->SetItemImage(kTOCCmd,        jx_help_toc);
	itsHelpMenu->SetItemImage(kThisWindowCmd, jx_help_specific);

	// must be done after creating widgets

	itsToolBar->LoadPrefs();
	if (itsToolBar->IsEmpty())
		{
		itsToolBar->AppendButton(itsFileMenu, kQuitCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsProcessMenu, kShowAllCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsProcessMenu, kEndCmd);
		itsToolBar->AppendButton(itsProcessMenu, kKillCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsProcessMenu, kPauseCmd);
		itsToolBar->AppendButton(itsProcessMenu, kContinueCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsProcessMenu, kReNiceCmd);
		itsToolBar->NewGroup();
		itsToolBar->AppendButton(itsHelpMenu, kTOCCmd);
		itsToolBar->AppendButton(itsHelpMenu, kThisWindowCmd);
		}
}