Home | History | Annotate | Download | only in gldebugger
      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 
     24 import org.eclipse.jface.dialogs.InputDialog;
     25 import org.eclipse.jface.window.Window;
     26 import org.eclipse.swt.SWT;
     27 import org.eclipse.swt.custom.ScrolledComposite;
     28 import org.eclipse.swt.events.SelectionEvent;
     29 import org.eclipse.swt.events.SelectionListener;
     30 import org.eclipse.swt.graphics.Point;
     31 import org.eclipse.swt.layout.FillLayout;
     32 import org.eclipse.swt.layout.GridLayout;
     33 import org.eclipse.swt.layout.RowLayout;
     34 import org.eclipse.swt.widgets.Button;
     35 import org.eclipse.swt.widgets.Composite;
     36 import org.eclipse.swt.widgets.Group;
     37 import org.eclipse.swt.widgets.Shell;
     38 
     39 import java.io.IOException;
     40 
     41 public class BreakpointOption extends ScrolledComposite implements SelectionListener,
     42         ProcessMessage {
     43 
     44     GLFramesView mGLFramesView;
     45     Button[] buttonsBreak = new Button[Function.values().length];
     46     /** cache of buttonsBreak[Function.getNumber()].getSelection */
     47     boolean[] breakpoints = new boolean[Function.values().length];
     48 
     49     BreakpointOption(GLFramesView view, Composite parent) {
     50         super(parent, SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL);
     51         mGLFramesView = view;
     52 
     53         Composite composite = new Composite(this, 0);
     54         GridLayout layout = new GridLayout();
     55         layout.numColumns = 4;
     56         composite.setLayout(layout);
     57         this.setLayout(new FillLayout());
     58 
     59         for (int i = 0; i < Function.values().length; i++) {
     60             Group group = new Group(composite, 0);
     61             group.setLayout(new RowLayout());
     62             group.setText(Function.values()[i].toString());
     63             Button btn = new Button(group, SWT.CHECK);
     64             btn.addSelectionListener(this);
     65             btn.setText("Break");
     66             btn.setSelection(false);
     67             breakpoints[Function.values()[i].getNumber()] = btn.getSelection();
     68             buttonsBreak[Function.values()[i].getNumber()] = btn;
     69         }
     70 
     71         Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
     72         composite.setSize(size);
     73         this.setContent(composite);
     74         this.setExpandHorizontal(true);
     75         this.setExpandVertical(true);
     76         this.setMinSize(size);
     77         this.layout();
     78     }
     79 
     80     void setBreakpoint(final int contextId, final Function function, final boolean enabled) {
     81         Message.Builder builder = Message.newBuilder();
     82         builder.setContextId(contextId);
     83         builder.setType(Type.Response);
     84         builder.setExpectResponse(false);
     85         builder.setFunction(Function.SETPROP);
     86         builder.setProp(Prop.ExpectResponse);
     87         builder.setArg0(function.getNumber());
     88         builder.setArg1(enabled ? 1 : 0);
     89         mGLFramesView.messageQueue.addCommand(builder.build());
     90         breakpoints[function.getNumber()] = enabled;
     91     }
     92 
     93     @Override
     94     public void widgetSelected(SelectionEvent e) {
     95         Button btn = (Button) e.widget;
     96         Group group = (Group) btn.getParent();
     97         int contextId = 0;
     98         if (mGLFramesView.current != null)
     99             contextId = mGLFramesView.current.contextId;
    100         setBreakpoint(contextId, Function.valueOf(group.getText()), btn.getSelection());
    101     }
    102 
    103     @Override
    104     public void widgetDefaultSelected(SelectionEvent e) {
    105     }
    106 
    107     private Function lastFunction = Function.NEG;
    108 
    109     @Override
    110     public boolean processMessage(final MessageQueue queue, final Message msg) throws IOException {
    111         if (!breakpoints[msg.getFunction().getNumber()])
    112             return false;
    113         // use DefaultProcessMessage just to register the GL call
    114         // but do not send response
    115         final int contextId = msg.getContextId();
    116         if (msg.getType() == Type.BeforeCall || msg.getType() == Type.AfterCall)
    117             queue.defaultProcessMessage(msg, true, false);
    118         final Message.Builder builder = Message.newBuilder();
    119         builder.setContextId(contextId);
    120         builder.setType(Type.Response);
    121         builder.setExpectResponse(true);
    122         final Shell shell = mGLFramesView.getViewSite().getShell();
    123         final boolean send[] = new boolean[1];
    124         shell.getDisplay().syncExec(new Runnable() {
    125             @Override
    126             public void run() {
    127                 String call = MessageFormatter.format(msg, false);
    128                 call = call.substring(0, call.indexOf("(")) + ' ' +
    129                         msg.getFunction() + call.substring(call.indexOf("("));
    130                 if (msg.hasData() && msg.getFunction() == Function.glShaderSource)
    131                 {
    132                     int index = call.indexOf("string=") + 7;
    133                     String ptr = call.substring(index, call.indexOf(',', index));
    134                     call = call.replace(ptr, '"' + msg.getData().toStringUtf8() + '"');
    135                 }
    136                 if (msg.getType() == Type.AfterCall)
    137                 {
    138                     call = "skip " + call;
    139                     builder.setFunction(Function.SKIP);
    140                 }
    141                 else if (msg.getType() == Type.BeforeCall)
    142                 {
    143                     call = "continue " + call;
    144                     builder.setFunction(Function.CONTINUE);
    145                 }
    146                 else
    147                 {
    148                     assert msg.getType() == Type.AfterGeneratedCall;
    149                     assert msg.getFunction() == lastFunction;
    150                     call = "skip " + call;
    151                     builder.setFunction(Function.SKIP);
    152                 }
    153                 InputDialog inputDialog = new InputDialog(shell,
    154                             msg.getFunction().toString() + " " + msg.getType().toString(),
    155                         "(s)kip, (c)continue, (r)emove bp or glFunction(...)",
    156                             call, null);
    157                 if (Window.OK == inputDialog.open())
    158                 {
    159                     String s = inputDialog.getValue().substring(0, 1).toLowerCase();
    160                     if (s.startsWith("s"))
    161                     {
    162                         builder.setFunction(Function.SKIP);
    163                         // AfterCall is skipped, so push BeforeCall to complete
    164                         if (queue.getPartialMessage(contextId) != null)
    165                             queue.completePartialMessage(contextId);
    166                     }
    167                     else if (s.startsWith("c"))
    168                         builder.setFunction(Function.CONTINUE);
    169                     else if (s.startsWith("r"))
    170                     {
    171                         Button btn = buttonsBreak[msg.getFunction().getNumber()];
    172                         btn.setSelection(false);
    173                         setBreakpoint(msg.getContextId(), msg.getFunction(), false);
    174                         builder.setExpectResponse(false);
    175                     }
    176                     else
    177                     {
    178                         MessageParserEx.instance.parse(builder, inputDialog.getValue());
    179                         lastFunction = builder.getFunction();
    180                         builder.setExpectResponse(true);
    181                         // AfterCall is skipped, so push BeforeCall to complete
    182                         if (queue.getPartialMessage(contextId) != null)
    183                             queue.completePartialMessage(contextId);
    184                     }
    185                 }
    186                 // else defaults to continue BeforeCall and skip AfterCall
    187             }
    188         });
    189         queue.sendMessage(builder.build());
    190         return true;
    191     }
    192 }
    193