sync with tizen_2.2
[sdk/emulator/qemu.git] / tizen / src / skin / client / src / org / tizen / emulator / skin / EmulatorSkin.java
1 /**
2  * Emulator Skin Process
3  *
4  * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * GiWoong Kim <giwoong.kim@samsung.com>
8  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  * HyunJun Son
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30 package org.tizen.emulator.skin;
31
32 import java.io.File;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.Iterator;
36 import java.util.LinkedList;
37 import java.util.List;
38 import java.util.Map.Entry;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
41
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.events.FocusEvent;
44 import org.eclipse.swt.events.FocusListener;
45 import org.eclipse.swt.events.KeyEvent;
46 import org.eclipse.swt.events.KeyListener;
47 import org.eclipse.swt.events.MenuDetectEvent;
48 import org.eclipse.swt.events.MenuDetectListener;
49 import org.eclipse.swt.events.MouseEvent;
50 import org.eclipse.swt.events.MouseListener;
51 import org.eclipse.swt.events.MouseMoveListener;
52 import org.eclipse.swt.events.MouseWheelListener;
53 import org.eclipse.swt.events.SelectionAdapter;
54 import org.eclipse.swt.events.SelectionEvent;
55 import org.eclipse.swt.events.ShellEvent;
56 import org.eclipse.swt.events.ShellListener;
57 import org.eclipse.swt.graphics.Color;
58 import org.eclipse.swt.graphics.Point;
59 import org.eclipse.swt.graphics.RGB;
60 import org.eclipse.swt.graphics.Rectangle;
61 import org.eclipse.swt.widgets.Canvas;
62 import org.eclipse.swt.widgets.Display;
63 import org.eclipse.swt.widgets.Menu;
64 import org.eclipse.swt.widgets.MenuItem;
65 import org.eclipse.swt.widgets.Shell;
66 import org.tizen.emulator.skin.comm.ICommunicator.KeyEventType;
67 import org.tizen.emulator.skin.comm.ICommunicator.MouseButtonType;
68 import org.tizen.emulator.skin.comm.ICommunicator.MouseEventType;
69 import org.tizen.emulator.skin.comm.ICommunicator.RotationInfo;
70 import org.tizen.emulator.skin.comm.ICommunicator.Scale;
71 import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
72 import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
73 import org.tizen.emulator.skin.comm.sock.data.BooleanData;
74 import org.tizen.emulator.skin.comm.sock.data.DisplayStateData;
75 import org.tizen.emulator.skin.comm.sock.data.KeyEventData;
76 import org.tizen.emulator.skin.comm.sock.data.MouseEventData;
77 import org.tizen.emulator.skin.config.EmulatorConfig;
78 import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
79 import org.tizen.emulator.skin.config.EmulatorConfig.SkinPropertiesConstants;
80 import org.tizen.emulator.skin.custom.ColorTag;
81 import org.tizen.emulator.skin.custom.CustomProgressBar;
82 import org.tizen.emulator.skin.custom.KeyWindow;
83 import org.tizen.emulator.skin.dbi.ColorsType;
84 import org.tizen.emulator.skin.dbi.KeyMapType;
85 import org.tizen.emulator.skin.dbi.RgbType;
86 import org.tizen.emulator.skin.dbi.RotationType;
87 import org.tizen.emulator.skin.dialog.AboutDialog;
88 import org.tizen.emulator.skin.dialog.DetailInfoDialog;
89 import org.tizen.emulator.skin.dialog.RamdumpDialog;
90 import org.tizen.emulator.skin.image.ImageRegistry;
91 import org.tizen.emulator.skin.image.ImageRegistry.IconName;
92 import org.tizen.emulator.skin.info.SkinInformation;
93 import org.tizen.emulator.skin.layout.GeneralPurposeSkinComposer;
94 import org.tizen.emulator.skin.layout.ISkinComposer;
95 import org.tizen.emulator.skin.layout.PhoneShapeSkinComposer;
96 import org.tizen.emulator.skin.log.SkinLogger;
97 import org.tizen.emulator.skin.screenshot.ScreenShotDialog;
98 import org.tizen.emulator.skin.util.SkinRotation;
99 import org.tizen.emulator.skin.util.SkinUtil;
100 import org.tizen.emulator.skin.util.SwtUtil;
101
102 /**
103  *
104  *
105  */
106 public class EmulatorSkin {
107
108         public class SkinReopenPolicy {
109
110                 private EmulatorSkin reopenSkin;
111                 private boolean reopen;
112
113                 private SkinReopenPolicy( EmulatorSkin reopenSkin, boolean reopen ) {
114                         this.reopenSkin = reopenSkin;
115                         this.reopen = reopen;
116                 }
117
118                 public EmulatorSkin getReopenSkin() {
119                         return reopenSkin;
120                 }
121
122                 public boolean isReopen() {
123                         return reopen;
124                 }
125
126         }
127
128         public enum SkinBasicColor {
129                 BLUE(0, 174, 239),
130                 YELLOW(246, 226, 0),
131                 LIME(0, 246, 12),
132                 VIOLET(168, 43, 255),
133                 ORANGE(246, 110, 0),
134                 MAGENTA(245, 48, 233),
135                 PURPLE(94, 73, 255),
136                 GREEN(179, 246, 0),
137                 RED(245, 48, 48),
138                 CYON(29, 223, 221);
139
140                 private int channelRed;
141                 private int channelGreen;
142                 private int channelBlue;
143
144                 SkinBasicColor(int r, int g, int b) {
145                         channelRed = r;
146                         channelGreen = g;
147                         channelBlue = b;
148                 }
149
150                 public RGB color() {
151                         return new RGB(channelRed, channelGreen, channelBlue);
152                 }
153         }
154
155         private static Logger logger =
156                         SkinLogger.getSkinLogger(EmulatorSkin.class).getLogger();
157
158         protected EmulatorConfig config;
159         protected EmulatorFingers finger;
160         protected Shell shell;
161         protected ImageRegistry imageRegistry;
162         protected Canvas lcdCanvas;
163         private int displayCanvasStyle;
164         protected SkinInformation skinInfo;
165         protected ISkinComposer skinComposer;
166
167         protected EmulatorSkinState currentState;
168
169         private boolean isDragStartedInLCD;
170         private boolean isShutdownRequested;
171         private boolean isAboutToReopen;
172         private boolean isOnTop;
173         private boolean isKeyWindow;
174         private boolean isOnKbd;
175
176         private Menu contextMenu;
177         public Color colorVM;
178         private MenuItem keyWindowItem; /* key window menu */
179         public KeyWindow keyWindow;
180         public int recentlyDocked;
181         public ColorTag pairTag;
182         public CustomProgressBar bootingProgress;
183         public ScreenShotDialog screenShotDialog;
184
185         public SocketCommunicator communicator;
186         private ShellListener shellListener;
187         private MenuDetectListener shellMenuDetectListener;
188
189         //private DragDetectListener canvasDragDetectListener;
190         private MouseMoveListener canvasMouseMoveListener;
191         private MouseListener canvasMouseListener;
192         private MouseWheelListener canvasMouseWheelListener;
193         private KeyListener canvasKeyListener;
194         private MenuDetectListener canvasMenuDetectListener;
195         private FocusListener canvasFocusListener;
196
197         private LinkedList<KeyEventData> pressedKeyEventList;
198
199         /* touch values */
200         private static int pressingX = -1, pressingY = -1;
201         private static int pressingOriginX = -1, pressingOriginY = -1;
202
203
204         private EmulatorSkin reopenSkin;
205         
206         /**
207          * @brief constructor
208          * @param config : configuration of emulator skin
209          * @param isOnTop : always on top flag
210         */
211         protected EmulatorSkin(EmulatorSkinState state, EmulatorFingers finger,
212                         EmulatorConfig config, SkinInformation skinInfo,
213                         int displayCanvasStyle, boolean isOnTop) {
214                 this.finger = finger;
215                 this.config = config;
216                 this.skinInfo = skinInfo;
217
218                 this.screenShotDialog = null;
219                 this.keyWindow = null;
220                 this.pressedKeyEventList = new LinkedList<KeyEventData>();
221
222                 this.isOnTop = isOnTop;
223                 this.isKeyWindow = false;
224                 this.recentlyDocked = SWT.NONE;
225
226                 int style = SWT.NO_TRIM | SWT.DOUBLE_BUFFERED;
227 //              if (skinInfo.isPhoneShape() == false) {
228 //                      style = SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.BORDER;
229 //              }
230                 this.shell = new Shell(Display.getDefault(), style);
231                 if (isOnTop == true) {
232                         SkinUtil.setTopMost(shell, true);
233                 }
234
235                 this.displayCanvasStyle = displayCanvasStyle;
236
237                 /* generate a pair tag color of key window */
238                 setColorVM();
239
240                 this.currentState = state;
241         }
242
243         public void setCommunicator(SocketCommunicator communicator) {
244                 this.communicator = communicator;
245                 this.finger.setCommunicator(this.communicator);
246         }
247
248         private void setColorVM() {
249                 int portNumber = config.getArgInt(ArgsConstants.NET_BASE_PORT) % 100;
250
251                 if (portNumber >= 26200) {
252                         int red = (int) (Math.random() * 256);
253                         int green = (int) (Math.random() * 256);
254                         int blue = (int) (Math.random() * 256);
255                         this.colorVM = new Color(shell.getDisplay(), new RGB(red, green, blue));
256                 } else {
257                         int vmIndex = (portNumber % 100) / 10;
258
259                         SkinBasicColor colors[] = SkinBasicColor.values();
260                         this.colorVM = new Color(shell.getDisplay(), colors[vmIndex].color());
261                 }
262         }
263
264         public long initLayout() {
265                 imageRegistry = ImageRegistry.getInstance();
266
267                 if (skinInfo.isPhoneShape() == true) { /* phone shape skin */
268                         skinComposer = new PhoneShapeSkinComposer(config, this,
269                                         shell, currentState, imageRegistry, communicator);
270
271                         ((PhoneShapeSkinComposer) skinComposer).addPhoneShapeListener(shell);
272                 } else { /* general purpose skin */
273                         skinComposer = new GeneralPurposeSkinComposer(config, this,
274                                         shell, currentState, imageRegistry);
275
276                         ((GeneralPurposeSkinComposer) skinComposer).addGeneralPurposeListener(shell);
277                 }
278
279                 lcdCanvas = skinComposer.compose(displayCanvasStyle);
280
281                 /* load a hover color */
282                 currentState.setHoverColor(loadHoverColor());
283
284                 /* added event handlers */
285                 addMainWindowListener(shell);
286                 addCanvasListener(shell, lcdCanvas);
287
288                 setFocus();
289
290                 /* attach a menu */
291                 this.isOnKbd = false;
292                 setMenu();
293
294                 return 0;
295         }
296
297         private void setMenu() {
298                 contextMenu = new Menu(shell);
299
300                 addMenuItems(shell, contextMenu);
301
302                 shell.setMenu(contextMenu);
303         }
304
305 //      private void readyToReopen( EmulatorSkin sourceSkin, boolean isOnTop ) {
306 //
307 //              logger.info( "Start Changing AlwaysOnTop status" );
308 //
309 //              sourceSkin.reopenSkin = new EmulatorSkin( sourceSkin.config, isOnTop );
310 //
311 //              sourceSkin.reopenSkin.lcdCanvas = sourceSkin.lcdCanvas;
312 //              Point previousLocation = sourceSkin.shell.getLocation();
313 //
314 //              sourceSkin.reopenSkin.composeInternal( sourceSkin.lcdCanvas, previousLocation.x, previousLocation.y,
315 //                              sourceSkin.currentLcdWidth, sourceSkin.currentLcdHeight, sourceSkin.currentScale,
316 //                              sourceSkin.currentRotationId, sourceSkin.isOnKbd );
317 //
318 //              sourceSkin.reopenSkin.windowHandleId = sourceSkin.windowHandleId;
319 //
320 //              sourceSkin.reopenSkin.communicator = sourceSkin.communicator;
321 //              sourceSkin.reopenSkin.communicator.resetSkin( reopenSkin );
322 //
323 //              sourceSkin.isAboutToReopen = true;
324 //              sourceSkin.isShutdownRequested = true;
325 //
326 //              if ( sourceSkin.isScreenShotOpened && ( null != sourceSkin.screenShotDialog ) ) {
327 //                      sourceSkin.screenShotDialog.setReserveImage( true );
328 //                      sourceSkin.screenShotDialog.setEmulatorSkin( reopenSkin );
329 //                      reopenSkin.isScreenShotOpened = true;
330 //                      reopenSkin.screenShotDialog = sourceSkin.screenShotDialog;
331 //                      // see open() method to know next logic for screenshot dialog.
332 //              }
333 //
334 //              sourceSkin.lcdCanvas.setParent( reopenSkin.shell );
335 //              sourceSkin.shell.close();
336 //
337 //      }
338
339         private Color loadHoverColor() {
340                 ColorsType colors = config.getDbiContents().getColors();
341
342                 if (null != colors) {
343                         RgbType hoverRgb = colors.getHoverColor();
344                         if (null != hoverRgb) {
345                                 Long r = hoverRgb.getR();
346                                 Long g = hoverRgb.getG();
347                                 Long b = hoverRgb.getB();
348
349                                 if (null != r && null != g && null != b) {
350                                         Color hoverColor = new Color(shell.getDisplay(),
351                                                         new RGB(r.intValue(), g.intValue(), b.intValue()));
352
353                                         return hoverColor;
354                                 }
355                         }
356                 }
357
358                 /* white */
359                 return (new Color(shell.getDisplay(), new RGB(255, 255, 255)));
360         }
361
362         public Color getColorVM() {
363                 return colorVM;
364         }
365
366         public ImageRegistry getImageRegistry() {
367                 return imageRegistry;
368         }
369
370         public SkinReopenPolicy open() {
371                 if (null == this.communicator) {
372                         logger.severe("communicator is null.");
373                         return null;
374                 }
375
376                 Display display = this.shell.getDisplay();
377
378                 this.shell.open();
379
380                 // logic only for reopen case ///////
381 //              if ( isScreenShotOpened && ( null != screenShotDialog ) ) {
382 //                      try {
383 //                              screenShotDialog.setReserveImage( false );
384 //                              screenShotDialog.open();
385 //                      } finally {
386 //                              isScreenShotOpened = false;
387 //                      }
388 //              }
389                 // ///////////////////////////////////
390
391                 while (!shell.isDisposed()) {
392                         if (!display.readAndDispatch()) {
393                                 display.sleep();
394                         }
395                 }
396
397                 return new SkinReopenPolicy(reopenSkin, isAboutToReopen);
398         }
399
400         protected void skinFinalize() {
401                 skinComposer.composerFinalize();
402         }
403
404         private void addMainWindowListener(final Shell shell) {
405
406                 shellListener = new ShellListener() {
407                         @Override
408                         public void shellClosed(ShellEvent event) {
409                                 logger.info("Main Window is closed");
410
411                                 if (isShutdownRequested) {
412                                         removeShellListeners();
413                                         removeCanvasListeners();
414
415                                         if (!isAboutToReopen) {
416                                                 /* close the screen shot window */
417                                                 if (null != screenShotDialog) {
418                                                         Shell scShell = screenShotDialog.getShell();
419                                                         if (!scShell.isDisposed()) {
420                                                                 scShell.close();
421                                                         }
422                                                         screenShotDialog = null;
423                                                 }
424
425                                                 /* save config only for emulator close */
426                                                 config.setSkinProperty(
427                                                                 SkinPropertiesConstants.WINDOW_X, shell.getLocation().x);
428                                                 config.setSkinProperty(
429                                                                 SkinPropertiesConstants.WINDOW_Y, shell.getLocation().y);
430                                                 config.setSkinProperty(
431                                                                 SkinPropertiesConstants.WINDOW_SCALE, currentState.getCurrentScale());
432                                                 config.setSkinProperty(
433                                                                 SkinPropertiesConstants.WINDOW_ROTATION, currentState.getCurrentRotationId());
434                                                 config.setSkinProperty(
435                                                                 SkinPropertiesConstants.WINDOW_ONTOP, Boolean.toString(isOnTop));
436
437                                                 int dockValue = 0;
438                                                 if (keyWindow != null && keyWindow.getShell().isVisible()) {
439                                                         dockValue = keyWindow.getDockPosition();
440                                                 }
441                                                 config.setSkinProperty(
442                                                                 SkinPropertiesConstants.KEYWINDOW_POSITION, dockValue);
443
444                                                 config.saveSkinProperties();
445
446                                                 /* close the Key Window */
447                                                 if (skinInfo.isPhoneShape() == false) {
448                                                         closeKeyWindow();
449                                                 }
450
451                                                 /* dispose the color */
452                                                 if (colorVM != null) {
453                                                         colorVM.dispose();
454                                                 }
455                                         }
456
457                                         if (currentState.getCurrentImage() != null) {
458                                                 currentState.getCurrentImage().dispose();
459                                         }
460                                         if (currentState.getCurrentKeyPressedImage() != null) {
461                                                 currentState.getCurrentKeyPressedImage().dispose();
462                                         }
463
464                                         if (currentState.getHoverColor() != null) {
465                                                 currentState.getHoverColor().dispose();
466                                         }
467
468                                         skinFinalize();
469
470                                 } else {
471                                         /* Skin have to be alive until
472                                          * receiving shutdown request from qemu */
473                                         event.doit = false;
474
475                                         if (null != communicator) {
476                                                 communicator.sendToQEMU(SendCommand.CLOSE, null);
477                                         }
478                                 }
479                         }
480
481                         @Override
482                         public void shellActivated(ShellEvent event) {
483                                 logger.info("activate");
484
485                                 if (keyWindow != null && isKeyWindow == true) {
486                                         if (isOnTop == false) {
487                                                 keyWindow.getShell().moveAbove(shell);
488
489                                                 if (keyWindow.getDockPosition() != SWT.NONE) {
490                                                         shell.moveAbove(keyWindow.getShell());
491                                                 }
492                                         } else {
493                                                 if (keyWindow.getDockPosition() == SWT.NONE) {
494                                                         keyWindow.getShell().moveAbove(shell);
495                                                 }
496                                         }
497                                 }
498                         }
499
500                         @Override
501                         public void shellDeactivated(ShellEvent event) {
502                                 //logger.info("deactivate");
503
504                                 /* do nothing */
505                         }
506
507                         @Override
508                         public void shellIconified(ShellEvent event) {
509                                 logger.info("iconified");
510
511                                 /* synchronization of minimization */
512                                 shell.getDisplay().asyncExec(new Runnable() {
513                                         @Override
514                                         public void run() {
515                                                 if (isKeyWindow == true && keyWindow != null) {
516                                                         if (keyWindow.getShell().getMinimized() == false) {
517                                                                 keyWindow.getShell().setVisible(false);
518                                                                 /* the tool style window is exposed
519                                                                 when even it was minimized */
520                                                                 keyWindow.getShell().setMinimized(true);
521                                                         }
522                                                 }
523                                         }
524                                 });
525                         }
526
527                         @Override
528                         public void shellDeiconified(ShellEvent event) {
529                                 logger.info("deiconified");
530
531                                 if (isKeyWindow == true && keyWindow != null) {
532                                         if (keyWindow.getShell().getMinimized() == true) {
533                                                 keyWindow.getShell().setMinimized(false);
534                                                 keyWindow.getShell().setVisible(true);
535                                         }
536                                 }
537
538                                 DisplayStateData lcdStateData = new DisplayStateData(
539                                                 currentState.getCurrentScale(), currentState.getCurrentRotationId());
540                                 communicator.sendToQEMU(SendCommand.CHANGE_LCD_STATE, lcdStateData);
541                         }
542                 };
543
544                 shell.addShellListener(shellListener);
545
546                 /* menu */
547                 shellMenuDetectListener = new MenuDetectListener() {
548                         @Override
549                         public void menuDetected(MenuDetectEvent e) {
550                                 Menu menu = EmulatorSkin.this.contextMenu;
551
552                                 if (menu != null) {
553                                         shell.setMenu(menu);
554                                         menu.setVisible(true);
555
556                                         e.doit = false;
557                                 } else {
558                                         shell.setMenu(null);
559                                 }
560                         }
561                 };
562
563                 shell.addMenuDetectListener(shellMenuDetectListener);
564         }
565
566         private void removeShellListeners() {
567                 if (null != shellListener) {
568                         shell.removeShellListener(shellListener);
569                 }
570
571                 if (null != shellMenuDetectListener) {
572                         shell.removeMenuDetectListener(shellMenuDetectListener);
573                 }
574         }
575
576         private void addCanvasListener(final Shell shell, final Canvas canvas) {
577                 /* menu */
578                 canvasMenuDetectListener = new MenuDetectListener() {
579                         @Override
580                         public void menuDetected(MenuDetectEvent e) {
581                                 Menu menu = EmulatorSkin.this.contextMenu;
582                                 keyForceRelease(true);
583
584                                 if (menu != null && EmulatorSkin.this.isDragStartedInLCD == false) {
585                                         lcdCanvas.setMenu(menu);
586                                         menu.setVisible(true);
587                                         e.doit = false;
588                                 } else {
589                                         lcdCanvas.setMenu(null);
590                                 }
591                         }
592                 };
593
594                 /* remove 'input method' menu item (avoid bug) */
595                 canvas.addMenuDetectListener(canvasMenuDetectListener);
596
597                 /* focus */
598                 canvasFocusListener = new FocusListener() {
599                         @Override
600                         public void focusGained(FocusEvent event) {
601                                 //logger.info("gain focus");
602
603                                 /* do nothing */
604                         }
605
606                         @Override
607                         public void focusLost(FocusEvent event) {
608                                 logger.info("lost focus");
609                                 keyForceRelease(false);
610                         }
611                 };
612
613                 lcdCanvas.addFocusListener(canvasFocusListener);
614
615                 /* mouse event */
616                 /*canvasDragDetectListener = new DragDetectListener() {
617
618                         @Override
619                         public void dragDetected( DragDetectEvent e ) {
620                                 if ( logger.isLoggable( Level.FINE ) ) {
621                                         logger.fine( "dragDetected e.button:" + e.button );
622                                 }
623                                 if ( 1 == e.button && // left button
624                                                 e.x > 0 && e.x < canvas.getSize().x && e.y > 0 && e.y < canvas.getSize().y ) {
625
626                                         if ( logger.isLoggable( Level.FINE ) ) {
627                                                 logger.fine( "dragDetected in display" );
628                                         }
629                                         EmulatorSkin.this.isDragStartedInLCD = true;
630
631                                 }
632                         }
633                 };
634
635                 canvas.addDragDetectListener(canvasDragDetectListener);*/
636
637                 canvasMouseMoveListener = new MouseMoveListener() {
638
639                         @Override
640                         public void mouseMove( MouseEvent e ) {
641                                 if ( true == EmulatorSkin.this.isDragStartedInLCD ) { //true = mouse down
642                                         int eventType = MouseEventType.DRAG.value();
643                                         Point canvasSize = canvas.getSize();
644
645                                         if ( e.x < 0 ) {
646                                                 e.x = 0;
647                                                 eventType = MouseEventType.RELEASE.value();
648                                                 EmulatorSkin.this.isDragStartedInLCD = false;
649                                         } else if ( e.x >= canvasSize.x ) {
650                                                 e.x = canvasSize.x - 1;
651                                                 eventType = MouseEventType.RELEASE.value();
652                                                 EmulatorSkin.this.isDragStartedInLCD = false;
653                                         }
654
655                                         if ( e.y < 0 ) {
656                                                 e.y = 0;
657                                                 eventType = MouseEventType.RELEASE.value();
658                                                 EmulatorSkin.this.isDragStartedInLCD = false;
659                                         } else if ( e.y >= canvasSize.y ) {
660                                                 e.y = canvasSize.y - 1;
661                                                 eventType = MouseEventType.RELEASE.value();
662                                                 EmulatorSkin.this.isDragStartedInLCD = false;
663                                         }
664
665                                         int[] geometry = SkinUtil.convertMouseGeometry(e.x, e.y,
666                                                         currentState.getCurrentResolutionWidth(),
667                                                         currentState.getCurrentResolutionHeight(),
668                                                         currentState.getCurrentScale(), currentState.getCurrentAngle());
669
670                                         if (SwtUtil.isMacPlatform()) {
671                                                 //eventType = MouseEventType.DRAG.value();
672                                                 if (finger.getMultiTouchEnable() == 1) {
673                                                         finger.maruFingerProcessing1(eventType,
674                                                                         e.x, e.y, geometry[0], geometry[1]);
675                                                         return;
676                                                 }
677                                                 else if (finger.getMultiTouchEnable() == 2) {
678                                                         finger.maruFingerProcessing2(eventType,
679                                                                         e.x, e.y, geometry[0], geometry[1]);
680                                                         return;
681                                                 }
682                                         }
683         
684                                         MouseEventData mouseEventData = new MouseEventData(
685                                                         MouseButtonType.LEFT.value(), eventType,
686                                                         e.x, e.y, geometry[0], geometry[1], 0);
687
688                                         communicator.sendToQEMU(SendCommand.SEND_MOUSE_EVENT, mouseEventData);
689                                 }
690                         }
691                 };
692
693                 canvas.addMouseMoveListener(canvasMouseMoveListener);
694
695                 canvasMouseListener = new MouseListener() {
696
697                         @Override
698                         public void mouseUp(MouseEvent e) {
699                                 if (1 == e.button) { /* left button */
700
701                                         int[] geometry = SkinUtil.convertMouseGeometry(e.x, e.y,
702                                                         currentState.getCurrentResolutionWidth(),
703                                                         currentState.getCurrentResolutionHeight(),
704                                                         currentState.getCurrentScale(), currentState.getCurrentAngle());
705                                         logger.info("mouseUp in display" +
706                                                         " x:" + geometry[0] + " y:" + geometry[1]);
707
708                                         if (true == EmulatorSkin.this.isDragStartedInLCD) {
709                                                 EmulatorSkin.this.isDragStartedInLCD = false;
710                                         }
711
712                                         if (SwtUtil.isMacPlatform()) {
713                                                 pressingX = pressingY = -1;
714                                                 pressingOriginX = pressingOriginY = -1;
715                                                 if (finger.getMultiTouchEnable() == 1) {
716                                                         logger.info("maruFingerProcessing1");
717                                                         finger.maruFingerProcessing1(MouseEventType.RELEASE.value(),
718                                                                         e.x, e.y, geometry[0], geometry[1]);
719                                                         return;
720                                                 }
721                                                 else if (finger.getMultiTouchEnable() == 2) {
722                                                         logger.info("maruFingerProcessing2");
723                                                         finger.maruFingerProcessing2(MouseEventType.RELEASE.value(),
724                                                                         e.x, e.y, geometry[0], geometry[1]);
725                                                         return;
726                                                 }
727                                         }
728                                         
729                                         MouseEventData mouseEventData = new MouseEventData(
730                                                         MouseButtonType.LEFT.value(), MouseEventType.RELEASE.value(),
731                                                         e.x, e.y, geometry[0], geometry[1], 0);
732
733                                         communicator.sendToQEMU(SendCommand.SEND_MOUSE_EVENT, mouseEventData);
734                                 } else if (2 == e.button) { /* wheel button */
735                                         logger.info("wheelUp in display");
736                                 }
737                         }
738
739                         @Override
740                         public void mouseDown(MouseEvent e) {
741                                 if (1 == e.button) { /* left button */
742
743                                         int[] geometry = SkinUtil.convertMouseGeometry(e.x, e.y,
744                                                         currentState.getCurrentResolutionWidth(),
745                                                         currentState.getCurrentResolutionHeight(),
746                                                         currentState.getCurrentScale(), currentState.getCurrentAngle());
747                                         logger.info("mouseDown in display" +
748                                                         " x:" + geometry[0] + " y:" + geometry[1]);
749
750                                         if (false == EmulatorSkin.this.isDragStartedInLCD) {
751                                                 EmulatorSkin.this.isDragStartedInLCD = true;
752                                         }
753
754                                         if (SwtUtil.isMacPlatform()) {
755                                                 pressingX = geometry[0];
756                                                 pressingY = geometry[1];
757                                                 pressingOriginX = e.x;
758                                                 pressingOriginY = e.y;
759         
760                                                 if (finger.getMultiTouchEnable() == 1) {
761                                                         logger.info("maruFingerProcessing1");
762                                                         finger.maruFingerProcessing1(MouseEventType.PRESS.value(),
763                                                                         e.x, e.y, geometry[0], geometry[1]);
764                                                         return;
765                                                 }
766                                                 else if (finger.getMultiTouchEnable() == 2) {
767                                                         logger.info("maruFingerProcessing2");
768                                                         finger.maruFingerProcessing2(MouseEventType.PRESS.value(),
769                                                                         e.x, e.y, geometry[0], geometry[1]);
770                                                         return;
771                                                 }
772                                         }
773                 
774                                         MouseEventData mouseEventData = new MouseEventData(
775                                                         MouseButtonType.LEFT.value(), MouseEventType.PRESS.value(),
776                                                         e.x, e.y, geometry[0], geometry[1], 0);
777
778                                         communicator.sendToQEMU(SendCommand.SEND_MOUSE_EVENT, mouseEventData);
779                                 }
780                         }
781
782                         @Override
783                         public void mouseDoubleClick(MouseEvent e) {
784                                 /* do nothing */
785                         }
786                 };
787
788                 canvas.addMouseListener(canvasMouseListener);
789
790                 canvasMouseWheelListener = new MouseWheelListener() {
791
792                         @Override
793                         public void mouseScrolled(MouseEvent e) {
794                                 int[] geometry = SkinUtil.convertMouseGeometry(e.x, e.y,
795                                                 currentState.getCurrentResolutionWidth(),
796                                                 currentState.getCurrentResolutionHeight(),
797                                                 currentState.getCurrentScale(), currentState.getCurrentAngle());
798                                 logger.info("mousewheel in display" +
799                                                 " x:" + geometry[0] + " y:" + geometry[1] + " value:" + e.count);
800
801                                 int eventType;
802                                 if (e.count < 0) {
803                                         eventType = MouseEventType.WHEELDOWN.value();
804                                 } else {
805                                         eventType = MouseEventType.WHEELUP.value();
806                                 }
807
808                                 MouseEventData mouseEventData = new MouseEventData(
809                                                 MouseButtonType.WHEEL.value(), eventType,
810                                                 e.x, e.y, geometry[0], geometry[1], e.count);
811
812                                 communicator.sendToQEMU(SendCommand.SEND_MOUSE_EVENT, mouseEventData);
813                         }
814                 };
815
816                 canvas.addMouseWheelListener(canvasMouseWheelListener);
817
818                 /* keyboard event */
819                 canvasKeyListener = new KeyListener() {
820
821                         private KeyEvent previous;
822                         private boolean disappearEvent = false;
823                         private int disappearKeycode = 0;
824                         private int disappearStateMask = 0;
825                         private int disappearKeyLocation = 0;
826
827                         @Override
828                         public void keyReleased(KeyEvent e) {
829                                 if (logger.isLoggable(Level.INFO)) {
830                                         logger.info("'" + e.character + "':" +
831                                                         e.keyCode + ":" + e.stateMask + ":" + e.keyLocation);
832                                 } else if (logger.isLoggable(Level.FINE)) {
833                                         logger.fine(e.toString());
834                                 }
835
836                                 int keyCode = e.keyCode;
837                                 int stateMask = e.stateMask;
838
839                                 previous = null;
840
841                                 /* generate a disappeared key event in Windows */
842                                 if (SwtUtil.isWindowsPlatform() && disappearEvent) {
843                                         disappearEvent = false;
844                                         if (isMetaKey(e.keyCode) && e.character != '\0') {
845                                                 logger.info("send disappear release : keycode=" + disappearKeycode +
846                                                                 ", stateMask=" + disappearStateMask +
847                                                                 ", keyLocation=" + disappearKeyLocation);
848
849                                                 KeyEventData keyEventData = new KeyEventData(
850                                                                 KeyEventType.RELEASED.value(),
851                                                                 disappearKeycode, disappearStateMask, disappearKeyLocation);
852                                                 communicator.sendToQEMU(SendCommand.SEND_KEY_EVENT, keyEventData);
853
854                                                 removePressedKey(keyEventData);
855
856                                                 disappearKeycode = 0;
857                                                 disappearStateMask = 0;
858                                                 disappearKeyLocation = 0;
859                                         }
860                                 }
861                                 else if (SwtUtil.isMacPlatform()) {
862                                         /* check multi-touch */
863                                         if (keyCode == SWT.SHIFT || keyCode == SWT.COMMAND) {
864                                                 int tempStateMask = stateMask & ~SWT.BUTTON1;
865                                                 if (tempStateMask == (SWT.SHIFT | SWT.COMMAND)) {
866                                                         finger.setMultiTouchEnable(1);
867                                                         logger.info("enable multi-touch = mode1");
868                                                 }
869                                                 else {
870                                                         finger.setMultiTouchEnable(0);
871                                                         finger.clearFingerSlot();
872                                                         logger.info("disable multi-touch");
873                                                 }
874                                         }
875                                 }
876
877                                 KeyEventData keyEventData = new KeyEventData(
878                                                 KeyEventType.RELEASED.value(), keyCode, stateMask, e.keyLocation);
879                                 communicator.sendToQEMU(SendCommand.SEND_KEY_EVENT, keyEventData);
880
881                                 removePressedKey(keyEventData);
882                         }
883
884                         @Override
885                         public void keyPressed(KeyEvent e) {
886                                 int keyCode = e.keyCode;
887                                 int stateMask = e.stateMask;
888
889                                 /* When the pressed key event is overwritten by next key event,
890                                  * the release event of previous key does not occur in Windows.
891                                  * So, we generate a release key event by ourselves
892                                  * that had been disappeared. */
893                                 if (SwtUtil.isWindowsPlatform()) {
894                                         if (null != previous) {
895                                                 if (previous.keyCode != e.keyCode) {
896
897                                                         if (isMetaKey(previous.keyCode)) {
898                                                                 disappearEvent = true;
899                                                                 disappearKeycode = keyCode;
900                                                                 disappearStateMask = stateMask;
901                                                                 disappearKeyLocation = e.keyLocation;
902                                                         } else {
903                                                                 /* three or more keys were pressed
904                                                                 at the same time */
905                                                                 if (disappearEvent == true) {
906                                                                         logger.info("replace the disappearEvent : " +
907                                                                                         disappearKeycode + "->" + keyCode);
908
909                                                                         disappearKeycode = keyCode;
910                                                                         disappearStateMask = stateMask;
911                                                                         disappearKeyLocation = e.keyLocation;
912                                                                 }
913
914                                                                 int previousKeyCode = previous.keyCode;
915                                                                 int previousStateMask = previous.stateMask;
916
917                                                                 if (logger.isLoggable(Level.INFO)) {
918                                                                         logger.info("send previous release : '" +
919                                                                                         previous.character + "':" + previous.keyCode + ":" +
920                                                                                         previous.stateMask + ":" + previous.keyLocation);
921                                                                 } else if (logger.isLoggable(Level.FINE)) {
922                                                                         logger.fine("send previous release :" + previous.toString());
923                                                                 }
924
925                                                                 KeyEventData keyEventData = new KeyEventData(KeyEventType.RELEASED.value(),
926                                                                                 previousKeyCode, previousStateMask, previous.keyLocation);
927                                                                 communicator.sendToQEMU(SendCommand.SEND_KEY_EVENT, keyEventData);
928
929                                                                 removePressedKey(keyEventData);
930                                                         }
931
932                                                 }
933                                         }
934                                 } //end isWindowsPlatform
935                                 else if (SwtUtil.isMacPlatform()) {
936                 //      if(finger.getMaxTouchPoint() > 1) {
937                                                 int tempStateMask = stateMask & ~SWT.BUTTON1;
938                                                 if ((keyCode == SWT.SHIFT && (tempStateMask & SWT.COMMAND) != 0) || 
939                                                                 (keyCode == SWT.COMMAND && (tempStateMask & SWT.SHIFT) != 0))
940                                                 {
941                                                         finger.setMultiTouchEnable(2);
942                                                         /* add a finger before start the multi-touch processing
943                                                                         if already exist the pressed touch in display */
944                                         if (pressingX != -1 && pressingY != -1 &&
945                                                         pressingOriginX != -1 && pressingOriginY != -1) {
946                                                         finger.addFingerPoint(
947                                                                 pressingOriginX, pressingOriginY,
948                                                                 pressingX, pressingY);
949                                                         pressingX = pressingY = -1;
950                                                         pressingOriginX = pressingOriginY = -1;
951                                                 }
952                                                         logger.info("enable multi-touch = mode2");
953                                                 }
954                                                 else if (keyCode == SWT.SHIFT || keyCode == SWT.COMMAND) {
955                                                         finger.setMultiTouchEnable(1);
956                                                         /* add a finger before start the multi-touch processing
957                                                          * if already exist the pressed touch in display */
958                                                         if (pressingX != -1 && pressingY != -1 &&
959                                                                         pressingOriginX != -1 && pressingOriginY != -1) {
960                                                 finger.addFingerPoint(
961                                                                 pressingOriginX, pressingOriginY,                                              
962                                                                 pressingX, pressingY);
963                                                 pressingX = pressingY = -1;
964                                                 pressingOriginX = pressingOriginY = -1;
965                                         }
966                                                         logger.info("enable multi-touch = mode1");
967                                                 }
968                 //      }
969                                 }
970
971                                 previous = e;
972
973                                 if (logger.isLoggable(Level.INFO)) {
974                                         logger.info("'" + e.character + "':" +
975                                                         e.keyCode + ":" + e.stateMask + ":" + e.keyLocation);
976                                 } else if (logger.isLoggable(Level.FINE)) {
977                                         logger.fine(e.toString());
978                                 }
979
980                                 KeyEventData keyEventData = new KeyEventData(
981                                                 KeyEventType.PRESSED.value(), keyCode, stateMask, e.keyLocation);
982                                 communicator.sendToQEMU(SendCommand.SEND_KEY_EVENT, keyEventData);
983
984                                 addPressedKey(keyEventData);
985                         }
986
987                 };
988
989                 canvas.addKeyListener(canvasKeyListener);
990         }
991
992         private boolean isMetaKey(int keyCode) {
993                 if (SWT.CTRL == keyCode ||
994                                 SWT.ALT == keyCode ||
995                                 SWT.SHIFT == keyCode ||
996                                 SWT.COMMAND == keyCode) {
997                         return true;
998                 }
999
1000                 return false;
1001         }
1002
1003         private synchronized boolean addPressedKey(KeyEventData pressData) {
1004                 for (KeyEventData data : pressedKeyEventList) {
1005                         if (data.keycode == pressData.keycode &&
1006                                         //data.stateMask == pressData.stateMask &&
1007                                         data.keyLocation == pressData.keyLocation) {
1008                                 return false;
1009                         }
1010                 }
1011
1012                 pressedKeyEventList.add(pressData);
1013                 return true;
1014         }
1015
1016         private synchronized boolean removePressedKey(KeyEventData releaseData) {
1017
1018                 for (KeyEventData data : pressedKeyEventList) {
1019                         if (data.keycode == releaseData.keycode &&
1020                                         //data.stateMask == releaseData.stateMask &&
1021                                         data.keyLocation == releaseData.keyLocation) {
1022                                 pressedKeyEventList.remove(data);
1023
1024                                 return true;
1025                         }
1026                 }
1027
1028                 return false;
1029         }
1030
1031         private void removeCanvasListeners() {
1032 //              if ( null != canvasDragDetectListener ) {
1033 //                      lcdCanvas.removeDragDetectListener( canvasDragDetectListener );
1034 //              }
1035                 if (null != canvasMouseMoveListener) {
1036                         lcdCanvas.removeMouseMoveListener(canvasMouseMoveListener);
1037                 }
1038
1039                 if (null != canvasMouseListener) {
1040                         lcdCanvas.removeMouseListener(canvasMouseListener);
1041                 }
1042
1043                 if (null != canvasKeyListener) {
1044                         lcdCanvas.removeKeyListener(canvasKeyListener);
1045                 }
1046
1047                 if (null != canvasMenuDetectListener) {
1048                         lcdCanvas.removeMenuDetectListener(canvasMenuDetectListener);
1049                 }
1050
1051                 if (null != canvasFocusListener) {
1052                         lcdCanvas.removeFocusListener(canvasFocusListener);
1053                 }
1054
1055                 if (null != canvasMouseWheelListener) {
1056                         lcdCanvas.removeMouseWheelListener(canvasMouseWheelListener);
1057                 }
1058         }
1059
1060         public void setFocus() {
1061                 lcdCanvas.setFocus();
1062         }
1063
1064         protected void openScreenShotWindow() {
1065                 /* abstract */
1066         }
1067
1068         public void dispalyBrightness(boolean on) {
1069                 if (on == true) {
1070                         displayOn();
1071                 } else {
1072                         displayOff();
1073                 }
1074         }
1075
1076         protected void displayOn() {
1077                 /* abstract */
1078         }
1079
1080         protected void displayOff() {
1081                 /* abstract */
1082         }
1083
1084         public boolean isSelectKeyWindow() {
1085                 return keyWindowItem.getSelection();
1086         }
1087
1088         public void openKeyWindow(int dockValue, boolean recreate) {
1089                 if (keyWindow != null) {
1090                         if (recreate == false) {
1091                                 /* show the key window */
1092                                 keyWindowItem.setSelection(isKeyWindow = true);
1093                                 pairTag.setVisible(true);
1094
1095                                 keyWindow.getShell().setVisible(true);
1096                                 SkinUtil.setTopMost(keyWindow.getShell(), isOnTop);
1097
1098                                 return;
1099                         } else {
1100                                 logger.info("recreate a keywindow");
1101                                 closeKeyWindow();
1102                         }
1103                 }
1104
1105                 /* create a key window */
1106                 List<KeyMapType> keyMapList =
1107                                 SkinUtil.getHWKeyMapList(currentState.getCurrentRotationId());
1108
1109                 if (keyMapList == null) {
1110                         keyWindowItem.setSelection(isKeyWindow = false);
1111                         logger.info("keyMapList is null");
1112                         return;
1113                 } else if (keyMapList.isEmpty() == true) {
1114                         keyWindowItem.setSelection(isKeyWindow = false);
1115                         logger.info("keyMapList is empty");
1116                         return;
1117                 }
1118
1119                 keyWindow = new KeyWindow(this, shell, communicator, keyMapList);
1120
1121                 keyWindowItem.setSelection(isKeyWindow = true);
1122                 SkinUtil.setTopMost(keyWindow.getShell(), isOnTop);
1123
1124                 pairTag.setVisible(true);
1125
1126                 keyWindow.open(dockValue);
1127         }
1128
1129         public void hideKeyWindow() {
1130                 keyWindowItem.setSelection(isKeyWindow = false);
1131                 pairTag.setVisible(false);
1132
1133                 if (keyWindow != null) {
1134                         keyWindow.getShell().setVisible(false);
1135                 }
1136         }
1137
1138         public void closeKeyWindow() {
1139                 keyWindowItem.setSelection(isKeyWindow = false);
1140                 pairTag.setVisible(false);
1141
1142                 if (keyWindow != null) {
1143                         keyWindow.getShell().close();
1144                         keyWindow = null;
1145                 }
1146         }
1147
1148         private void addMenuItems(final Shell shell, final Menu menu) {
1149
1150                 /* Emulator detail info menu */
1151                 final MenuItem detailInfoItem = new MenuItem(menu, SWT.PUSH);
1152
1153                 String emulatorName = SkinUtil.makeEmulatorName(config);
1154                 detailInfoItem.setText(emulatorName);
1155                 detailInfoItem.setImage(imageRegistry.getIcon(IconName.DETAIL_INFO));
1156                 detailInfoItem.addSelectionListener(new SelectionAdapter() {
1157                         @Override
1158                         public void widgetSelected(SelectionEvent e) {
1159                                 if (logger.isLoggable(Level.FINE)) {
1160                                         logger.fine("Open detail info");
1161                                 }
1162
1163                                 String emulatorName = SkinUtil.makeEmulatorName(config);
1164                                 DetailInfoDialog detailInfoDialog = new DetailInfoDialog(
1165                                                 shell, emulatorName, communicator, config);
1166                                 detailInfoDialog.open();
1167                         }
1168                 } );
1169
1170                 new MenuItem(menu, SWT.SEPARATOR);
1171
1172                 /* Always on top menu */
1173                 if (!SwtUtil.isMacPlatform()) { /* not supported on mac */
1174                         final MenuItem onTopItem = new MenuItem(menu, SWT.CHECK);
1175                         onTopItem.setText("&Always On Top");
1176                         onTopItem.setSelection(isOnTop);
1177
1178                         onTopItem.addSelectionListener(new SelectionAdapter() {
1179                                 @Override
1180                                 public void widgetSelected(SelectionEvent e) {
1181                                         isOnTop = onTopItem.getSelection();
1182
1183                                         logger.info("Select Always On Top : " + isOnTop);
1184                                         // readyToReopen(EmulatorSkin.this, isOnTop);
1185
1186                                         if (SkinUtil.setTopMost(shell, isOnTop) == false) {
1187                                                 logger.info("failed to Always On Top");
1188                                         } else {
1189                                                 if (keyWindow != null) {
1190                                                         SkinUtil.setTopMost(keyWindow.getShell(), isOnTop);
1191                                                 }
1192                                         }
1193                                 }
1194                         } );
1195                 }
1196
1197                 /* Rotate menu */
1198                 final MenuItem rotateItem = new MenuItem(menu, SWT.CASCADE);
1199                 rotateItem.setText("&Rotate");
1200                 rotateItem.setImage(imageRegistry.getIcon(IconName.ROTATE));
1201                 Menu rotateMenu = createRotateMenu(menu.getShell());
1202                 rotateItem.setMenu(rotateMenu);
1203
1204                 /* Scale menu */
1205                 final MenuItem scaleItem = new MenuItem(menu, SWT.CASCADE);
1206                 scaleItem.setText("&Scale");
1207                 scaleItem.setImage(imageRegistry.getIcon(IconName.SCALE));
1208                 Menu scaleMenu = createScaleMenu(menu.getShell());
1209                 scaleItem.setMenu(scaleMenu);
1210
1211                 new MenuItem(menu, SWT.SEPARATOR);
1212
1213                 /* Key Window menu */
1214                 if (skinInfo.isPhoneShape() == false) { //TODO:
1215                 keyWindowItem = new MenuItem(menu, SWT.CHECK);
1216                 keyWindowItem.setText("&Key Window");
1217                 keyWindowItem.setSelection(isKeyWindow);
1218
1219                 keyWindowItem.addSelectionListener(new SelectionAdapter() {
1220                         @Override
1221                         public void widgetSelected(SelectionEvent e) {
1222                                 final boolean selectKeyWindow = keyWindowItem.getSelection();
1223
1224                                 if (selectKeyWindow == true) {
1225                                         if (keyWindow == null) {
1226                                                 openKeyWindow(recentlyDocked, false);
1227                                                 recentlyDocked = SWT.NONE;
1228                                         } else {
1229                                                 openKeyWindow(keyWindow.getDockPosition(), false);
1230                                         }
1231                                 } else { /* hide a key window */
1232                                         if (keyWindow != null &&
1233                                                         keyWindow.getDockPosition() != SWT.NONE) {
1234                                                 /* close the Key Window if it is docked to Main Window */
1235                                                 recentlyDocked = keyWindow.getDockPosition();
1236                                                 closeKeyWindow();
1237                                         } else {
1238                                                 hideKeyWindow();
1239                                         }
1240                                 }
1241                         }
1242                 } );
1243                 }
1244
1245                 /* Advanced menu */
1246                 final MenuItem advancedItem = new MenuItem(menu, SWT.CASCADE);
1247                 advancedItem.setText("Ad&vanced");
1248                 advancedItem.setImage(imageRegistry.getIcon(IconName.ADVANCED));
1249                 Menu advancedMenu = createAdvancedMenu(menu.getShell());
1250                 advancedItem.setMenu(advancedMenu);
1251
1252                 /* Shell menu */
1253                 final MenuItem shellItem = new MenuItem(menu, SWT.PUSH);
1254                 shellItem.setText("S&hell");
1255                 shellItem.setImage(imageRegistry.getIcon(IconName.SHELL));
1256
1257                 shellItem.addSelectionListener(new SelectionAdapter() {
1258                         @Override
1259                         public void widgetSelected(SelectionEvent e) {
1260                                 if (!communicator.isSdbDaemonStarted()) {
1261                                         SkinUtil.openMessage(shell, null, "SDB is not ready.\n" +
1262                                                         "Please wait until the emulator is completely boot up.",
1263                                                         SWT.ICON_WARNING, config);
1264                                         return;
1265                                 }
1266
1267                                 String sdbPath = SkinUtil.getSdbPath();
1268
1269                                 File sdbFile = new File(sdbPath);
1270                                 if (!sdbFile.exists()) {
1271                                         logger.log(Level.INFO, "SDB file is not exist : " + sdbFile.getAbsolutePath());
1272                                         try {
1273                                                 SkinUtil.openMessage(shell, null,
1274                                                                 "SDB file is not exist in the following path.\n" + sdbFile.getCanonicalPath()
1275                                                                 , SWT.ICON_ERROR, config);
1276                                         } catch (IOException ee) {
1277                                                 logger.log(Level.SEVERE, ee.getMessage(), ee);
1278                                         }
1279                                         return;
1280                                 }
1281
1282                                 int portSdb = config.getArgInt(ArgsConstants.NET_BASE_PORT);
1283
1284                                 ProcessBuilder procSdb = new ProcessBuilder();
1285
1286                                 if (SwtUtil.isLinuxPlatform()) {
1287                                         procSdb.command("/usr/bin/gnome-terminal", "--disable-factory",
1288                                                         "--title=" + SkinUtil.makeEmulatorName( config ), "-x", sdbPath,
1289                                                         "-s", "emulator-" + portSdb, "shell");
1290                                 } else if (SwtUtil.isWindowsPlatform()) {
1291                                         procSdb.command("cmd.exe", "/c", "start", sdbPath, "sdb",
1292                                                         "-s", "emulator-" + portSdb, "shell");
1293                                 } else if (SwtUtil.isMacPlatform()) {
1294                                         procSdb.command("./sdbscript", "emulator-" + portSdb);
1295                                         //procSdb.command("/usr/X11/bin/uxterm", "-T", "emulator-" + portSdb, "-e", sdbPath,"shell");
1296                                 }
1297
1298                                 logger.log(Level.INFO, procSdb.command().toString());
1299
1300                                 try {
1301                                         procSdb.start(); /* open the sdb shell */
1302                                 } catch (Exception ee) {
1303                                         logger.log(Level.SEVERE, ee.getMessage(), ee);
1304                                         SkinUtil.openMessage(shell, null, "Fail to open Shell: \n" +
1305                                                         ee.getMessage(), SWT.ICON_ERROR, config);
1306                                 }
1307
1308                                 communicator.sendToQEMU(SendCommand.OPEN_SHELL, null);
1309                         }
1310                 } );
1311
1312                 new MenuItem(menu, SWT.SEPARATOR);
1313
1314                 /* Close menu */
1315                 MenuItem closeItem = new MenuItem(menu, SWT.PUSH);
1316                 closeItem.setText("&Close");
1317                 closeItem.setImage(imageRegistry.getIcon(IconName.CLOSE));
1318
1319                 closeItem.addSelectionListener(new SelectionAdapter() {
1320                         @Override
1321                         public void widgetSelected(SelectionEvent e) {
1322                                 logger.info("Close Menu is selected");
1323                                 communicator.sendToQEMU(SendCommand.CLOSE, null);
1324                         }
1325                 } );
1326
1327         }
1328
1329         private Menu createRotateMenu(final Shell shell) {
1330
1331                 Menu menu = new Menu( shell, SWT.DROP_DOWN );
1332
1333                 final List<MenuItem> rotationList = new ArrayList<MenuItem>();
1334
1335                 Iterator<Entry<Short, RotationType>> iterator = SkinRotation.getRotationIterator();
1336
1337                 while ( iterator.hasNext() ) {
1338
1339                         Entry<Short, RotationType> entry = iterator.next();
1340                         Short rotationId = entry.getKey();
1341                         RotationType section = entry.getValue();
1342
1343                         final MenuItem menuItem = new MenuItem( menu, SWT.RADIO );
1344                         menuItem.setText( section.getName().value() );
1345                         menuItem.setData( rotationId );
1346
1347                         if (currentState.getCurrentRotationId() == rotationId) {
1348                                 menuItem.setSelection( true );
1349                         }
1350
1351                         rotationList.add( menuItem );
1352
1353                 }
1354
1355                 /* temp : swap rotation menu names */
1356                 if (currentState.getCurrentResolutionWidth() >
1357                                 currentState.getCurrentResolutionHeight())
1358                 {
1359                         for (MenuItem m : rotationList) {
1360                                 short rotationId = (Short) m.getData();
1361
1362                                 if (rotationId == RotationInfo.PORTRAIT.id()) {
1363                                         String landscape = SkinRotation.getRotation(
1364                                                         RotationInfo.LANDSCAPE.id()).getName().value();
1365                                         m.setText(landscape);
1366                                 } else if (rotationId == RotationInfo.LANDSCAPE.id()) {
1367                                         String portrait = SkinRotation.getRotation(
1368                                                         RotationInfo.PORTRAIT.id()).getName().value();
1369                                         m.setText(portrait);
1370                                 } else if (rotationId == RotationInfo.REVERSE_PORTRAIT.id()) {
1371                                         String landscapeReverse = SkinRotation.getRotation(
1372                                                         RotationInfo.REVERSE_LANDSCAPE.id()).getName().value();
1373                                         m.setText(landscapeReverse);
1374                                 } else if (rotationId == RotationInfo.REVERSE_LANDSCAPE.id()) {
1375                                         String portraitReverse = SkinRotation.getRotation(
1376                                                         RotationInfo.REVERSE_PORTRAIT.id()).getName().value();
1377                                         m.setText(portraitReverse);
1378                                 }
1379                         }
1380                 }
1381
1382                 SelectionAdapter selectionAdapter = new SelectionAdapter() {
1383                         @Override
1384                         public void widgetSelected(SelectionEvent e) {
1385
1386                                 MenuItem item = (MenuItem) e.getSource();
1387
1388                                 boolean selection = item.getSelection();
1389
1390                                 if (!selection) {
1391                                         return;
1392                                 }
1393
1394                                 if (!communicator.isSensorDaemonStarted()) {
1395
1396                                         /* roll back a selection */
1397                                         item.setSelection(false);
1398
1399                                         for (MenuItem m : rotationList) {
1400                                                 short rotationId = (Short) m.getData();
1401                                                 if (currentState.getCurrentRotationId() == rotationId) {
1402                                                         m.setSelection(true);
1403                                                         break;
1404                                                 }
1405                                         }
1406
1407                                         SkinUtil.openMessage(shell, null,
1408                                                         "Rotation is not ready.\nPlease wait until the emulator is completely boot up.",
1409                                                         SWT.ICON_WARNING, config);
1410                                         return;
1411                                 }
1412
1413                                 final short rotationId = ((Short) item.getData());
1414
1415                                 shell.getDisplay().syncExec(new Runnable() {
1416                                         @Override
1417                                         public void run() {
1418 //                                              Point location = new Point(100, 100);
1419 //
1420 //                                              if (skinInfo.isPhoneShape()) { /* TODO: */
1421 //                                                      location = shell.getLocation();
1422 //                                                      shell.setVisible(false);
1423 //                                              }
1424
1425                                                 skinComposer.arrangeSkin(currentState.getCurrentScale(), rotationId);
1426
1427 //                                              if (skinInfo.isPhoneShape()) { /* TODO: */
1428 //                                                      shell.setVisible(true);
1429 //                                                      shell.setLocation(location);
1430 //                                                      SkinUtil.setTopMost(shell, isOnTop);
1431 //                                              }
1432
1433                                                 /* location correction */
1434                                                 Rectangle monitorBounds = Display.getDefault().getBounds();
1435                                                 Rectangle emulatorBounds = shell.getBounds();
1436                                                 shell.setLocation(
1437                                                                 Math.max(emulatorBounds.x, monitorBounds.x),
1438                                                                 Math.max(emulatorBounds.y, monitorBounds.y));
1439                                         }
1440                                 });
1441
1442                                 DisplayStateData lcdStateData =
1443                                                 new DisplayStateData(currentState.getCurrentScale(), rotationId);
1444                                 communicator.sendToQEMU(SendCommand.CHANGE_LCD_STATE, lcdStateData);
1445                         }
1446                 };
1447
1448                 for (MenuItem menuItem : rotationList) {
1449                         menuItem.addSelectionListener(selectionAdapter);
1450                 }
1451
1452                 return menu;
1453         }
1454
1455         private Menu createScaleMenu(final Shell shell) {
1456
1457                 Menu menu = new Menu(shell, SWT.DROP_DOWN);
1458
1459                 final List<MenuItem> scaleList = new ArrayList<MenuItem>();
1460
1461                 final MenuItem scaleOneItem = new MenuItem(menu, SWT.RADIO);
1462                 scaleOneItem.setText("1x");
1463                 scaleOneItem.setData(Scale.SCALE_100);
1464                 scaleList.add(scaleOneItem);
1465
1466                 final MenuItem scaleThreeQtrItem = new MenuItem(menu, SWT.RADIO);
1467                 scaleThreeQtrItem.setText("3/4x");
1468                 scaleThreeQtrItem.setData(Scale.SCALE_75);
1469                 scaleList.add( scaleThreeQtrItem );
1470
1471                 final MenuItem scalehalfItem = new MenuItem(menu, SWT.RADIO);
1472                 scalehalfItem.setText("1/2x");
1473                 scalehalfItem.setData(Scale.SCALE_50);
1474                 scaleList.add(scalehalfItem);
1475
1476                 final MenuItem scaleOneQtrItem = new MenuItem(menu, SWT.RADIO);
1477                 scaleOneQtrItem.setText("1/4x");
1478                 scaleOneQtrItem.setData(Scale.SCALE_25);
1479                 scaleList.add(scaleOneQtrItem);
1480
1481                 SelectionAdapter selectionAdapter = new SelectionAdapter() {
1482                         @Override
1483                         public void widgetSelected(SelectionEvent e) {
1484
1485                                 MenuItem item = (MenuItem) e.getSource();
1486
1487                                 boolean selection = item.getSelection();
1488
1489                                 if (!selection) {
1490                                         return;
1491                                 }
1492
1493                                 final int scale = ((Scale) item.getData()).value();
1494
1495                                 shell.getDisplay().syncExec(new Runnable() {
1496                                         @Override
1497                                         public void run() {
1498 //                                              Point location = new Point(100, 100);
1499 //
1500 //                                              if (skinInfo.isPhoneShape()) { /* TODO: */
1501 //                                                      location = shell.getLocation();
1502 //                                                      shell.setVisible(false);
1503 //                                              }
1504
1505                                                 skinComposer.arrangeSkin(scale, currentState.getCurrentRotationId());
1506
1507 //                                              if (skinInfo.isPhoneShape()) { /* TODO: */
1508 //                                                      shell.setVisible(true);
1509 //                                                      shell.setLocation(location);
1510 //                                                      SkinUtil.setTopMost(shell, isOnTop);
1511 //                                              }
1512
1513                                                 /* location correction */
1514                                                 Rectangle monitorBounds = Display.getDefault().getBounds();
1515                                                 Rectangle emulatorBounds = shell.getBounds();
1516                                                 shell.setLocation(
1517                                                                 Math.max(emulatorBounds.x, monitorBounds.x),
1518                                                                 Math.max(emulatorBounds.y, monitorBounds.y));
1519                                         }
1520                                 });
1521
1522                                 DisplayStateData lcdStateData =
1523                                                 new DisplayStateData(scale, currentState.getCurrentRotationId());
1524                                 communicator.sendToQEMU(SendCommand.CHANGE_LCD_STATE, lcdStateData);
1525
1526                         }
1527                 };
1528                 
1529                 for (MenuItem menuItem : scaleList) {
1530
1531                         int scale = ((Scale) menuItem.getData()).value();
1532                         if (currentState.getCurrentScale() == scale) {
1533                                 menuItem.setSelection(true);
1534                         }
1535
1536                         menuItem.addSelectionListener(selectionAdapter);
1537                 }
1538
1539                 return menu;
1540         }
1541
1542         private Menu createDiagnosisMenu(Shell shell) {
1543                 Menu menu = new Menu(shell, SWT.DROP_DOWN);
1544
1545                 final MenuItem ramdumpItem = new MenuItem(menu, SWT.PUSH);
1546                 ramdumpItem.setText("&Ram Dump");
1547
1548                 ramdumpItem.addSelectionListener(new SelectionAdapter() {
1549                         @Override
1550                         public void widgetSelected(SelectionEvent e) {
1551                                 logger.info("Ram dump menu is selected");
1552
1553                                 communicator.setRamdumpFlag(true);
1554                                 communicator.sendToQEMU(SendCommand.RAM_DUMP, null);
1555
1556                                 RamdumpDialog ramdumpDialog;
1557                                 try {
1558                                         ramdumpDialog = new RamdumpDialog(EmulatorSkin.this.shell, communicator, config);
1559                                         ramdumpDialog.open();
1560                                 } catch (IOException ee) {
1561                                         logger.log( Level.SEVERE, ee.getMessage(), ee);
1562                                 }
1563                         }
1564                 });
1565
1566                 /* final MenuItem guestdumpItem = new MenuItem(menu, SWT.PUSH);
1567                 guestdumpItem.setText("&Guest Memory Dump");
1568
1569                 guestdumpItem.addSelectionListener(new SelectionAdapter() {
1570                         @Override
1571                         public void widgetSelected(SelectionEvent e) {
1572                                 logger.info("Guest memory dump menu is selected");
1573
1574                                 communicator.setRamdumpFlag(true);
1575                                 communicator.sendToQEMU(SendCommand.GUEST_DUMP, null);
1576                         }
1577                 }); */
1578
1579                 return menu;
1580         }
1581
1582         private Menu createAdvancedMenu(final Shell shell) {
1583
1584                 final Menu menu = new Menu(shell, SWT.DROP_DOWN);
1585
1586                 /* Screen shot menu */
1587                 final MenuItem screenshotItem = new MenuItem(menu, SWT.PUSH);
1588                 screenshotItem.setText("&Screen Shot");
1589                 screenshotItem.setImage(imageRegistry.getIcon(IconName.SCREENSHOT));
1590                 screenshotItem.addSelectionListener(new SelectionAdapter() {
1591                         @Override
1592                         public void widgetSelected(SelectionEvent e) {
1593                                 logger.info("ScreenShot Menu is selected");
1594
1595                                 openScreenShotWindow();
1596                         }
1597                 } );
1598
1599                 /* VirtIO Keyboard Menu */
1600                 final MenuItem hostKeyboardItem = new MenuItem(menu, SWT.CASCADE);
1601                 hostKeyboardItem.setText("&Host Keyboard");
1602                 hostKeyboardItem.setImage(imageRegistry.getIcon(IconName.HOST_KEYBOARD));
1603
1604                 Menu hostKeyboardMenu = new Menu(shell, SWT.DROP_DOWN);
1605
1606                 final MenuItem kbdOnItem = new MenuItem(hostKeyboardMenu, SWT.RADIO);
1607                 kbdOnItem.setText("On");
1608                 kbdOnItem.setSelection( isOnKbd );
1609
1610                 final MenuItem kbdOffItem = new MenuItem(hostKeyboardMenu, SWT.RADIO);
1611                 kbdOffItem.setText("Off");
1612                 kbdOffItem.setSelection(!isOnKbd);
1613
1614                 SelectionAdapter kbdSelectionAdaptor = new SelectionAdapter() {
1615                         @Override
1616                         public void widgetSelected(SelectionEvent e) {
1617                                 if (!communicator.isSensorDaemonStarted()) {
1618                                         SkinUtil.openMessage(shell, null,
1619                                                         "Host Keyboard is not ready.\nPlease wait until the emulator is completely boot up.",
1620                                                         SWT.ICON_WARNING, config);
1621                                         kbdOnItem.setSelection(isOnKbd);
1622                                         kbdOffItem.setSelection(!isOnKbd);
1623
1624                                         return;
1625                                 }
1626
1627                                 MenuItem item = (MenuItem) e.getSource();
1628                                 if (item.getSelection()) {
1629                                         boolean on = item.equals(kbdOnItem);
1630                                         isOnKbd = on;
1631                                         logger.info("Host Keyboard " + isOnKbd);
1632
1633                                         communicator.sendToQEMU(
1634                                                         SendCommand.HOST_KBD, new BooleanData(on, SendCommand.HOST_KBD.toString()));
1635                                 }
1636
1637                         }
1638                 };
1639
1640                 kbdOnItem.addSelectionListener(kbdSelectionAdaptor);
1641                 kbdOffItem.addSelectionListener(kbdSelectionAdaptor);
1642
1643                 hostKeyboardItem.setMenu(hostKeyboardMenu);
1644
1645                 /* Diagnosis menu */
1646                 if (SwtUtil.isLinuxPlatform()) { //TODO: windows
1647                         final MenuItem diagnosisItem = new MenuItem(menu, SWT.CASCADE);
1648                         diagnosisItem.setText("&Diagnosis");
1649                         diagnosisItem.setImage(imageRegistry.getIcon(IconName.DIAGNOSIS));
1650                         Menu diagnosisMenu = createDiagnosisMenu(menu.getShell());
1651                         diagnosisItem.setMenu(diagnosisMenu);
1652                 }
1653
1654                 new MenuItem(menu, SWT.SEPARATOR);
1655
1656                 /* About menu */
1657                 final MenuItem aboutItem = new MenuItem(menu, SWT.PUSH);
1658                 aboutItem.setText("&About");
1659                 aboutItem.setImage(imageRegistry.getIcon(IconName.ABOUT));
1660
1661                 aboutItem.addSelectionListener(new SelectionAdapter() {
1662                         private boolean isOpen;
1663
1664                         @Override
1665                         public void widgetSelected(SelectionEvent e) {
1666                                 if (!isOpen) {
1667                                         isOpen = true;
1668
1669                                         logger.info("Open the about dialog");
1670                                         AboutDialog dialog = new AboutDialog(shell, config);
1671                                         dialog.open();
1672                                         isOpen = false;
1673                                 }
1674                         }
1675                 } );
1676
1677                 new MenuItem(menu, SWT.SEPARATOR);
1678
1679                 /* Force close menu */
1680                 final MenuItem forceCloseItem = new MenuItem(menu, SWT.PUSH);
1681                 forceCloseItem.setText("&Force Close");
1682                 forceCloseItem.setImage(imageRegistry.getIcon(IconName.FORCE_CLOSE));
1683
1684                 forceCloseItem.addSelectionListener(new SelectionAdapter() {
1685                         @Override
1686                         public void widgetSelected(SelectionEvent e) {
1687                                 logger.info("Force close is selected");
1688
1689                                 int answer = SkinUtil.openMessage(shell, null,
1690                                                 "If you force stop an emulator, it may cause some problems.\n" +
1691                                                 "Are you sure you want to contiue?",
1692                                                 SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL, config);
1693
1694                                 if (answer == SWT.OK) {
1695                                         logger.info("force close!!!");
1696                                         System.exit(-1);
1697                                 }
1698                         }
1699                 });
1700
1701                 return menu;
1702
1703         }
1704
1705         public void shutdown() {
1706
1707                 isShutdownRequested = true;
1708
1709                 if (!this.shell.isDisposed()) {
1710                         this.shell.getDisplay().asyncExec(new Runnable() {
1711                                 @Override
1712                                 public void run() {
1713                                         if (!shell.isDisposed()) {
1714                                                 EmulatorSkin.this.shell.close();
1715                                         }
1716                                 }
1717                         } );
1718                 }
1719
1720         }
1721
1722         public short getCurrentRotationId() {
1723                 return currentState.getCurrentRotationId();
1724         }
1725
1726         public void keyForceRelease(boolean isMetaFilter) {
1727                 /* key event compensation */
1728                 if (pressedKeyEventList.isEmpty() == false) {
1729                         for (KeyEventData data : pressedKeyEventList) {
1730                                 if (isMetaFilter == true) {
1731                                         if (isMetaKey(data.keycode) == true) {
1732                                                 /* keep multi-touching */
1733                                                 continue;
1734                                         }
1735                                 }
1736
1737                                 KeyEventData keyEventData = new KeyEventData(
1738                                                 KeyEventType.RELEASED.value(), data.keycode,
1739                                                 data.stateMask, data.keyLocation);
1740                                 communicator.sendToQEMU(
1741                                                 SendCommand.SEND_KEY_EVENT, keyEventData, false);
1742
1743                                 logger.info("auto release : keycode=" + keyEventData.keycode +
1744                                                 ", stateMask=" + keyEventData.stateMask +
1745                                                 ", keyLocation=" + keyEventData.keyLocation);
1746                         }
1747                 }
1748
1749                 pressedKeyEventList.clear();
1750         }
1751 }