]> git.xonotic.org Git - xonotic/netradiant.git/commitdiff
Merge commit '1a0075a3f03af095ee32ded7f101cac79267f906' into master-merge
authorThomas Debesse <dev@illwieckz.net>
Tue, 21 Jun 2022 02:52:21 +0000 (04:52 +0200)
committerThomas Debesse <dev@illwieckz.net>
Tue, 21 Jun 2022 02:52:21 +0000 (04:52 +0200)
1  2 
radiant/camwindow.cpp
radiant/camwindow.h
radiant/mainframe.cpp
radiant/xywindow.cpp
radiant/xywindow.h

diff --combined radiant/camwindow.cpp
index 6bae24c738cc674ef4e6a3e30f2a51028814eb1a,358d1b51711fa7b4634d97996941c585bfe70dc1..33316edc4c49ac685559164903a4441be62bfe72
@@@ -76,7 -76,6 +76,7 @@@ void CameraMovedNotify()
  
  struct camwindow_globals_private_t
  {
 +      int m_nFOV;
        int m_nMoveSpeed;
        bool m_bCamLinkSpeed;
        int m_nAngleSpeed;
@@@ -87,7 -86,6 +87,7 @@@
        int m_nStrafeMode;
  
        camwindow_globals_private_t() :
 +              m_nFOV( 110 ),
                m_nMoveSpeed( 100 ),
                m_bCamLinkSpeed( true ),
                m_nAngleSpeed( 3 ),
@@@ -153,6 -151,8 +153,6 @@@ struct camera_
        guint m_keymove_handler;
  
  
 -      float fieldOfView;
 -
        DeferredMotionDelta m_mouseMove;
  
        static void motionDelta( int x, int y, void* data ){
                origin( 0, 0, 0 ),
                angles( 0, 0, 0 ),
                color( 0, 0, 0 ),
 +              projection( g_matrix4_identity ),
 +              modelview( g_matrix4_identity ),
                movementflags( 0 ),
 +              m_keycontrol_timer(),
                m_keymove_handler( 0 ),
 -              fieldOfView( 110.0f ),
                m_mouseMove( motionDelta, this ),
                m_view( view ),
                m_update( update ){
@@@ -204,7 -202,7 +204,7 @@@ float Camera_getFarClipPlane( camera_t
  
  void Camera_updateProjection( camera_t& camera ){
        float farClip = Camera_getFarClipPlane( camera );
 -      camera.projection = projection_for_camera( farClip / 4096.0f, farClip, camera.fieldOfView, camera.width, camera.height );
 +      camera.projection = projection_for_camera( farClip / 4096.0f, farClip, (float)g_camwindow_globals_private.m_nFOV, camera.width, camera.height );
  
        camera.m_view->Construct( camera.projection, camera.modelview, camera.width, camera.height );
  }
@@@ -529,9 -527,6 +529,9 @@@ typedef ReferenceCaller<camera_t, void(
  typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
  
  
 +const float MIN_FOV = 60;
 +const float MAX_FOV = 179;
 +const float FOV_STEP = 10;
  const float SPEED_MOVE = 32;
  const float SPEED_TURN = 22.5;
  const float MIN_CAM_SPEED = 10;
@@@ -1302,7 -1297,7 +1302,7 @@@ void CamWnd::Cam_PositionDrag()
                CamWnd_Update( camwnd );
                CameraMovedNotify();
  
 -              Sys_SetCursorPos( m_parent, m_PositionDragCursorX, m_PositionDragCursorY );
 +              Sys_SetCursorPos( m_gl_widget, m_PositionDragCursorX, m_PositionDragCursorY );
        }
  }
  #endif
@@@ -1327,9 -1322,7 +1327,9 @@@ void CamWnd::EnableFreeMove()
  
        gtk_window_set_focus( m_parent, m_gl_widget );
        m_freemove_handle_focusout = m_gl_widget.connect( "focus_out_event", G_CALLBACK( camwindow_freemove_focusout ), this );
 -      m_freezePointer.freeze_pointer( m_parent, m_gl_widget, Camera_motionDelta, &m_Camera );
 +      /* We chose to replace m_parent by m_gl_widget but NetRadiantCustom does:
 +      m_freezePointer.freeze_pointer( m_parent, m_gl_widget, Camera_motionDelta, &m_Camera ); */
 +      m_freezePointer.freeze_pointer( m_gl_widget, Camera_motionDelta, &m_Camera );
  
        CamWnd_Update( *this );
  }
@@@ -1344,8 -1337,7 +1344,8 @@@ void CamWnd::DisableFreeMove()
        CamWnd_Remove_Handlers_FreeMove( *this );
        CamWnd_Add_Handlers_Move( *this );
  
 -      m_freezePointer.unfreeze_pointer( m_parent, true );
 +      m_freezePointer.unfreeze_pointer( m_gl_widget, true );
 +
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_freemove_handle_focusout );
  
        CamWnd_Update( *this );
@@@ -1399,11 -1391,9 +1399,11 @@@ void PopState()
        m_state_stack.pop_back();
  }
  void Highlight( EHighlightMode mode, bool bEnable = true ){
 -      ( bEnable )
 -      ? m_state_stack.back().m_highlight |= mode
 -                                                                                : m_state_stack.back().m_highlight &= ~mode;
 +      if ( bEnable ) {
 +              m_state_stack.back().m_highlight |= mode;
 +      } else {
 +              m_state_stack.back().m_highlight &= ~mode;
 +      }
  }
  void setLights( const LightList& lights ){
        m_state_stack.back().m_lights = &lights;
@@@ -1642,7 -1632,7 +1642,7 @@@ void CamWnd::BenchMark()
                Vector3 angles;
                angles[CAMERA_ROLL] = 0;
                angles[CAMERA_PITCH] = 0;
 -              angles[CAMERA_YAW] = static_cast<float>( i * ( 360.0 / 100.0 ) );
 +              angles[CAMERA_YAW] = i * 360.0f / 100.0f;
                Camera_setAngles( *this, angles );
        }
        double dEnd = Sys_DoubleTime();
  }
  
  
- void fill_view_camera_menu( ui::Menu menu ){
-       create_check_menu_item_with_mnemonic( menu, "Camera View", "ToggleCamera" );
- }
  void GlobalCamera_ResetAngles(){
        CamWnd& camwnd = *g_camwnd;
        Vector3 angles;
        angles[CAMERA_ROLL] = angles[CAMERA_PITCH] = 0;
 -      angles[CAMERA_YAW] = static_cast<float>( 22.5 * floor( ( Camera_getAngles( camwnd )[CAMERA_YAW] + 11 ) / 22.5 ) );
 +      angles[CAMERA_YAW] = 22.5f * floorf( ( Camera_getAngles( camwnd )[CAMERA_YAW] + 11 ) / 22.5f );
        Camera_setAngles( camwnd, angles );
  }
  
@@@ -1686,8 -1672,8 +1682,8 @@@ void Camera_CubeIn()
  void Camera_CubeOut(){
        CamWnd& camwnd = *g_camwnd;
        g_camwindow_globals.m_nCubicScale++;
 -      if ( g_camwindow_globals.m_nCubicScale > 23 ) {
 -              g_camwindow_globals.m_nCubicScale = 23;
 +      if ( g_camwindow_globals.m_nCubicScale > 46 ) {
 +              g_camwindow_globals.m_nCubicScale = 46;
        }
        Camera_updateProjection( camwnd.getCamera() );
        CamWnd_Update( camwnd );
@@@ -1735,8 -1721,6 +1731,8 @@@ void CamWnd_registerShortcuts()
                command_connect_accelerator( "TogglePreview" );
        }
  
 +      command_connect_accelerator( "FOVInc" );
 +      command_connect_accelerator( "FOVDec" );
        command_connect_accelerator( "CameraSpeedInc" );
        command_connect_accelerator( "CameraSpeedDec" );
  }
