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 128 public void inputChanged(Viewer v, Object oldInput, Object newInput) { 129 frame = (Frame) newInput; 130 } 131 132 @Override 133 public void dispose() { 134 } 135 136 public Object[] getElements(Object parent) { 137 return frame.get().toArray(); 138 } 139 140 @Override 141 public String getText(Object obj) { 142 MessageData msgData = (MessageData) obj; 143 return msgData.text; 144 } 145 146 @Override 147 public Image getImage(Object obj) { 148 MessageData msgData = (MessageData) obj; 149 return msgData.getImage(); 150 } 151 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 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 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 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 190 public SampleView() { 191 192 } 193 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 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 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 398 private void contributeToActionBars() { 399 IActionBars bars = getViewSite().getActionBars(); 400 fillLocalPullDown(bars.getMenuManager()); 401 fillLocalToolBar(bars.getToolBarManager()); 402 } 403 404 private void fillLocalPullDown(IMenuManager manager) { 405 // manager.add(actionConnect); 406 // manager.add(new Separator()); 407 // manager.add(actionDisconnect); 408 } 409 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 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 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 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 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 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 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 712 public void setFocus() { 713 viewer.getControl().setFocus(); 714 } 715 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 */ 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 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 814 public void widgetDefaultSelected(SelectionEvent e) { 815 widgetSelected(e); 816 } 817 } 818