1 /*
   2  * Copyright (c) 2012, 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 package com.sun.glass.ui.swt;
  26 
  27 import java.nio.IntBuffer;
  28 import java.util.Map;
  29 
  30 import com.sun.glass.events.*;
  31 import com.sun.glass.ui.*;
  32 
  33 import org.eclipse.swt.*;
  34 import org.eclipse.swt.widgets.*;
  35 import org.eclipse.swt.dnd.DropTarget;
  36 import org.eclipse.swt.graphics.*;
  37 //import org.eclipse.swt.internal.cocoa.OS;
  38 
  39 final class SWTView extends View {
  40     Canvas canvas;
  41     DropTarget dropTarget;
  42 
  43     static Shell hiddenShell;
  44     
  45     public SWTView() {
  46         super();
  47     }
  48 
  49     //TODO - implement IME
  50     @Override protected void _enableInputMethodEvents(long ptr, boolean enable) { }
  51 
  52     @Override
  53     protected int _getNativeFrameBuffer(long ptr) {
  54         return 0;
  55     }
  56 
  57     @Override protected long _create(Map caps) {
  58         if (hiddenShell == null) {
  59             hiddenShell = new Shell(Display.getDefault(), SWT.SHELL_TRIM);
  60             Display.getDefault().disposeExec(() -> {
  61                 hiddenShell.dispose();
  62                 hiddenShell = null;
  63             });
  64         }
  65         int bits = SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.LEFT_TO_RIGHT;// | SWT.NO_FOCUS;
  66         if (SWT.getPlatform().equals("cocoa")) {
  67             canvas = SWTApplication.createGLCanvas(hiddenShell, bits, caps);
  68 
  69 //            NSView view = canvas.view;
  70 //            long setWantsLayer_SEL = OS.sel_registerName("setWantsLayer:");
  71 //            OS.objc_msgSend(view.id, setWantsLayer_SEL, true);
  72         } else {
  73             canvas = new Canvas(hiddenShell, bits);
  74         }
  75         canvas.setData(this);
  76         Listener keyListener = event -> sendKeyEvent(event);
  77         int [] keyEvents = new int[] {
  78             SWT.KeyDown,
  79             SWT.KeyUp,
  80         };
  81         for (int i=0; i<keyEvents.length; i++) {
  82             canvas.addListener (keyEvents[i], keyListener);
  83         }
  84         Listener mouseListener = event -> sendMouseEvent(event);
  85         int [] mouseEvents = new int[] {
  86             SWT.MouseDown,
  87             SWT.MouseUp,
  88             SWT.MouseMove,
  89             SWT.MouseEnter,
  90             SWT.MouseExit,
  91             SWT.MouseHorizontalWheel,
  92             SWT.MouseVerticalWheel,
  93             SWT.MenuDetect,
  94         };
  95         for (int i=0; i<mouseEvents.length; i++) {
  96             canvas.addListener (mouseEvents[i], mouseListener);
  97         }
  98         canvas.addListener(SWT.Paint, event -> notifyRepaint(event.x, event.y, event.width, event.height));
  99         canvas.addListener(SWT.Resize, event -> {
 100             Rectangle rect = canvas.getClientArea();
 101             notifyResize(rect.width, rect.height);
 102         });
 103         
 104         //TODO - refactor to drop target creation in a better place
 105         dropTarget = SWTClipboard.createDropTarget(canvas);
 106         
 107         return SWTApplication.getHandle(canvas);
 108     }
 109 
 110     long layerID = 0;
 111     @Override public int getNativeRemoteLayerId(String serverName) {
 112         if (layerID != 0) return (int)layerID;
 113         // used when run inside plugin
 114 /*
 115 //        long JRSRemoteLayer_class = OS.objc_getClass("JRSRenderServer");
 116 
 117         Class<?> OS = Class.forName("org.eclipse.swt.internal.cocoa.OS");
 118         Method objc_getClass = OS.getDeclaredMethod("objc_getClass", String.class);
 119         long JRSRemoteLayer_class = (Long)objc_getClass.invoke(OS, "JRSRenderServer");
 120         
 121         
 122         //RemoteLayerStartServer
 123 //        long startRenderServer_SEL = OS.sel_registerName("startRenderServer");
 124 //        long result = OS.objc_msgSend(JRSRemoteLayer_class, startRenderServer_SEL);
 125 //        System.out.println("sent startRenderServer="+result);
 126         
 127         //RemoteLayerGetServerPort
 128         System.out.println("connecting to " + serverName);
 129         NSString str = (NSString) new NSString().alloc();
 130         str = NSString.stringWith(serverName);
 131         System.out.println("class="+JRSRemoteLayer_class);
 132         long recieveRenderServer_SEL = OS.sel_registerName("recieveRenderServer:");
 133         System.out.println("SEL="+recieveRenderServer_SEL);
 134         System.out.println("sending msg getPort");
 135         long port = OS.objc_msgSend(JRSRemoteLayer_class, recieveRenderServer_SEL, str.id);
 136         System.out.println("port="+port);
 137         
 138         //RemoteLayerGetRemoteFromLocal
 139 //        long localLayer = getNativeLayer();
 140         NSView view = canvas.view;
 141 //
 142 //        long setWantsLayer_SEL = OS.sel_registerName("setWantsLayer:");
 143 //        OS.objc_msgSend(view.id, setWantsLayer_SEL, true);
 144         
 145         long layer_SEL = OS.sel_registerName("layer");
 146         long localLayer = OS.objc_msgSend(view.id, layer_SEL);
 147         System.out.println("localLayer="+localLayer);
 148         long createRemoteLayer_SEL = OS.sel_registerName("createRemoteLayerBoundTo:");
 149         System.out.println("sending msg createRemoteLayerBoundTo");
 150         long remoteLayer = OS.objc_msgSend(localLayer, createRemoteLayer_SEL, port);
 151         System.out.println("remoter layer =" + remoteLayer);
 152         
 153         //RemoteLayerGetIdForRemote
 154         long layerID_SEL = OS.sel_registerName("layerID");
 155         System.out.println("sending msg layerID_SEL");
 156         layerID = OS.objc_msgSend(remoteLayer, layerID_SEL);
 157         System.out.println("returning layerID="+layerID);
 158         
 159         String s = Display.getAppVersion();
 160         if (s==null) s = "";
 161         s+= " create remote layer " + layerID;
 162         Display.setAppVersion(s);
 163         */
 164 
 165         return (int)layerID;
 166     }
 167 
 168     @Override protected long _getNativeView(long ptr) {
 169         return ptr;
 170     }
 171 
 172     @Override protected  int _getX(long ptr) {
 173         //TODO - implement offset in parent
 174         return 0;
 175     }
 176     @Override protected int _getY(long ptr) {
 177         //TODO - implement offset in parent
 178         return 0;
 179     }
 180 
 181     @Override protected boolean _close(long ptr) {
 182         //TODO - implement destroy of a view
 183         return false;
 184     }
 185 
 186     @Override protected void _scheduleRepaint(long ptr) {
 187         canvas.redraw();
 188     }
 189 
 190     @Override protected  void _begin(final long ptr) {
 191         SWTApplication.lockFocus(canvas);
 192     }
 193     
 194     @Override protected void _end(final long ptr) {
 195         SWTApplication.unlockFocus(canvas);
 196     }
 197 
 198     @Override protected boolean _enterFullscreen(long ptr, boolean animate, boolean keepRatio, boolean hideCursor) {
 199         canvas.getShell().setFullScreen(true);
 200         if (canvas.getShell().getFullScreen()) {
 201             notifyView(ViewEvent.FULLSCREEN_ENTER);
 202             return true;
 203         }
 204         return false;
 205     };
 206     @Override protected void _exitFullscreen(long ptr, boolean animate) {
 207         canvas.getShell().setFullScreen(false);
 208         if (!canvas.getShell().getFullScreen()) {
 209             notifyView(ViewEvent.FULLSCREEN_EXIT);
 210         }
 211     };
 212 
 213     @Override  protected void _setParent(long ptr, long parentPtr) {
 214         //TODO - implement set parent (is this necessary?)
 215         //throw new RuntimeException("SWTView._setParent not implemented.");
 216     }
 217     
 218     @Override protected void _uploadPixels(long ptr, Pixels pixels) {
 219         //TODO - optimize pixel uploading
 220         int width = pixels.getWidth(), height = pixels.getHeight();
 221         int [] bytes = ((IntBuffer)pixels.getPixels()).array();
 222         PaletteData palette = new PaletteData(0x00ff0000, 0x0000ff00, 0x000000ff);
 223         
 224         //long t0 = System.currentTimeMillis();
 225         ImageData imageData = new ImageData(width, height, 32, palette);
 226         //long t1 = System.currentTimeMillis();
 227         //System.out.println("new ImageData: " + (t1-t0));
 228         
 229         imageData.setPixels(0, 0, width * height, bytes, 0);
 230         //long t2 = System.currentTimeMillis();
 231         //System.out.println("setPixels: " + (t2-t1));
 232         
 233         Image image = new Image(canvas.getDisplay(), imageData);
 234         //long t3 = System.currentTimeMillis();
 235         //System.out.println("new Image: " + (t3-t2));
 236         
 237         GC gc = new GC (canvas);
 238         //long t4 = System.currentTimeMillis();
 239         //System.out.println("new GC: " + (t4-t3));
 240         
 241         gc.drawImage(image, 0, 0);
 242         //long t5 = System.currentTimeMillis();
 243         //System.out.println("drawImage: " + (t5-t4));
 244         
 245         image.dispose();
 246         //long t6 = System.currentTimeMillis();
 247         //System.out.println("image.dispose(): " + (t6-t5));
 248         
 249         gc.dispose();
 250         //long t7 = System.currentTimeMillis();
 251         //System.out.println("gc.dispose(): " + (t7-t6));
 252     }
 253 
 254     void sendKeyEvent (Event event) {
 255         //TODO - should the notifyXXX be called instead?
 256         EventHandler eventHandler = getEventHandler();
 257         if (eventHandler == null) return;
 258         long time = System.nanoTime();
 259         int keyCode = SWTApplication.getKeyCode(event);
 260         int modifiers = SWTApplication.getModifiers(event);
 261         int action = event.type == SWT.KeyDown ? KeyEvent.PRESS : KeyEvent.RELEASE;
 262         char[] chars = new char[] { event.character };
 263         eventHandler.handleKeyEvent(this, time, action, keyCode, chars, modifiers);
 264         if (event.character != '\0' && event.type == SWT.KeyDown) {
 265             eventHandler.handleKeyEvent(this, time, KeyEvent.TYPED, keyCode, chars, modifiers);
 266         }
 267     }
 268 
 269     void sendMouseEvent (Event event) {
 270         //TODO - should the notifyXXX be called instead?
 271         EventHandler eventHandler = getEventHandler();
 272         if (eventHandler == null) return;
 273         long time = System.nanoTime();
 274         int type = 0;
 275         switch (event.type) {
 276             case SWT.MouseDown:
 277                 type = MouseEvent.DOWN;
 278                 if ((canvas.getShell().getStyle() & SWT.NO_FOCUS) != 0) {
 279                     canvas.forceFocus();
 280                 }
 281                 break;
 282             case SWT.MouseUp:
 283                 type = MouseEvent.UP;
 284                 break;
 285             case SWT.MouseMove:
 286                 if ((event.stateMask & SWT.BUTTON_MASK) != 0) {
 287                     type = MouseEvent.DRAG;
 288                 } else {
 289                     type = MouseEvent.MOVE;
 290                 }
 291                 break;
 292             case SWT.MouseEnter:
 293                 type = MouseEvent.ENTER;
 294                 break;
 295             case SWT.MouseExit:
 296                 type = MouseEvent.EXIT;
 297                 break;
 298             case SWT.MouseHorizontalWheel:
 299                 type = MouseEvent.WHEEL;
 300                 break;
 301             case SWT.MouseVerticalWheel:
 302                 type = MouseEvent.WHEEL;
 303                 break;
 304             case SWT.MenuDetect:
 305                 break;
 306         }
 307         int button = SWTApplication.getButton(event);
 308         int modifiers = SWTApplication.getModifiers(event);
 309         switch (event.type) {
 310             case SWT.MouseHorizontalWheel:
 311                 //TODO - horizontal mouse wheel not implemented
 312                 break;
 313             case SWT.MouseVerticalWheel: {
 314                 //TODO - mouse wheel not implemented, these values are hard coded
 315                 Point point = canvas.toDisplay(event.x, event.y);
 316                 eventHandler.handleScrollEvent(this, time, event.x, event.y, point.x, point.y, 0, event.count, modifiers, 1, 1, 1, 1, 1, 1);
 317                 break;
 318             }
 319             case SWT.MenuDetect: {
 320                 //TODO - compute trigger, don't hard code
 321                 boolean isKeyboardTrigger = false;
 322                 Point point = canvas.toControl(event.x, event.y);
 323                 eventHandler.handleMenuEvent(this, point.x, point.y, event.x, event.y, isKeyboardTrigger);
 324                 break;
 325             }
 326             default: {
 327                 //TODO - compute trigger, don't hard code
 328                 boolean isPopupTrigger = false;
 329                 Point point = canvas.toDisplay(event.x, event.y);
 330                 eventHandler.handleMouseEvent(this, time, type, button, event.x, event.y, point.x, point.y, modifiers, isPopupTrigger, false);
 331             }
 332         }
 333     }
 334     
 335     //TODO - fix visibility
 336     public void notifyDragStart(int button, int x, int y, int xAbs, int yAbs) {
 337         super. notifyDragStart(button, x, y, xAbs, yAbs);
 338     }
 339     
 340     //TODO - fix visibility
 341     public void notifyDragEnd(int performedAction) {
 342         super.notifyDragEnd(performedAction) ;
 343     }
 344 
 345     //TODO - fix visibility
 346     public int notifyDragEnter(int x, int y, int xAbs, int yAbs, int recommendedDropAction) {
 347         return super.notifyDragEnter(x, y, xAbs, yAbs, recommendedDropAction);
 348     }
 349 
 350     //TODO - fix visibility
 351     public int notifyDragOver(int x, int y, int xAbs, int yAbs, int recommendedDropAction) {
 352         return super.notifyDragOver(x, y, xAbs, yAbs, recommendedDropAction);
 353     }
 354 
 355     //TODO - fix visibility
 356     public void notifyDragLeave() {
 357         super.notifyDragLeave();
 358     }
 359 
 360     //TODO - fix visibility
 361     public int notifyDragDrop(int x, int y, int xAbs, int yAbs, int recommendedDropAction) {
 362         return super.notifyDragDrop(x, y, xAbs, yAbs, recommendedDropAction);
 363     }
 364 }
 365