• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2011, The Android Open Source Project
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 
17 package com.android.ide.eclipse.gldebugger;
18 
19 import com.android.ide.eclipse.gldebugger.DebuggerMessage.Message;
20 import com.android.ide.eclipse.gldebugger.DebuggerMessage.Message.Function;
21 import com.android.ide.eclipse.gldebugger.DebuggerMessage.Message.Prop;
22 import com.android.ide.eclipse.gldebugger.DebuggerMessage.Message.Type;
23 import com.android.sdklib.util.SparseArray;
24 
25 import org.eclipse.jface.action.Action;
26 import org.eclipse.jface.action.IMenuListener;
27 import org.eclipse.jface.action.IMenuManager;
28 import org.eclipse.jface.action.IToolBarManager;
29 import org.eclipse.jface.action.MenuManager;
30 import org.eclipse.jface.action.Separator;
31 import org.eclipse.jface.dialogs.InputDialog;
32 import org.eclipse.jface.dialogs.MessageDialog;
33 import org.eclipse.jface.viewers.ISelectionChangedListener;
34 import org.eclipse.jface.viewers.IStructuredContentProvider;
35 import org.eclipse.jface.viewers.ITableLabelProvider;
36 import org.eclipse.jface.viewers.LabelProvider;
37 import org.eclipse.jface.viewers.ListViewer;
38 import org.eclipse.jface.viewers.SelectionChangedEvent;
39 import org.eclipse.jface.viewers.StructuredSelection;
40 import org.eclipse.jface.viewers.TreeViewer;
41 import org.eclipse.jface.viewers.Viewer;
42 import org.eclipse.jface.viewers.ViewerFilter;
43 import org.eclipse.jface.viewers.ViewerSorter;
44 import org.eclipse.jface.window.Window;
45 import org.eclipse.swt.SWT;
46 import org.eclipse.swt.events.SelectionEvent;
47 import org.eclipse.swt.events.SelectionListener;
48 import org.eclipse.swt.graphics.Font;
49 import org.eclipse.swt.graphics.GC;
50 import org.eclipse.swt.graphics.Image;
51 import org.eclipse.swt.graphics.Point;
52 import org.eclipse.swt.graphics.Rectangle;
53 import org.eclipse.swt.layout.GridData;
54 import org.eclipse.swt.layout.GridLayout;
55 import org.eclipse.swt.widgets.Canvas;
56 import org.eclipse.swt.widgets.Composite;
57 import org.eclipse.swt.widgets.Event;
58 import org.eclipse.swt.widgets.FileDialog;
59 import org.eclipse.swt.widgets.Listener;
60 import org.eclipse.swt.widgets.Menu;
61 import org.eclipse.swt.widgets.ScrollBar;
62 import org.eclipse.swt.widgets.Shell;
63 import org.eclipse.swt.widgets.Slider;
64 import org.eclipse.swt.widgets.TabFolder;
65 import org.eclipse.swt.widgets.TabItem;
66 import org.eclipse.swt.widgets.Text;
67 import org.eclipse.ui.IActionBars;
68 import org.eclipse.ui.IWorkbenchActionConstants;
69 import org.eclipse.ui.PlatformUI;
70 import org.eclipse.ui.part.ViewPart;
71 
72 import java.io.FileInputStream;
73 import java.io.FileNotFoundException;
74 import java.nio.ByteOrder;
75 
76 /**
77  * This sample class demonstrates how to plug-in a new workbench view. The view
78  * shows data obtained from the model. The sample creates a dummy model on the
79  * fly, but a real implementation would connect to the model available either in
80  * this or another plug-in (e.g. the workspace). The view is connected to the
81  * model using a content provider.
82  * <p>
83  * The view uses a label provider to define how model objects should be
84  * presented in the view. Each view can present the same model objects using
85  * different labels and icons, if needed. Alternatively, a single label provider
86  * can be shared between views in order to ensure that objects of the same type
87  * are presented in the same way everywhere.
88  * <p>
89  */
90 
91 public class SampleView extends ViewPart implements Runnable, SelectionListener {
92     public static final ByteOrder targetByteOrder = ByteOrder.LITTLE_ENDIAN;
93 
94     boolean running = false;
95     Thread thread;
96     MessageQueue messageQueue;
97     SparseArray<DebugContext> debugContexts = new SparseArray<DebugContext>();
98 
99     /** The ID of the view as specified by the extension. */
100     public static final String ID = "glesv2debuggerclient.views.SampleView";
101 
102     TabFolder tabFolder;
103     TabItem tabItemText, tabItemImage, tabItemBreakpointOption;
104     TabItem tabItemShaderEditor, tabContextViewer;
105     ListViewer viewer; // ListViewer / TableViewer
106     Slider frameNum; // scale max cannot overlap min, so max is array size
107     TreeViewer contextViewer;
108     BreakpointOption breakpointOption;
109     ShaderEditor shaderEditor;
110     Canvas canvas;
111     Text text;
112     Action actionConnect; // connect / disconnect
113 
114     Action actionAutoScroll;
115     Action actionFilter;
116     Action actionPort;
117 
118     Action actContext; // for toggling contexts
119     DebugContext current = null;
120 
121     Point origin = new Point(0, 0); // for smooth scrolling canvas
122     String[] filters = null;
123 
124     class ViewContentProvider extends LabelProvider implements IStructuredContentProvider,
125             ITableLabelProvider {
126         Frame frame = null;
127 
inputChanged(Viewer v, Object oldInput, Object newInput)128         public void inputChanged(Viewer v, Object oldInput, Object newInput) {
129             frame = (Frame) newInput;
130         }
131 
132         @Override
dispose()133         public void dispose() {
134         }
135 
getElements(Object parent)136         public Object[] getElements(Object parent) {
137             return frame.get().toArray();
138         }
139 
140         @Override
getText(Object obj)141         public String getText(Object obj) {
142             MessageData msgData = (MessageData) obj;
143             return msgData.text;
144         }
145 
146         @Override
getImage(Object obj)147         public Image getImage(Object obj) {
148             MessageData msgData = (MessageData) obj;
149             return msgData.getImage();
150         }
151 
getColumnText(Object obj, int index)152         public String getColumnText(Object obj, int index) {
153             MessageData msgData = (MessageData) obj;
154             if (index >= msgData.columns.length)
155                 return null;
156             return msgData.columns[index];
157         }
158 
getColumnImage(Object obj, int index)159         public Image getColumnImage(Object obj, int index) {
160             if (index > -1)
161                 return null;
162             MessageData msgData = (MessageData) obj;
163             return msgData.getImage();
164         }
165     }
166 
167     class NameSorter extends ViewerSorter {
168         @Override
compare(Viewer viewer, Object e1, Object e2)169         public int compare(Viewer viewer, Object e1, Object e2) {
170             MessageData m1 = (MessageData) e1;
171             MessageData m2 = (MessageData) e2;
172             return (int) ((m1.msg.getTime() - m2.msg.getTime()) * 100);
173         }
174     }
175 
176     class Filter extends ViewerFilter {
177         @Override
select(Viewer viewer, Object parentElement, Object element)178         public boolean select(Viewer viewer, Object parentElement,
179                 Object element) {
180             MessageData msgData = (MessageData) element;
181             if (null == filters)
182                 return true;
183             for (int i = 0; i < filters.length; i++)
184                 if (msgData.text.contains(filters[i]))
185                     return true;
186             return false;
187         }
188     }
189 
SampleView()190     public SampleView() {
191 
192     }
193 
createLeftPane(Composite parent)194     public void createLeftPane(Composite parent) {
195         Composite composite = new Composite(parent, 0);
196 
197         GridLayout gridLayout = new GridLayout();
198         gridLayout.numColumns = 1;
199         composite.setLayout(gridLayout);
200 
201         frameNum = new Slider(composite, SWT.BORDER | SWT.HORIZONTAL);
202         frameNum.setMinimum(0);
203         frameNum.setMaximum(1);
204         frameNum.setSelection(0);
205         frameNum.addSelectionListener(this);
206 
207         GridData gridData = new GridData();
208         gridData.horizontalAlignment = SWT.FILL;
209         gridData.grabExcessHorizontalSpace = true;
210         gridData.verticalAlignment = SWT.FILL;
211         frameNum.setLayoutData(gridData);
212 
213         // Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL |
214         // SWT.MULTI
215         // | SWT.FULL_SELECTION);
216         // TableLayout layout = new TableLayout();
217         // table.setLayout(layout);
218         // table.setLinesVisible(true);
219         // table.setHeaderVisible(true);
220         // String[] headings = {
221         // "Name", "Elapsed (ms)", "Detail"
222         // };
223         // int[] weights = {
224         // 50, 16, 60
225         // };
226         // int[] widths = {
227         // 180, 90, 200
228         // };
229         // for (int i = 0; i < headings.length; i++) {
230         // layout.addColumnData(new ColumnWeightData(weights[i], widths[i],
231         // true));
232         // TableColumn nameCol = new TableColumn(table, SWT.NONE, i);
233         // nameCol.setText(headings[i]);
234         // }
235 
236         // viewer = new TableViewer(table);
237         viewer = new ListViewer(composite, SWT.DEFAULT);
238         viewer.getList().setFont(new Font(viewer.getList().getDisplay(),
239                 "Courier", 10, SWT.BOLD));
240         ViewContentProvider contentProvider = new ViewContentProvider();
241         viewer.setContentProvider(contentProvider);
242         viewer.setLabelProvider(contentProvider);
243         // viewer.setSorter(new NameSorter());
244         viewer.setFilters(new ViewerFilter[] {
245                 new Filter()
246         });
247 
248         gridData = new GridData();
249         gridData.horizontalAlignment = SWT.FILL;
250         gridData.grabExcessHorizontalSpace = true;
251         gridData.verticalAlignment = SWT.FILL;
252         gridData.grabExcessVerticalSpace = true;
253         viewer.getControl().setLayoutData(gridData);
254     }
255 
256     /**
257      * This is a callback that will allow us to create the viewer and initialize
258      * it.
259      */
260     @Override
createPartControl(Composite parent)261     public void createPartControl(Composite parent) {
262         createLeftPane(parent);
263 
264         // Create the help context id for the viewer's control
265         PlatformUI.getWorkbench().getHelpSystem()
266                 .setHelp(viewer.getControl(), "GLESv2DebuggerClient.viewer");
267 
268         tabFolder = new TabFolder(parent, SWT.BORDER);
269 
270         text = new Text(tabFolder, SWT.NO_BACKGROUND | SWT.READ_ONLY
271                 | SWT.V_SCROLL | SWT.H_SCROLL);
272 
273         tabItemText = new TabItem(tabFolder, SWT.NONE);
274         tabItemText.setText("Text");
275         tabItemText.setControl(text);
276 
277         canvas = new Canvas(tabFolder, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE
278                 | SWT.V_SCROLL | SWT.H_SCROLL);
279         tabItemImage = new TabItem(tabFolder, SWT.NONE);
280         tabItemImage.setText("Image");
281         tabItemImage.setControl(canvas);
282 
283         breakpointOption = new BreakpointOption(this, tabFolder);
284         tabItemBreakpointOption = new TabItem(tabFolder, SWT.NONE);
285         tabItemBreakpointOption.setText("Breakpoint Option");
286         tabItemBreakpointOption.setControl(breakpointOption);
287 
288         shaderEditor = new ShaderEditor(this, tabFolder);
289         tabItemShaderEditor = new TabItem(tabFolder, SWT.NONE);
290         tabItemShaderEditor.setText("Shader Editor");
291         tabItemShaderEditor.setControl(shaderEditor);
292 
293         contextViewer = new TreeViewer(tabFolder);
294         ContextViewProvider contextViewProvider = new ContextViewProvider(this);
295         contextViewer.addSelectionChangedListener(contextViewProvider);
296         contextViewer.setContentProvider(contextViewProvider);
297         contextViewer.setLabelProvider(contextViewProvider);
298         tabContextViewer = new TabItem(tabFolder, SWT.NONE);
299         tabContextViewer.setText("Context Viewer");
300         tabContextViewer.setControl(contextViewer.getTree());
301 
302         final ScrollBar hBar = canvas.getHorizontalBar();
303         hBar.addListener(SWT.Selection, new Listener() {
304             public void handleEvent(Event e) {
305                 if (null == canvas.getBackgroundImage())
306                     return;
307                 Image image = canvas.getBackgroundImage();
308                 int hSelection = hBar.getSelection();
309                 int destX = -hSelection - origin.x;
310                 Rectangle rect = image.getBounds();
311                 canvas.scroll(destX, 0, 0, 0, rect.width, rect.height, false);
312                 origin.x = -hSelection;
313             }
314         });
315         final ScrollBar vBar = canvas.getVerticalBar();
316         vBar.addListener(SWT.Selection, new Listener() {
317             public void handleEvent(Event e) {
318                 if (null == canvas.getBackgroundImage())
319                     return;
320                 Image image = canvas.getBackgroundImage();
321                 int vSelection = vBar.getSelection();
322                 int destY = -vSelection - origin.y;
323                 Rectangle rect = image.getBounds();
324                 canvas.scroll(0, destY, 0, 0, rect.width, rect.height, false);
325                 origin.y = -vSelection;
326             }
327         });
328         canvas.addListener(SWT.Resize, new Listener() {
329             public void handleEvent(Event e) {
330                 if (null == canvas.getBackgroundImage())
331                     return;
332                 Image image = canvas.getBackgroundImage();
333                 Rectangle rect = image.getBounds();
334                 Rectangle client = canvas.getClientArea();
335                 hBar.setMaximum(rect.width);
336                 vBar.setMaximum(rect.height);
337                 hBar.setThumb(Math.min(rect.width, client.width));
338                 vBar.setThumb(Math.min(rect.height, client.height));
339                 int hPage = rect.width - client.width;
340                 int vPage = rect.height - client.height;
341                 int hSelection = hBar.getSelection();
342                 int vSelection = vBar.getSelection();
343                 if (hSelection >= hPage) {
344                     if (hPage <= 0)
345                         hSelection = 0;
346                     origin.x = -hSelection;
347                 }
348                 if (vSelection >= vPage) {
349                     if (vPage <= 0)
350                         vSelection = 0;
351                     origin.y = -vSelection;
352                 }
353                 canvas.redraw();
354             }
355         });
356         canvas.addListener(SWT.Paint, new Listener() {
357             public void handleEvent(Event e) {
358                 if (null == canvas.getBackgroundImage())
359                     return;
360                 Image image = canvas.getBackgroundImage();
361                 GC gc = e.gc;
362                 gc.drawImage(image, origin.x, origin.y);
363                 Rectangle rect = image.getBounds();
364                 Rectangle client = canvas.getClientArea();
365                 int marginWidth = client.width - rect.width;
366                 if (marginWidth > 0) {
367                     gc.fillRectangle(rect.width, 0, marginWidth, client.height);
368                 }
369                 int marginHeight = client.height - rect.height;
370                 if (marginHeight > 0) {
371                     gc.fillRectangle(0, rect.height, client.width, marginHeight);
372                 }
373             }
374         });
375 
376         hookContextMenu();
377         hookSelectionChanged();
378         contributeToActionBars();
379 
380         messageQueue = new MessageQueue(this, new ProcessMessage[] {
381                 breakpointOption, shaderEditor
382         });
383     }
384 
hookContextMenu()385     private void hookContextMenu() {
386         MenuManager menuMgr = new MenuManager("#PopupMenu");
387         menuMgr.setRemoveAllWhenShown(true);
388         menuMgr.addMenuListener(new IMenuListener() {
389             public void menuAboutToShow(IMenuManager manager) {
390                 SampleView.this.fillContextMenu(manager);
391             }
392         });
393         Menu menu = menuMgr.createContextMenu(viewer.getControl());
394         viewer.getControl().setMenu(menu);
395         getSite().registerContextMenu(menuMgr, viewer);
396     }
397 
contributeToActionBars()398     private void contributeToActionBars() {
399         IActionBars bars = getViewSite().getActionBars();
400         fillLocalPullDown(bars.getMenuManager());
401         fillLocalToolBar(bars.getToolBarManager());
402     }
403 
fillLocalPullDown(IMenuManager manager)404     private void fillLocalPullDown(IMenuManager manager) {
405         // manager.add(actionConnect);
406         // manager.add(new Separator());
407         // manager.add(actionDisconnect);
408     }
409 
fillContextMenu(IMenuManager manager)410     private void fillContextMenu(IMenuManager manager) {
411         // manager.add(actionConnect);
412         // manager.add(actionDisconnect);
413         // Other plug-ins can contribute there actions here
414         manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
415     }
416 
fillLocalToolBar(final IToolBarManager manager)417     private void fillLocalToolBar(final IToolBarManager manager) {
418         actionConnect = new Action("Connect", Action.AS_PUSH_BUTTON) {
419             @Override
420             public void run() {
421                 if (!running)
422                     changeContext(null); // viewer will switch to newest context
423                 connectDisconnect();
424             }
425         };
426         manager.add(actionConnect);
427 
428         manager.add(new Action("Open File", Action.AS_PUSH_BUTTON)
429         {
430             @Override
431             public void run()
432             {
433                 if (!running)
434                 {
435                     changeContext(null); // viewer will switch to newest context
436                     openFile();
437                 }
438             }
439         });
440 
441         final Shell shell = this.getViewSite().getShell();
442         actionAutoScroll = new Action("Auto Scroll", Action.AS_CHECK_BOX) {
443             @Override
444             public void run() {
445             }
446         };
447         actionAutoScroll.setChecked(true);
448         manager.add(actionAutoScroll);
449 
450         actionFilter = new Action("*", Action.AS_DROP_DOWN_MENU) {
451             @Override
452             public void run() {
453                 org.eclipse.jface.dialogs.InputDialog dialog = new org.eclipse.jface.dialogs.InputDialog(
454                         shell, "Contains Filter",
455                         "case sensitive substring or *",
456                         actionFilter.getText(), null);
457                 if (Window.OK == dialog.open()) {
458                     actionFilter.setText(dialog.getValue());
459                     manager.update(true);
460                     filters = dialog.getValue().split("\\|");
461                     if (filters.length == 1 && filters[0].equals("*"))
462                         filters = null;
463                     viewer.refresh();
464                 }
465 
466             }
467         };
468         manager.add(actionFilter);
469 
470         manager.add(new Action("CaptureDraw", Action.AS_DROP_DOWN_MENU)
471         {
472             @Override
473             public void run()
474             {
475                 int contextId = 0;
476                 if (current != null)
477                     contextId = current.contextId;
478                 InputDialog inputDialog = new InputDialog(shell,
479                         "Capture glDrawArrays/Elements",
480                         "Enter number of glDrawArrays/Elements to glReadPixels for "
481                                 + "context 0x" + Integer.toHexString(contextId) +
482                                 "\n(0x0 is any context)", "9001", null);
483                 if (inputDialog.open() != Window.OK)
484                     return;
485                 Message.Builder builder = Message.newBuilder();
486                 builder.setContextId(contextId);
487                 builder.setType(Type.Response);
488                 builder.setExpectResponse(false);
489                 builder.setFunction(Function.SETPROP);
490                 builder.setProp(Prop.CaptureDraw);
491                 builder.setArg0(Integer.parseInt(inputDialog.getValue()));
492                 messageQueue.addCommand(builder.build());
493             }
494         });
495 
496         manager.add(new Action("CaptureSwap", Action.AS_DROP_DOWN_MENU)
497         {
498             @Override
499             public void run()
500             {
501                 int contextId = 0;
502                 if (current != null)
503                     contextId = current.contextId;
504                 InputDialog inputDialog = new InputDialog(shell,
505                         "Capture eglSwapBuffers",
506                         "Enter number of eglSwapBuffers to glReadPixels for "
507                                 + "context 0x" + Integer.toHexString(contextId) +
508                                 "\n(0x0 is any context)", "9001", null);
509                 if (inputDialog.open() != Window.OK)
510                     return;
511                 Message.Builder builder = Message.newBuilder();
512                 builder.setContextId(contextId);
513                 builder.setType(Type.Response);
514                 builder.setExpectResponse(false);
515                 builder.setFunction(Function.SETPROP);
516                 builder.setProp(Prop.CaptureSwap);
517                 builder.setArg0(Integer.parseInt(inputDialog.getValue()));
518                 messageQueue.addCommand(builder.build());
519             }
520         });
521 
522         manager.add(new Action("SYSTEM_TIME_THREAD", Action.AS_DROP_DOWN_MENU)
523         {
524             @Override
525             public void run()
526             {
527                 final String[] timeModes = {
528                         "SYSTEM_TIME_REALTIME", "SYSTEM_TIME_MONOTONIC", "SYSTEM_TIME_PROCESS",
529                         "SYSTEM_TIME_THREAD"
530                 };
531                 int i = java.util.Arrays.asList(timeModes).indexOf(this.getText());
532                 i = (i + 1) % timeModes.length;
533                 Message.Builder builder = Message.newBuilder();
534                 builder.setContextId(0); // FIXME: proper context id
535                 builder.setType(Type.Response);
536                 builder.setExpectResponse(false);
537                 builder.setFunction(Message.Function.SETPROP);
538                 builder.setProp(Prop.TimeMode);
539                 builder.setArg0(i);
540                 messageQueue.addCommand(builder.build());
541                 this.setText(timeModes[i]);
542                 manager.update(true);
543             }
544         });
545 
546         actContext = new Action("Context: 0x", Action.AS_DROP_DOWN_MENU) {
547             @Override
548             public void run() {
549                 if (debugContexts.size() < 2)
550                     return;
551                 final String idStr = this.getText().substring(
552                                           "Context: 0x".length());
553                 if (idStr.length() == 0)
554                     return;
555                 final int contextId = Integer.parseInt(idStr, 16);
556                 int index = debugContexts.indexOfKey(contextId);
557                 index = (index + 1) % debugContexts.size();
558                 changeContext(debugContexts.valueAt(index));
559             }
560         };
561         manager.add(actContext);
562 
563         actionPort = new Action("5039", Action.AS_DROP_DOWN_MENU)
564         {
565             @Override
566             public void run() {
567                 InputDialog dialog = new InputDialog(shell, "Port", "Debugger port",
568                         actionPort.getText(), null);
569                 if (Window.OK == dialog.open()) {
570                     actionPort.setText(dialog.getValue());
571                     manager.update(true);
572                 }
573             }
574         };
575         manager.add(actionPort);
576 
577         manager.add(new Action("CodeGen Frame", Action.AS_PUSH_BUTTON)
578         {
579             @Override
580             public void run()
581             {
582                 if (current != null)
583                 {
584                     new CodeGen().codeGenFrame((Frame) viewer.getInput());
585                     // need to reload current frame
586                     viewer.setInput(current.getFrame(frameNum.getSelection()));
587                 }
588             }
589         });
590 
591         manager.add(new Action("CodeGen Frames", Action.AS_PUSH_BUTTON)
592         {
593             @Override
594             public void run()
595             {
596                 if (current != null)
597                 {
598                     new CodeGen().codeGenFrames(current, frameNum.getSelection() + 1,
599                             getSite().getShell());
600                     // need to reload current frame
601                     viewer.setInput(current.getFrame(frameNum.getSelection()));
602                 }
603             }
604         });
605     }
606 
openFile()607     private void openFile() {
608         FileDialog dialog = new FileDialog(getSite().getShell(), SWT.OPEN);
609         dialog.setText("Open");
610         dialog.setFilterExtensions(new String[] {
611                 "*.gles2dbg"
612         });
613         String filePath = dialog.open();
614         if (filePath == null)
615             return;
616         FileInputStream file = null;
617         try {
618             file = new FileInputStream(filePath);
619         } catch (FileNotFoundException e) {
620             e.printStackTrace();
621             return;
622         }
623         running = true;
624         messageQueue.start(targetByteOrder, file);
625         thread = new Thread(this);
626         thread.start();
627         actionConnect.setText("Disconnect");
628         getViewSite().getActionBars().getToolBarManager().update(true);
629     }
630 
connectDisconnect()631     private void connectDisconnect() {
632         if (!running) {
633             running = true;
634             messageQueue.start(targetByteOrder, null);
635             thread = new Thread(this);
636             thread.start();
637             actionConnect.setText("Disconnect");
638         } else {
639             running = false;
640             messageQueue.stop();
641             actionConnect.setText("Connect");
642         }
643         this.getSite().getShell().getDisplay().syncExec(new Runnable() {
644             public void run() {
645                 getViewSite().getActionBars().getToolBarManager().update(true);
646             }
647         });
648     }
649 
messageDataSelected(final MessageData msgData)650     void messageDataSelected(final MessageData msgData) {
651         if (null == msgData)
652             return;
653         if (frameNum.getSelection() == frameNum.getMaximum())
654             return; // scale max cannot overlap min, so max is array size
655         final Frame frame = current.getFrame(frameNum.getSelection());
656         final Context context = frame.computeContext(msgData);
657         contextViewer.setInput(context);
658         if (msgData.getImage() != null) {
659             canvas.setBackgroundImage(msgData.getImage());
660             tabFolder.setSelection(tabItemImage);
661             canvas.redraw();
662         } else if (null != msgData.shader) {
663             text.setText(msgData.shader);
664             tabFolder.setSelection(tabItemText);
665         } else if (null != msgData.attribs) {
666             StringBuilder builder = new StringBuilder();
667             final int maxAttrib = msgData.msg.getArg7();
668             for (int i = 0; i < msgData.attribs[0].length / 4; i++) {
669                 if (msgData.indices != null) {
670                     builder.append(msgData.indices[i] & 0xffff);
671                     builder.append(": ");
672                 }
673                 for (int j = 0; j < maxAttrib; j++) {
674                     for (int k = 0; k < 4; k++)
675                         builder.append(String.format("%.3g ", msgData.attribs[j][i * 4 + k]));
676                     if (j < maxAttrib - 1)
677                         builder.append("|| ");
678                 }
679                 builder.append('\n');
680             }
681             text.setText(builder.toString());
682             tabFolder.setSelection(tabItemText);
683         }
684     }
685 
hookSelectionChanged()686     private void hookSelectionChanged() {
687         viewer.addSelectionChangedListener(new ISelectionChangedListener() {
688             public void selectionChanged(SelectionChangedEvent event) {
689                 StructuredSelection selection = (StructuredSelection) event
690                         .getSelection();
691                 if (null == selection)
692                     return;
693                 MessageData msgData = (MessageData) selection.getFirstElement();
694                 messageDataSelected(msgData);
695             }
696         });
697     }
698 
showError(final Exception e)699     public void showError(final Exception e) {
700         viewer.getControl().getDisplay().syncExec(new Runnable() {
701             public void run() {
702                 MessageDialog.openError(viewer.getControl().getShell(),
703                         "GL ES 2.0 Debugger Client", e.getMessage());
704             }
705         });
706     }
707 
708     /**
709      * Passing the focus request to the viewer's control.
710      */
711     @Override
setFocus()712     public void setFocus() {
713         viewer.getControl().setFocus();
714     }
715 
run()716     public void run() {
717         int newMessages = 0;
718 
719         boolean shaderEditorUpdate = false;
720         while (running) {
721             final Message oriMsg = messageQueue.removeCompleteMessage(0);
722             if (oriMsg == null && !messageQueue.isRunning())
723                 break;
724             if (newMessages > 60 || (newMessages > 0 && null == oriMsg)) {
725                 newMessages = 0;
726                 if (current != null && current.uiUpdate)
727                     getSite().getShell().getDisplay().syncExec(new Runnable() {
728                         public void run() {
729                             if (frameNum.getSelection() == current.frameCount() - 1 ||
730                                     frameNum.getSelection() == current.frameCount() - 2)
731                             {
732                                 viewer.refresh(false);
733                                 if (actionAutoScroll.isChecked())
734                                     viewer.getList().setSelection(
735                                             viewer.getList().getItemCount() - 1);
736                             }
737                             frameNum.setMaximum(current.frameCount());
738                         }
739                     });
740                 current.uiUpdate = false;
741 
742                 if (shaderEditorUpdate)
743                     this.getSite().getShell().getDisplay().syncExec(new Runnable() {
744                         public void run() {
745                             shaderEditor.updateUI();
746                         }
747                     });
748                 shaderEditorUpdate = false;
749             }
750             if (null == oriMsg) {
751                 try {
752                     Thread.sleep(1);
753                     continue;
754                 } catch (InterruptedException e) {
755                     showError(e);
756                 }
757             }
758             DebugContext debugContext = debugContexts.get(oriMsg.getContextId());
759             if (debugContext == null) {
760                 debugContext = new DebugContext(oriMsg.getContextId());
761                 debugContexts.put(oriMsg.getContextId(), debugContext);
762             }
763             debugContext.processMessage(oriMsg);
764             shaderEditorUpdate |= debugContext.currentContext.serverShader.uiUpdate;
765             debugContext.currentContext.serverShader.uiUpdate = false;
766             if (current == null && debugContext.frameCount() > 0)
767                 changeContext(debugContext);
768             newMessages++;
769         }
770         if (running)
771             connectDisconnect(); // error occurred, disconnect
772     }
773 
774     /** can be called from non-UI thread */
changeContext(final DebugContext newContext)775     void changeContext(final DebugContext newContext) {
776         getSite().getShell().getDisplay().syncExec(new Runnable() {
777             public void run() {
778                 current = newContext;
779                 if (current != null)
780                 {
781                     frameNum.setMaximum(current.frameCount());
782                     if (frameNum.getSelection() >= current.frameCount())
783                         if (current.frameCount() > 0)
784                             frameNum.setSelection(current.frameCount() - 1);
785                         else
786                             frameNum.setSelection(0);
787                     viewer.setInput(current.getFrame(frameNum.getSelection()));
788                     actContext.setText("Context: 0x" + Integer.toHexString(current.contextId));
789                 }
790                 else
791                 {
792                     frameNum.setMaximum(1); // cannot overlap min
793                     frameNum.setSelection(0);
794                     viewer.setInput(null);
795                     actContext.setText("Context: 0x");
796                 }
797                 shaderEditor.updateUI();
798                 getViewSite().getActionBars().getToolBarManager().update(true);
799             }
800         });
801     }
802 
widgetSelected(SelectionEvent e)803     public void widgetSelected(SelectionEvent e) {
804         if (e.widget != frameNum)
805             assert false;
806         if (current == null)
807             return;
808         if (frameNum.getSelection() == current.frameCount())
809             return; // scale maximum cannot overlap minimum
810         Frame frame = current.getFrame(frameNum.getSelection());
811         viewer.setInput(frame);
812     }
813 
widgetDefaultSelected(SelectionEvent e)814     public void widgetDefaultSelected(SelectionEvent e) {
815         widgetSelected(e);
816     }
817 }
818