1 /**
2  * @file
3  * @brief Main Window for UFORadiant
4  * @note Creates the editing windows and dialogs, creates commands and
5  * registers preferences as well as handling internal paths
6  */
7 
8 /*
9  Copyright (C) 1999-2006 Id Software, Inc. and contributors.
10  For a list of contributors, see the accompanying CONTRIBUTORS file.
11 
12  This file is part of GtkRadiant.
13 
14  GtkRadiant is free software; you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation; either version 2 of the License, or
17  (at your option) any later version.
18 
19  GtkRadiant is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with GtkRadiant; if not, write to the Free Software
26  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "../../../../config.h"
31 #endif
32 #include "mainframe.h"
33 #include "radiant_i18n.h"
34 
35 #include "debugging/debugging.h"
36 #include "version.h"
37 
38 #include "ifilesystem.h"
39 #include "iundo.h"
40 #include "ifilter.h"
41 #include "iradiant.h"
42 #include "iregistry.h"
43 #include "igamemanager.h"
44 #include "iuimanager.h"
45 #include "itextures.h"
46 #include "igl.h"
47 #include "iump.h"
48 #include "ieventmanager.h"
49 #include "iselectionset.h"
50 #include "moduleobservers.h"
51 
52 #include "os/path.h"
53 #include "os/file.h"
54 
55 #include "gtkutil/clipboard.h"
56 #include "gtkutil/frame.h"
57 #include "gtkutil/glfont.h"
58 #include "gtkutil/glwidget.h"
59 #include "gtkutil/image.h"
60 #include "gtkutil/widget.h"
61 #include "gtkutil/IconTextMenuToggle.h"
62 #include "gtkutil/MultiMonitor.h"
63 #include "gtkutil/menu.h"
64 
65 #include "SplitPaneLayout.h"
66 #include "../mru/MRU.h"
67 #include "../splash/Splash.h"
68 #include "../Icons.h"
69 #include "../common/ToolbarCreator.h"
70 #include "../menu/FiltersMenu.h"
71 
72 #include "../../commands.h"
73 #include "../../map/AutoSaver.h"
74 #include "../../sidebar/sidebar.h"
75 #include "../../sidebar/texturebrowser.h"
76 #include "../../sidebar/surfaceinspector/surfaceinspector.h"
77 #include "../../settings/PreferenceDialog.h"
78 #include "../../render/OpenGLRenderSystem.h"
79 #include "../../camera/CamWnd.h"
80 #include "../../camera/GlobalCamera.h"
81 #include "../../xyview/GlobalXYWnd.h"
82 #include "../../textool/TexTool.h"
83 #include "../../server.h"
84 #include "../../plugin.h"
85 #include "../../windowobservers.h"
86 #include "../../environment.h"
87 
88 namespace {
89 const std::string RKEY_WINDOW_STATE = "user/ui/mainFrame/window";
90 const std::string RKEY_MULTIMON_START_MONITOR = "user/ui/multiMonitor/startMonitorNum";
91 }
92 
93 // Virtual file system
94 class VFSModuleObserver: public ModuleObserver
95 {
96 		std::size_t m_unrealised;
97 	public:
VFSModuleObserver()98 		VFSModuleObserver () :
99 			m_unrealised(1)
100 		{
101 		}
realise(void)102 		void realise (void)
103 		{
104 			if (--m_unrealised == 0) {
105 				GlobalFileSystem().initDirectory(GlobalRadiant().getFullGamePath());
106 				GlobalFileSystem().initialise();
107 			}
108 		}
unrealise(void)109 		void unrealise (void)
110 		{
111 			if (++m_unrealised == 1) {
112 				GlobalFileSystem().shutdown();
113 			}
114 		}
115 };
116 
117 namespace {
118 VFSModuleObserver g_VFSModuleObserver;
119 ModuleObservers g_gameModeObservers;
120 }
121 
Radiant_attachGameModeObserver(ModuleObserver & observer)122 void Radiant_attachGameModeObserver (ModuleObserver& observer)
123 {
124 	g_gameModeObservers.attach(observer);
125 }
126 
Radiant_detachGameModeObserver(ModuleObserver & observer)127 void Radiant_detachGameModeObserver (ModuleObserver& observer)
128 {
129 	g_gameModeObservers.detach(observer);
130 }
131 
132 ModuleObservers g_gameToolsPathObservers;
133 
Radiant_attachGameToolsPathObserver(ModuleObserver & observer)134 void Radiant_attachGameToolsPathObserver (ModuleObserver& observer)
135 {
136 	g_gameToolsPathObservers.attach(observer);
137 }
138 
Radiant_detachGameToolsPathObserver(ModuleObserver & observer)139 void Radiant_detachGameToolsPathObserver (ModuleObserver& observer)
140 {
141 	g_gameToolsPathObservers.detach(observer);
142 }
143 
144 // This is called from main() to start up the Radiant stuff.
Radiant_Initialise(void)145 void Radiant_Initialise (void)
146 {
147 	// Load the ColourSchemes from the registry
148 	ColourSchemes().loadColourSchemes();
149 
150 	// Load the other modules
151 	Radiant_Construct(GlobalRadiantModuleServer());
152 
153 	g_VFSModuleObserver.realise();
154 	GlobalTextureBrowser().createWidget();
155 
156 	// Rebuild the map path basing on the userGamePath
157 	std::string newMapPath = GlobalRadiant().getFullGamePath() + "maps/";
158 	g_mkdir_with_parents(newMapPath.c_str(), 0755);
159 	Environment::Instance().setMapsPath(newMapPath);
160 
161 	g_gameToolsPathObservers.realise();
162 	g_gameModeObservers.realise();
163 
164 	GlobalUMPSystem().init();
165 
166 	// Construct the MRU commands and menu structure
167 	GlobalMRU().constructMenu();
168 
169 	// Initialise the most recently used files list
170 	GlobalMRU().loadRecentFiles();
171 
172 	gtkutil::MultiMonitor::printMonitorInfo();
173 }
174 
Radiant_Shutdown(void)175 void Radiant_Shutdown (void)
176 {
177 	Environment::Instance().deletePathsFromRegistry();
178 
179 	GlobalMRU().saveRecentFiles();
180 
181 	g_VFSModuleObserver.unrealise();
182 	Environment::Instance().setMapsPath("");
183 	g_gameModeObservers.unrealise();
184 	g_gameToolsPathObservers.unrealise();
185 
186 	Radiant_Destroy();
187 }
188 
window_realize_remove_decoration(GtkWidget * widget,gpointer data)189 static gint window_realize_remove_decoration (GtkWidget* widget, gpointer data)
190 {
191 	gdk_window_set_decorations(widget->window, (GdkWMDecoration) (GDK_DECOR_ALL | GDK_DECOR_MENU | GDK_DECOR_MINIMIZE
192 			| GDK_DECOR_MAXIMIZE));
193 	return FALSE;
194 }
195 
196 class WaitDialog
197 {
198 	public:
199 		GtkWindow* m_window;
200 		GtkLabel* m_label;
201 };
202 
create_wait_dialog(const std::string & title,const std::string & text)203 static WaitDialog create_wait_dialog (const std::string& title, const std::string& text)
204 {
205 	WaitDialog dialog;
206 
207 	dialog.m_window = create_floating_window(title, GlobalRadiant().getMainWindow());
208 	gtk_window_set_resizable(dialog.m_window, FALSE);
209 	gtk_container_set_border_width(GTK_CONTAINER(dialog.m_window), 0);
210 	gtk_window_set_position(dialog.m_window, GTK_WIN_POS_CENTER_ON_PARENT);
211 
212 	g_signal_connect(G_OBJECT(dialog.m_window), "realize", G_CALLBACK(window_realize_remove_decoration), 0);
213 
214 	{
215 		dialog.m_label = GTK_LABEL(gtk_label_new(text.c_str()));
216 		gtk_misc_set_alignment(GTK_MISC(dialog.m_label), 0.5, 0.5);
217 		gtk_label_set_justify(dialog.m_label, GTK_JUSTIFY_CENTER);
218 		gtk_widget_show(GTK_WIDGET(dialog.m_label));
219 		gtk_widget_set_size_request(GTK_WIDGET(dialog.m_label), 300, 100);
220 
221 		gtk_container_add(GTK_CONTAINER(dialog.m_window), GTK_WIDGET(dialog.m_label));
222 	}
223 	return dialog;
224 }
225 
226 namespace {
227 clock_t g_lastRedrawTime = 0;
228 const clock_t c_redrawInterval = clock_t(CLOCKS_PER_SEC / 10);
229 
redrawRequired(void)230 bool redrawRequired (void)
231 {
232 	clock_t currentTime = std::clock();
233 	if (currentTime - g_lastRedrawTime >= c_redrawInterval) {
234 		g_lastRedrawTime = currentTime;
235 		return true;
236 	}
237 	return false;
238 }
239 }
240 
MainFrame_isActiveApp(void)241 static bool MainFrame_isActiveApp (void)
242 {
243 	GList* list = gtk_window_list_toplevels();
244 	for (GList* i = list; i != 0; i = g_list_next(i)) {
245 		if (gtk_window_is_active(GTK_WINDOW(i->data))) {
246 			return true;
247 		}
248 	}
249 	return false;
250 }
251 
252 typedef std::list<std::string> StringStack;
253 static StringStack g_wait_stack;
254 static WaitDialog g_wait;
255 
ScreenUpdates_Enabled(void)256 bool ScreenUpdates_Enabled (void)
257 {
258 	return g_wait_stack.empty();
259 }
260 
ScreenUpdates_process(void)261 void ScreenUpdates_process (void)
262 {
263 	if (redrawRequired() && GTK_WIDGET_VISIBLE(g_wait.m_window)) {
264 		while (gtk_events_pending()) {
265 			gtk_main_iteration();
266 		}
267 	}
268 }
269 
ScreenUpdates_Disable(const std::string & message,const std::string & title)270 void ScreenUpdates_Disable (const std::string& message, const std::string& title)
271 {
272 	if (g_wait_stack.empty()) {
273 		map::AutoSaver().stopTimer();
274 
275 		while (gtk_events_pending()) {
276 			gtk_main_iteration();
277 		}
278 
279 		const bool isActiveApp = MainFrame_isActiveApp();
280 
281 		g_wait = create_wait_dialog(title, message);
282 
283 		if (isActiveApp) {
284 			gtk_widget_show(GTK_WIDGET(g_wait.m_window));
285 			gtk_grab_add(GTK_WIDGET(g_wait.m_window));
286 			ScreenUpdates_process();
287 		}
288 	} else if (GTK_WIDGET_VISIBLE(g_wait.m_window)) {
289 		gtk_label_set_text(g_wait.m_label, message.c_str());
290 		ScreenUpdates_process();
291 	}
292 	g_wait_stack.push_back(message);
293 }
294 
ScreenUpdates_Enable(void)295 void ScreenUpdates_Enable (void)
296 {
297 	ASSERT_MESSAGE(!ScreenUpdates_Enabled(), "screen updates already enabled");
298 	g_wait_stack.pop_back();
299 	if (g_wait_stack.empty()) {
300 		map::AutoSaver().startTimer();
301 		gtk_grab_remove(GTK_WIDGET(g_wait.m_window));
302 		destroy_floating_window(g_wait.m_window);
303 		g_wait.m_window = 0;
304 	} else if (GTK_WIDGET_VISIBLE(g_wait.m_window)) {
305 		gtk_label_set_text(g_wait.m_label, g_wait_stack.back().c_str());
306 		ScreenUpdates_process();
307 	}
308 }
309 
GlobalCamera_UpdateWindow(void)310 void GlobalCamera_UpdateWindow (void)
311 {
312 	if (g_pParentWnd != 0) {
313 		g_pParentWnd->GetCamWnd()->update();
314 	}
315 }
316 
XY_UpdateAllWindows(void)317 void XY_UpdateAllWindows (void)
318 {
319 	if (g_pParentWnd != 0) {
320 		GlobalXYWnd().updateAllViews();
321 	}
322 }
323 
UpdateAllWindows(void)324 void UpdateAllWindows (void)
325 {
326 	GlobalCamera_UpdateWindow();
327 	XY_UpdateAllWindows();
328 }
329 
ClipperChangeNotify(void)330 void ClipperChangeNotify (void)
331 {
332 	GlobalCamera_UpdateWindow();
333 	XY_UpdateAllWindows();
334 }
335 
create_main_statusbar(GtkWidget * pStatusLabel[c_count_status])336 static GtkWidget* create_main_statusbar (GtkWidget *pStatusLabel[c_count_status])
337 {
338 	GtkTable* table = GTK_TABLE(gtk_table_new(1, c_count_status + 1, FALSE));
339 	gtk_widget_show(GTK_WIDGET(table));
340 
341 	{
342 		GtkLabel* label = GTK_LABEL(gtk_label_new(_("Label")));
343 		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
344 		gtk_misc_set_padding(GTK_MISC(label), 2, 2);
345 		gtk_widget_show(GTK_WIDGET(label));
346 		gtk_table_attach_defaults(table, GTK_WIDGET(label), 0, 1, 0, 1);
347 		pStatusLabel[c_command_status] = GTK_WIDGET(label);
348 	}
349 
350 	for (int i = 1; i < c_count_status; ++i) {
351 		GtkFrame* frame = GTK_FRAME(gtk_frame_new(0));
352 		gtk_widget_show(GTK_WIDGET(frame));
353 		gtk_table_attach_defaults(table, GTK_WIDGET(frame), i, i + 1, 0, 1);
354 		gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN);
355 
356 		GtkLabel* label = GTK_LABEL(gtk_label_new(_("Label")));
357 		gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END);
358 		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
359 		gtk_misc_set_padding(GTK_MISC(label), 2, 2);
360 		gtk_widget_show(GTK_WIDGET(label));
361 		gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(label));
362 		pStatusLabel[i] = GTK_WIDGET(label);
363 	}
364 
365 	return GTK_WIDGET(table);
366 }
367 
368 class MainWindowActive
369 {
notify(GtkWindow * window,gpointer dummy,MainWindowActive * self)370 		static gboolean notify (GtkWindow* window, gpointer dummy, MainWindowActive* self)
371 		{
372 			if (g_wait.m_window != 0 && gtk_window_is_active(window) && !GTK_WIDGET_VISIBLE(g_wait.m_window)) {
373 				gtk_widget_show(GTK_WIDGET(g_wait.m_window));
374 			}
375 
376 			return FALSE;
377 		}
378 	public:
connect(GtkWindow * toplevel_window)379 		void connect (GtkWindow* toplevel_window)
380 		{
381 			g_signal_connect(G_OBJECT(toplevel_window), "notify::is-active", G_CALLBACK(notify), this);
382 		}
383 };
384 
385 MainWindowActive g_MainWindowActive;
386 
387 // =============================================================================
388 // MainFrame class
389 
390 MainFrame* g_pParentWnd = 0;
391 
MainFrame_getWindow(void)392 GtkWindow* MainFrame_getWindow (void)
393 {
394 	if (g_pParentWnd == 0) {
395 		return 0;
396 	}
397 	return g_pParentWnd->m_window;
398 }
399 
MainFrame()400 MainFrame::MainFrame () :
401 	m_window(0), g_currentToolMode(0), g_defaultToolMode(0), m_idleRedrawStatusText(RedrawStatusTextCaller(*this))
402 {
403 	m_pCamWnd = 0;
404 
405 	for (int n = 0; n < c_count_status; n++) {
406 		m_pStatusLabel[n] = 0;
407 	}
408 
409 	// Register this class in the preference system so that the constructPreferencePage() gets called.
410 	GlobalPreferenceSystem().addConstructor(this);
411 
412 	Create();
413 }
414 
~MainFrame(void)415 MainFrame::~MainFrame (void)
416 {
417 	SaveWindowInfo();
418 
419 	gtk_widget_hide(GTK_WIDGET(m_window));
420 
421 	Shutdown();
422 
423 	gtk_widget_destroy(GTK_WIDGET(m_window));
424 }
425 
mainframe_delete(GtkWidget * widget,GdkEvent * event,gpointer data)426 static gint mainframe_delete (GtkWidget *widget, GdkEvent *event, gpointer data)
427 {
428 	if (GlobalMap().askForSave("Exit Radiant")) {
429 		gtk_main_quit();
430 	}
431 
432 	return TRUE;
433 }
434 
constructPreferencePage(PreferenceGroup & group)435 void MainFrame::constructPreferencePage (PreferenceGroup& group)
436 {
437 	// Add another page for Multi-Monitor stuff
438 	PreferencesPage* page(group.createPage(_("Display"), _("Multi Monitor")));
439 
440 	// Initialise the registry, if no key is set
441 	if (GlobalRegistry().get(RKEY_MULTIMON_START_MONITOR).empty()) {
442 		GlobalRegistry().set(RKEY_MULTIMON_START_MONITOR, "0");
443 	}
444 
445 	ComboBoxValueList list;
446 
447 	for (int i = 0; i < gtkutil::MultiMonitor::getNumMonitors(); ++i) {
448 		GdkRectangle rect = gtkutil::MultiMonitor::getMonitor(i);
449 
450 		list.push_back(string::format("Monitor %d (%dx%d)", i, rect.width, rect.height));
451 	}
452 
453 	page->appendCombo(_("Start UFORadiant on monitor"), RKEY_MULTIMON_START_MONITOR, list);
454 }
455 
456 /**
457  * @brief Create the user settable window layout
458  */
Create(void)459 void MainFrame::Create (void)
460 {
461 	GtkWindow* window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
462 
463 	// do this here, because the commands are needed
464 	_sidebar = new ui::Sidebar();
465 	GtkWidget *sidebar = _sidebar->getWidget();
466 
467 	// Tell the XYManager which window the xyviews should be transient for
468 	GlobalXYWnd().setGlobalParentWindow(window);
469 
470 	GlobalWindowObservers_connectTopLevel(window);
471 
472 	gtk_window_set_transient_for(ui::Splash::Instance().getWindow(), window);
473 
474 #ifndef _WIN32
475 	{
476 		GdkPixbuf* pixbuf = gtkutil::getLocalPixbuf(ui::icons::ICON);
477 		if (pixbuf != 0) {
478 			gtk_window_set_icon(window, pixbuf);
479 			g_object_unref(pixbuf);
480 		}
481 	}
482 #endif
483 
484 	gtk_widget_add_events(GTK_WIDGET(window), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK);
485 	g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(mainframe_delete), this);
486 
487 	m_position_tracker.connect(window);
488 
489 	g_MainWindowActive.connect(window);
490 
491 	GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
492 	gtk_container_add(GTK_CONTAINER(window), vbox);
493 	gtk_widget_show(vbox);
494 
495 	GlobalEventManager().connect(GTK_OBJECT(window));
496 	GlobalEventManager().connectAccelGroup(GTK_WINDOW(window));
497 
498 	m_nCurrentStyle = eSplit;
499 
500 	// Create the Filter menu entries
501 	ui::FiltersMenu::addItemsToMainMenu();
502 
503 	// Retrieve the "main" menubar from the UIManager
504 	GtkMenuBar* mainMenu = GTK_MENU_BAR(GlobalUIManager().getMenuManager()->get("main"));
505 	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(mainMenu), false, false, 0);
506 
507 	// Instantiate the ToolbarCreator and retrieve the standard toolbar widget
508 	ui::ToolbarCreator toolbarCreator;
509 
510 	GtkToolbar* generalToolbar = toolbarCreator.getToolbar("view");
511 	gtk_widget_show(GTK_WIDGET(generalToolbar));
512 
513 	GlobalSelectionSetManager().init(generalToolbar);
514 
515 	// Pack it into the main window
516 	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(generalToolbar), FALSE, FALSE, 0);
517 
518 	GtkWidget* main_statusbar = create_main_statusbar(m_pStatusLabel);
519 	gtk_box_pack_end(GTK_BOX(vbox), main_statusbar, FALSE, TRUE, 2);
520 
521 	GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
522 	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
523 	gtk_widget_show(hbox);
524 
525 	GtkToolbar* main_toolbar_v = toolbarCreator.getToolbar("edit");
526 	gtk_widget_show(GTK_WIDGET(main_toolbar_v));
527 
528 	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(main_toolbar_v), FALSE, FALSE, 0);
529 
530 
531 	// Connect the window position tracker
532 	_windowPosition.loadFromPath(RKEY_WINDOW_STATE);
533 
534 	// Yes, connect the position tracker, this overrides the existing setting.
535 	_windowPosition.connect(window);
536 
537 	int startMonitor = GlobalRegistry().getInt(RKEY_MULTIMON_START_MONITOR);
538 	if (startMonitor < gtkutil::MultiMonitor::getNumMonitors()) {
539 		// Load the correct coordinates into the position tracker
540 		_windowPosition.fitToScreen(gtkutil::MultiMonitor::getMonitor(startMonitor), 0.8f, 0.8f);
541 	}
542 
543 	// Apply the position
544 	_windowPosition.applyPosition();
545 
546 	int windowState = string::toInt(GlobalRegistry().getAttribute(RKEY_WINDOW_STATE, "state"), GDK_WINDOW_STATE_MAXIMIZED);
547 	if (windowState & GDK_WINDOW_STATE_MAXIMIZED)
548 		gtk_window_maximize(window);
549 
550 	m_window = window;
551 
552 	gtk_widget_show(GTK_WIDGET(window));
553 
554 	// The default XYView pointer
555 	XYWnd* xyWnd;
556 
557 	GtkWidget* mainHBox = gtk_hbox_new(0, 0);
558 	gtk_box_pack_start(GTK_BOX(hbox), mainHBox, TRUE, TRUE, 0);
559 	gtk_widget_show(mainHBox);
560 
561 	int w, h;
562 	gtk_window_get_size(window, &w, &h);
563 
564 	// camera
565 	m_pCamWnd = GlobalCamera().newCamWnd();
566 	GlobalCamera().setCamWnd(m_pCamWnd);
567 	GlobalCamera().setParent(m_pCamWnd, window);
568 	GtkWidget* camera = m_pCamWnd->getWidget();
569 
570 	// Allocate the three ortho views
571 	xyWnd = GlobalXYWnd().createXY();
572 	xyWnd->setViewType(XY);
573 	GtkWidget* xy = xyWnd->getWidget();
574 
575 	XYWnd* yzWnd = GlobalXYWnd().createXY();
576 	yzWnd->setViewType(YZ);
577 	GtkWidget* yz = yzWnd->getWidget();
578 
579 	XYWnd* xzWnd = GlobalXYWnd().createXY();
580 	xzWnd->setViewType(XZ);
581 	GtkWidget* xz = xzWnd->getWidget();
582 
583 	// split view (4 views)
584 	GtkHPaned* split = create_split_views(camera, yz, xy, xz);
585 	gtk_box_pack_start(GTK_BOX(mainHBox), GTK_WIDGET(split), TRUE, TRUE, 0);
586 
587 	// greebo: In any layout, there is at least the XY view present, make it active
588 	GlobalXYWnd().setActiveXY(xyWnd);
589 
590 	PreferencesDialog_constructWindow(window);
591 
592 	GlobalGrid().addGridChangeCallback(FreeCaller<XY_UpdateAllWindows> ());
593 
594 	/* enable button state tracker, set default states for begin */
595 	GlobalUndoSystem().trackerAttach(m_saveStateTracker);
596 
597 	gtk_box_pack_start(GTK_BOX(mainHBox), GTK_WIDGET(sidebar), FALSE, FALSE, 0);
598 
599 	// Start the autosave timer so that it can periodically check the map for changes
600 	map::AutoSaver().startTimer();
601 }
602 
SaveWindowInfo(void)603 void MainFrame::SaveWindowInfo (void)
604 {
605 	// Delete all the current window states from the registry
606 	GlobalRegistry().deleteXPath(RKEY_WINDOW_STATE);
607 
608 	// Tell the position tracker to save the information
609 	_windowPosition.saveToPath(RKEY_WINDOW_STATE);
610 
611 	GdkWindow* window = GTK_WIDGET(m_window)->window;
612 	if (window != NULL)
613 		GlobalRegistry().setAttribute(RKEY_WINDOW_STATE, "state", string::toString(gdk_window_get_state(window)));
614 }
615 
Shutdown(void)616 void MainFrame::Shutdown (void)
617 {
618 	map::AutoSaver().stopTimer();
619 	ui::TexTool::Instance().shutdown();
620 
621 	GlobalUndoSystem().trackerDetach(m_saveStateTracker);
622 
623 	GlobalXYWnd().destroyViews();
624 
625 	GlobalCamera().deleteCamWnd(m_pCamWnd);
626 	m_pCamWnd = 0;
627 
628 	PreferencesDialog_destroyWindow();
629 
630 	delete _sidebar;
631 
632 	// Stop the AutoSaver class from being called
633 	map::AutoSaver().stopTimer();
634 }
635 
636 /**
637  * @brief Updates the statusbar text with command, position, texture and so on
638  * @sa TextureBrowser_SetStatus
639  */
RedrawStatusText(void)640 void MainFrame::RedrawStatusText (void)
641 {
642 	gtk_label_set_markup(GTK_LABEL(m_pStatusLabel[c_command_status]), m_command_status.c_str());
643 	gtk_label_set_markup(GTK_LABEL(m_pStatusLabel[c_position_status]), m_position_status.c_str());
644 	gtk_label_set_markup(GTK_LABEL(m_pStatusLabel[c_brushcount_status]), m_brushcount_status.c_str());
645 	gtk_label_set_markup(GTK_LABEL(m_pStatusLabel[c_texture_status]), m_texture_status.c_str());
646 }
647 
UpdateStatusText(void)648 void MainFrame::UpdateStatusText (void)
649 {
650 	m_idleRedrawStatusText.queueDraw();
651 }
652 
SetStatusText(std::string & status_text,const std::string & pText)653 void MainFrame::SetStatusText (std::string& status_text, const std::string& pText)
654 {
655 	status_text = pText;
656 	UpdateStatusText();
657 }
658 
659 /**
660  * @brief Updates the first statusbar column
661  * @param[in] status the status to print into the first statusbar column
662  * @sa MainFrame::RedrawStatusText
663  * @sa MainFrame::SetStatusText
664  */
Sys_Status(const std::string & status)665 void Sys_Status (const std::string& status)
666 {
667 	if (g_pParentWnd != 0) {
668 		g_pParentWnd->SetStatusText(g_pParentWnd->m_command_status, status);
669 	}
670 }
671 
672 namespace {
673 GLFont g_font(0, 0);
674 }
675 
GlobalGL_sharedContextCreated(void)676 static void GlobalGL_sharedContextCreated (void)
677 {
678 	// report OpenGL information
679 	globalOutputStream() << "GL_VENDOR: " << reinterpret_cast<const char*> (glGetString(GL_VENDOR)) << "\n";
680 	globalOutputStream() << "GL_RENDERER: " << reinterpret_cast<const char*> (glGetString(GL_RENDERER)) << "\n";
681 	globalOutputStream() << "GL_VERSION: " << reinterpret_cast<const char*> (glGetString(GL_VERSION)) << "\n";
682 	globalOutputStream() << "GL_EXTENSIONS: " << reinterpret_cast<const char*> (glGetString(GL_EXTENSIONS)) << "\n";
683 
684 	QGL_sharedContextCreated(GlobalOpenGL());
685 
686 	GlobalShaderCache().realise();
687 	GlobalTexturesCache().realise();
688 
689 	/* use default font here (Sans 10 is gtk default) */
690 	GtkSettings *settings = gtk_settings_get_default();
691 	gchar* fontname;
692 	g_object_get(settings, "gtk-font-name", &fontname, (char*) 0);
693 	g_font = glfont_create(fontname);
694 	// Fallbacks
695 	if (g_font.getPixelHeight() == -1)
696 		g_font = glfont_create("Sans 10");
697 	if (g_font.getPixelHeight() == -1)
698 		g_font = glfont_create("fixed 10");
699 	if (g_font.getPixelHeight() == -1)
700 		g_font = glfont_create("courier new 10");
701 
702 	GlobalOpenGL().m_font = g_font.getDisplayList();
703 	GlobalOpenGL().m_fontHeight = g_font.getPixelHeight();
704 }
705 
GlobalGL_sharedContextDestroyed(void)706 static void GlobalGL_sharedContextDestroyed (void)
707 {
708 	GlobalTexturesCache().unrealise();
709 	GlobalShaderCache().unrealise();
710 }
711 
712 #include "preferencesystem.h"
713 #include "stringio.h"
714 
MainFrame_Construct(void)715 void MainFrame_Construct (void)
716 {
717 	// Tell the FilterSystem to register its commands
718 	GlobalFilterSystem().init();
719 
720 	Commands_Register();
721 
722 	GLWidget_sharedContextCreated = GlobalGL_sharedContextCreated;
723 	GLWidget_sharedContextDestroyed = GlobalGL_sharedContextDestroyed;
724 
725 	// Broadcast the startup event
726 	GlobalRadiant().broadcastStartupEvent();
727 }
728 
MainFrame_Destroy(void)729 void MainFrame_Destroy (void)
730 {
731 	// Broadcast shutdown event to RadiantListeners
732 	GlobalRadiant().broadcastShutdownEvent();
733 }
734 
735 /**
736  * Called whenever save was completed. This causes the UndoSaveTracker to mark this point as saved.
737  */
SaveComplete()738 void MainFrame::SaveComplete ()
739 {
740 	m_saveStateTracker.storeState();
741 }
742