1 /*
   2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.java.swing.plaf.gtk;
  27 
  28 import java.awt.*;
  29 import java.awt.image.*;
  30 import java.util.HashMap;
  31 import javax.swing.*;
  32 import javax.swing.plaf.synth.*;
  33 
  34 import com.sun.java.swing.plaf.gtk.GTKConstants.ArrowType;
  35 import com.sun.java.swing.plaf.gtk.GTKConstants.ExpanderStyle;
  36 import com.sun.java.swing.plaf.gtk.GTKConstants.Orientation;
  37 import com.sun.java.swing.plaf.gtk.GTKConstants.PositionType;
  38 import com.sun.java.swing.plaf.gtk.GTKConstants.ShadowType;
  39 import com.sun.java.swing.plaf.gtk.GTKConstants.TextDirection;
  40 
  41 import sun.awt.image.SunWritableRaster;
  42 import sun.swing.ImageCache;
  43 
  44 /**
  45  * GTKEngine delegates all painting job to native GTK libraries.
  46  *
  47  * Painting with GTKEngine looks like this:
  48  * First, startPainting() is called. It prepares an offscreen buffer of the
  49  *   required size.
  50  * Then, any number of paintXXX() methods can be called. They effectively ignore
  51  *   the Graphics parameter and draw to the offscreen buffer.
  52  * Finally, finishPainting() should be called. It fills the data buffer passed
  53  *   in with the image data.
  54  *
  55  * @author Josh Outwater
  56  */
  57 class GTKEngine {
  58 
  59     static final GTKEngine INSTANCE = new GTKEngine();
  60 
  61     /** Size of the image cache */
  62     private static final int CACHE_SIZE = 50;
  63 
  64     /** This enum mirrors that in gtk2_interface.h */
  65     static enum WidgetType {
  66         BUTTON, CHECK_BOX, CHECK_BOX_MENU_ITEM, COLOR_CHOOSER,
  67         COMBO_BOX, COMBO_BOX_ARROW_BUTTON, COMBO_BOX_TEXT_FIELD,
  68         DESKTOP_ICON, DESKTOP_PANE, EDITOR_PANE, FORMATTED_TEXT_FIELD,
  69         HANDLE_BOX, HPROGRESS_BAR,
  70         HSCROLL_BAR, HSCROLL_BAR_BUTTON_LEFT, HSCROLL_BAR_BUTTON_RIGHT,
  71         HSCROLL_BAR_TRACK, HSCROLL_BAR_THUMB,
  72         HSEPARATOR, HSLIDER, HSLIDER_TRACK, HSLIDER_THUMB, HSPLIT_PANE_DIVIDER,
  73         INTERNAL_FRAME, INTERNAL_FRAME_TITLE_PANE, IMAGE, LABEL, LIST, MENU,
  74         MENU_BAR, MENU_ITEM, MENU_ITEM_ACCELERATOR, OPTION_PANE, PANEL,
  75         PASSWORD_FIELD, POPUP_MENU, POPUP_MENU_SEPARATOR,
  76         RADIO_BUTTON, RADIO_BUTTON_MENU_ITEM, ROOT_PANE, SCROLL_PANE,
  77         SPINNER, SPINNER_ARROW_BUTTON, SPINNER_TEXT_FIELD,
  78         SPLIT_PANE, TABBED_PANE, TABBED_PANE_TAB_AREA, TABBED_PANE_CONTENT,
  79         TABBED_PANE_TAB, TABLE, TABLE_HEADER, TEXT_AREA, TEXT_FIELD, TEXT_PANE,
  80         TITLED_BORDER,
  81         TOGGLE_BUTTON, TOOL_BAR, TOOL_BAR_DRAG_WINDOW, TOOL_BAR_SEPARATOR,
  82         TOOL_TIP, TREE, TREE_CELL, VIEWPORT, VPROGRESS_BAR,
  83         VSCROLL_BAR, VSCROLL_BAR_BUTTON_UP, VSCROLL_BAR_BUTTON_DOWN,
  84         VSCROLL_BAR_TRACK, VSCROLL_BAR_THUMB,
  85         VSEPARATOR, VSLIDER, VSLIDER_TRACK, VSLIDER_THUMB,
  86         VSPLIT_PANE_DIVIDER
  87     }
  88 
  89     /**
  90      * Representation of GtkSettings properties.
  91      * When we need more settings we can add them here and
  92      * to all implementations of getGTKSetting().
  93      */
  94     static enum Settings {
  95         GTK_FONT_NAME,
  96         GTK_ICON_SIZES,
  97         GTK_CURSOR_BLINK,
  98         GTK_CURSOR_BLINK_TIME
  99     }
 100 
 101     /* Custom regions are needed for representing regions that don't exist
 102      * in the original Region class.
 103      */
 104     static class CustomRegion extends Region {
 105         /*
 106          * TITLED_BORDER Region is mapped to GtkFrame class which can draw
 107          * titled borders around components.
 108          */
 109         static Region TITLED_BORDER = new CustomRegion("TitledBorder");
 110 
 111         private CustomRegion(String name) {
 112             super(name, null, false);
 113         }
 114     }
 115 
 116 
 117     private static HashMap<Region, Object> regionToWidgetTypeMap;
 118     private ImageCache cache = new ImageCache(CACHE_SIZE);
 119     private int x0, y0, w0, h0;
 120     private Graphics graphics;
 121     private Object[] cacheArgs;
 122 
 123     private native void native_paint_arrow(
 124             int widgetType, int state, int shadowType, String detail,
 125             int x, int y, int width, int height, int arrowType);
 126     private native void native_paint_box(
 127             int widgetType, int state, int shadowType, String detail,
 128             int x, int y, int width, int height, int synthState, int dir);
 129     private native void native_paint_box_gap(
 130             int widgetType, int state, int shadowType, String detail,
 131             int x, int y, int width, int height,
 132             int gapSide, int gapX, int gapWidth);
 133     private native void native_paint_check(
 134             int widgetType, int synthState, String detail,
 135             int x, int y, int width, int height);
 136     private native void native_paint_expander(
 137             int widgetType, int state, String detail,
 138             int x, int y, int width, int height, int expanderStyle);
 139     private native void native_paint_extension(
 140             int widgetType, int state, int shadowType, String detail,
 141             int x, int y, int width, int height, int placement);
 142     private native void native_paint_flat_box(
 143             int widgetType, int state, int shadowType, String detail,
 144             int x, int y, int width, int height, boolean hasFocus);
 145     private native void native_paint_focus(
 146             int widgetType, int state, String detail,
 147             int x, int y, int width, int height);
 148     private native void native_paint_handle(
 149             int widgetType, int state, int shadowType, String detail,
 150             int x, int y, int width, int height, int orientation);
 151     private native void native_paint_hline(
 152             int widgetType, int state, String detail,
 153             int x, int y, int width, int height);
 154     private native void native_paint_option(
 155             int widgetType, int synthState, String detail,
 156             int x, int y, int width, int height);
 157     private native void native_paint_shadow(
 158             int widgetType, int state, int shadowType, String detail,
 159             int x, int y, int width, int height, int synthState, int dir);
 160     private native void native_paint_slider(
 161             int widgetType, int state, int shadowType, String detail,
 162             int x, int y, int width, int height, int orientation);
 163     private native void native_paint_vline(
 164             int widgetType, int state, String detail,
 165             int x, int y, int width, int height);
 166     private native void native_paint_background(
 167             int widgetType, int state, int x, int y, int width, int height);
 168     private native Object native_get_gtk_setting(int property);
 169     private native void nativeSetRangeValue(int widgetType, double value,
 170                                             double min, double max,
 171                                             double visible);
 172 
 173     private native void nativeStartPainting(int w, int h);
 174     private native int nativeFinishPainting(int[] buffer, int width, int height);
 175     private native void native_switch_theme();
 176 
 177     static {
 178         // Make sure the awt toolkit is loaded so we have access to native
 179         // methods.
 180         Toolkit.getDefaultToolkit();
 181 
 182         // Initialize regionToWidgetTypeMap
 183         regionToWidgetTypeMap = new HashMap<Region, Object>(50);
 184         regionToWidgetTypeMap.put(Region.ARROW_BUTTON, new WidgetType[] {
 185             WidgetType.SPINNER_ARROW_BUTTON,
 186             WidgetType.COMBO_BOX_ARROW_BUTTON,
 187             WidgetType.HSCROLL_BAR_BUTTON_LEFT,
 188             WidgetType.HSCROLL_BAR_BUTTON_RIGHT,
 189             WidgetType.VSCROLL_BAR_BUTTON_UP,
 190             WidgetType.VSCROLL_BAR_BUTTON_DOWN});
 191         regionToWidgetTypeMap.put(Region.BUTTON, WidgetType.BUTTON);
 192         regionToWidgetTypeMap.put(Region.CHECK_BOX, WidgetType.CHECK_BOX);
 193         regionToWidgetTypeMap.put(Region.CHECK_BOX_MENU_ITEM,
 194                                   WidgetType.CHECK_BOX_MENU_ITEM);
 195         regionToWidgetTypeMap.put(Region.COLOR_CHOOSER, WidgetType.COLOR_CHOOSER);
 196         regionToWidgetTypeMap.put(Region.FILE_CHOOSER, WidgetType.OPTION_PANE);
 197         regionToWidgetTypeMap.put(Region.COMBO_BOX, WidgetType.COMBO_BOX);
 198         regionToWidgetTypeMap.put(Region.DESKTOP_ICON, WidgetType.DESKTOP_ICON);
 199         regionToWidgetTypeMap.put(Region.DESKTOP_PANE, WidgetType.DESKTOP_PANE);
 200         regionToWidgetTypeMap.put(Region.EDITOR_PANE, WidgetType.EDITOR_PANE);
 201         regionToWidgetTypeMap.put(Region.FORMATTED_TEXT_FIELD, new WidgetType[] {
 202             WidgetType.FORMATTED_TEXT_FIELD, WidgetType.SPINNER_TEXT_FIELD});
 203         regionToWidgetTypeMap.put(GTKRegion.HANDLE_BOX, WidgetType.HANDLE_BOX);
 204         regionToWidgetTypeMap.put(Region.INTERNAL_FRAME,
 205                                   WidgetType.INTERNAL_FRAME);
 206         regionToWidgetTypeMap.put(Region.INTERNAL_FRAME_TITLE_PANE,
 207                                   WidgetType.INTERNAL_FRAME_TITLE_PANE);
 208         regionToWidgetTypeMap.put(Region.LABEL, new WidgetType[] {
 209             WidgetType.LABEL, WidgetType.COMBO_BOX_TEXT_FIELD});
 210         regionToWidgetTypeMap.put(Region.LIST, WidgetType.LIST);
 211         regionToWidgetTypeMap.put(Region.MENU, WidgetType.MENU);
 212         regionToWidgetTypeMap.put(Region.MENU_BAR, WidgetType.MENU_BAR);
 213         regionToWidgetTypeMap.put(Region.MENU_ITEM, WidgetType.MENU_ITEM);
 214         regionToWidgetTypeMap.put(Region.MENU_ITEM_ACCELERATOR,
 215                                   WidgetType.MENU_ITEM_ACCELERATOR);
 216         regionToWidgetTypeMap.put(Region.OPTION_PANE, WidgetType.OPTION_PANE);
 217         regionToWidgetTypeMap.put(Region.PANEL, WidgetType.PANEL);
 218         regionToWidgetTypeMap.put(Region.PASSWORD_FIELD,
 219                                   WidgetType.PASSWORD_FIELD);
 220         regionToWidgetTypeMap.put(Region.POPUP_MENU, WidgetType.POPUP_MENU);
 221         regionToWidgetTypeMap.put(Region.POPUP_MENU_SEPARATOR,
 222                                   WidgetType.POPUP_MENU_SEPARATOR);
 223         regionToWidgetTypeMap.put(Region.PROGRESS_BAR, new WidgetType[] {
 224             WidgetType.HPROGRESS_BAR, WidgetType.VPROGRESS_BAR});
 225         regionToWidgetTypeMap.put(Region.RADIO_BUTTON, WidgetType.RADIO_BUTTON);
 226         regionToWidgetTypeMap.put(Region.RADIO_BUTTON_MENU_ITEM,
 227                                   WidgetType.RADIO_BUTTON_MENU_ITEM);
 228         regionToWidgetTypeMap.put(Region.ROOT_PANE, WidgetType.ROOT_PANE);
 229         regionToWidgetTypeMap.put(Region.SCROLL_BAR, new WidgetType[] {
 230             WidgetType.HSCROLL_BAR, WidgetType.VSCROLL_BAR});
 231         regionToWidgetTypeMap.put(Region.SCROLL_BAR_THUMB, new WidgetType[] {
 232             WidgetType.HSCROLL_BAR_THUMB, WidgetType.VSCROLL_BAR_THUMB});
 233         regionToWidgetTypeMap.put(Region.SCROLL_BAR_TRACK, new WidgetType[] {
 234             WidgetType.HSCROLL_BAR_TRACK, WidgetType.VSCROLL_BAR_TRACK});
 235         regionToWidgetTypeMap.put(Region.SCROLL_PANE, WidgetType.SCROLL_PANE);
 236         regionToWidgetTypeMap.put(Region.SEPARATOR, new WidgetType[] {
 237             WidgetType.HSEPARATOR, WidgetType.VSEPARATOR});
 238         regionToWidgetTypeMap.put(Region.SLIDER, new WidgetType[] {
 239             WidgetType.HSLIDER, WidgetType.VSLIDER});
 240         regionToWidgetTypeMap.put(Region.SLIDER_THUMB, new WidgetType[] {
 241             WidgetType.HSLIDER_THUMB, WidgetType.VSLIDER_THUMB});
 242         regionToWidgetTypeMap.put(Region.SLIDER_TRACK, new WidgetType[] {
 243             WidgetType.HSLIDER_TRACK, WidgetType.VSLIDER_TRACK});
 244         regionToWidgetTypeMap.put(Region.SPINNER, WidgetType.SPINNER);
 245         regionToWidgetTypeMap.put(Region.SPLIT_PANE, WidgetType.SPLIT_PANE);
 246         regionToWidgetTypeMap.put(Region.SPLIT_PANE_DIVIDER, new WidgetType[] {
 247             WidgetType.HSPLIT_PANE_DIVIDER, WidgetType.VSPLIT_PANE_DIVIDER});
 248         regionToWidgetTypeMap.put(Region.TABBED_PANE, WidgetType.TABBED_PANE);
 249         regionToWidgetTypeMap.put(Region.TABBED_PANE_CONTENT,
 250                                   WidgetType.TABBED_PANE_CONTENT);
 251         regionToWidgetTypeMap.put(Region.TABBED_PANE_TAB,
 252                                   WidgetType.TABBED_PANE_TAB);
 253         regionToWidgetTypeMap.put(Region.TABBED_PANE_TAB_AREA,
 254                                   WidgetType.TABBED_PANE_TAB_AREA);
 255         regionToWidgetTypeMap.put(Region.TABLE, WidgetType.TABLE);
 256         regionToWidgetTypeMap.put(Region.TABLE_HEADER, WidgetType.TABLE_HEADER);
 257         regionToWidgetTypeMap.put(Region.TEXT_AREA, WidgetType.TEXT_AREA);
 258         regionToWidgetTypeMap.put(Region.TEXT_FIELD, new WidgetType[] {
 259             WidgetType.TEXT_FIELD, WidgetType.COMBO_BOX_TEXT_FIELD});
 260         regionToWidgetTypeMap.put(Region.TEXT_PANE, WidgetType.TEXT_PANE);
 261         regionToWidgetTypeMap.put(CustomRegion.TITLED_BORDER, WidgetType.TITLED_BORDER);
 262         regionToWidgetTypeMap.put(Region.TOGGLE_BUTTON, WidgetType.TOGGLE_BUTTON);
 263         regionToWidgetTypeMap.put(Region.TOOL_BAR, WidgetType.TOOL_BAR);
 264         regionToWidgetTypeMap.put(Region.TOOL_BAR_CONTENT, WidgetType.TOOL_BAR);
 265         regionToWidgetTypeMap.put(Region.TOOL_BAR_DRAG_WINDOW,
 266                                   WidgetType.TOOL_BAR_DRAG_WINDOW);
 267         regionToWidgetTypeMap.put(Region.TOOL_BAR_SEPARATOR,
 268                                   WidgetType.TOOL_BAR_SEPARATOR);
 269         regionToWidgetTypeMap.put(Region.TOOL_TIP, WidgetType.TOOL_TIP);
 270         regionToWidgetTypeMap.put(Region.TREE, WidgetType.TREE);
 271         regionToWidgetTypeMap.put(Region.TREE_CELL, WidgetType.TREE_CELL);
 272         regionToWidgetTypeMap.put(Region.VIEWPORT, WidgetType.VIEWPORT);
 273     }
 274 
 275     /** Translate Region and JComponent into WidgetType ordinals */
 276     static WidgetType getWidgetType(JComponent c, Region id) {
 277         Object value = regionToWidgetTypeMap.get(id);
 278 
 279         if (value instanceof WidgetType) {
 280             return (WidgetType)value;
 281         }
 282 
 283         WidgetType[] widgets = (WidgetType[])value;
 284         if (c == null ) {
 285             return widgets[0];
 286         }
 287 
 288         if (c instanceof JScrollBar) {
 289             return (((JScrollBar)c).getOrientation() == JScrollBar.HORIZONTAL) ?
 290                 widgets[0] : widgets[1];
 291         } else if (c instanceof JSeparator) {
 292             JSeparator separator = (JSeparator)c;
 293 
 294             /* We should return correrct WidgetType if the seperator is inserted
 295              * in Menu/PopupMenu/ToolBar. BugID: 6465603
 296              */
 297             if (separator.getParent() instanceof JPopupMenu) {
 298                 return WidgetType.POPUP_MENU_SEPARATOR;
 299             } else if (separator.getParent() instanceof JToolBar) {
 300                 return WidgetType.TOOL_BAR_SEPARATOR;
 301             }
 302 
 303             return (separator.getOrientation() == JSeparator.HORIZONTAL) ?
 304                 widgets[0] : widgets[1];
 305         } else if (c instanceof JSlider) {
 306             return (((JSlider)c).getOrientation() == JSlider.HORIZONTAL) ?
 307                 widgets[0] : widgets[1];
 308         } else if (c instanceof JProgressBar) {
 309             return (((JProgressBar)c).getOrientation() == JProgressBar.HORIZONTAL) ?
 310                 widgets[0] : widgets[1];
 311         } else if (c instanceof JSplitPane) {
 312             return (((JSplitPane)c).getOrientation() == JSplitPane.HORIZONTAL_SPLIT) ?
 313                 widgets[1] : widgets[0];
 314         } else if (id == Region.LABEL) {
 315             /*
 316              * For all ListCellRenderers we will use COMBO_BOX_TEXT_FIELD widget
 317              * type because we can get correct insets. List items however won't be
 318              * drawn as a text entry (see GTKPainter.paintLabelBackground).
 319              */
 320             if (c instanceof ListCellRenderer) {
 321                 return widgets[1];
 322             } else {
 323                 return widgets[0];
 324             }
 325         } else if (id == Region.TEXT_FIELD) {
 326             String name = c.getName();
 327             if (name != null && name.startsWith("ComboBox")) {
 328                 return widgets[1];
 329             } else {
 330                 return widgets[0];
 331             }
 332         } else if (id == Region.FORMATTED_TEXT_FIELD) {
 333             String name = c.getName();
 334             if (name != null && name.startsWith("Spinner")) {
 335                 return widgets[1];
 336             } else {
 337                 return widgets[0];
 338             }
 339         } else if (id == Region.ARROW_BUTTON) {
 340             if (c.getParent() instanceof JScrollBar) {
 341                 Integer prop = (Integer)
 342                     c.getClientProperty("__arrow_direction__");
 343                 int dir = (prop != null) ?
 344                     prop.intValue() : SwingConstants.WEST;
 345                 switch (dir) {
 346                 case SwingConstants.WEST:
 347                     return WidgetType.HSCROLL_BAR_BUTTON_LEFT;
 348                 case SwingConstants.EAST:
 349                     return WidgetType.HSCROLL_BAR_BUTTON_RIGHT;
 350                 case SwingConstants.NORTH:
 351                     return WidgetType.VSCROLL_BAR_BUTTON_UP;
 352                 case SwingConstants.SOUTH:
 353                     return WidgetType.VSCROLL_BAR_BUTTON_DOWN;
 354                 default:
 355                     return null;
 356                 }
 357             } else if (c.getParent() instanceof JComboBox) {
 358                 return WidgetType.COMBO_BOX_ARROW_BUTTON;
 359             } else {
 360                 return WidgetType.SPINNER_ARROW_BUTTON;
 361             }
 362         }
 363 
 364         return null;
 365     }
 366 
 367     private static int getTextDirection(SynthContext context) {
 368         TextDirection dir = TextDirection.NONE;
 369         JComponent comp = context.getComponent();
 370         if (comp != null) {
 371             ComponentOrientation co = comp.getComponentOrientation();
 372             if (co != null) {
 373                 dir = co.isLeftToRight() ?
 374                     TextDirection.LTR : TextDirection.RTL;
 375             }
 376         }
 377         return dir.ordinal();
 378     }
 379 
 380     public void paintArrow(Graphics g, SynthContext context,
 381             Region id, int state, ShadowType shadowType, ArrowType direction,
 382             String detail, int x, int y, int w, int h) {
 383 
 384         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 385         int widget = getWidgetType(context.getComponent(), id).ordinal();
 386         native_paint_arrow(widget, state, shadowType.ordinal(),
 387                 detail, x - x0, y - y0, w, h, direction.ordinal());
 388     }
 389 
 390     public void paintBox(Graphics g, SynthContext context,
 391             Region id, int state, ShadowType shadowType,
 392             String detail, int x, int y, int w, int h) {
 393 
 394         int gtkState =
 395             GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 396         int synthState = context.getComponentState();
 397         int dir = getTextDirection(context);
 398         int widget = getWidgetType(context.getComponent(), id).ordinal();
 399         native_paint_box(widget, gtkState, shadowType.ordinal(),
 400                          detail, x - x0, y - y0, w, h, synthState, dir);
 401     }
 402 
 403     public void paintBoxGap(Graphics g, SynthContext context,
 404             Region id, int state, ShadowType shadowType,
 405             String detail, int x, int y, int w, int h,
 406             PositionType boxGapType, int tabBegin, int size) {
 407 
 408         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 409         int widget = getWidgetType(context.getComponent(), id).ordinal();
 410         native_paint_box_gap(widget, state, shadowType.ordinal(), detail,
 411                 x - x0, y - y0, w, h, boxGapType.ordinal(), tabBegin, size);
 412     }
 413 
 414     public void paintCheck(Graphics g, SynthContext context,
 415             Region id, String detail, int x, int y, int w, int h) {
 416 
 417         int synthState = context.getComponentState();
 418         int widget = getWidgetType(context.getComponent(), id).ordinal();
 419         native_paint_check(widget, synthState, detail, x - x0, y - y0, w, h);
 420     }
 421 
 422     public void paintExpander(Graphics g, SynthContext context,
 423             Region id, int state, ExpanderStyle expanderStyle, String detail,
 424             int x, int y, int w, int h) {
 425 
 426         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 427         int widget = getWidgetType(context.getComponent(), id).ordinal();
 428         native_paint_expander(widget, state, detail, x - x0, y - y0, w, h,
 429                               expanderStyle.ordinal());
 430     }
 431 
 432     public void paintExtension(Graphics g, SynthContext context,
 433             Region id, int state, ShadowType shadowType, String detail,
 434             int x, int y, int w, int h, PositionType placement, int tabIndex) {
 435 
 436         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 437         int widget = getWidgetType(context.getComponent(), id).ordinal();
 438         native_paint_extension(widget, state, shadowType.ordinal(), detail,
 439                                x - x0, y - y0, w, h, placement.ordinal());
 440     }
 441 
 442     public void paintFlatBox(Graphics g, SynthContext context,
 443             Region id, int state, ShadowType shadowType, String detail,
 444             int x, int y, int w, int h, ColorType colorType) {
 445 
 446         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 447         int widget = getWidgetType(context.getComponent(), id).ordinal();
 448         native_paint_flat_box(widget, state, shadowType.ordinal(), detail,
 449                               x - x0, y - y0, w, h,
 450                               context.getComponent().hasFocus());
 451     }
 452 
 453     public void paintFocus(Graphics g, SynthContext context,
 454             Region id, int state, String detail, int x, int y, int w, int h) {
 455 
 456         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 457         int widget = getWidgetType(context.getComponent(), id).ordinal();
 458         native_paint_focus(widget, state, detail, x - x0, y - y0, w, h);
 459     }
 460 
 461     public void paintHandle(Graphics g, SynthContext context,
 462             Region id, int state, ShadowType shadowType, String detail,
 463             int x, int y, int w, int h, Orientation orientation) {
 464 
 465         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 466         int widget = getWidgetType(context.getComponent(), id).ordinal();
 467         native_paint_handle(widget, state, shadowType.ordinal(), detail,
 468                             x - x0, y - y0, w, h, orientation.ordinal());
 469     }
 470 
 471     public void paintHline(Graphics g, SynthContext context,
 472             Region id, int state, String detail, int x, int y, int w, int h) {
 473 
 474         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 475         int widget = getWidgetType(context.getComponent(), id).ordinal();
 476         native_paint_hline(widget, state, detail, x - x0, y - y0, w, h);
 477     }
 478 
 479     public void paintOption(Graphics g, SynthContext context,
 480             Region id, String detail, int x, int y, int w, int h) {
 481 
 482         int synthState = context.getComponentState();
 483         int widget = getWidgetType(context.getComponent(), id).ordinal();
 484         native_paint_option(widget, synthState, detail, x - x0, y - y0, w, h);
 485     }
 486 
 487     public void paintShadow(Graphics g, SynthContext context,
 488             Region id, int state, ShadowType shadowType, String detail,
 489             int x, int y, int w, int h) {
 490 
 491         int gtkState =
 492             GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 493         int synthState = context.getComponentState();
 494         int dir = getTextDirection(context);
 495         int widget = getWidgetType(context.getComponent(), id).ordinal();
 496         native_paint_shadow(widget, gtkState, shadowType.ordinal(), detail,
 497                             x - x0, y - y0, w, h, synthState, dir);
 498     }
 499 
 500     public void paintSlider(Graphics g, SynthContext context,
 501             Region id, int state, ShadowType shadowType, String detail,
 502             int x, int y, int w, int h, Orientation orientation) {
 503 
 504         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 505         int widget = getWidgetType(context.getComponent(), id).ordinal();
 506         native_paint_slider(widget, state, shadowType.ordinal(), detail,
 507                             x - x0, y - y0, w, h, orientation.ordinal());
 508     }
 509 
 510     public void paintVline(Graphics g, SynthContext context,
 511             Region id, int state, String detail, int x, int y, int w, int h) {
 512 
 513         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 514         int widget = getWidgetType(context.getComponent(), id).ordinal();
 515         native_paint_vline(widget, state, detail, x - x0, y - y0, w, h);
 516     }
 517 
 518     public void paintBackground(Graphics g, SynthContext context,
 519             Region id, int state, Color color, int x, int y, int w, int h) {
 520 
 521         state = GTKLookAndFeel.synthStateToGTKStateType(state).ordinal();
 522         int widget = getWidgetType(context.getComponent(), id).ordinal();
 523         native_paint_background(widget, state, x - x0, y - y0, w, h);
 524     }
 525 
 526     private static final ColorModel[] COLOR_MODELS = {
 527         // Transparency.OPAQUE
 528         new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
 529         // Transparency.BITMASK
 530         new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000),
 531         // Transparency.TRANSLUCENT
 532         ColorModel.getRGBdefault(),
 533     };
 534 
 535     private static final int[][] BAND_OFFSETS = {
 536         { 0x00ff0000, 0x0000ff00, 0x000000ff },             // OPAQUE
 537         { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000 }, // BITMASK
 538         { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }  // TRANSLUCENT
 539     };
 540 
 541 
 542     /**
 543      * Paint a cached image identified by its size and a set of additional
 544      * arguments, if there's one.
 545      *
 546      * @return true if a cached image has been painted, false otherwise
 547      */
 548     public boolean paintCachedImage(Graphics g,
 549             int x, int y, int w, int h, Object... args) {
 550         if (w <= 0 || h <= 0) {
 551             return true;
 552         }
 553 
 554         // look for cached image
 555         Image img = cache.getImage(getClass(), null, w, h, args);
 556         if (img != null) {
 557             g.drawImage(img, x, y, null);
 558             return true;
 559         }
 560         return false;
 561     }
 562 
 563     /*
 564      * Allocate a native offscreen buffer of the specified size.
 565      */
 566     public void startPainting(Graphics g,
 567             int x, int y, int w, int h, Object... args) {
 568         nativeStartPainting(w, h);
 569         x0 = x;
 570         y0 = y;
 571         w0 = w;
 572         h0 = h;
 573         graphics = g;
 574         cacheArgs = args;
 575     }
 576 
 577     /**
 578      * Convenience method that delegates to finishPainting() with
 579      * caching enabled.
 580      */
 581     public void finishPainting() {
 582         finishPainting(true);
 583     }
 584 
 585     /**
 586      * Called to indicate that painting is finished. We create a new
 587      * BufferedImage from the offscreen buffer, (optionally) cache it,
 588      * and paint it.
 589      */
 590     public void finishPainting(boolean useCache) {
 591         DataBufferInt dataBuffer = new DataBufferInt(w0 * h0);
 592         // Note that stealData() requires a markDirty() afterwards
 593         // since we modify the data in it.
 594         int transparency =
 595             nativeFinishPainting(SunWritableRaster.stealData(dataBuffer, 0),
 596                                  w0, h0);
 597         SunWritableRaster.markDirty(dataBuffer);
 598 
 599         int[] bands = BAND_OFFSETS[transparency - 1];
 600         WritableRaster raster = Raster.createPackedRaster(
 601                 dataBuffer, w0, h0, w0, bands, null);
 602 
 603         ColorModel cm = COLOR_MODELS[transparency - 1];
 604         Image img = new BufferedImage(cm, raster, false, null);
 605         if (useCache) {
 606             cache.setImage(getClass(), null, w0, h0, cacheArgs, img);
 607         }
 608         graphics.drawImage(img, x0, y0, null);
 609     }
 610 
 611     /**
 612      * Notify native layer of theme change, and flush cache
 613      */
 614     public void themeChanged() {
 615         synchronized(sun.awt.UNIXToolkit.GTK_LOCK) {
 616             native_switch_theme();
 617         }
 618         cache.flush();
 619     }
 620 
 621     /* GtkSettings enum mirrors that in gtk2_interface.h */
 622     public Object getSetting(Settings property) {
 623         synchronized(sun.awt.UNIXToolkit.GTK_LOCK) {
 624             return native_get_gtk_setting(property.ordinal());
 625         }
 626     }
 627 
 628     /**
 629      * Sets up the GtkAdjustment values for the native GtkRange widget
 630      * associated with the given region (e.g. SLIDER, SCROLL_BAR).
 631      */
 632     void setRangeValue(SynthContext context, Region id,
 633                        double value, double min, double max, double visible) {
 634         int widget = getWidgetType(context.getComponent(), id).ordinal();
 635         nativeSetRangeValue(widget, value, min, max, visible);
 636     }
 637 }