Monday, August 12, 2013

Logitech Perfomance MX Extra Buttons for Ubuntu Gnome

This configures the extra buttons on my Logitech Performance MX to do the following:

  • The "Zoom" button works like "Alt-Tab". Press and hold the "Zoom" button and use the scroll wheel to select a program.
  • The "Overview" button starts the Gnome overview.

First install the necessary software:

sudo apt-get install xautomation
sudo apt-get install xbindkeys
 
 
Create a configuration for xbindkeys
 
gedit ~/.xbindkeysrc 


.xbindkeyrc has to look like this:

# zoom ->; switch applications
# start with zoom key pressed
"xte 'keydown Alt_L'; xte 'key Tab'"
  b:13

# end with zoom key released
"xte 'keyup Alt_L'"
  alt+release+b:13

# left if wheel forward
"xte 'key Left'"
  alt+b:4

# right if wheel back
"xte 'key Right'"
  alt+b:5

# overview
"xte 'keydown Alt_L'; xte 'sleep 1'; xte 'key F1'; xte 'keyup Alt_L'"
  b:10

Test you settings by starting xbindkeys

xbindkeys -p -v


If the buttons work log out and in again. xbindkeys should start automatically in Ubuntu 13.04.

Of course you can add even more actions for the other buttons of the mouse by editing .xbindkeyrc.

Saturday, October 27, 2012

Ubuntu Unity HUD and Eclipse

To make the Eclipse menu available in HUD Eclipse has to be removed from the HUD blacklist. This can be done using the following script (has to be run with sudo).
#!/bin/bash
cd ~
mkdir -p hud4eclipse_working_dir
cd hud4eclipse_working_dir
cp /usr/lib/x86_64-linux-gnu/gtk-2.0/2.10.0/menuproxies/libappmenu.so .
cat libappmenu.so | sed s/Eclipse/Xclipse/ > libappmenu.so.new
cp libappmenu.so.new /usr/lib/x86_64-linux-gnu/gtk-2.0/2.10.0/menuproxies/libappmenu.so
The script works for Ubuntu 12.10 with Eclipse 3.8. Nevertheless it should work with other Eclipse versions as well.

Wednesday, April 20, 2011

Disper indicator for switching Nvidia display modes on Ubuntu 11.04 Natty

This is a small Pyhton script which displays an indicator for Disper in Ubuntu 11.04 Natty (Unity desktop).

Disper can be found at http://launchpad.net/disper.

As far as I know this is the only command line utility which can handle the TwinView settings for Nvidia cards.


import gobject
import gtk
import appindicator
import commands

def single(w):
    commands.getstatusoutput('disper -s')

def extend(w):
    commands.getstatusoutput('disper -e')

def clone(w):
    commands.getstatusoutput('disper -c')

def add_menu_item(name, action):
  menu_item = gtk.MenuItem(name)
  menu.append(menu_item)
  menu_item.connect("activate", action)
  menu_item.show()
    
if __name__ == "__main__":
  ind = appindicator.Indicator ("disper-indicator",
                              "gsd-xrandr",
                              appindicator.CATEGORY_HARDWARE)
  ind.set_status (appindicator.STATUS_ACTIVE)

  menu = gtk.Menu()
 
  add_menu_item('Single', single)
  add_menu_item('Extend', extend)
  add_menu_item('Clone', clone)

  ind.set_menu(menu)

  gtk.main()

Monday, January 10, 2011

Android AppEngine Login Error 500

Android caches authentication tokens. Therefore when getting a 500 error while authenticating against AppEngine the reason might be a timed out authentication token. In this case the token has to be invalidated and a new login request has to be send.

if (response.getStatusLine().getStatusCode() != 302) {
  Log.d(TAG, "Login failed. Trying again with new token.");
  AccountManager accountManager = AccountManager.get(context);
  accountManager.invalidateAuthToken("com.google",getAuthenticationToken(context));
}

Tuesday, December 21, 2010

Android Google App Engine Authentication

Using GAE together with Android is nice because the Google account on the Android device can be used to authenticate users in a Google App Engine application. The user does not have to create a new login or enter username and password.

In order to make this work an authentication token has to be retrieved from Google Account on the device. Using this token a cookie from GAE is requested which can be used to authenticate HTTP connections.

Doing all this can be tricky so I implemented the following HttpContext which gets the authentication cookie and makes working with GAE easier.


package axegr.android.net.http;

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AccountsException;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.net.http.AndroidHttpClient;
import android.os.Bundle;

public final class AuthenticatedAppEngineContext implements HttpContext {
  private HttpContext delegate_;
  private CookieStore cookieStore_;

  public static HttpContext newInstance(Context context, String uri)
      throws AccountsException, AuthenticationException {
    if (context == null)
      throw new IllegalArgumentException("context is null");
    return new AuthenticatedAppEngineContext(context, uri);
  }

