Path: blob/master/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java
41159 views
/*1* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt.X11;2627import java.awt.AWTEvent;28import java.awt.AWTException;29import java.awt.BufferCapabilities;30import java.awt.Color;31import java.awt.Component;32import java.awt.Container;33import java.awt.Cursor;34import java.awt.Dimension;35import java.awt.Font;36import java.awt.FontMetrics;37import java.awt.Graphics;38import java.awt.GraphicsConfiguration;39import java.awt.Image;40import java.awt.Insets;41import java.awt.Rectangle;42import java.awt.SystemColor;43import java.awt.Toolkit;44import java.awt.Window;45import java.awt.dnd.DropTarget;46import java.awt.dnd.peer.DropTargetPeer;47import java.awt.event.FocusEvent;48import java.awt.event.InputEvent;49import java.awt.event.InputMethodEvent;50import java.awt.event.KeyEvent;51import java.awt.event.MouseEvent;52import java.awt.event.MouseWheelEvent;53import java.awt.event.PaintEvent;54import java.awt.event.WindowEvent;55import java.awt.image.VolatileImage;56import java.awt.peer.ComponentPeer;57import java.awt.peer.ContainerPeer;58import java.util.Collection;59import java.util.Objects;60import java.util.Set;6162import sun.awt.AWTAccessor;63import sun.awt.AWTAccessor.ComponentAccessor;64import sun.awt.SunToolkit;65import sun.awt.X11GraphicsConfig;66import sun.awt.event.IgnorePaintEvent;67import sun.awt.image.SunVolatileImage;68import sun.java2d.BackBufferCapsProvider;69import sun.java2d.pipe.Region;70import sun.util.logging.PlatformLogger;717273public class XComponentPeer extends XWindow implements ComponentPeer, DropTargetPeer,74BackBufferCapsProvider75{76private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XComponentPeer");77private static final PlatformLogger buffersLog = PlatformLogger.getLogger("sun.awt.X11.XComponentPeer.multibuffer");78private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XComponentPeer");79private static final PlatformLogger fontLog = PlatformLogger.getLogger("sun.awt.X11.font.XComponentPeer");80private static final PlatformLogger enableLog = PlatformLogger.getLogger("sun.awt.X11.enable.XComponentPeer");81private static final PlatformLogger shapeLog = PlatformLogger.getLogger("sun.awt.X11.shape.XComponentPeer");8283boolean paintPending = false;84boolean isLayouting = false;85private boolean enabled;8687// Actually used only by XDecoratedPeer88protected int boundsOperation;8990Color foreground;91Color background;9293// Colors calculated as on Motif using MotifColorUtilties.94// If you use these, call updateMotifColors() in the peer's Constructor and95// setBackground(). Examples are XCheckboxPeer and XButtonPeer.96Color darkShadow;97Color lightShadow;98Color selectColor;99100Font font;101private long backBuffer = 0;102private VolatileImage xBackBuffer = null;103104static Color[] systemColors;105106XComponentPeer() {107}108109XComponentPeer (XCreateWindowParams params) {110super(params);111}112113XComponentPeer(Component target, long parentWindow, Rectangle bounds) {114super(target, parentWindow, bounds);115}116117/**118* Standard peer constructor, with corresponding Component119*/120XComponentPeer(Component target) {121super(target);122}123124125void preInit(XCreateWindowParams params) {126super.preInit(params);127boundsOperation = DEFAULT_OPERATION;128}129void postInit(XCreateWindowParams params) {130super.postInit(params);131132pSetCursor(target.getCursor());133134foreground = target.getForeground();135background = target.getBackground();136font = target.getFont();137138if (isInitialReshape()) {139Rectangle r = target.getBounds();140reshape(r.x, r.y, r.width, r.height);141}142143setEnabled(target.isEnabled());144145if (target.isVisible()) {146setVisible(true);147}148}149150protected boolean isInitialReshape() {151return true;152}153154public void reparent(ContainerPeer newNativeParent) {155XComponentPeer newPeer = (XComponentPeer)newNativeParent;156XToolkit.awtLock();157try {158XlibWrapper.XReparentWindow(XToolkit.getDisplay(),159getWindow(), newPeer.getContentWindow(),160scaleUp(x), scaleUp(y));161parentWindow = newPeer;162} finally {163XToolkit.awtUnlock();164}165}166public boolean isReparentSupported() {167return System.getProperty("sun.awt.X11.XComponentPeer.reparentNotSupported", "false").equals("false");168}169170@SuppressWarnings("deprecation")171public boolean isObscured() {172Container container = (target instanceof Container) ?173(Container)target : target.getParent();174175if (container == null) {176return true;177}178179Container parent;180while ((parent = container.getParent()) != null) {181container = parent;182}183184if (container instanceof Window) {185XWindowPeer wpeer = AWTAccessor.getComponentAccessor()186.getPeer(container);187if (wpeer != null) {188return (wpeer.winAttr.visibilityState !=189XWindowAttributesData.AWT_UNOBSCURED);190}191}192return true;193}194195public boolean canDetermineObscurity() {196return true;197}198199/*************************************************200* FOCUS STUFF201*************************************************/202203/**204* Keeps the track of focused state of the _NATIVE_ window205*/206boolean bHasFocus = false;207208/**209* Descendants should use this method to determine whether or not native window210* has focus.211*/212public final boolean hasFocus() {213return bHasFocus;214}215216/**217* Called when component receives focus218*/219public void focusGained(FocusEvent e) {220if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {221focusLog.fine("{0}", e);222}223bHasFocus = true;224}225226/**227* Called when component loses focus228*/229public void focusLost(FocusEvent e) {230if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {231focusLog.fine("{0}", e);232}233bHasFocus = false;234}235236public boolean isFocusable() {237/* should be implemented by other sub-classes */238return false;239}240241static final AWTEvent wrapInSequenced(AWTEvent event) {242return AWTAccessor.getSequencedEventAccessor().create(event);243}244245// TODO: consider moving it to KeyboardFocusManagerPeerImpl246@SuppressWarnings("deprecation")247public final boolean requestFocus(Component lightweightChild, boolean temporary,248boolean focusedWindowChangeAllowed, long time,249FocusEvent.Cause cause)250{251if (XKeyboardFocusManagerPeer.252processSynchronousLightweightTransfer(target, lightweightChild, temporary,253focusedWindowChangeAllowed, time))254{255return true;256}257258int result = XKeyboardFocusManagerPeer.259shouldNativelyFocusHeavyweight(target, lightweightChild,260temporary, focusedWindowChangeAllowed,261time, cause);262263switch (result) {264case XKeyboardFocusManagerPeer.SNFH_FAILURE:265return false;266case XKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:267// Currently we just generate focus events like we deal with lightweight instead of calling268// XSetInputFocus on native window269if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {270focusLog.finer("Proceeding with request to " +271lightweightChild + " in " + target);272}273/**274* The problems with requests in non-focused window arise because shouldNativelyFocusHeavyweight275* checks that native window is focused while appropriate WINDOW_GAINED_FOCUS has not yet276* been processed - it is in EventQueue. Thus, SNFH allows native request and stores request record277* in requests list - and it breaks our requests sequence as first record on WGF should be the last278* focus owner which had focus before WLF. So, we should not add request record for such requests279* but store this component in mostRecent - and return true as before for compatibility.280*/281Window parentWindow = SunToolkit.getContainingWindow(target);282if (parentWindow == null) {283return rejectFocusRequestHelper("WARNING: Parent window is null");284}285XWindowPeer wpeer = AWTAccessor.getComponentAccessor()286.getPeer(parentWindow);287if (wpeer == null) {288return rejectFocusRequestHelper("WARNING: Parent window's peer is null");289}290/*291* Passing null 'actualFocusedWindow' as we don't want to restore focus on it292* when a component inside a Frame is requesting focus.293* See 6314575 for details.294*/295boolean res = wpeer.requestWindowFocus(null);296297if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {298focusLog.finer("Requested window focus: " + res);299}300// If parent window can be made focused and has been made focused(synchronously)301// then we can proceed with children, otherwise we retreat.302if (!(res && parentWindow.isFocused())) {303return rejectFocusRequestHelper("Waiting for asynchronous processing of the request");304}305return XKeyboardFocusManagerPeer.deliverFocus(lightweightChild,306target,307temporary,308focusedWindowChangeAllowed,309time, cause);310// Motif compatibility code311case XKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:312// Either lightweight or excessive request - all events are generated.313return true;314}315return false;316}317318private boolean rejectFocusRequestHelper(String logMsg) {319if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {320focusLog.finer(logMsg);321}322XKeyboardFocusManagerPeer.removeLastFocusRequest(target);323return false;324}325326void handleJavaFocusEvent(AWTEvent e) {327if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {328focusLog.finer(e.toString());329}330if (e.getID() == FocusEvent.FOCUS_GAINED) {331focusGained((FocusEvent)e);332} else {333focusLost((FocusEvent)e);334}335}336337void handleJavaWindowFocusEvent(AWTEvent e) {338}339340/*************************************************341* END OF FOCUS STUFF342*************************************************/343344345346public void setVisible(boolean b) {347xSetVisible(b);348}349350public void hide() {351setVisible(false);352}353354/**355* @see java.awt.peer.ComponentPeer356*/357public void setEnabled(final boolean value) {358if (enableLog.isLoggable(PlatformLogger.Level.FINE)) {359enableLog.fine("{0}ing {1}", (value ? "Enabl" : "Disabl"), this);360}361boolean status = value;362// If any of our heavyweight ancestors are disable, we should be too363// See 6176875 for more information364final Container cp = SunToolkit.getNativeContainer(target);365final ComponentAccessor acc = AWTAccessor.getComponentAccessor();366if (cp != null) {367status &= acc.<XComponentPeer>getPeer(cp).isEnabled();368}369synchronized (getStateLock()) {370if (enabled == status) {371return;372}373enabled = status;374}375376if (target instanceof Container) {377final Component[] list = ((Container) target).getComponents();378for (final Component child : list) {379final ComponentPeer p = acc.getPeer(child);380if (p != null) {381p.setEnabled(status && child.isEnabled());382}383}384}385repaint();386}387388//389// public so aw/Window can call it390//391public final boolean isEnabled() {392synchronized (getStateLock()) {393return enabled;394}395}396397@Override398public void paint(final Graphics g) {399super.paint(g);400// allow target to change the picture401target.paint(g);402}403404public Graphics getGraphics() {405return getGraphics(surfaceData, getPeerForeground(), getPeerBackground(), getPeerFont());406}407public void print(Graphics g) {408// clear rect here to emulate X clears rect before Expose409g.setColor(target.getBackground());410g.fillRect(0, 0, target.getWidth(), target.getHeight());411g.setColor(target.getForeground());412// paint peer413paintPeer(g);414// allow target to change the picture415target.print(g);416}417418public void setBounds(int x, int y, int width, int height, int op) {419this.x = x;420this.y = y;421this.width = width;422this.height = height;423xSetBounds(x,y,width,height);424validateSurface();425layout();426}427428public void reshape(int x, int y, int width, int height) {429setBounds(x, y, width, height, SET_BOUNDS);430}431432public void coalescePaintEvent(PaintEvent e) {433Rectangle r = e.getUpdateRect();434if (!(e instanceof IgnorePaintEvent)) {435paintArea.add(r, e.getID());436}437if (true) {438switch(e.getID()) {439case PaintEvent.UPDATE:440if (log.isLoggable(PlatformLogger.Level.FINER)) {441log.finer("XCP coalescePaintEvent : UPDATE : add : x = " +442r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);443}444return;445case PaintEvent.PAINT:446if (log.isLoggable(PlatformLogger.Level.FINER)) {447log.finer("XCP coalescePaintEvent : PAINT : add : x = " +448r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);449}450return;451}452}453}454455XWindowPeer getParentTopLevel() {456ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();457Container parent = (target instanceof Container) ? ((Container)target) : (compAccessor.getParent(target));458// Search for parent window459while (parent != null && !(parent instanceof Window)) {460parent = compAccessor.getParent(parent);461}462if (parent != null) {463return (XWindowPeer)compAccessor.getPeer(parent);464} else {465return null;466}467}468469/* This method is intended to be over-ridden by peers to perform user interaction */470void handleJavaMouseEvent(MouseEvent e) {471switch (e.getID()) {472case MouseEvent.MOUSE_PRESSED:473if (target == e.getSource() &&474!target.isFocusOwner() &&475XKeyboardFocusManagerPeer.shouldFocusOnClick(target))476{477XWindowPeer parentXWindow = getParentTopLevel();478Window parentWindow = ((Window)parentXWindow.getTarget());479// Simple windows are non-focusable in X terms but focusable in Java terms.480// As X-non-focusable they don't receive any focus events - we should generate them481// by ourselfves.482// if (parentXWindow.isFocusableWindow() /*&& parentXWindow.isSimpleWindow()*/ &&483// !(getCurrentNativeFocusedWindow() == parentWindow))484// {485// setCurrentNativeFocusedWindow(parentWindow);486// WindowEvent wfg = new WindowEvent(parentWindow, WindowEvent.WINDOW_GAINED_FOCUS);487// parentWindow.dispatchEvent(wfg);488// }489XKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT);490}491break;492}493}494495/* This method is intended to be over-ridden by peers to perform user interaction */496void handleJavaKeyEvent(KeyEvent e) {497}498499/* This method is intended to be over-ridden by peers to perform user interaction */500void handleJavaMouseWheelEvent(MouseWheelEvent e) {501}502503504/* This method is intended to be over-ridden by peers to perform user interaction */505void handleJavaInputMethodEvent(InputMethodEvent e) {506}507508void handleF10JavaKeyEvent(KeyEvent e) {509if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_F10) {510XWindowPeer winPeer = this.getToplevelXWindow();511if (winPeer instanceof XFramePeer) {512XMenuBarPeer mPeer = ((XFramePeer)winPeer).getMenubarPeer();513if (mPeer != null) {514mPeer.handleF10KeyPress(e);515}516}517}518}519520@SuppressWarnings("fallthrough")521public void handleEvent(java.awt.AWTEvent e) {522if ((e instanceof InputEvent) && !((InputEvent)e).isConsumed() && target.isEnabled()) {523if (e instanceof MouseEvent) {524if (e instanceof MouseWheelEvent) {525handleJavaMouseWheelEvent((MouseWheelEvent) e);526}527else528handleJavaMouseEvent((MouseEvent) e);529}530else if (e instanceof KeyEvent) {531handleF10JavaKeyEvent((KeyEvent)e);532handleJavaKeyEvent((KeyEvent)e);533}534}535else if (e instanceof KeyEvent && !((InputEvent)e).isConsumed()) {536// even if target is disabled.537handleF10JavaKeyEvent((KeyEvent)e);538}539else if (e instanceof InputMethodEvent) {540handleJavaInputMethodEvent((InputMethodEvent) e);541}542543int id = e.getID();544545switch(id) {546case PaintEvent.PAINT:547// Got native painting548paintPending = false;549// Fallthrough to next statement550case PaintEvent.UPDATE:551// Skip all painting while layouting and all UPDATEs552// while waiting for native paint553if (!isLayouting && !paintPending) {554paintArea.paint(target,false);555}556return;557case FocusEvent.FOCUS_LOST:558case FocusEvent.FOCUS_GAINED:559handleJavaFocusEvent(e);560break;561case WindowEvent.WINDOW_LOST_FOCUS:562case WindowEvent.WINDOW_GAINED_FOCUS:563handleJavaWindowFocusEvent(e);564break;565default:566break;567}568569}570571public Dimension getMinimumSize() {572return target.getSize();573}574575public Dimension getPreferredSize() {576return getMinimumSize();577}578579public void layout() {}580581void updateMotifColors(Color bg) {582int red = bg.getRed();583int green = bg.getGreen();584int blue = bg.getBlue();585586darkShadow = new Color(MotifColorUtilities.calculateBottomShadowFromBackground(red,green,blue));587lightShadow = new Color(MotifColorUtilities.calculateTopShadowFromBackground(red,green,blue));588selectColor= new Color(MotifColorUtilities.calculateSelectFromBackground(red,green,blue));589}590591/*592* Draw a 3D rectangle using the Motif colors.593* "Normal" rectangles have shadows on the bottom.594* "Depressed" rectangles (such as pressed buttons) have shadows on the top,595* in which case true should be passed for topShadow.596*/597public void drawMotif3DRect(Graphics g,598int x, int y, int width, int height,599boolean topShadow) {600g.setColor(topShadow ? darkShadow : lightShadow);601g.drawLine(x, y, x+width, y); // top602g.drawLine(x, y+height, x, y); // left603604g.setColor(topShadow ? lightShadow : darkShadow );605g.drawLine(x+1, y+height, x+width, y+height); // bottom606g.drawLine(x+width, y+height, x+width, y+1); // right607}608609@Override610public void setBackground(Color c) {611if (log.isLoggable(PlatformLogger.Level.FINE)) {612log.fine("Set background to " + c);613}614synchronized (getStateLock()) {615if (Objects.equals(background, c)) {616return;617}618background = c;619}620super.setBackground(c);621repaint();622}623624@Override625public void setForeground(Color c) {626if (log.isLoggable(PlatformLogger.Level.FINE)) {627log.fine("Set foreground to " + c);628}629synchronized (getStateLock()) {630if (Objects.equals(foreground, c)) {631return;632}633foreground = c;634}635repaint();636}637638/**639* Gets the font metrics for the specified font.640* @param font the font for which font metrics is to be641* obtained642* @return the font metrics for {@code font}643* @see #getFont644* @see java.awt.peer.ComponentPeer#getFontMetrics(Font)645* @see Toolkit#getFontMetrics(Font)646* @since 1.0647*/648public FontMetrics getFontMetrics(Font font) {649if (fontLog.isLoggable(PlatformLogger.Level.FINE)) {650fontLog.fine("Getting font metrics for " + font);651}652return sun.font.FontDesignMetrics.getMetrics(font);653}654655@Override656public void setFont(Font f) {657if (f == null) {658f = XWindow.getDefaultFont();659}660synchronized (getStateLock()) {661if (f.equals(font)) {662return;663}664font = f;665}666// as it stands currently we don't need to do layout since667// layout is done in the Component upon setFont.668//layout();669repaint();670}671672public Font getFont() {673return font;674}675676public void updateCursorImmediately() {677XGlobalCursorManager.getCursorManager().updateCursorImmediately();678}679680public final void pSetCursor(Cursor cursor) {681this.pSetCursor(cursor, true);682}683684/*685* The method changes the cursor.686* @param cursor a new cursor to change to.687* @param ignoreSubComponents if {@code true} is passed then688* the new cursor will be installed on window.689* if {@code false} is passed then690* subsequent components will try to handle691* this request and install their cursor.692*/693//ignoreSubComponents not used here694public void pSetCursor(Cursor cursor, boolean ignoreSubComponents) {695XToolkit.awtLock();696try {697long xcursor = XGlobalCursorManager.getCursor(cursor);698699XSetWindowAttributes xwa = new XSetWindowAttributes();700xwa.set_cursor(xcursor);701702long valuemask = XConstants.CWCursor;703704XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),getWindow(),valuemask,xwa.pData);705XlibWrapper.XFlush(XToolkit.getDisplay());706xwa.dispose();707} finally {708XToolkit.awtUnlock();709}710}711712public Image createImage(int width, int height) {713return graphicsConfig.createAcceleratedImage(target, width, height);714}715716public VolatileImage createVolatileImage(int width, int height) {717return new SunVolatileImage(target, width, height);718}719720public Insets getInsets() {721return new Insets(0, 0, 0, 0);722}723724public void beginValidate() {725}726727public void endValidate() {728}729730// Returns true if we are inside begin/endLayout and731// are waiting for native painting732public boolean isPaintPending() {733return paintPending && isLayouting;734}735736public boolean handlesWheelScrolling() {737return false;738}739740public void beginLayout() {741// Skip all painting till endLayout742isLayouting = true;743744}745746public void endLayout() {747if (!paintPending && !paintArea.isEmpty()748&& !AWTAccessor.getComponentAccessor().getIgnoreRepaint(target))749{750// if not waiting for native painting repaint damaged area751postEvent(new PaintEvent(target, PaintEvent.PAINT,752new Rectangle()));753}754isLayouting = false;755}756757public Color getWinBackground() {758return getPeerBackground();759}760761static int[] getRGBvals(Color c) {762763int[] rgbvals = new int[3];764765rgbvals[0] = c.getRed();766rgbvals[1] = c.getGreen();767rgbvals[2] = c.getBlue();768769return rgbvals;770}771772static final int BACKGROUND_COLOR = 0;773static final int HIGHLIGHT_COLOR = 1;774static final int SHADOW_COLOR = 2;775static final int FOREGROUND_COLOR = 3;776777public Color[] getGUIcolors() {778Color[] c = new Color[4];779float backb, highb, shadowb, hue, saturation;780c[BACKGROUND_COLOR] = getWinBackground();781if (c[BACKGROUND_COLOR] == null) {782c[BACKGROUND_COLOR] = super.getWinBackground();783}784if (c[BACKGROUND_COLOR] == null) {785c[BACKGROUND_COLOR] = Color.lightGray;786}787788int[] rgb = getRGBvals(c[BACKGROUND_COLOR]);789790float[] hsb = Color.RGBtoHSB(rgb[0],rgb[1],rgb[2],null);791792hue = hsb[0];793saturation = hsb[1];794backb = hsb[2];795796797/* Calculate Highlight Brightness */798799highb = backb + 0.2f;800shadowb = backb - 0.4f;801if ((highb > 1.0) ) {802if ((1.0 - backb) < 0.05) {803highb = shadowb + 0.25f;804} else {805highb = 1.0f;806}807} else {808if (shadowb < 0.0) {809if ((backb - 0.0) < 0.25) {810highb = backb + 0.75f;811shadowb = highb - 0.2f;812} else {813shadowb = 0.0f;814}815}816}817c[HIGHLIGHT_COLOR] = Color.getHSBColor(hue,saturation,highb);818c[SHADOW_COLOR] = Color.getHSBColor(hue,saturation,shadowb);819820821/*822c[SHADOW_COLOR] = c[BACKGROUND_COLOR].darker();823int r2 = c[SHADOW_COLOR].getRed();824int g2 = c[SHADOW_COLOR].getGreen();825int b2 = c[SHADOW_COLOR].getBlue();826*/827828c[FOREGROUND_COLOR] = getPeerForeground();829if (c[FOREGROUND_COLOR] == null) {830c[FOREGROUND_COLOR] = Color.black;831}832/*833if ((c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR]))834&& (c[BACKGROUND_COLOR].equals(c[SHADOW_COLOR]))) {835c[SHADOW_COLOR] = new Color(c[BACKGROUND_COLOR].getRed() + 75,836c[BACKGROUND_COLOR].getGreen() + 75,837c[BACKGROUND_COLOR].getBlue() + 75);838c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR].brighter();839} else if (c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR])) {840c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR];841c[SHADOW_COLOR] = c[SHADOW_COLOR].darker();842}843*/844if (! isEnabled()) {845c[BACKGROUND_COLOR] = c[BACKGROUND_COLOR].darker();846// Reduce the contrast847// Calculate the NTSC gray (NB: REC709 L* might be better!)848// for foreground and background; then multiply the foreground849// by the average lightness850851852Color tc = c[BACKGROUND_COLOR];853int bg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11;854855tc = c[FOREGROUND_COLOR];856int fg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11;857858float ave = (float) ((fg + bg) / 51000.0);859// 255 * 100 * 2860861Color newForeground = new Color((int) (tc.getRed() * ave),862(int) (tc.getGreen() * ave),863(int) (tc.getBlue() * ave));864865if (newForeground.equals(c[FOREGROUND_COLOR])) {866// This probably means the foreground color is black or white867newForeground = new Color(ave, ave, ave);868}869c[FOREGROUND_COLOR] = newForeground;870871}872873874return c;875}876877/**878* Returns an array of Colors similar to getGUIcolors(), but using the879* System colors. This is useful if pieces of a Component (such as880* the integrated scrollbars of a List) should retain the System color881* instead of the background color set by Component.setBackground().882*/883static Color[] getSystemColors() {884if (systemColors == null) {885systemColors = new Color[4];886systemColors[BACKGROUND_COLOR] = SystemColor.window;887systemColors[HIGHLIGHT_COLOR] = SystemColor.controlLtHighlight;888systemColors[SHADOW_COLOR] = SystemColor.controlShadow;889systemColors[FOREGROUND_COLOR] = SystemColor.windowText;890}891return systemColors;892}893894/**895* Draw a 3D oval.896*/897public void draw3DOval(Graphics g, Color[] colors,898int x, int y, int w, int h, boolean raised)899{900Color c = g.getColor();901g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]);902g.drawArc(x, y, w, h, 45, 180);903g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]);904g.drawArc(x, y, w, h, 225, 180);905g.setColor(c);906}907908public void draw3DRect(Graphics g, Color[] colors,909int x, int y, int width, int height, boolean raised)910{911Color c = g.getColor();912g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]);913g.drawLine(x, y, x, y + height);914g.drawLine(x + 1, y, x + width - 1, y);915g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]);916g.drawLine(x + 1, y + height, x + width, y + height);917g.drawLine(x + width, y, x + width, y + height - 1);918g.setColor(c);919}920921/*922* drawXXX() methods are used to print the native components by923* rendering the Motif look ourselves.924* ToDo(aim): needs to query native motif for more accurate color925* information.926*/927void draw3DOval(Graphics g, Color bg,928int x, int y, int w, int h, boolean raised)929{930Color c = g.getColor();931Color shadow = bg.darker();932Color highlight = bg.brighter();933934g.setColor(raised ? highlight : shadow);935g.drawArc(x, y, w, h, 45, 180);936g.setColor(raised ? shadow : highlight);937g.drawArc(x, y, w, h, 225, 180);938g.setColor(c);939}940941void draw3DRect(Graphics g, Color bg,942int x, int y, int width, int height,943boolean raised) {944Color c = g.getColor();945Color shadow = bg.darker();946Color highlight = bg.brighter();947948g.setColor(raised ? highlight : shadow);949g.drawLine(x, y, x, y + height);950g.drawLine(x + 1, y, x + width - 1, y);951g.setColor(raised ? shadow : highlight);952g.drawLine(x + 1, y + height, x + width, y + height);953g.drawLine(x + width, y, x + width, y + height - 1);954g.setColor(c);955}956957void drawScrollbar(Graphics g, Color bg, int thickness, int length,958int min, int max, int val, int vis, boolean horizontal) {959Color c = g.getColor();960double f = (double)(length - 2*(thickness-1)) / Math.max(1, ((max - min) + vis));961int v1 = thickness + (int)(f * (val - min));962int v2 = (int)(f * vis);963int w2 = thickness-4;964int[] tpts_x = new int[3];965int[] tpts_y = new int[3];966967if (length < 3*w2 ) {968v1 = v2 = 0;969if (length < 2*w2 + 2) {970w2 = (length-2)/2;971}972} else if (v2 < 7) {973// enforce a minimum handle size974v1 = Math.max(0, v1 - ((7 - v2)>>1));975v2 = 7;976}977978int ctr = thickness/2;979int sbmin = ctr - w2/2;980int sbmax = ctr + w2/2;981982// paint the background slightly darker983{984Color d = new Color((int) (bg.getRed() * 0.85),985(int) (bg.getGreen() * 0.85),986(int) (bg.getBlue() * 0.85));987988g.setColor(d);989if (horizontal) {990g.fillRect(0, 0, length, thickness);991} else {992g.fillRect(0, 0, thickness, length);993}994}995996// paint the thumb and arrows in the normal background color997g.setColor(bg);998if (v1 > 0) {999if (horizontal) {1000g.fillRect(v1, 3, v2, thickness-3);1001} else {1002g.fillRect(3, v1, thickness-3, v2);1003}1004}10051006tpts_x[0] = ctr; tpts_y[0] = 2;1007tpts_x[1] = sbmin; tpts_y[1] = w2;1008tpts_x[2] = sbmax; tpts_y[2] = w2;1009if (horizontal) {1010g.fillPolygon(tpts_y, tpts_x, 3);1011} else {1012g.fillPolygon(tpts_x, tpts_y, 3);1013}10141015tpts_y[0] = length-2;1016tpts_y[1] = length-w2;1017tpts_y[2] = length-w2;1018if (horizontal) {1019g.fillPolygon(tpts_y, tpts_x, 3);1020} else {1021g.fillPolygon(tpts_x, tpts_y, 3);1022}10231024Color highlight = bg.brighter();10251026// // // // draw the "highlighted" edges1027g.setColor(highlight);10281029// outline & arrows1030if (horizontal) {1031g.drawLine(1, thickness, length - 1, thickness);1032g.drawLine(length - 1, 1, length - 1, thickness);10331034// arrows1035g.drawLine(1, ctr, w2, sbmin);1036g.drawLine(length - w2, sbmin, length - w2, sbmax);1037g.drawLine(length - w2, sbmin, length - 2, ctr);10381039} else {1040g.drawLine(thickness, 1, thickness, length - 1);1041g.drawLine(1, length - 1, thickness, length - 1);10421043// arrows1044g.drawLine(ctr, 1, sbmin, w2);1045g.drawLine(sbmin, length - w2, sbmax, length - w2);1046g.drawLine(sbmin, length - w2, ctr, length - 2);1047}10481049// thumb1050if (v1 > 0) {1051if (horizontal) {1052g.drawLine(v1, 2, v1 + v2, 2);1053g.drawLine(v1, 2, v1, thickness-3);1054} else {1055g.drawLine(2, v1, 2, v1 + v2);1056g.drawLine(2, v1, thickness-3, v1);1057}1058}10591060Color shadow = bg.darker();10611062// // // // draw the "shadowed" edges1063g.setColor(shadow);10641065// outline && arrows1066if (horizontal) {1067g.drawLine(0, 0, 0, thickness);1068g.drawLine(0, 0, length - 1, 0);10691070// arrows1071g.drawLine(w2, sbmin, w2, sbmax);1072g.drawLine(w2, sbmax, 1, ctr);1073g.drawLine(length-2, ctr, length-w2, sbmax);10741075} else {1076g.drawLine(0, 0, thickness, 0);1077g.drawLine(0, 0, 0, length - 1);10781079// arrows1080g.drawLine(sbmin, w2, sbmax, w2);1081g.drawLine(sbmax, w2, ctr, 1);1082g.drawLine(ctr, length-2, sbmax, length-w2);1083}10841085// thumb1086if (v1 > 0) {1087if (horizontal) {1088g.drawLine(v1 + v2, 2, v1 + v2, thickness-2);1089g.drawLine(v1, thickness-2, v1 + v2, thickness-2);1090} else {1091g.drawLine(2, v1 + v2, thickness-2, v1 + v2);1092g.drawLine(thickness-2, v1, thickness-2, v1 + v2);1093}1094}1095g.setColor(c);1096}10971098/**1099* The following multibuffering-related methods delegate to our1100* associated GraphicsConfig (X11 or GLX) to handle the appropriate1101* native windowing system specific actions.1102*/11031104private BufferCapabilities backBufferCaps;11051106public void createBuffers(int numBuffers, BufferCapabilities caps)1107throws AWTException1108{1109if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) {1110buffersLog.fine("createBuffers(" + numBuffers + ", " + caps + ")");1111}1112// set the caps first, they're used when creating the bb1113backBufferCaps = caps;1114backBuffer = graphicsConfig.createBackBuffer(this, numBuffers, caps);1115xBackBuffer = graphicsConfig.createBackBufferImage(target,1116backBuffer);1117}11181119@Override1120public BufferCapabilities getBackBufferCaps() {1121return backBufferCaps;1122}11231124public void flip(int x1, int y1, int x2, int y2,1125BufferCapabilities.FlipContents flipAction)1126{1127if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) {1128buffersLog.fine("flip(" + flipAction + ")");1129}1130if (backBuffer == 0) {1131throw new IllegalStateException("Buffers have not been created");1132}1133graphicsConfig.flip(this, target, xBackBuffer,1134x1, y1, x2, y2, flipAction);1135}11361137public Image getBackBuffer() {1138if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) {1139buffersLog.fine("getBackBuffer()");1140}1141if (backBuffer == 0) {1142throw new IllegalStateException("Buffers have not been created");1143}1144return xBackBuffer;1145}11461147public void destroyBuffers() {1148if (buffersLog.isLoggable(PlatformLogger.Level.FINE)) {1149buffersLog.fine("destroyBuffers()");1150}1151graphicsConfig.destroyBackBuffer(backBuffer);1152backBuffer = 0;1153xBackBuffer = null;1154}11551156// End of multi-buffering11571158public void notifyTextComponentChange(boolean add){1159Container parent = AWTAccessor.getComponentAccessor().getParent(target);1160while(!(parent == null ||1161parent instanceof java.awt.Frame ||1162parent instanceof java.awt.Dialog)) {1163parent = AWTAccessor.getComponentAccessor().getParent(parent);1164}11651166/* FIX ME - FIX ME need to implement InputMethods1167if (parent instanceof java.awt.Frame ||1168parent instanceof java.awt.Dialog) {1169if (add)1170((MInputMethodControl)parent.getPeer()).addTextComponent((MComponentPeer)this);1171else1172((MInputMethodControl)parent.getPeer()).removeTextComponent((MComponentPeer)this);1173}1174*/1175}11761177/**1178* Returns true if this event is disabled and shouldn't be processed by window1179* Currently if target component is disabled the following event will be disabled on window:1180* ButtonPress, ButtonRelease, KeyPress, KeyRelease, EnterNotify, LeaveNotify, MotionNotify1181*/1182protected boolean isEventDisabled(XEvent e) {1183if (enableLog.isLoggable(PlatformLogger.Level.FINEST)) {1184enableLog.finest("Component is {1}, checking for disabled event {0}", e, (isEnabled()?"enabled":"disable"));1185}1186if (!isEnabled()) {1187switch (e.get_type()) {1188case XConstants.ButtonPress:1189case XConstants.ButtonRelease:1190case XConstants.KeyPress:1191case XConstants.KeyRelease:1192case XConstants.EnterNotify:1193case XConstants.LeaveNotify:1194case XConstants.MotionNotify:1195if (enableLog.isLoggable(PlatformLogger.Level.FINER)) {1196enableLog.finer("Event {0} is disable", e);1197}1198return true;1199}1200}1201switch(e.get_type()) {1202case XConstants.MapNotify:1203case XConstants.UnmapNotify:1204return true;1205}1206return super.isEventDisabled(e);1207}12081209Color getPeerBackground() {1210return background;1211}12121213Color getPeerForeground() {1214return foreground;1215}12161217Font getPeerFont() {1218return font;1219}12201221Dimension getPeerSize() {1222return new Dimension(width,height);1223}12241225public void setBoundsOperation(int operation) {1226synchronized(getStateLock()) {1227if (boundsOperation == DEFAULT_OPERATION) {1228boundsOperation = operation;1229} else if (operation == RESET_OPERATION) {1230boundsOperation = DEFAULT_OPERATION;1231}1232}1233}12341235static String operationToString(int operation) {1236switch (operation) {1237case SET_LOCATION:1238return "SET_LOCATION";1239case SET_SIZE:1240return "SET_SIZE";1241case SET_CLIENT_SIZE:1242return "SET_CLIENT_SIZE";1243default:1244case SET_BOUNDS:1245return "SET_BOUNDS";1246}1247}12481249/**1250* Lowers this component at the bottom of the above HW peer. If the above parameter1251* is null then the method places this component at the top of the Z-order.1252*/1253public void setZOrder(ComponentPeer above) {1254long aboveWindow = (above != null) ? ((XComponentPeer)above).getWindow() : 0;12551256XToolkit.awtLock();1257try{1258XlibWrapper.SetZOrder(XToolkit.getDisplay(), getWindow(), aboveWindow);1259}finally{1260XToolkit.awtUnlock();1261}1262}12631264private void addTree(Collection<Long> order, Set<Long> set, Container cont) {1265for (int i = 0; i < cont.getComponentCount(); i++) {1266Component comp = cont.getComponent(i);1267Object peer = AWTAccessor.getComponentAccessor().getPeer(comp);1268if (peer instanceof XComponentPeer) {1269Long window = Long.valueOf(((XComponentPeer)peer).getWindow());1270if (!set.contains(window)) {1271set.add(window);1272order.add(window);1273}1274} else if (comp instanceof Container) {1275// It is lightweight container, it might contain heavyweight components attached to this1276// peer1277addTree(order, set, (Container)comp);1278}1279}1280}12811282/****** DropTargetPeer implementation ********************/12831284public void addDropTarget(DropTarget dt) {1285Component comp = target;1286while(!(comp == null || comp instanceof Window)) {1287comp = comp.getParent();1288}12891290if (comp instanceof Window) {1291XWindowPeer wpeer = AWTAccessor.getComponentAccessor().getPeer(comp);1292if (wpeer != null) {1293wpeer.addDropTarget();1294}1295}1296}12971298public void removeDropTarget(DropTarget dt) {1299Component comp = target;1300while(!(comp == null || comp instanceof Window)) {1301comp = comp.getParent();1302}13031304if (comp instanceof Window) {1305XWindowPeer wpeer = AWTAccessor.getComponentAccessor()1306.getPeer(comp);1307if (wpeer != null) {1308wpeer.removeDropTarget();1309}1310}1311}13121313/**1314* Applies the shape to the X-window.1315* @since 1.71316*/1317public void applyShape(Region shape) {1318if (XlibUtil.isShapingSupported()) {1319if (shapeLog.isLoggable(PlatformLogger.Level.FINER)) {1320shapeLog.finer(1321"*** INFO: Setting shape: PEER: " + this1322+ "; WINDOW: " + getWindow()1323+ "; TARGET: " + target1324+ "; SHAPE: " + shape);1325}1326XToolkit.awtLock();1327try {1328if (shape != null) {13291330int scale = getScale();1331if (scale != 1) {1332shape = shape.getScaledRegion(scale, scale);1333}13341335XlibWrapper.SetRectangularShape(1336XToolkit.getDisplay(),1337getWindow(),1338shape.getLoX(), shape.getLoY(),1339shape.getHiX(), shape.getHiY(),1340(shape.isRectangular() ? null : shape)1341);1342} else {1343XlibWrapper.SetRectangularShape(1344XToolkit.getDisplay(),1345getWindow(),13460, 0,13470, 0,1348null1349);1350}1351} finally {1352XToolkit.awtUnlock();1353}1354} else {1355if (shapeLog.isLoggable(PlatformLogger.Level.FINER)) {1356shapeLog.finer("*** WARNING: Shaping is NOT supported!");1357}1358}1359}13601361public boolean updateGraphicsData(GraphicsConfiguration gc) {1362int oldVisual = -1, newVisual = -1;13631364if (graphicsConfig != null) {1365oldVisual = graphicsConfig.getVisual();1366}1367if (gc != null && gc instanceof X11GraphicsConfig) {1368newVisual = ((X11GraphicsConfig)gc).getVisual();1369}13701371// If the new visual differs from the old one, the peer must be1372// recreated because X11 does not allow changing the visual on the fly.1373// So we even skip the initGraphicsConfiguration() call.1374// The initial assignment should happen though, hence the != -1 thing.1375if (oldVisual != -1 && oldVisual != newVisual) {1376return true;1377}13781379initGraphicsConfiguration();1380doValidateSurface();1381return false;1382}1383}138413851386