IGraphicsCarbon::~IGraphicsCarbon()
{
  if (mTextEntryView)
  {
    RemoveEventHandler(mTextEntryHandler);
    mTextEntryHandler = 0;

    #if USE_MLTE
    TXNFocus(mTextEntryView, false);
    TXNClear(mTextEntryView);
    TXNDeleteObject(mTextEntryView);
    #else
    HIViewRemoveFromSuperview(mTextEntryView);
    #endif

    mTextEntryView = 0;
    mEdControl = 0;
    mEdParam = 0;
  }

  RemoveEventLoopTimer(mTimer);
  RemoveEventHandler(mControlHandler);
  RemoveEventHandler(mWindowHandler);
  mTimer = 0;
  mView = 0;
//  DisposeRgn(mRgn);
}
void IGraphicsCarbon::EndUserInput(bool commit)
{
  if (mTextEntryHandler)
  {
    RemoveEventHandler(mTextEntryHandler);
    mTextEntryHandler = 0;
  }
  else
  {
    return;
  }

  if (commit)
  {
    // Get the text
    CharsHandle textHandle;
    TXNGetDataEncoded(mTextEntryView, kTXNStartOffset, kTXNEndOffset, &textHandle, kTXNTextData);

    // Check that we have some worthwhile data
    if (textHandle != NULL && GetHandleSize(textHandle) > 0)
    {
      const long textLength = GetHandleSize(textHandle);
      char txt[257];
      strncpy(txt, *textHandle, (textLength > 255) ? 255 : textLength);
      txt[(textLength > 255) ? 255 : textLength] = '\0';

      if (mEdParam)
        mGraphicsMac->SetFromStringAfterPrompt(mEdControl, mEdParam, txt);
      else
        mEdControl->TextFromTextEntry(txt);
    }
  }

  if (mTextEntryView)
  {
    TXNFocus(mTextEntryView, false);
    TXNClear(mTextEntryView);
    TXNDeleteObject(mTextEntryView);
    mTextEntryView = 0;
  }

  if (mIsComposited)
  {
    HIViewSetNeedsDisplay(mView, true);
  }
  else
  {
    mEdControl->SetDirty(false);
    mEdControl->Redraw();
  }

  SetThemeCursor(kThemeArrowCursor);
  SetUserFocusWindow(kUserFocusAuto);

  mEdControl = 0;
  mEdParam = 0;
}
	/* YASTControlCarbonEventHandler defines the main entry point for all
	of the carbon event handlers installed for the YASTControl. */
