]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/texwindow.cpp
Merge commit 'ff48e71434a414958e6e56628ccf04284d030784' into master-merge
[xonotic/netradiant.git] / radiant / texwindow.cpp
index 87094456636620ff9c038cbf2d29ab9f6163a25e..f1cc83f5bee9abd7a5429a6dc0c77e33eccdf0ff 100644 (file)
@@ -101,12 +101,7 @@ 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
        }
 }
 
@@ -174,6 +169,7 @@ typedef ReferenceCaller<TextureGroups, void(const char*), TextureGroups_addShade
 void TextureGroups_addDirectory( TextureGroups& groups, const char* directory ){
        groups.insert( directory );
 }
+
 typedef ReferenceCaller<TextureGroups, void(const char*), TextureGroups_addDirectory> TextureGroupsAddDirectoryCaller;
 
 class DeferredAdjustment
@@ -241,6 +237,10 @@ void TextureBrowser_showShadersExport( const Callback<void(bool)> & importer );
 
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShadersExport> TextureBrowserShowShadersExport;
 
+void TextureBrowser_showTexturesExport( const Callback<void(bool)> & importer );
+
+typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showTexturesExport> TextureBrowserShowTexturesExport;
+
 void TextureBrowser_showShaderlistOnly( const Callback<void(bool)> & importer );
 
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShaderlistOnly> TextureBrowserShowShaderlistOnlyExport;
@@ -271,6 +271,14 @@ 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::New};
@@ -294,6 +302,7 @@ std::set<CopiedString> m_found_shaders;
 ToggleItem m_hideunused_item;
 ToggleItem m_hidenotex_item;
 ToggleItem m_showshaders_item;
+ToggleItem m_showtextures_item;
 ToggleItem m_showshaderlistonly_item;
 ToggleItem m_fixedsize_item;
 ToggleItem m_filternotex_item;
@@ -314,6 +323,7 @@ std::size_t m_mouseWheelScrollIncrement;
 std::size_t m_textureScale;
 // make the texture increments match the grid changes
 bool m_showShaders;
+bool m_showTextures;
 bool m_showTextureScrollbar;
 StartupShaders m_startupShaders;
 // if true, the texture window will only display in-use shaders
@@ -324,42 +334,78 @@ bool m_searchedTags;
 bool m_tags;
 // The uniform size (in pixels) that textures are resized to when m_resizeTextures is true.
 int m_uniformTextureSize;
+int m_uniformTextureMinSize;
 
 // Return the display width of a texture in the texture browser
