]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/texwindow.cpp
freebsd: exclude more libraries when bundling
[xonotic/netradiant.git] / radiant / texwindow.cpp
index 34a9f9260663cbb0bc07bbd0a15cc026808c74b4..8a5cefb9f020e818b692e7190c7a06299b5c8ee7 100644 (file)
@@ -32,6 +32,7 @@
 #include "debugging/debugging.h"
 #include "warnings.h"
 
+#include "defaults.h"
 #include "ifilesystem.h"
 #include "iundo.h"
 #include "igl.h"
@@ -86,9 +87,6 @@
 #include "shaders.h"
 #include "commands.h"
 
-#define NOTEX_BASENAME "notex"
-#define SHADERNOTEX_BASENAME "shadernotex"
-
 bool TextureBrowser_showWads(){
        return !string_empty( g_pGameDescription->getKeyValue( "show_wads" ) );
 }
@@ -103,14 +101,10 @@ typedef std::set<CopiedString> TextureGroups;
 
 void TextureGroups_addWad( TextureGroups& groups, const char* archive ){
        if ( extension_equal( path_get_extension( archive ), "wad" ) ) {
-#if 1
                groups.insert( archive );
-#else
-               CopiedString archiveBaseName( path_get_filename_start( archive ), path_get_filename_base_end( archive ) );
-               groups.insert( archiveBaseName );
-#endif
        }
 }
+
 typedef ReferenceCaller<TextureGroups, void(const char*), TextureGroups_addWad> TextureGroupsAddWadCaller;
 
 namespace
@@ -124,7 +118,9 @@ bool g_TextureBrowser_enableAlpha = true;
 
 CopiedString g_notex;
 CopiedString g_shadernotex;
+
 bool isMissing(const char* name);