static pascal OSStatus YASTControlCarbonEventHandler(
									EventHandlerCallRef myHandler,
									EventRef event,
									void* userData) {
	#pragma unused ( myHandler )
    OSStatus err, returnedResult;
	YASTControlVarsPtr varsp;
	UInt32 eclass, ekind;
		/* set up locals */
	eclass = GetEventClass(event);
	ekind = GetEventKind(event);
	varsp = (YASTControlVarsPtr) userData;
	returnedResult = eventNotHandledErr;
		/* dispatch the event by class*/
	switch (eclass) {
	
		case kEventClassWindow:
			if ( ekind == kEventWindowCursorChange ) {
				Point where;
				UInt32 modifiers;
				Boolean cursorWasSet;
					/* get the mouse position */
				err = GetEventParameter( event, kEventParamMouseLocation, 
						typeQDPoint,  NULL, sizeof(where), NULL, &where);
				if (err == noErr) {
					err = GetEventParameter( event, kEventParamKeyModifiers, 
							typeUInt32,  NULL, sizeof(modifiers), NULL, &modifiers);
					if (err == noErr) {
						SetPort(varsp->fGrafPtr);
						GlobalToLocal(&where);
						if (PtInRect(where, &varsp->fRBounds)) {
							err = HandleControlSetCursor( varsp->fControl, where, modifiers, &cursorWasSet);
							if (err != noErr) cursorWasSet = false;
							if ( ! cursorWasSet ) InitCursor();
							returnedResult = noErr;
						}
					}
				}
			}
			break;
	
		case kEventClassMouse:
				/* handle mouse downs in the control, but only if the
				control is in focus. */
			if ( ekind == kEventMouseDown ) {
				EventRecord outEvent;
				if ( varsp->fInFocus ) {
					if (ConvertEventRefToEventRecord( event, &outEvent)) {
						TXNClick( varsp->fTXNObject,  &outEvent);
					}
					returnedResult = noErr;
				}
			}
			break;

		case kEventClassTextInput:
			if ( ekind == kEventUnicodeForKeyEvent
			&& varsp->fTabMovesFocus) {
				UniChar mUnicodeText[8];
				UInt32 bytecount, nchars;
					/* get the character */
				err = GetEventParameter(event, kEventParamTextInputSendText, 
							typeUnicodeText, NULL, sizeof(mUnicodeText),
							&bytecount, (char*) mUnicodeText);
				if ((err == noErr)
				&& (bytecount >= sizeof(UniChar))) {
					nchars = ( bytecount / sizeof(UniChar) );
						/* if it's not the tab key, forget it... */
					if ( mUnicodeText[0] == '\t' ) {
						EventRef rawKeyEvent;
						Boolean shiftDown;
							/* is the shift key held down? */
						shiftDown = false;
						err = GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, 
									typeEventRef, NULL, sizeof(rawKeyEvent), NULL, &rawKeyEvent);
						if (err == noErr) {
							UInt32 modifiers;
							err = GetEventParameter(rawKeyEvent, kEventParamKeyModifiers, 
									typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers);
							if (err == noErr) {
								shiftDown = ( (modifiers & shiftKey) != 0 );
							}
						}
							/* advance the keyboard focus, backwards if shift is down */
						if (shiftDown)
							ReverseKeyboardFocus( varsp->fWindow );
						else AdvanceKeyboardFocus( varsp->fWindow );
							/* noErr lets the CEM know we handled the event */
						returnedResult = noErr;
					}
				}
			}
			break;

		case kEventClassControl:
			switch (ekind) {

				case kEventControlSetFocusPart:
					{	ControlPartCode thePart;
						err = GetEventParameter(event, kEventParamControlPart, 
							typeControlPartCode, NULL, sizeof(thePart), NULL, &thePart);
						if (err == noErr) {
							switch (thePart) {
								default:
								case kControlFocusNoPart: /* turn off focus */
									if ( varsp->fInFocus ) {
										TXNFocus( varsp->fTXNObject, false);
										varsp->fInFocus = false;
									}
									thePart = kControlFocusNoPart;
									break;
								case kYASTControlOnlyPart: /* turn on focus */
									if ( !  varsp->fInFocus ) {
										TXNFocus( varsp->fTXNObject, true);
										varsp->fInFocus = true;
									}
									thePart = kYASTControlOnlyPart;
									break;
								case kControlFocusPrevPart: /* toggle focus on/off */
								case kControlFocusNextPart:
									varsp->fInFocus = ! varsp->fInFocus;
									TXNFocus( varsp->fTXNObject, varsp->fInFocus);
									thePart = (varsp->fInFocus ? kYASTControlOnlyPart : kControlFocusNoPart);
									break;
							}
							SetPort(varsp->fGrafPtr);
								/* calculate the next highlight state */
							SetTextActivation(varsp, varsp->fIsActive && varsp->fInFocus);
								/* redraw the text fram and focus rectangle to indicate the
								new focus state */
							DrawThemeEditTextFrame(&varsp->fRTextOutline,
								varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
							RedrawFocusOutline(varsp);
						}
							/* pass back the foocus part code */
						err = SetEventParameter( event, kEventParamControlPart,
								typeControlPartCode, sizeof(thePart), &thePart);
						returnedResult = err;
					}
					break;

				case kEventControlHitTest:
						/* this event does not necessairly mean that a mouse click
						has occured.  Here we are simply testing to see if a particular
						point is located inside of the control.  More complicated controls
						would return different part codes for different parts of
						themselves;  but, since YASTControls only advertise one part, the
						hit test here is more or less a boolean test. */
					{	ControlPartCode thePart;
						Point where;
						err = GetEventParameter(event, kEventParamMouseLocation, 
							typeQDPoint, NULL, sizeof(where), NULL, &where);
						if (err == noErr) {
							if (PtInRect(where, &varsp->fRTextArea)) {
								thePart = kYASTControlOnlyPart;
							} else thePart = 0;
							err = SetEventParameter( event, kEventParamControlPart,
										typeControlPartCode, sizeof(thePart), &thePart);
						}
						returnedResult = err;
					}
					break;

				case kEventControlClick:
						/* here we handle focus switching on the control.  Actual tracking
						of mouse down events in the control is performed in the kEventClassMouse
						mouse down handler above. */
					if ( ! varsp->fInFocus ) {
						SetKeyboardFocus(varsp->fWindow, varsp->fControl, kYASTControlOnlyPart);
						returnedResult = noErr;
					}
					break;
					
				case kEventControlBoundsChanged:
						/* we moved, or switched size - recalculate our rectangles */
					{	Rect bounds;
						err = GetEventParameter(event, kEventParamCurrentBounds, 
							typeQDRectangle, NULL, sizeof(bounds), NULL, &bounds);
						if (err == noErr) {
							YASTControlCalculateBounds(varsp, &bounds);
							TXNSetFrameBounds( varsp->fTXNObject,
								varsp->fRTextArea.top, varsp->fRTextArea.left,
								varsp->fRTextArea.bottom, varsp->fRTextArea.right,
								varsp->fTXNFrameID);
						}
					}
					break;
						
				case kEventControlActivate:
				case kEventControlDeactivate:
					{	SetPort(varsp->fGrafPtr);
						varsp->fIsActive = (ekind == kEventControlActivate);
						SetTextActivation(varsp, varsp->fIsActive && varsp->fInFocus);
							/* redraw the frame */
						DrawThemeEditTextFrame(&varsp->fRTextOutline,
							varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
						RedrawFocusOutline(varsp);
						returnedResult = noErr;
					}
					break;
					
				case kEventControlDraw:
						/* redraw the control */
					SetPort(varsp->fGrafPtr);
						/* update the text region */
					TXNDraw(varsp->fTXNObject, NULL);
						/* restore the drawing environment */
						/* draw the text frame and focus frame (if necessary) */
					DrawThemeEditTextFrame(&varsp->fRTextOutline,
						varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
					RedrawFocusOutline(varsp);
					returnedResult = noErr;
					break;
					
				case kEventControlSetCursor:
						/* cursor adjustment */
					{	SetPortWindowPort(varsp->fWindow);
						TXNAdjustCursor( varsp->fTXNObject, varsp->fRTextOutlineRegion);
						returnedResult = noErr;
					}
					break;
					
				case kEventControlDispose:
						/* RemoveEventHandler(varsp->fControlEvents); -- this call has been
						left out on purpose because it will be called automatically when the
						control is disposed. */
					RemoveEventHandler(varsp->fWindowEvents);
					TXNDeleteObject(varsp->fTXNObject);
					DisposeRgn(varsp->fRTextOutlineRegion);
					free(varsp);
						/* returnedResult = noErr; -- this has been left out on purpose
						because we want the dispatching to continue and dispose of the control */
					break;
					
				case kEventControlSetData:
					{	ResType inTagName;
						Size inBufferSize;
						void * inBuffer;
						err = GetEventParameter( event, kEventParamControlDataTag, typeEnumeration, 
							NULL, sizeof(inTagName), NULL, &inTagName);
						if (err == noErr) {
							err = GetEventParameter( event, kEventParamControlDataBuffer, typePtr, 
								NULL, sizeof(inBuffer), NULL, &inBuffer);
							if (err == noErr) {
								err = GetEventParameter( event, kEventParamControlDataBufferSize, typeLongInteger, 
									NULL, sizeof(inBufferSize), NULL, &inBufferSize);
								if (err == noErr) {
									err = YASTControlSetData(varsp, inTagName, inBuffer, inBufferSize);
								}
							}
						}
						returnedResult = err;
					}
					break;
					
				case kEventControlGetData:
					{	ResType inTagName;
						Size inBufferSize, outBufferSize;
						void * inBuffer;
						err = GetEventParameter( event, kEventParamControlDataTag, typeEnumeration, 
							NULL, sizeof(inTagName), NULL, &inTagName);
						if (err == noErr) {
							err = GetEventParameter( event, kEventParamControlDataBuffer, typePtr, 
								NULL, sizeof(inBuffer), NULL, &inBuffer);
							if (err == noErr) {
								err = GetEventParameter( event, kEventParamControlDataBufferSize, typeLongInteger, 
									NULL, sizeof(inBufferSize), NULL, &inBufferSize);
								if (err == noErr) {
									err = YASTControlGetData(varsp, inTagName, inBuffer, inBufferSize, &outBufferSize);
									if (err == noErr) {
										err = SetEventParameter( event, kEventParamControlDataBufferSize,
													typeLongInteger, sizeof(outBufferSize), &outBufferSize);
									}
								}
							}
						}
						returnedResult = err;
					}
					break;
					
			}
			break;
		case kEventClassCommand:
			if ( ekind == kEventProcessCommand ) {
				HICommand command;
				err = GetEventParameter( event, kEventParamDirectObject,
										typeHICommand, NULL, sizeof(command), NULL, &command);
				if (err == noErr) {
					switch (command.commandID) {
						case kHICommandUndo:
							TXNUndo(varsp->fTXNObject);
							returnedResult = noErr;
							break;
						case kHICommandRedo:
							TXNRedo(varsp->fTXNObject);
							returnedResult = noErr;
							break;
						case kHICommandCut:
							ClearCurrentScrap();
							err = TXNCut(varsp->fTXNObject); 
							if (err == noErr)
								err = TXNConvertToPublicScrap();
							returnedResult = err;
							break;
						case kHICommandCopy:
							ClearCurrentScrap();
							err = TXNCopy(varsp->fTXNObject);
							if (err == noErr)
								err = TXNConvertToPublicScrap();
							returnedResult = err;
							break;
						case kHICommandPaste:
							err = TXNConvertFromPublicScrap();
							if (err == noErr)
								err = TXNPaste(varsp->fTXNObject);
							returnedResult = err;
							break;
						case kHICommandClear:
							err = TXNClear(varsp->fTXNObject);
							returnedResult = err;
							break;
						case kHICommandSelectAll:
							err = TXNSetSelection(varsp->fTXNObject, kTXNStartOffset, kTXNEndOffset);
							returnedResult = err;
							break;
					}
				}
			} else if ( ekind == kEventCommandUpdateStatus ) {
				HICommand command;
				TXNOffset oStartOffset, oEndOffset;
				TXNActionKey oActionKey;

				err = GetEventParameter( event, kEventParamDirectObject, typeHICommand, 
										NULL, sizeof(command), NULL, &command);
				
				if ((err == noErr)
				&& ((command.attributes & kHICommandFromMenu) != 0)) {
					switch (command.commandID) {
						case kHICommandUndo:
							if (TXNCanUndo(varsp->fTXNObject, &oActionKey)) {
								EnableMenuItem(command.menu.menuRef, 0); /* required pre OS 10.2 */
								EnableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							} else DisableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							returnedResult = noErr;
							break;
						case kHICommandRedo:
							if (TXNCanRedo(varsp->fTXNObject, &oActionKey)) {
								EnableMenuItem(command.menu.menuRef, 0); /* required pre OS 10.2 */
								EnableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							} else DisableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							returnedResult = noErr;
							break;
						case kHICommandCut:
						case kHICommandCopy:
						case kHICommandClear:
							TXNGetSelection(varsp->fTXNObject, &oStartOffset, &oEndOffset);
							if (oStartOffset != oEndOffset) {
								EnableMenuItem(command.menu.menuRef, 0); /* required pre OS 10.2 */
								EnableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							} else DisableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							returnedResult = noErr;
							break;
						case kHICommandPaste:
							if (TXNIsScrapPastable()) {
								EnableMenuItem(command.menu.menuRef, 0); /* required pre OS 10.2 */
								EnableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							} else DisableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							returnedResult = noErr;
							break;
						case kHICommandSelectAll:
							if(TXNDataSize(varsp->fTXNObject) > 0) {
								EnableMenuItem(command.menu.menuRef, 0); /* required pre OS 10.2 */
								EnableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							} else DisableMenuItem(command.menu.menuRef, command.menu.menuItemIndex);
							returnedResult = noErr;
							break;
					}
				}
			}
			break;
	}
    return returnedResult;
}