[Title] bug fix : side effect of SWT.ON_TOP
authorSon Hyunjun <hj79.son@samsung.com>
Tue, 17 Apr 2012 00:15:24 +0000 (09:15 +0900)
committerSon Hyunjun <hj79.son@samsung.com>
Tue, 17 Apr 2012 00:15:24 +0000 (09:15 +0900)
[Type] Bugfix
[Module] Skin
[Priority] Major
[CQ#]
[Redmine#]
[Problem] alway on top hides emulator menu bar(in Windows and Ubuntu) and steals other app's focus(in Ubuntu).
[Cause]
[Solution] use native apis based on 'wmctrl'.

Change-Id: I7bfe481e34b69780388b2953bc6a7dcb6a735317

tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkin.java [changed mode: 0644->0755]
tizen/src/skin/client/src/org/tizen/emulator/skin/EmulatorSkinMain.java

old mode 100644 (file)
new mode 100755 (executable)
index 7911540..ae56898
@@ -31,7 +31,10 @@ package org.tizen.emulator.skin;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -119,6 +122,9 @@ public class EmulatorSkin {
 
        }
 
+       public static final String GTK_OS_CLASS = "org.eclipse.swt.internal.gtk.OS";
+       public static final String WIN32_OS_CLASS = "org.eclipse.swt.internal.win32.OS";
+       
        private Logger logger = SkinLogger.getSkinLogger( EmulatorSkin.class ).getLogger();
 
        private EmulatorConfig config;
@@ -166,17 +172,13 @@ public class EmulatorSkin {
        private MenuDetectListener canvasMenuDetectListener;
 
        private EmulatorSkin reopenSkin;
-
+       
        protected EmulatorSkin( EmulatorConfig config, boolean isOnTop ) {
                this.config = config;
                this.isDefaultHoverColor = true;
-
                this.isOnTop = isOnTop;
-
+               
                int style = SWT.NO_TRIM;
-               if ( isOnTop ) {
-                       style |= SWT.ON_TOP;
-               }
                this.shell = new Shell( Display.getDefault(), style );
 
        }
@@ -257,39 +259,39 @@ public class EmulatorSkin {
 
        }
 
-       private void readyToReopen( EmulatorSkin sourceSkin, boolean isOnTop ) {
-
-               logger.info( "Start Changing AlwaysOnTop status" );
-
-               sourceSkin.reopenSkin = new EmulatorSkin( sourceSkin.config, isOnTop );
-
-               sourceSkin.reopenSkin.lcdCanvas = sourceSkin.lcdCanvas;
-               Point previousLocation = sourceSkin.shell.getLocation();
-
-               sourceSkin.reopenSkin.composeInternal( sourceSkin.lcdCanvas, previousLocation.x, previousLocation.y,
-                               sourceSkin.currentLcdWidth, sourceSkin.currentLcdHeight, sourceSkin.currentScale,
-                               sourceSkin.currentRotationId, sourceSkin.isOnUsbKbd );
-
-               sourceSkin.reopenSkin.windowHandleId = sourceSkin.windowHandleId;
-
-               sourceSkin.reopenSkin.communicator = sourceSkin.communicator;
-               sourceSkin.reopenSkin.communicator.resetSkin( reopenSkin );
-
-               sourceSkin.isAboutToReopen = true;
-               sourceSkin.isShutdownRequested = true;
-
-               if ( sourceSkin.isScreenShotOpened && ( null != sourceSkin.screenShotDialog ) ) {
-                       sourceSkin.screenShotDialog.setReserveImage( true );
-                       sourceSkin.screenShotDialog.setEmulatorSkin( reopenSkin );
-                       reopenSkin.isScreenShotOpened = true;
-                       reopenSkin.screenShotDialog = sourceSkin.screenShotDialog;
-                       // see open() method to know next logic for screenshot dialog.
-               }
-
-               sourceSkin.lcdCanvas.setParent( reopenSkin.shell );
-               sourceSkin.shell.close();
-
-       }
+//     private void readyToReopen( EmulatorSkin sourceSkin, boolean isOnTop ) {
+//
+//             logger.info( "Start Changing AlwaysOnTop status" );
+//
+//             sourceSkin.reopenSkin = new EmulatorSkin( sourceSkin.config, isOnTop );
+//
+//             sourceSkin.reopenSkin.lcdCanvas = sourceSkin.lcdCanvas;
+//             Point previousLocation = sourceSkin.shell.getLocation();
+//
+//             sourceSkin.reopenSkin.composeInternal( sourceSkin.lcdCanvas, previousLocation.x, previousLocation.y,
+//                             sourceSkin.currentLcdWidth, sourceSkin.currentLcdHeight, sourceSkin.currentScale,
+//                             sourceSkin.currentRotationId, sourceSkin.isOnUsbKbd );
+//
+//             sourceSkin.reopenSkin.windowHandleId = sourceSkin.windowHandleId;
+//
+//             sourceSkin.reopenSkin.communicator = sourceSkin.communicator;
+//             sourceSkin.reopenSkin.communicator.resetSkin( reopenSkin );
+//
+//             sourceSkin.isAboutToReopen = true;
+//             sourceSkin.isShutdownRequested = true;
+//
+//             if ( sourceSkin.isScreenShotOpened && ( null != sourceSkin.screenShotDialog ) ) {
+//                     sourceSkin.screenShotDialog.setReserveImage( true );
+//                     sourceSkin.screenShotDialog.setEmulatorSkin( reopenSkin );
+//                     reopenSkin.isScreenShotOpened = true;
+//                     reopenSkin.screenShotDialog = sourceSkin.screenShotDialog;
+//                     // see open() method to know next logic for screenshot dialog.
+//             }
+//
+//             sourceSkin.lcdCanvas.setParent( reopenSkin.shell );
+//             sourceSkin.shell.close();
+//
+//     }
 
        private int getWindowHandleId() {
 
@@ -402,6 +404,8 @@ public class EmulatorSkin {
                        currentKeyPressedImage.dispose();
                }
 
+               shell.redraw();
+
                currentImage = SkinUtil.createScaledImage( imageRegistry, shell, rotationId, scale, ImageType.IMG_TYPE_MAIN );
                currentKeyPressedImage = SkinUtil.createScaledImage( imageRegistry, shell, rotationId, scale,
                                ImageType.IMG_TYPE_PRESSED );
@@ -884,6 +888,80 @@ public class EmulatorSkin {
 
        }
 
+       private Field getOSField( String field ) {
+
+               String className = "";
+               if ( SkinUtil.isLinuxPlatform() ) {
+                       className = GTK_OS_CLASS;
+               } else if ( SkinUtil.isWindowsPlatform() ) {
+                       className = WIN32_OS_CLASS;
+               }
+
+               Field f = null;
+               try {
+                       f = Class.forName( className ).getField( field );
+               } catch ( ClassNotFoundException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( SecurityException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( NoSuchFieldException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+               return f;
+               
+       }
+
+       private Method getOSMethod( String method, Class<?>... parameterTypes ) {
+
+               String className = "";
+               if ( SkinUtil.isLinuxPlatform() ) {
+                       className = GTK_OS_CLASS;
+               } else if ( SkinUtil.isWindowsPlatform() ) {
+                       className = WIN32_OS_CLASS;
+               }
+
+               Method m = null;
+               try {
+                       m = Class.forName( className ).getMethod( method, parameterTypes );
+               } catch ( ClassNotFoundException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( SecurityException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( NoSuchMethodException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+               return m;
+
+       }
+
+       private Method getOSMethod( String method ) {
+               return  getOSMethod( method, new Class<?>[]{} );
+       }
+
+       private Object invokeOSMethod( Method method, Object... args ) {
+
+               if ( null == method ) {
+                       return null;
+               }
+
+               try {
+                       return method.invoke( null, args );
+               } catch ( IllegalArgumentException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( IllegalAccessException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               } catch ( InvocationTargetException e ) {
+                       logger.log( Level.SEVERE, e.getMessage(), e );
+               }
+
+               return null;
+               
+       }
+
+       private Object invokeOSMethod( Method method ) {
+               return invokeOSMethod( method, new Object[]{} );
+       }
+       
        private void addMenuItems( final Shell shell, final Menu menu ) {
 
                final MenuItem detailInfoItem = new MenuItem( menu, SWT.PUSH );
@@ -920,8 +998,286 @@ public class EmulatorSkin {
                                        logger.fine( "Select Always On Top. : " + isOnTop );
                                }
 
-                               readyToReopen( EmulatorSkin.this, isOnTop );
+                               // readyToReopen( EmulatorSkin.this, isOnTop );
+
+                               
+                               if( SkinUtil.isLinuxPlatform() ) {
+
+                                       // reference : http://wmctrl.sourcearchive.com/documentation/1.07/main_8c-source.html
+                                       
+//                                     if ( !OS.GDK_WINDOWING_X11() ) {
+//                                             logger.warning( "There is no x11 system." );
+//                                             return;
+//                                     }
+//
+//                                     int eventData0 = isOnTop ? 1 : 0; // 'add' or 'remove'
+//
+//                                     int topHandle = 0;
+//
+//                                     Method m = null;
+//                                     try {
+//                                             m = Shell.class.getDeclaredMethod( "topHandle", new Class<?>[] {} );
+//                                             m.setAccessible( true );
+//                                             topHandle = (Integer) m.invoke( shell, new Object[] {} );
+//                                     } catch ( SecurityException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( NoSuchMethodException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( IllegalArgumentException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( IllegalAccessException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     } catch ( InvocationTargetException ex ) {
+//                                             logger.log( Level.SEVERE, ex.getMessage(), ex );
+//                                     }
+//
+//                                     int xWindow = OS.gdk_x11_drawable_get_xid( OS.GTK_WIDGET_WINDOW( topHandle ) );
+//                                     int xDisplay = OS.GDK_DISPLAY();
+//
+//                                     byte[] messageBuffer = Converter.wcsToMbcs( null, "_NET_WM_STATE", true );
+//                                     int xMessageAtomType = OS.XInternAtom( xDisplay, messageBuffer, false );
+//
+//                                     messageBuffer = Converter.wcsToMbcs( null, "_NET_WM_STATE_ABOVE", true );
+//                                     int xMessageAtomAbove = OS.XInternAtom( xDisplay, messageBuffer, false );
+//
+//                                     XClientMessageEvent event = new XClientMessageEvent();
+//                                     event.type = OS.ClientMessage;
+//                                     event.window = xWindow;
+//                                     event.message_type = xMessageAtomType;
+//                                     event.format = 32;
+//                                     event.data[0] = eventData0;
+//                                     event.data[1] = xMessageAtomAbove;
+//
+//                                     int clientEvent = OS.g_malloc( XClientMessageEvent.sizeof );
+//                                     OS.memmove( clientEvent, event, XClientMessageEvent.sizeof );
+//                                     int rootWin = OS.XDefaultRootWindow( xDisplay );
+//                                     // SubstructureRedirectMask:1L<<20 | SubstructureNotifyMask:1L<<19
+//                                     OS.XSendEvent( xDisplay, rootWin, false, (int) ( 1L << 20 | 1L << 19 ), clientEvent );
+//                                     OS.g_free( clientEvent );
+
+                                       Boolean gdkWindowingX11  = (Boolean) invokeOSMethod( getOSMethod( "GDK_WINDOWING_X11" ) );
+                                       if( null == gdkWindowingX11 ) {
+                                               return;
+                                       }
+                                       if( !gdkWindowingX11 ) {
+                                               logger.warning( "There is no x11 system." );
+                                               return;
+                                       }
+                                       
+                                       int eventData0 = isOnTop ? 1 : 0; // 'add' or 'remove'
+                                       
+                                       int topHandle = 0;
+                                       
+                                       Method m = null;
+                                       try {
+                                               m = Shell.class.getDeclaredMethod( "topHandle", new Class<?>[] {} );
+                                               m.setAccessible( true );
+                                               topHandle = (Integer) m.invoke( shell, new Object[] {} );
+                                       } catch ( SecurityException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( NoSuchMethodException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalArgumentException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( InvocationTargetException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Integer gtkWidgetWindow = (Integer) invokeOSMethod(
+                                                       getOSMethod( "GTK_WIDGET_WINDOW", int.class ), topHandle );
+                                       if( null == gtkWidgetWindow ) {
+                                               return;
+                                       }
+                                       
+                                       Integer xWindow = (Integer) invokeOSMethod( getOSMethod( "gdk_x11_drawable_get_xid", int.class ),
+                                                       gtkWidgetWindow );
+                                       if( null == xWindow ) {
+                                               return;
+                                       }
+                                       
+                                       Integer xDisplay = (Integer) invokeOSMethod( getOSMethod( "GDK_DISPLAY" ) );
+                                       if( null == xDisplay ) {
+                                               return;
+                                       }
+                                       
+                                       Method xInternAtom = getOSMethod( "XInternAtom", int.class, byte[].class, boolean.class );
+                                       
+                                       Class<?> converterClass = null;
+                                       try {
+                                               converterClass = Class.forName( "org.eclipse.swt.internal.Converter" );
+                                       } catch ( ClassNotFoundException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Method wcsToMbcs = null;
+                                       byte[] messageBufferState = null;
+                                       byte[] messageBufferAbove = null;
+                                       
+                                       try {
+                                               wcsToMbcs = converterClass.getMethod( "wcsToMbcs", String.class, String.class, boolean.class );
+                                       } catch ( SecurityException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( NoSuchMethodException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       try {
+                                               messageBufferState = (byte[]) wcsToMbcs.invoke( null, null, "_NET_WM_STATE", true );
+                                               messageBufferAbove = (byte[]) wcsToMbcs.invoke( null, null, "_NET_WM_STATE_ABOVE", true );
+                                       } catch ( IllegalArgumentException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( InvocationTargetException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Integer xMessageAtomType = (Integer) invokeOSMethod( xInternAtom, xDisplay, messageBufferState, false );
+                                       if( null == xMessageAtomType ) {
+                                               return;
+                                       }
+
+                                       Integer xMessageAtomAbove = (Integer) invokeOSMethod( xInternAtom, xDisplay, messageBufferAbove, false );
+                                       if( null == xMessageAtomAbove ) {
+                                               return;
+                                       }
+                                       
+                                       Class<?> eventClazz = null;
+                                       Object event = null;
+                                       try {
+                                               eventClazz = Class.forName( "org.eclipse.swt.internal.gtk.XClientMessageEvent" );
+                                               event = eventClazz.newInstance();
+                                       } catch ( InstantiationException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       } catch ( ClassNotFoundException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                       }
+                                       
+                                       if( null == eventClazz || null == event ) {
+                                               return;
+                                       }
+                                       
+                                       Integer malloc = null;
+                                       try {
+                                               
+                                               Field type = eventClazz.getField( "type" );
+                                               
+                                               Field clientMessageField = getOSField( "ClientMessage" );
+                                               if( null == clientMessageField ) {
+                                                       return;
+                                               }
+                                               type.set( event, clientMessageField.get( null ) );
+                                               
+                                               Field window = eventClazz.getField( "window" );
+                                               window.set( event, xWindow );
+                                               Field messageType = eventClazz.getField( "message_type" );
+                                               messageType.set( event, xMessageAtomType );
+                                               Field format = eventClazz.getField( "format" );
+                                               format.set( event, 32 );
+                                               
+                                               Object data = Array.newInstance( int.class, 5 );
+                                               Array.setInt( data, 0, eventData0 );
+                                               Array.setInt( data, 1, xMessageAtomAbove );
+                                               Array.setInt( data, 2, 0 );
+                                               Array.setInt( data, 3, 0 );
+                                               Array.setInt( data, 4, 0 );
+                                               
+                                               Field dataField = eventClazz.getField( "data" );
+                                               dataField.set( event, data );
+                                               
+                                               Field sizeofField = eventClazz.getField( "sizeof" );
+                                               Integer sizeof = (Integer) sizeofField.get( null );
+                                               
+                                               Method gMalloc = getOSMethod( "g_malloc", int.class );
+                                               malloc = (Integer) invokeOSMethod( gMalloc, sizeof );
+                                               
+                                               Method memmove = getOSMethod( "memmove", int.class, eventClazz, int.class );
+                                               invokeOSMethod( memmove, malloc, event, sizeof );
+                                               
+                                       } catch ( NoSuchFieldException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+                                       
+                                       Method xDefaultRootWindow = getOSMethod( "XDefaultRootWindow", int.class );
+                                       Integer rootWin = (Integer) invokeOSMethod( xDefaultRootWindow, xDisplay );
+                                       
+                                       Method xSendEvent = getOSMethod( "XSendEvent", int.class, int.class, boolean.class, int.class,
+                                                       int.class );
+                                       // SubstructureRedirectMask:1L<<20 | SubstructureNotifyMask:1L<<19
+                                       invokeOSMethod( xSendEvent, xDisplay, rootWin, false, (int) ( 1L << 20 | 1L << 19 ), malloc );
+                                       invokeOSMethod( getOSMethod( "g_free", int.class ), malloc ) ;
+                                       
+                               }else if( SkinUtil.isWindowsPlatform() ) {
+                                       
+                                       Point location = shell.getLocation();
+                                       
+//                                     int hWndInsertAfter = 0;
+//                                     if( isOnTop ) {
+//                                             hWndInsertAfter = OS.HWND_TOPMOST;
+//                                     }else {
+//                                             hWndInsertAfter = OS.HWND_NOTOPMOST;
+//                                     }
+//                                     
+//                                     OS.SetWindowPos( shell.handle, hWndInsertAfter, location.x, location.y, 0, 0, OS.SWP_NOSIZE );
+
+                                       int hWndInsertAfter = 0;
+                                       int noSize = 0;
+
+                                       try {
+                                               if ( isOnTop ) {
+                                                       Field topMost = getOSField( "HWND_TOPMOST" );
+                                                       if ( null == topMost ) {
+                                                               return;
+                                                       }
+                                                       hWndInsertAfter = topMost.getInt( null );
+                                               } else {
+                                                       Field noTopMost = getOSField( "HWND_NOTOPMOST" );
+                                                       if ( null == noTopMost ) {
+                                                               return;
+                                                       }
+                                                       hWndInsertAfter = noTopMost.getInt( null );
+                                               }
+
+                                               Field noSizeField = getOSField( "SWP_NOSIZE" );
+                                               if ( null == noSizeField ) {
+                                                       return;
+                                               }
+                                               noSize = noSizeField.getInt( null );
+
+                                       } catch ( IllegalArgumentException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       } catch ( IllegalAccessException ex ) {
+                                               logger.log( Level.SEVERE, ex.getMessage(), ex );
+                                               return;
+                                       }
+
+                                       Method m = getOSMethod( "SetWindowPos", int.class, int.class, int.class, int.class, int.class,
+                                                       int.class, int.class );
 
+                                       invokeOSMethod( m, shell.handle, hWndInsertAfter, location.x, location.y, 0, 0, noSize );
+
+                               }
+                               
                        }
                } );
 
index 98795496edb121a65f7f3b17b81a3f4d90fc658c..874cfbe293cd38d6657c4e71217bbf1fc877ee12 100644 (file)
@@ -43,7 +43,6 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.MessageBox;
 import org.eclipse.swt.widgets.Shell;
-import org.tizen.emulator.skin.EmulatorSkin.SkinReopenPolicy;
 import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
 import org.tizen.emulator.skin.config.EmulatorConfig;
 import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
@@ -153,27 +152,29 @@ public class EmulatorSkinMain {
                                Thread communicatorThread = new Thread( communicator );
                                communicatorThread.start();
                                
-                               SkinReopenPolicy reopenPolicy = skin.open();
+//                             SkinReopenPolicy reopenPolicy = skin.open();
+//                             
+//                             while( true ) {
+//
+//                                     if( null != reopenPolicy ) {
+//                                             
+//                                             if( reopenPolicy.isReopen() ) {
+//                                                     
+//                                                     EmulatorSkin reopenSkin = reopenPolicy.getReopenSkin();
+//                                                     logger.info( "Reopen skin dialog." );
+//                                                     reopenPolicy = reopenSkin.open();
+//                                                     
+//                                             }else {
+//                                                     break;
+//                                             }
+//                                             
+//                                     }else {
+//                                             break;
+//                                     }
+//
+//                             }
                                
-                               while( true ) {
-
-                                       if( null != reopenPolicy ) {
-                                               
-                                               if( reopenPolicy.isReopen() ) {
-                                                       
-                                                       EmulatorSkin reopenSkin = reopenPolicy.getReopenSkin();
-                                                       logger.info( "Reopen skin dialog." );
-                                                       reopenPolicy = reopenSkin.open();
-                                                       
-                                               }else {
-                                                       break;
-                                               }
-                                               
-                                       }else {
-                                               break;
-                                       }
-
-                               }
+                               skin.open();
                                
                        } else {
                                logger.severe( "CommSocket is null." );