@@@ -1854,7 -1838,6 +1850,7 @@@ struct RenderMode 
  };
  
  void Camera_constructPreferences( PreferencesPage& page ){
 +      page.appendSlider( "FOV", g_camwindow_globals_private.m_nFOV, TRUE, 0, 0, 100, MIN_FOV, MAX_FOV, 1, 10 );
        page.appendSlider( "Movement Speed", g_camwindow_globals_private.m_nMoveSpeed, TRUE, 0, 0, 100, MIN_CAM_SPEED, MAX_CAM_SPEED, 1, 10 );
        page.appendCheckBox( "", "Link strafe speed to movement speed", g_camwindow_globals_private.m_bCamLinkSpeed );
        page.appendSlider( "Rotation Speed", g_camwindow_globals_private.m_nAngleSpeed, TRUE, 0, 0, 3, 1, 180, 1, 10 );
@@@ -1908,31 -1891,6 +1904,31 @@@ void Camera_registerPreferencesPage()
  #include "stringio.h"
  #include "dialog.h"
  
 +void FOV_increase(){
 +      CamWnd& camwnd = *g_camwnd;
 +      if ( g_camwindow_globals_private.m_nFOV <= ( MAX_FOV - FOV_STEP - 10 ) ) {
 +              g_camwindow_globals_private.m_nFOV += FOV_STEP;
 +      }
 +      else {
 +              g_camwindow_globals_private.m_nFOV = MAX_FOV - 10;
 +      }
 +      Camera_updateProjection( camwnd.getCamera() );
 +      CamWnd_Update( camwnd );
 +}
 +
 +void FOV_decrease(){
 +      CamWnd& camwnd = *g_camwnd;
 +      if ( g_camwindow_globals_private.m_nFOV >= ( MIN_FOV + FOV_STEP ) ) {
 +              g_camwindow_globals_private.m_nFOV -= FOV_STEP;
 +      }
 +      else {
 +              g_camwindow_globals_private.m_nFOV = MIN_FOV;
 +      }
 +      Camera_updateProjection( camwnd.getCamera() );
 +      CamWnd_Update( camwnd );
 +}
 +
 +
  void CameraSpeed_increase(){
        if ( g_camwindow_globals_private.m_nMoveSpeed <= ( MAX_CAM_SPEED - CAM_SPEED_STEP - 10 ) ) {
                g_camwindow_globals_private.m_nMoveSpeed += CAM_SPEED_STEP;
@@@ -1963,16 -1921,13 +1959,16 @@@ void CamWnd_Construct()
        GlobalCommands_insert( "DownFloor", makeCallbackF(Camera_ChangeFloorDown), Accelerator( GDK_KEY_Next ) );
  
        GlobalToggles_insert( "ToggleCamera", ToggleShown::ToggleCaller( g_camera_shown ), ToggleItem::AddCallbackCaller( g_camera_shown.m_item ), Accelerator( 'C', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
      GlobalCommands_insert( "LookThroughSelected", makeCallbackF(GlobalCamera_LookThroughSelected) );
      GlobalCommands_insert( "LookThroughCamera", makeCallbackF(GlobalCamera_LookThroughCamera) );
//    GlobalCommands_insert( "LookThroughSelected", makeCallbackF(GlobalCamera_LookThroughSelected) );
//    GlobalCommands_insert( "LookThroughCamera", makeCallbackF(GlobalCamera_LookThroughCamera) );
  
        if ( g_pGameDescription->mGameType == "doom3" ) {
                GlobalCommands_insert( "TogglePreview", makeCallbackF(CamWnd_TogglePreview), Accelerator( GDK_KEY_F3 ) );
        }
  
 +      GlobalCommands_insert( "FOVInc", makeCallbackF(FOV_increase), Accelerator( GDK_KEY_KP_Multiply, (GdkModifierType)GDK_SHIFT_MASK ) );
 +      GlobalCommands_insert( "FOVDec", makeCallbackF(FOV_decrease), Accelerator( GDK_KEY_KP_Divide, (GdkModifierType)GDK_SHIFT_MASK ) );
 +
        GlobalCommands_insert( "CameraSpeedInc", makeCallbackF(CameraSpeed_increase), Accelerator( GDK_KEY_KP_Add, (GdkModifierType)GDK_SHIFT_MASK ) );
        GlobalCommands_insert( "CameraSpeedDec", makeCallbackF(CameraSpeed_decrease), Accelerator( GDK_KEY_KP_Subtract, (GdkModifierType)GDK_SHIFT_MASK ) );
  
        GlobalToggles_insert( "ShowStats", makeCallbackF(ShowStatsToggle), ToggleItem::AddCallbackCaller( g_show_stats ) );
  
        GlobalPreferenceSystem().registerPreference( "ShowStats", make_property_string( g_camwindow_globals_private.m_showStats ) );
 +      GlobalPreferenceSystem().registerPreference( "FOV", make_property_string( g_camwindow_globals_private.m_nFOV ) );
        GlobalPreferenceSystem().registerPreference( "MoveSpeed", make_property_string( g_camwindow_globals_private.m_nMoveSpeed ) );
        GlobalPreferenceSystem().registerPreference( "CamLinkSpeed", make_property_string( g_camwindow_globals_private.m_bCamLinkSpeed ) );
        GlobalPreferenceSystem().registerPreference( "AngleSpeed", make_property_string( g_camwindow_globals_private.m_nAngleSpeed ) );
diff --combined radiant/camwindow.h
index 9ed6d24260d0013dc149e906ba91473948d7ceea,a838e18ab1a9b3449f301caa297189bee4a971cb..4bb850806fe9798a80bcbd12ea2741b2c52f21b5
@@@ -39,7 -39,6 +39,6 @@@ void CamWnd_setParent( CamWnd& camwnd, 
  
  void GlobalCamera_setCamWnd( CamWnd& camwnd );
  
- void fill_view_camera_menu( ui::Menu menu );
  void CamWnd_constructToolbar( ui::Toolbar toolbar );
  void CamWnd_registerShortcuts();
  
@@@ -69,7 -68,7 +68,7 @@@ struct camwindow_globals_
        camwindow_globals_t() :
                color_cameraback( 0.25f, 0.25f, 0.25f ),
                color_selbrushes3d( 1.0f, 0.f, 0.f ),
 -              m_nCubicScale( 14 ){
 +              m_nCubicScale( 26 ){
        }
  
  };
diff --combined radiant/mainframe.cpp
index acc56f614abc5458a9c07910a9f6ad9eac7db7a4,c2efdc3aa34452176c32071912c63f5273c03534..ec650edfbb4615bbbf7061def16ecf480db9797a
  #include "texwindow.h"
  #include "filterbar.h"
  
 +#if GDEF_OS_WINDOWS
 +#include <process.h>
 +#else
 +#include <spawn.h>
 +#endif
 +
 +#ifdef WORKAROUND_WINDOWS_GTK2_GLWIDGET
 +/* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 +#define WORKAROUND_GOBJECT_SET_GLWIDGET(window, widget) g_object_set_data( G_OBJECT( window ), "glwidget", G_OBJECT( widget ) )
 +#else
 +#define WORKAROUND_GOBJECT_SET_GLWIDGET(window, widget)
 +#endif
 +
  #define GARUX_DISABLE_GTKTHEME
  #ifndef GARUX_DISABLE_GTKTHEME
  #include "gtktheme.h"
  #endif
  
 -
  struct layout_globals_t
  {
        WindowPosition m_position;
@@@ -173,8 -161,6 +173,8 @@@ void VFS_Refresh()
        RefreshReferences();
        // also refresh texture browser
        TextureBrowser_RefreshShaders();
 +      // also show textures (all or common)
 +      TextureBrowser_ShowStartupShaders( GlobalTextureBrowser() );
  }
  
  void VFS_Restart(){
@@@ -233,7 -219,9 +233,7 @@@ void HomePaths_Realise()
                        }
                        path.clear();
                        path << DirectoryCleaned( g_get_home_dir() ) << prefix << "/";
 -#endif
 -
 -#if GDEF_OS_WINDOWS
 +#elif GDEF_OS_WINDOWS
                        TCHAR mydocsdir[MAX_PATH + 1];
                        wchar_t *mydocsdirw;
                        HMODULE shfolder = LoadLibrary( "shfolder.dll" );
                                        break;
                                }
                        }
 -#endif
 -
 -#if GDEF_OS_POSIX
 +#elif GDEF_OS_XDG
 +                      path.clear();
 +                      path << DirectoryCleaned( g_get_user_data_dir() ) << ( prefix + 1 ) << "/";
 +                      if ( file_exists( path.c_str() ) && file_is_directory( path.c_str() ) ) {
 +                              g_qeglobals.m_userEnginePath = path.c_str();
 +                              break;
 +                      }
 +                      else {
                        path.clear();
                        path << DirectoryCleaned( g_get_home_dir() ) << prefix << "/";
                        g_qeglobals.m_userEnginePath = path.c_str();
                        break;
 +                      }
  #endif
                }
  
@@@ -458,32 -440,14 +458,32 @@@ void setPakPath( int num, const char* p
  }
  
  
 -// App Path
 +// executable file path (full path)
 +CopiedString g_strAppFilePath;
 +
 +// directory paths
 +CopiedString g_strAppPath; 
 +CopiedString g_strLibPath;
 +CopiedString g_strDataPath;
  
 -CopiedString g_strAppPath;                 ///< holds the full path of the executable
 +const char* AppFilePath_get(){
 +      return g_strAppFilePath.c_str();
 +}
  
  const char* AppPath_get(){
        return g_strAppPath.c_str();
  }
  
 +const char *LibPath_get()
 +{
 +    return g_strLibPath.c_str();
 +}
 +
 +const char *DataPath_get()
 +{
 +    return g_strDataPath.c_str();
 +}
 +
  /// the path to the local rc-dir
  const char* LocalRcPath_get( void ){
        static CopiedString rc_path;
@@@ -582,28 -546,39 +582,28 @@@ struct PakPath4 
  bool g_disableEnginePath = false;
  bool g_disableHomePath = false;
  
 -void Paths_constructPreferences( PreferencesPage& page ){
 +void Paths_constructBasicPreferences(  PreferencesPage& page ) {
        page.appendPathEntry( "Engine Path", true, make_property<EnginePath>(g_strEnginePath) );
 +}
  
 -      page.appendCheckBox(
 -              "", "Do not use Engine Path",
 -              g_disableEnginePath
 -                                                );
 +void Paths_constructPreferences( PreferencesPage& page ){
 +      Paths_constructBasicPreferences( page );
  
 -      page.appendCheckBox(
 -              "", "Do not use Home Path",
 -              g_disableHomePath
 -              );
 +      page.appendSpacer( 4 );
 +      page.appendLabel( "", "Advanced options" );
 +      page.appendCheckBox( "", "Do not use Engine Path", g_disableEnginePath );
 +      page.appendCheckBox( "", "Do not use Home Path", g_disableHomePath );
  
 -      for ( int i = 0; i < g_pakPathCount; i++ ) {
 -              std::string label = "Pak Path " + std::to_string(i);
 -              switch (i) {
 -                      case 0:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath0>( g_strPakPath[i] ) );
 -                      break;
 -                      case 1:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath1>( g_strPakPath[i] ) );
 -                      break;
 -                      case 2:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath2>( g_strPakPath[i] ) );
 -                      break;
 -                      case 3:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath3>( g_strPakPath[i] ) );
 -                      break;
 -                      case 4:
 -                      page.appendPathEntry( label.c_str(), true, make_property<PakPath4>( g_strPakPath[i] ) );
 -                      break;
 -}
 -      }
 +      page.appendSpacer( 4 );
 +      page.appendLabel( "", "Only a very few games support Pak Paths," );
 +      page.appendLabel( "", "if you don't know what it is, leave this blank." );
 +
 +      const char *label = "Pak Path ";
 +      page.appendPathEntry( label, true, make_property<PakPath0>( g_strPakPath[0] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath1>( g_strPakPath[1] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath2>( g_strPakPath[2] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath3>( g_strPakPath[3] ) );
 +      page.appendPathEntry( label, true, make_property<PakPath4>( g_strPakPath[4] ) );
  }
  
  void Paths_constructPage( PreferenceGroup& group ){
@@@ -620,14 -595,14 +620,14 @@@ class PathsDialog : public Dialo
  {
  public:
  ui::Window BuildDialog(){
 -      auto frame = create_dialog_frame( "Path settings", ui::Shadow::ETCHED_IN );
 +      auto frame = create_dialog_frame( "Path Settings", ui::Shadow::ETCHED_IN );
  
        auto vbox2 = create_dialog_vbox( 0, 4 );
        frame.add(vbox2);
  
        {
 -              PreferencesPage preferencesPage( *this, vbox2 );
 -              Paths_constructPreferences( preferencesPage );
 +              PreferencesPage page( *this, vbox2 );
 +              Paths_constructBasicPreferences( page );
        }
  
        return ui::Window(create_simple_modal_dialog_window( "Engine Path Not Found", m_modal, frame ));
@@@ -786,7 -761,7 +786,7 @@@ void Radiant_detachGameToolsPathObserve
  void Radiant_Initialise(){
        GlobalModuleServer_Initialise();
  
 -      Radiant_loadModulesFromRoot( AppPath_get() );
 +      Radiant_loadModulesFromRoot( LibPath_get() );
  
        Preferences_Load();
  
@@@ -815,7 -790,7 +815,7 @@@ void Radiant_Shutdown()
  }
  
  void Exit(){
 -      if ( ConfirmModified( "Exit Radiant" ) ) {
 +      if ( ConfirmModified( "Exit " RADIANT_NAME ) ) {
                gtk_main_quit();
        }
  }
@@@ -974,53 -949,6 +974,53 @@@ void ColorScheme_Ydnar()
        XY_UpdateAllWindows();
  }
  
 +/* color scheme to fit the GTK Adwaita Dark theme */
 +void ColorScheme_AdwaitaDark()
 +{
 +      // SI_Colors0
 +      // GlobalTextureBrowser().color_textureback
 +      TextureBrowser_setBackgroundColour(GlobalTextureBrowser(), Vector3(0.25f, 0.25f, 0.25f));
 +
 +      // SI_Colors4
 +      g_camwindow_globals.color_cameraback = Vector3(0.25f, 0.25f, 0.25f);
 +      // SI_Colors12
 +      g_camwindow_globals.color_selbrushes3d = Vector3(1.0f, 0.0f, 0.0f);
 +      CamWnd_Update(*g_pParentWnd->GetCamWnd());
 +
 +      // SI_Colors1
 +      g_xywindow_globals.color_gridback = Vector3(0.25f, 0.25f, 0.25f);
 +      // SI_Colors2
 +      g_xywindow_globals.color_gridminor = Vector3(0.21f, 0.23f, 0.23f);
 +      // SI_Colors3
 +      g_xywindow_globals.color_gridmajor = Vector3(0.14f, 0.15f, 0.15f);
 +      // SI_Colors14
 +      g_xywindow_globals.color_gridmajor_alt = Vector3(1.0f, 0.0f, 0.0f);
 +      // SI_Colors6
 +      g_xywindow_globals.color_gridblock = Vector3(1.0f, 1.0f, 1.0f);
 +      // SI_Colors7
 +      g_xywindow_globals.color_gridtext = Vector3(0.0f, 0.0f, 0.0f);
 +      // ??
 +      g_xywindow_globals.color_selbrushes = Vector3(1.0f, 0.0f, 0.0f);
 +      // ??
 +      g_xywindow_globals.color_clipper = Vector3(0.0f, 0.0f, 1.0f);
 +      // SI_Colors8
 +      g_xywindow_globals.color_brushes = Vector3(0.73f, 0.73f, 0.73f);
 +
 +      // SI_AxisColors0
 +      g_xywindow_globals.AxisColorX = Vector3(1.0f, 0.0f, 0.0f);
 +      // SI_AxisColors1
 +      g_xywindow_globals.AxisColorY = Vector3(0.0f, 1.0f, 0.0f);
 +      // SI_AxisColors2
 +      g_xywindow_globals.AxisColorZ = Vector3(0.0f, 0.0f, 1.0f);
 +      SetWorldspawnColour(g_xywindow_globals.color_brushes);
 +      // ??
 +      g_xywindow_globals.color_viewname = Vector3(0.5f, 0.0f, 0.75f);
 +      XY_UpdateAllWindows();
 +
 +      // SI_Colors5
 +      // g_entity_globals.color_entity = Vector3(0.0f, 0.0f, 0.0f);
 +}
 +
  typedef Callback<void(Vector3&)> GetColourCallback;
  typedef Callback<void(const Vector3&)> SetColourCallback;
  
@@@ -1134,7 -1062,6 +1134,7 @@@ ui::MenuItem create_colours_menu()
        create_menu_item_with_mnemonic( menu_3, "Q3Radiant Original", "ColorSchemeQER" );
        create_menu_item_with_mnemonic( menu_3, "Black and Green", "ColorSchemeBlackAndGreen" );
        create_menu_item_with_mnemonic( menu_3, "Maya/Max/Lightwave Emulation", "ColorSchemeYdnar" );
 +      create_menu_item_with_mnemonic(menu_3, "Adwaita Dark", "ColorSchemeAdwaitaDark");
  
  #ifndef GARUX_DISABLE_GTKTHEME
        create_menu_item_with_mnemonic( menu_in_menu, "GTK Theme...", "gtkThemeDlg" );
@@@ -1831,11 -1758,9 +1831,11 @@@ void Selection_SnapToGrid()
  
  
  static gint qe_every_second( gpointer data ){
 -      GdkModifierType mask;
 +      if (g_pParentWnd == nullptr)
 +              return TRUE;
  
 -      gdk_window_get_pointer( 0, 0, 0, &mask );
 +      GdkModifierType mask;
 +      gdk_window_get_pointer( gtk_widget_get_window(g_pParentWnd->m_window), nullptr, nullptr, &mask );
  
        if ( ( mask & ( GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK ) ) == 0 ) {
                QE_CheckAutoSave();
@@@ -1947,18 -1872,15 +1947,18 @@@ void ScreenUpdates_Disable( const char
                bool isActiveApp = MainFrame_isActiveApp();
  
                g_wait = create_wait_dialog( title, message );
 -              gtk_grab_add( g_wait.m_window  );
  
                if ( isActiveApp ) {
                        g_wait.m_window.show();
 +                      gtk_grab_add( g_wait.m_window  );
                        ScreenUpdates_process();
                }
        }
        else if ( g_wait.m_window.visible() ) {
                g_wait.m_label.text(message);
 +              if ( GTK_IS_WINDOW(g_wait.m_window) ) {
 +                      gtk_grab_add(g_wait.m_window);
 +              }
                ScreenUpdates_process();
        }
        g_wait_stack.push_back( message );
@@@ -2124,20 -2046,6 +2124,6 @@@ ui::MenuItem create_edit_menu()
        return edit_menu_item;
  }
  
- void fill_view_xy_top_menu( ui::Menu menu ){
-       create_check_menu_item_with_mnemonic( menu, "XY (Top) View", "ToggleView" );
- }
- void fill_view_yz_side_menu( ui::Menu menu ){
-       create_check_menu_item_with_mnemonic( menu, "YZ (Side) View", "ToggleSideView" );
- }
- void fill_view_xz_front_menu( ui::Menu menu ){
-       create_check_menu_item_with_mnemonic( menu, "XZ (Front) View", "ToggleFrontView" );
- }
  
  ui::Widget g_toggle_z_item{ui::null};
  ui::Widget g_toggle_console_item{ui::null};
@@@ -2153,13 -2061,13 +2139,13 @@@ ui::MenuItem create_view_menu( MainFram
        }
  
        if ( style == MainFrame::eFloating ) {
-               fill_view_camera_menu( menu );
-               fill_view_xy_top_menu( menu );
-               fill_view_yz_side_menu( menu );
-               fill_view_xz_front_menu( menu );
+               create_check_menu_item_with_mnemonic( menu, "Camera View", "ToggleCamera" );
+               create_check_menu_item_with_mnemonic( menu, "XY (Top) View", "ToggleView" );
+               create_check_menu_item_with_mnemonic( menu, "XZ (Front) View", "ToggleFrontView" );
+               create_check_menu_item_with_mnemonic( menu, "YZ (Side) View", "ToggleSideView" );
        }
        if ( style == MainFrame::eFloating || style == MainFrame::eSplit ) {
-               create_menu_item_with_mnemonic( menu, "Console View", "ToggleConsole" );
+               create_menu_item_with_mnemonic( menu, "Console", "ToggleConsole" );
                create_menu_item_with_mnemonic( menu, "Texture Browser", "ToggleTextures" );
                create_menu_item_with_mnemonic( menu, "Entity Inspector", "ToggleEntityInspector" );
        }
                create_menu_item_with_mnemonic( camera_menu, "Far Clip Plane In", "CubicClipZoomIn" );
                create_menu_item_with_mnemonic( camera_menu, "Far Clip Plane Out", "CubicClipZoomOut" );
                menu_separator( camera_menu );
 +              create_menu_item_with_mnemonic( camera_menu, "Decrease FOV", "FOVDec" );
 +              create_menu_item_with_mnemonic( camera_menu, "Increase FOV", "FOVInc" );
 +              menu_separator( camera_menu );
                create_menu_item_with_mnemonic( camera_menu, "Next leak spot", "NextLeakSpot" );
                create_menu_item_with_mnemonic( camera_menu, "Previous leak spot", "PrevLeakSpot" );
-               menu_separator( camera_menu );
-               create_menu_item_with_mnemonic( camera_menu, "Look Through Selected", "LookThroughSelected" );
-               create_menu_item_with_mnemonic( camera_menu, "Look Through Camera", "LookThroughCamera" );
+               //cameramodel is not implemented in instances, thus useless
+ //            menu_separator( camera_menu );
+ //            create_menu_item_with_mnemonic( camera_menu, "Look Through Selected", "LookThroughSelected" );
+ //            create_menu_item_with_mnemonic( camera_menu, "Look Through Camera", "LookThroughCamera" );
        }
        menu_separator( menu );
        {
                if ( style == MainFrame::eRegular || style == MainFrame::eRegularLeft || style == MainFrame::eFloating ) {
                        create_menu_item_with_mnemonic( orthographic_menu, "_Next (XY, YZ, XY)", "NextView" );
                        create_menu_item_with_mnemonic( orthographic_menu, "XY (Top)", "ViewTop" );
-                       create_menu_item_with_mnemonic( orthographic_menu, "YZ", "ViewSide" );
-                       create_menu_item_with_mnemonic( orthographic_menu, "XZ", "ViewFront" );
+                       create_menu_item_with_mnemonic( orthographic_menu, "XZ (Front)", "ViewFront" );
+                       create_menu_item_with_mnemonic( orthographic_menu, "YZ (Side)", "ViewSide" );
                        menu_separator( orthographic_menu );
                }
+               else{
+                       create_menu_item_with_mnemonic( orthographic_menu, "Center on Selected", "NextView" );
+               }
  
                create_menu_item_with_mnemonic( orthographic_menu, "Center on Selected", "CenterXYView" );
                menu_separator( orthographic_menu );
@@@ -2437,7 -2346,7 +2427,7 @@@ ui::MenuItem create_help_menu()
  
        create_menu_item_with_mnemonic( menu, "Bug report", makeCallbackF(OpenBugReportURL) );
        create_menu_item_with_mnemonic( menu, "Shortcuts list", makeCallbackF(DoCommandListDlg) );
 -      create_menu_item_with_mnemonic( menu, "_About", makeCallbackF(DoAbout) );
 +      create_menu_item_with_mnemonic( menu, "_About...", makeCallbackF(DoAbout) );
  
        return help_menu_item;
  }
@@@ -2831,14 -2740,10 +2821,14 @@@ MainFrame::~MainFrame()
  
        for ( std::vector<ui::Widget>::iterator i = g_floating_windows.begin(); i != g_floating_windows.end(); ++i )
        {
 +#ifndef WORKAROUND_MACOS_GTK2_DESTROY
                i->destroy();
 +#endif
        }
  
 +#ifndef WORKAROUND_MACOS_GTK2_DESTROY
        m_window.destroy();
 +#endif
  }
  
  void MainFrame::SetActiveXY( XYWnd* p ){
@@@ -2995,16 -2900,13 +2985,16 @@@ WindowPositionTracker g_posXZWnd
  WindowPositionTracker g_posYZWnd;
  
  static gint mainframe_delete( ui::Widget widget, GdkEvent *event, gpointer data ){
 -      if ( ConfirmModified( "Exit Radiant" ) ) {
 +      if ( ConfirmModified( "Exit " RADIANT_NAME ) ) {
                gtk_main_quit();
        }
  
        return TRUE;
  }
  
 +PanedState g_single_hpaned = { 0.75f, -1, };
 +PanedState g_single_vpaned = { 0.75f, -1, };
 +
  void MainFrame::Create(){
        ui::Window window = ui::Window( ui::window_type::TOP );
  
  
        window.show();
  
 -      if ( CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft ) {
 +      if ( CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft )
 +      {
                {
                        ui::Widget hsplit = ui::HPaned(ui::New);
                        m_hSplit = hsplit;
                        }
                }
        }
 -      else if ( CurrentStyle() == eFloating ) {
 +      else if ( CurrentStyle() == eFloating )
 +      {
                {
                        ui::Window window = ui::Window(create_persistent_floating_window( "Camera", m_window ));
                        global_accel_connect_window( window );
                                window.add(frame);
                        }
                        CamWnd_setParent( *m_pCamWnd, window );
 -#define GARUX_GTK_WORKAROUND
 -#ifndef GARUX_GTK_WORKAROUND
 -                      /* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 -                      g_object_set_data( G_OBJECT( window ), "glwidget", CamWnd_getWidget( *m_pCamWnd ) );
 -#endif
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, CamWnd_getWidget( *m_pCamWnd ) );
  
                        g_floating_windows.push_back( window );
                }
                                window.add(frame);
                        }
                        XY_Top_Shown_Construct( window );
 -#ifndef GARUX_GTK_WORKAROUND
 -                      /* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 -                      g_object_set_data( G_OBJECT( window ), "glwidget", m_pXYWnd->GetWidget() );
 -#endif
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, m_pXYWnd->GetWidget() );
  
                        g_floating_windows.push_back( window );
                }
                        }
  
                        XZ_Front_Shown_Construct( window );
 -#ifndef GARUX_GTK_WORKAROUND
 -                      /* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 -                      g_object_set_data( G_OBJECT( window ), "glwidget", m_pXZWnd->GetWidget() );
 -#endif
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, m_pXZWnd->GetWidget() );
  
                        g_floating_windows.push_back( window );
                }
                        }
  
                        YZ_Side_Shown_Construct( window );
 -#ifndef GARUX_GTK_WORKAROUND
 -                      /* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 -                      g_object_set_data( G_OBJECT( window ), "glwidget", m_pYZWnd->GetWidget() );
 -#endif
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, m_pYZWnd->GetWidget() );
  
                        g_floating_windows.push_back( window );
                }
                {
                        auto frame = create_framed_widget( TextureBrowser_constructWindow( GroupDialog_getWindow() ) );
                        g_page_textures = GroupDialog_addPage( "Textures", frame, TextureBrowserExportTitleCaller() );
 -#ifndef GARUX_GTK_WORKAROUND
 -                      /* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 -                      g_object_set_data( G_OBJECT( GroupDialog_getWindow() ), "glwidget", TextureBrowser_getGLWidget() );
 -#endif
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( GroupDialog_getWindow(), TextureBrowser_getGLWidget() );
                }
  
                // FIXME: find a way to do it with newer syntax
  
                GroupDialog_show();
        }
 -      else // 4 way
 +      else if ( CurrentStyle() == eSplit )
        {
                m_pCamWnd = NewCamWnd();
                GlobalCamera_setCamWnd( *m_pCamWnd );
                {
              auto frame = create_framed_widget( TextureBrowser_constructWindow( GroupDialog_getWindow() ) );
                        g_page_textures = GroupDialog_addPage( "Textures", frame, TextureBrowserExportTitleCaller() );
 -#ifndef GARUX_GTK_WORKAROUND
 -                      /* workaround for gtk 2.24 issue: not displayed glwidget after toggle */
 -                      g_object_set_data( G_OBJECT( GroupDialog_getWindow() ), "glwidget", TextureBrowser_getGLWidget() );
 -#endif
 +
 +                      WORKAROUND_GOBJECT_SET_GLWIDGET( window, TextureBrowser_getGLWidget() );
                }
        }
 +      else // single window
 +      {
 +              m_pCamWnd = NewCamWnd();
 +              GlobalCamera_setCamWnd( *m_pCamWnd );
 +              CamWnd_setParent( *m_pCamWnd, window );
 +
 +              ui::Widget camera = CamWnd_getWidget( *m_pCamWnd );
 +
 +              m_pYZWnd = new XYWnd();
 +              m_pYZWnd->SetViewType( YZ );
 +
 +              ui::Widget yz = m_pYZWnd->GetWidget();
 +
 +              m_pXYWnd = new XYWnd();
 +              m_pXYWnd->SetViewType( XY );
 +
 +              ui::Widget xy = m_pXYWnd->GetWidget();
 +
 +              m_pXZWnd = new XYWnd();
 +              m_pXZWnd->SetViewType( XZ );
 +
 +              ui::Widget xz = m_pXZWnd->GetWidget();
 +
 +              ui::Widget hsplit = ui::HPaned(ui::New);
 +              vbox.pack_start( hsplit, TRUE, TRUE, 0 );
 +              hsplit.show();
 +
 +              /* Before merging NetRadiantCustom:
 +              ui::Widget split = create_split_views( camera, yz, xy, xz ); */
 +              m_hSplit = create_split_views( camera, yz, xy, xz, m_vSplit, m_vSplit2 );
 +
 +              ui::Widget vsplit = ui::VPaned(ui::New);
 +              vsplit.show();
 +
 +              // textures
 +              ui::Widget texture_window = create_framed_widget( TextureBrowser_constructWindow( window ) );
 +
 +              // console
 +              ui::Widget console_window = create_framed_widget( Console_constructWindow( window ) );
 +
 +              /* Before merging NetRadiantCustom:
 +              gtk_paned_add1( GTK_PANED( hsplit ), m_hSplit );
 +              gtk_paned_add2( GTK_PANED( hsplit ), vsplit );
 +
 +              gtk_paned_add1( GTK_PANED( vsplit ), texture_window  );
 +              gtk_paned_add2( GTK_PANED( vsplit ), console_window  );
 +              */
 +
 +              gtk_paned_pack1( GTK_PANED( hsplit ), m_hSplit, TRUE, TRUE );
 +              gtk_paned_pack2( GTK_PANED( hsplit ), vsplit, TRUE, TRUE);
 +
 +              gtk_paned_pack1( GTK_PANED( vsplit ), texture_window, TRUE, TRUE );
 +              gtk_paned_pack2( GTK_PANED( vsplit ), console_window, TRUE, TRUE );
 +
 +              hsplit.connect( "size_allocate", G_CALLBACK( hpaned_allocate ), &g_single_hpaned );
 +              hsplit.connect( "notify::position", G_CALLBACK( paned_position ), &g_single_hpaned );
 +
 +              vsplit.connect( "size_allocate", G_CALLBACK( vpaned_allocate ), &g_single_vpaned );
 +              vsplit.connect( "notify::position", G_CALLBACK( paned_position ), &g_single_vpaned );
 +      }
  
        EntityList_constructWindow( window );
        PreferencesDialog_constructWindow( window );
@@@ -3458,7 -3312,7 +3448,7 @@@ void MainFrame::SetStatusText( CopiedSt
  }
  
  void Sys_Status( const char* status ){
 -      if ( g_pParentWnd != 0 ) {
 +      if ( g_pParentWnd != nullptr ) {
                g_pParentWnd->SetStatusText( g_pParentWnd->m_command_status, status );
        }
  }
@@@ -3490,7 -3344,7 +3480,7 @@@ void MainFrame::SetGridStatus()
  }
  
  void GridStatus_onTextureLockEnabledChanged(){
 -      if ( g_pParentWnd != 0 ) {
 +      if ( g_pParentWnd != nullptr ) {
                g_pParentWnd->SetGridStatus();
        }
  }
@@@ -3535,7 -3389,7 +3525,7 @@@ void GlobalGL_sharedContextDestroyed()
  
  void Layout_constructPreferences( PreferencesPage& page ){
        {
 -              const char* layouts[] = { "window1.png", "window2.png", "window3.png", "window4.png" };
 +              const char* layouts[] = { "window1.png", "window2.png", "window3.png", "window4.png", "window5.png" };
                page.appendRadioIcons(
                        "Window Layout",
                        STRING_ARRAY_RANGE( layouts ),
@@@ -3662,9 -3516,9 +3652,9 @@@ void Maximize_View()
                g_maximizeview.toggle();
  }
  
 -
  #include "preferencesystem.h"
  #include "stringio.h"
 +#include "transformpath/transformpath.h"
  
  void MainFrame_Construct(){
        GlobalCommands_insert( "OpenManual", makeCallbackF(OpenHelpURL), Accelerator( GDK_KEY_F1 ) );
        GlobalCommands_insert( "ColorSchemeQER", makeCallbackF(ColorScheme_QER) );
        GlobalCommands_insert( "ColorSchemeBlackAndGreen", makeCallbackF(ColorScheme_Black) );
        GlobalCommands_insert( "ColorSchemeYdnar", makeCallbackF(ColorScheme_Ydnar) );
 +      GlobalCommands_insert( "ColorSchemeAdwaitaDark", makeCallbackF(ColorScheme_AdwaitaDark));
        GlobalCommands_insert( "ChooseTextureBackgroundColor", makeCallback( g_ColoursMenu.m_textureback ) );
        GlobalCommands_insert( "ChooseGridBackgroundColor", makeCallback( g_ColoursMenu.m_xyback ) );
        GlobalCommands_insert( "ChooseGridMajorColor", makeCallback( g_ColoursMenu.m_gridmajor ) );
  #error "unknown platform"
  #endif
                ;
 +
                StringOutputStream path( 256 );
                path << DirectoryCleaned( g_pGameDescription->getRequiredKeyValue( ENGINEPATH_ATTRIBUTE ) );
 -              g_strEnginePath = path.c_str();
 +
 +              g_strEnginePath = transformPath( path.c_str() ).c_str();
                GlobalPreferenceSystem().registerPreference( "EnginePath", make_property_string( g_strEnginePath ) );
        }
  
        g_entityCount.setCountChangedCallback( makeCallbackF(QE_entityCountChanged) );
        GlobalEntityCreator().setCounter( &g_entityCount );
  
 -      GLWidget_sharedContextCreated = GlobalGL_sharedContextCreated;
 -      GLWidget_sharedContextDestroyed = GlobalGL_sharedContextDestroyed;
 +      glwidget_set_shared_context_constructors( GlobalGL_sharedContextCreated, GlobalGL_sharedContextDestroyed);
  
        GlobalEntityClassManager().attach( g_WorldspawnColourEntityClassObserver );
  }
@@@ -3889,61 -3741,3 +3879,61 @@@ void GLWindow_Construct()
  
  void GLWindow_Destroy(){
  }
 +
 +/* HACK: If ui::main is not called yet,
 +gtk_main_quit will not quit, so tell main
 +to not call ui::main. This happens when a
 +map is loaded from command line and require
 +a restart because of wrong format.
 +Delete this when the code to not have to
 +restart to load another format is merged. */
 +extern bool g_dontStart;
 +
 +void Radiant_Restart(){
 +      // preferences are expected to be already saved in any way
 +      // this is just to be sure and be future proof
 +      Preferences_Save();
 +
 +      // this asks user for saving if map is modified
 +      // user can chose to not save, it's ok
 +      ConfirmModified( "Restart " RADIANT_NAME );
 +
 +      int status;
 +
 +      char *argv[ 3 ];
 +      char exe_file[ 256 ];
 +      char map_file[ 256 ];
 +      bool with_map = false;
 +
 +      strncpy( exe_file, g_strAppFilePath.c_str(), 256 );
 +
 +      if ( !Map_Unnamed( g_map ) ) {
 +              strncpy( map_file, Map_Name( g_map ), 256 );
 +              with_map = true;
 +      }
 +
 +      argv[ 0 ] = exe_file;
 +      argv[ 1 ] = with_map ? map_file : NULL;
 +      argv[ 2 ] = NULL;
 +
 +#if GDEF_OS_WINDOWS
 +      status = !_spawnvpe( P_NOWAIT, exe_file, argv, environ );
 +#else
 +      pid_t pid;
 +
 +      status = posix_spawn( &pid, exe_file, NULL, NULL, argv, environ );
 +#endif
 +
 +      // quit if radiant successfully started
 +      if ( status == 0 ) {
 +              gtk_main_quit();
 +              /* HACK: If ui::main is not called yet,
 +              gtk_main_quit will not quit, so tell main
 +              to not call ui::main. This happens when a
 +              map is loaded from command line and require
 +              a restart because of wrong format.
 +              Delete this when the code to not have to
 +              restart to load another format is merged. */
 +              g_dontStart = true;
 +      }
 +}
diff --combined radiant/xywindow.cpp
index e5128ae7db609b38335d9229f684897437c64a64,e573d6568d55dcd13035df48c6c81bbcbaeda1a8..63ef5973b107e3eb25f175ef1775795d639086c6
@@@ -58,7 -58,6 +58,7 @@@
  #include "gtkutil/widget.h"
  #include "gtkutil/glwidget.h"
  #include "gtkutil/filechooser.h"
 +#include "gtkutil/cursor.h"
  #include "gtkmisc.h"
  #include "select.h"
  #include "csg.h"
@@@ -366,7 -365,7 +366,7 @@@ struct xywindow_globals_private_
                show_names( false ),
                show_coordinates( false ),
                show_angles( true ),
-               show_outline( false ),
+               show_outline( true ),
                show_axis( true ),
  
                d_show_work( false ),
@@@ -556,19 -555,6 +556,19 @@@ void XYWnd::ZoomInWithMouse( int pointx
        }
  }
  
 +void XYWnd::Redraw() {
 +      if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
 +              if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
 +                      GlobalOpenGL_debugAssertNoErrors();
 +                      XY_Draw();
 +                      GlobalOpenGL_debugAssertNoErrors();
 +
 +                      m_XORRectangle.set( rectangle_t() );
 +              }
 +              glwidget_swap_buffers( m_gl_widget );
 +      }
 +}
 +
  VIEWTYPE GlobalXYWnd_getCurrentViewType(){
        ASSERT_NOTNULL( g_pParentWnd );
        ASSERT_NOTNULL( g_pParentWnd->ActiveXY() );
@@@ -823,13 -809,24 +823,14 @@@ gboolean xywnd_size_allocate( ui::Widge
  }
  
  gboolean xywnd_expose( ui::Widget widget, GdkEventExpose* event, XYWnd* xywnd ){
 -      if ( glwidget_make_current( xywnd->GetWidget() ) != FALSE ) {
 -              if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
 -                      GlobalOpenGL_debugAssertNoErrors();
 -                      xywnd->XY_Draw();
 -                      GlobalOpenGL_debugAssertNoErrors();
 -
 -                      xywnd->m_XORRectangle.set( rectangle_t() );
 -              }
 -              glwidget_swap_buffers( xywnd->GetWidget() );
 -      }
 +      xywnd->Redraw();
        return FALSE;
  }
  
 -
  void XYWnd_CameraMoved( XYWnd& xywnd ){
        if ( g_xywindow_globals_private.m_bCamXYUpdate ) {
-               XYWnd_Update( xywnd );
+               //XYWnd_Update( xywnd );
+               xywnd.UpdateCameraIcon();
        }
  }
  
@@@ -841,7 -838,6 +842,7 @@@ XYWnd::XYWnd() 
        m_window_observer( NewWindowObserver() ),
        m_XORRectangle( m_gl_widget ),
        m_chasemouse_handler( 0 ){
 +
        m_bActive = false;
        m_buttonstate = 0;
  
  
        Map_addValidCallback( g_map, DeferredDrawOnMapValidChangedCaller( m_deferredDraw ) );
  
 -      updateProjection();
 -      updateModelview();
 +      // This reconstruct=false argument is used to avoid a circular dependency
 +      // between modelview and projection initialization and a valgrind complaint
 +      updateProjection( false );
 +      updateModelview( false );
 +      m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
  
        AddSceneChangeCallback( ReferenceCaller<XYWnd, void(), &XYWnd_Update>( *this ) );
        AddCameraMovedCallback( ReferenceCaller<XYWnd, void(), &XYWnd_CameraMoved>( *this ) );
@@@ -998,11 -991,14 +999,11 @@@ void XYWnd::Clipper_Crosshair_OnMouseMo
        Vector3 mousePosition;
        XY_ToPoint( x, y, mousePosition );
        if ( ClipMode() && GlobalClipPoints_Find( mousePosition, (VIEWTYPE)m_viewType, m_fScale ) != 0 ) {
 -              GdkCursor *cursor;
 -              cursor = gdk_cursor_new( GDK_CROSSHAIR );
 -              gdk_window_set_cursor( gtk_widget_get_window(m_gl_widget), cursor );
 -              gdk_cursor_unref( cursor );
 +              set_cursor ( m_gl_widget, GDK_CROSSHAIR );
        }
        else
        {
 -              gdk_window_set_cursor( gtk_widget_get_window(m_gl_widget), 0 );
 +              default_cursor( m_gl_widget );
        }
  }
  
@@@ -1135,8 -1131,8 +1136,8 @@@ void entitycreate_activated( ui::Widge
                g_pParentWnd->ActiveXY()->OnEntityCreate( entity_name );
        }
        else {
 -              GlobalRadiant().m_pfnMessageBox( MainFrame_getWindow(), "There's already a worldspawn in your map!"
 -                                                                                                                                                        "",
 +              GlobalRadiant().m_pfnMessageBox( MainFrame_getWindow(),
 +                      "There's already a worldspawn in your map!",
                                                                                 "Info",
                                                                                 eMB_OK,
                                                                                 eMB_ICONDEFAULT );
@@@ -1251,17 -1247,13 +1252,17 @@@ void XYWnd::Move_Begin()
                Move_End();
        }
        m_move_started = true;
 -      g_xywnd_freezePointer.freeze_pointer( m_parent  ? m_parent : MainFrame_getWindow(), m_gl_widget, XYWnd_moveDelta, this );
 +      /* NetRadiantCustom did this instead:
 +      g_xywnd_freezePointer.freeze_pointer( m_parent  ? m_parent : MainFrame_getWindow(), m_gl_widget, XYWnd_moveDelta, this ); */
 +      g_xywnd_freezePointer.freeze_pointer( m_gl_widget, XYWnd_moveDelta, this );
        m_move_focusOut = m_gl_widget.connect( "focus_out_event", G_CALLBACK( XYWnd_Move_focusOut ), this );
  }
  
  void XYWnd::Move_End(){
        m_move_started = false;
 -      g_xywnd_freezePointer.unfreeze_pointer( m_parent ? m_parent : MainFrame_getWindow(), false );
 +      /* NetRadiant did this instead:
 +      g_xywnd_freezePointer.unfreeze_pointer( m_parent ? m_parent : MainFrame_getWindow(), false ); */
 +      g_xywnd_freezePointer.unfreeze_pointer( m_gl_widget, false );
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_move_focusOut );
  }
  
@@@ -1300,9 -1292,7 +1301,9 @@@ void XYWnd::Zoom_Begin()
        }
        m_zoom_started = true;
        g_dragZoom = 0;
 -      g_xywnd_freezePointer.freeze_pointer( m_parent ? m_parent : MainFrame_getWindow(), m_gl_widget, XYWnd_zoomDelta, this );
 +      /* NetRadiantCustom did this instead:
 +      g_xywnd_freezePointer.freeze_pointer( m_parent ? m_parent : MainFrame_getWindow(), m_gl_widget, XYWnd_zoomDelta, this ); */
 +      g_xywnd_freezePointer.freeze_pointer( m_parent ? m_parent : MainFrame_getWindow(), XYWnd_zoomDelta, this );
        m_zoom_focusOut = m_gl_widget.connect( "focus_out_event", G_CALLBACK( XYWnd_Zoom_focusOut ), this );
  }
  
@@@ -1574,25 -1564,17 +1575,25 @@@ void XYWnd::XY_DisableBackground( void 
  
  void WXY_BackgroundSelect( void ){
        bool brushesSelected = Scene_countSelectedBrushes( GlobalSceneGraph() ) != 0;
 +
 +      ui::Window main_window = MainFrame_getWindow();
 +
        if ( !brushesSelected ) {
 -              ui::alert( ui::root, "You have to select some brushes to get the bounding box for.\n",
 +              ui::alert( main_window, "You have to select some brushes to get the bounding box for.\n",
                                                "No selection", ui::alert_type::OK, ui::alert_icon::Error );
                return;
        }
  
 -      const char *filename = MainFrame_getWindow().file_dialog( TRUE, "Background Image", NULL, NULL );
 +      const char *filename = main_window.file_dialog( TRUE, "Background Image", NULL, NULL );
 +
        g_pParentWnd->ActiveXY()->XY_DisableBackground();
 +
        if ( filename ) {
                g_pParentWnd->ActiveXY()->XY_LoadBackgroundImage( filename );
        }
 +
 +      // Draw the background image immediately (do not wait for user input).
 +      g_pParentWnd->ActiveXY()->Redraw();
  }
  
  /*
@@@ -2058,47 -2040,106 +2059,106 @@@ void XYWnd::XY_DrawBlockGrid()
  }
  
  void XYWnd::DrawCameraIcon( const Vector3& origin, const Vector3& angles ){
-       float x, y, fov, box;
-       double a;
-       fov = 48 / m_fScale;
-       box = 16 / m_fScale;
+       Cam.fov = 48 / m_fScale;
+       Cam.box = 16 / m_fScale;
  
        if ( m_viewType == XY ) {
-               x = origin[0];
-               y = origin[1];
-               a = degrees_to_radians( angles[CAMERA_YAW] );
+               Cam.x = origin[0];
+               Cam.y = origin[1];
+               Cam.a = degrees_to_radians( angles[CAMERA_YAW] );
        }
        else if ( m_viewType == YZ ) {
-               x = origin[1];
-               y = origin[2];
-               a = degrees_to_radians( angles[CAMERA_PITCH] );
+               Cam.x = origin[1];
+               Cam.y = origin[2];
+               Cam.a = degrees_to_radians( angles[CAMERA_PITCH] );
        }
        else
        {
-               x = origin[0];
-               y = origin[2];
-               a = degrees_to_radians( angles[CAMERA_PITCH] );
+               Cam.x = origin[0];
+               Cam.y = origin[2];
+               Cam.a = degrees_to_radians( angles[CAMERA_PITCH] );
        }
  
-       glColor3f( 0.0, 0.0, 1.0 );
+       //glColor3f( 0.0, 0.0, 1.0 );
+       glColor3f( 1.0, 1.0, 1.0 );
        glBegin( GL_LINE_STRIP );
-       glVertex3f( x - box,y,0 );
-       glVertex3f( x,y + ( box / 2 ),0 );
-       glVertex3f( x + box,y,0 );
-       glVertex3f( x,y - ( box / 2 ),0 );
-       glVertex3f( x - box,y,0 );
-       glVertex3f( x + box,y,0 );
+       glVertex3f( Cam.x - Cam.box,Cam.y,0 );
+       glVertex3f( Cam.x,Cam.y + ( Cam.box / 2 ),0 );
+       glVertex3f( Cam.x + Cam.box,Cam.y,0 );
+       glVertex3f( Cam.x,Cam.y - ( Cam.box / 2 ),0 );
+       glVertex3f( Cam.x - Cam.box,Cam.y,0 );
+       glVertex3f( Cam.x + Cam.box,Cam.y,0 );
        glEnd();
  
        glBegin( GL_LINE_STRIP );
-       glVertex3f( x + static_cast<float>( fov * cos( a + c_pi / 4 ) ), y + static_cast<float>( fov * sin( a + c_pi / 4 ) ), 0 );
-       glVertex3f( x, y, 0 );
-       glVertex3f( x + static_cast<float>( fov * cos( a - c_pi / 4 ) ), y + static_cast<float>( fov * sin( a - c_pi / 4 ) ), 0 );
+       glVertex3f( Cam.x + static_cast<float>( Cam.fov * cos( Cam.a + c_pi / 4 ) ), Cam.y + static_cast<float>( Cam.fov * sin( Cam.a + c_pi / 4 ) ), 0 );
+       glVertex3f( Cam.x, Cam.y, 0 );
+       glVertex3f( Cam.x + static_cast<float>( Cam.fov * cos( Cam.a - c_pi / 4 ) ), Cam.y + static_cast<float>( Cam.fov * sin( Cam.a - c_pi / 4 ) ), 0 );
        glEnd();
  
  }
  
+ void XYWnd::UpdateCameraIcon( void ){
+       if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
+               if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
+                       GlobalOpenGL_debugAssertNoErrors();
+                       glDrawBuffer( GL_FRONT );
+                       {
+                               // clear
+                               glViewport( 0, 0, m_nWidth, m_nHeight );
+                               // set up viewpoint
+                               glMatrixMode( GL_PROJECTION );
+                               glLoadMatrixf( reinterpret_cast<const float*>( &m_projection ) );
+                               glMatrixMode( GL_MODELVIEW );
+                               glLoadIdentity();
+                               glScalef( m_fScale, m_fScale, 1 );
+                               int nDim1 = ( m_viewType == YZ ) ? 1 : 0;
+                               int nDim2 = ( m_viewType == XY ) ? 1 : 2;
+                               glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 );
+                               glDisable( GL_LINE_STIPPLE );
+                               glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+                               glDisableClientState( GL_NORMAL_ARRAY );
+                               glDisableClientState( GL_COLOR_ARRAY );
+                               glDisable( GL_TEXTURE_2D );
+                               glDisable( GL_LIGHTING );
+                               glDisable( GL_COLOR_MATERIAL );
+                               glDisable( GL_DEPTH_TEST );
+                               glDisable( GL_TEXTURE_1D );
+                               glEnable( GL_BLEND );
+                               glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
+                               //glColor3f( 0.0, 0.0, 1.0 );
+                               glColor3f( 1.0, 1.0, 1.0 );
+                               glBegin( GL_LINE_STRIP );
+                               glVertex3f( Cam.x - Cam.box,Cam.y,0 );
+                               glVertex3f( Cam.x,Cam.y + ( Cam.box / 2 ),0 );
+                               glVertex3f( Cam.x + Cam.box,Cam.y,0 );
+                               glVertex3f( Cam.x,Cam.y - ( Cam.box / 2 ),0 );
+                               glVertex3f( Cam.x - Cam.box,Cam.y,0 );
+                               glVertex3f( Cam.x + Cam.box,Cam.y,0 );
+                               glEnd();
+                               glBegin( GL_LINE_STRIP );
+                               glVertex3f( Cam.x + static_cast<float>( Cam.fov * cos( Cam.a + c_pi / 4 ) ), Cam.y + static_cast<float>( Cam.fov * sin( Cam.a + c_pi / 4 ) ), 0 );
+                               glVertex3f( Cam.x, Cam.y, 0 );
+                               glVertex3f( Cam.x + static_cast<float>( Cam.fov * cos( Cam.a - c_pi / 4 ) ), Cam.y + static_cast<float>( Cam.fov * sin( Cam.a - c_pi / 4 ) ), 0 );
+                               glEnd();
+                               XYWnd::DrawCameraIcon( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Camera_getAngles( *g_pParentWnd->GetCamWnd() ) );
+                               glDisable( GL_BLEND );
+                       }
+                       glDrawBuffer( GL_BACK );
+                       GlobalOpenGL_debugAssertNoErrors();
+                       glwidget_make_current( m_gl_widget );
+               }
+       }
+ }
  
  float Betwixt( float f1, float f2 ){
        if ( f1 > f2 ) {
@@@ -2304,7 -2345,7 +2364,7 @@@ RenderStateFlags m_globalstate
  Shader* m_state_selected;
  };
  
 -void XYWnd::updateProjection(){
 +void XYWnd::updateProjection( bool reconstruct ){
        m_projection[0] = 1.0f / static_cast<float>( m_nWidth / 2 );
        m_projection[5] = 1.0f / static_cast<float>( m_nHeight / 2 );
        m_projection[10] = 1.0f / ( g_MaxWorldCoord * m_fScale );
  
        m_projection[15] = 1.0f;
  
 +      if (reconstruct) {
        m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
  }
 +}
  
  // note: modelview matrix must have a uniform scale, otherwise strange things happen when rendering the rotation manipulator.
 -void XYWnd::updateModelview(){
 +void XYWnd::updateModelview( bool reconstruct ){
        int nDim1 = ( m_viewType == YZ ) ? 1 : 0;
        int nDim2 = ( m_viewType == XY ) ? 1 : 2;
  
        m_modelview[3] = m_modelview[7] = m_modelview[11] = 0;
        m_modelview[15] = 1;
  
 +      if (reconstruct) {
        m_view.Construct( m_projection, m_modelview, m_nWidth, m_nHeight );
 +      }
  }
  
  /*
@@@ -2537,7 -2574,10 +2597,10 @@@ void XYWnd::XY_Draw()
        glScalef( m_fScale, m_fScale, 1 );
        glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 );
  
+       glEnable( GL_BLEND );
+       glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
        DrawCameraIcon( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Camera_getAngles( *g_pParentWnd->GetCamWnd() ) );
+       glDisable( GL_BLEND );
  
        Feedback_draw2D( m_viewType );
  
@@@ -2634,7 -2674,7 +2697,7 @@@ void XY_Split_Focus()
  }
  
  void XY_Focus(){
-       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit ) {
+       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) {
                // cannot do this in a split window
                // do something else that the user may want here
                XY_Split_Focus();
        XYWnd_Focus( xywnd );
  }
  
- void XY_Top(){
-       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) {
+ void XY_TopFrontSide( VIEWTYPE viewtype ){
+       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit ) {
                // cannot do this in a split window
                // do something else that the user may want here
                XY_Split_Focus();
                return;
        }
-       XYWnd* xywnd = g_pParentWnd->GetXYWnd();
-       xywnd->SetViewType( XY );
+       XYWnd* xywnd = g_pParentWnd->CurrentStyle() == MainFrame::eFloating ? g_pParentWnd->ActiveXY() : g_pParentWnd->GetXYWnd();
+       xywnd->SetViewType( viewtype );
        XYWnd_Focus( xywnd );
  }
  
- void XY_Side(){
-       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) {
-               // cannot do this in a split window
-               // do something else that the user may want here
-               XY_Split_Focus();
-               return;
-       }
+ void XY_Top(){
+       XY_TopFrontSide( XY );
+ }
  
-       XYWnd* xywnd = g_pParentWnd->GetXYWnd();
-       xywnd->SetViewType( XZ );
-       XYWnd_Focus( xywnd );
+ void XY_Side(){
+       XY_TopFrontSide( XZ );
  }
  
  void XY_Front(){
-       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) {
-               // cannot do this in a split window
-               // do something else that the user may want here
-               XY_Split_Focus();
-               return;
-       }
-       XYWnd* xywnd = g_pParentWnd->GetXYWnd();
-       xywnd->SetViewType( YZ );
-       XYWnd_Focus( xywnd );
+       XY_TopFrontSide( YZ );
  }
  
- void XY_Next(){
-       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) {
-               // cannot do this in a split window
-               // do something else that the user may want here
-               XY_Split_Focus();
-               return;
-       }
-       XYWnd* xywnd = g_pParentWnd->GetXYWnd();
+ void XY_NextView( XYWnd* xywnd ){
        if ( xywnd->GetViewType() == XY ) {
                xywnd->SetViewType( XZ );
        }
        XYWnd_Focus( xywnd );
  }
  
+ void XY_Next(){
+       if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit ) {
+               // cannot do this in a split window
+               // do something else that the user may want here
+               XY_Split_Focus();
+               return;
+       }
+       XYWnd* xywnd = g_pParentWnd->CurrentStyle() == MainFrame::eFloating ? g_pParentWnd->ActiveXY() : g_pParentWnd->GetXYWnd();
+       XY_NextView( xywnd );
+ }
  void XY_Zoom100(){
        if ( g_pParentWnd->GetXYWnd() ) {
                g_pParentWnd->GetXYWnd()->SetScale( 1 );
diff --combined radiant/xywindow.h
index 071f132cbe5dd19713a90ba207672cd3cfc0aa59,5273ee4ec7ab0ba18d537783daa050152dcc0cff..36a5f1cb786258cf6f4999ebfe918b9ca9131487
@@@ -128,10 -128,7 +128,10 @@@ void ZoomIn()
  void ZoomOut();
  void ZoomInWithMouse( int pointx, int pointy );
  
 +void Redraw();
 +
  void RenderActive();
 +
  void SetActive( bool b ){
        m_bActive = b;
        RenderActive();
  bool Active(){
        return m_bActive;
  };
+ struct camera_icon_t
+ {
+       float x, y, fov, box;
+       double a;
+ };
+ camera_icon_t Cam;
+ void UpdateCameraIcon();
  
  void Clipper_OnLButtonDown( int x, int y );
  void Clipper_OnLButtonUp( int x, int y );
@@@ -161,8 -166,8 +169,8 @@@ guint m_chasemouse_handler
  void ChaseMouse();
  bool chaseMouseMotion( int pointx, int pointy );
  
 -void updateModelview();
 -void updateProjection();
 +void updateModelview(bool reconstruct = true);
 +void updateProjection(bool reconstruct = true);
  Matrix4 m_projection;
  Matrix4 m_modelview;
  
@@@ -254,8 -259,6 +262,8 @@@ struct xywindow_globals_
        Vector3 color_selbrushes;
        Vector3 color_clipper;
        Vector3 color_viewname;
 +      Vector3 color_gridminor_alt;
 +      Vector3 color_gridmajor_alt;
        Vector3 AxisColorX;
        Vector3 AxisColorY;
        Vector3 AxisColorZ;
                color_selbrushes( 1.f, 0.f, 0.f ),
                color_clipper( 0.f, 0.f, 1.f ),
                color_viewname( 0.5f, 0.f, 0.75f ),
 +              color_gridminor_alt( 0.f, 0.f, 0.f ),
 +              color_gridmajor_alt( 0.f, 0.f, 0.f ),
  
                AxisColorX( 1.f, 0.f, 0.f ),
                AxisColorY( 0.f, 1.f, 0.f ),