-int getTextureWidth( qtexture_t* tex ){
-       int width;
+/*void getTextureWH( qtexture_t* tex, int *width, int *height ){
        if ( !g_TextureBrowser_fixedSize ) {
                // Don't use uniform size
-               width = (int)( tex->width * ( (float)m_textureScale / 100 ) );
+               *width = (int)( tex->width * ( (float)m_textureScale / 100 ) );
+               *height = (int)( tex->height * ( (float)m_textureScale / 100 ) );
+
        }
-       else if
-       ( tex->width >= tex->height ) {
+       else if ( tex->width >= tex->height ) {
                // Texture is square, or wider than it is tall
-               width = m_uniformTextureSize;
+               if ( tex->width >= m_uniformTextureSize ){
+                       *width = m_uniformTextureSize;
+                       *height = (int)( m_uniformTextureSize * ( (float)tex->height / tex->width ) );
+               }
+               else if ( tex->width <= m_uniformTextureMinSize ){
+                       *width = m_uniformTextureMinSize;
+                       *height = (int)( m_uniformTextureMinSize * ( (float)tex->height / tex->width ) );
+               }
+               else {
+                       *width = tex->width;
+                       *height = tex->height;
+               }
        }
        else {
-               // Otherwise, preserve the texture's aspect ratio
-               width = (int)( m_uniformTextureSize * ( (float)tex->width / tex->height ) );
+               // Texture taller than it is wide
+               if ( tex->height >= m_uniformTextureSize ){
+                       *height = m_uniformTextureSize;
+                       *width = (int)( m_uniformTextureSize * ( (float)tex->width / tex->height ) );
+               }
+               else if ( tex->height <= m_uniformTextureMinSize ){
+                       *height = m_uniformTextureMinSize;
+                       *width = (int)( m_uniformTextureMinSize * ( (float)tex->width / tex->height ) );
+               }
+               else {
+                       *width = tex->width;
+                       *height = tex->height;
+               }
        }
-       return width;
 }
 
-// Return the display height of a texture in the texture browser
-int getTextureHeight( qtexture_t* tex ){
-       int height;
-       if ( !g_TextureBrowser_fixedSize ) {
+*/
+void getTextureWH( qtexture_t* tex, int &W, int &H ){
                // Don't use uniform size
-               height = (int)( tex->height * ( (float)m_textureScale / 100 ) );
-       }
-       else if ( tex->height >= tex->width ) {
-               // Texture is square, or taller than it is wide
-               height = m_uniformTextureSize;
-       }
-       else {
-               // Otherwise, preserve the texture's aspect ratio
-               height = (int)( m_uniformTextureSize * ( (float)tex->height / tex->width ) );
+               W = (int)( tex->width * ( (float)m_textureScale / 100 ) );
+               H = (int)( tex->height * ( (float)m_textureScale / 100 ) );
+
+       if ( g_TextureBrowser_fixedSize ){
+               if      ( W >= H ) {
+                       // Texture is square, or wider than it is tall
+                       if ( W >= m_uniformTextureSize ){
+                               H = m_uniformTextureSize * H / W;
+                               W = m_uniformTextureSize;
+                       }
+                       else if ( W <= m_uniformTextureMinSize ){
+                               H = m_uniformTextureMinSize * H / W;
+                               W = m_uniformTextureMinSize;
+                       }
+               }
+               else {
+                       // Texture taller than it is wide
+                       if ( H >= m_uniformTextureSize ){
+                               W = m_uniformTextureSize * W / H;
+                               H = m_uniformTextureSize;
+                       }
+                       else if ( H <= m_uniformTextureMinSize ){
+                               W = m_uniformTextureMinSize * W / H;
+                               H = m_uniformTextureMinSize;
+                       }
+               }
        }
-       return height;
 }
 
 TextureBrowser() :
@@ -367,6 +413,7 @@ TextureBrowser() :
        m_hideunused_item( TextureBrowserHideUnusedExport() ),
        m_hidenotex_item( TextureBrowserFilterFallbackExport() ),
        m_showshaders_item( TextureBrowserShowShadersExport() ),
+       m_showtextures_item( TextureBrowserShowTexturesExport() ),
        m_showshaderlistonly_item( TextureBrowserShowShaderlistOnlyExport() ),
        m_fixedsize_item( TextureBrowserFixedSizeExport() ),
        m_filternotex_item( TextureBrowserFilterMissingExport() ),
@@ -378,13 +425,15 @@ TextureBrowser() :
        m_mouseWheelScrollIncrement( 64 ),
        m_textureScale( 50 ),
        m_showShaders( true ),
+       m_showTextures( true ),
        m_showTextureScrollbar( true ),
        m_startupShaders( STARTUPSHADERS_NONE ),
        m_hideUnused( false ),
        m_rmbSelected( false ),
        m_searchedTags( false ),
        m_tags( false ),
-       m_uniformTextureSize( 96 ){
+       m_uniformTextureSize( 160 ),
+       m_uniformTextureMinSize( 48 ){
 }
 };
 
@@ -394,7 +443,7 @@ void ( *TextureBrowser_textureSelected )( const char* shader );
 void TextureBrowser_updateScroll( TextureBrowser& textureBrowser );
 
 
-const char* TextureBrowser_getComonShadersName(){
+const char* TextureBrowser_getCommonShadersName(){
        const char* value = g_pGameDescription->getKeyValue( "common_shaders_name" );
        if ( !string_empty( value ) ) {
                return value;
@@ -402,7 +451,7 @@ const char* TextureBrowser_getComonShadersName(){
        return "Common";
 }
 
-const char* TextureBrowser_getComonShadersDir(){
+const char* TextureBrowser_getCommonShadersDir(){
        const char* value = g_pGameDescription->getKeyValue( "common_shaders_dir" );
        if ( !string_empty( value ) ) {
                return value;
@@ -485,8 +534,8 @@ void Texture_StartPos( TextureLayout& layout ){
 void Texture_NextPos( TextureBrowser& textureBrowser, TextureLayout& layout, qtexture_t* current_texture, int *x, int *y ){
        qtexture_t* q = current_texture;
 
-       int nWidth = textureBrowser.getTextureWidth( q );
-       int nHeight = textureBrowser.getTextureHeight( q );
+       int nWidth, nHeight;
+       textureBrowser.getTextureWH( q, nWidth, nHeight );
        if ( layout.current_x + nWidth > textureBrowser.width - 8 && layout.current_row ) { // go to the next row unless the texture is the first on the row
                layout.current_x = 8;
                layout.current_y -= layout.current_row + TextureBrowser_fontHeight( textureBrowser ) + 4;
@@ -522,7 +571,7 @@ bool TextureSearch_IsShown( const char* name ){
 }
 
 // if texture_showinuse jump over non in-use textures
-bool Texture_IsShown( IShader* shader, bool show_shaders, bool hideUnused ){
+bool Texture_IsShown( IShader* shader, bool show_shaders, bool show_textures, bool hideUnused ){
        // filter missing shaders
        // ugly: filter on built-in fallback name after substitution
        if ( g_TextureBrowser_filterMissing ) {
@@ -561,6 +610,10 @@ bool Texture_IsShown( IShader* shader, bool show_shaders, bool hideUnused ){
                return false;
        }
 
+       if ( !show_textures && shader->IsDefault() ) {
+               return false;
+       }
+
        if ( hideUnused && !shader->IsInUse() ) {
                return false;
        }
@@ -574,7 +627,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;
                }
        }
@@ -601,13 +662,15 @@ void TextureBrowser_evaluateHeight( TextureBrowser& textureBrowser ){
                {
                        IShader* shader = QERApp_ActiveShaders_IteratorCurrent();
 
-                       if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_hideUnused ) ) {
+                       if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_showTextures, textureBrowser.m_hideUnused ) ) {
                                continue;
                        }
 
                        int x, y;
                        Texture_NextPos( textureBrowser, layout, shader->getTexture(), &x, &y );
-                       textureBrowser.m_nTotalHeight = std::max( textureBrowser.m_nTotalHeight, abs( layout.current_y ) + TextureBrowser_fontHeight( textureBrowser ) + textureBrowser.getTextureHeight( shader->getTexture() ) + 4 );
+                       int nWidth, nHeight;
+                       textureBrowser.getTextureWH( shader->getTexture(), nWidth, nHeight );
+                       textureBrowser.m_nTotalHeight = std::max( textureBrowser.m_nTotalHeight, abs( layout.current_y ) + TextureBrowser_fontHeight( textureBrowser ) + nHeight + 4 );
                }
        }
 }
@@ -662,7 +725,8 @@ Signal0 m_realiseCallbacks;
 public:
 void realise(){
        m_realiseCallbacks();
-       TextureBrowser_constructTreeStore();
+       /* texturebrowser tree update on vfs restart */
+//     TextureBrowser_constructTreeStore();
 }
 
 void unrealise(){
@@ -769,6 +833,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() );
 }
 };
 
@@ -811,6 +876,14 @@ void operator()( const char* name ) const {
 };
 
 void TextureDirectory_loadTexture( const char* directory, const char* texture ){
+       // Doom3-like dds/ prefix (used by DarkPlaces).
+       // When we list dds/textures/ folder,
+       // store the texture names without dds/ prefix.
+       if ( !strncmp( "dds/", directory, 4 ) )
+       {
+               directory = &directory[ 4 ];
+       }
+
        StringOutputStream name( 256 );
        name << directory << StringRange( texture, path_get_filename_base_end( texture ) );
 
@@ -845,10 +918,22 @@ 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 );
+               if ( archive != nullptr )
+               {
                LoadShaderVisitor visitor;
                archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "textures/" );
+
+                       // Doom3-like dds/ prefix (used by DarkPlaces).
+                       archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "dds/textures/" );
+               }
+               else if ( extension_equal_i( path_get_extension( directory ), "wad" ) )
+               {
+                       globalErrorStream() << "Failed to load " << directory << "\n";
+               }
        }
        else
        {
@@ -865,7 +950,19 @@ void TextureBrowser_ShowDirectory( TextureBrowser& textureBrowser, const char* d
                        StringOutputStream dirstring( 64 );
                        dirstring << "textures/" << directory;
 
-                       Radiant_getImageModules().foreachModule( LoadTexturesByTypeVisitor( dirstring.c_str() ) );
+                       {
+                               LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
+                               Radiant_getImageModules().foreachModule( visitor );
+                       }
+
+                       // Doom3-like dds/ prefix (used by DarkPlaces).
+                       dirstring.clear();
+                       dirstring << "dds/textures/" << directory;
+
+                       {
+                               LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
+                               Radiant_getImageModules().foreachModule( visitor );
+                       }
                }
        }
 
@@ -892,6 +989,15 @@ void TextureBrowser_ShowTagSearchResult( TextureBrowser& textureBrowser, const c
                        LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
                        Radiant_getImageModules().foreachModule( visitor );
                }
+
+               // Doom3-like dds/ prefix (used by DarkPlaces).
+               dirstring.clear();
+               dirstring << "dds/textures/" << directory;
+
+               {
+                       LoadTexturesByTypeVisitor visitor( dirstring.c_str() );
+                       Radiant_getImageModules().foreachModule( visitor );
+               }
        }
 
        // we'll display the newly loaded textures + all the ones already in use
@@ -913,6 +1019,12 @@ void TextureBrowser_showShadersExport( const Callback<void(bool)> & importer ){
 
 typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showShadersExport> TextureBrowserShowShadersExport;
 
+void TextureBrowser_showTexturesExport( const Callback<void(bool)> & importer ){
+       importer( GlobalTextureBrowser().m_showTextures );
+}
+
+typedef FreeCaller<void(const Callback<void(bool)> &), TextureBrowser_showTexturesExport> TextureBrowserShowTexturesExport;
+
 void TextureBrowser_showShaderlistOnly( const Callback<void(bool)> & importer ){
        importer( g_TextureBrowser_shaderlistOnly );
 }
@@ -960,7 +1072,7 @@ void TextureBrowser_SetHideUnused( TextureBrowser& textureBrowser, bool hideUnus
 
 void TextureBrowser_ShowStartupShaders( TextureBrowser& textureBrowser ){
        if ( textureBrowser.m_startupShaders == STARTUPSHADERS_COMMON ) {
-               TextureBrowser_ShowDirectory( textureBrowser, TextureBrowser_getComonShadersDir() );
+               TextureBrowser_ShowDirectory( textureBrowser, TextureBrowser_getCommonShadersDir() );
        }
 }
 
@@ -978,7 +1090,7 @@ void TextureBrowser_Focus( TextureBrowser& textureBrowser, const char* name ){
        {
                IShader* shader = QERApp_ActiveShaders_IteratorCurrent();
 
-               if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_hideUnused ) ) {
+               if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_showTextures, textureBrowser.m_hideUnused ) ) {
                        continue;
                }
 
@@ -1019,7 +1131,7 @@ IShader* Texture_At( TextureBrowser& textureBrowser, int mx, int my ){
        {
                IShader* shader = QERApp_ActiveShaders_IteratorCurrent();
 
-               if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_hideUnused ) ) {
+               if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_showTextures, textureBrowser.m_hideUnused ) ) {
                        continue;
                }
 
@@ -1030,8 +1142,8 @@ IShader* Texture_At( TextureBrowser& textureBrowser, int mx, int my ){
                        break;
                }
 
-               int nWidth = textureBrowser.getTextureWidth( q );
-               int nHeight = textureBrowser.getTextureHeight( q );
+               int nWidth, nHeight;
+               textureBrowser.getTextureWH( q, nWidth, nHeight );
                if ( mx > x && mx - x < nWidth
                         && my < y && y - my < nHeight + TextureBrowser_fontHeight( textureBrowser ) ) {
                        return shader;
@@ -1096,11 +1208,11 @@ void TextureBrowser_trackingDelta( int x, int y, unsigned int state, void* data
 }
 
 void TextureBrowser_Tracking_MouseDown( TextureBrowser& textureBrowser ){
-       textureBrowser.m_freezePointer.freeze_pointer( textureBrowser.m_parent, TextureBrowser_trackingDelta, &textureBrowser );
+       textureBrowser.m_freezePointer.freeze_pointer( textureBrowser.m_gl_widget, TextureBrowser_trackingDelta, &textureBrowser );
 }
 
 void TextureBrowser_Tracking_MouseUp( TextureBrowser& textureBrowser ){
-       textureBrowser.m_freezePointer.unfreeze_pointer( textureBrowser.m_parent );
+       textureBrowser.m_freezePointer.unfreeze_pointer( textureBrowser.m_gl_widget );
 }
 
 void TextureBrowser_Selection_MouseDown( TextureBrowser& textureBrowser, guint32 flags, int pointx, int pointy ){
@@ -1130,12 +1242,15 @@ 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();
 
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glDisable( GL_DEPTH_TEST );
+
+       //glDisable( GL_BLEND );
        if ( g_TextureBrowser_enableAlpha ) {
                glEnable( GL_BLEND );
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1143,6 +1258,7 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
        else {
                glDisable( GL_BLEND );
        }
+
        glOrtho( 0, textureBrowser.width, originy - textureBrowser.height, originy, -100, 100 );
        glEnable( GL_TEXTURE_2D );
 
@@ -1156,7 +1272,7 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
        {
                IShader* shader = QERApp_ActiveShaders_IteratorCurrent();
 
-               if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_hideUnused ) ) {
+               if ( !Texture_IsShown( shader, textureBrowser.m_showShaders, textureBrowser.m_showTextures, textureBrowser.m_hideUnused ) ) {
                        continue;
                }
 
@@ -1167,8 +1283,8 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
                        break;
                }
 
-               int nWidth = textureBrowser.getTextureWidth( q );
-               int nHeight = textureBrowser.getTextureHeight( q );
+               int nWidth, nHeight;
+               textureBrowser.getTextureWH( q, nWidth, nHeight );
 
                if ( y != last_y ) {
                        last_y = y;
@@ -1184,8 +1300,41 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
                        // shaders have a white border, simple textures don't
                        // if !texture_showinuse: (some textures displayed may not be in use)
                        // draw an additional square around with 0.5 1 0.5 color
+                       glLineWidth( 1 );
+                       // shader border:
+                       if ( !shader->IsDefault() ) {
+                       //real 1px white/black stipple
+                               glColor3f( 0, 0, 0 );
+                               glDisable( GL_TEXTURE_2D );
+
+                               float xf = (float)x;
+                               float yf = (float)( y - TextureBrowser_fontHeight( textureBrowser ) );
+                               glBegin( GL_LINE_LOOP );
+                               glVertex2f( xf - 1.5,yf + 1.5 );
+                               glVertex2f( xf - 1.5,yf - nHeight - 1.5 );
+                               glVertex2f( xf + 1.5 + nWidth,yf - nHeight - 1.5 );
+                               glVertex2f( xf + 1.5 + nWidth,yf + 1.5 );
+
+                               glEnd();
+
+                               glEnable( GL_LINE_STIPPLE );
+                               glLineStipple( 1, 0x0FFF );
+
+                               glBegin( GL_LINE_LOOP );
+                               glColor3f( 1, 1, 1 );
+
+                               glVertex2f( xf - 1.5,yf + 1.5 );
+                               glVertex2f( xf - 1.5,yf - nHeight - 1.5 );
+                               glVertex2f( xf + 1.5 + nWidth,yf - nHeight - 1.5 );
+                               glVertex2f( xf + 1.5 + nWidth,yf + 1.5 );
+
+                               glEnd();
+                               glDisable( GL_LINE_STIPPLE );
+                               glEnable( GL_TEXTURE_2D );
+
+                       }
                        if ( shader_equal( TextureBrowser_GetSelectedShader( textureBrowser ), shader->getName() ) ) {
-                               glLineWidth( 3 );
+                               glLineWidth( 2 );
                                if ( textureBrowser.m_rmbSelected ) {
                                        glColor3f( 0,0,1 );
                                }
@@ -1204,45 +1353,29 @@ void Texture_Draw( TextureBrowser& textureBrowser ){
                                glEnable( GL_TEXTURE_2D );
                                glLineWidth( 1 );
                        }
-                       else
-                       {
-                               glLineWidth( 1 );
-                               // shader border:
-                               if ( !shader->IsDefault() ) {
-                                       glColor3f( 1,1,1 );
-                                       glDisable( GL_TEXTURE_2D );
-
-                                       glBegin( GL_LINE_LOOP );
-                                       glVertex2i( x - 1,y + 1 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glVertex2i( x - 1,y - nHeight - 1 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glVertex2i( x + 1 + nWidth,y - nHeight - 1 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glVertex2i( x + 1 + nWidth,y + 1 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glEnd();
-                                       glEnable( GL_TEXTURE_2D );
-                               }
-
-                               // highlight in-use textures
-                               if ( !textureBrowser.m_hideUnused && shader->IsInUse() ) {
-                                       glColor3f( 0.5,1,0.5 );
-                                       glDisable( GL_TEXTURE_2D );
-                                       glBegin( GL_LINE_LOOP );
-                                       glVertex2i( x - 3,y + 3 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glVertex2i( x - 3,y - nHeight - 3 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glVertex2i( x + 3 + nWidth,y - nHeight - 3 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glVertex2i( x + 3 + nWidth,y + 3 - TextureBrowser_fontHeight( textureBrowser ) );
-                                       glEnd();
-                                       glEnable( GL_TEXTURE_2D );
-                               }
+                       // highlight in-use textures
+                       else if ( !textureBrowser.m_hideUnused && shader->IsInUse() ) {
+                       //1px with float
+                               float xf = (float)x;
+                               float yf = (float)( y - TextureBrowser_fontHeight( textureBrowser ) );
+                               glColor3f( 0.5,1,0.5 );
+                               glDisable( GL_TEXTURE_2D );
+                               glBegin( GL_LINE_LOOP );
+                               glVertex2f( xf - 3.5,yf + 3.5 );
+                               glVertex2f( xf - 3.5,yf - nHeight - 3.5 );
+                               glVertex2f( xf + 3.5 + nWidth,yf - nHeight - 3.5 );
+                               glVertex2f( xf + 3.5 + nWidth,yf + 3.5 );
+                               glEnd();
+                               glEnable( GL_TEXTURE_2D );
                        }
 
                        // draw checkerboard for transparent textures
-                       if ( g_TextureBrowser_enableAlpha )
+                       if ( g_TextureBrowser_enableAlpha )
                        {
                                glDisable( GL_TEXTURE_2D );
                                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;
@@ -1256,7 +1389,6 @@ 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 );
                        }
@@ -1311,15 +1443,32 @@ void TextureBrowser_queueDraw( TextureBrowser& textureBrowser ){
 void TextureBrowser_setScale( TextureBrowser& textureBrowser, std::size_t scale ){
        textureBrowser.m_textureScale = scale;
 
+       textureBrowser.m_heightChanged = true;
+       textureBrowser.m_originInvalid = true;
+       g_activeShadersChangedCallbacks();
+
        TextureBrowser_queueDraw( textureBrowser );
 }
 
 void TextureBrowser_setUniformSize( TextureBrowser& textureBrowser, std::size_t scale ){
        textureBrowser.m_uniformTextureSize = scale;
 
+       textureBrowser.m_heightChanged = true;
+       textureBrowser.m_originInvalid = true;
+       g_activeShadersChangedCallbacks();
+
        TextureBrowser_queueDraw( textureBrowser );
 }
 
+void TextureBrowser_setUniformMinSize( TextureBrowser& textureBrowser, std::size_t scale ){
+       textureBrowser.m_uniformTextureMinSize = scale;
+
+       textureBrowser.m_heightChanged = true;
+       textureBrowser.m_originInvalid = true;
+       g_activeShadersChangedCallbacks();
+
+       TextureBrowser_queueDraw( textureBrowser );
+}
 
 void TextureBrowser_MouseWheel( TextureBrowser& textureBrowser, bool bUp ){
        int originy = TextureBrowser_getOriginY( textureBrowser );
@@ -1403,7 +1552,7 @@ void BuildStoreAvailableTags(   ui::ListStore storeAvailable,
 gboolean TextureBrowser_button_press( ui::Widget widget, GdkEventButton* event, TextureBrowser* textureBrowser ){
        if ( event->type == GDK_BUTTON_PRESS ) {
                if ( event->button == 3 ) {
-                       if ( GlobalTextureBrowser().m_tags ) {
+                       if ( textureBrowser->m_tags ) {
                                textureBrowser->m_rmbSelected = true;
                                TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast<int>( event->x ), static_cast<int>( event->y ) );
 
@@ -1424,19 +1573,43 @@ gboolean TextureBrowser_button_press( ui::Widget widget, GdkEventButton* event,
                else if ( event->button == 1 ) {
                        TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast<int>( event->x ), static_cast<int>( event->y ) );
 
-                       if ( GlobalTextureBrowser().m_tags ) {
+                       if ( textureBrowser->m_tags ) {
                                textureBrowser->m_rmbSelected = false;
                                textureBrowser->m_tag_frame.hide();
                        }
                }
        }
+       else if ( event->type == GDK_2BUTTON_PRESS ) {
+               #define GARUX_DISABLE_2BUTTON
+               #ifndef GARUX_DISABLE_2BUTTON
+               const char* sh = textureBrowser->shader.c_str();
+               char* dir = strrchr( sh, '/' );
+               if( dir != NULL ){
+                       *(dir + 1) = '\0';
+                       dir = strchr( sh, '/' );
+                       if( dir != NULL ){
+                               dir++;
+                               if( *dir != '\0'){
+                                       ScopeDisableScreenUpdates disableScreenUpdates( dir, "Loading Textures" );
+                                       TextureBrowser_ShowDirectory( *textureBrowser, dir );
+                                       TextureBrowser_queueDraw( *textureBrowser );
+                               }
+                       }
+               }
+               #endif
+       }
+       else if ( event->type == GDK_3BUTTON_PRESS ) {
+               ScopeDisableScreenUpdates disableScreenUpdates( TextureBrowser_getCommonShadersDir(), "Loading Textures" );
+               TextureBrowser_ShowDirectory( *textureBrowser, TextureBrowser_getCommonShadersDir() );
+               TextureBrowser_queueDraw( *textureBrowser );
+       }
        return FALSE;
 }
 
 gboolean TextureBrowser_button_release( ui::Widget widget, GdkEventButton* event, TextureBrowser* textureBrowser ){
        if ( event->type == GDK_BUTTON_RELEASE ) {
                if ( event->button == 3 ) {
-                       if ( !GlobalTextureBrowser().m_tags ) {
+                       if ( !textureBrowser->m_tags ) {
                                TextureBrowser_Tracking_MouseUp( *textureBrowser );
                        }
                }
@@ -1495,7 +1668,7 @@ gboolean TextureBrowser_size_allocate( ui::Widget widget, GtkAllocation* allocat
        return FALSE;
 }
 
-gboolean TextureBrowser_expose( ui::Widget widget, GdkEventExpose* event, TextureBrowser* textureBrowser ){
+void TextureBrowser_redraw( TextureBrowser* textureBrowser ){
        if ( glwidget_make_current( textureBrowser->m_gl_widget ) != FALSE ) {
                GlobalOpenGL_debugAssertNoErrors();
                TextureBrowser_evaluateHeight( *textureBrowser );
@@ -1503,30 +1676,44 @@ gboolean TextureBrowser_expose( ui::Widget widget, GdkEventExpose* event, Textur
                GlobalOpenGL_debugAssertNoErrors();
                glwidget_swap_buffers( textureBrowser->m_gl_widget );
        }
-       return FALSE;
 }
 
-
-TextureBrowser g_TextureBrowser;
+gboolean TextureBrowser_expose( ui::Widget widget, GdkEventExpose* event, TextureBrowser* textureBrowser ){
+       TextureBrowser_redraw( textureBrowser );
+       return FALSE;
+}
 
 TextureBrowser& GlobalTextureBrowser(){
-       return g_TextureBrowser;
+       static TextureBrowser textureBrowser;
+       return textureBrowser;
 }
 
 bool TextureBrowser_hideUnused(){
-       return g_TextureBrowser.m_hideUnused;
+       return GlobalTextureBrowser().m_hideUnused;
 }
 
 void TextureBrowser_ToggleHideUnused(){
-       if ( g_TextureBrowser.m_hideUnused ) {
-               TextureBrowser_SetHideUnused( g_TextureBrowser, false );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       if ( textureBrowser.m_hideUnused ) {
+               TextureBrowser_SetHideUnused( textureBrowser, false );
        }
        else
        {
-               TextureBrowser_SetHideUnused( g_TextureBrowser, true );
+               TextureBrowser_SetHideUnused( textureBrowser, true );
        }
 }
 
+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;
@@ -1534,23 +1721,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;
                        }
                }
@@ -1587,17 +1778,18 @@ void TextureBrowser_constructTreeStore(){
        auto store = ui::TreeStore::from(gtk_tree_store_new( 1, G_TYPE_STRING ));
        TextureGroups_constructTreeModel( groups, store );
 
-       gtk_tree_view_set_model(g_TextureBrowser.m_treeViewTree, store);
+       gtk_tree_view_set_model(GlobalTextureBrowser().m_treeViewTree, store);
 
        g_object_unref( G_OBJECT( store ) );
 }
 
 void TextureBrowser_constructTreeStoreTags(){
        TextureGroups groups;
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
        auto store = ui::TreeStore::from(gtk_tree_store_new( 1, G_TYPE_STRING ));
-    auto model = g_TextureBrowser.m_all_tags_list;
+       auto model = GlobalTextureBrowser().m_all_tags_list;
 
-       gtk_tree_view_set_model(g_TextureBrowser.m_treeViewTags, model );
+       gtk_tree_view_set_model(GlobalTextureBrowser().m_treeViewTags, model );
 
        g_object_unref( G_OBJECT( store ) );
 }
@@ -1615,7 +1807,7 @@ void TreeView_onRowActivated( ui::TreeView treeview, ui::TreePath path, ui::Tree
                strcpy( dirName, buffer );
                g_free( buffer );
 
-               g_TextureBrowser.m_searchedTags = false;
+               GlobalTextureBrowser().m_searchedTags = false;
 
                if ( !TextureBrowser_showWads() ) {
                        strcat( dirName, "/" );
@@ -1624,17 +1816,20 @@ void TreeView_onRowActivated( ui::TreeView treeview, ui::TreePath path, ui::Tree
                ScopeDisableScreenUpdates disableScreenUpdates( dirName, "Loading Textures" );
                TextureBrowser_ShowDirectory( GlobalTextureBrowser(), dirName );
                TextureBrowser_queueDraw( GlobalTextureBrowser() );
+               //deactivate, so SPACE and RETURN wont be broken for 2d
+               gtk_window_set_focus( GTK_WINDOW( gtk_widget_get_toplevel( GTK_WIDGET( treeview ) ) ), NULL );
        }
 }
 
 void TextureBrowser_createTreeViewTree(){
-       gtk_tree_view_set_enable_search(g_TextureBrowser.m_treeViewTree, FALSE );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       gtk_tree_view_set_enable_search(textureBrowser.m_treeViewTree, FALSE );
 
-       gtk_tree_view_set_headers_visible(g_TextureBrowser.m_treeViewTree, FALSE );
-       g_TextureBrowser.m_treeViewTree.connect( "row-activated", (GCallback) TreeView_onRowActivated, NULL );
+       gtk_tree_view_set_headers_visible(textureBrowser.m_treeViewTree, FALSE );
+       textureBrowser.m_treeViewTree.connect( "row-activated", (GCallback) TreeView_onRowActivated, NULL );
 
        auto renderer = ui::CellRendererText(ui::New);
-       gtk_tree_view_insert_column_with_attributes(g_TextureBrowser.m_treeViewTree, -1, "", renderer, "text", 0, NULL );
+       gtk_tree_view_insert_column_with_attributes(textureBrowser.m_treeViewTree, -1, "", renderer, "text", 0, NULL );
 
        TextureBrowser_constructTreeStore();
 }
@@ -1685,20 +1880,22 @@ gboolean TreeViewTags_onButtonPressed( ui::TreeView treeview, GdkEventButton *ev
 }
 
 void TextureBrowser_createTreeViewTags(){
-       g_TextureBrowser.m_treeViewTags = ui::TreeView(ui::New);
-       gtk_tree_view_set_enable_search(g_TextureBrowser.m_treeViewTags, FALSE );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       textureBrowser.m_treeViewTags = ui::TreeView(ui::New);
+       gtk_tree_view_set_enable_search(textureBrowser.m_treeViewTags, FALSE );
 
-       g_TextureBrowser.m_treeViewTags.connect( "button-press-event", (GCallback)TreeViewTags_onButtonPressed, NULL );
+       textureBrowser.m_treeViewTags.connect( "button-press-event", (GCallback)TreeViewTags_onButtonPressed, NULL );
 
-       gtk_tree_view_set_headers_visible(g_TextureBrowser.m_treeViewTags, FALSE );
+       gtk_tree_view_set_headers_visible(textureBrowser.m_treeViewTags, FALSE );
 
        auto renderer = ui::CellRendererText(ui::New);
-       gtk_tree_view_insert_column_with_attributes(g_TextureBrowser.m_treeViewTags, -1, "", renderer, "text", 0, NULL );
+       gtk_tree_view_insert_column_with_attributes(textureBrowser.m_treeViewTags, -1, "", renderer, "text", 0, NULL );
 
        TextureBrowser_constructTreeStoreTags();
 }
 
 ui::MenuItem TextureBrowser_constructViewMenu( ui::Menu menu ){
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
        ui::MenuItem textures_menu_item = ui::MenuItem(new_sub_menu_item_with_mnemonic( "_View" ));
 
        if ( g_Layout_enableDetachableMenus.m_value ) {
@@ -1715,23 +1912,24 @@ ui::MenuItem TextureBrowser_constructViewMenu( ui::Menu menu ){
 
        menu_separator( 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" ) ) ) {
-               g_TextureBrowser.m_showShaders = true;
+       if ( g_pGameDescription->mGameType == "doom3" || TextureBrowser_showWads() ) {
+               textureBrowser.m_showShaders = true;
        }
        else
        {
                create_check_menu_item_with_mnemonic( menu, "Show shaders", "ToggleShowShaders" );
+               create_check_menu_item_with_mnemonic( menu, "Show textures", "ToggleShowTextures" );
+               menu_separator( menu );
        }
 
-       if ( g_pGameDescription->mGameType != "doom3" && string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
-               create_check_menu_item_with_mnemonic( menu, "Shaders Only", "ToggleShowShaderlistOnly" );
-       }
-       if ( g_TextureBrowser.m_tags ) {
+       if ( textureBrowser.m_tags ) {
                create_menu_item_with_mnemonic( menu, "Show Untagged", "ShowUntagged" );
        }
+       if ( g_pGameDescription->mGameType != "doom3" && string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
+               create_check_menu_item_with_mnemonic( menu, "ShaderList Only", "ToggleShowShaderlistOnly" );
+       }
 
        menu_separator( menu );
        create_check_menu_item_with_mnemonic( menu, "Fixed Size", "FixedSize" );
@@ -1739,14 +1937,18 @@ ui::MenuItem TextureBrowser_constructViewMenu( ui::Menu menu ){
 
        if ( string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
                menu_separator( menu );
-               g_TextureBrowser.m_shader_info_item = ui::Widget(create_menu_item_with_mnemonic( menu, "Shader Info", "ShaderInfo"  ));
-               gtk_widget_set_sensitive( g_TextureBrowser.m_shader_info_item, FALSE );
+               textureBrowser.m_shader_info_item = ui::Widget(create_menu_item_with_mnemonic( menu, "Shader Info", "ShaderInfo"  ));
+               gtk_widget_set_sensitive( textureBrowser.m_shader_info_item, FALSE );
        }
 
 
        return textures_menu_item;
 }
 
+void Popup_View_Menu( GtkWidget *widget, GtkMenu *menu ){
+       gtk_menu_popup( menu, NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time() );
+}
+
 ui::MenuItem TextureBrowser_constructToolsMenu( ui::Menu menu ){
        ui::MenuItem textures_menu_item = ui::MenuItem(new_sub_menu_item_with_mnemonic( "_Tools" ));
 
@@ -1777,7 +1979,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 );
@@ -1790,8 +1992,9 @@ void TextureBrowser_assignTags(){
        GSList* selected = NULL;
        GSList* node;
        gchar* tag_assigned;
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
-    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_available_tree );
+       auto selection = gtk_tree_view_get_selection(textureBrowser.m_available_tree );
 
        gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
 
@@ -1803,27 +2006,27 @@ void TextureBrowser_assignTags(){
                        if ( path ) {
                                GtkTreeIter iter;
 
-                               if ( gtk_tree_model_get_iter(g_TextureBrowser.m_available_store, &iter, path ) ) {
-                                       gtk_tree_model_get(g_TextureBrowser.m_available_store, &iter, TAG_COLUMN, &tag_assigned, -1 );
-                                       if ( !TagBuilder.CheckShaderTag( g_TextureBrowser.shader.c_str() ) ) {
+                               if ( gtk_tree_model_get_iter(textureBrowser.m_available_store, &iter, path ) ) {
+                                       gtk_tree_model_get(textureBrowser.m_available_store, &iter, TAG_COLUMN, &tag_assigned, -1 );
+                                       if ( !TagBuilder.CheckShaderTag( textureBrowser.shader.c_str() ) ) {
                                                // create a custom shader/texture entry
-                                               IShader* ishader = QERApp_Shader_ForName( g_TextureBrowser.shader.c_str() );
+                                               IShader* ishader = QERApp_Shader_ForName( textureBrowser.shader.c_str() );
                                                CopiedString filename = ishader->getShaderFileName();
 
                                                if ( filename.empty() ) {
                                                        // it's a texture
-                                                       TagBuilder.AddShaderNode( g_TextureBrowser.shader.c_str(), CUSTOM, TEXTURE );
+                                                       TagBuilder.AddShaderNode( textureBrowser.shader.c_str(), CUSTOM, TEXTURE );
                                                }
                                                else {
                                                        // it's a shader
-                                                       TagBuilder.AddShaderNode( g_TextureBrowser.shader.c_str(), CUSTOM, SHADER );
+                                                       TagBuilder.AddShaderNode( textureBrowser.shader.c_str(), CUSTOM, SHADER );
                                                }
                                                ishader->DecRef();
                                        }
-                                       TagBuilder.AddShaderTag( g_TextureBrowser.shader.c_str(), (char*)tag_assigned, TAG );
+                                       TagBuilder.AddShaderTag( textureBrowser.shader.c_str(), (char*)tag_assigned, TAG );
 
-                                       gtk_list_store_remove( g_TextureBrowser.m_available_store, &iter );
-                                       g_TextureBrowser.m_assigned_store.append(TAG_COLUMN, tag_assigned);
+                                       gtk_list_store_remove( textureBrowser.m_available_store, &iter );
+                                       textureBrowser.m_assigned_store.append(TAG_COLUMN, tag_assigned);
                                }
                        }
                }
@@ -1840,8 +2043,9 @@ void TextureBrowser_removeTags(){
        GSList* selected = NULL;
        GSList* node;
        gchar* tag;
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
-    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_assigned_tree );
+       auto selection = gtk_tree_view_get_selection(textureBrowser.m_assigned_tree );
 
        gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
 
@@ -1853,10 +2057,10 @@ void TextureBrowser_removeTags(){
                        if ( path ) {
                                GtkTreeIter iter;
 
-                               if ( gtk_tree_model_get_iter(g_TextureBrowser.m_assigned_store, &iter, path ) ) {
-                                       gtk_tree_model_get(g_TextureBrowser.m_assigned_store, &iter, TAG_COLUMN, &tag, -1 );
-                                       TagBuilder.DeleteShaderTag( g_TextureBrowser.shader.c_str(), tag );
-                                       gtk_list_store_remove( g_TextureBrowser.m_assigned_store, &iter );
+                               if ( gtk_tree_model_get_iter(textureBrowser.m_assigned_store, &iter, path ) ) {
+                                       gtk_tree_model_get(textureBrowser.m_assigned_store, &iter, TAG_COLUMN, &tag, -1 );
+                                       TagBuilder.DeleteShaderTag( textureBrowser.shader.c_str(), tag );
+                                       gtk_list_store_remove( textureBrowser.m_assigned_store, &iter );
                                }
                        }
                }
@@ -1864,7 +2068,7 @@ void TextureBrowser_removeTags(){
                g_slist_foreach( selected, (GFunc)gtk_tree_row_reference_free, NULL );
 
                // Update the "available tags list"
-               BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
+               BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
 
                // Save changes
                TagBuilder.SaveXmlDoc();
@@ -1873,13 +2077,14 @@ void TextureBrowser_removeTags(){
 }
 
 void TextureBrowser_buildTagList(){
-       g_TextureBrowser.m_all_tags_list.clear();
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       textureBrowser.m_all_tags_list.clear();
 
        std::set<CopiedString>::iterator iter;
 
-       for ( iter = g_TextureBrowser.m_all_tags.begin(); iter != g_TextureBrowser.m_all_tags.end(); ++iter )
+       for ( iter = textureBrowser.m_all_tags.begin(); iter != textureBrowser.m_all_tags.end(); ++iter )
        {
-               g_TextureBrowser.m_all_tags_list.append(TAG_COLUMN, (*iter).c_str());
+               textureBrowser.m_all_tags_list.append(TAG_COLUMN, (*iter).c_str());
        }
 }
 
@@ -1889,8 +2094,9 @@ void TextureBrowser_searchTags(){
        gchar* tag;
        char buffer[256];
        char tags_searched[256];
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
-    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
+       auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
 
        gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
 
@@ -1905,8 +2111,8 @@ void TextureBrowser_searchTags(){
                        if ( path ) {
                                GtkTreeIter iter;
 
-                               if ( gtk_tree_model_get_iter(g_TextureBrowser.m_all_tags_list, &iter, path ) ) {
-                                       gtk_tree_model_get(g_TextureBrowser.m_all_tags_list, &iter, TAG_COLUMN, &tag, -1 );
+                               if ( gtk_tree_model_get_iter(textureBrowser.m_all_tags_list, &iter, path ) ) {
+                                       gtk_tree_model_get(textureBrowser.m_all_tags_list, &iter, TAG_COLUMN, &tag, -1 );
 
                                        strcat( buffer, tag );
                                        strcat( tags_searched, tag );
@@ -1922,18 +2128,18 @@ void TextureBrowser_searchTags(){
 
                g_slist_foreach( selected, (GFunc)gtk_tree_row_reference_free, NULL );
 
-               g_TextureBrowser.m_found_shaders.clear(); // delete old list
-               TagBuilder.TagSearch( buffer, g_TextureBrowser.m_found_shaders );
+               textureBrowser.m_found_shaders.clear(); // delete old list
+               TagBuilder.TagSearch( buffer, textureBrowser.m_found_shaders );
 
-               if ( !g_TextureBrowser.m_found_shaders.empty() ) { // found something
-                       size_t shaders_found = g_TextureBrowser.m_found_shaders.size();
+               if ( !textureBrowser.m_found_shaders.empty() ) { // found something
+                       size_t shaders_found = textureBrowser.m_found_shaders.size();
 
                        globalOutputStream() << "Found " << (unsigned int)shaders_found << " textures and shaders with " << tags_searched << "\n";
                        ScopeDisableScreenUpdates disableScreenUpdates( "Searching...", "Loading Textures" );
 
                        std::set<CopiedString>::iterator iter;
 
-                       for ( iter = g_TextureBrowser.m_found_shaders.begin(); iter != g_TextureBrowser.m_found_shaders.end(); iter++ )
+                       for ( iter = textureBrowser.m_found_shaders.begin(); iter != textureBrowser.m_found_shaders.end(); iter++ )
                        {
                                std::string path = ( *iter ).c_str();
                                size_t pos = path.find_last_of( "/", path.size() );
@@ -1942,62 +2148,66 @@ void TextureBrowser_searchTags(){
                                TextureDirectory_loadTexture( path.c_str(), name.c_str() );
                        }
                }
-               g_TextureBrowser.m_searchedTags = true;
+               textureBrowser.m_searchedTags = true;
                g_TextureBrowser_currentDirectory = tags_searched;
 
-               g_TextureBrowser.m_nTotalHeight = 0;
-               TextureBrowser_setOriginY( g_TextureBrowser, 0 );
-               TextureBrowser_heightChanged( g_TextureBrowser );
+               textureBrowser.m_nTotalHeight = 0;
+               TextureBrowser_setOriginY( textureBrowser, 0 );
+               TextureBrowser_heightChanged( textureBrowser );
                TextureBrowser_updateTitle();
        }
        g_slist_free( selected );
 }
 
 void TextureBrowser_toggleSearchButton(){
-       gint page = gtk_notebook_get_current_page( GTK_NOTEBOOK( g_TextureBrowser.m_tag_notebook ) );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       gint page = gtk_notebook_get_current_page( GTK_NOTEBOOK( textureBrowser.m_tag_notebook ) );
 
        if ( page == 0 ) { // tag page
-               gtk_widget_show_all( g_TextureBrowser.m_search_button );
+               gtk_widget_show_all( textureBrowser.m_search_button );
        }
        else {
-               g_TextureBrowser.m_search_button.hide();
+               textureBrowser.m_search_button.hide();
        }
 }
 
 void TextureBrowser_constructTagNotebook(){
-       g_TextureBrowser.m_tag_notebook = ui::Widget::from(gtk_notebook_new());
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       textureBrowser.m_tag_notebook = ui::Widget::from(gtk_notebook_new());
        ui::Widget labelTags = ui::Label( "Tags" );
        ui::Widget labelTextures = ui::Label( "Textures" );
 
-       gtk_notebook_append_page( GTK_NOTEBOOK( g_TextureBrowser.m_tag_notebook ), g_TextureBrowser.m_scr_win_tree, labelTextures );
-       gtk_notebook_append_page( GTK_NOTEBOOK( g_TextureBrowser.m_tag_notebook ), g_TextureBrowser.m_scr_win_tags, labelTags );
+       gtk_notebook_append_page( GTK_NOTEBOOK( textureBrowser.m_tag_notebook ), textureBrowser.m_scr_win_tree, labelTextures );
+       gtk_notebook_append_page( GTK_NOTEBOOK( textureBrowser.m_tag_notebook ), textureBrowser.m_scr_win_tags, labelTags );
 
-       g_TextureBrowser.m_tag_notebook.connect( "switch-page", G_CALLBACK( TextureBrowser_toggleSearchButton ), NULL );
+       textureBrowser.m_tag_notebook.connect( "switch-page", G_CALLBACK( TextureBrowser_toggleSearchButton ), NULL );
 
-       gtk_widget_show_all( g_TextureBrowser.m_tag_notebook );
+       gtk_widget_show_all( textureBrowser.m_tag_notebook );
 }
 
 void TextureBrowser_constructSearchButton(){
        auto image = ui::Widget::from(gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_SMALL_TOOLBAR ));
-       g_TextureBrowser.m_search_button = ui::Button(ui::New);
-       g_TextureBrowser.m_search_button.connect( "clicked", G_CALLBACK( TextureBrowser_searchTags ), NULL );
-       gtk_widget_set_tooltip_text(g_TextureBrowser.m_search_button, "Search with selected tags");
-       g_TextureBrowser.m_search_button.add(image);
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       textureBrowser.m_search_button = ui::Button(ui::New);
+       textureBrowser.m_search_button.connect( "clicked", G_CALLBACK( TextureBrowser_searchTags ), NULL );
+       gtk_widget_set_tooltip_text(textureBrowser.m_search_button, "Search with selected tags");
+       textureBrowser.m_search_button.add(image);
 }
 
 void TextureBrowser_checkTagFile(){
        const char SHADERTAG_FILE[] = "shadertags.xml";
        CopiedString default_filename, rc_filename;
        StringOutputStream stream( 256 );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
        stream << LocalRcPath_get();
        stream << SHADERTAG_FILE;
        rc_filename = stream.c_str();
 
        if ( file_exists( rc_filename.c_str() ) ) {
-               g_TextureBrowser.m_tags = TagBuilder.OpenXmlDoc( rc_filename.c_str() );
+               textureBrowser.m_tags = TagBuilder.OpenXmlDoc( rc_filename.c_str() );
 
-               if ( g_TextureBrowser.m_tags ) {
+               if ( textureBrowser.m_tags ) {
                        globalOutputStream() << "Loading tag file " << rc_filename.c_str() << ".\n";
                }
        }
@@ -2010,9 +2220,9 @@ void TextureBrowser_checkTagFile(){
                default_filename = stream.c_str();
 
                if ( file_exists( default_filename.c_str() ) ) {
-                       g_TextureBrowser.m_tags = TagBuilder.OpenXmlDoc( default_filename.c_str(), rc_filename.c_str() );
+                       textureBrowser.m_tags = TagBuilder.OpenXmlDoc( default_filename.c_str(), rc_filename.c_str() );
 
-                       if ( g_TextureBrowser.m_tags ) {
+                       if ( textureBrowser.m_tags ) {
                                globalOutputStream() << "Loading default tag file " << default_filename.c_str() << ".\n";
                        }
                }
@@ -2028,169 +2238,240 @@ void TextureBrowser_SetNotex(){
        IShader* shadernotex = QERApp_Shader_ForName( DEFAULT_SHADERNOTEX_NAME );
 
        g_notex = notex->getTexture()->name;
+
        g_shadernotex = shadernotex->getTexture()->name;
 
        notex->DecRef();
        shadernotex->DecRef();
 }
 
+static bool isGLWidgetConstructed = false;
+static bool isWindowConstructed = false;
+
+void TextureBrowser_constructGLWidget(){
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       textureBrowser.m_gl_widget = glwidget_new( FALSE );
+       g_object_ref( textureBrowser.m_gl_widget._handle );
+
+       gtk_widget_set_events( 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( textureBrowser.m_gl_widget, true );
+
+       textureBrowser.m_sizeHandler = textureBrowser.m_gl_widget.connect( "size_allocate", G_CALLBACK( TextureBrowser_size_allocate ), &textureBrowser );
+       textureBrowser.m_exposeHandler = textureBrowser.m_gl_widget.on_render( G_CALLBACK( TextureBrowser_expose ), &textureBrowser );
+
+       textureBrowser.m_gl_widget.connect( "button_press_event", G_CALLBACK( TextureBrowser_button_press ), &textureBrowser );
+       textureBrowser.m_gl_widget.connect( "button_release_event", G_CALLBACK( TextureBrowser_button_release ), &textureBrowser );
+       textureBrowser.m_gl_widget.connect( "motion_notify_event", G_CALLBACK( TextureBrowser_motion ), &textureBrowser );
+       textureBrowser.m_gl_widget.connect( "scroll_event", G_CALLBACK( TextureBrowser_scroll ), &textureBrowser );
+
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+       textureBrowser.m_hframe.pack_start( textureBrowser.m_gl_widget, TRUE, TRUE, 0 );
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+       textureBrowser.m_frame.pack_start( textureBrowser.m_gl_widget, TRUE, TRUE, 0 );
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
+
+       textureBrowser.m_gl_widget.show();
+
+       isGLWidgetConstructed = true;
+}
+
 ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
        // The gl_widget and the tag assignment frame should be packed into a GtkVPaned with the slider
        // position stored in local.pref. gtk_paned_get_position() and gtk_paned_set_position() don't
        // seem to work in gtk 2.4 and the arrow buttons don't handle GTK_FILL, so here's another thing
        // for the "once-the-gtk-libs-are-updated-TODO-list" :x
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
        TextureBrowser_checkTagFile();
        TextureBrowser_SetNotex();
 
-       GlobalShaderSystem().setActiveShadersChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_activeShadersChanged>( g_TextureBrowser ) );
+       GlobalShaderSystem().setActiveShadersChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_activeShadersChanged>( textureBrowser ) );
 
-       g_TextureBrowser.m_parent = toplevel;
+       textureBrowser.m_parent = toplevel;
 
        auto table = ui::Table(3, 3, FALSE);
        auto vbox = ui::VBox(FALSE, 0);
        table.attach(vbox, {0, 1, 1, 3}, {GTK_FILL, GTK_FILL});
        vbox.show();
 
-       ui::Widget menu_bar{ui::null};
+       // ui::Widget menu_bar{ui::null};
+       auto toolbar = ui::Toolbar::from( gtk_toolbar_new() );
 
        { // menu bar
-               menu_bar = ui::Widget::from(gtk_menu_bar_new());
+               // menu_bar = ui::Widget::from(gtk_menu_bar_new());
                auto menu_view = ui::Menu(ui::New);
-               auto view_item = TextureBrowser_constructViewMenu( menu_view );
-               gtk_menu_item_set_submenu( GTK_MENU_ITEM( view_item ), menu_view );
-               gtk_menu_shell_append( GTK_MENU_SHELL( menu_bar ), view_item );
+               // auto view_item = TextureBrowser_constructViewMenu( menu_view );
+               TextureBrowser_constructViewMenu( menu_view );
+               gtk_menu_set_title( menu_view, "View" );
+               // gtk_menu_item_set_submenu( GTK_MENU_ITEM( view_item ), menu_view );
+               // gtk_menu_shell_append( GTK_MENU_SHELL( menu_bar ), view_item );
 
+               //gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( toolbar ), 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0 );
+               gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( toolbar ), FALSE, FALSE, 0 );
+
+               //view menu button
+               {
+                       auto button = toolbar_append_button( toolbar, "View", "texbro_view.png" );
+                       button.dimensions( 22, 22 );
+                       button.connect( "clicked", G_CALLBACK( Popup_View_Menu ), menu_view );
+
+                       //to show detached menu over floating tex bro
+                       gtk_menu_attach_to_widget( GTK_MENU( menu_view ), GTK_WIDGET( button ), NULL );
+               }
+               {
+                       auto button = toolbar_append_button( toolbar, "Find / Replace...", "texbro_gtk-find-and-replace.png", "FindReplaceTextures" );
+                       button.dimensions( 22, 22 );
+               }
+               {
+                       auto button = toolbar_append_button( toolbar, "Flush & Reload Shaders", "texbro_refresh.png", "RefreshShaders" );
+                       button.dimensions( 22, 22 );
+               }
+               toolbar.show();
+
+/*
                auto menu_tools = ui::Menu(ui::New);
                auto tools_item = TextureBrowser_constructToolsMenu( menu_tools );
                gtk_menu_item_set_submenu( GTK_MENU_ITEM( tools_item ), menu_tools );
                gtk_menu_shell_append( GTK_MENU_SHELL( menu_bar ), tools_item );
-
-               table.attach(menu_bar, {0, 3, 0, 1}, {GTK_FILL, GTK_SHRINK});
-               menu_bar.show();
+*/
+               // table.attach(menu_bar, {0, 3, 0, 1}, {GTK_FILL, GTK_SHRINK});
+               // menu_bar.show();
        }
        { // Texture TreeView
-               g_TextureBrowser.m_scr_win_tree = ui::ScrolledWindow(ui::New);
-               gtk_container_set_border_width( GTK_CONTAINER( g_TextureBrowser.m_scr_win_tree ), 0 );
+               textureBrowser.m_scr_win_tree = ui::ScrolledWindow(ui::New);
+               gtk_container_set_border_width( GTK_CONTAINER( textureBrowser.m_scr_win_tree ), 0 );
 
                // vertical only scrolling for treeview
-               gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tree ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
+               gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tree ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
 
-               g_TextureBrowser.m_scr_win_tree.show();
+               textureBrowser.m_scr_win_tree.show();
 
                TextureBrowser_createTreeViewTree();
 
-               gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tree ), g_TextureBrowser.m_treeViewTree  );
-               g_TextureBrowser.m_treeViewTree.show();
+               gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tree ), textureBrowser.m_treeViewTree  );
+               textureBrowser.m_treeViewTree.show();
        }
        { // gl_widget scrollbar
                auto w = ui::Widget::from(gtk_vscrollbar_new( ui::Adjustment( 0,0,0,1,1,0 ) ));
                table.attach(w, {2, 3, 1, 2}, {GTK_SHRINK, GTK_FILL});
                w.show();
-               g_TextureBrowser.m_texture_scroll = w;
+               textureBrowser.m_texture_scroll = w;
 
-               auto vadjustment = ui::Adjustment::from(gtk_range_get_adjustment( GTK_RANGE( g_TextureBrowser.m_texture_scroll ) ));
-               vadjustment.connect( "value_changed", G_CALLBACK( TextureBrowser_verticalScroll ), &g_TextureBrowser );
+               auto vadjustment = ui::Adjustment::from(gtk_range_get_adjustment( GTK_RANGE( textureBrowser.m_texture_scroll ) ));
+               vadjustment.connect( "value_changed", G_CALLBACK( TextureBrowser_verticalScroll ), &textureBrowser );
 
-               g_TextureBrowser.m_texture_scroll.visible(g_TextureBrowser.m_showTextureScrollbar);
+               textureBrowser.m_texture_scroll.visible(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
+               textureBrowser.m_vframe = ui::VBox( FALSE, 0 );
+               table.attach(textureBrowser.m_vframe, {1, 2, 1, 2});
+
+               textureBrowser.m_vfiller = ui::VBox( FALSE, 0 );
+               textureBrowser.m_vframe.pack_start( textureBrowser.m_vfiller, FALSE, FALSE, 0 );
 
-               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 );
+               textureBrowser.m_hframe = ui::HBox( FALSE, 0 );
+               textureBrowser.m_vframe.pack_start( textureBrowser.m_hframe, TRUE, TRUE, 0 );
 
-               table.attach(g_TextureBrowser.m_gl_widget, {1, 2, 1, 2});
-               g_TextureBrowser.m_gl_widget.show();
+               textureBrowser.m_hfiller = ui::HBox( FALSE, 0 );
+               textureBrowser.m_hframe.pack_start( textureBrowser.m_hfiller, FALSE, FALSE, 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 );
+               textureBrowser.m_vframe.show();
+               textureBrowser.m_vfiller.show();
+               textureBrowser.m_hframe.show(),
+               textureBrowser.m_hfiller.show();
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+               textureBrowser.m_frame = ui::VBox( FALSE, 0 );
+               table.attach(textureBrowser.m_frame, {1, 2, 1, 2});
+               textureBrowser.m_frame.show();
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
 
-               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 );
+               TextureBrowser_constructGLWidget();
        }
 
        // tag stuff
-       if ( g_TextureBrowser.m_tags ) {
+       if ( textureBrowser.m_tags ) {
                { // fill tag GtkListStore
-                       g_TextureBrowser.m_all_tags_list = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
-            auto sortable = GTK_TREE_SORTABLE( g_TextureBrowser.m_all_tags_list );
+                       textureBrowser.m_all_tags_list = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
+            auto sortable = GTK_TREE_SORTABLE( textureBrowser.m_all_tags_list );
                        gtk_tree_sortable_set_sort_column_id( sortable, TAG_COLUMN, GTK_SORT_ASCENDING );
 
-                       TagBuilder.GetAllTags( g_TextureBrowser.m_all_tags );
+                       TagBuilder.GetAllTags( textureBrowser.m_all_tags );
                        TextureBrowser_buildTagList();
                }
                { // tag menu bar
                        auto menu_tags = ui::Menu(ui::New);
-                       auto tags_item = TextureBrowser_constructTagsMenu( menu_tags );
-                       gtk_menu_item_set_submenu( GTK_MENU_ITEM( tags_item ), menu_tags );
-                       gtk_menu_shell_append( GTK_MENU_SHELL( menu_bar ), tags_item );
+                       // auto tags_item = TextureBrowser_constructTagsMenu( menu_tags );
+                       TextureBrowser_constructTagsMenu( menu_tags );
+                       // gtk_menu_item_set_submenu( GTK_MENU_ITEM( tags_item ), menu_tags );
+                       // gtk_menu_shell_append( GTK_MENU_SHELL( menu_bar ), tags_item );
+
+                       auto button = toolbar_append_button( toolbar, "Tags", "texbro_tags.png" );
+                       button.dimensions( 22, 22 );
+                       button.connect( "clicked", G_CALLBACK( Popup_View_Menu ), menu_tags );
                }
                { // Tag TreeView
-                       g_TextureBrowser.m_scr_win_tags = ui::ScrolledWindow(ui::New);
-                       gtk_container_set_border_width( GTK_CONTAINER( g_TextureBrowser.m_scr_win_tags ), 0 );
+                       textureBrowser.m_scr_win_tags = ui::ScrolledWindow(ui::New);
+                       gtk_container_set_border_width( GTK_CONTAINER( textureBrowser.m_scr_win_tags ), 0 );
 
                        // vertical only scrolling for treeview
-                       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tags ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
+                       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tags ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
 
                        TextureBrowser_createTreeViewTags();
 
-            auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
+            auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
 
-                       gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( g_TextureBrowser.m_scr_win_tags ), g_TextureBrowser.m_treeViewTags  );
-                       g_TextureBrowser.m_treeViewTags.show();
+                       gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( textureBrowser.m_scr_win_tags ), textureBrowser.m_treeViewTags  );
+                       textureBrowser.m_treeViewTags.show();
                }
                { // Texture/Tag notebook
                        TextureBrowser_constructTagNotebook();
-                       vbox.pack_start( g_TextureBrowser.m_tag_notebook, TRUE, TRUE, 0 );
+                       vbox.pack_start( textureBrowser.m_tag_notebook, TRUE, TRUE, 0 );
                }
                { // Tag search button
                        TextureBrowser_constructSearchButton();
-                       vbox.pack_end(g_TextureBrowser.m_search_button, FALSE, FALSE, 0);
+                       vbox.pack_end(textureBrowser.m_search_button, FALSE, FALSE, 0);
                }
                auto frame_table = ui::Table(3, 3, FALSE);
                { // Tag frame
 
-                       g_TextureBrowser.m_tag_frame = ui::Frame( "Tag assignment" );
-                       gtk_frame_set_label_align( GTK_FRAME( g_TextureBrowser.m_tag_frame ), 0.5, 0.5 );
-                       gtk_frame_set_shadow_type( GTK_FRAME( g_TextureBrowser.m_tag_frame ), GTK_SHADOW_NONE );
+                       textureBrowser.m_tag_frame = ui::Frame( "Tag assignment" );
+                       gtk_frame_set_label_align( GTK_FRAME( textureBrowser.m_tag_frame ), 0.5, 0.5 );
+                       gtk_frame_set_shadow_type( GTK_FRAME( textureBrowser.m_tag_frame ), GTK_SHADOW_NONE );
 
-                       table.attach(g_TextureBrowser.m_tag_frame, {1, 3, 2, 3}, {GTK_FILL, GTK_SHRINK});
+                       table.attach(textureBrowser.m_tag_frame, {1, 3, 2, 3}, {GTK_FILL, GTK_SHRINK});
 
                        frame_table.show();
 
-                       g_TextureBrowser.m_tag_frame.add(frame_table);
+                       textureBrowser.m_tag_frame.add(frame_table);
                }
                { // assigned tag list
                        ui::Widget scrolled_win = ui::ScrolledWindow(ui::New);
                        gtk_container_set_border_width( GTK_CONTAINER( scrolled_win ), 0 );
                        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_win ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
 
-                       g_TextureBrowser.m_assigned_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
+                       textureBrowser.m_assigned_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
 
-            auto sortable = GTK_TREE_SORTABLE( g_TextureBrowser.m_assigned_store );
+            auto sortable = GTK_TREE_SORTABLE( textureBrowser.m_assigned_store );
                        gtk_tree_sortable_set_sort_column_id( sortable, TAG_COLUMN, GTK_SORT_ASCENDING );
 
                        auto renderer = ui::CellRendererText(ui::New);
 
-                       g_TextureBrowser.m_assigned_tree = ui::TreeView(ui::TreeModel::from(g_TextureBrowser.m_assigned_store._handle));
-                       g_TextureBrowser.m_assigned_store.unref();
-                       g_TextureBrowser.m_assigned_tree.connect( "row-activated", (GCallback) TextureBrowser_removeTags, NULL );
-                       gtk_tree_view_set_headers_visible(g_TextureBrowser.m_assigned_tree, FALSE );
+                       textureBrowser.m_assigned_tree = ui::TreeView(ui::TreeModel::from(textureBrowser.m_assigned_store._handle));
+                       textureBrowser.m_assigned_store.unref();
+                       textureBrowser.m_assigned_tree.connect( "row-activated", (GCallback) TextureBrowser_removeTags, NULL );
+                       gtk_tree_view_set_headers_visible(textureBrowser.m_assigned_tree, FALSE );
 
-            auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_assigned_tree );
+            auto selection = gtk_tree_view_get_selection(textureBrowser.m_assigned_tree );
                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
 
             auto column = ui::TreeViewColumn( "", renderer, {{"text", TAG_COLUMN}} );
-                       gtk_tree_view_append_column(g_TextureBrowser.m_assigned_tree, column );
-                       g_TextureBrowser.m_assigned_tree.show();
+                       gtk_tree_view_append_column(textureBrowser.m_assigned_tree, column );
+                       textureBrowser.m_assigned_tree.show();
 
                        scrolled_win.show();
-                       gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), g_TextureBrowser.m_assigned_tree  );
+                       gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), textureBrowser.m_assigned_tree  );
 
                        frame_table.attach(scrolled_win, {0, 1, 1, 3}, {GTK_FILL, GTK_FILL});
                }
@@ -2199,26 +2480,26 @@ ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
                        gtk_container_set_border_width( GTK_CONTAINER( scrolled_win ), 0 );
                        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_win ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
 
-                       g_TextureBrowser.m_available_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
-            auto sortable = GTK_TREE_SORTABLE( g_TextureBrowser.m_available_store );
+                       textureBrowser.m_available_store = ui::ListStore::from(gtk_list_store_new( N_COLUMNS, G_TYPE_STRING ));
+            auto sortable = GTK_TREE_SORTABLE( textureBrowser.m_available_store );
                        gtk_tree_sortable_set_sort_column_id( sortable, TAG_COLUMN, GTK_SORT_ASCENDING );
 
                        auto renderer = ui::CellRendererText(ui::New);
 
-                       g_TextureBrowser.m_available_tree = ui::TreeView(ui::TreeModel::from(g_TextureBrowser.m_available_store._handle));
-                       g_TextureBrowser.m_available_store.unref();
-                       g_TextureBrowser.m_available_tree.connect( "row-activated", (GCallback) TextureBrowser_assignTags, NULL );
-                       gtk_tree_view_set_headers_visible(g_TextureBrowser.m_available_tree, FALSE );
+                       textureBrowser.m_available_tree = ui::TreeView(ui::TreeModel::from(textureBrowser.m_available_store._handle));
+                       textureBrowser.m_available_store.unref();
+                       textureBrowser.m_available_tree.connect( "row-activated", (GCallback) TextureBrowser_assignTags, NULL );
+                       gtk_tree_view_set_headers_visible(textureBrowser.m_available_tree, FALSE );
 
-            auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_available_tree );
+            auto selection = gtk_tree_view_get_selection(textureBrowser.m_available_tree );
                        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
 
             auto column = ui::TreeViewColumn( "", renderer, {{"text", TAG_COLUMN}} );
-                       gtk_tree_view_append_column(g_TextureBrowser.m_available_tree, column );
-                       g_TextureBrowser.m_available_tree.show();
+                       gtk_tree_view_append_column(textureBrowser.m_available_tree, column );
+                       textureBrowser.m_available_tree.show();
 
                        scrolled_win.show();
-                       gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), g_TextureBrowser.m_available_tree  );
+                       gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_win ), textureBrowser.m_available_tree  );
 
                        frame_table.attach(scrolled_win, {2, 3, 1, 3}, {GTK_FILL, GTK_FILL});
                }
@@ -2257,24 +2538,82 @@ ui::Widget TextureBrowser_constructWindow( ui::Window toplevel ){
                }
        }
        else { // no tag support, show the texture tree only
-               vbox.pack_start( g_TextureBrowser.m_scr_win_tree, TRUE, TRUE, 0 );
+               vbox.pack_start( textureBrowser.m_scr_win_tree, TRUE, TRUE, 0 );
        }
 
        // TODO do we need this?
        //gtk_container_set_focus_chain(GTK_CONTAINER(hbox_table), NULL);
 
+       isWindowConstructed = true;
+
        return table;
 }
 
+void TextureBrowser_destroyGLWidget(){
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       if ( isGLWidgetConstructed )
+       {
+               g_signal_handler_disconnect( G_OBJECT( textureBrowser.m_gl_widget ), textureBrowser.m_sizeHandler );
+               g_signal_handler_disconnect( G_OBJECT( textureBrowser.m_gl_widget ), textureBrowser.m_exposeHandler );
+
+#ifdef WORKAROUND_MACOS_GTK2_GLWIDGET
+               textureBrowser.m_hframe.remove( textureBrowser.m_gl_widget );
+#else // !WORKAROUND_MACOS_GTK2_GLWIDGET
+               textureBrowser.m_frame.remove( textureBrowser.m_gl_widget );
+#endif // !WORKAROUND_MACOS_GTK2_GLWIDGET
+
+               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();
+}
+
+#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(){
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       if ( isWindowConstructed && isGLWidgetConstructed )
+       {
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_vfiller, FALSE, FALSE, 0, ui::Packing::START );
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hframe, TRUE, TRUE, 0, ui::Packing::START );
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hfiller, FALSE, FALSE, 0, ui::Packing::START );
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_gl_widget, TRUE, TRUE, 0, ui::Packing::START );
 
-       g_TextureBrowser.m_gl_widget.unref();
+               textureBrowser.m_gl_widget.show();
+}
 }
 
+void TextureBrowser_hideGLWidget(){
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       if ( isWindowConstructed && isGLWidgetConstructed )
+       {
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_vfiller, TRUE, TRUE, 0, ui::Packing::START);
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hframe, FALSE, FALSE, 0, ui::Packing::END );
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_hfiller, TRUE, TRUE, 0, ui::Packing::START);
+               textureBrowser.m_vframe.set_child_packing( textureBrowser.m_gl_widget, FALSE, FALSE, 0, ui::Packing::END );
+
+               // The hack needs the GL widget to not be hidden to work,
+               // so resizing it triggers the redraw of it with the new size.
+               // GlobalTextureBrowser().m_gl_widget.hide();
+
+               // Trigger the redraw.
+               TextureBrowser_redraw( &GlobalTextureBrowser() );
+               ui::process();
+       }
+}
+#endif // WORKAROUND_MACOS_GTK2_GLWIDGET
+
 const Vector3& TextureBrowser_getBackgroundColour( TextureBrowser& textureBrowser ){
        return textureBrowser.color_textureback;
 }
@@ -2293,7 +2632,7 @@ void TextureBrowser_selectionHelper( ui::TreeModel model, ui::TreePath path, Gtk
 }
 
 void TextureBrowser_shaderInfo(){
-       const char* name = TextureBrowser_GetSelectedShader( g_TextureBrowser );
+       const char* name = TextureBrowser_GetSelectedShader( GlobalTextureBrowser() );
        IShader* shader = QERApp_Shader_ForName( name );
 
        DoShaderInfoDlg( name, shader->getShaderFileName(), "Shader Info" );
@@ -2303,20 +2642,21 @@ void TextureBrowser_shaderInfo(){
 
 void TextureBrowser_addTag(){
        CopiedString tag;
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
        EMessageBoxReturn result = DoShaderTagDlg( &tag, "Add shader tag" );
 
        if ( result == eIDOK && !tag.empty() ) {
                GtkTreeIter iter;
-               g_TextureBrowser.m_all_tags.insert( tag.c_str() );
-               gtk_list_store_append( g_TextureBrowser.m_available_store, &iter );
-               gtk_list_store_set( g_TextureBrowser.m_available_store, &iter, TAG_COLUMN, tag.c_str(), -1 );
+               textureBrowser.m_all_tags.insert( tag.c_str() );
+               gtk_list_store_append( textureBrowser.m_available_store, &iter );
+               gtk_list_store_set( textureBrowser.m_available_store, &iter, TAG_COLUMN, tag.c_str(), -1 );
 
                // Select the currently added tag in the available list
-        auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_available_tree );
+        auto selection = gtk_tree_view_get_selection(textureBrowser.m_available_tree );
                gtk_tree_selection_select_iter( selection, &iter );
 
-               g_TextureBrowser.m_all_tags_list.append(TAG_COLUMN, tag.c_str());
+               textureBrowser.m_all_tags_list.append(TAG_COLUMN, tag.c_str());
        }
 }
 
@@ -2329,8 +2669,9 @@ void TextureBrowser_renameTag(){
         */
 
        GSList* selected = NULL;
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
-    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
+       auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
        gtk_tree_selection_selected_foreach( selection, GtkTreeSelectionForeachFunc( TextureBrowser_selectionHelper ), &selected );
 
        if ( g_slist_length( selected ) == 1 ) { // we only rename a single tag
@@ -2342,41 +2683,42 @@ void TextureBrowser_renameTag(){
                        gchar* rowTag;
                        gchar* oldTag = (char*)selected->data;
 
-                       bool row = gtk_tree_model_get_iter_first(g_TextureBrowser.m_all_tags_list, &iterList ) != 0;
+                       bool row = gtk_tree_model_get_iter_first(textureBrowser.m_all_tags_list, &iterList ) != 0;
 
                        while ( row )
                        {
-                               gtk_tree_model_get(g_TextureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, &rowTag, -1 );
+                               gtk_tree_model_get(textureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, &rowTag, -1 );
 
                                if ( strcmp( rowTag, oldTag ) == 0 ) {
-                                       gtk_list_store_set( g_TextureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, newTag.c_str(), -1 );
+                                       gtk_list_store_set( textureBrowser.m_all_tags_list, &iterList, TAG_COLUMN, newTag.c_str(), -1 );
                                }
-                               row = gtk_tree_model_iter_next(g_TextureBrowser.m_all_tags_list, &iterList ) != 0;
+                               row = gtk_tree_model_iter_next(textureBrowser.m_all_tags_list, &iterList ) != 0;
                        }
 
                        TagBuilder.RenameShaderTag( oldTag, newTag.c_str() );
 
-                       g_TextureBrowser.m_all_tags.erase( (CopiedString)oldTag );
-                       g_TextureBrowser.m_all_tags.insert( newTag );
+                       textureBrowser.m_all_tags.erase( (CopiedString)oldTag );
+                       textureBrowser.m_all_tags.insert( newTag );
 
-                       BuildStoreAssignedTags( g_TextureBrowser.m_assigned_store, g_TextureBrowser.shader.c_str(), &g_TextureBrowser );
-                       BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
+                       BuildStoreAssignedTags( textureBrowser.m_assigned_store, textureBrowser.shader.c_str(), &textureBrowser );
+                       BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
                }
        }
        else
        {
-               ui::alert( g_TextureBrowser.m_parent, "Select a single tag for renaming." );
+               ui::alert( textureBrowser.m_parent, "Select a single tag for renaming." );
        }
 }
 
 void TextureBrowser_deleteTag(){
        GSList* selected = NULL;
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
 
-    auto selection = gtk_tree_view_get_selection(g_TextureBrowser.m_treeViewTags );
+       auto selection = gtk_tree_view_get_selection(textureBrowser.m_treeViewTags );
        gtk_tree_selection_selected_foreach( selection, GtkTreeSelectionForeachFunc( TextureBrowser_selectionHelper ), &selected );
 
        if ( g_slist_length( selected ) == 1 ) { // we only delete a single tag
-               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 );
+               auto result = ui::alert( 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;
@@ -2384,39 +2726,41 @@ void TextureBrowser_deleteTag(){
 
                        gchar* tagSelected = (char*)selected->data;
 
-                       bool row = gtk_tree_model_get_iter_first(g_TextureBrowser.m_all_tags_list, &iterSelected ) != 0;
+                       bool row = gtk_tree_model_get_iter_first(textureBrowser.m_all_tags_list, &iterSelected ) != 0;
 
                        while ( row )
                        {
-                               gtk_tree_model_get(g_TextureBrowser.m_all_tags_list, &iterSelected, TAG_COLUMN, &rowTag, -1 );
+                               gtk_tree_model_get(textureBrowser.m_all_tags_list, &iterSelected, TAG_COLUMN, &rowTag, -1 );
 
                                if ( strcmp( rowTag, tagSelected ) == 0 ) {
-                                       gtk_list_store_remove( g_TextureBrowser.m_all_tags_list, &iterSelected );
+                                       gtk_list_store_remove( textureBrowser.m_all_tags_list, &iterSelected );
                                        break;
                                }
-                               row = gtk_tree_model_iter_next(g_TextureBrowser.m_all_tags_list, &iterSelected ) != 0;
+                               row = gtk_tree_model_iter_next(textureBrowser.m_all_tags_list, &iterSelected ) != 0;
                        }
 
                        TagBuilder.DeleteTag( tagSelected );
-                       g_TextureBrowser.m_all_tags.erase( (CopiedString)tagSelected );
+                       textureBrowser.m_all_tags.erase( (CopiedString)tagSelected );
 
-                       BuildStoreAssignedTags( g_TextureBrowser.m_assigned_store, g_TextureBrowser.shader.c_str(), &g_TextureBrowser );
-                       BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
+                       BuildStoreAssignedTags( textureBrowser.m_assigned_store, textureBrowser.shader.c_str(), &textureBrowser );
+                       BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
                }
        }
        else {
-               ui::alert( g_TextureBrowser.m_parent, "Select a single tag for deletion." );
+               ui::alert( textureBrowser.m_parent, "Select a single tag for deletion." );
        }
 }
 
 void TextureBrowser_copyTag(){
-       g_TextureBrowser.m_copied_tags.clear();
-       TagBuilder.GetShaderTags( g_TextureBrowser.shader.c_str(), g_TextureBrowser.m_copied_tags );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       textureBrowser.m_copied_tags.clear();
+       TagBuilder.GetShaderTags( textureBrowser.shader.c_str(), textureBrowser.m_copied_tags );
 }
 
 void TextureBrowser_pasteTag(){
-       IShader* ishader = QERApp_Shader_ForName( g_TextureBrowser.shader.c_str() );
-       CopiedString shader = g_TextureBrowser.shader.c_str();
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       IShader* ishader = QERApp_Shader_ForName( textureBrowser.shader.c_str() );
+       CopiedString shader = textureBrowser.shader.c_str();
 
        if ( !TagBuilder.CheckShaderTag( shader.c_str() ) ) {
                CopiedString shaderFile = ishader->getShaderFileName();
@@ -2430,18 +2774,18 @@ void TextureBrowser_pasteTag(){
                        TagBuilder.AddShaderNode( shader.c_str(), CUSTOM, SHADER );
                }
 
-               for ( size_t i = 0; i < g_TextureBrowser.m_copied_tags.size(); ++i )
+               for ( size_t i = 0; i < textureBrowser.m_copied_tags.size(); ++i )
                {
-                       TagBuilder.AddShaderTag( shader.c_str(), g_TextureBrowser.m_copied_tags[i].c_str(), TAG );
+                       TagBuilder.AddShaderTag( shader.c_str(), textureBrowser.m_copied_tags[i].c_str(), TAG );
                }
        }
        else
        {
-               for ( size_t i = 0; i < g_TextureBrowser.m_copied_tags.size(); ++i )
+               for ( size_t i = 0; i < textureBrowser.m_copied_tags.size(); ++i )
                {
-                       if ( !TagBuilder.CheckShaderTag( shader.c_str(), g_TextureBrowser.m_copied_tags[i].c_str() ) ) {
+                       if ( !TagBuilder.CheckShaderTag( shader.c_str(), textureBrowser.m_copied_tags[i].c_str() ) ) {
                                // the tag doesn't exist - let's add it
-                               TagBuilder.AddShaderTag( shader.c_str(), g_TextureBrowser.m_copied_tags[i].c_str(), TAG );
+                               TagBuilder.AddShaderTag( shader.c_str(), textureBrowser.m_copied_tags[i].c_str(), TAG );
                        }
                }
        }
@@ -2449,14 +2793,16 @@ void TextureBrowser_pasteTag(){
        ishader->DecRef();
 
        TagBuilder.SaveXmlDoc();
-       BuildStoreAssignedTags( g_TextureBrowser.m_assigned_store, shader.c_str(), &g_TextureBrowser );
-       BuildStoreAvailableTags( g_TextureBrowser.m_available_store, g_TextureBrowser.m_assigned_store, g_TextureBrowser.m_all_tags, &g_TextureBrowser );
+       BuildStoreAssignedTags( textureBrowser.m_assigned_store, shader.c_str(), &textureBrowser );
+       BuildStoreAvailableTags( textureBrowser.m_available_store, textureBrowser.m_assigned_store, textureBrowser.m_all_tags, &textureBrowser );
 }
 
 void TextureBrowser_RefreshShaders(){
-       ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Shaders" );
-       GlobalShaderSystem().refresh();
-       UpdateAllWindows();
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+
+       /* When shaders are refreshed, forces reloading the textures as well.
+       Previously it would at best only display shaders, at worst mess up some textured objects. */
+
     auto selection = gtk_tree_view_get_selection(GlobalTextureBrowser().m_treeViewTree);
        GtkTreeModel* model = NULL;
        GtkTreeIter iter;
@@ -2471,42 +2817,76 @@ void TextureBrowser_RefreshShaders(){
                if ( !TextureBrowser_showWads() ) {
                        strcat( dirName, "/" );
                }
+
+               ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Shaders" );
+               GlobalShaderSystem().refresh();
+               /* texturebrowser tree update on vfs restart */
+               TextureBrowser_constructTreeStore();
+               UpdateAllWindows();
+
                TextureBrowser_ShowDirectory( GlobalTextureBrowser(), dirName );
                TextureBrowser_queueDraw( GlobalTextureBrowser() );
        }
+
+       else{
+               ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Shaders" );
+               GlobalShaderSystem().refresh();
+               /* texturebrowser tree update on vfs restart */
+               TextureBrowser_constructTreeStore();
+               UpdateAllWindows();
+       }
 }
 
 void TextureBrowser_ToggleShowShaders(){
-       g_TextureBrowser.m_showShaders ^= 1;
-       g_TextureBrowser.m_showshaders_item.update();
-       TextureBrowser_queueDraw( g_TextureBrowser );
+       GlobalTextureBrowser().m_showShaders ^= 1;
+       GlobalTextureBrowser().m_showshaders_item.update();
+
+       GlobalTextureBrowser().m_heightChanged = true;
+       GlobalTextureBrowser().m_originInvalid = true;
+       g_activeShadersChangedCallbacks();
+
+       TextureBrowser_queueDraw( GlobalTextureBrowser() );
+}
+
+void TextureBrowser_ToggleShowTextures(){
+       GlobalTextureBrowser().m_showTextures ^= 1;
+       GlobalTextureBrowser().m_showtextures_item.update();
+
+       GlobalTextureBrowser().m_heightChanged = true;
+       GlobalTextureBrowser().m_originInvalid = true;
+       g_activeShadersChangedCallbacks();
+
+       TextureBrowser_queueDraw( GlobalTextureBrowser() );
 }
 
 void TextureBrowser_ToggleShowShaderListOnly(){
        g_TextureBrowser_shaderlistOnly ^= 1;
-       g_TextureBrowser.m_showshaderlistonly_item.update();
+       GlobalTextureBrowser().m_showshaderlistonly_item.update();
 
        TextureBrowser_constructTreeStore();
 }
 
 void TextureBrowser_showAll(){
        g_TextureBrowser_currentDirectory = "";
-       g_TextureBrowser.m_searchedTags = false;
-       TextureBrowser_heightChanged( g_TextureBrowser );
+       GlobalTextureBrowser().m_searchedTags = false;
+//     TextureBrowser_SetHideUnused( GlobalTextureBrowser(), false );
+       TextureBrowser_ToggleHideUnused();
+       //TextureBrowser_heightChanged( GlobalTextureBrowser() );
        TextureBrowser_updateTitle();
 }
 
 void TextureBrowser_showUntagged(){
-       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 );
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+       auto result = ui::alert( 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();
-               TagBuilder.GetUntagged( g_TextureBrowser.m_found_shaders );
+               textureBrowser.m_found_shaders.clear();
+               TagBuilder.GetUntagged( textureBrowser.m_found_shaders );
                std::set<CopiedString>::iterator iter;
 
                ScopeDisableScreenUpdates disableScreenUpdates( "Searching untagged textures...", "Loading Textures" );
 
-               for ( iter = g_TextureBrowser.m_found_shaders.begin(); iter != g_TextureBrowser.m_found_shaders.end(); iter++ )
+               for ( iter = textureBrowser.m_found_shaders.begin(); iter != textureBrowser.m_found_shaders.end(); iter++ )
                {
                        std::string path = ( *iter ).c_str();
                        size_t pos = path.find_last_of( "/", path.size() );
@@ -2518,7 +2898,7 @@ void TextureBrowser_showUntagged(){
 
                g_TextureBrowser_currentDirectory = "Untagged";
                TextureBrowser_queueDraw( GlobalTextureBrowser() );
-               TextureBrowser_heightChanged( g_TextureBrowser );
+               TextureBrowser_heightChanged( textureBrowser );
                TextureBrowser_updateTitle();
        }
 }
@@ -2606,7 +2986,18 @@ struct TextureScale {
 
 struct UniformTextureSize {
        static void Export(const TextureBrowser &self, const Callback<void(int)> &returnz) {
-               returnz(g_TextureBrowser.m_uniformTextureSize);
+               returnz(GlobalTextureBrowser().m_uniformTextureSize);
+       }
+
+       static void Import(TextureBrowser &self, int value) {
+               if (value > 16)
+                       TextureBrowser_setUniformSize(self, value);
+       }
+};
+
+struct UniformTextureMinSize {
+       static void Export(const TextureBrowser &self, const Callback<void(int)> &returnz) {
+               returnz(GlobalTextureBrowser().m_uniformTextureMinSize);
        }
 
        static void Import(TextureBrowser &self, int value) {
@@ -2628,18 +3019,15 @@ void TextureBrowser_constructPreferences( PreferencesPage& page ){
                        make_property<TextureScale>(GlobalTextureBrowser())
                        );
        }
-       page.appendSpinner(
-               "Texture Thumbnail Size",
-               GlobalTextureBrowser().m_uniformTextureSize,
-               GlobalTextureBrowser().m_uniformTextureSize,
-               16, 8192
-       );
+       page.appendSpinner( "Thumbnails Max Size", GlobalTextureBrowser().m_uniformTextureSize, GlobalTextureBrowser().m_uniformTextureSize, 16, 8192 );
+       page.appendSpinner( "Thumbnails Min Size", GlobalTextureBrowser().m_uniformTextureMinSize, GlobalTextureBrowser().m_uniformTextureMinSize, 16, 8192 );
        page.appendEntry( "Mousewheel Increment", GlobalTextureBrowser().m_mouseWheelScrollIncrement );
        {
-               const char* startup_shaders[] = { "None", TextureBrowser_getComonShadersName() };
+               const char* startup_shaders[] = { "None", TextureBrowser_getCommonShadersName() };
                page.appendCombo( "Load Shaders at Startup", reinterpret_cast<int&>( GlobalTextureBrowser().m_startupShaders ), STRING_ARRAY_RANGE( startup_shaders ) );
        }
 }
+
 void TextureBrowser_constructPage( PreferenceGroup& group ){
        PreferencesPage page( group.createPage( "Texture Browser", "Texture Browser Preferences" ) );
        TextureBrowser_constructPreferences( page );
@@ -2657,6 +3045,8 @@ void TextureBrowser_registerPreferencesPage(){
 void TextureClipboard_textureSelected( const char* shader );
 
 void TextureBrowser_Construct(){
+       TextureBrowser &textureBrowser = GlobalTextureBrowser();
+
        GlobalCommands_insert( "ShaderInfo", makeCallbackF(TextureBrowser_shaderInfo) );
        GlobalCommands_insert( "ShowUntagged", makeCallbackF(TextureBrowser_showUntagged) );
        GlobalCommands_insert( "AddTag", makeCallbackF(TextureBrowser_addTag) );
@@ -2665,31 +3055,35 @@ void TextureBrowser_Construct(){
        GlobalCommands_insert( "CopyTag", makeCallbackF(TextureBrowser_copyTag) );
        GlobalCommands_insert( "PasteTag", makeCallbackF(TextureBrowser_pasteTag) );
        GlobalCommands_insert( "RefreshShaders", makeCallbackF(VFS_Refresh) );
-       GlobalToggles_insert( "ShowInUse", makeCallbackF(TextureBrowser_ToggleHideUnused), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_hideunused_item ), Accelerator( 'U' ) );
+       GlobalToggles_insert( "ShowInUse", makeCallbackF(TextureBrowser_ToggleHideUnused), ToggleItem::AddCallbackCaller( textureBrowser.m_hideunused_item ), Accelerator( 'U' ) );
        GlobalCommands_insert( "ShowAllTextures", makeCallbackF(TextureBrowser_showAll), Accelerator( 'A', (GdkModifierType)GDK_CONTROL_MASK ) );
        GlobalCommands_insert( "ToggleTextures", makeCallbackF(TextureBrowser_toggleShow), Accelerator( 'T' ) );
-       GlobalToggles_insert( "ToggleShowShaders", makeCallbackF(TextureBrowser_ToggleShowShaders), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_showshaders_item ) );
-       GlobalToggles_insert( "ToggleShowShaderlistOnly", makeCallbackF(TextureBrowser_ToggleShowShaderListOnly), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_showshaderlistonly_item ) );
-       GlobalToggles_insert( "FixedSize", makeCallbackF(TextureBrowser_FixedSize), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_fixedsize_item ) );
-       GlobalToggles_insert( "FilterMissing", makeCallbackF(TextureBrowser_FilterMissing), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_filternotex_item ) );
-       GlobalToggles_insert( "FilterFallback", makeCallbackF(TextureBrowser_FilterFallback), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_hidenotex_item ) );
-       GlobalToggles_insert( "EnableAlpha", makeCallbackF(TextureBrowser_EnableAlpha), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_enablealpha_item ) );
-
-       GlobalPreferenceSystem().registerPreference( "TextureScale", make_property_string<TextureScale>(g_TextureBrowser) );
-       GlobalPreferenceSystem().registerPreference( "UniformTextureSize", make_property_string<UniformTextureSize>(g_TextureBrowser) );
-       GlobalPreferenceSystem().registerPreference( "TextureScrollbar", make_property_string<TextureBrowser_ShowScrollbar>(GlobalTextureBrowser()));
-       GlobalPreferenceSystem().registerPreference( "ShowShaders", make_property_string( GlobalTextureBrowser().m_showShaders ) );
+       GlobalToggles_insert( "ToggleShowShaders", makeCallbackF(TextureBrowser_ToggleShowShaders), ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_showshaders_item ) );
+       GlobalToggles_insert( "ToggleShowTextures", makeCallbackF(TextureBrowser_ToggleShowTextures), ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_showtextures_item ) );
+       GlobalToggles_insert( "ToggleShowShaderlistOnly", makeCallbackF(TextureBrowser_ToggleShowShaderListOnly),
+ ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_showshaderlistonly_item ) );
+       GlobalToggles_insert( "FixedSize", makeCallbackF(TextureBrowser_FixedSize), ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_fixedsize_item ) );
+       GlobalToggles_insert( "FilterMissing", makeCallbackF(TextureBrowser_FilterMissing), ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_filternotex_item ) );
+       GlobalToggles_insert( "FilterFallback", makeCallbackF(TextureBrowser_FilterFallback), ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_hidenotex_item ) );
+       GlobalToggles_insert( "EnableAlpha", makeCallbackF(TextureBrowser_EnableAlpha), ToggleItem::AddCallbackCaller( GlobalTextureBrowser().m_enablealpha_item ) );
+
+       GlobalPreferenceSystem().registerPreference( "TextureScale", make_property_string<TextureScale>(textureBrowser) );
+       GlobalPreferenceSystem().registerPreference( "UniformTextureSize", make_property_string<UniformTextureSize>(textureBrowser) );
+       GlobalPreferenceSystem().registerPreference( "UniformTextureMinSize", make_property_string<UniformTextureMinSize>(textureBrowser) );
+       GlobalPreferenceSystem().registerPreference( "TextureScrollbar", make_property_string<TextureBrowser_ShowScrollbar>(textureBrowser));
+       GlobalPreferenceSystem().registerPreference( "ShowShaders", make_property_string( textureBrowser.m_showShaders ) );
+       GlobalPreferenceSystem().registerPreference( "ShowTextures", make_property_string( GlobalTextureBrowser().m_showTextures ) );
        GlobalPreferenceSystem().registerPreference( "ShowShaderlistOnly", make_property_string( g_TextureBrowser_shaderlistOnly ) );
        GlobalPreferenceSystem().registerPreference( "FixedSize", make_property_string( g_TextureBrowser_fixedSize ) );
        GlobalPreferenceSystem().registerPreference( "FilterMissing", make_property_string( g_TextureBrowser_filterMissing ) );
        GlobalPreferenceSystem().registerPreference( "EnableAlpha", make_property_string( g_TextureBrowser_enableAlpha ) );
-       GlobalPreferenceSystem().registerPreference( "LoadShaders", make_property_string( reinterpret_cast<int&>( GlobalTextureBrowser().m_startupShaders ) ) );
-       GlobalPreferenceSystem().registerPreference( "WheelMouseInc", make_property_string( GlobalTextureBrowser().m_mouseWheelScrollIncrement ) );
-       GlobalPreferenceSystem().registerPreference( "SI_Colors0", make_property_string( GlobalTextureBrowser().color_textureback ) );
+       GlobalPreferenceSystem().registerPreference( "LoadShaders", make_property_string( reinterpret_cast<int&>( textureBrowser.m_startupShaders ) ) );
+       GlobalPreferenceSystem().registerPreference( "WheelMouseInc", make_property_string( textureBrowser.m_mouseWheelScrollIncrement ) );
+       GlobalPreferenceSystem().registerPreference( "SI_Colors0", make_property_string( textureBrowser.color_textureback ) );
 
-       g_TextureBrowser.shader = texdef_name_default();
+       textureBrowser.shader = texdef_name_default();
 
-       Textures_setModeChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_queueDraw>( g_TextureBrowser ) );
+       Textures_setModeChangedNotify( ReferenceCaller<TextureBrowser, void(), TextureBrowser_queueDraw>( textureBrowser ) );
 
        TextureBrowser_registerPreferencesPage();
 
@@ -2703,3 +3097,13 @@ void TextureBrowser_Destroy(){
 
        Textures_setModeChangedNotify( Callback<void()>() );
 }
+
+ui::Widget TextureBrowser_getGLWidget(){
+       return GlobalTextureBrowser().m_gl_widget;
+}
+
+#if WORKAROUND_WINDOWS_GTK2_GLWIDGET
+ui::GLArea TextureBrowser_getGLWidget(){
+       return GlobalTextureBrowser().m_gl_widget;
+}
+#endif // WORKAROUND_WINDOWS_GTK2_GLWIDGET