+
 bool isNotex(const char* name);
 
 bool isMissing(const char* name){
@@ -138,10 +134,10 @@ bool isMissing(const char* name){
 }
 
 bool isNotex(const char* name){
-       if ( string_equal_suffix( name, "/" NOTEX_BASENAME ) ) {
+       if ( string_equal_suffix( name, "/" DEFAULT_NOTEX_BASENAME ) ) {
                return true;
        }
-       if ( string_equal_suffix( name, "/" SHADERNOTEX_BASENAME ) ) {
+       if ( string_equal_suffix( name, "/" DEFAULT_SHADERNOTEX_BASENAME ) ) {
                return true;
        }
        return false;
@@ -167,6 +163,7 @@ void TextureGroups_addShader( TextureGroups& groups, const char* shaderName ){
                }
        }
 }
+
 typedef ReferenceCaller<TextureGroups, void(const char*), TextureGroups_addShader> TextureGroupsAddShaderCaller;
 
 void TextureGroups_addDirectory( TextureGroups& groups, const char* directory ){
@@ -178,7 +175,9 @@ class DeferredAdjustment
 {
 gdouble m_value;
 guint m_handler;
+
 typedef void ( *ValueChangedFunction )( void* data, gdouble value );
+
 ValueChangedFunction m_function;
 void* m_data;
 
@@ -191,28 +190,31 @@ static gboolean deferred_value_changed( gpointer data ){
        reinterpret_cast<DeferredAdjustment*>( data )->m_value = 0;
        return FALSE;
 }
+
 public:
 DeferredAdjustment( ValueChangedFunction function, void* data ) : m_value( 0 ), m_handler( 0 ), m_function( function ), m_data( data ){
 }
+
 void flush(){
        if ( m_handler != 0 ) {
                g_source_remove( m_handler );
                deferred_value_changed( this );
        }
 }
+
 void value_changed( gdouble value ){
        m_value = value;
        if ( m_handler == 0 ) {
                m_handler = g_idle_add( deferred_value_changed, this );
        }
 }
+
 static void adjustment_value_changed(ui::Adjustment adjustment, DeferredAdjustment* self ){
        self->value_changed( gtk_adjustment_get_value(adjustment) );
 }
 };
 
 
-
 class TextureBrowser;
 
 typedef ReferenceCaller<TextureBrowser, void(), TextureBrowser_queueDraw> TextureBrowserQueueDrawCaller;
@@ -227,24 +229,31 @@ enum StartupShaders
 };
 
 void TextureBrowser_hideUnusedExport( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_hideUnusedExport> TextureBrowserHideUnusedExport;
 
 void TextureBrowser_showShadersExport( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShadersExport> TextureBrowserShowShadersExport;
 
 void TextureBrowser_showShaderlistOnly( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShaderlistOnly> TextureBrowserShowShaderlistOnlyExport;
 
 void TextureBrowser_fixedSize( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_fixedSize> TextureBrowserFixedSizeExport;
 
 void TextureBrowser_filterMissing( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_filterMissing> TextureBrowserFilterMissingExport;
 
 void TextureBrowser_filterFallback( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_filterFallback> TextureBrowserFilterFallbackExport;
 
 void TextureBrowser_enableAlpha( const Callback<void(bool)> & importer );
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_enableAlpha> TextureBrowserEnableAlphaExport;
 
 class TextureBrowser
@@ -257,9 +266,17 @@ int m_nTotalHeight;
 CopiedString shader;
 
 ui::Window m_parent{ui::null};
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+ui::VBox m_vframe{ui::null};
+ui::VBox m_vfiller{ui::null};
+ui::HBox m_hframe{ui::null};
+ui::HBox m_hfiller{ui::null};
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+ui::VBox m_frame{ui::null};
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
 ui::GLArea m_gl_widget{ui::null};
 ui::Widget m_texture_scroll{ui::null};
-ui::TreeView m_treeViewTree{ui::null};
+ui::TreeView m_treeViewTree{ui::New};
 ui::TreeView m_treeViewTags{ui::null};
 ui::Frame m_tag_frame{ui::null};
 ui::ListStore m_assigned_store{ui::null};
@@ -310,6 +327,7 @@ bool m_searchedTags;
 bool m_tags;
 // The uniform size (in pixels) that textures are resized to when m_resizeTextures is true.
 int m_uniformTextureSize;
+
 // Return the display width of a texture in the texture browser
 int getTextureWidth( qtexture_t* tex ){
        int width;
@@ -328,6 +346,7 @@ int getTextureWidth( qtexture_t* tex ){
        }
        return width;
 }
+
 // Return the display height of a texture in the texture browser
 int getTextureHeight( qtexture_t* tex ){
        int height;
@@ -558,7 +577,15 @@ bool Texture_IsShown( IShader* shader, bool show_shaders, bool hideUnused ){
                }
        }
        else {
-               if ( !shader_equal_prefix( shader_get_textureName( shader->getName() ), g_TextureBrowser_currentDirectory.c_str() ) ) {
+               if ( TextureBrowser_showWads() )
+               {
+                       if ( g_TextureBrowser_currentDirectory != ""
+                               && !string_equal( shader->getWadName(), g_TextureBrowser_currentDirectory.c_str() ) )
+                       {
+                               return false;
+                       }
+               }
+               else if ( !shader_equal_prefix( shader_get_textureName( shader->getName() ), g_TextureBrowser_currentDirectory.c_str() ) ) {
                        return false;
                }
        }
@@ -648,8 +675,10 @@ void realise(){
        m_realiseCallbacks();
        TextureBrowser_constructTreeStore();
 }
+
 void unrealise(){
 }
+
 void insert( const SignalHandler& handler ){
        m_realiseCallbacks.connectLast( handler );
 }
@@ -721,14 +750,27 @@ bool texture_name_ignore( const char* name ){
                endswith( strTemp.c_str(), ".diffuse" ) ||
                endswith( strTemp.c_str(), ".blend" ) ||
                endswith( strTemp.c_str(), ".alpha" ) ||
-               endswith( strTemp.c_str(), "_norm" ) ||
+               endswith( strTemp.c_str(), "_alpha" ) ||
+               /* Quetoo */
+               endswith( strTemp.c_str(), "_h" ) ||
+               endswith( strTemp.c_str(), "_local" ) ||
+               endswith( strTemp.c_str(), "_nm" ) ||
+               endswith( strTemp.c_str(), "_s" ) ||
+               /* DarkPlaces */
                endswith( strTemp.c_str(), "_bump" ) ||
                endswith( strTemp.c_str(), "_glow" ) ||
                endswith( strTemp.c_str(), "_gloss" ) ||
+               endswith( strTemp.c_str(), "_luma" ) ||
+               endswith( strTemp.c_str(), "_norm" ) ||
                endswith( strTemp.c_str(), "_pants" ) ||
                endswith( strTemp.c_str(), "_shirt" ) ||
                endswith( strTemp.c_str(), "_reflect" ) ||
-               endswith( strTemp.c_str(), "_alpha" ) ||
+               /* Unvanquished */
+               endswith( strTemp.c_str(), "_d" ) ||
+               endswith( strTemp.c_str(), "_n" ) ||
+               endswith( strTemp.c_str(), "_p" ) ||
+               endswith( strTemp.c_str(), "_g" ) ||
+               endswith( strTemp.c_str(), "_a" ) ||
                0;
 }
 
@@ -738,6 +780,7 @@ public:
 void visit( const char* name ){
        IShader* shader = QERApp_Shader_ForName( CopiedString( StringRange( name, path_get_filename_base_end( name ) ) ).c_str() );
        shader->DecRef();
+       shader->setWadName( g_TextureBrowser_currentDirectory.c_str() );
 }
 };
 
@@ -755,7 +798,6 @@ void TextureBrowser_updateTitle(){
 }
 
 
-
 class TextureCategoryLoadShader
 {
 const char* m_directory;
@@ -767,6 +809,7 @@ TextureCategoryLoadShader( const char* directory, std::size_t& count )
        : m_directory( directory ), m_count( count ){
        m_count = 0;
 }
+
 void operator()( const char* name ) const {
        if ( shader_equal_prefix( name, "textures/" )
                 && shader_equal_prefix( name + string_length( "textures/" ), m_directory ) ) {
@@ -796,6 +839,7 @@ void TextureDirectory_loadTexture( const char* directory, const char* texture ){
        IShader* shader = QERApp_Shader_ForName( name.c_str() );
        shader->DecRef();
 }
+
 typedef ConstPointerCaller<char, void(const char*), TextureDirectory_loadTexture> TextureDirectoryLoadTextureCaller;
 
 class LoadTexturesByTypeVisitor : public ImageModules::Visitor
@@ -805,6 +849,7 @@ public:
 LoadTexturesByTypeVisitor( const char* dirstring )
        : m_dirstring( dirstring ){
 }
+
 void visit( const char* minor, const _QERPlugImageTable& table ) const {
        GlobalFileSystem().forEachFile( m_dirstring, minor, TextureDirectoryLoadTextureCaller( m_dirstring ) );
 }
@@ -812,10 +857,19 @@ void visit( const char* minor, const _QERPlugImageTable& table ) const {
 
 void TextureBrowser_ShowDirectory( TextureBrowser& textureBrowser, const char* directory ){
        if ( TextureBrowser_showWads() ) {
+               g_TextureBrowser_currentDirectory = directory;
+               TextureBrowser_heightChanged( textureBrowser );
+
                Archive* archive = GlobalFileSystem().getArchive( directory );
-               ASSERT_NOTNULL( archive );
-               LoadShaderVisitor visitor;
-               archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "textures/" );
+               if ( archive != nullptr )
+               {
+                       LoadShaderVisitor visitor;
+                       archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "textures/" );
+               }
+               else if ( extension_equal_i( path_get_extension( directory ), "wad" ) )
+               {
+                       globalErrorStream() << "Failed to load " << directory << "\n";
+               }
        }
        else
        {
@@ -871,36 +925,43 @@ bool TextureBrowser_hideUnused();
 void TextureBrowser_hideUnusedExport( const Callback<void(bool)> & importer ){
        importer( TextureBrowser_hideUnused() );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_hideUnusedExport> TextureBrowserHideUnusedExport;
 
 void TextureBrowser_showShadersExport( const Callback<void(bool)> & importer ){
        importer( GlobalTextureBrowser().m_showShaders );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShadersExport> TextureBrowserShowShadersExport;
 
 void TextureBrowser_showShaderlistOnly( const Callback<void(bool)> & importer ){
        importer( g_TextureBrowser_shaderlistOnly );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShaderlistOnly> TextureBrowserShowShaderlistOnlyExport;
 
 void TextureBrowser_fixedSize( const Callback<void(bool)> & importer ){
        importer( g_TextureBrowser_fixedSize );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_fixedSize> TextureBrowser_FixedSizeExport;
 
 void TextureBrowser_filterMissing( const Callback<void(bool)> & importer ){
        importer( g_TextureBrowser_filterMissing );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_filterMissing> TextureBrowser_filterMissingExport;
 
 void TextureBrowser_filterFallback( const Callback<void(bool)> & importer ){
        importer( g_TextureBrowser_filterFallback );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_filterFallback> TextureBrowser_filterFallbackExport;
 
 void TextureBrowser_enableAlpha( const Callback<void(bool)> & importer ){
        importer( g_TextureBrowser_enableAlpha );
 }
+
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_enableAlpha> TextureBrowser_enableAlphaExport;
 
 void TextureBrowser_SetHideUnused( TextureBrowser& textureBrowser, bool hideUnused ){
@@ -1090,6 +1151,7 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
                                  textureBrowser.color_textureback[1],
                                  textureBrowser.color_textureback[2],
                                  0 );
+
        glViewport( 0, 0, textureBrowser.width, textureBrowser.height );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
@@ -1202,6 +1264,7 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
                                glBegin( GL_QUADS );
                                int font_height = TextureBrowser_fontHeight( textureBrowser );
                                for ( int i = 0; i < nHeight; i += 8 )
+                               {
                                        for ( int j = 0; j < nWidth; j += 8 )
                                        {
                                                unsigned char color = (i + j) / 8 % 2 ? 0x66 : 0x99;
@@ -1215,6 +1278,7 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
                                                glVertex2i(x + left,  y - nHeight - font_height + bottom);
                                                glVertex2i(x + right, y - nHeight - font_height + bottom);
                                        }
+                               }
                                glEnd();
                                glEnable( GL_TEXTURE_2D );
                        }
@@ -1464,7 +1528,6 @@ gboolean TextureBrowser_expose( ui::Widget widget, GdkEventExpose* event, Textur
        return FALSE;
 }
 
-
 TextureBrowser g_TextureBrowser;
 
 TextureBrowser& GlobalTextureBrowser(){
@@ -1485,6 +1548,17 @@ void TextureBrowser_ToggleHideUnused(){
        }
 }
 
+const char* TextureGroups_transformDirName( const char* dirName, StringOutputStream *archiveName )
+{
+       if ( TextureBrowser_showWads() ) {
+               archiveName->clear();
+               *archiveName << StringRange( path_get_filename_start( dirName ), path_get_filename_base_end( dirName ) ) \
+                       << "." << path_get_extension( dirName );
+               return archiveName->c_str();
+       }
+       return dirName;
+}
+
 void TextureGroups_constructTreeModel( TextureGroups groups, ui::TreeStore store ){
        // put the information from the old textures menu into a treeview
        GtkTreeIter iter, child;
@@ -1492,23 +1566,27 @@ void TextureGroups_constructTreeModel( TextureGroups groups, ui::TreeStore store
        TextureGroups::const_iterator i = groups.begin();
        while ( i != groups.end() )
        {
-               const char* dirName = ( *i ).c_str();
+               StringOutputStream archiveName;
+               StringOutputStream nextArchiveName;
+               const char* dirName = TextureGroups_transformDirName( ( *i ).c_str(), &archiveName );
+
                const char* firstUnderscore = strchr( dirName, '_' );
                StringRange dirRoot( dirName, ( firstUnderscore == 0 ) ? dirName : firstUnderscore + 1 );
 
                TextureGroups::const_iterator next = i;
                ++next;
+
                if ( firstUnderscore != 0
                         && next != groups.end()
-                        && string_equal_start( ( *next ).c_str(), dirRoot ) ) {
+                        && string_equal_start( TextureGroups_transformDirName( ( *next ).c_str(), &nextArchiveName ), dirRoot ) ) {
                        gtk_tree_store_append( store, &iter, NULL );
                        gtk_tree_store_set( store, &iter, 0, CopiedString( StringRange( dirName, firstUnderscore ) ).c_str(), -1 );
 
                        // keep going...
-                       while ( i != groups.end() && string_equal_start( ( *i ).c_str(), dirRoot ) )
+                       while ( i != groups.end() && string_equal_start( TextureGroups_transformDirName( ( *i ).c_str(), &nextArchiveName ), dirRoot ) )
                        {
                                gtk_tree_store_append( store, &child, &iter );
-                               gtk_tree_store_set( store, &child, 0, ( *i ).c_str(), -1 );
+                               gtk_tree_store_set( store, &child, 0, TextureGroups_transformDirName( ( *i ).c_str(), &nextArchiveName ), -1 );
                                ++i;
                        }
                }
@@ -1586,7 +1664,6 @@ void TreeView_onRowActivated( ui::TreeView treeview, ui::TreePath path, ui::Tree
 }
 
 void TextureBrowser_createTreeViewTree(){
-       g_TextureBrowser.m_treeViewTree = ui::TreeView(ui::New);
        gtk_tree_view_set_enable_search(g_TextureBrowser.m_treeViewTree, FALSE );
 
        gtk_tree_view_set_headers_visible(g_TextureBrowser.m_treeViewTree, FALSE );
@@ -1599,7 +1676,9 @@ void TextureBrowser_createTreeViewTree(){
 }
 
 void TextureBrowser_addTag();
+
 void TextureBrowser_renameTag();
+
 void TextureBrowser_deleteTag();
 
 void TextureBrowser_createContextMenu( ui::Widget treeview, GdkEventButton *event ){
@@ -1675,7 +1754,7 @@ ui::MenuItem TextureBrowser_constructViewMenu( ui::Menu menu ){
        create_menu_item_with_mnemonic( menu, "Show All", "ShowAllTextures" );
 
        // we always want to show shaders but don't want a "Show Shaders" menu for doom3 and .wad file games
-       if ( g_pGameDescription->mGameType == "doom3" || !string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
+       if ( g_pGameDescription->mGameType == "doom3" || TextureBrowser_showWads() ) {
                g_TextureBrowser.m_showShaders = true;
        }
        else
@@ -1734,7 +1813,7 @@ ui::MenuItem TextureBrowser_constructTagsMenu( ui::Menu menu ){
        return textures_menu_item;
 }
 
-gboolean TextureBrowser_tagMoveHelper( ui::TreeModel model, ui::TreePath path, GtkTreeIter iter, GSList** selected ){
+gboolean TextureBrowser_tagMoveHelper( ui::TreeModel model, ui::TreePath path, GtkTreeIter* iter, GSList** selected ){
        g_assert( selected != NULL );
 
     auto rowref = gtk_tree_row_reference_new( model, path );
@@ -1981,13 +2060,44 @@ void TextureBrowser_checkTagFile(){
 }
 
 void TextureBrowser_SetNotex(){
-       StringOutputStream name( 256 );
-       name << GlobalRadiant().getAppPath() << "bitmaps/" NOTEX_BASENAME ".png";
-       g_notex = name.c_str();
+       IShader* notex = QERApp_Shader_ForName( DEFAULT_NOTEX_NAME );
+       IShader* shadernotex = QERApp_Shader_ForName( DEFAULT_SHADERNOTEX_NAME );
+
+       g_notex = notex->getTexture()->name;
+
+       g_shadernotex = shadernotex->getTexture()->name;
 
-       name = StringOutputStream(256);
-       name << GlobalRadiant().getAppPath() << "bitmaps/" SHADERNOTEX_BASENAME " .png";
-       g_shadernotex = name.c_str();
+       notex->DecRef();
+       shadernotex->DecRef();
+}
+
+static bool isGLWidgetConstructed = false;
+static bool isWindowConstructed = false;
+
+void TextureBrowser_constructGLWidget(){
+       g_TextureBrowser.m_gl_widget = glwidget_new( FALSE );
+       g_object_ref( g_TextureBrowser.m_gl_widget._handle );
+
+       gtk_widget_set_events( g_TextureBrowser.m_gl_widget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK );
+       gtk_widget_set_can_focus( g_TextureBrowser.m_gl_widget, true );
+
+       g_TextureBrowser.m_sizeHandler = g_TextureBrowser.m_gl_widget.connect( "size_allocate", G_CALLBACK( TextureBrowser_size_allocate ), &g_TextureBrowser );
+       g_TextureBrowser.m_exposeHandler = g_TextureBrowser.m_gl_widget.on_render( G_CALLBACK( TextureBrowser_expose ), &g_TextureBrowser );
+
+       g_TextureBrowser.m_gl_widget.connect( "button_press_event", G_CALLBACK( TextureBrowser_button_press ), &g_TextureBrowser );
+       g_TextureBrowser.m_gl_widget.connect( "button_release_event", G_CALLBACK( TextureBrowser_button_release ), &g_TextureBrowser );
+       g_TextureBrowser.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( TextureBrowser_motion ), &g_TextureBrowser );
+       g_TextureBrowser.m_gl_widget.connect( "scroll_event", G_CALLBACK( TextureBrowser_scroll ), &g_TextureBrowser );
+
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+       g_TextureBrowser.m_hframe.pack_start( g_TextureBrowser.m_gl_widget, TRUE, TRUE, 0 );
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+       g_TextureBrowser.m_frame.pack_start( g_TextureBrowser.m_gl_widget, TRUE, TRUE, 0 );
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
+
+       g_TextureBrowser.m_gl_widget.show();
+
+       isGLWidgetConstructed = true;
 }
 
 ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
@@ -2051,22 +2161,30 @@ ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
                g_TextureBrowser.m_texture_scroll.visible(g_TextureBrowser.m_showTextureScrollbar);
        }
        { // gl_widget
-               g_TextureBrowser.m_gl_widget = glwidget_new( FALSE );
-               g_object_ref( g_TextureBrowser.m_gl_widget._handle );
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+               g_TextureBrowser.m_vframe = ui::VBox( FALSE, 0 );
+               table.attach(g_TextureBrowser.m_vframe, {1, 2, 1, 2});
 
-               gtk_widget_set_events( g_TextureBrowser.m_gl_widget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK );
-               gtk_widget_set_can_focus( g_TextureBrowser.m_gl_widget, true );
+               g_TextureBrowser.m_vfiller = ui::VBox( FALSE, 0 );
+               g_TextureBrowser.m_vframe.pack_start( g_TextureBrowser.m_vfiller, FALSE, FALSE, 0 );
 
-               table.attach(g_TextureBrowser.m_gl_widget, {1, 2, 1, 2});
-               g_TextureBrowser.m_gl_widget.show();
+               g_TextureBrowser.m_hframe = ui::HBox( FALSE, 0 );
+               g_TextureBrowser.m_vframe.pack_start( g_TextureBrowser.m_hframe, TRUE, TRUE, 0 );
 
-               g_TextureBrowser.m_sizeHandler = g_TextureBrowser.m_gl_widget.connect( "size_allocate", G_CALLBACK( TextureBrowser_size_allocate ), &g_TextureBrowser );
-               g_TextureBrowser.m_exposeHandler = g_TextureBrowser.m_gl_widget.on_render( G_CALLBACK( TextureBrowser_expose ), &g_TextureBrowser );
+               g_TextureBrowser.m_hfiller = ui::HBox( FALSE, 0 );
+               g_TextureBrowser.m_hframe.pack_start( g_TextureBrowser.m_hfiller, FALSE, FALSE, 0 );
 
-               g_TextureBrowser.m_gl_widget.connect( "button_press_event", G_CALLBACK( TextureBrowser_button_press ), &g_TextureBrowser );
-               g_TextureBrowser.m_gl_widget.connect( "button_release_event", G_CALLBACK( TextureBrowser_button_release ), &g_TextureBrowser );
-               g_TextureBrowser.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( TextureBrowser_motion ), &g_TextureBrowser );
-               g_TextureBrowser.m_gl_widget.connect( "scroll_event", G_CALLBACK( TextureBrowser_scroll ), &g_TextureBrowser );
+               g_TextureBrowser.m_vframe.show();
+               g_TextureBrowser.m_vfiller.show();
+               g_TextureBrowser.m_hframe.show(),
+               g_TextureBrowser.m_hfiller.show();
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+               g_TextureBrowser.m_frame = ui::VBox( FALSE, 0 );
+               table.attach(g_TextureBrowser.m_frame, {1, 2, 1, 2});
+               g_TextureBrowser.m_frame.show();
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
+
+               TextureBrowser_constructGLWidget();
        }
 
        // tag stuff
@@ -2219,18 +2337,67 @@ ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
        // TODO do we need this?
        //gtk_container_set_focus_chain(GTK_CONTAINER(hbox_table), NULL);
 
+       isWindowConstructed = true;
+
        return table;
 }
 
+void TextureBrowser_destroyGLWidget(){
+       if ( isGLWidgetConstructed )
+       {
+               g_signal_handler_disconnect( G_OBJECT( g_TextureBrowser.m_gl_widget ), g_TextureBrowser.m_sizeHandler );
+               g_signal_handler_disconnect( G_OBJECT( g_TextureBrowser.m_gl_widget ), g_TextureBrowser.m_exposeHandler );
+
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+               g_TextureBrowser.m_hframe.remove( g_TextureBrowser.m_gl_widget );
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+               g_TextureBrowser.m_frame.remove( g_TextureBrowser.m_gl_widget );
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
+
+               g_TextureBrowser.m_gl_widget.unref();
+
+               isGLWidgetConstructed = false;
+       }
+}
+
 void TextureBrowser_destroyWindow(){
        GlobalShaderSystem().setActiveShadersChangedNotify( Callback<void()>() );
 
-       g_signal_handler_disconnect( G_OBJECT( g_TextureBrowser.m_gl_widget ), g_TextureBrowser.m_sizeHandler );
-       g_signal_handler_disconnect( G_OBJECT( g_TextureBrowser.m_gl_widget ), g_TextureBrowser.m_exposeHandler );
+       TextureBrowser_destroyGLWidget();
+}
 
-       g_TextureBrowser.m_gl_widget.unref();
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+/* workaround for gtkglext on gtk 2 issue: OpenGL texture viewport being drawn over the other pages */
+/* this is very ugly: force the resizing of the viewport to a single bottom line by forcing the
+ * resizing of the gl widget by expanding some empty boxes, so the widget area size is reduced
+ * while covered by another page, so the texture viewport is still rendered over the other page
+ * but does not annoy the user that much because it's just a line on the bottom that may even
+ * be printed over existing bottom frame or very close to it. */
+void TextureBrowser_showGLWidget(){
+       if ( isWindowConstructed && isGLWidgetConstructed )
+       {
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_vfiller, FALSE, FALSE, 0, ui::Packing::START );
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_hframe, TRUE, TRUE, 0, ui::Packing::START );
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_hfiller, FALSE, FALSE, 0, ui::Packing::START );
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_gl_widget, TRUE, TRUE, 0, ui::Packing::START );
+               GlobalTextureBrowser().m_gl_widget.show();
+       }
 }
 
+void TextureBrowser_hideGLWidget(){
+       if ( isWindowConstructed && isGLWidgetConstructed )
+       {
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_vfiller, TRUE, TRUE, 0, ui::Packing::START);
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_hframe, FALSE, FALSE, 0, ui::Packing::END );
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_hfiller, TRUE, TRUE, 0, ui::Packing::START);
+               GlobalTextureBrowser().m_vframe.set_child_packing( GlobalTextureBrowser().m_gl_widget, FALSE, FALSE, 0, ui::Packing::END );
+               GdkEventExpose event = {};
+               TextureBrowser_expose( GlobalTextureBrowser().m_gl_widget, &event, &GlobalTextureBrowser() );
+               GlobalTextureBrowser().m_gl_widget.hide();
+       }
+}
+#endif // WORKAROUND_MACOS_GTK2_GLWIDGET
+
 const Vector3& TextureBrowser_getBackgroundColour( TextureBrowser& textureBrowser ){
        return textureBrowser.color_textureback;
 }
@@ -2321,7 +2488,7 @@ void TextureBrowser_renameTag(){
        }
        else
        {
-               g_TextureBrowser.m_parent.alert( "Select a single tag for renaming." );
+               ui::alert( g_TextureBrowser.m_parent, "Select a single tag for renaming." );
        }
 }
 
@@ -2332,7 +2499,7 @@ void TextureBrowser_deleteTag(){
        gtk_tree_selection_selected_foreach( selection, GtkTreeSelectionForeachFunc( TextureBrowser_selectionHelper ), &selected );
 
        if ( g_slist_length( selected ) == 1 ) { // we only delete a single tag
-               auto result = g_TextureBrowser.m_parent.alert( "Are you sure you want to delete the selected tag?", "Delete Tag", ui::alert_type::YESNO, ui::alert_icon::Question );
+               auto result = ui::alert( g_TextureBrowser.m_parent, "Are you sure you want to delete the selected tag?", "Delete Tag", ui::alert_type::YESNO, ui::alert_icon::Question );
 
                if ( result == ui::alert_response::YES ) {
                        GtkTreeIter iterSelected;
@@ -2361,7 +2528,7 @@ void TextureBrowser_deleteTag(){
                }
        }
        else {
-               g_TextureBrowser.m_parent.alert( "Select a single tag for deletion." );
+               ui::alert( g_TextureBrowser.m_parent, "Select a single tag for deletion." );
        }
 }
 
@@ -2453,7 +2620,7 @@ void TextureBrowser_showAll(){
 }
 
 void TextureBrowser_showUntagged(){
-       auto result = g_TextureBrowser.m_parent.alert( "WARNING! This function might need a lot of memory and time. Are you sure you want to use it?", "Show Untagged", ui::alert_type::YESNO, ui::alert_icon::Warning );
+       auto result = ui::alert( g_TextureBrowser.m_parent, "WARNING! This function might need a lot of memory and time. Are you sure you want to use it?", "Show Untagged", ui::alert_type::YESNO, ui::alert_icon::Warning );
 
        if ( result == ui::alert_response::YES ) {
                g_TextureBrowser.m_found_shaders.clear();
@@ -2600,6 +2767,7 @@ void TextureBrowser_constructPage( PreferenceGroup& group ){
        PreferencesPage page( group.createPage( "Texture Browser", "Texture Browser Preferences" ) );
        TextureBrowser_constructPreferences( page );
 }
+
 void TextureBrowser_registerPreferencesPage(){
        PreferencesDialog_addSettingsPage( makeCallbackF(TextureBrowser_constructPage) );
 }
@@ -2652,8 +2820,15 @@ void TextureBrowser_Construct(){
 
        TextureBrowser_textureSelected = TextureClipboard_textureSelected;
 }
+
 void TextureBrowser_Destroy(){
        GlobalShaderSystem().detach( g_ShadersObserver );
 
        Textures_setModeChangedNotify( Callback<void()>() );
 }
+
+#if WORKAROUND_WINDOWS_GTK2_GLWIDGET
+ui::GLArea TextureBrowser_getGLWidget(){
+       return GlobalTextureBrowser().m_gl_widget;
+}
+#endif // WORKAROUND_WINDOWS_GTK2_GLWIDGET