  private AuthenticatedAppEngineContext(Context context, String uri)
      throws AccountsException, AuthenticationException {
    delegate_ = new BasicHttpContext();
    String authToken = getAuthenticationToken(context);
    AndroidHttpClient httpClient = AndroidHttpClient.newInstance(
        "GetAuthCookieClient", context);
    try {
      httpClient.getParams().setBooleanParameter(
          ClientPNames.HANDLE_REDIRECTS, false);
      cookieStore_ = new BasicCookieStore();
      setAttribute(ClientContext.COOKIE_STORE, cookieStore_);
      HttpGet http_get = new HttpGet(uri
          + "/_ah/login?continue=http://localhost/&auth=" + authToken);
      HttpResponse response = httpClient.execute(http_get, this);
      checkResponse(cookieStore_, response);
    } catch (IOException e) {
      throw new AuthenticationException(
          "error getting the authentication cookie", e);
    } finally {
      httpClient.close();
    }

  }

  private void checkResponse(CookieStore cookieStore, HttpResponse response)
      throws AuthenticationException {
    if (response.getStatusLine().getStatusCode() != 302) {
      throw new AuthenticationException(
          "authentication response was not a redirect");
    }
    if (!isAuthenticationCookiePresent(cookieStore)) {
      throw new AuthenticationException(
          "authentication cookie not found in cookie store");
    }
  }

  private String getAuthenticationToken(Context context)
      throws AccountsException {
    AccountManager accountManager = AccountManager.get(context);
    Account[] accounts = accountManager.getAccountsByType("com.google");

    if (accounts == null || accounts.length == 0) {
      throw new AccountsException(
          "no account of type 'com.google' found on this device");
    }

    try {
      Account account = accounts[0];
      AccountManagerFuture<Bundle> accountManagerFuture = accountManager
          .getAuthToken(account, "ah", true, null, null);
      Bundle authTokenBundle = null;
      authTokenBundle = accountManagerFuture.getResult();
      String authToken = authTokenBundle
          .get(AccountManager.KEY_AUTHTOKEN).toString();
      return authToken;

    } catch (OperationCanceledException e) {
      throw new AccountsException(
          "could not get authentication token from account 'com.google'",
          e);
    } catch (AuthenticatorException e) {
      throw new AccountsException(
          "could not get authentication token from account 'com.google'",
          e);
    } catch (IOException e) {
      throw new AccountsException(
          "could not get authentication token from account 'com.google'",
          e);
    }
  }

  private boolean isAuthenticationCookiePresent(CookieStore cookieStore) {
    for (Cookie cookie : cookieStore.getCookies()) {
      if (cookie.getName().equals("ACSID")
          || cookie.getName().equals("SACSID"))
        return true;
    }
    return false;
  }

  public Object getAttribute(String id) {
    return delegate_.getAttribute(id);
  }

  public Object removeAttribute(String id) {
    return delegate_.removeAttribute(id);
  }

  public void setAttribute(String id, Object obj) {
    delegate_.setAttribute(id, obj);
  }

}


And here is an example on how to use it:


    AndroidHttpClient client = AndroidHttpClient.newInstance(
        "IntegrationTestAgent", this.getContext());
    try {
      String baseUri = "https://android-gae-http-test.appspot.com";
      HttpContext httpContext = AuthenticatedAppEngineContext
          .newInstance(this.getContext(), baseUri);
      HttpGet get = new HttpGet(baseUri + "/authenticated/get");
      HttpResponse response = client.execute(get, httpContext);
      String result = EntityUtils.toString(response.getEntity());
    } finally {
      client.close();
    }

Saturday, November 27, 2010

Android Color Spinner

A quick hack for choosing colors with a Spinner. The color names are not displayed, instead the values of a string array are parsed as color values.




Lets start with the spinner declaration:

Spinner spinner = (Spinner) findViewById(R.id.color_spinner);
  ArrayAdapter adapter = new ArrayAdapter(this,
  R.layout.color_spinner_item, new String[] { "#F5F6F6",
    "#FFC0CB", "#FF0000", "#C00000" });
  adapter.setDropDownViewResource(R.layout.color_spinner_dropdown_item);
  spinner.setAdapter(adapter);

Next thing is the layout definitions for the item and the dropdown item:

color_spinner_dropdown_item.xml
<view xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@android:id/text1"
       class="net.eggeral.CheckedColorTextView" 
       style="?android:attr/spinnerDropDownItemStyle"
       android:singleLine="true"
       android:layout_width="fill_parent"
       android:layout_height="?android:attr/listPreferredItemHeight"
       android:ellipsize="marquee" />

color_spinner_item.xml
<view
  class="net.eggeral.ColorTextView" 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"/>

And two custom views for item and dropdown item:

CheckedColorTextView.java
package net.eggeral;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.CheckedTextView;

public class CheckedColorTextView extends CheckedTextView {
public CheckedColorTextView(Context context) {
super(context);
}

public CheckedColorTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void onDraw(Canvas canvas) {
int color = Color.parseColor(getText().toString());
Paint paint = new Paint();
paint.setColor(color);
setTextColor(color);

canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), 5, 5,
paint);
super.onDraw(canvas);
}
}

ColorTextView.java
package net.eggeral.marmind;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.TextView;

public class ColorTextView extends TextView {
public ColorTextView(Context context) {
super(context);
}

public ColorTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.parseColor(getText().toString()));

canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), 5, 5,
paint);
}
}

Friday, August 20, 2010

Wait for ExtJs Ajax Request to Finish with Selenium

To wait for an ExtJs Ajax call to finish in Selenium the following statement can be used:


_selenium.WaitForCondition("selenium.browserbot.getCurrentWindow().Ext.Ajax.isLoading() == false;", _defaultTimeout);