| /* |
| ** Copyright 2011, The Android Open Source Project |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| package com.android.glesv2debugger; |
| |
| import com.android.glesv2debugger.DebuggerMessage.Message; |
| import com.android.glesv2debugger.DebuggerMessage.Message.Function; |
| import com.android.glesv2debugger.DebuggerMessage.Message.Prop; |
| import com.android.glesv2debugger.DebuggerMessage.Message.Type; |
| |
| import org.eclipse.jface.dialogs.InputDialog; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.ScrolledComposite; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.layout.RowLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| |
| public class BreakpointOption extends ScrolledComposite implements SelectionListener { |
| |
| SampleView sampleView; |
| HashMap<Function, Button> buttonsBreak = new HashMap<Function, Button>(); |
| |
| BreakpointOption(SampleView sampleView, Composite parent) { |
| super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL); |
| this.sampleView = sampleView; |
| |
| Composite composite = new Composite(this, 0); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 4; |
| composite.setLayout(layout); |
| this.setLayout(new FillLayout()); |
| |
| for (int i = 0; i < Function.values().length; i++) { |
| Group group = new Group(composite, 0); |
| group.setLayout(new RowLayout()); |
| group.setText(Function.values()[i].toString()); |
| Button btn = new Button(group, SWT.CHECK); |
| btn.addSelectionListener(this); |
| btn.setText("Break"); |
| btn.setSelection(false); |
| buttonsBreak.put(Function.values()[i], btn); |
| } |
| |
| Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); |
| composite.setSize(size); |
| this.setContent(composite); |
| this.setExpandHorizontal(true); |
| this.setExpandVertical(true); |
| this.setMinSize(size); |
| this.layout(); |
| } |
| |
| void SetBreakpoint(Function function, boolean enabled) { |
| Message.Builder builder = Message.newBuilder(); |
| builder.setContextId(0); // FIXME: proper context id |
| builder.setType(Type.Response); |
| builder.setExpectResponse(false); |
| builder.setFunction(Function.SETPROP); |
| builder.setProp(Prop.ExpectResponse); |
| builder.setArg0(function.getNumber()); |
| builder.setArg1(enabled ? 1 : 0); |
| sampleView.messageQueue.AddCommand(builder.build()); |
| } |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| Button btn = (Button) e.widget; |
| Group group = (Group) btn.getParent(); |
| SetBreakpoint(Function.valueOf(group.getText()), btn.getSelection()); |
| } |
| |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| } |
| |
| private Function lastFunction = Function.NEG; |
| |
| public boolean ProcessMessage(final MessageQueue queue, final Message msg) throws IOException { |
| // use DefaultProcessMessage just to register the GL call |
| // but do not send response |
| if (msg.getType() == Type.BeforeCall || msg.getType() == Type.AfterCall) |
| queue.DefaultProcessMessage(msg, true, false); |
| final Message.Builder builder = Message.newBuilder(); |
| builder.setContextId(msg.getContextId()); |
| builder.setType(Type.Response); |
| builder.setExpectResponse(true); |
| final Shell shell = sampleView.getViewSite().getShell(); |
| shell.getDisplay().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| String call = MessageFormatter.Format(msg, false); |
| call = call.substring(0, call.indexOf("(")) + ' ' + |
| msg.getFunction() + call.substring(call.indexOf("(")); |
| if (msg.hasData() && msg.getFunction() == Function.glShaderSource) |
| { |
| int index = call.indexOf("string=") + 7; |
| String ptr = call.substring(index, call.indexOf(',', index)); |
| call = call.replace(ptr, '"' + msg.getData().toStringUtf8() + '"'); |
| } |
| if (msg.getType() == Type.AfterCall) |
| { |
| call = "skip " + call; |
| builder.setFunction(Function.SKIP); |
| } |
| else if (msg.getType() == Type.BeforeCall) |
| { |
| call = "continue " + call; |
| builder.setFunction(Function.CONTINUE); |
| } |
| else |
| { |
| assert msg.getType() == Type.AfterGeneratedCall; |
| assert msg.getFunction() == lastFunction; |
| call = "skip " + call; |
| builder.setFunction(Function.SKIP); |
| } |
| InputDialog inputDialog = new InputDialog(shell, |
| msg.getFunction().toString() + " " + msg.getType().toString(), |
| "(s)kip, (c)continue, (r)emove bp or glFunction(...)", |
| call, null); |
| if (Window.OK == inputDialog.open()) |
| { |
| String s = inputDialog.getValue().substring(0, 1).toLowerCase(); |
| if (s.startsWith("s")) |
| { |
| builder.setFunction(Function.SKIP); |
| // AfterCall is skipped, so push BeforeCall to complete |
| if (msg.getType() == Type.BeforeCall) |
| queue.CompletePartialMessage(msg.getContextId()); |
| } |
| else if (s.startsWith("c")) |
| builder.setFunction(Function.CONTINUE); |
| else if (s.startsWith("r")) |
| { |
| Button btn = buttonsBreak.get(msg.getFunction()); |
| btn.setSelection(false); |
| SetBreakpoint(msg.getFunction(), false); |
| builder.setExpectResponse(false); |
| } |
| else |
| { |
| MessageParserEx.instance.Parse(builder, inputDialog.getValue()); |
| lastFunction = builder.getFunction(); |
| // AfterCall is skipped, so push BeforeCall to complete |
| if (msg.getType() == Type.BeforeCall) |
| queue.CompletePartialMessage(msg.getContextId()); |
| } |
| } |
| // else defaults to continue BeforeCall and skip AfterCall |
| } |
| }); |
| queue.SendMessage(builder.build()); |
| return true; |
| } |
| } |