File indexing completed on 2024-04-28 05:32:20

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004     SPDX-FileCopyrightText: 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
0005 
0006     based on the Null Theme Engine for Gtk+.
0007     SPDX-FileCopyrightText: 2008 Robert Staudinger <robert.staudinger@gmail.com>
0008 
0009     Icon rendering code from Walmis
0010     <http://gnome-look.org/content/show.php?content=77783&forumpage=3>
0011 
0012     SPDX-License-Identifier: LGPL-2.0-or-later
0013 */
0014 
0015 #include "oxygenstylewrapper.h"
0016 
0017 #include "oxygen.h"
0018 #include "oxygenanimations.h"
0019 #include "oxygenargbhelper.h"
0020 #include "oxygencairoutils.h"
0021 #include "oxygendefines.h"
0022 #include "oxygengtkcellinfo.h"
0023 #include "oxygengtkdetails.h"
0024 #include "oxygengtktypenames.h"
0025 #include "oxygengtkutils.h"
0026 #include "oxygenmetrics.h"
0027 #include "oxygenstyle.h"
0028 #include "oxygenwidgetexplorer.h"
0029 #include "oxygenwindowmanager.h"
0030 #include "oxygencolorutils.h"
0031 #include "config.h"
0032 
0033 #include <iostream>
0034 namespace Oxygen
0035 {
0036 
0037     //___________________________________________________________________________________________________________
0038     GtkStyleClass* StyleWrapper::_parentClass = 0L;
0039     GTypeInfo StyleWrapper::_typeInfo;
0040     GType StyleWrapper::_type = 0L;
0041     XulInfo StyleWrapper::_xulInfo = XulInfo();
0042 
0043     //___________________________________________________________________________________________________________
0044     static void draw_animated_button(
0045         GdkWindow* window,
0046         GdkRectangle* clipRect,
0047         GtkWidget* widget )
0048     {
0049 
0050         #if OXYGEN_DEBUG
0051         std::cerr
0052             << "Oxygen::draw_animated_button -"
0053             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
0054             << std::endl;
0055         #endif
0056 
0057         ToolBarStateEngine& engine( Style::instance().animations().toolBarStateEngine() );
0058         engine.registerWidget(widget);
0059         if( engine.animatedRectangleIsValid( widget ) )
0060         {
0061 
0062             const GdkRectangle& rect( engine.animatedRectangle( widget ) );
0063             Style::instance().renderButtonSlab( window, clipRect, rect.x, rect.y, rect.width, rect.height, Flat|Hover );
0064 
0065         } else if( engine.isLocked( widget ) && gtk_widget_get_state( engine.widget( widget, AnimationCurrent ) ) != GTK_STATE_ACTIVE ) {
0066 
0067             const GdkRectangle& rect( engine.rectangle( widget, AnimationCurrent ) );
0068             Style::instance().renderButtonSlab( window, clipRect, rect.x, rect.y, rect.width, rect.height, Flat|Hover );
0069 
0070         } else if( engine.isAnimated( widget, AnimationPrevious ) && gtk_widget_get_state( engine.widget( widget, AnimationPrevious ) ) != GTK_STATE_ACTIVE ) {
0071 
0072             const AnimationData data( engine.animationData( widget, AnimationPrevious ) );
0073             const GdkRectangle& rect( engine.rectangle( widget, AnimationPrevious ) );
0074             Style::instance().renderButtonSlab( window, clipRect, rect.x, rect.y, rect.width, rect.height, Flat|Hover, data );
0075 
0076         }
0077 
0078     }
0079 
0080     //___________________________________________________________________________________________________________
0081     static void draw_flat_box(
0082         GtkStyle* style,
0083         GdkWindow* window,
0084         GtkStateType state,
0085         GtkShadowType shadow,
0086         GdkRectangle* clipRect,
0087         GtkWidget* widget,
0088         const char* detail,
0089         gint x,
0090         gint y,
0091         gint w,
0092         gint h )
0093     {
0094         g_return_if_fail( style && window );
0095         Style::instance().sanitizeSize( window, w, h );
0096 
0097         #if OXYGEN_DEBUG
0098         std::cerr
0099             << "Oxygen::draw_flat_box -"
0100             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
0101             << " state: " << Gtk::TypeNames::state( state )
0102             << " shadow: " << Gtk::TypeNames::shadow( shadow )
0103             << " detail: " << (detail ? detail:"0x0" )
0104             << std::endl;
0105         #endif
0106 
0107         const Gtk::Detail d( detail );
0108 
0109         // Render tab background
0110         if(Style::instance().settings().applicationName().isOpenOffice() && GTK_IS_NOTEBOOK(widget))
0111         {
0112             Style::instance().renderWindowBackground(window,widget,NULL,x,y,w,h);
0113             return;
0114         }
0115 
0116         if( d.isBase() || d.isEventBox() || (d.isNull() && Gtk::g_object_is_a( G_OBJECT( widget ), "ShellWindow" ) ) )
0117         {
0118 
0119             // if background pixmap is provided, fallback to default painting
0120             if( style->bg_pixmap[state] )
0121             {
0122                 StyleWrapper::parentClass()->draw_flat_box( style, window, state,
0123                     shadow, clipRect, widget, detail,
0124                     x, y, w, h );
0125 
0126                 return;
0127             }
0128 
0129             // for opera, render flat background, always
0130             // (using renderwindowbackground will at best fall back to flat, at worse, render garbage)
0131             if( Style::instance().settings().applicationName().isOpera() )
0132             {
0133                 Style::instance().fill( window, clipRect, x, y, w, h, Palette::Window );
0134                 return;
0135             }
0136 
0137             // do nothing for mozilla, acrobat, gnome applets, and other hint-specific windows
0138             if(
0139                 Style::instance().settings().applicationName().useFlatBackground( widget ) ||
0140                 Gtk::gtk_widget_is_applet( widget ) ||
0141                 Gtk::gdk_window_nobackground( window ) )
0142             { return; }
0143 
0144             // if background has been modified, simply fill with background color
0145             /*
0146             note: this is an inconsistent design choice. In principle we could just
0147             - register the widgets to the relevant engines as below
0148             - pass the modified color to renderWindowBackground
0149             */
0150             if( Gtk::gtk_widget_style_is_modified( widget, state, GTK_RC_BG ) )
0151             {
0152                 Style::instance().animations().flatWidgetEngine().registerFlatWidget( widget );
0153                 Style::instance().fill( window, clipRect, x, y, w, h, Gtk::gdk_get_color( style->bg[state] ) );
0154                 return;
0155             }
0156 
0157             // register to relevant engines
0158             if( GTK_IS_WINDOW( widget ) )
0159             {
0160 
0161                 Style::instance().animations().mainWindowEngine().registerWidget( widget );
0162 
0163             } else if( GtkWidget* parent = Gtk::gtk_parent_scrolled_window( widget ) ) {
0164 
0165                 Style::instance().animations().scrollBarEngine().registerScrolledWindow( parent );
0166 
0167             }
0168 
0169             // change gtk dialog button order
0170             GtkWidget *toplevel = gtk_widget_get_toplevel( widget );
0171             if( GTK_IS_DIALOG( toplevel ) )
0172             { Style::instance().animations().dialogEngine().registerWidget( toplevel ); }
0173 
0174             // render background gradient
0175             StyleOptions options;
0176             options._customColors.insert( Palette::Window, Gtk::gdk_get_color( style->bg[state] ) );
0177             const bool success( Style::instance().renderWindowBackground( window, widget, clipRect, x, y, w, h, options ) );
0178 
0179             // if widget has flat parent, store in flatWidget engine so that children gets the right background nonetheless
0180             if( success && Style::instance().animations().flatWidgetEngine().flatParent( widget ) )
0181             { Style::instance().animations().flatWidgetEngine().registerPaintWidget( widget ); }
0182 
0183             // register to window manager
0184             if( success &&
0185                 Gtk::gdk_window_is_base( window ) &&
0186                 !( GTK_IS_EVENT_BOX( widget ) &&
0187                 !gtk_event_box_get_above_child( GTK_EVENT_BOX( widget ) ) ) )
0188             {
0189                 BackgroundHints hints( BackgroundGradient );
0190                 if( Style::instance().hasBackgroundSurface() ) hints |= BackgroundPixmap;
0191                 Style::instance().animations().backgroundHintEngine().registerWidget( widget, hints );
0192             }
0193 
0194             // possible groupbox background
0195             if( d.isEventBox() && Gtk::gtk_parent_groupbox( widget ) )
0196             {
0197                 options |= Blend;
0198                 Style::instance().renderGroupBoxBackground( window, widget, clipRect, x, y, w, h, options );
0199             }
0200 
0201             // also draw possible animated tool button
0202             if( !d.isNull() )
0203             { draw_animated_button( window, clipRect, widget ); }
0204 
0205             return;
0206 
0207         } else if( d.isViewportBin() ) {
0208 
0209             // do nothing for gnome applets
0210             if( Gtk::gtk_widget_is_applet( widget ) ) return;
0211 
0212             // for modified bg, fill with flat custom color
0213             if( Gtk::gtk_widget_style_is_modified( widget, state, GTK_RC_BG ) )
0214             {
0215 
0216                 Style::instance().fill( window, clipRect, x, y, w, h, Gtk::gdk_get_color( style->bg[state] ) );
0217 
0218             } else if(
0219                 Style::instance().settings().applicationName().useFlatBackground( widget ) ||
0220                 !Style::instance().animations().backgroundHintEngine().contains( gtk_widget_get_toplevel( widget ) ) )
0221             {
0222 
0223                 // for mozilla and openoffice fill with flat color
0224                 Style::instance().fill( window, clipRect, x, y, w, h, Palette::Window );
0225                 return;
0226 
0227             } else {
0228 
0229                 // make sure that widget is registered to scrolledBarEngine,
0230                 // so that background gets updated properly
0231                 if( GtkWidget* parent = Gtk::gtk_parent_scrolled_window( widget ) )
0232                 { Style::instance().animations().scrollBarEngine().registerScrolledWindow( parent ); }
0233 
0234                 // render background gradient
0235                 Style::instance().renderWindowBackground( window, widget, clipRect, x, y, w, h );
0236 
0237             }
0238 
0239             // also draw possible animated tool button
0240             draw_animated_button( window, clipRect, widget );
0241 
0242             return;
0243 
0244         } else if( d.isTrough() ) {
0245 
0246             if( GTK_IS_PROGRESS_BAR( widget ) )
0247             {
0248                 if( Style::instance().settings().applicationName().isOpenOffice() )
0249                 {
0250                     StyleOptions options;
0251                     if( Gtk::gtk_widget_is_vertical( widget ) ) options |= Vertical;
0252                     Style::instance().renderProgressBarHole( window, clipRect, x,y,w,h, options );
0253                 }
0254                 return;
0255             }
0256 
0257         } else if( d.isTooltip() && Style::instance().settings().tooltipDrawStyledFrames() ) {
0258 
0259             // mozilla and openoffice get square non Argb tooltips no matter what
0260             if(
0261                 Style::instance().settings().applicationName().isOpenOffice() ||
0262                 Style::instance().settings().applicationName().isXul() )
0263             {
0264                 Style::instance().renderTooltipBackground( window, clipRect, x, y, w, h, StyleOptions() );
0265                 return;
0266             }
0267 
0268             StyleOptions options( Round );
0269             if( Gtk::gtk_widget_has_rgba( widget ) ) options |= Alpha;
0270 
0271             if( GDK_IS_WINDOW( window ) )
0272             {
0273                 WidgetSizeEngine& engine( Style::instance().animations().widgetSizeEngine() );
0274                 engine.registerWidget( widget );
0275                 if( engine.update(widget) )
0276                 {
0277                     Style::instance().adjustMask( widget, engine.width( widget ), engine.height( widget ), engine.alpha( widget ) );
0278                     Style::instance().setWindowBlur( widget, engine.alpha( widget ) );
0279                 }
0280             }
0281 
0282             Style::instance().renderTooltipBackground( window, clipRect, x, y, w, h, options );
0283             return;
0284 
0285         } else if(
0286             d.isCheckButton() ||
0287             d.isRadioButton() ||
0288             d.isExpander() ) {
0289 
0290             return;
0291 
0292         } else if( d.isCell() ) {
0293 
0294             StyleOptions options( widget, state );
0295 
0296             // select palete colorgroup for cell background
0297             Palette::Group group( Palette::Active );
0298             if( options & Disabled ) group = Palette::Disabled;
0299             else if( !(options&Focus) ) group = Palette::Inactive;
0300 
0301             // render background
0302             // render "normal" background
0303             bool drawTreeLines( true );
0304             ColorUtils::Rgba background;
0305 
0306             if( Gtk::gtk_widget_style_is_modified( widget, GTK_STATE_NORMAL, GTK_RC_BASE ) )
0307             {
0308 
0309                 /*
0310                 do not draw tree lines when a custom background color is set
0311                 since it usually does not work for non-selected items
0312                 */
0313                 drawTreeLines = false;
0314 
0315                 // assign background
0316                 background = Gtk::gdk_get_color( style->base[GTK_STATE_NORMAL] );
0317 
0318             } else if( widget && std::string( G_OBJECT_TYPE_NAME( widget ) ).find( "MiroTreeView" ) != std::string::npos ) {
0319 
0320                 drawTreeLines = false;
0321 
0322             } else if( d.isCellEven() || Gtk::gtk_combobox_is_tree_view( widget ) ) {
0323 
0324                 background = Style::instance().settings().palette().color( group, Palette::Base );
0325 
0326             } else if( d.isCellOdd() ) {
0327 
0328                 background = Style::instance().settings().palette().color( group, Palette::BaseAlternate );
0329 
0330             }
0331 
0332             if( background.isValid() ) Style::instance().fill( window, clipRect, x, y, w, h, background );
0333             if( Gtk::gtk_combobox_is_tree_view( widget ) )
0334             {
0335 
0336                 // draw flat selection in combobox list
0337                 if(state==GTK_STATE_SELECTED)
0338                 {
0339                     ColorUtils::Rgba selection( Style::instance().settings().palette().color( Palette::Active, Palette::Selected ) );
0340                     Style::instance().fill( window, clipRect, x, y, w, h, selection );
0341                 }
0342 
0343             } else {
0344 
0345                 const bool reversed( Gtk::gtk_widget_layout_is_reversed( widget ) );
0346 
0347                 // draw rounded selection in normal list,
0348                 // and detect hover
0349                 bool forceCellStart( false );
0350                 bool forceCellEnd( false );
0351                 if( GTK_IS_TREE_VIEW( widget ) )
0352                 {
0353 
0354                     GtkTreeView* treeView( GTK_TREE_VIEW( widget ) );
0355                     Gtk::CellInfo cellInfo( treeView, x, y, w, h );
0356 
0357                     Style::instance().animations().treeViewEngine().registerWidget( widget );
0358                     if( Style::instance().animations().treeViewEngine().isDirty( widget ) )
0359                     { Style::instance().animations().treeViewEngine().updateHoveredCell( widget ); }
0360 
0361                     if( cellInfo.isValid() && Style::instance().animations().treeViewEngine().isCellHovered( widget, cellInfo ) )
0362                     { options |= Hover; }
0363 
0364                     const bool showExpanders( gtk_tree_view_get_show_expanders( treeView ) );
0365                     if( showExpanders && cellInfo.isValid() && cellInfo.isExpanderColumn( treeView ))
0366                     {
0367 
0368                         // tree lines
0369                         if( drawTreeLines && Style::instance().settings().viewDrawTreeBranchLines() && showExpanders )
0370                         {
0371 
0372                             // generate flags from cell info
0373                             Gtk::CellInfoFlags cellFlags( treeView, cellInfo );
0374                             if( reversed ) cellFlags._flags |= Gtk::CellInfoFlags::Reversed;
0375 
0376                             // set proper options
0377                             StyleOptions options( widget, state, shadow );
0378 
0379                             // and render
0380                             Style::instance().renderTreeLines( window, clipRect, x, y, w, h, cellFlags, options );
0381 
0382                         }
0383 
0384                         // change selection rect so that it does not overlap with expander
0385                         if( reversed ) forceCellEnd = true;
0386                         else forceCellStart = true;
0387 
0388                         forceCellStart = true;
0389                         if( options&(Selected|Hover) )
0390                         {
0391 
0392                             // get expander size from widget
0393                             int depth( cellInfo.depth() );
0394                             int expanderSize(0);
0395                             gtk_widget_style_get( widget, "expander-size", &expanderSize, NULL );
0396 
0397                             int offset( 3 + expanderSize * depth + ( 4 + gtk_tree_view_get_level_indentation( treeView ) )*(depth-1) );
0398 
0399                             if( reversed ) w-= offset;
0400                             else {
0401 
0402                                 x += offset;
0403                                 w -= offset;
0404 
0405                             }
0406 
0407                         }
0408 
0409                     } else if( showExpanders && (options&(Selected|Hover)) && cellInfo.isValid() && cellInfo.isLeftOfExpanderColumn( treeView ) ) {
0410 
0411                         if( reversed ) forceCellStart = true;
0412                         else forceCellEnd = true;
0413 
0414                     }
0415 
0416                     // check if column is last
0417                     if( (options&(Selected|Hover)) && cellInfo.isValid() )
0418                     {
0419                         if(cellInfo.isLastVisibleColumn( treeView ))
0420                         {
0421                             if( reversed ) forceCellStart = true;
0422                             else forceCellEnd = true;
0423                         }
0424                         if(cellInfo.isFirstVisibleColumn( treeView ))
0425                         {
0426                             if( reversed ) forceCellEnd = true;
0427                             else forceCellStart = true;
0428                         }
0429                     }
0430 
0431                 }
0432 
0433                 if( options & (Selected|Hover) )
0434                 {
0435 
0436                     TileSet::Tiles tiles( TileSet::Center );
0437                     if( d.isCellStart() ) tiles |= TileSet::Left;
0438                     else if( d.isCellEnd() ) tiles |= TileSet::Right;
0439                     else if( !d.isCellMiddle() ) tiles = TileSet::Horizontal;
0440 
0441                     if( forceCellStart ) tiles |= TileSet::Left;
0442                     if( forceCellEnd ) tiles |= TileSet::Right;
0443 
0444                     Style::instance().renderSelection( window, clipRect, x, y, w, h, tiles, options );
0445 
0446                 }
0447 
0448             }
0449 
0450             return;
0451 
0452 
0453         } else if( d.isIconViewItem() ) {
0454 
0455             StyleOptions options( widget, state );
0456             if( options&(Selected|Hover) )
0457             {
0458                 // adjustments have been tuned empirically
0459                 Style::instance().renderSelection( window, clipRect, x, y, w, h, TileSet::Full, options );
0460             }
0461             return;
0462 
0463         } else if( d.isEntryBg() && !Style::instance().settings().applicationName().isXul( widget ) ) {
0464 
0465             // FIXME: how to detect Chromium address bar more correctly?
0466             const bool isChromeAddressBar( widget &&
0467                     GTK_IS_HBOX(widget) &&
0468                     Style::instance().settings().applicationName().isGoogleChrome() );
0469             if(Style::instance().settings().applicationName().isOpenOffice())
0470             {
0471                 const char* ver=Style::instance().settings().applicationName().versionString();
0472                 // If ver appears non-NULL, we have at least LibO 4.0.
0473                 // For now, it's enough to differentiate old version from new.
0474                 // If something gets broken in newer version, we'll have to parse ver.
0475                 if(ver)
0476                 {
0477                     x-=3;
0478                     w+=6;
0479                 }
0480                 else
0481                 {
0482                     x+=2;
0483                     w-=4;
0484                     y+=1;
0485                     h-=2;
0486                 }
0487             }
0488 
0489             StyleOptions options( widget, state, shadow );
0490             if(
0491                 !Style::instance().settings().applicationName().isGoogleChrome() &&
0492                 !Style::instance().settings().applicationName().isOpenOffice( widget ) )
0493             { options |= NoFill; }
0494 
0495             // calculate proper offsets so that the glow/shadow match parent frame
0496             const int sideMargin( isChromeAddressBar ? 0 : std::max( 0, style->xthickness - 2 ) );
0497             const int xOffset( style->xthickness + 1 - sideMargin );
0498 
0499             // adjust horizontal positioning and width
0500             x -= xOffset;
0501             w += 2*xOffset;
0502 
0503             if( GtkWidget* parent = Gtk::gtk_parent_combobox_entry( widget ) )
0504             {
0505 
0506                 // check if parent is in style map
0507                 Style::instance().animations().comboBoxEntryEngine().registerWidget( parent );
0508                 Style::instance().animations().comboBoxEntryEngine().setEntry( parent, widget );
0509                 Style::instance().animations().comboBoxEntryEngine().setEntryFocus( parent, options & Focus );
0510 
0511                 if( state != GTK_STATE_INSENSITIVE )
0512                 {
0513                     if( Style::instance().animations().comboBoxEntryEngine().hasFocus( parent ) ) options |= Focus;
0514                     else options &= ~Focus;
0515 
0516                     if(  Style::instance().animations().comboBoxEntryEngine().hovered( parent ) ) options |= Hover;
0517                     else options &= ~Hover;
0518                 }
0519 
0520                 /*
0521                 for some reason, adjusting y and h using ythickness does not work for combobox_entry
0522                 one need to use parent allocation instead
0523                 */
0524                 const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( parent ) );
0525                 y -= (allocation.height-h + 1)/2;
0526                 h = allocation.height;
0527 
0528                 // partial highlight
0529                 TileSet::Tiles tiles( TileSet::Ring );
0530                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( parent, options, AnimationHover|AnimationFocus, AnimationFocus ) );
0531                 if( Gtk::gtk_widget_layout_is_reversed( widget ) )
0532                 {
0533 
0534                     // hide left part and increase width
0535                     tiles &= ~TileSet::Left;
0536                     Style::instance().renderHoleBackground( window, widget, clipRect, x-sideMargin-2, y, w+2*sideMargin+2, h, TileSet::Full, sideMargin );
0537                     Style::instance().renderHole( window, clipRect, x-9, y, w+9, h, options, data, tiles );
0538 
0539                 } else {
0540 
0541                     // hide right part and increase width
0542                     tiles &= ~TileSet::Right;
0543                     Style::instance().renderHoleBackground( window, widget, clipRect, x-sideMargin, y, w+2*sideMargin+2, h, TileSet::Full, sideMargin );
0544                     Style::instance().renderHole( window, clipRect, x, y, w+9, h, options, data, tiles );
0545 
0546                 }
0547 
0548             } else if( GTK_IS_SPIN_BUTTON( widget ) ) {
0549 
0550                 // do nothing for frameless entries
0551                 if( !gtk_entry_get_has_frame( GTK_ENTRY( widget ) ) )
0552                 { return; }
0553 
0554                 const int yOffset( style->ythickness + 1 );
0555 
0556                 // there is no need to render anything if both offsets are larger than 4
0557                 if( xOffset > 4 && yOffset > 4 ) return;
0558 
0559                 // adjust vertical positioning and height
0560                 y -= yOffset;
0561                 h += 2*yOffset;
0562 
0563                 // for libreoffice do nothing
0564                 if( Style::instance().settings().applicationName().isOpenOffice( widget ) )
0565                 { return; }
0566 
0567                 if(
0568                     Style::instance().animations().hoverEngine().contains( widget ) &&
0569                     Style::instance().animations().hoverEngine().hovered( widget ) )
0570                 { options |= Hover; }
0571 
0572                 // plain background
0573                 ColorUtils::Rgba background( Gtk::gdk_get_color( style->base[gtk_widget_get_state(widget)] ) );
0574                 Style::instance().fill( window, clipRect, x, y, w, h, background );
0575 
0576                 // animation data
0577                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );
0578 
0579                 // hole
0580                 TileSet::Tiles tiles( TileSet::Ring );
0581                 if( Gtk::gtk_widget_layout_is_reversed( widget ) )
0582                 {
0583 
0584                     // hide right part and adjust width
0585                     tiles &= ~TileSet::Left;
0586                     Style::instance().renderHoleBackground( window, widget, clipRect, x-2-sideMargin, y, w+2*sideMargin+2, h, tiles, sideMargin );
0587                     Style::instance().renderHole( window, clipRect, x-7, y, w+7, h, options, data, tiles );
0588 
0589                 } else {
0590 
0591                     // hide right part and adjust width
0592                     tiles &= ~TileSet::Right;
0593                     Style::instance().renderHoleBackground( window, widget, clipRect, x-sideMargin, y, w+2*sideMargin, h, tiles, sideMargin );
0594                     Style::instance().renderHole( window, clipRect, x, y, w+7, h, options, data, tiles );
0595 
0596                 }
0597 
0598             } else {
0599 
0600                 // do nothing for frameless entries
0601                 if( GTK_IS_ENTRY( widget ) && !gtk_entry_get_has_frame( GTK_ENTRY( widget ) ) )
0602                 { return; }
0603 
0604                 const int yOffset( style->ythickness + 1 );
0605 
0606                 // there is no need to render anything if both offsets are larger than 4
0607                 if( xOffset > 4 && yOffset > 4 ) return;
0608 
0609                 // adjust vertical positioning and height
0610                 y -= yOffset;
0611                 h += 2*yOffset;
0612 
0613                 if(
0614                     Style::instance().animations().hoverEngine().contains( widget ) &&
0615                     Style::instance().animations().hoverEngine().hovered( widget ) )
0616                 { options |= Hover; }
0617 
0618                 // compare painting rect to widget rect, to decide if some sides are to be masked
0619                 TileSet::Tiles tiles = TileSet::Ring;
0620                 GdkWindow* widgetWindow( gtk_widget_get_window( widget ) );
0621                 if( widget && window != widgetWindow && GDK_IS_WINDOW( window ) && widgetWindow == gdk_window_get_parent( window )  )
0622                 {
0623 
0624                     const int widgetWindowWidth( Gtk::gtk_widget_get_allocation( widget ).width );
0625                     int localWindowX( 0 );
0626                     int localWindowWidth( 0 );
0627                     gdk_window_get_position( window, &localWindowX, 0L );
0628                     gdk_window_get_size( window, &localWindowWidth, 0L );
0629 
0630                     // remove left border if needed
0631                     if( localWindowX > 5 )
0632                     {
0633                         tiles &= ~TileSet::Left;
0634                         x -= 9;
0635                         w += 9;
0636                     }
0637 
0638                     // remove right border if needed
0639                     if( localWindowX + localWindowWidth < widgetWindowWidth - 5 )
0640                     {
0641                         tiles &= ~TileSet::Right;
0642                         w += 9;
0643                     }
0644 
0645                 }
0646 
0647                 // render hole
0648                 Style::instance().renderHoleBackground( window, widget, clipRect, x-sideMargin, y, w+2*sideMargin, h, TileSet::Full, sideMargin );
0649                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );
0650                 Style::instance().renderHole( window, clipRect, x, y, w, h, options, data, tiles );
0651 
0652             }
0653 
0654             return;
0655 
0656         }
0657 
0658         // call parent method if reaching here
0659         StyleWrapper::parentClass()->draw_flat_box( style, window, state,
0660             shadow, clipRect, widget, detail,
0661             x, y, w, h );
0662 
0663     }
0664 
0665     //_____________________________________________________________________________________
0666     Cairo::Surface processTabCloseButton(GtkWidget* widget, GtkStateType state)
0667     {
0668 
0669         #if OXYGEN_DEBUG
0670         std::cerr << "Oxygen::processTabCloseButton("<<widget<<","<<state <<")"<< std::endl;
0671         #endif
0672 
0673         if(!widget)
0674             return 0L;
0675 
0676         switch (state)
0677         {
0678             case GTK_STATE_NORMAL:
0679             {
0680 
0681                 // check if our button is on active page and if not, make it gray
0682                 GtkNotebook* notebook=GTK_NOTEBOOK(Gtk::gtk_parent_notebook(widget));
0683                 GtkWidget* page=gtk_notebook_get_nth_page(notebook,gtk_notebook_get_current_page(notebook));
0684                 if( !page ) break;
0685 
0686                 GtkWidget* tabLabel=gtk_notebook_get_tab_label(notebook,page);
0687                 if( !tabLabel ) break;
0688 
0689                 if( !Gtk::gtk_widget_is_parent( widget, tabLabel ) ) return Style::instance().tabCloseButton( Disabled );
0690                 else return Style::instance().tabCloseButton( StyleOptions() );
0691 
0692             }
0693 
0694             break;
0695 
0696             case GTK_STATE_ACTIVE: return Style::instance().tabCloseButton( Focus );
0697             case GTK_STATE_PRELIGHT: return Style::instance().tabCloseButton( Hover );
0698             default: break;
0699 
0700         }
0701 
0702         return 0L;
0703 
0704     }
0705 
0706     //___________________________________________________________________________________________________________
0707     static void draw_box( GtkStyle* style,
0708         GdkWindow* window,
0709         GtkStateType state,
0710         GtkShadowType shadow,
0711         GdkRectangle* clipRect,
0712         GtkWidget* widget,
0713         const gchar* detail,
0714         gint x,
0715         gint y,
0716         gint w,
0717         gint h )
0718     {
0719         g_return_if_fail( style && window );
0720 
0721         #if OXYGEN_DEBUG
0722         std::cerr
0723             << "Oxygen::draw_box -"
0724             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
0725             << " state: " << Gtk::TypeNames::state( state )
0726             << " shadow: " << Gtk::TypeNames::shadow( shadow )
0727             << " detail: " << (detail ? detail:"0x0" )
0728             << " rect: " << Gtk::gdk_rectangle( x, y, w, h )
0729             << " thickness: " << style->xthickness << "," << style->ythickness
0730             << std::endl;
0731         #endif
0732 
0733         Style::instance().sanitizeSize( window, w, h );
0734         const Gtk::Detail d( detail );
0735 
0736         // Don't draw anything for OpenOffice or steppers will look like slabs.
0737         if( d.isStepper() && Style::instance().settings().applicationName().isOpenOffice( widget ))
0738         { return; }
0739 
0740         // Don't render window bg here because it's redundant and leads to problems with bg gradient behind buttons
0741         if( GTK_IS_WINDOW(widget) && Style::instance().settings().applicationName().isOpenOffice( widget ))
0742         { return; }
0743 
0744         GtkWidget* parent(0L);
0745         if( d.isInfoBar() )
0746         {
0747 
0748             Style::instance().renderInfoBar( window, clipRect, x, y, w, h, Gtk::gdk_get_color( style->bg[state] ) );
0749 
0750 
0751         } else if( d.isButton() || d.isOptionMenu() || d.isToggleButton() ) {
0752 
0753             // pathbar buttons
0754             if( Gtk::gtk_button_is_in_path_bar(widget) )
0755             {
0756 
0757                 // https://bugzilla.gnome.org/show_bug.cgi?id=635511
0758                 std::string name(G_OBJECT_TYPE_NAME( gtk_widget_get_parent( widget ) ) );
0759                 Style::instance().animations().hoverEngine().registerWidget( widget );
0760 
0761                 // only two style options possible: hover or don't draw
0762                 StyleOptions options;
0763                 const bool reversed( Gtk::gtk_widget_layout_is_reversed( widget ) );
0764                 const bool isLast( Gtk::gtk_path_bar_button_is_last( widget ) );
0765                 if(state!=GTK_STATE_NORMAL && state!=GTK_STATE_INSENSITIVE)
0766                 {
0767                     if( !(state==GTK_STATE_ACTIVE && !Style::instance().animations().hoverEngine().hovered( widget ) ) )
0768                     {
0769                         options |= Hover;
0770                         if( isLast )
0771                         {
0772                             if( reversed )
0773                             {
0774 
0775                                 x += 10;
0776                                 w-=10;
0777 
0778                             } else w -= 10;
0779                         }
0780 
0781                         Style::instance().renderSelection(window,clipRect,x,y,w,h,TileSet::Full,options);
0782                     }
0783                 }
0784 
0785                 if( GTK_IS_TOGGLE_BUTTON(widget) && !isLast )
0786                 {
0787 
0788                     options |= Contrast;
0789 
0790                     if( reversed ) Style::instance().renderArrow(window,NULL,GTK_ARROW_LEFT, x+3,y,5,h,QtSettings::ArrowNormal, options, Palette::WindowText);
0791                     else Style::instance().renderArrow(window,NULL,GTK_ARROW_RIGHT,x+w-8,y,5,h,QtSettings::ArrowNormal, options, Palette::WindowText);
0792 
0793                 }
0794 
0795                 return;
0796 
0797             }
0798 
0799             // treeview headers
0800             if( Gtk::gtk_button_is_header( widget ) )
0801             {
0802 
0803                 // register to scrolled window engine if any
0804                 if(
0805                     ( parent = Gtk::gtk_parent_scrolled_window( widget ) ) &&
0806                     Style::instance().animations().scrolledWindowEngine().contains( parent )
0807                     )
0808                 { Style::instance().animations().scrolledWindowEngine().registerChild( parent, widget ); }
0809 
0810                 // treevew header
0811                 Style::instance().renderHeaderBackground( window, clipRect, x, y, w, h );
0812                 return;
0813 
0814             }
0815 
0816             // combobox entry buttons
0817             if( ( parent = Gtk::gtk_parent_combobox_entry( widget ) ) ) {
0818 
0819                 // combobox entry buttons
0820                 // keep track of whether button is active (pressed-down) or pre-lighted
0821                 const bool buttonActive( state == GTK_STATE_ACTIVE || state == GTK_STATE_PRELIGHT );
0822 
0823                 // get the state from the combobox
0824                 /* this fixes rendering issues when the arrow is disabled, but not the entry */
0825                 state = gtk_widget_get_state(parent);
0826 
0827                 /*
0828                 editable combobox button get a hole (with left corner hidden), and a background
0829                 that match the corresponding text entry background.
0830                 */
0831 
0832                 StyleOptions options( widget, state, shadow );
0833                 if(
0834                     !Style::instance().settings().applicationName().isOpenOffice( widget ) &&
0835                     !Style::instance().settings().applicationName().isGoogleChrome() )
0836                 { options |= NoFill; }
0837 
0838                 if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
0839                 { options |= Blend; }
0840 
0841                 // focus handling
0842                 Style::instance().animations().comboBoxEntryEngine().registerWidget( parent );
0843                 Style::instance().animations().comboBoxEntryEngine().setButton( parent, widget );
0844 
0845                 // background
0846                 int sideMargin( 0 );
0847                 {
0848                     GtkWidget* entry( gtk_bin_get_child( GTK_BIN( parent ) ) );
0849                     GtkStyle* style( gtk_widget_get_style( entry ) );
0850                     sideMargin = std::max( 0, style->xthickness - 2 );
0851                     ColorUtils::Rgba background( Gtk::gdk_get_color( style->base[state] ) );
0852                     Style::instance().fill( window, clipRect, x, y, w, h, background );
0853                 }
0854 
0855                 // update option accordingly
0856                 if( state == GTK_STATE_INSENSITIVE ) options &= ~(Hover|Focus);
0857                 else {
0858 
0859                     Style::instance().animations().comboBoxEntryEngine().setButtonFocus( parent, options & Focus );
0860                     if( Style::instance().animations().comboBoxEntryEngine().hasFocus( parent ) ) options |= Focus;
0861                     else options &= ~Focus;
0862 
0863                     // properly set button hover state. Pressed-down buttons are marked hovered, consistently with Qt
0864                     Style::instance().animations().comboBoxEntryEngine().setButtonHovered( parent, buttonActive );
0865                     if( Style::instance().animations().comboBoxEntryEngine().hovered( parent ) ) options |= Hover;
0866                     else options &= ~Hover;
0867 
0868                 }
0869 
0870                 // render
0871                 TileSet::Tiles tiles( TileSet::Ring);
0872                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( parent, options, AnimationHover|AnimationFocus, AnimationFocus ) );
0873                 if( Gtk::gtk_widget_layout_is_reversed( widget ) )
0874                 {
0875 
0876                     // hide right and adjust width
0877                     tiles &= ~TileSet::Right;
0878                     Style::instance().renderHoleBackground( window, widget, clipRect, x-1, y, w+6, h, tiles, sideMargin );
0879 
0880                     x += sideMargin;
0881                     w -= sideMargin;
0882                     Style::instance().renderHole( window, clipRect, x-1, y, w+8, h, options, data, tiles  );
0883 
0884                 } else {
0885 
0886                     // hide left and adjust width
0887                     tiles &= ~TileSet::Left;
0888                     Style::instance().renderHoleBackground( window, widget, clipRect, x-5, y, w+6, h, tiles, sideMargin );
0889 
0890                     w -= sideMargin;
0891                     Style::instance().renderHole( window, clipRect, x-7, y, w+8, h, options, data, tiles  );
0892 
0893                 }
0894 
0895                 return;
0896 
0897             }
0898 
0899             // combobox buttons
0900             if(
0901                 ( parent = Gtk::gtk_parent_combobox( widget ) ) &&
0902                 !Style::instance().settings().applicationName().isXul( widget ) &&
0903                 Gtk::gtk_combobox_appears_as_list( parent )
0904                 )
0905             {
0906 
0907                 {
0908                     // Set minimum combobox button height if it's smaller
0909                     GtkAllocation alloc;
0910                     gtk_widget_get_allocation(widget,&alloc);
0911                     gtk_widget_get_size_request(widget,&alloc.width,NULL);
0912                     if(alloc.height<22)
0913                         gtk_widget_set_size_request(widget,alloc.width,22);
0914                 }
0915                 // combobox buttons
0916                 const bool reversed( Gtk::gtk_widget_layout_is_reversed( widget ) );
0917 
0918                 StyleOptions options( widget, state, shadow );
0919                 if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
0920                 { options |= Blend; }
0921 
0922                 Style::instance().animations().comboBoxEngine().registerWidget( parent );
0923                 Style::instance().animations().comboBoxEngine().setButton( parent, widget );
0924                 Style::instance().animations().comboBoxEngine().setButtonFocus( parent, options & Focus );
0925 
0926                 if( Gtk::gtk_combobox_has_frame( parent ) )
0927                 {
0928                     if( Style::instance().animations().comboBoxEngine().hovered( parent ) ) options |= Hover;
0929 
0930                     // tiles
0931                     TileSet::Tiles tiles( TileSet::Ring );
0932 
0933                     // animation state
0934                     const AnimationData data( (options&Sunken) ?
0935                         AnimationData():
0936                         Style::instance().animations().widgetStateEngine().get( parent, options ) );
0937 
0938                     if( reversed )
0939                     {
0940 
0941                         tiles &= ~TileSet::Right;
0942                         Style::instance().renderButtonSlab( window, clipRect, x, y, w+7, h, options, data, tiles );
0943 
0944                     } else {
0945 
0946                         tiles &= ~TileSet::Left;
0947                         Style::instance().renderButtonSlab( window, clipRect, x-7, y, w+7, h, options, data, tiles );
0948 
0949                     }
0950 
0951                     return;
0952 
0953                 } else {
0954 
0955                     options |= Flat;
0956                     if( Style::instance().animations().comboBoxEngine().hovered( parent ) ) options |= Hover;
0957                     if( reversed ) Style::instance().renderButtonSlab( window, clipRect, x+1, y, w, h, options );
0958                     else Style::instance().renderButtonSlab( window, clipRect, x-1, y, w, h, options );
0959                     return;
0960 
0961                 }
0962 
0963             }
0964 
0965             // combo button
0966             if( ( parent = Gtk::gtk_parent_combo( widget ) ) )
0967             {
0968 
0969                 StyleOptions options( widget, state, shadow );
0970                 if(!Style::instance().settings().applicationName().useFlatBackground(widget))
0971                 { options |= Blend; }
0972 
0973                 if( Style::instance().settings().applicationName().isOpenOffice( widget ) )
0974                 {
0975 
0976                     // Hover doesn't work correctly in OpenOffice, so disable it
0977                     options &= ~(Hover|Focus);
0978                     TileSet::Tiles tiles( TileSet::Full );
0979                     tiles &= ( ~TileSet::Left );
0980                     Style::instance().renderHole( window, clipRect, x-10, y-1, w+11, h+2, options, tiles );
0981                     return;
0982 
0983                 } else {
0984 
0985                     /*
0986                     make button flat; disable focus and hover
0987                     (this is handled when rendering the arrow
0988                     This doesn't work for OpenOffice.
0989                     */
0990                     options |= Flat;
0991                     options &= ~(Hover|Focus);
0992                     Style::instance().animations().comboEngine().registerWidget( parent );
0993                     return;
0994 
0995                 }
0996 
0997             }
0998 
0999             // notebook close buttons
1000             if( Gtk::gtk_notebook_is_close_button(widget))
1001             {
1002 
1003                 if( gtk_button_get_relief(GTK_BUTTON(widget))==GTK_RELIEF_NONE )
1004                 { gtk_button_set_relief(GTK_BUTTON(widget),GTK_RELIEF_NORMAL); }
1005 
1006                 if( Cairo::Surface surface = processTabCloseButton(widget,state) )
1007                 {
1008 
1009                     // hide previous image
1010                     // show ours instead
1011                     if( GtkWidget* image = Gtk::gtk_button_find_image(widget) )
1012                     { gtk_widget_hide(image); }
1013 
1014                     // center the button image
1015                     int width(0);
1016                     int height(0);
1017                     cairo_surface_get_size( surface, width, height );
1018                     x += (w-width)/2;
1019                     y += (h-height)/2;
1020 
1021                     // render the image
1022                     Cairo::Context context( window, clipRect );
1023                     cairo_set_source_surface( context, surface, x, y);
1024                     cairo_paint(context);
1025 
1026                 }
1027 
1028                 return;
1029 
1030             }
1031 
1032             #if GTK_CHECK_VERSION(2, 20, 0)
1033             // tool itemgroup buttons
1034             if( GTK_IS_TOOL_ITEM_GROUP( widget ) ) return;
1035             #endif
1036 
1037             // for google chrome, make GtkChromeButton appear as flat
1038             if(
1039                 Style::instance().settings().applicationName().isGoogleChrome() &&
1040                 !Gtk::gtk_button_is_flat( widget ) &&
1041                 Gtk::g_object_is_a( G_OBJECT( widget ), "GtkChromeButton" ) )
1042             { gtk_button_set_relief( GTK_BUTTON( widget ), GTK_RELIEF_NONE ); }
1043 
1044             // options
1045             StyleOptions options( widget, state, shadow );
1046             if(!Style::instance().settings().applicationName().useFlatBackground(widget))
1047             { options |= Blend; }
1048 
1049             // default case
1050             if( style )
1051             { options._customColors.insert( options&Flat ? Palette::Window:Palette::Button, Gtk::gdk_get_color( style->bg[state] ) ); }
1052 
1053             // flat buttons
1054             bool useWidgetState( true );
1055             AnimationData data;
1056             // Such small buttons should rather be flat for OpenOffice (the only ones present there seem
1057             // to be the navigation buttons under vertical scrollbar in main window)
1058             bool ooFlat(Style::instance().settings().applicationName().isOpenOffice() && w<20 && h<20 && w==h);
1059             // LibO formula entry expand expand button is very small, would look better if rendered flat
1060             bool ooFormulaExpand(Style::instance().settings().applicationName().isOpenOffice() && w==16);
1061 
1062             if( (widget && Gtk::gtk_button_is_flat( widget )) || ooFlat || ooFormulaExpand )
1063             {
1064 
1065                 // set button as flat and disable focus
1066                 options |= Flat;
1067                 options &= ~Focus;
1068 
1069                 if(!Style::instance().settings().applicationName().isOpenOffice())
1070                 {
1071                     // register to Hover engine and check state
1072                     Style::instance().animations().hoverEngine().registerWidget( widget );
1073                     if( (options&Hover) )  Style::instance().animations().hoverEngine().setHovered( widget, true );
1074                     else if( Style::instance().animations().hoverEngine().hovered( widget ) ) options |= Hover;
1075 
1076                     // register to ToolBarState engine
1077                     ToolBarStateEngine& engine( Style::instance().animations().toolBarStateEngine() );
1078                     GtkWidget* parent( 0L );
1079 
1080                     bool toolPalette(false);
1081                     #if GTK_CHECK_VERSION(2,20,0)
1082                     toolPalette=Gtk::gtk_widget_find_parent( widget, GTK_TYPE_TOOL_PALETTE );
1083                     #endif
1084 
1085                     if( !toolPalette && (parent = engine.findParent( widget ) ) )
1086                     {
1087 
1088                         // register child
1089                         engine.registerChild( parent, widget, options&Hover );
1090                         useWidgetState = false;
1091 
1092                         if( engine.animatedRectangleIsValid( parent ) && !(options&Sunken) ) {
1093 
1094                             return;
1095 
1096                         } if( engine.widget( parent, AnimationCurrent ) == widget ) {
1097 
1098                             data = engine.animationData( parent, AnimationCurrent );
1099 
1100                             if( engine.isLocked( parent ) ) options |= Hover;
1101 
1102                         } else if( (options & Sunken ) && engine.widget( parent, AnimationPrevious ) == widget ) {
1103 
1104                             data = engine.animationData( parent, AnimationPrevious );
1105 
1106                         }
1107 
1108                     }
1109                 }
1110                 else if(ooFlat)
1111                 {
1112                     // Fill with bottom color because the buttons are most likely at the bottom
1113                     Cairo::Context context(window);
1114                     cairo_set_source(context,ColorUtils::backgroundBottomColor( Style::instance().settings().palette().color( Palette::Window )));
1115                     cairo_rectangle(context,x,y,w,h);
1116                     cairo_fill(context);
1117                 }
1118 
1119             }
1120 
1121             // retrieve animation
1122             if( useWidgetState )
1123             { data = Style::instance().animations().widgetStateEngine().get( widget, options ); }
1124 
1125             if(Style::instance().settings().applicationName().isOpenOffice())
1126                 Style::instance().renderWindowBackground(window,clipRect,x,y,w,h);
1127             // render
1128             Style::instance().renderButtonSlab( window, clipRect, x, y, w, h, options, data );
1129 
1130         } else if( d.isMenuBar() ) {
1131 
1132             if( !Style::instance().settings().applicationName().useFlatBackground( widget ) &&
1133                 !Gtk::gtk_widget_is_applet( widget ) )
1134             {
1135 
1136                 StyleOptions options;
1137 
1138                 if( style )
1139                 { options._customColors.insert( Palette::Window, Gtk::gdk_get_color( style->bg[state] ) ); }
1140 
1141                 // window background
1142                 Style::instance().renderWindowBackground( window, clipRect, x, y, w, h, options );
1143 
1144                 // possible groupbox background
1145                 if( Gtk::gtk_parent_groupbox( widget ) )
1146                 { Style::instance().renderGroupBoxBackground( window, widget, clipRect, x, y, w, h, Blend ); }
1147 
1148             }
1149             // check animation state
1150             if( GTK_IS_MENU_BAR( widget ) )
1151             {
1152 
1153                 MenuBarStateEngine& engine( Style::instance().animations().menuBarStateEngine() );
1154                 engine.registerWidget(widget);
1155                 if( engine.animatedRectangleIsValid( widget ) )
1156                 {
1157 
1158                     const GdkRectangle& rect( engine.animatedRectangle( widget ) );
1159                     StyleOptions options( Hover );
1160                     if( !Style::instance().settings().applicationName().useFlatBackground( widget ) )
1161                     { options |= Blend; }
1162 
1163                     Style::instance().renderMenuItemRect( window, clipRect, engine.widget( widget, AnimationCurrent ), rect.x, rect.y, rect.width, rect.height, options );
1164 
1165                 } else if( engine.isAnimated( widget, AnimationPrevious ) ) {
1166 
1167                     const AnimationData data( engine.animationData( widget, AnimationPrevious ) );
1168                     const GdkRectangle& rect( engine.rectangle( widget, AnimationPrevious ) );
1169                     StyleOptions options( Hover );
1170                     if( !Style::instance().settings().applicationName().useFlatBackground( widget ) )
1171                     { options |= Blend; }
1172 
1173                     Style::instance().renderMenuItemRect( window, clipRect, engine.widget( widget, AnimationPrevious ), rect.x, rect.y, rect.width, rect.height, options, data );
1174 
1175                 }
1176 
1177             }
1178 
1179             return;
1180 
1181         } else if( d.isToolBar() ) {
1182 
1183             // eclipse works ok with animations, though should have flat background
1184             if( Style::instance().settings().applicationName().isEclipse() )
1185             {
1186 
1187                 draw_animated_button( window, clipRect, widget );
1188                 return;
1189 
1190             } else if( Style::instance().settings().applicationName().useFlatBackground( widget ) || Gtk::gtk_widget_is_applet( widget )  ) {
1191 
1192                 return;
1193 
1194             } else {
1195 
1196                 Style::instance().renderWindowBackground( window, clipRect, x, y, w, h );
1197 
1198                 // possible groupbox background
1199                 if( Gtk::gtk_parent_groupbox( widget ) )
1200                 { Style::instance().renderGroupBoxBackground( window, widget, clipRect, x, y, w, h, Blend ); }
1201 
1202                 // also draw possible animated tool button
1203                 draw_animated_button( window, clipRect, widget );
1204                 return;
1205 
1206             }
1207 
1208         } else if( d.isMenu() ) {
1209 
1210             if( GTK_IS_MENU( widget ) && gtk_menu_get_tearoff_state( GTK_MENU( widget ) ) )
1211             {
1212 
1213                 if(
1214                     Gtk::gdk_window_is_base( window ) &&
1215                     !Style::instance().settings().applicationName().isXul( widget ) )
1216                 {
1217                     BackgroundHints hints( BackgroundGradient );
1218                     if( Style::instance().hasBackgroundSurface() ) hints |= BackgroundPixmap;
1219                     Style::instance().animations().backgroundHintEngine().registerWidget( widget, hints );
1220                 }
1221 
1222                 Style::instance().renderWindowBackground( window, widget, clipRect, x, y, w, h );
1223 
1224             } else {
1225 
1226                 StyleOptions options( Menu );
1227 
1228                 // set alpha flag. Special handling is needed for mozilla and openoffice.
1229                 if( Style::instance().settings().applicationName().isXul( widget ) ||
1230                     Style::instance().settings().applicationName().isOpenOffice( widget ) )
1231                 {
1232 
1233                     Style::instance().renderMenuBackground( window, clipRect, x, y, w, h, options );
1234 
1235                     // since menus are rendered square anyway, we can set the alpha channel
1236                     // based on the screen properties only, in order to prevent ugly shadow to be drawn
1237                     if( Gtk::gdk_default_screen_is_composited() ) options |= Alpha;
1238                     Style::instance().drawFloatFrame( window, clipRect, x, y, w, h, options );
1239                     return;
1240                 }
1241 
1242                 options |= Round;
1243                 if( Gtk::gtk_widget_has_rgba( widget ) ) options |= Alpha;
1244 
1245                 if( style )
1246                 { options._customColors.insert( Palette::Window, Gtk::gdk_get_color( style->bg[state] ) ); }
1247 
1248                 // add mask if needed
1249                 if( GTK_IS_MENU(widget) )
1250                 {
1251                     Style::instance().animations().menuItemEngine().registerMenu( widget );
1252 
1253                     WidgetSizeEngine& engine( Style::instance().animations().widgetSizeEngine() );
1254                     engine.registerWidget( widget );
1255                     if( engine.update( widget ) )
1256                     {
1257                         Style::instance().adjustMask( widget, engine.width( widget ), engine.height( widget ), engine.alpha( widget ) );
1258                         if( Style::instance().settings().backgroundOpacity() < 255 )
1259                         { Style::instance().setWindowBlur( widget, engine.alpha( widget ) ); }
1260                     }
1261                 }
1262 
1263                 // if render
1264                 if( !Style::instance().renderMenuBackground( window, clipRect, x, y, w, h, options ) )
1265                 { options &= ~Round; }
1266 
1267                 Style::instance().drawFloatFrame( window, clipRect, x, y, w, h, options );
1268 
1269             }
1270 
1271             // check animation state
1272             if( GTK_IS_MENU( widget ) )
1273             {
1274 
1275                 MenuStateEngine& engine( Style::instance().animations().menuStateEngine() );
1276                 engine.registerWidget(widget);
1277 
1278                 if( engine.animatedRectangleIsValid( widget ) )
1279                 {
1280 
1281                     const GdkRectangle& rect( engine.animatedRectangle( widget ) );
1282                     Style::instance().renderMenuItemRect( window, clipRect, engine.widget( widget, AnimationCurrent ), rect.x, rect.y, rect.width, rect.height, Hover );
1283 
1284                 } else if( engine.isLocked( widget ) ) {
1285 
1286                     const GdkRectangle& rect( engine.rectangle( widget, AnimationCurrent ) );
1287                     Style::instance().renderMenuItemRect( window, clipRect, engine.widget( widget, AnimationCurrent ), rect.x, rect.y, rect.width, rect.height, Hover );
1288 
1289                } else if( engine.isAnimated( widget, AnimationPrevious ) ) {
1290 
1291                     const AnimationData data( engine.animationData( widget, AnimationPrevious ) );
1292                     const GdkRectangle& rect( engine.rectangle( widget, AnimationPrevious ) );
1293                     Style::instance().renderMenuItemRect( window, clipRect, engine.widget( widget, AnimationPrevious ), rect.x, rect.y, rect.width, rect.height, Hover, data );
1294 
1295                  }
1296 
1297             }
1298 
1299 
1300         } else if( d.isMenuScrollArrow() ) {
1301 
1302             return;
1303 
1304         } else if( d.isDefaultButton() || d.isScrollBar() || d.isPaned() || d.isHandleBox() ) {
1305 
1306             return;
1307 
1308         } else if( d.isDockItem() ) {
1309 
1310             // force window background for dock-items. Fixes inkscape docks
1311             Style::instance().renderWindowBackground( window, clipRect, x, y, w, h );
1312 
1313         } else if( d.isMenuItem() ) {
1314 
1315             if( GTK_IS_MENU_ITEM( widget ) )
1316             {
1317                 GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
1318                 Style::instance().animations().menuItemEngine().registerWidget( child );
1319             }
1320 
1321             GtkWidget* parent( gtk_widget_get_parent( widget ) );
1322             AnimationData data;
1323             if( GTK_IS_MENU_BAR( parent ) )
1324             {
1325 
1326                 MenuBarStateEngine& engine = Style::instance().animations().menuBarStateEngine();
1327                 engine.registerWidget( parent );
1328                 if( engine.animatedRectangleIsValid( parent ) )
1329                 {
1330                     return;
1331 
1332                 } else if( engine.widget( parent, AnimationCurrent ) == widget ) {
1333 
1334                     data = engine.animationData( parent, AnimationCurrent );
1335 
1336                 }
1337 
1338             } else if( GTK_IS_MENU( parent ) ) {
1339 
1340                 MenuStateEngine& engine = Style::instance().animations().menuStateEngine();
1341                 engine.registerWidget( parent );
1342                 if( engine.animatedRectangleIsValid( parent ) )
1343                 {
1344                     return;
1345 
1346                 } else if( engine.widget( parent, AnimationCurrent ) == widget ) {
1347 
1348                     data = engine.animationData( parent, AnimationCurrent );
1349 
1350                 }
1351 
1352             }
1353 
1354 
1355             StyleOptions options( widget, state, shadow );
1356             if( !Style::instance().settings().applicationName().useFlatBackground( widget ) )
1357             { options |= Blend; }
1358 
1359             Style::instance().renderMenuItemRect( window, clipRect, widget, x, y, w, h, options, data );
1360 
1361         } else if( d.isTroughAny() && GTK_IS_SCALE( widget ) ) {
1362 
1363             const bool vertical( Gtk::gtk_widget_is_vertical( widget ) );
1364             const int offset( 6 );
1365             if( vertical ) {
1366 
1367                 // TODO: calculate this value from the style "slider-width" property
1368                 if( d.isTrough() ) Style::instance().renderSliderGroove( window, clipRect, x, y + offset, w, h - 2*offset, Vertical );
1369                 else if( d.isTroughLower() ) Style::instance().renderSliderGroove( window, clipRect, x, y + offset, w, h, Vertical );
1370                 else if( d.isTroughUpper() ) Style::instance().renderSliderGroove( window, clipRect, x, y, w, h - offset, Vertical );
1371 
1372             } else {
1373 
1374                 // TODO: calculate this value from the style "slider-width" property
1375                 const int offset( 6 );
1376                 if( d.isTrough() ) Style::instance().renderSliderGroove( window, clipRect, x + offset, y, w - 2*offset, h, StyleOptions() );
1377                 else if( d.isTroughLower() ) Style::instance().renderSliderGroove( window, clipRect, x + offset, y, w, h, StyleOptions() );
1378                 else if( d.isTroughUpper() ) Style::instance().renderSliderGroove( window, clipRect, x, y, w - offset, h, StyleOptions() );
1379 
1380             }
1381 
1382         } else if( d.isTrough() && shadow == GTK_SHADOW_IN ) {
1383 
1384             if( GTK_IS_PROGRESS_BAR( widget ) )
1385             {
1386 
1387                 if( !Style::instance().settings().applicationName().isXul( widget ) &&
1388                     !Style::instance().settings().applicationName().isOpenOffice( widget ) )
1389                 {
1390                     /*
1391                     need to call the parent style implementation here,
1392                     otherwise some uninitialized pixels are present.
1393                     Not sure why
1394                     */
1395                     StyleWrapper::parentClass()->draw_box( style, window, state, shadow, clipRect, widget, detail, x, y, w, h );
1396 
1397                     if( !Gtk::gtk_widget_is_applet( widget ) )
1398                     {
1399 
1400                         Style::instance().renderWindowBackground( window, widget, clipRect, x, y, w, h );
1401 
1402                         // possible groupbox background
1403                         if( Gtk::gtk_parent_groupbox( widget ) )
1404                         { Style::instance().renderGroupBoxBackground( window, widget, clipRect, x, y, w, h, Blend ); }
1405 
1406                     }
1407                 }
1408 
1409                 StyleOptions options;
1410                 if( Gtk::gtk_widget_is_vertical( widget ) ) options |= Vertical;
1411                 Style::instance().renderProgressBarHole( window, clipRect, x, y, w, h, options );
1412 
1413             } else if( GTK_IS_VSCROLLBAR( widget ) ) {
1414 
1415                 if(Style::instance().settings().applicationName().isOpenOffice( widget ) )
1416                 {
1417                     // adjust scrollbar hole since it has wrong geometry in OOo
1418                     y-=1;
1419                 }
1420 
1421 
1422                 Style::instance().adjustScrollBarHole( x, y, w, h, Vertical );
1423                 Style::instance().renderScrollBarHole( window, clipRect, x, y+1, w-1, h-1, Vertical );
1424 
1425             } else if( GTK_IS_HSCROLLBAR( widget ) ) {
1426 
1427                 if(Style::instance().settings().applicationName().isOpenOffice( widget ) )
1428                 {
1429                     // adjust scrollbar hole since it has wrong geometry in OOo
1430                     x-=2; w+=1;
1431                 }
1432 
1433                 Style::instance().adjustScrollBarHole( x, y, w, h, StyleOptions() );
1434                 Style::instance().renderScrollBarHole( window, clipRect, x+1, y, w-2, h-1, StyleOptions() );
1435 
1436             }
1437 
1438         } else if( d.isSpinButton()) {
1439 
1440             StyleOptions options( widget, state, shadow );
1441             options |= Blend;
1442 
1443             if( Style::instance().settings().applicationName().isOpenOffice( widget ) )
1444             {
1445                 // Do nothing for openoffice
1446                 return;
1447             } else {
1448 
1449                 options |= NoFill;
1450                 ColorUtils::Rgba background( Gtk::gdk_get_color( style->base[gtk_widget_get_state(widget)] ) );
1451                 if( Style::instance().settings().applicationName().isXul( widget ) )
1452                 {
1453 
1454                     /*
1455                     for firefox on has to mask out the corners manually,
1456                     because renderholebackground fails
1457                     */
1458                     Cairo::Context context( window, clipRect );
1459                     cairo_rounded_rectangle( context, x-4, y+2, w+3, h-4, 2, CornersRight );
1460                     cairo_set_source( context, background );
1461                     cairo_fill( context );
1462 
1463                     x += 1;
1464                     w += 2;
1465 
1466                 } else Style::instance().fill( window, clipRect, x, y, w, h, background );
1467 
1468             }
1469 
1470             if(
1471                 Style::instance().animations().hoverEngine().contains( widget ) &&
1472                 Style::instance().animations().hoverEngine().hovered( widget ) )
1473             { options |= Hover; }
1474 
1475             TileSet::Tiles tiles( TileSet::Ring);
1476             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );
1477 
1478             const int sideMargin( std::max( 0, style->xthickness - 2 ) );
1479             if( Gtk::gtk_widget_layout_is_reversed( widget ) )
1480             {
1481 
1482                 tiles &= ~TileSet::Right;
1483 
1484                 if( !Style::instance().settings().applicationName().isOpenOffice( widget ) &&
1485                     !Style::instance().settings().applicationName().isXul( widget ) )
1486                 { Style::instance().renderHoleBackground( window, widget, clipRect, x-1, y-1, w+6, h+2, tiles, sideMargin ); }
1487 
1488                 // shrink spinbox entry hole by 3px on right side
1489                 x += sideMargin;
1490                 w -= sideMargin;
1491                 Style::instance().renderHole( window, clipRect, x-1, y-1, w+8, h+2, options, data, tiles );
1492 
1493             } else {
1494 
1495                 tiles &= ~TileSet::Left;
1496 
1497                 if( !Style::instance().settings().applicationName().isOpenOffice( widget ) &&
1498                     !Style::instance().settings().applicationName().isXul( widget ) )
1499                 { Style::instance().renderHoleBackground( window, widget, clipRect, x-5, y-1, w+6, h+2, tiles, sideMargin ); }
1500 
1501                 // shrink spinbox entry hole by 3px on right side
1502                 w -= sideMargin;
1503                 Style::instance().renderHole( window, clipRect, x-7, y-1, w+8, h+2, options, data, tiles );
1504 
1505             }
1506 
1507 
1508         } else if( d.isSpinButtonUp() || d.isSpinButtonDown() )
1509         {
1510 
1511             if( Style::instance().settings().applicationName().isOpenOffice( widget ) )
1512             {
1513                 if(state==GTK_STATE_ACTIVE)
1514                     state=GTK_STATE_NORMAL;
1515                 ColorUtils::Rgba background( Gtk::gdk_get_color( style->base[state] ) );
1516                 Cairo::Context context( window, clipRect );
1517                 StyleOptions options( NoFill );
1518                 options|=Blend;
1519                 TileSet::Tiles tiles( TileSet::Ring );
1520                 tiles &= ~TileSet::Left;
1521                 {
1522                     int W(w-4), Y(y),H(h);
1523                     if(d.isSpinButtonUp())
1524                     {
1525                         tiles &= ~TileSet::Bottom;
1526                         Y+=1;
1527                     }
1528                     else
1529                     {
1530                         tiles &= ~TileSet::Top;
1531                         H-=2;
1532                     }
1533 
1534                     cairo_rounded_rectangle( context, x, Y, W, H, 2, CornersRight );
1535                     cairo_set_source( context, background );
1536                     cairo_fill( context );
1537                 }
1538 
1539                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );
1540                 if(d.isSpinButtonUp())
1541                     Style::instance().renderHole( window, clipRect, x-7, y, w+5, h+6, options, data, tiles );
1542                 else
1543                     Style::instance().renderHole( window, clipRect, x-6, y-7, w+4, h+7, options, data, tiles );
1544                 return;
1545             }
1546 
1547 
1548         } else if( d.isSpinButtonArrow() ) {
1549 
1550             return;
1551 
1552         } else if( d.isBar() ) {
1553 
1554             StyleOptions options( widget, state, shadow );
1555             if(GTK_IS_PROGRESS_BAR(widget))
1556             {
1557 
1558                 // active state must be set by hand cause it is not set by gtk
1559                 if( !gtk_widget_is_sensitive( widget ) )
1560                 { options |= Disabled; }
1561 
1562                 // get orientation
1563                 if( Gtk::gtk_widget_is_vertical( widget ) )
1564                 { options |= Vertical; }
1565 
1566                 /*
1567                 need to adjust rect and clip for altered x/y thickness
1568                 because gtk passes it to the handle and not to the hole
1569                 */
1570                 const int delta_x = 1 - style->xthickness;
1571                 const int delta_y = -style->ythickness;
1572                 x += delta_x; w -= 2*delta_x;
1573                 y += delta_y; h -= 2*delta_y;
1574 
1575                 if( clipRect )
1576                 {
1577                     clipRect->x += delta_x; clipRect->width -= 2*delta_x;
1578                     clipRect->y += delta_y; clipRect->height -= 2*delta_y;
1579                 }
1580 
1581                 if(Style::instance().settings().applicationName().isOpenOffice())
1582                 {
1583                     ++x;
1584                     w-=2;
1585                 }
1586                 // need to adjust rect and clip to handle unexpected x/y thickness values
1587                 Style::instance().renderProgressBarHandle( window, clipRect, x, y, w, h, options );
1588 
1589             } else {
1590 
1591                 // most likely it's progressbar in the list
1592                 // FIXME: is it always the case ? Should we check on TREE_VIEW, CELL_VIEW, like done with scrollbar hole ?
1593                 Style::instance().renderProgressBarHandle( window, clipRect, x-1, y, w+1, h, options );
1594 
1595             }
1596 
1597             return;
1598 
1599         } else if( d.isEntryProgress() ) {
1600 
1601             StyleOptions options( widget, state, shadow );
1602             Style::instance().renderProgressBarHandle( window, clipRect, x-2, y-1, w+4, h+2, options );
1603 
1604         } else if( d.isTroughFillLevel () ) {
1605 
1606             return;
1607 
1608         } else if( d.isRuler() ) {
1609 
1610             Style::instance().renderWindowBackground(window,widget,clipRect,x,y,w,h);
1611 
1612         } else {
1613 
1614             StyleWrapper::parentClass()->draw_box( style, window, state,
1615                 shadow, clipRect, widget, detail,
1616                 x, y, w, h );
1617         }
1618 
1619     }
1620 
1621     //___________________________________________________________________________________________________________
1622     static void draw_shadow(
1623         GtkStyle* style,
1624         GdkWindow* window,
1625         GtkStateType state,
1626         GtkShadowType shadow,
1627         GdkRectangle* clipRect,
1628         GtkWidget* widget,
1629         const gchar* detail,
1630         gint x,
1631         gint y,
1632         gint w,
1633         gint h )
1634     {
1635         g_return_if_fail( style && window );
1636         Style::instance().sanitizeSize( window, w, h );
1637 
1638         #if OXYGEN_DEBUG
1639         std::cerr
1640             << "Oxygen::draw_shadow -"
1641             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
1642             << " state: " << Gtk::TypeNames::state( state )
1643             << " shadow: " << Gtk::TypeNames::shadow( shadow )
1644             << " detail: " << (detail ? detail:"0x0" )
1645             << " rect: " << Gtk::gdk_rectangle( x, y, w, h )
1646             << " thickness: " << style->xthickness << "," << style->ythickness
1647             << std::endl;
1648         #endif
1649 
1650         GtkWidget* parent( 0L );
1651         const Gtk::Detail d( detail );
1652 
1653         // ugly Gnumeric header
1654         if( d.is("GnmItemBarCell") )
1655         { return; }
1656 
1657         // adjust shadow type for some known widgets
1658         if( d.isScrolledWindow() && GTK_IS_SCROLLED_WINDOW( widget ) )
1659         {
1660 
1661             // make sure that scrolled windows containing a treeView have sunken frame
1662             if( shadow != GTK_SHADOW_IN && Gtk::gtk_scrolled_window_force_sunken( widget ) )
1663             {
1664 
1665                 shadow = GTK_SHADOW_IN;
1666                 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( widget ), GTK_SHADOW_IN );
1667 
1668             }
1669 
1670             // register to inner shadow engine
1671             if(
1672                 shadow == GTK_SHADOW_IN &&
1673                 gtk_scrolled_window_get_shadow_type( GTK_SCROLLED_WINDOW( widget ) ) == GTK_SHADOW_IN &&
1674                 Style::instance().animations().innerShadowEngine().contains( widget ) )
1675             { Style::instance().animations().innerShadowEngine().registerChild( widget, gtk_bin_get_child( GTK_BIN( widget ) ) ); }
1676 
1677         } else if(
1678             d.isFrame() &&
1679             ( shadow == GTK_SHADOW_ETCHED_IN || shadow == GTK_SHADOW_ETCHED_OUT ) &&
1680             GTK_IS_FRAME( widget ) &&
1681             Gtk::gtk_scrolled_window_force_sunken( widget )
1682             )
1683         {
1684 
1685             // make sure that entry shadows are drawn
1686             shadow = GTK_SHADOW_IN;
1687             gtk_frame_set_shadow_type( GTK_FRAME( widget ), GTK_SHADOW_IN );
1688 
1689         } else if( d.isEntry() && shadow != GTK_SHADOW_IN ) {
1690 
1691             // make sure that entry shadows are drawn
1692             shadow = GTK_SHADOW_IN;
1693 
1694         }
1695 
1696         // check if it's combobox list window
1697         if( Gtk::gtk_combobox_is_scrolled_window( widget ) && GTK_IS_WINDOW( parent = gtk_widget_get_parent( widget ) ) )
1698         {
1699 
1700             // setup options
1701             StyleOptions options( Round );
1702             if( Gtk::gtk_widget_has_rgba(parent) ) options|=Alpha;
1703             const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( parent ) );
1704 
1705             // always register to widget size engine
1706             WidgetSizeEngine& engine( Style::instance().animations().widgetSizeEngine() );
1707             engine.registerWidget( parent );
1708             const WidgetSizeData::ChangedFlags changedFlags( engine.update( parent ) );
1709             if( changedFlags ) Style::instance().adjustMask( parent, engine.width( parent ), engine.height( parent ), engine.alpha( parent ) );
1710 
1711             #if !ENABLE_INNER_SHADOWS_HACK
1712             if( changedFlags & WidgetSizeData::SizeChanged )
1713             {
1714                 // also sets inner list mask
1715                 if( GtkWidget* child = gtk_bin_get_child( GTK_BIN( widget ) ) )
1716                 {
1717                     const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( child ) );
1718 
1719                     // offset is needed to make combobox list border 3px wide instead of default 2
1720                     // additional pixel is for ugly shadow
1721                     const gint offset( options&Alpha ? 0:1 );
1722                     GdkPixmap* mask( Style::instance().helper().roundMask(
1723                         allocation.width - 2*offset,
1724                         allocation.height - 2*offset,
1725                         3 ) );
1726 
1727                     gdk_window_shape_combine_mask( gtk_widget_get_window( child ), mask, offset, offset );
1728                     gdk_pixmap_unref( mask );
1729                 }
1730             }
1731             #endif
1732 
1733             // menu background and float frame
1734             GdkWindow* parentWindow( gtk_widget_get_window( parent ) );
1735             Style::instance().renderMenuBackground( parentWindow, clipRect, allocation.x, allocation.y, allocation.width, allocation.height, options );
1736             Style::instance().drawFloatFrame( parentWindow, clipRect, allocation.x, allocation.y, allocation.width, allocation.height, options );
1737 
1738             return;
1739 
1740         } else if( d.isBase() && GTK_IS_MENU( widget ) ) {
1741 
1742                 // this is to prevent mozilla to
1743                 // draw yet another frame around menus
1744                 return;
1745 
1746         } else if( Gtk::gtk_combo_is_viewport( widget ) ) {
1747 
1748             return;
1749 
1750         } else if( Gtk::gtk_combo_is_frame( widget ) ) {
1751 
1752             // make GtkCombo list look a bit better
1753             // retrieve proper parent and check
1754             GtkWidget* parent=gtk_widget_get_parent(widget);
1755             if( parent ) parent=gtk_widget_get_parent(parent);
1756             if( !( parent && GTK_IS_WINDOW(parent) ) ) return;
1757 
1758             // setup options
1759             StyleOptions options( Round );
1760             if( Gtk::gtk_widget_has_rgba(parent) ) options|=Alpha;
1761 
1762             // make background window rounded
1763             WidgetSizeEngine& engine( Style::instance().animations().widgetSizeEngine() );
1764             engine.registerWidget( parent );
1765             if( engine.update(parent) )
1766             { Style::instance().adjustMask( parent, engine.width( parent ), engine.height( parent ), engine.alpha( parent ) ); }
1767 
1768             // menu background and float frame
1769             Style::instance().renderMenuBackground( window, clipRect, x, y, w, h, options );
1770             Style::instance().drawFloatFrame( window, clipRect, x, y, w, h, options );
1771 
1772             return;
1773 
1774         } else if( d.isSlider() || d.isRuler() || d.isDragAndDrop() ) {
1775 
1776             return;
1777 
1778         } else if( ( d.isEntry() || d.isViewport() || d.isScrolledWindow() ) && shadow == GTK_SHADOW_IN ) {
1779 
1780             StyleOptions options( widget, state, shadow );
1781             options |= NoFill;
1782 
1783             if( GtkWidget* parent = Gtk::gtk_parent_combobox_entry( widget ) )
1784             {
1785 
1786                 // check if parent is in style map
1787                 Style::instance().animations().comboBoxEntryEngine().registerWidget( parent );
1788                 Style::instance().animations().comboBoxEntryEngine().setEntry( parent, widget );
1789                 Style::instance().animations().comboBoxEntryEngine().setEntryFocus( parent, options & Focus );
1790 
1791                 if( Style::instance().animations().comboBoxEntryEngine().hasFocus( parent ) ) options |= Focus;
1792                 else options &= ~Focus;
1793 
1794                 if(  Style::instance().animations().comboBoxEntryEngine().hovered( parent ) ) options |= Hover;
1795                 else options &= ~Hover;
1796 
1797                 // render
1798                 TileSet::Tiles tiles( TileSet::Ring );
1799                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( parent, options, AnimationHover|AnimationFocus, AnimationFocus ) );
1800                 const int sideMargin( std::max( 0, style->xthickness - 2 ) );
1801                 if( Gtk::gtk_widget_layout_is_reversed( widget ) )
1802                 {
1803 
1804                     tiles &= ~TileSet::Left;
1805                     Style::instance().renderHoleBackground( window, widget, clipRect, x-6, y, w+7, h, tiles, sideMargin );
1806 
1807                     w -= sideMargin;
1808                     Style::instance().renderHole( window, clipRect, x-8, y, w+9, h, options, data, tiles );
1809 
1810                 } else {
1811 
1812                     tiles &= ~TileSet::Right;
1813                     Style::instance().renderHoleBackground( window, widget, clipRect, x-1, y, w+7, h, tiles, sideMargin );
1814 
1815                     x += sideMargin;
1816                     w -= sideMargin;
1817                     Style::instance().renderHole( window, clipRect, x-1, y, w+9, h, options, data, tiles );
1818 
1819                 }
1820 
1821             } else if( GTK_IS_SPIN_BUTTON( widget ) ) {
1822 
1823                 // register to hover engine
1824                 Style::instance().animations().hoverEngine().registerWidget( widget, true );
1825                 if( Style::instance().animations().hoverEngine().hovered( widget ) )
1826                 { options |= Hover; }
1827 
1828                 if( !Style::instance().settings().applicationName().isXul( widget ) )
1829                 {
1830 
1831                     // fill the inside of the spinbox manually
1832                     ColorUtils::Rgba background( Gtk::gdk_get_color( style->base[gtk_widget_get_state( widget )] ) );
1833                     if( Style::instance().settings().applicationName().isOpenOffice( widget ) )
1834                     {
1835 
1836                         // for openoffice on has to properly round the corners
1837                         Cairo::Context context( window, clipRect );
1838                         cairo_rounded_rectangle( context, x+1, y+1, w-1, h-3, 2, CornersLeft );
1839                         cairo_set_source( context, background );
1840                         cairo_fill( context );
1841 
1842                     } else {
1843 
1844                         Style::instance().fill( window, clipRect, x, y, w, h, background );
1845 
1846                     }
1847 
1848                 }
1849 
1850                 // vertical alignment
1851                 if( !Style::instance().settings().applicationName().isOpenOffice( widget ) )
1852                 { y-=1; h+=2; }
1853 
1854                 // basic adjustments
1855                 x-=1; w+=2;
1856 
1857                 // animation data
1858                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );
1859 
1860                 TileSet::Tiles tiles( TileSet::Ring );
1861 
1862                 const int sideMargin( std::max( 0, style->xthickness - 2 ) );
1863                 if( Gtk::gtk_widget_layout_is_reversed( widget ) )
1864                 {
1865 
1866                     tiles &= ~TileSet::Left;
1867 
1868                     if( !Style::instance().settings().applicationName().isOpenOffice( widget ) )
1869                     {
1870                         Style::instance().renderHoleBackground( window, widget, clipRect, x, y, w, h, tiles, sideMargin );
1871                         w-= sideMargin;
1872                     }
1873 
1874                     Style::instance().renderHole( window, clipRect, x-7, y, w+7, h, options, data, tiles );
1875 
1876                 } else {
1877 
1878                     tiles &= ~TileSet::Right;
1879 
1880                     if( !Style::instance().settings().applicationName().isOpenOffice( widget ) )
1881                     {
1882                         Style::instance().renderHoleBackground( window, widget, clipRect, x, y, w, h, tiles, sideMargin );
1883                         x += sideMargin;
1884                         w -= sideMargin;
1885                     }
1886 
1887                     Style::instance().renderHole( window, clipRect, x, y, w+7, h, options, data, tiles );
1888 
1889                 }
1890 
1891             } else {
1892 
1893                 if( Style::instance().settings().applicationName().isGoogleChrome() && GTK_IS_HBOX( widget ) )
1894                 { options &= ~NoFill; }
1895 
1896                 // register to hover engine
1897                 if( GTK_IS_ENTRY( widget ) && !Style::instance().settings().applicationName().isOpenOffice( widget ) )
1898                 {
1899 
1900                     Style::instance().animations().hoverEngine().registerWidget( widget, true );
1901                     if( Style::instance().animations().hoverEngine().hovered( widget ) )
1902                     { options |= Hover; }
1903 
1904                 } else if( GTK_IS_SCROLLED_WINDOW( widget ) ) {
1905 
1906                     Style::instance().animations().scrolledWindowEngine().registerWidget( widget );
1907 
1908                     options &= ~(Hover|Focus);
1909                     if( Style::instance().animations().scrolledWindowEngine().focused( widget ) ) options |= Focus;
1910                     if( Style::instance().animations().scrolledWindowEngine().hovered( widget ) ) options |= Hover;
1911 
1912 
1913                 } else {
1914 
1915                     options &= ~(Hover|Focus);
1916 
1917                 }
1918 
1919                 // Do nothing for OpenOffice
1920                 if(d.isEntry() && Style::instance().settings().applicationName().isOpenOffice())
1921                     return;
1922                 // OpenOffice or Chromium address bar
1923                 if( (widget && GTK_IS_HBOX(widget) && Style::instance().settings().applicationName().isGoogleChrome()) ||
1924                         Style::instance().settings().applicationName().isOpenOffice() )
1925                 {
1926 
1927                     if( d.isEntry() )
1928                     {
1929 
1930                         options &= ~NoFill;
1931                         Style::instance().renderHoleBackground( window, widget, clipRect, x-1, y-1, w+2, h+2 );
1932                         Style::instance().renderHole( window, clipRect, x-1, y-1, w+2, h+2, options );
1933 
1934                     } else {
1935 
1936                         Style::instance().renderHole( window, clipRect, x, y, w, h, options );
1937 
1938                     }
1939 
1940                 } else {
1941 
1942                     // basic adjustments
1943                     x-=1; y-=1;
1944                     w+=2; h+=2;
1945 
1946                     const int sideMargin( std::max( 0, style->xthickness - 2 ) );
1947                     if( !Style::instance().settings().applicationName().isXul( widget ) )
1948                     { Style::instance().renderHoleBackground( window, widget, clipRect, x, y, w, h, TileSet::Full, sideMargin ); }
1949 
1950                     // shrink entry by 3px at each side
1951                     if( d.isEntry() )
1952                     {
1953 
1954                         x += sideMargin;
1955                         w -= 2*sideMargin;
1956 
1957                     }
1958 
1959                     // animation
1960                     const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );
1961                     if(!Style::instance().animations().innerShadowEngine().contains(widget) || shadow!=GTK_SHADOW_IN)
1962                     {
1963 
1964                         Style::instance().renderHole( window, clipRect, x, y, w, h, options, data );
1965 
1966                     } else {
1967 
1968                         Style::instance().renderHole( window, clipRect, x+1, y+1, w-2, h-2, options, data );
1969 
1970                     }
1971 
1972                 }
1973 
1974             }
1975 
1976             return;
1977 
1978         } else if( ( d.isTrough() || d.isBar() ) && GTK_IS_PROGRESS_BAR( widget ) ) {
1979 
1980             return;
1981 
1982         } else if (GTK_IS_NOTEBOOK(widget)) {
1983 
1984             if( !Style::instance().settings().applicationName().isOpenOffice( widget ) )
1985             {
1986                 Style::instance().renderWindowBackground( window, clipRect, x-4, y-4, w+8, h+8 );
1987                 draw_animated_button( window, clipRect, widget );
1988             }
1989 
1990             if( gtk_notebook_get_show_tabs( GTK_NOTEBOOK( widget ) ) )
1991             {
1992 
1993                 Style::instance().renderSlab(window,clipRect,x-1,y-1,w+2,h+2,NoFill);
1994 
1995             }
1996 
1997         } else if( GTK_IS_CALENDAR( widget ) && shadow == GTK_SHADOW_OUT ) {
1998 
1999             // calendar header
2000             if( style )
2001             {
2002                 Style::instance().fill( window,clipRect,x-2,y-2,w+4,h+4, Gtk::gdk_get_color( style->base[state] ) );
2003                 Style::instance().renderWindowBackground( window, widget, clipRect,x+2,y+2,w-4,h-6 );
2004             }
2005 
2006             StyleOptions options( NoFill );
2007             if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
2008             { options |= Blend; }
2009 
2010             Style::instance().renderSlab(window,clipRect,x-2,y-2,w+4,h+2, options );
2011 
2012         } else if(
2013             (parent = Gtk::gtk_parent_combobox( widget )) &&
2014             !GTK_IS_CELL_VIEW( widget ) &&
2015             !Style::instance().settings().applicationName().isXul( widget ) ) {
2016 
2017             Style::instance().animations().comboBoxEngine().registerWidget( parent );
2018             Style::instance().animations().comboBoxEngine().registerChild( parent, widget );
2019             GtkShadowType shadow( Style::instance().animations().comboBoxEngine().pressed( parent ) ? GTK_SHADOW_IN:GTK_SHADOW_OUT );
2020 
2021             StyleOptions options( widget, state, shadow );
2022             if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
2023             { options |= Blend; }
2024 
2025             if( Style::instance().animations().comboBoxEngine().hasFocus( parent ) ) options |= Focus;
2026             else options &= ~Focus;
2027 
2028             if(  Style::instance().animations().comboBoxEngine().hovered( parent ) ) options |= Hover;
2029             else options &= ~Hover;
2030 
2031             // animation state
2032             const AnimationData data( (options&Sunken) ? AnimationData():Style::instance().animations().widgetStateEngine().get( parent, options ) );
2033 
2034             // tiles
2035             TileSet::Tiles tiles( TileSet::Ring );
2036 
2037             if( Gtk::gtk_widget_layout_is_reversed( widget ) )
2038             {
2039 
2040                 tiles &= ~TileSet::Left;
2041                 Style::instance().renderButtonSlab( window, clipRect, x-10, y, w+10, h, options, data, tiles );
2042 
2043             } else {
2044 
2045                 tiles &= ~TileSet::Right;
2046                 Style::instance().renderButtonSlab( window, clipRect, x, y, w+10, h, options, data, tiles );
2047 
2048             }
2049 
2050         } else if( d.isNull() && (GTK_IS_TREE_VIEW(widget) || GTK_IS_CELL_VIEW(widget)) && shadow==GTK_SHADOW_IN ) {
2051 
2052             // it's likely progressbar hole
2053             // FIXME: is it enough to check for TreeView? is shadow_in the only possible case?
2054             Style::instance().renderProgressBarHole( window, clipRect, x-2, y, w+3, h, StyleOptions() );
2055 
2056         } else if(Style::instance().settings().applicationName().isOpenOffice() && x==0 && y==0)
2057         {
2058             StyleOptions options(Blend);
2059             if( Gtk::gdk_default_screen_is_composited() ) options |= Alpha;
2060             Style::instance().drawFloatFrame( window, clipRect, x,y,w,h,options);
2061             return;
2062         } else if( shadow == GTK_SHADOW_IN && !Gtk::gtk_parent_statusbar( widget ) ) {
2063 
2064             if( GTK_IS_FRAME( widget ) )
2065             {
2066 
2067                 /*
2068                 check for scrolled windows embedded in frames, that contain a treeview.
2069                 if found, change the shadowtypes for consistency with normal -sunken- scrolled windows.
2070                 this should improve rendering of most mandriva drake tools
2071                 */
2072                 GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
2073                 if(
2074                     GTK_IS_SCROLLED_WINDOW( child ) &&
2075                     GTK_IS_TREE_VIEW( gtk_bin_get_child( GTK_BIN( child ) ) ) )
2076                 {
2077                     gtk_frame_set_shadow_type( GTK_FRAME( widget ), GTK_SHADOW_NONE );
2078 
2079                     // also change scrolled window shadow if needed
2080                     GtkScrolledWindow* scrolledWindow(GTK_SCROLLED_WINDOW( child ) );
2081                     if( gtk_scrolled_window_get_shadow_type( scrolledWindow ) != GTK_SHADOW_IN )
2082                     {
2083                         gtk_scrolled_window_set_shadow_type( scrolledWindow, GTK_SHADOW_IN );
2084                         if( Style::instance().animations().innerShadowEngine().contains( child ) )
2085                         { Style::instance().animations().innerShadowEngine().registerChild( child, gtk_bin_get_child( GTK_BIN( child ) ) ); }
2086                     }
2087 
2088                     return;
2089 
2090                 }
2091 
2092             }
2093 
2094             // default shadow_in frame
2095             // hole background is needed for some special cases
2096             if( GTK_IS_CALENDAR( widget ) )
2097             {
2098 
2099                 const int sideMargin( std::max( 0, style->xthickness - 2 ) );
2100                 Style::instance().renderHoleBackground(
2101                     window, widget, clipRect,
2102                     x-1-sideMargin, y-1, w+2+2*sideMargin, h+2,
2103                     TileSet::Full, sideMargin );
2104             }
2105 
2106             // hole
2107             Style::instance().renderHole( window, clipRect, x-1, y-1, w+2, h+2, NoFill );
2108 
2109         } else if( (shadow == GTK_SHADOW_ETCHED_IN || shadow == GTK_SHADOW_ETCHED_OUT) && !Gtk::gtk_parent_button( widget )) {
2110 
2111             // default etched frame
2112             Style::instance().renderDockFrame( window, clipRect, x, y+1, w, h-2, Blend );
2113 
2114         } else if( shadow == GTK_SHADOW_OUT ) {
2115 
2116             if( d.isFrame() && Gtk::gtk_widget_is_groupbox( widget ) )
2117             {
2118 
2119                 Style::instance().renderGroupBoxFrame( window, widget, clipRect, x-1, y-1, w+2, h+2, Blend );
2120 
2121             } else {
2122 
2123                 Style::instance().renderSlab( window, clipRect, x-1, y-1, w+2, h+2, NoFill );
2124 
2125             }
2126 
2127         }
2128 
2129         return;
2130     }
2131 
2132     //___________________________________________________________________________________________________________
2133     static void draw_check( GtkStyle* style,
2134         GdkWindow* window,
2135         GtkStateType state,
2136         GtkShadowType shadow,
2137         GdkRectangle* clipRect,
2138         GtkWidget* widget,
2139         const gchar* detail,
2140         gint x,
2141         gint y,
2142         gint w,
2143         gint h )
2144     {
2145         g_return_if_fail( style && window );
2146 
2147         Style::instance().sanitizeSize( window, w, h );
2148 
2149         #if OXYGEN_DEBUG
2150         std::cerr
2151             << "Oxygen::draw_check -"
2152             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2153             << " state: " << Gtk::TypeNames::state( state )
2154             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2155             << " detail: " << (detail ? detail:"0x0" )
2156             << std::endl;
2157         #endif
2158 
2159         const Gtk::Detail d( detail );
2160         if( d.isCheckButton() || d.isCellCheck() )
2161         {
2162 
2163             StyleOptions options( widget, state, shadow );
2164 
2165             // this ensures that hover keeps precedence of focus for pressed down buttons
2166             if( state == GTK_STATE_ACTIVE ) options |= Hover;
2167 
2168             // test whether blending should be enabled
2169             if( !(
2170                 d.isCellCheck() ||
2171                 Gtk::gtk_parent_tree_view( widget ) ||
2172                 Gtk::gtk_widget_has_custom_background( widget ) ||
2173                 Style::instance().settings().applicationName().useFlatBackground( widget )
2174                 ) )
2175             { options |= Blend; }
2176 
2177             AnimationData data;
2178             if( d.isCellCheck() )
2179             {
2180 
2181                 /*
2182                 TODO: use dedicated engine to handle animations.
2183                 It should use Widget and CellInfo for tagging, and work like
2184                 TabWidgetState engine
2185                 */
2186                 options &= ~(Focus|Hover);
2187                 if( GTK_IS_TREE_VIEW( widget ) )
2188                 {
2189                     GtkTreeView* treeView( GTK_TREE_VIEW( widget ) );
2190                     const Gtk::CellInfo cellInfo( treeView, x, y, w, h );
2191                     if( cellInfo.isValid() &&
2192                         Style::instance().animations().treeViewEngine().contains( widget ) &&
2193                         Style::instance().animations().treeViewEngine().isCellHovered( widget, cellInfo, false ) )
2194                     { options |= Hover; }
2195 
2196                     // disable active flag, which is not set properly for listviews
2197                     options &= ~Active;
2198 
2199                     // retrieve animation state
2200                     data = Style::instance().animations().treeViewStateEngine().get( widget, cellInfo, options );
2201 
2202                 }
2203 
2204             } else {
2205 
2206                 // retrieve animation state
2207                 data = Style::instance().animations().widgetStateEngine().get( widget, options );
2208 
2209             }
2210 
2211             if( Style::instance().settings().applicationName().isXul( widget ) )
2212             {
2213                 StyleWrapper::xulInfo().setType( XulInfo::CheckBox );
2214                 StyleWrapper::xulInfo().setRect( Gtk::gdk_rectangle( x, y, w, h ) );
2215             }
2216 
2217             Style::instance().renderCheckBox( window, clipRect, x, y, w, h, shadow, options, data );
2218 
2219         } else if( d.isCheck() && ( GTK_IS_CHECK_MENU_ITEM( widget ) || /* for LibreOffice */GTK_IS_MENU_ITEM( widget ) ) ) {
2220 
2221             // Fix cliprect for LibreOffice
2222             if( clipRect && GTK_IS_MENU_ITEM(widget))
2223             { ++clipRect->width; }
2224 
2225             StyleOptions options( widget, state, shadow );
2226             options |= (Blend|Flat|NoFill);
2227             Style::instance().renderCheckBox( window, clipRect, x, y, w, h, shadow, options );
2228 
2229         } else {
2230 
2231             StyleWrapper::parentClass()->draw_check( style, window, state,
2232                 shadow, clipRect, widget, detail,
2233                 x, y, w, h );
2234         }
2235 
2236     }
2237 
2238     //___________________________________________________________________________________________________________
2239     static void draw_option( GtkStyle* style,
2240         GdkWindow* window,
2241         GtkStateType state,
2242         GtkShadowType shadow,
2243         GdkRectangle* clipRect,
2244         GtkWidget* widget,
2245         const gchar* detail,
2246         gint x,
2247         gint y,
2248         gint w,
2249         gint h )
2250     {
2251         g_return_if_fail( style && window );
2252 
2253         Style::instance().sanitizeSize( window, w, h );
2254 
2255         #if OXYGEN_DEBUG
2256         std::cerr
2257             << "Oxygen::draw_option -"
2258             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2259             << " state: " << Gtk::TypeNames::state( state )
2260             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2261             << " detail: " << (detail ? detail:"0x0" )
2262             << std::endl;
2263         #endif
2264 
2265         Gtk::Detail d( detail );
2266         if( d.isRadioButton() )
2267         {
2268 
2269             StyleOptions options( widget, state, shadow );
2270 
2271             // this ensures that hover keeps precedence of focus for pressed down buttons
2272             if( state == GTK_STATE_ACTIVE ) options |= Hover;
2273 
2274             if( !(
2275                 Gtk::gtk_parent_tree_view( widget ) ||
2276                 Gtk::gtk_widget_has_custom_background( widget ) ||
2277                 Style::instance().settings().applicationName().useFlatBackground(widget) ) )
2278             { options |= Blend; }
2279 
2280 
2281 
2282             if( Style::instance().settings().applicationName().isXul( widget ) )
2283             {
2284                 StyleWrapper::xulInfo().setType( XulInfo::RadioButton );
2285                 StyleWrapper::xulInfo().setRect( Gtk::gdk_rectangle( x, y, w, h ) );
2286             }
2287 
2288             // retrieve animation state and render accordingly
2289             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options ) );
2290             Style::instance().renderRadioButton( window, clipRect, x, y, w, h, shadow, options, data );
2291 
2292         } else if( d.isOption() || d.isCellRadio() ) {
2293 
2294             // load options
2295             StyleOptions options( widget, state, shadow );
2296             if( !( d.isCellRadio() || Gtk::gtk_parent_tree_view( widget ) ) )
2297             {
2298                 if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
2299                 { options |= Blend; }
2300 
2301                 if( Gtk::gtk_parent_menu( widget ) )
2302                 {
2303 
2304                     // add menu flag and disable Hover/Focus
2305                     options|=Menu;
2306                     options &= ~(Hover|Focus);
2307                     x-=1;
2308                     y-=1;
2309                     if(Style::instance().settings().applicationName().isOpenOffice())
2310                     {
2311                         // Override the sizes passed by LibreOffice and draw how we want it to look
2312                         // Mostly works OK, but in scrollable menus results in glitches. But scrollable menus have
2313                         // their own glitches, so this seems to be not much of a problem.
2314                         clipRect=0;
2315                         x-=(CheckBox_Size-w)/2;
2316                         y-=(CheckBox_Size-h)/2-1;
2317                         w=CheckBox_Size;
2318                         h=CheckBox_Size;
2319                     }
2320                 }
2321 
2322             }
2323 
2324             AnimationData data;
2325             if( d.isCellRadio() )
2326             {
2327                 /*
2328                 TODO: use dedicated engine to handle animations.
2329                 It should use Widget and CellInfo for tagging, and work like
2330                 TabWidgetState engine
2331                 */
2332                 options &= ~(Focus|Hover);
2333                 if( GTK_IS_TREE_VIEW( widget ) )
2334                 {
2335 
2336                     GtkTreeView* treeView( GTK_TREE_VIEW( widget ) );
2337                     Gtk::CellInfo cellInfo( treeView, x, y, w, h );
2338                     if( cellInfo.isValid() &&
2339                         Style::instance().animations().treeViewEngine().contains( widget ) &&
2340                         Style::instance().animations().treeViewEngine().isCellHovered( widget, cellInfo, false ) )
2341                     { options |= Hover; }
2342 
2343                     // disable active flag, which is not set properly for listviews
2344                     options &= ~Active;
2345 
2346                     data = Style::instance().animations().treeViewStateEngine().get( widget, cellInfo, options );
2347 
2348                 }
2349 
2350             }
2351 
2352             Style::instance().renderRadioButton( window, clipRect, x, y, w, h, shadow, options, data );
2353 
2354         } else {
2355 
2356             StyleWrapper::parentClass()->draw_option( style, window, state,
2357                 shadow, clipRect, widget, detail,
2358                 x, y, w, h );
2359 
2360         }
2361     }
2362 
2363     //___________________________________________________________________________________________________________
2364     static void draw_hline(
2365         GtkStyle* style,
2366         GdkWindow* window,
2367         GtkStateType state,
2368         GdkRectangle* clipRect,
2369         GtkWidget* widget,
2370         const gchar* detail,
2371         gint x1,
2372         gint x2,
2373         gint y )
2374     {
2375         g_return_if_fail( style && window );
2376 
2377         #if OXYGEN_DEBUG
2378         std::cerr
2379             << "Oxygen::draw_hline -"
2380             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2381             << " state: " << Gtk::TypeNames::state( state )
2382             << " detail: " << (detail ? detail:"0x0" )
2383             << std::endl;
2384         #endif
2385 
2386         Gtk::Detail d( detail );
2387         if( d.isVScale() )
2388         {
2389 
2390             return;
2391 
2392         } else if( d.isToolBar() && !Style::instance().settings().toolBarDrawItemSeparator() ) {
2393 
2394             return;
2395 
2396         } else if( d.isTearOffMenuItem() ) {
2397 
2398             if( widget && gtk_widget_get_state( widget ) != GTK_STATE_PRELIGHT )
2399             {
2400                 // render background, this is needed to prevent a plain rect to be rendered (by gtk) where the item is
2401                 // rectangle is adjusted manually so that it matches
2402                 if(
2403                     widget &&
2404                     GTK_IS_MENU( gtk_widget_get_parent( widget ) ) &&
2405                     gtk_menu_get_tearoff_state( GTK_MENU( gtk_widget_get_parent( widget ) ) ) )
2406                 {
2407 
2408                     Style::instance().renderWindowBackground( window, widget, clipRect, x1-4, y-7, x2-x1+10, 20 );
2409 
2410                 } else {
2411 
2412                     Style::instance().renderMenuBackground( window, clipRect, x1-4, y-7, x2-x1+8, 20, Menu );
2413                 }
2414 
2415             }
2416 
2417             // separators
2418             bool accepted( true );
2419             if( widget )
2420             {
2421                 // do not draw side hlines because they conflict with selection rect
2422                 const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) );
2423                 if( x1 <= allocation.x + 5 || x2 >= allocation.x + allocation.width - 5 )
2424                 { accepted = false; }
2425             }
2426 
2427             if( accepted )
2428             { Style::instance().drawSeparator( window, clipRect, x1, y+1, x2-x1, 0, StyleOptions() ); }
2429 
2430         } else {
2431 
2432             StyleOptions options;
2433             if( !Gtk::gtk_parent_tree_view( widget ) )
2434             {
2435                 if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
2436                 { options |= Blend; }
2437 
2438                 if( Gtk::gtk_parent_menu( widget ) ) options |= Menu;
2439             }
2440 
2441             Style::instance().drawSeparator( window, clipRect, x1, y, x2-x1, 0, options );
2442 
2443         }
2444 
2445     }
2446 
2447     //___________________________________________________________________________________________________________
2448     static void draw_vline( GtkStyle* style,
2449         GdkWindow* window,
2450         GtkStateType state,
2451         GdkRectangle* clipRect,
2452         GtkWidget* widget,
2453         const gchar* detail,
2454         gint y1,
2455         gint y2,
2456         gint x )
2457     {
2458         g_return_if_fail( style && window );
2459 
2460         #if OXYGEN_DEBUG
2461         std::cerr
2462             << "Oxygen::draw_vline -"
2463             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2464             << " state: " << Gtk::TypeNames::state( state )
2465             << " detail: " << (detail ? detail:"0x0" )
2466             << std::endl;
2467         #endif
2468 
2469         // disable vline in buttons (should correspond to comboboxes)
2470         Gtk::Detail d( detail );
2471         if( d.isHScale() || Gtk::gtk_parent_button( widget ) ) return;
2472         else if( d.isToolBar() && !Style::instance().settings().toolBarDrawItemSeparator() ) return;
2473         else {
2474 
2475             StyleOptions options( Vertical );
2476             if( !Gtk::gtk_parent_tree_view( widget ) )
2477             {
2478                 if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
2479                 { options |= Blend; }
2480 
2481                 if( Gtk::gtk_parent_menu( widget ) ) options |= Menu;
2482 
2483             }
2484             Style::instance().drawSeparator( window, clipRect, x+1, y1, 0, y2-y1, options );
2485 
2486         }
2487 
2488     }
2489 
2490     //___________________________________________________________________________________________________________
2491     static void draw_arrow( GtkStyle* style,
2492         GdkWindow* window,
2493         GtkStateType state,
2494         GtkShadowType shadow,
2495         GdkRectangle* clipRect,
2496         GtkWidget* widget,
2497         const gchar* detail,
2498         GtkArrowType arrow,
2499         gboolean fill,
2500         gint x,
2501         gint y,
2502         gint w,
2503         gint h )
2504     {
2505 
2506         g_return_if_fail( style && window );
2507         Style::instance().sanitizeSize( window, w, h );
2508 
2509         #if OXYGEN_DEBUG
2510         std::cerr
2511             << "Oxygen::draw_arrow -"
2512             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2513             << " state: " << Gtk::TypeNames::state( state )
2514             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2515             << " arrow: " << Gtk::TypeNames::arrow( arrow )
2516             << " fill: " << (fill ? "true":"false")
2517             << " detail: " << (detail ? detail:"0x0" )
2518             << std::endl;
2519         #endif
2520 
2521         {
2522             // Deal with GimpScaleComboBox misplaced arrow because of entry shrinking
2523             GtkWidget* parent=gtk_widget_get_parent(widget);
2524             if(parent) parent=gtk_widget_get_parent(parent);
2525             if( parent && std::string(G_OBJECT_TYPE_NAME(parent)) == "GimpScaleComboBox")
2526             { x--; }
2527 
2528         }
2529 
2530         const Gtk::Detail d( detail );
2531 
2532         // by default all arrows are animated
2533         QtSettings::ArrowSize arrowSize( QtSettings::ArrowNormal );
2534         if( d.isMenuItem() && Style::instance().settings().applicationName().isXul( widget ) )
2535         { arrowSize = QtSettings::ArrowTiny; }
2536 
2537         // define default color role
2538         Palette::Role role( Palette::ButtonText );
2539 
2540         // define options
2541         StyleOptions options( widget, state );
2542         options |= Contrast;
2543 
2544         // Arrows which are active are painted as hovered
2545         if( state == GTK_STATE_ACTIVE ) options |= Hover;
2546 
2547         // animation data
2548         AnimationData data;
2549 
2550         // if true, widgetStateEngine is used to decide on animation state
2551         // use either custom engine, or disable animation, otherwise
2552         bool useWidgetStateEngine( true );
2553 
2554         GtkWidget* parent( 0L );
2555         if( d.isTearOffMenuItem() )
2556         {
2557             if( widget &&
2558                 gtk_widget_get_state( widget ) != GTK_STATE_PRELIGHT &&
2559                 GTK_IS_MENU( gtk_widget_get_parent( widget ) ) &&
2560                 gtk_menu_get_tearoff_state( GTK_MENU( gtk_widget_get_parent( widget ) ) ) )
2561             { Style::instance().renderWindowBackground( window, widget, clipRect, x-8, y-8, w+16, h+16); }
2562 
2563             // disable highlight in menus, for consistancy with oxygen qt style
2564             options &= ~( Focus|Hover );
2565 
2566             useWidgetStateEngine = false;
2567 
2568         } else if( d.isMenuItem() && !Gtk::gtk_parent_tree_view( widget ) ) {
2569 
2570             // disable highlight in menus, for consistancy with oxygen qt style
2571             options &= ~( Focus|Hover );
2572             role = Palette::WindowText;
2573             useWidgetStateEngine = false;
2574 
2575         } else if( d.isSpinButton() ) {
2576 
2577             // use dedicated engine to get animation state
2578             data = Style::instance().animations().arrowStateEngine().get( widget, arrow, options );
2579             useWidgetStateEngine = false;
2580 
2581             if( Gtk::gtk_widget_layout_is_reversed( widget ) ) x+=1;
2582             else x-=1;
2583 
2584             if( arrow == GTK_ARROW_UP && !Style::instance().settings().applicationName().isOpenOffice( widget ) )
2585             {
2586 
2587                 y+= 1;
2588 
2589             }
2590 
2591             if( arrow == GTK_ARROW_DOWN && Style::instance().settings().applicationName().isOpenOffice( widget ) )
2592             {
2593 
2594                 y-= 1;
2595 
2596             }
2597 
2598             // disable contrast
2599             options &= ~Contrast;
2600 
2601             role = Palette::Text;
2602 
2603         } else if( d.isNotebook() ) {
2604 
2605             // use dedicated engine to get animation state
2606             data = Style::instance().animations().arrowStateEngine().get( widget, arrow, options );
2607             useWidgetStateEngine = false;
2608 
2609             if( GTK_IS_NOTEBOOK( widget ) )
2610             {
2611                 const int offset = 6;
2612                 switch( gtk_notebook_get_tab_pos( GTK_NOTEBOOK( widget ) ) )
2613                 {
2614                     default:
2615                     case GTK_POS_TOP: h += offset; break;
2616                     case GTK_POS_LEFT: w += offset; break;
2617                     case GTK_POS_BOTTOM: y-=offset; h+=offset; break;
2618                     case GTK_POS_RIGHT: x -= offset; w += offset; break;
2619                 }
2620             }
2621 
2622             role = Palette::WindowText;
2623 
2624         } else if( Gtk::gtk_parent_combobox_entry( widget ) ) {
2625 
2626             if( state != GTK_STATE_INSENSITIVE ) options &= ~Contrast;
2627             role = Palette::Text;
2628 
2629             if( Gtk::gtk_widget_layout_is_reversed( widget ) )
2630             { x+=2; }
2631 
2632         } else if( Gtk::gtk_parent_combo( widget ) ) {
2633 
2634             role = Palette::WindowText;
2635 
2636             if( Gtk::gtk_widget_layout_is_reversed( widget ) )
2637             { x+=2; }
2638 
2639         } else if( ( parent = Gtk::gtk_parent_combobox( widget ) ) ) {
2640 
2641             useWidgetStateEngine = false;
2642 
2643             options &= ~( Focus|Hover );
2644             role = Palette::ButtonText;
2645 
2646             if( Gtk::gtk_widget_layout_is_reversed( widget ) )
2647             { x+=2; }
2648 
2649         } else if( ( parent = Gtk::gtk_parent_button( widget ) ) ) {
2650 
2651 
2652             if(!Gtk::gtk_parent_tree_view( widget ) &&
2653                 !Gtk::gtk_parent_combo( widget ) )
2654             {
2655 
2656                 useWidgetStateEngine = false;
2657                 options &= ~( Focus|Hover );
2658 
2659                 if( d.isArrow() && GTK_IS_ARROW( widget ) )
2660                 {
2661 
2662                     x += 1;
2663                     role = Palette::WindowText;
2664                 }
2665 
2666             } else if( Gtk::gtk_button_is_header( parent ) && Style::instance().settings().viewInvertSortIndicator() ) {
2667 
2668                 arrow = (arrow == GTK_ARROW_UP) ? GTK_ARROW_DOWN:GTK_ARROW_UP;
2669 
2670             }
2671 
2672         } else if( GTK_IS_CALENDAR( widget ) ) {
2673 
2674             // FIXME: needs dedicated engine to
2675             // handle smooth animations
2676             useWidgetStateEngine = false;
2677 
2678             if( !Gtk::gtk_widget_is_applet( widget ) )
2679             {
2680 
2681                 // need to render background behind arrows from calendar
2682                 // offsets are empirical
2683                 Style::instance().renderWindowBackground( window, widget, clipRect, x-2, y-3, w+4, h+6 );
2684                 role = Palette::WindowText;
2685 
2686             }
2687 
2688         } else if( GTK_IS_SCROLLBAR( widget ) ) {
2689 
2690             // use dedicated engine to get animation state
2691             useWidgetStateEngine = false;
2692             data = Style::instance().animations().scrollBarStateEngine().get( widget, Gtk::gdk_rectangle( x, y, w, h ), arrow, options );
2693             role = Palette::WindowText;
2694 
2695         }
2696 
2697         // render arrow
2698         if( useWidgetStateEngine ) data = Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover );
2699         Style::instance().renderArrow( window, clipRect, arrow, x, y, w, h, arrowSize, options, data, role );
2700 
2701     }
2702 
2703 
2704     //___________________________________________________________________________________________________________
2705     static void draw_expander(
2706         GtkStyle* style,
2707         GdkWindow* window,
2708         GtkStateType state,
2709         GdkRectangle* clipRect,
2710         GtkWidget* widget,
2711         const char* detail,
2712         gint x,
2713         gint y,
2714         GtkExpanderStyle expanderStyle )
2715     {
2716         g_return_if_fail( style && window );
2717 
2718         #if OXYGEN_DEBUG
2719         std::cerr
2720             << "Oxygen::draw_expander -"
2721             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2722             << " state: " << Gtk::TypeNames::state( state )
2723             << " expander: " << Gtk::TypeNames::expanderStyle( expanderStyle )
2724             << " detail: " << (detail ? detail:"0x0" )
2725             << std::endl;
2726         #endif
2727 
2728         StyleOptions options( widget, state );
2729         const Gtk::Detail d( detail );
2730         const Palette::Role role( d.isTreeView() ? Palette::Text : Palette::WindowText );
2731 
2732         /*
2733         TODO: For TreeViews, use dedicated engine to handle animations.
2734         It should use Widget and CellInfo for tagging, and work like
2735         TabWidgetState engine.
2736         */
2737         AnimationData data;
2738         if( d.isTreeView() && GTK_IS_TREE_VIEW( widget ) )
2739         {
2740             GtkTreeView* treeView( GTK_TREE_VIEW( widget ) );
2741             const Gtk::CellInfo cellInfo( treeView, x-3, y-4, 10, 10 );
2742             data = Style::instance().animations().treeViewStateEngine().get( widget, cellInfo, options );
2743         }
2744 
2745         if( Style::instance().settings().viewDrawTriangularExpander() )
2746         {
2747 
2748             GtkArrowType arrow;
2749             const bool isExpanded( expanderStyle !=GTK_EXPANDER_COLLAPSED && expanderStyle != GTK_EXPANDER_SEMI_COLLAPSED );
2750             if( isExpanded ) arrow = GTK_ARROW_DOWN;
2751             else if( Gtk::gtk_widget_layout_is_reversed( widget ) ) arrow = GTK_ARROW_LEFT;
2752             else arrow = GTK_ARROW_RIGHT;
2753 
2754             const Gtk::Detail d( detail );
2755             if( d.isTreeView() )
2756             {
2757 
2758                 const QtSettings::ArrowSize arrowSize = Style::instance().settings().viewTriangularExpanderSize();
2759                 Style::instance().renderArrow( window, clipRect, arrow, x-3, y-4, 10, 10, arrowSize, options, data, role );
2760 
2761             } else {
2762 
2763                 options |= Contrast;
2764                 const QtSettings::ArrowSize arrowSize = QtSettings::ArrowNormal;
2765                 const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover ) );
2766                 Style::instance().renderArrow( window, clipRect, arrow, x-3, y-5, 10, 10, arrowSize, options, data, role );
2767 
2768             }
2769 
2770         } else if( d.isTreeView() ) {
2771 
2772             Style::instance().renderTreeExpander( window, clipRect, x-3, y-4, 10, 10, expanderStyle, options, data, role );
2773 
2774         } else {
2775 
2776             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover ) );
2777             Style::instance().renderTreeExpander( window, clipRect, x-3, y-5, 10, 10, expanderStyle, options, data, role );
2778 
2779         }
2780 
2781     }
2782 
2783     //___________________________________________________________________________________________________________
2784     static void draw_diamond( GtkStyle* style,
2785         GdkWindow* window,
2786         GtkStateType state,
2787         GtkShadowType shadow,
2788         GdkRectangle* clipRect,
2789         GtkWidget* widget,
2790         const char* detail,
2791         gint x,
2792         gint y,
2793         gint w,
2794         gint h )
2795     {
2796         g_return_if_fail( style && window );
2797         Style::instance().sanitizeSize( window, w, h );
2798 
2799         #if OXYGEN_DEBUG
2800         std::cerr
2801             << "Oxygen::draw_diamond -"
2802             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2803             << " state: " << Gtk::TypeNames::state( state )
2804             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2805             << " detail: " << (detail ? detail:"0x0" )
2806             << std::endl;
2807         #endif
2808 
2809         StyleWrapper::parentClass()->draw_diamond( style, window, state,
2810             shadow, clipRect, widget, detail,
2811             x, y, w, h );
2812     }
2813 
2814     //___________________________________________________________________________________________________________
2815     static void draw_tab( GtkStyle* style,
2816         GdkWindow* window,
2817         GtkStateType state,
2818         GtkShadowType shadow,
2819         GdkRectangle* clipRect,
2820         GtkWidget* widget,
2821         const char* detail,
2822         gint x,
2823         gint y,
2824         gint w,
2825         gint h )
2826     {
2827         g_return_if_fail( style && window );
2828 
2829         Style::instance().sanitizeSize( window, w, h );
2830 
2831         #if OXYGEN_DEBUG
2832         std::cerr
2833             << "Oxygen::draw_tab -"
2834             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2835             << " state: " << Gtk::TypeNames::state( state )
2836             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2837             << " detail: " << (detail ? detail:"0x0" )
2838             << std::endl;
2839         #endif
2840 
2841         Gtk::Detail d( detail );
2842         if( d.isOptionMenuTab() )
2843         {
2844 
2845             // render
2846             GtkArrowType arrow = GTK_ARROW_DOWN;
2847             QtSettings::ArrowSize arrowSize = QtSettings::ArrowNormal;
2848             StyleOptions options( widget, state, shadow );
2849             options |= Contrast;
2850 
2851             // disable hover and focus
2852             options &= ~(Hover|Focus);
2853 
2854             Style::instance().renderArrow( window, clipRect, arrow, x, y, w, h, arrowSize, options );
2855             return;
2856 
2857         } else {
2858 
2859             StyleWrapper::parentClass()->draw_tab( style, window, state,
2860                 shadow, clipRect, widget, detail,
2861                 x, y, w, h );
2862         }
2863 
2864     }
2865 
2866     //___________________________________________________________________________________________________________
2867     static void draw_shadow_gap( GtkStyle* style,
2868         GdkWindow* window,
2869         GtkStateType state,
2870         GtkShadowType shadow,
2871         GdkRectangle* clipRect,
2872         GtkWidget* widget,
2873         const gchar* detail,
2874         gint x,
2875         gint y,
2876         gint w,
2877         gint h,
2878         GtkPositionType position,
2879         gint gap_x,
2880         gint gap_w )
2881     {
2882         g_return_if_fail( style && window );
2883 
2884         Style::instance().sanitizeSize( window, w, h );
2885 
2886         #if OXYGEN_DEBUG
2887         std::cerr
2888             << "Oxygen::draw_shadow_gap -"
2889             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2890             << " state: " << Gtk::TypeNames::state( state )
2891             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2892             << " position: " << Gtk::TypeNames::position( position )
2893             << " detail: " << (detail ? detail:"0x0" )
2894             << std::endl;
2895         #endif
2896 
2897         Gtk::Detail d( detail );
2898         if( d.isFrame() )
2899         {
2900 
2901             const Gtk::Gap gap( gap_x, gap_w, position );
2902             if( shadow == GTK_SHADOW_IN )
2903             {
2904 
2905                 const int sideMargin( std::max( 0, style->xthickness - 2 ) );
2906                 Style::instance().renderHoleBackground( window, widget, clipRect, x-1-sideMargin, y-1, w+2+2*sideMargin, h+2, TileSet::Full, sideMargin );
2907                 Style::instance().renderHole( window, clipRect, x-1, y-1, w+2, h+1, gap, NoFill );
2908 
2909             } else if( shadow == GTK_SHADOW_OUT ) {
2910 
2911                 Style::instance().renderSlab( window, clipRect, x-1, y-4, w+2, h+4, gap, NoFill );
2912 
2913             } else if( shadow == GTK_SHADOW_ETCHED_IN || shadow == GTK_SHADOW_ETCHED_OUT ) {
2914 
2915                 Style::instance().renderDockFrame( window, clipRect, x, y-1, w, h+1, gap, Blend );
2916 
2917             }
2918 
2919             return;
2920 
2921         } else {
2922 
2923             StyleWrapper::parentClass()->draw_shadow_gap( style, window, state,
2924                 shadow, clipRect, widget, detail,
2925                 x, y, w, h,
2926                 position, gap_x, gap_w );
2927         }
2928 
2929     }
2930 
2931     //___________________________________________________________________________________________________________
2932     static void draw_box_gap( GtkStyle* style,
2933         GdkWindow* window,
2934         GtkStateType state,
2935         GtkShadowType shadow,
2936         GdkRectangle* clipRect,
2937         GtkWidget* widget,
2938         const gchar* detail,
2939         gint x,
2940         gint y,
2941         gint w,
2942         gint h,
2943         GtkPositionType position,
2944         gint gap_x,
2945         gint gap_w )
2946     {
2947         g_return_if_fail( style && window );
2948 
2949         Style::instance().sanitizeSize( window, w, h );
2950 
2951         #if OXYGEN_DEBUG
2952         std::cerr
2953             << "Oxygen::draw_box_gap -"
2954             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
2955             << " state: " << Gtk::TypeNames::state( state )
2956             << " shadow: " << Gtk::TypeNames::shadow( shadow )
2957             << " position: " << Gtk::TypeNames::position( position )
2958             << " detail: " << (detail ? detail:"0x0" )
2959             << std::endl;
2960         #endif
2961 
2962         const Gtk::Detail d( detail );
2963         if( d.isNotebook() )
2964         {
2965 
2966             // this might move to drawShadowGap
2967             StyleOptions options( widget, GTK_STATE_NORMAL, shadow );
2968             options |= NoFill;
2969             options &= ~(Hover|Focus);
2970 
2971             if( Style::instance().settings().applicationName().isXul( widget ) )
2972             {
2973 
2974                 Gtk::Gap gap( gap_x, gap_w, position );
2975 
2976                 /*
2977                 firefox calls box_gap twice. Once for the main frame, once for the actual gap
2978                 the second call must be discarded somehow
2979                 */
2980                 if( h>12 )
2981                 { Style::instance().renderSlab( window, clipRect, x, y-3, w, h-4, gap, options ); }
2982 
2983             } else {
2984 
2985                 if( GTK_IS_NOTEBOOK( widget ) && !Gtk::gdk_default_screen_is_composited() )
2986                 {
2987 
2988                     // this trick ensures that tabbar is always redrawn
2989                     Style::instance().animations().tabWidgetEngine().registerWidget( widget );
2990                     Style::instance().animations().tabWidgetEngine().toggleDirty( widget );
2991 
2992                 }
2993 
2994                 Gtk::Gap gap;
2995 
2996                 // need adjustment depending on gap side
2997                 const int adjust = 2;
2998                 switch( position )
2999                 {
3000 
3001                     case GTK_POS_TOP:
3002                     gap = Gtk::Gap( 0, w+2, position );
3003                     y -= adjust;
3004                     h += adjust;
3005                     break;
3006 
3007                     case GTK_POS_BOTTOM:
3008                     gap = Gtk::Gap( 0, w+2, position );
3009                     h += adjust;
3010                     break;
3011 
3012                     case GTK_POS_LEFT:
3013                     gap = Gtk::Gap( 0, h+2, position );
3014                     x -= adjust;
3015                     w +=  adjust;
3016                     break;
3017 
3018                     case GTK_POS_RIGHT:
3019                     gap = Gtk::Gap( 0, h+2, position );
3020                     w += adjust;
3021                     break;
3022 
3023                     default: return;
3024 
3025                 }
3026 
3027                 if(Style::instance().settings().applicationName().isOpenOffice())
3028                     gap.setHeight( 0 );
3029                 else
3030                     gap.setHeight( 8 );
3031                 Style::instance().renderTabBarFrame( window, clipRect, x-1, y-1, w+2, h+2, gap, options );
3032 
3033             }
3034 
3035         } else {
3036 
3037             StyleWrapper::parentClass()->draw_box_gap( style, window, state,
3038                 shadow, clipRect, widget, detail,
3039                 x, y, w, h,
3040                 position, gap_x, gap_w );
3041         }
3042 
3043     }
3044 
3045     //___________________________________________________________________________________________________________
3046     static void draw_slider( GtkStyle* style,
3047         GdkWindow* window,
3048         GtkStateType state,
3049         GtkShadowType shadow,
3050         GdkRectangle* clipRect,
3051         GtkWidget* widget,
3052         const gchar* detail,
3053         gint x,
3054         gint y,
3055         gint w,
3056         gint h,
3057         GtkOrientation orientation )
3058     {
3059         g_return_if_fail( style && window );
3060         Style::instance().sanitizeSize( window, w, h );
3061 
3062         #if OXYGEN_DEBUG
3063         std::cerr
3064             << "Oxygen::draw_slider -"
3065             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3066             << " state: " << Gtk::TypeNames::state( state )
3067             << " shadow: " << Gtk::TypeNames::shadow( shadow )
3068             << " orientation: " << Gtk::TypeNames::orientation( orientation )
3069             << " detail: " << (detail ? detail:"0x0" )
3070             << std::endl;
3071         #endif
3072 
3073         Gtk::Detail d( detail );
3074         if( d.isScale() )
3075         {
3076 
3077             StyleOptions options( widget, state, shadow );
3078 
3079             if(!Style::instance().settings().applicationName().useFlatBackground( widget ))
3080             { options |= Blend; }
3081 
3082             if( GTK_IS_VSCALE( widget ) ) options |= Vertical;
3083 
3084             // retrieve animation state and render accordingly
3085             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options ) );
3086             Style::instance().renderSliderHandle( window, clipRect, x, y, w, h, options, data );
3087 
3088             return;
3089 
3090         } else if( GTK_IS_VSCROLLBAR( widget ) ) {
3091 
3092             StyleOptions options( widget, state, shadow );
3093             if( options&Sunken ) options |= Hover;
3094             options |= Vertical;
3095 
3096             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover ) );
3097             Style::instance().renderScrollBarHandle( window, clipRect, x, y, w-1, h, options, data );
3098 
3099         } else if( GTK_IS_HSCROLLBAR( widget ) ) {
3100 
3101             StyleOptions options( widget, state, shadow );
3102             if( options&Sunken ) options |= Hover;
3103 
3104             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover ) );
3105             Style::instance().renderScrollBarHandle( window, clipRect, x, y, w, h-1, options, data );
3106 
3107         } else {
3108 
3109             StyleWrapper::parentClass()->draw_slider( style, window, state,
3110                 shadow, clipRect, widget, detail,
3111                 x, y, w, h,
3112                 orientation );
3113         }
3114 
3115     }
3116 
3117     //___________________________________________________________________________________________________________
3118     static void draw_extension( GtkStyle* style,
3119         GdkWindow* window,
3120         GtkStateType state,
3121         GtkShadowType shadow,
3122         GdkRectangle* clipRect,
3123         GtkWidget* widget,
3124         const gchar* detail,
3125         gint x,
3126         gint y,
3127         gint w,
3128         gint h,
3129         GtkPositionType position )
3130     {
3131 
3132         g_return_if_fail( style && window );
3133 
3134         Style::instance().sanitizeSize( window, w, h );
3135 
3136         #if OXYGEN_DEBUG
3137         std::cerr
3138             << "Oxygen::draw_extension -"
3139             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3140             << " state: " << Gtk::TypeNames::state( state )
3141             << " shadow: " << Gtk::TypeNames::shadow( shadow )
3142             << " position: " << Gtk::TypeNames::position( position )
3143             << " detail: " << (detail ? detail:"0x0" )
3144             << std::endl;
3145         #endif
3146 
3147         Gtk::Detail d( detail );
3148 
3149         // Will be used for LibreOffice
3150         bool prelight(g_object_get_data(G_OBJECT(window),"libreoffice-tab-is-prelit"));
3151 
3152         if( d.isTab() )
3153         {
3154             StyleOptions options( widget, state, shadow );
3155             if(prelight)
3156                 options|=Hover;
3157             TabOptions tabOptions( widget, state, position, x, y, w, h );
3158 
3159             const bool isCurrentTab( tabOptions & CurrentTab );
3160             bool drawTabBarBase( isCurrentTab );
3161             bool dragInProgress( false );
3162 
3163             /*
3164             see if tab is hovered. This is only done if widget is notebook, and if not running a mozilla
3165             (or open office) app, because the latter do not pass the actual tab rect as argument
3166             */
3167             const bool isXul( Style::instance().settings().applicationName().isXul( widget ) );
3168             const bool isOpenOffice( Style::instance().settings().applicationName().isOpenOffice( widget ) );
3169 
3170             // if passed window is invalid, do not hover
3171             const bool disableHover( !GDK_IS_WINDOW( window ) );
3172 
3173             AnimationData data;
3174             if( GTK_IS_NOTEBOOK( widget ) && !( isXul || isOpenOffice || disableHover ) )
3175             {
3176 
3177                 // make sure widget is registered
3178                 Style::instance().animations().tabWidgetEngine().registerWidget( widget );
3179 
3180                 // get current tab, update tabRect and see if current tab is hovered
3181                 const int tabIndex( Gtk::gtk_notebook_find_tab( widget, x+w/2, y+h/2 ) );
3182                 Style::instance().animations().tabWidgetEngine().updateTabRect( widget, tabIndex, x, y, w, h );
3183                 if( tabIndex == Style::instance().animations().tabWidgetEngine().hoveredTab( widget ) )
3184                 { options |= Hover; }
3185 
3186                 // check tab position and add relevant option flags
3187                 GtkNotebook* notebook( GTK_NOTEBOOK( widget ) );
3188                 if( tabIndex == 0 ) tabOptions |= FirstTab;
3189                 if( tabIndex == gtk_notebook_get_n_pages( notebook ) - 1 ) tabOptions |= LastTab;
3190 
3191                 const int current( gtk_notebook_get_current_page( notebook ) );
3192                 if( tabIndex == current-1 ) tabOptions |= LeftOfSelected;
3193                 else if( tabIndex == current+1 ) tabOptions |= RightOfSelected;
3194 
3195                 // update drag in progress flag
3196                 if( isCurrentTab )
3197                 {
3198                     bool drag( widget && (window != gtk_widget_get_window( widget ) ) );
3199                     Style::instance().animations().tabWidgetEngine().setDragInProgress( widget, drag );
3200                 }
3201 
3202                 dragInProgress = Style::instance().animations().tabWidgetEngine().dragInProgress( widget );
3203 
3204                 // this does not work when the first tab is being grabbed
3205                 if( dragInProgress )
3206                 {
3207                     int firstTabIndex( Gtk::gtk_notebook_find_first_tab( widget ) );
3208                     int focusTabIndex( gtk_notebook_get_current_page( notebook ) );
3209                     drawTabBarBase = (tabIndex == firstTabIndex && !isCurrentTab ) || (firstTabIndex == focusTabIndex && tabIndex == firstTabIndex+1 );
3210                 }
3211 
3212                 if( !isCurrentTab )
3213                 { data = Style::instance().animations().tabWidgetStateEngine().get( widget, tabIndex, options ); }
3214 
3215             }
3216 
3217             if( isOpenOffice )
3218             { x+=1; }
3219 
3220             // render
3221             if( isXul ) tabOptions |= Xul;
3222 
3223             Style::instance().renderTab( window, clipRect, x, y, w, h, position, options, tabOptions, data );
3224 
3225             // render tabbar base if current tab
3226             if( !isOpenOffice && drawTabBarBase )
3227             {
3228 
3229                 const GtkAllocation allocation( Gtk::gtk_widget_get_allocation( widget ) );
3230                 int borderWidth( GTK_IS_CONTAINER( widget ) ? gtk_container_get_border_width( GTK_CONTAINER( widget ) ):0 );
3231                 int xBase( allocation.x + borderWidth );
3232                 int yBase( allocation.y + borderWidth );
3233                 int wBase( allocation.width - 2*borderWidth );
3234                 int hBase( allocation.height - 2*borderWidth );
3235 
3236                 Gtk::Gap gap;
3237                 switch( position )
3238                 {
3239                     case GTK_POS_BOTTOM:
3240                     case GTK_POS_TOP:
3241                     if( !dragInProgress ) gap = Gtk::Gap( x - xBase + 5, w - 6, position );
3242                     yBase = y;
3243                     hBase = h;
3244                     break;
3245 
3246                     case GTK_POS_LEFT:
3247                     case GTK_POS_RIGHT:
3248                     if( !dragInProgress ) gap = Gtk::Gap( y - yBase + 5, h - 6, position );
3249                     xBase = x;
3250                     wBase = w;
3251                     break;
3252 
3253                     default: break;
3254 
3255                 }
3256 
3257                 gap.setHeight( 8 );
3258 
3259                 Style::instance().renderTabBarBase( window, clipRect, xBase-1, yBase-1, wBase+2, hBase+2, position, gap, options, tabOptions );
3260 
3261             }
3262             else if(isOpenOffice && !clipRect )
3263             {
3264                 options&=~Hover;
3265                 Cairo::Context context(window);
3266                 const ColorUtils::Rgba base( Style::instance().settings().palette().color( Palette::Window ) );
3267 
3268                 if(position==GTK_POS_BOTTOM)
3269                 {
3270                     if(isCurrentTab)
3271                     {
3272                         cairo_rectangle(context,x,y,w,h);
3273                         cairo_rectangle_negative(context, x+4, y, w-8, h);
3274                         cairo_clip(context);
3275                         ++y;
3276                     }
3277                     Style::instance().helper().slab( base, 0 ).render( context, x-8, y+h-4, w+17, 15, TileSet::Top );
3278                 }
3279                 else if(position==GTK_POS_TOP)
3280                 {
3281                     if(isCurrentTab)
3282                     {
3283                         cairo_rectangle(context,x-1,y,w+2,h);
3284                         cairo_rectangle_negative(context, x+3, y, w-6, h);
3285                         cairo_clip(context);
3286                         y+=4;
3287                     }
3288                     Style::instance().helper().slab( base, 0 ).render( context, x-8, y-15, w+17, 16, TileSet::Bottom );
3289                 }
3290             }
3291 
3292             if( GTK_IS_NOTEBOOK( widget ) )
3293             { Gtk::gtk_notebook_update_close_buttons(GTK_NOTEBOOK(widget)); }
3294 
3295         }
3296 
3297     }
3298 
3299     //___________________________________________________________________________________________________________
3300     static void draw_focus(
3301         GtkStyle* style,
3302         GdkWindow* window,
3303         GtkStateType state,
3304         GdkRectangle* clipRect,
3305         GtkWidget* widget,
3306         const char* detail,
3307         gint x,
3308         gint y,
3309         gint w,
3310         gint h )
3311     {
3312 
3313         g_return_if_fail( style && window );
3314 
3315         Style::instance().sanitizeSize( window, w, h );
3316 
3317         #if OXYGEN_DEBUG
3318         std::cerr
3319             << "Oxygen::draw_focus -"
3320             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3321             << " state: " << Gtk::TypeNames::state( state )
3322             << " detail: " << (detail ? detail:"0x0" )
3323             << std::endl;
3324         #endif
3325 
3326         Gtk::Detail d( detail );
3327 
3328         // special handling of Xul checkboxes and radio buttons
3329         if( Style::instance().settings().applicationName().isXul() && (d.isCheckButton() || d.isRadioButton() ) && !gtk_widget_has_focus( widget ) )
3330         {
3331 
3332             // try set correct rectangle based on last call to either draw_check or draw_option
3333             bool forceRadioButton( false );
3334             if( StyleWrapper::xulInfo().isValid() )
3335             {
3336 
3337                 forceRadioButton = StyleWrapper::xulInfo().type() == XulInfo::RadioButton;
3338 
3339                 x = StyleWrapper::xulInfo().rect().x;
3340                 y = StyleWrapper::xulInfo().rect().y;
3341                 w = StyleWrapper::xulInfo().rect().width;
3342                 h = StyleWrapper::xulInfo().rect().height;
3343                 clipRect = 0L;
3344 
3345                 // clear Xul info
3346                 StyleWrapper::xulInfo().clear();
3347 
3348             } else {
3349 
3350                 return;
3351 
3352             }
3353 
3354             // Render focus here, since XUL apps don't let us figure out focused state in draw_box() etc.
3355             if( ( d.isRadioButton() && GTK_IS_RADIO_BUTTON(widget) ) || ( d.isCheckButton() && GTK_IS_CHECK_BUTTON(widget) && forceRadioButton ) )
3356             {
3357 
3358                 Style::instance().renderRadioButton(window,clipRect, x, y, w, h, GTK_SHADOW_NONE,Focus|NoFill,AnimationData());
3359                 return;
3360 
3361             } else if( d.isCheckButton() && GTK_IS_CHECK_BUTTON(widget) ) {
3362 
3363                 Style::instance().renderSlab(window,clipRect, x-1, y-1 ,w+3, h+3, Focus|NoFill,AnimationData());
3364                 return;
3365 
3366             }
3367 
3368         }
3369 
3370         if( d.isNull() && GTK_IS_WINDOW( widget ) )
3371         {
3372 
3373             // TODO: implement something better
3374             return StyleWrapper::parentClass()->draw_focus( style, window, state,
3375                 clipRect, widget, detail,
3376                 x, y, w, h );
3377 
3378         }
3379 
3380         return;
3381 
3382     }
3383 
3384 
3385     //___________________________________________________________________________________________________________
3386     static void draw_handle( GtkStyle* style,
3387         GdkWindow* window,
3388         GtkStateType state,
3389         GtkShadowType shadow,
3390         GdkRectangle* clipRect,
3391         GtkWidget* widget,
3392         const gchar* detail,
3393         gint x,
3394         gint y,
3395         gint w,
3396         gint h,
3397         GtkOrientation orientation )
3398     {
3399         g_return_if_fail( style && window );
3400 
3401         Style::instance().sanitizeSize( window, w, h );
3402 
3403         #if OXYGEN_DEBUG
3404         std::cerr
3405             << "Oxygen::draw_handle -"
3406             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3407             << " state: " << Gtk::TypeNames::state( state )
3408             << " shadow: " << Gtk::TypeNames::shadow( shadow )
3409             << " orientation: " << Gtk::TypeNames::orientation( orientation )
3410             << " detail: " << (detail ? detail:"0x0" )
3411             << std::endl;
3412         #endif
3413 
3414         Gtk::Detail d( detail );
3415         if( d.isPaned() )
3416         {
3417 
3418             Style::instance().animations().panedEngine().registerWidget( widget );
3419 
3420             StyleOptions options( widget, state, shadow );
3421             if( GTK_IS_VPANED( widget ) )
3422             {
3423                 options |= Vertical;
3424 
3425             } else if( Gtk::g_object_is_a( G_OBJECT( widget ), "GtkPizza" ) ) {
3426 
3427                 Style::instance().renderWindowBackground( window, widget, clipRect, x, y, w, h );
3428                 if( w>h ) options |= Vertical;
3429 
3430             }
3431 
3432             const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, Gtk::gdk_rectangle( x, y, w, h ), options, AnimationHover ) );
3433             Style::instance().renderSplitter( window, 0L, x, y, w, h, options, data );
3434 
3435         } else if( d.isHandleBox() ) {
3436 
3437             if( !Gtk::gtk_widget_is_applet( widget ) )
3438             {
3439                 Style::instance().renderWindowBackground( window, widget, clipRect, x, y, w, h );
3440             }
3441 
3442             StyleOptions options( widget, state, shadow );
3443             if( orientation == GTK_ORIENTATION_VERTICAL ) options |= Vertical;
3444             Style::instance().renderToolBarHandle( window, clipRect, x, y, w, h, options );
3445 
3446         } else {
3447 
3448             StyleWrapper::parentClass()->draw_handle( style, window, state,
3449                 shadow, clipRect, widget, detail,
3450                 x, y, w, h,
3451                 orientation );
3452         }
3453 
3454     }
3455 
3456     //___________________________________________________________________________________________________________
3457     static void draw_resize_grip(
3458         GtkStyle* style,
3459         GdkWindow* window,
3460         GtkStateType state,
3461         GdkRectangle* clipRect,
3462         GtkWidget* widget,
3463         const char* detail,
3464         GdkWindowEdge edge,
3465         gint x,
3466         gint y,
3467         gint w,
3468         gint h )
3469     {
3470         g_return_if_fail( style && window );
3471 
3472         #if OXYGEN_DEBUG
3473         std::cerr
3474             << "Oxygen::draw_resize_grip -"
3475             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3476             << " state: " << Gtk::TypeNames::state( state )
3477             << " edge: " << Gtk::TypeNames::windowEdge( edge )
3478             << " detail: " << (detail ? detail:"0x0" )
3479             << std::endl;
3480         #endif
3481 
3482         // no resize grip in oxygen no matter what
3483         return;
3484     }
3485 
3486     //___________________________________________________________
3487     static GdkPixbuf* render_stated_pixbuf( GdkPixbuf* source, GtkStateType state, bool useEffect )
3488     {
3489 
3490         #if OXYGEN_DEBUG
3491         std::cerr
3492             << "Oxygen::render_stated_pixbuf -"
3493             << " state: " << Gtk::TypeNames::state( state )
3494             << " useEffect: " << useEffect
3495             << std::endl;
3496         #endif
3497 
3498         // first make a copy
3499         GdkPixbuf* stated( source );
3500         if( state == GTK_STATE_INSENSITIVE )
3501         {
3502 
3503             stated = Gtk::gdk_pixbuf_set_alpha( source, 0.3 );
3504             gdk_pixbuf_saturate_and_pixelate( stated, stated, 0.1, false );
3505 
3506         } else if( useEffect && state == GTK_STATE_PRELIGHT ) {
3507 
3508             stated = gdk_pixbuf_copy( source );
3509             if(!Gtk::gdk_pixbuf_to_gamma( stated, 0.7 ) )
3510             {
3511                 // FIXME: correct the value to match KDE
3512                 /*
3513                 in fact KDE allows one to set many different effects on icon
3514                 not sure we want to copy this code all over the place, especially since nobody changes the default settings,
3515                 as far as I know */
3516                 gdk_pixbuf_saturate_and_pixelate( source, stated, 1.2, false );
3517             }
3518 
3519         }
3520 
3521         return stated;
3522     }
3523 
3524     //___________________________________________________________
3525     static GdkPixbuf* render_icon(
3526         GtkStyle* style,
3527         const GtkIconSource* source,
3528         GtkTextDirection,
3529         GtkStateType state,
3530         GtkIconSize size,
3531         GtkWidget* widget,
3532         const char* detail )
3533     {
3534 
3535         #if OXYGEN_DEBUG
3536         const char* filename( source ? gtk_icon_source_get_filename( source ) : 0L );
3537         const char* iconname( source ? gtk_icon_source_get_icon_name( source ) : 0L );
3538         std::cerr
3539             << "Oxygen::render_icon -"
3540             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3541             << " state: " << Gtk::TypeNames::state( state )
3542             << " file name: " << (filename ? filename:"0x0")
3543             << " icon name: " << (iconname ? iconname:"0x0")
3544             << " icon size: " << Gtk::TypeNames::iconSize( size )
3545             << " detail: " << (detail ? detail:"0x0" )
3546             << std::endl;
3547         #endif
3548 
3549         GdkPixbuf* base_pixbuf( gtk_icon_source_get_pixbuf( source ) );
3550         g_return_val_if_fail( base_pixbuf != 0L, 0L );
3551 
3552         // retrieve screen and settings
3553         GdkScreen *screen( 0L );
3554         GtkSettings *settings( 0L );
3555         if( widget && gtk_widget_has_screen( widget ) )
3556         {
3557 
3558             screen = gtk_widget_get_screen( widget );
3559             settings = gtk_settings_get_for_screen( screen );
3560 
3561         } else if (style->colormap) {
3562 
3563             screen = gdk_colormap_get_screen( style->colormap );
3564             settings = gtk_settings_get_for_screen( screen );
3565 
3566         } else {
3567 
3568             settings = gtk_settings_get_default();
3569 
3570         }
3571 
3572         int width = 1;
3573         int height = 1;
3574         if( size != (GtkIconSize)-1 && !gtk_icon_size_lookup_for_settings( settings, size, &width, &height ) )
3575         {
3576             g_warning (G_STRLOC ": invalid icon size '%d'", size);
3577             return 0L;
3578         }
3579 
3580         /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise,
3581         * leave it alone. */
3582         GdkPixbuf *scaled( 0L);
3583         if( size != (GtkIconSize)-1 && gtk_icon_source_get_size_wildcarded( source ) )
3584         {
3585 
3586             scaled = Gtk::gdk_pixbuf_resize( base_pixbuf, width, height );
3587 
3588         } else {
3589 
3590             scaled = static_cast<GdkPixbuf*>( g_object_ref( base_pixbuf ) );
3591 
3592         }
3593 
3594         if( !gtk_icon_source_get_state_wildcarded( source ) ) return scaled;
3595         else {
3596 
3597             // non-flat pushbuttons don't have any icon effect
3598             const bool useEffect( Style::instance().settings().useIconEffect() && Gtk::gtk_button_is_flat( Gtk::gtk_parent_button( widget ) ) );
3599 
3600             /* If the state was wildcarded, then generate a state. */
3601             GdkPixbuf *stated( render_stated_pixbuf( scaled, state, useEffect ) );
3602 
3603             // clean-up
3604             if( stated != scaled )
3605             { g_object_unref( scaled ); }
3606 
3607             // return
3608             return stated;
3609 
3610         }
3611 
3612     }
3613 
3614     //___________________________________________________________________________________________________________
3615     static void draw_layout(
3616         GtkStyle* style,
3617         GdkWindow* window,
3618         GtkStateType state,
3619         gboolean use_text,
3620         GdkRectangle* clipRect,
3621         GtkWidget* widget,
3622         const gchar* detail,
3623         gint x, gint y,
3624         PangoLayout* layout)
3625     {
3626 
3627         #if OXYGEN_DEBUG
3628         std::cerr
3629             << "Oxygen::draw_layout -"
3630             << " widget: " << widget << " (" << (widget ? G_OBJECT_TYPE_NAME( widget ):"0x0") << ")"
3631             << " state: " << Gtk::TypeNames::state( state )
3632             << " detail: " << (detail ? detail:"0x0" )
3633             << std::endl;
3634         #endif
3635 
3636         const Gtk::Detail d(detail);
3637 
3638         // draw progressbar text white if above indicator, black if not
3639         if( GTK_IS_PROGRESS( widget ) || GTK_IS_PROGRESS_BAR( widget ) || d.isProgressBar() )
3640         {
3641             Cairo::Context context( window,clipRect );
3642             if(state==GTK_STATE_PRELIGHT) gdk_cairo_set_source_color(context, &style->text[GTK_STATE_SELECTED]);
3643             else gdk_cairo_set_source_color(context, &style->text[state]);
3644             cairo_translate(context,x,y);
3645             pango_cairo_show_layout(context,layout);
3646             return;
3647         }
3648 
3649         if( state == GTK_STATE_INSENSITIVE )
3650         {
3651 
3652             // for inactive text, we do the painting ourselves
3653             // to prevent 'emboss' inactive text rendering from gtk
3654             Cairo::Context context( window, clipRect );
3655             gdk_cairo_set_source_color( context, use_text ? &style->text[state] : &style->fg[state] );
3656             const PangoMatrix* matrix( pango_context_get_matrix( pango_layout_get_context( layout ) ) );
3657             if( matrix )
3658             {
3659                 cairo_matrix_t cairo_matrix;
3660                 PangoRectangle rect;
3661 
3662                 cairo_matrix_init( &cairo_matrix, matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0 );
3663                 pango_layout_get_extents( layout, 0L, &rect );
3664                 pango_matrix_transform_rectangle( matrix, &rect );
3665                 pango_extents_to_pixels( &rect, 0L );
3666 
3667                 cairo_matrix.x0 += x - rect.x;
3668                 cairo_matrix.y0 += y - rect.y;
3669 
3670                 cairo_set_matrix( context, &cairo_matrix );
3671 
3672             } else cairo_translate( context, x, y );
3673 
3674             pango_cairo_show_layout( context, layout );
3675 
3676         } else if( GtkWidget* parent = Gtk::gtk_parent_button( widget ) ) {
3677 
3678             // for flat buttons, do not use PRELIGHT color, since there is no PRELIGHT background rendered.
3679             if( Gtk::gtk_button_is_flat( parent ) && ( state == GTK_STATE_PRELIGHT || state == GTK_STATE_ACTIVE )  ) state = GTK_STATE_NORMAL;
3680             StyleWrapper::parentClass()->draw_layout(
3681                 style, window, state, use_text,
3682                 clipRect, widget, detail, x, y, layout );
3683 
3684 
3685         } else {
3686 
3687             // in all other cases, fallback on default rendering, for now
3688             StyleWrapper::parentClass()->draw_layout(
3689                 style, window, state, use_text,
3690                 clipRect, widget, detail, x, y, layout );
3691 
3692         }
3693     }
3694 
3695     //_______________________________________________________________________________________________________________
3696     void StyleWrapper::instanceInit( OxygenStyle* self )
3697     {
3698 
3699         #if OXYGEN_DEBUG
3700         std::cerr << "Oxygen::StyleWrapper::instanceInit" << std::endl;
3701         #endif
3702 
3703         // style initialization
3704         /*
3705         this is normally achieved in theme_init, but is somehow not working with gnome shell
3706         so that it is redone here, since duplication is avoided when initialization is called twice without modifications
3707         */
3708         Style::instance().initialize();
3709 
3710         // hooks
3711         Style::instance().animations().initializeHooks();
3712         Style::instance().shadowHelper().initializeHooks();
3713         Style::instance().widgetExplorer().initializeHooks();
3714 
3715         if( !Style::instance().settings().applicationName().isEclipse() )
3716         { Style::instance().windowManager().initializeHooks(); }
3717 
3718         if( Style::instance().settings().argbEnabled() &&
3719             !Style::instance().settings().applicationName().isXul() )
3720         { Style::instance().argbHelper().initializeHooks(); }
3721 
3722         // disable all animations for openoffice
3723         // and re-enable combobox animations
3724         if( Oxygen::Style::instance().settings().applicationName().isOpenOffice() )
3725         {
3726             Oxygen::Style::instance().animations().setEnabled( false );
3727             Oxygen::Style::instance().animations().setInnerShadowsEnabled( false );
3728             Oxygen::Style::instance().animations().comboBoxEngine().setEnabled( true );
3729             Oxygen::Style::instance().animations().backgroundHintEngine().setEnabled( true );
3730         }
3731 
3732     }
3733 
3734     //_______________________________________________________________________________________________________________
3735     void StyleWrapper::classInit( OxygenStyleClass* klass )
3736     {
3737 
3738         #if OXYGEN_DEBUG
3739         std::cerr << "Oxygen::StyleWrapper::classInit" << std::endl;
3740         #endif
3741 
3742         GtkStyleClass* style_class( GTK_STYLE_CLASS( klass ) );
3743 
3744         _parentClass = static_cast<GtkStyleClass*>( g_type_class_peek_parent( klass ) );
3745 
3746         style_class->draw_hline = draw_hline;
3747         style_class->draw_vline = draw_vline;
3748         style_class->draw_shadow = draw_shadow;
3749         style_class->draw_arrow = draw_arrow;
3750 
3751         style_class->draw_diamond = draw_diamond;
3752 
3753         style_class->draw_box = draw_box;
3754         style_class->draw_flat_box = draw_flat_box;
3755         style_class->draw_check = draw_check;
3756         style_class->draw_option = draw_option;
3757         style_class->draw_tab = draw_tab;
3758         style_class->draw_shadow_gap = draw_shadow_gap;
3759         style_class->draw_box_gap = draw_box_gap;
3760         style_class->draw_extension = draw_extension;
3761         style_class->draw_focus = draw_focus;
3762         style_class->draw_slider = draw_slider;
3763         style_class->draw_handle = draw_handle;
3764         style_class->draw_resize_grip = draw_resize_grip;
3765         style_class->draw_expander = draw_expander;
3766 
3767         // icon rendering
3768         style_class->render_icon = render_icon;
3769 
3770         // text rendering
3771         style_class->draw_layout = draw_layout;
3772 
3773     }
3774 
3775     //_______________________________________________________________________________________________________________
3776     void StyleWrapper::registerType( GTypeModule* module )
3777     {
3778 
3779         #if OXYGEN_DEBUG
3780         std::cerr << "Oxygen::StyleWrapper::registerType" << std::endl;
3781         #endif
3782 
3783         const GTypeInfo info =
3784         {
3785             (guint16)sizeof( OxygenStyleClass ),
3786             (GBaseInitFunc) NULL,
3787             (GBaseFinalizeFunc) NULL,
3788             (GClassInitFunc) classInit,
3789             (GClassFinalizeFunc) NULL,
3790             NULL,
3791             (guint16)sizeof( OxygenStyle ),
3792             0,
3793             (GInstanceInitFunc) instanceInit,
3794             NULL
3795         };
3796 
3797         _typeInfo = info;
3798         _type = g_type_module_register_type( module, GTK_TYPE_STYLE, "OxygenStyle", &_typeInfo, GTypeFlags(0 ) );
3799 
3800         #if OXYGEN_DEBUG
3801         std::cerr << "Oxygen::StyleWrapper::registerType - done" << std::endl;
3802         #endif
3803 
3804     }
3805 
3806     //_______________________________________________________________________________________________________________
3807     void StyleWrapper::registerVersionType( void )
3808     {
3809 
3810         // register version type
3811         GType type( g_type_register_static_simple(
3812             G_TYPE_OBJECT,
3813             OXYGEN_VERSION_TYPE_NAME,
3814             (guint16)sizeof( GObjectClass ),
3815             (GClassInitFunc) NULL,
3816             (guint16)sizeof( GObject ),
3817             (GInstanceInitFunc) NULL,
3818             G_TYPE_FLAG_ABSTRACT ) );
3819 
3820         // quark
3821         GQuark quark( g_quark_from_string( OXYGEN_VERSION_QUARK_NAME ) );
3822         g_type_set_qdata( type, quark, (gpointer) OXYGEN_VERSION );
3823 
3824     }
3825 
3826     //_______________________________________________________________________________________________________________
3827     GType StyleWrapper::type( void )
3828     { return _type; }
3829 
3830 }