Rectangle[] getRectangles(int linkIndex) {
   int lineCount = layout.getLineCount();
   Rectangle[] rects = new Rectangle[lineCount];
   int[] lineOffsets = layout.getLineOffsets();
   Point point = offsets[linkIndex];
   int lineStart = 1;
   while (point.x > lineOffsets[lineStart]) lineStart++;
   int lineEnd = 1;
   while (point.y > lineOffsets[lineEnd]) lineEnd++;
   int index = 0;
   if (lineStart == lineEnd) {
     rects[index++] = layout.getBounds(point.x, point.y);
   } else {
     rects[index++] = layout.getBounds(point.x, lineOffsets[lineStart] - 1);
     rects[index++] = layout.getBounds(lineOffsets[lineEnd - 1], point.y);
     if (lineEnd - lineStart > 1) {
       for (int i = lineStart; i < lineEnd - 1; i++) {
         rects[index++] = layout.getLineBounds(i);
       }
     }
   }
   if (rects.length != index) {
     Rectangle[] tmp = new Rectangle[index];
     System.arraycopy(rects, 0, tmp, 0, index);
     rects = tmp;
   }
   return rects;
 }
 @Override
 public Point computeSize(int wHint, int hHint, boolean changed) {
   checkWidget();
   if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
   if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
   int width, height;
   int layoutWidth = layout.getWidth();
   // TEMPORARY CODE
   if (wHint == 0) {
     layout.setWidth(1);
     Rectangle rect = layout.getBounds();
     width = 0;
     height = rect.height;
   } else {
     layout.setWidth(wHint);
     Rectangle rect = layout.getBounds();
     width = rect.width;
     height = rect.height;
   }
   layout.setWidth(layoutWidth);
   if (wHint != SWT.DEFAULT) width = wHint;
   if (hHint != SWT.DEFAULT) height = hHint;
   int border = getBorderWidth();
   width += border * 2;
   height += border * 2;
   return new Point(width, height);
 }
 @Override
 long /*int*/ gtk_button_press_event(long /*int*/ widget, long /*int*/ event) {
   long /*int*/ result = super.gtk_button_press_event(widget, event);
   if (result != 0) return result;
   GdkEventButton gdkEvent = new GdkEventButton();
   OS.memmove(gdkEvent, event, GdkEventButton.sizeof);
   if (gdkEvent.button == 1 && gdkEvent.type == OS.GDK_BUTTON_PRESS) {
     if (focusIndex != -1) setFocus();
     int x = (int) gdkEvent.x;
     int y = (int) gdkEvent.y;
     if ((style & SWT.MIRRORED) != 0) x = getClientWidth() - x;
     int offset = layout.getOffset(x, y, null);
     int oldSelectionX = selection.x;
     int oldSelectionY = selection.y;
     selection.x = offset;
     selection.y = -1;
     if (oldSelectionX != -1 && oldSelectionY != -1) {
       if (oldSelectionX > oldSelectionY) {
         int temp = oldSelectionX;
         oldSelectionX = oldSelectionY;
         oldSelectionY = temp;
       }
       Rectangle rect = layout.getBounds(oldSelectionX, oldSelectionY);
       redraw(rect.x, rect.y, rect.width, rect.height, false);
     }
     for (int j = 0; j < offsets.length; j++) {
       Rectangle[] rects = getRectangles(j);
       for (int i = 0; i < rects.length; i++) {
         Rectangle rect = rects[i];
         if (rect.contains(x, y)) {
           focusIndex = j;
           redraw();
           return result;
         }
       }
     }
   }
   return result;
 }
 @Override
 long /*int*/ gtk_motion_notify_event(long /*int*/ widget, long /*int*/ event) {
   long /*int*/ result = super.gtk_motion_notify_event(widget, event);
   if (result != 0) return result;
   GdkEventMotion gdkEvent = new GdkEventMotion();
   OS.memmove(gdkEvent, event, GdkEventMotion.sizeof);
   int x = (int) gdkEvent.x;
   int y = (int) gdkEvent.y;
   if ((style & SWT.MIRRORED) != 0) x = getClientWidth() - x;
   if ((gdkEvent.state & OS.GDK_BUTTON1_MASK) != 0) {
     int oldSelection = selection.y;
     selection.y = layout.getOffset(x, y, null);
     if (selection.y != oldSelection) {
       int newSelection = selection.y;
       if (oldSelection > newSelection) {
         int temp = oldSelection;
         oldSelection = newSelection;
         newSelection = temp;
       }
       Rectangle rect = layout.getBounds(oldSelection, newSelection);
       redraw(rect.x, rect.y, rect.width, rect.height, false);
     }
   } else {
     for (int j = 0; j < offsets.length; j++) {
       Rectangle[] rects = getRectangles(j);
       for (int i = 0; i < rects.length; i++) {
         Rectangle rect = rects[i];
         if (rect.contains(x, y)) {
           setCursor(display.getSystemCursor(SWT.CURSOR_HAND));
           return result;
         }
       }
     }
     setCursor(null);
   }
   return result;
 }