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.LabelProvider; 36 import org.eclipse.jface.viewers.ListViewer; 37 import org.eclipse.jface.viewers.SelectionChangedEvent; 38 import org.eclipse.jface.viewers.StructuredSelection; 39 import org.eclipse.jface.viewers.TreeViewer; 40 import org.eclipse.jface.viewers.Viewer; 41 import org.eclipse.jface.viewers.ViewerFilter; 42 import org.eclipse.jface.window.Window; 43 import org.eclipse.swt.SWT; 44 import org.eclipse.swt.events.SelectionAdapter; 45 import org.eclipse.swt.events.SelectionEvent; 46 import org.eclipse.swt.graphics.Font; 47 import org.eclipse.swt.graphics.GC; 48 import org.eclipse.swt.graphics.Image; 49 import org.eclipse.swt.graphics.Point; 50 import org.eclipse.swt.graphics.Rectangle; 51 import org.eclipse.swt.layout.GridData; 52 import org.eclipse.swt.layout.GridLayout; 53 import org.eclipse.swt.widgets.Canvas; 54 import org.eclipse.swt.widgets.Composite; 55 import org.eclipse.swt.widgets.Event; 56 import org.eclipse.swt.widgets.FileDialog; 57 import org.eclipse.swt.widgets.Label; 58 import org.eclipse.swt.widgets.Listener; 59 import org.eclipse.swt.widgets.Menu; 60 import org.eclipse.swt.widgets.Scale; 61 import org.eclipse.swt.widgets.ScrollBar; 62 import org.eclipse.swt.widgets.Shell; 63 import org.eclipse.swt.widgets.Spinner; 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.part.ViewPart; 70 71 import java.io.FileInputStream; 72 import java.io.FileNotFoundException; 73 import java.nio.ByteOrder; 74 75 public class GLFramesView extends ViewPart implements Runnable { 76 public static final ByteOrder TARGET_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; 77 78 private boolean mRunning = false; 79 private Thread mThread; 80 81 MessageQueue messageQueue; 82 SparseArray<DebugContext> debugContexts = new SparseArray<DebugContext>(); 83 84 TabFolder tabFolder; 85 TabItem tabItemText, tabItemImage, tabItemBreakpointOption; 86 TabItem tabItemShaderEditor, tabContextViewer; 87 88 private ListViewer mViewer; // ListViewer / TableViewer 89 private Scale mFrameScale; // scale max cannot overlap min, so max is array size 90 private Spinner mFrameNumberspinner; 91 private TreeViewer mContextViewer; 92 private BreakpointOption mBreakpointOption; 93 private ShaderEditor mShaderEditor; 94 Canvas canvas; 95 private Text mText; 96 private Action mActionConnect; // connect / disconnect 97 98 private Action mActionAutoScroll; 99 private Action mActionFilter; 100 Action actionPort; 101 102 private Action mActionContext; // for toggling contexts 103 DebugContext current = null; 104 105 private Point mOrigin = new Point(0, 0); // for smooth scrolling canvas 106 private String[] mTextFilters = null; 107 108 private static class ViewContentProvider extends LabelProvider implements IStructuredContentProvider { 109 private Frame mFrame = null; 110 111 @Override inputChanged(Viewer v, Object oldInput, Object newInput)112 public void inputChanged(Viewer v, Object oldInput, Object newInput) { 113 mFrame = (Frame) newInput; 114 } 115 116 @Override dispose()117 public void dispose() { 118 } 119 120 @Override getElements(Object parent)121 public Object[] getElements(Object parent) { 122 return mFrame.get().toArray(); 123 } 124 125 @Override getText(Object obj)126 public String getText(Object obj) { 127 MessageData msgData = (MessageData) obj; 128 return msgData.text; 129 } 130 131 @Override getImage(Object obj)132 public Image getImage(Object obj) { 133 MessageData msgData = (MessageData) obj; 134 return msgData.getImage(); 135 } 136 } 137 138 private class Filter extends ViewerFilter { 139 @Override select(Viewer viewer, Object parentElement, Object element)140 public boolean select(Viewer viewer, Object parentElement, 141 Object element) { 142 MessageData msgData = (MessageData) element; 143 if (null == mTextFilters) 144 return true; 145 for (int i = 0; i < mTextFilters.length; i++) 146 if (msgData.text.contains(mTextFilters[i])) 147 return true; 148 return false; 149 } 150 } 151 createLeftPane(Composite parent)152 private void createLeftPane(Composite parent) { 153 Composite composite = new Composite(parent, 0); 154 155 GridLayout gridLayout = new GridLayout(); 156 gridLayout.numColumns = 3; 157 composite.setLayout(gridLayout); 158 composite.setLayoutData(new GridData(GridData.FILL_BOTH)); 159 160 // Frame: -------|slider|--------- [ Spinner ] 161 Label l = new Label(composite, SWT.NONE); 162 l.setText("Frame:"); 163 164 mFrameScale = new Scale(composite, SWT.BORDER | SWT.HORIZONTAL); 165 mFrameScale.setMinimum(0); 166 mFrameScale.setMaximum(1); 167 mFrameScale.setSelection(0); 168 mFrameScale.addSelectionListener(new SelectionAdapter() { 169 @Override 170 public void widgetSelected(SelectionEvent e) { 171 if (current == null) { 172 return; 173 } 174 int selectedFrame = mFrameScale.getSelection(); 175 mFrameNumberspinner.setSelection(selectedFrame); 176 selectFrame(selectedFrame); 177 } 178 }); 179 180 GridData gridData = new GridData(GridData.FILL_HORIZONTAL); 181 mFrameScale.setLayoutData(gridData); 182 183 mFrameNumberspinner = new Spinner(composite, SWT.BORDER); 184 mFrameNumberspinner.setMinimum(0); 185 mFrameNumberspinner.setMaximum(1); 186 mFrameNumberspinner.setSelection(0); 187 mFrameNumberspinner.addSelectionListener(new SelectionAdapter() { 188 @Override 189 public void widgetSelected(SelectionEvent e) { 190 if (current == null) { 191 return; 192 } 193 int selectedFrame = mFrameNumberspinner.getSelection(); 194 mFrameScale.setSelection(selectedFrame); 195 selectFrame(selectedFrame); 196 } 197 }); 198 199 mViewer = new ListViewer(composite, SWT.DEFAULT); 200 mViewer.getList().setFont(new Font(mViewer.getList().getDisplay(), 201 "Courier", 10, SWT.BOLD)); 202 ViewContentProvider contentProvider = new ViewContentProvider(); 203 mViewer.setContentProvider(contentProvider); 204 mViewer.setLabelProvider(contentProvider); 205 mViewer.setFilters(new ViewerFilter[] { 206 new Filter() 207 }); 208 209 gridData = new GridData(GridData.FILL_BOTH); 210 gridData.horizontalSpan = 3; 211 mViewer.getControl().setLayoutData(gridData); 212 } 213 selectFrame(int frameNumber)214 private void selectFrame(int frameNumber) { 215 if (frameNumber == current.frameCount()) { 216 return; // scale maximum cannot overlap minimum 217 } 218 219 Frame frame = current.getFrame(frameNumber); 220 mViewer.setInput(frame); 221 } 222 223 @Override createPartControl(Composite parent)224 public void createPartControl(Composite parent) { 225 createLeftPane(parent); 226 227 tabFolder = new TabFolder(parent, SWT.BORDER); 228 229 mText = new Text(tabFolder, SWT.NO_BACKGROUND | SWT.READ_ONLY 230 | SWT.V_SCROLL | SWT.H_SCROLL); 231 232 tabItemText = new TabItem(tabFolder, SWT.NONE); 233 tabItemText.setText("Text"); 234 tabItemText.setControl(mText); 235 236 canvas = new Canvas(tabFolder, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE 237 | SWT.V_SCROLL | SWT.H_SCROLL); 238 tabItemImage = new TabItem(tabFolder, SWT.NONE); 239 tabItemImage.setText("Image"); 240 tabItemImage.setControl(canvas); 241 242 mBreakpointOption = new BreakpointOption(this, tabFolder); 243 tabItemBreakpointOption = new TabItem(tabFolder, SWT.NONE); 244 tabItemBreakpointOption.setText("Breakpoint Option"); 245 tabItemBreakpointOption.setControl(mBreakpointOption); 246 247 mShaderEditor = new ShaderEditor(this, tabFolder); 248 tabItemShaderEditor = new TabItem(tabFolder, SWT.NONE); 249 tabItemShaderEditor.setText("Shader Editor"); 250 tabItemShaderEditor.setControl(mShaderEditor); 251 252 mContextViewer = new TreeViewer(tabFolder); 253 ContextViewProvider contextViewProvider = new ContextViewProvider(this); 254 mContextViewer.addSelectionChangedListener(contextViewProvider); 255 mContextViewer.setContentProvider(contextViewProvider); 256 mContextViewer.setLabelProvider(contextViewProvider); 257 tabContextViewer = new TabItem(tabFolder, SWT.NONE); 258 tabContextViewer.setText("Context Viewer"); 259 tabContextViewer.setControl(mContextViewer.getTree()); 260 261 final ScrollBar hBar = canvas.getHorizontalBar(); 262 hBar.addListener(SWT.Selection, new Listener() { 263 @Override 264 public void handleEvent(Event e) { 265 if (null == canvas.getBackgroundImage()) 266 return; 267 Image image = canvas.getBackgroundImage(); 268 int hSelection = hBar.getSelection(); 269 int destX = -hSelection - mOrigin.x; 270 Rectangle rect = image.getBounds(); 271 canvas.scroll(destX, 0, 0, 0, rect.width, rect.height, false); 272 mOrigin.x = -hSelection; 273 } 274 }); 275 final ScrollBar vBar = canvas.getVerticalBar(); 276 vBar.addListener(SWT.Selection, new Listener() { 277 @Override 278 public void handleEvent(Event e) { 279 if (null == canvas.getBackgroundImage()) 280 return; 281 Image image = canvas.getBackgroundImage(); 282 int vSelection = vBar.getSelection(); 283 int destY = -vSelection - mOrigin.y; 284 Rectangle rect = image.getBounds(); 285 canvas.scroll(0, destY, 0, 0, rect.width, rect.height, false); 286 mOrigin.y = -vSelection; 287 } 288 }); 289 canvas.addListener(SWT.Resize, new Listener() { 290 @Override 291 public void handleEvent(Event e) { 292 if (null == canvas.getBackgroundImage()) 293 return; 294 Image image = canvas.getBackgroundImage(); 295 Rectangle rect = image.getBounds(); 296 Rectangle client = canvas.getClientArea(); 297 hBar.setMaximum(rect.width); 298 vBar.setMaximum(rect.height); 299 hBar.setThumb(Math.min(rect.width, client.width)); 300 vBar.setThumb(Math.min(rect.height, client.height)); 301 int hPage = rect.width - client.width; 302 int vPage = rect.height - client.height; 303 int hSelection = hBar.getSelection(); 304 int vSelection = vBar.getSelection(); 305 if (hSelection >= hPage) { 306 if (hPage <= 0) 307 hSelection = 0; 308 mOrigin.x = -hSelection; 309 } 310 if (vSelection >= vPage) { 311 if (vPage <= 0) 312 vSelection = 0; 313 mOrigin.y = -vSelection; 314 } 315 canvas.redraw(); 316 } 317 }); 318 canvas.addListener(SWT.Paint, new Listener() { 319 @Override 320 public void handleEvent(Event e) { 321 if (null == canvas.getBackgroundImage()) 322 return; 323 Image image = canvas.getBackgroundImage(); 324 GC gc = e.gc; 325 gc.drawImage(image, mOrigin.x, mOrigin.y); 326 Rectangle rect = image.getBounds(); 327 Rectangle client = canvas.getClientArea(); 328 int marginWidth = client.width - rect.width; 329 if (marginWidth > 0) { 330 gc.fillRectangle(rect.width, 0, marginWidth, client.height); 331 } 332 int marginHeight = client.height - rect.height; 333 if (marginHeight > 0) { 334 gc.fillRectangle(0, rect.height, client.width, marginHeight); 335 } 336 } 337 }); 338 339 hookContextMenu(); 340 hookSelectionChanged(); 341 contributeToActionBars(); 342 343 messageQueue = new MessageQueue(this, new ProcessMessage[] { 344 mBreakpointOption, mShaderEditor 345 }); 346 } 347 hookContextMenu()348 private void hookContextMenu() { 349 MenuManager menuMgr = new MenuManager("#PopupMenu"); 350 menuMgr.setRemoveAllWhenShown(true); 351 menuMgr.addMenuListener(new IMenuListener() { 352 @Override 353 public void menuAboutToShow(IMenuManager manager) { 354 GLFramesView.this.fillContextMenu(manager); 355 } 356 }); 357 Menu menu = menuMgr.createContextMenu(mViewer.getControl()); 358 mViewer.getControl().setMenu(menu); 359 getSite().registerContextMenu(menuMgr, mViewer); 360 } 361 contributeToActionBars()362 private void contributeToActionBars() { 363 IActionBars bars = getViewSite().getActionBars(); 364 fillLocalToolBar(bars.getToolBarManager()); 365 } 366 fillContextMenu(IMenuManager manager)367 private void fillContextMenu(IMenuManager manager) { 368 // Other plug-ins can contribute there actions here 369 manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); 370 } 371 fillLocalToolBar(final IToolBarManager manager)372 private void fillLocalToolBar(final IToolBarManager manager) { 373 mActionConnect = new Action("Connect", Action.AS_PUSH_BUTTON) { 374 @Override 375 public void run() { 376 if (!mRunning) 377 changeContext(null); // viewer will switch to newest context 378 connectDisconnect(); 379 } 380 }; 381 manager.add(mActionConnect); 382 383 manager.add(new Action("Open File", Action.AS_PUSH_BUTTON) { 384 @Override 385 public void run() { 386 if (!mRunning) { 387 changeContext(null); // viewer will switch to newest context 388 openFile(); 389 } 390 } 391 }); 392 393 final Shell shell = this.getViewSite().getShell(); 394 mActionAutoScroll = new Action("Auto Scroll", Action.AS_CHECK_BOX) { 395 @Override 396 public void run() { 397 } 398 }; 399 mActionAutoScroll.setChecked(true); 400 manager.add(mActionAutoScroll); 401 402 mActionFilter = new Action("*", Action.AS_DROP_DOWN_MENU) { 403 @Override 404 public void run() { 405 InputDialog dialog = new InputDialog( 406 shell, "Contains Filter", 407 "case sensitive substring or *", 408 mActionFilter.getText(), null); 409 if (Window.OK == dialog.open()) { 410 mActionFilter.setText(dialog.getValue()); 411 manager.update(true); 412 mTextFilters = dialog.getValue().split("\\|"); 413 if (mTextFilters.length == 1 && mTextFilters[0].equals("*")) 414 mTextFilters = null; 415 mViewer.refresh(); 416 } 417 418 } 419 }; 420 manager.add(mActionFilter); 421 422 manager.add(new Action("CaptureDraw", Action.AS_DROP_DOWN_MENU) { 423 @Override 424 public void run() { 425 int contextId = 0; 426 if (current != null) 427 contextId = current.contextId; 428 InputDialog inputDialog = new InputDialog(shell, 429 "Capture glDrawArrays/Elements", 430 "Enter number of glDrawArrays/Elements to glReadPixels for " 431 + "context 0x" + Integer.toHexString(contextId) + 432 "\n(0x0 is any context)", "9001", null); 433 if (inputDialog.open() != Window.OK) 434 return; 435 Message.Builder builder = Message.newBuilder(); 436 builder.setContextId(contextId); 437 builder.setType(Type.Response); 438 builder.setExpectResponse(false); 439 builder.setFunction(Function.SETPROP); 440 builder.setProp(Prop.CaptureDraw); 441 builder.setArg0(Integer.parseInt(inputDialog.getValue())); 442 messageQueue.addCommand(builder.build()); 443 } 444 }); 445 446 manager.add(new Action("CaptureSwap", Action.AS_DROP_DOWN_MENU) { 447 @Override 448 public void run() { 449 int contextId = 0; 450 if (current != null) 451 contextId = current.contextId; 452 InputDialog inputDialog = new InputDialog(shell, 453 "Capture eglSwapBuffers", 454 "Enter number of eglSwapBuffers to glReadPixels for " 455 + "context 0x" + Integer.toHexString(contextId) + 456 "\n(0x0 is any context)", "9001", null); 457 if (inputDialog.open() != Window.OK) 458 return; 459 Message.Builder builder = Message.newBuilder(); 460 builder.setContextId(contextId); 461 builder.setType(Type.Response); 462 builder.setExpectResponse(false); 463 builder.setFunction(Function.SETPROP); 464 builder.setProp(Prop.CaptureSwap); 465 builder.setArg0(Integer.parseInt(inputDialog.getValue())); 466 messageQueue.addCommand(builder.build()); 467 } 468 }); 469 470 manager.add(new Action("SYSTEM_TIME_THREAD", Action.AS_DROP_DOWN_MENU) { 471 @Override 472 public void run() { 473 final String[] timeModes = { 474 "SYSTEM_TIME_REALTIME", "SYSTEM_TIME_MONOTONIC", "SYSTEM_TIME_PROCESS", 475 "SYSTEM_TIME_THREAD" 476 }; 477 int i = java.util.Arrays.asList(timeModes).indexOf(this.getText()); 478 i = (i + 1) % timeModes.length; 479 Message.Builder builder = Message.newBuilder(); 480 builder.setContextId(0); // FIXME: proper context id 481 builder.setType(Type.Response); 482 builder.setExpectResponse(false); 483 builder.setFunction(Message.Function.SETPROP); 484 builder.setProp(Prop.TimeMode); 485 builder.setArg0(i); 486 messageQueue.addCommand(builder.build()); 487 this.setText(timeModes[i]); 488 manager.update(true); 489 } 490 }); 491 492 mActionContext = new Action("Context: 0x", Action.AS_DROP_DOWN_MENU) { 493 @Override 494 public void run() { 495 if (debugContexts.size() < 2) 496 return; 497 final String idStr = this.getText().substring( 498 "Context: 0x".length()); 499 if (idStr.length() == 0) 500 return; 501 final int contextId = Integer.parseInt(idStr, 16); 502 int index = debugContexts.indexOfKey(contextId); 503 index = (index + 1) % debugContexts.size(); 504 changeContext(debugContexts.valueAt(index)); 505 } 506 }; 507 manager.add(mActionContext); 508 509 actionPort = new Action("5039", Action.AS_DROP_DOWN_MENU) { 510 @Override 511 public void run() { 512 InputDialog dialog = new InputDialog(shell, "Port", "Debugger port", 513 actionPort.getText(), null); 514 if (Window.OK == dialog.open()) { 515 actionPort.setText(dialog.getValue()); 516 manager.update(true); 517 } 518 } 519 }; 520 manager.add(actionPort); 521 522 manager.add(new Action("CodeGen Frame", Action.AS_PUSH_BUTTON) { 523 @Override 524 public void run() { 525 if (current != null) { 526 new CodeGen().codeGenFrame((Frame) mViewer.getInput()); 527 // need to reload current frame 528 mViewer.setInput(current.getFrame(mFrameScale.getSelection())); 529 } 530 } 531 }); 532 533 manager.add(new Action("CodeGen Frames", Action.AS_PUSH_BUTTON) { 534 @Override 535 public void run() { 536 if (current != null) { 537 new CodeGen().codeGenFrames(current, mFrameScale.getSelection() + 1, 538 getSite().getShell()); 539 // need to reload current frame 540 mViewer.setInput(current.getFrame(mFrameScale.getSelection())); 541 } 542 } 543 }); 544 } 545 openFile()546 private void openFile() { 547 FileDialog dialog = new FileDialog(getSite().getShell(), SWT.OPEN); 548 dialog.setText("Open"); 549 dialog.setFilterExtensions(new String[] { 550 "*.gles2dbg" 551 }); 552 String filePath = dialog.open(); 553 if (filePath == null) 554 return; 555 FileInputStream file = null; 556 try { 557 file = new FileInputStream(filePath); 558 } catch (FileNotFoundException e) { 559 e.printStackTrace(); 560 return; 561 } 562 mRunning = true; 563 messageQueue.start(TARGET_BYTE_ORDER, file); 564 mThread = new Thread(this); 565 mThread.start(); 566 mActionConnect.setText("Disconnect"); 567 getViewSite().getActionBars().getToolBarManager().update(true); 568 } 569 connectDisconnect()570 private void connectDisconnect() { 571 if (!mRunning) { 572 mRunning = true; 573 messageQueue.start(TARGET_BYTE_ORDER, null); 574 mThread = new Thread(this); 575 mThread.start(); 576 mActionConnect.setText("Disconnect"); 577 } else { 578 mRunning = false; 579 messageQueue.stop(); 580 mActionConnect.setText("Connect"); 581 } 582 this.getSite().getShell().getDisplay().syncExec(new Runnable() { 583 @Override 584 public void run() { 585 getViewSite().getActionBars().getToolBarManager().update(true); 586 } 587 }); 588 } 589 messageDataSelected(final MessageData msgData)590 void messageDataSelected(final MessageData msgData) { 591 if (null == msgData) 592 return; 593 if (mFrameScale.getSelection() == mFrameScale.getMaximum()) 594 return; // scale max cannot overlap min, so max is array size 595 final Frame frame = current.getFrame(mFrameScale.getSelection()); 596 final Context context = frame.computeContext(msgData); 597 mContextViewer.setInput(context); 598 if (msgData.getImage() != null) { 599 canvas.setBackgroundImage(msgData.getImage()); 600 tabFolder.setSelection(tabItemImage); 601 canvas.redraw(); 602 } else if (null != msgData.shader) { 603 mText.setText(msgData.shader); 604 tabFolder.setSelection(tabItemText); 605 } else if (null != msgData.attribs) { 606 StringBuilder builder = new StringBuilder(); 607 final int maxAttrib = msgData.msg.getArg7(); 608 for (int i = 0; i < msgData.attribs[0].length / 4; i++) { 609 if (msgData.indices != null) { 610 builder.append(msgData.indices[i] & 0xffff); 611 builder.append(": "); 612 } 613 for (int j = 0; j < maxAttrib; j++) { 614 for (int k = 0; k < 4; k++) 615 builder.append(String.format("%.3g ", msgData.attribs[j][i * 4 + k])); 616 if (j < maxAttrib - 1) 617 builder.append("|| "); 618 } 619 builder.append('\n'); 620 } 621 mText.setText(builder.toString()); 622 tabFolder.setSelection(tabItemText); 623 } 624 } 625 hookSelectionChanged()626 private void hookSelectionChanged() { 627 mViewer.addSelectionChangedListener(new ISelectionChangedListener() { 628 @Override 629 public void selectionChanged(SelectionChangedEvent event) { 630 StructuredSelection selection = (StructuredSelection) event 631 .getSelection(); 632 if (null == selection) 633 return; 634 MessageData msgData = (MessageData) selection.getFirstElement(); 635 messageDataSelected(msgData); 636 } 637 }); 638 } 639 showError(final Exception e)640 public void showError(final Exception e) { 641 mViewer.getControl().getDisplay().syncExec(new Runnable() { 642 @Override 643 public void run() { 644 MessageDialog.openError(mViewer.getControl().getShell(), 645 "GL ES 2.0 Debugger Client", e.getMessage()); 646 } 647 }); 648 } 649 650 /** 651 * Passing the focus request to the viewer's control. 652 */ 653 @Override setFocus()654 public void setFocus() { 655 mViewer.getControl().setFocus(); 656 } 657 658 @Override run()659 public void run() { 660 int newMessages = 0; 661 662 boolean shaderEditorUpdate = false; 663 while (mRunning) { 664 final Message oriMsg = messageQueue.removeCompleteMessage(0); 665 if (oriMsg == null && !messageQueue.isRunning()) 666 break; 667 if (newMessages > 60 || (newMessages > 0 && null == oriMsg)) { 668 newMessages = 0; 669 if (current != null && current.uiUpdate) 670 getSite().getShell().getDisplay().syncExec(new Runnable() { 671 @Override 672 public void run() { 673 if (mFrameScale.getSelection() == current.frameCount() - 1 || 674 mFrameScale.getSelection() == current.frameCount() - 2) 675 { 676 mViewer.refresh(false); 677 if (mActionAutoScroll.isChecked()) 678 mViewer.getList().setSelection( 679 mViewer.getList().getItemCount() - 1); 680 } 681 setMaxFrameCount(current.frameCount()); 682 } 683 }); 684 current.uiUpdate = false; 685 686 if (shaderEditorUpdate) 687 this.getSite().getShell().getDisplay().syncExec(new Runnable() { 688 @Override 689 public void run() { 690 mShaderEditor.updateUI(); 691 } 692 }); 693 shaderEditorUpdate = false; 694 } 695 if (null == oriMsg) { 696 try { 697 Thread.sleep(1); 698 continue; 699 } catch (InterruptedException e) { 700 showError(e); 701 } 702 } 703 DebugContext debugContext = debugContexts.get(oriMsg.getContextId()); 704 if (debugContext == null) { 705 debugContext = new DebugContext(oriMsg.getContextId()); 706 debugContexts.put(oriMsg.getContextId(), debugContext); 707 } 708 debugContext.processMessage(oriMsg); 709 shaderEditorUpdate |= debugContext.currentContext.serverShader.uiUpdate; 710 debugContext.currentContext.serverShader.uiUpdate = false; 711 if (current == null && debugContext.frameCount() > 0) 712 changeContext(debugContext); 713 newMessages++; 714 } 715 if (mRunning) 716 connectDisconnect(); // error occurred, disconnect 717 } 718 setMaxFrameCount(int frameCount)719 private void setMaxFrameCount(int frameCount) { 720 mFrameScale.setMaximum(frameCount); 721 mFrameNumberspinner.setMaximum(frameCount); 722 } 723 setSelectedFrame(int frameNumber)724 private void setSelectedFrame(int frameNumber) { 725 mFrameScale.setSelection(frameNumber); 726 mFrameNumberspinner.setSelection(frameNumber); 727 } 728 729 /** can be called from non-UI thread */ changeContext(final DebugContext newContext)730 void changeContext(final DebugContext newContext) { 731 getSite().getShell().getDisplay().syncExec(new Runnable() { 732 @Override 733 public void run() { 734 current = newContext; 735 if (current != null) { 736 setMaxFrameCount(current.frameCount()); 737 738 int frame = Math.min(mFrameScale.getSelection(), current.frameCount() - 1); 739 if (frame < 0) { 740 frame = 0; 741 } 742 setSelectedFrame(frame); 743 mViewer.setInput(current.getFrame(frame)); 744 mActionContext.setText("Context: 0x" + Integer.toHexString(current.contextId)); 745 } else { 746 setMaxFrameCount(1); 747 setSelectedFrame(0); 748 749 mViewer.setInput(null); 750 mActionContext.setText("Context: 0x"); 751 } 752 mShaderEditor.updateUI(); 753 getViewSite().getActionBars().getToolBarManager().update(true); 754 } 755 }); 756 } 757 } 758