/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiSource Application Framework * Copyright (C) 1998 AbiSource, Inc. * Copyright (C) 2001-2004 Hubert Figuiere * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #import #import "ut_debugmsg.h" #import "ut_assert.h" #import "ut_sleep.h" #import "fv_View.h" #import "ev_EditMethod.h" #import "ev_CocoaKeyboard.h" #import "ev_CocoaMouse.h" #import "ev_CocoaMenu.h" #import "ev_CocoaMenuBar.h" #import "ev_CocoaMenuPopup.h" #import "ev_CocoaToolbar.h" #import "ev_Toolbar.h" #import "gr_CocoaGraphics.h" #import "xap_App.h" #import "xap_CocoaApp.h" #import "xap_CocoaAppController.h" #import "xap_CocoaFrameImpl.h" #import "xap_CocoaTextView.h" #import "xap_CocoaTimer.h" #import "xap_CocoaToolbarWindow.h" #import "xap_CocoaToolPalette.h" #import "xap_FrameImpl.h" #import "xap_Frame.h" /*****************************************************************/ #define ENSUREP(p) do { UT_ASSERT(p); if (!p) goto Cleanup; } while (0) NSString* XAP_CocoaFrameImpl::XAP_FrameNeedToolbar = @"XAP_FrameNeedToolbar"; NSString* XAP_CocoaFrameImpl::XAP_FrameReleaseToolbar = @"XAP_FrameReleaseToolbar"; /*! * Background abi repaint function. \param XAP_CocoaFrameImpl * p pointer to the Frame that initiated this background repainter. */ int XAP_CocoaFrameImpl::_fe::abi_expose_repaint(void * p) { // // Grab our pointer so we can do useful stuff. // UT_Rect localCopy; XAP_Frame * pF = (XAP_Frame *)p; FV_View * pV = (FV_View *) pF->getCurrentView(); if(!pV) { return TRUE; } GR_Graphics * pG = pV->getGraphics(); if(pG->isDontRedraw()) { // // Come back later // return TRUE; } pG->setSpawnedRedraw(true); if(pG->isExposePending()) { while(pG->isExposedAreaAccessed()) { UT_usleep(10); // 10 microseconds } pG->setExposedAreaAccessed(true); localCopy.set(pG->getPendingRect()->left,pG->getPendingRect()->top, pG->getPendingRect()->width,pG->getPendingRect()->height); // // Clear out this set of expose info // pG->setExposePending(false); pG->setExposedAreaAccessed(false); // UT_DEBUGMSG(("Painting area: left=%d, top=%d, width=%d, height=%d\n", localCopy.left, localCopy.top, localCopy.width, localCopy.height)); xxx_UT_DEBUGMSG(("SEVIOR: Repaint now \n")); pV->draw(&localCopy); } // // OK we've finshed. Wait for the next signal // pG->setSpawnedRedraw(false); return TRUE; } /*****************************************************************/ XAP_CocoaFrameImpl::XAP_CocoaFrameImpl(XAP_Frame* frame, XAP_CocoaApp * app) : XAP_FrameImpl (frame), m_dialogFactory(frame, app), m_pCocoaApp(app), m_pCocoaPopup(NULL), m_frameController(nil), m_iAbiRepaintID(0) { // m_pView = NULL; } // TODO when cloning a new frame from an existing one // TODO should we also clone any frame-persistent // TODO dialog data ?? /* XAP_CocoaFrameImpl::XAP_CocoaFrameImpl(XAP_CocoaFrameImpl * f) : XAP_FrameImpl(f), m_dialogFactory(f->m_pFrame, static_cast(f->m_pCocoaApp)), m_pCocoaApp(f->m_pCocoaApp), m_pCocoaMenu(NULL), m_pCocoaPopup(NULL), m_frameController(nil), m_iAbiRepaintID(0) { m_pView = NULL; } */ XAP_CocoaFrameImpl::~XAP_CocoaFrameImpl(void) { // only delete the things we created... if(m_iAbiRepaintID) { XAP_stopCocoaTimer(m_iAbiRepaintID); } if (m_frameController != nil) { [m_frameController release]; } DELETEP(m_pCocoaPopup); } /* bool XAP_CocoaFrameImpl::initialize(const char * szKeyBindingsKey, const char * szKeyBindingsDefaultValue, const char * szMenuLayoutKey, const char * szMenuLayoutDefaultValue, const char * szMenuLabelSetKey, const char * szMenuLabelSetDefaultValue, const char * szToolbarLayoutsKey, const char * szToolbarLayoutsDefaultValue, const char * szToolbarLabelSetKey, const char * szToolbarLabelSetDefaultValue) { bool bResult; // invoke our base class first. bResult = XAP_Frame::initialize(szKeyBindingsKey, szKeyBindingsDefaultValue, szMenuLayoutKey, szMenuLayoutDefaultValue, szMenuLabelSetKey, szMenuLabelSetDefaultValue, szToolbarLayoutsKey, szToolbarLayoutsDefaultValue, szToolbarLabelSetKey, szToolbarLabelSetDefaultValue); UT_ASSERT(bResult); */ void XAP_CocoaFrameImpl::_initialize() { // get a handle to our keyboard binding mechanism // and to our mouse binding mechanism. EV_EditEventMapper * pEEM = XAP_App::getApp()->getEditEventMapper(); UT_ASSERT(pEEM); m_pKeyboard = new ev_CocoaKeyboard(pEEM); UT_ASSERT(m_pKeyboard); m_pMouse = new EV_CocoaMouse(pEEM); UT_ASSERT(m_pMouse); // // Start background repaint // if(m_iAbiRepaintID == 0) { m_iAbiRepaintID = XAP_newCocoaTimer(100, _fe::abi_expose_repaint, this); } else { XAP_stopCocoaTimer(m_iAbiRepaintID); m_iAbiRepaintID = XAP_newCocoaTimer(100, _fe::abi_expose_repaint, this); } } void XAP_CocoaFrameImpl::notifyViewChanged(AV_View * pView) // called from XAP_Frame::setView(pView) { if (XAP_Frame * pFrame = getFrame()) { XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate]; [pController resetCurrentView:pView inFrame:pFrame]; } } UT_sint32 XAP_CocoaFrameImpl::_setInputMode(const char * szName) { UT_sint32 result = XAP_App::getApp()->setInputMode(szName); if (result == 1) { // if it actually changed we need to update keyboard and mouse EV_EditEventMapper * pEEM = XAP_App::getApp()->getEditEventMapper(); UT_ASSERT(pEEM); m_pKeyboard->setEditEventMap(pEEM); m_pMouse->setEditEventMap(pEEM); } return result; } NSWindow * XAP_CocoaFrameImpl::getTopLevelWindow(void) const { UT_ASSERT (m_frameController); return [m_frameController window]; } NSView * XAP_CocoaFrameImpl::getVBoxWidget(void) const { UT_ASSERT (m_frameController); return [m_frameController getMainView]; } XAP_DialogFactory * XAP_CocoaFrameImpl::_getDialogFactory(void) { return &m_dialogFactory; } void XAP_CocoaFrameImpl::_nullUpdate() const { /* FIXME: do this more propperly if there is any chance...*/ [[m_frameController window] displayIfNeeded]; } static UT_uint32 s_iNewFrameOffsetX = 0; static UT_uint32 s_iNewFrameOffsetY = 0; void XAP_CocoaFrameImpl::_createTopLevelWindow(void) { // create a top-level window for us. m_frameController = _createController(); UT_ASSERT (m_frameController); NSWindow * theWindow = [m_frameController window]; UT_ASSERT (theWindow); [theWindow setTitle:[NSString stringWithUTF8String:m_pCocoaApp->getApplicationTitleForTitleBar()]]; // create a toolbar instance for each toolbar listed in our base class. _createToolbars(); // Let the app-specific frame code create the contents of // the child area of the window (between the toolbars and // the status bar). _createDocumentWindow(); // Let the app-specific frame code create the status bar // if it wants to. we will put it below the document // window (a peer with toolbars and the overall sunkenbox) // so that it will appear outside of the scrollbars. _createStatusBarWindow([m_frameController getStatusBar]); // set the icon _setWindowIcon(); // set geometry hints as the user requested int x, y; UT_uint32 width, height; XAP_CocoaApp::windowGeometryFlags f; m_pCocoaApp->getGeometry(&x, &y, &width, &height, &f); // Set the size if requested NSSize userSize; // userSize.width = (width < 300.0f) ? 300.0f : static_cast(width); // userSize.height = (height < 300.0f) ? 300.0f : static_cast(height); if (f & XAP_CocoaApp::GEOMETRY_FLAG_SIZE) { NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; screenFrame.size.height -= [[XAP_CocoaToolbarWindow_Controller sharedToolbar] height]; if ([XAP_CocoaToolPalette instantiated]) { NSWindow * palettePanel = [[XAP_CocoaToolPalette instance:theWindow] window]; if ([palettePanel isVisible]) { NSRect paletteFrame = [palettePanel frame]; if (paletteFrame.origin.x < screenFrame.origin.x + 10.0f) // panel at left { screenFrame.origin.x += paletteFrame.size.width; screenFrame.size.width -= paletteFrame.size.width; } else if (paletteFrame.origin.x + paletteFrame.size.width > screenFrame.origin.x + screenFrame.size.width - 10.0f) // panel at right { screenFrame.size.width -= paletteFrame.size.width; } } } userSize.height = screenFrame.size.height; userSize.width = rintf(screenFrame.size.height * 0.9f); if (m_pCocoaApp->getFrameCount() == 1) { s_iNewFrameOffsetX = 0; s_iNewFrameOffsetY = 0; } screenFrame.origin.x += s_iNewFrameOffsetX; screenFrame.size.height -= s_iNewFrameOffsetY; s_iNewFrameOffsetX = (s_iNewFrameOffsetX <= 128) ? (s_iNewFrameOffsetX + 32) : 0; s_iNewFrameOffsetY = (s_iNewFrameOffsetY < 128) ? (s_iNewFrameOffsetY + 32) : 0; NSRect windowFrame; windowFrame.size.width = UT_MIN(screenFrame.size.width, userSize.width ); // 813); windowFrame.size.height = UT_MIN(screenFrame.size.height, userSize.height); // 836); windowFrame.origin.x = screenFrame.origin.x; windowFrame.origin.y = screenFrame.origin.y + screenFrame.size.height - windowFrame.size.height; [theWindow setFrame:windowFrame display:YES]; } } /*! * This code is used by the dynamic toolbar API to rebuild a toolbar after a * a change in the toolbar structure. */ void XAP_CocoaFrameImpl::_rebuildToolbar(UT_uint32 ibar) { XAP_Frame* pFrame = getFrame(); // // Destroy the old toolbar // EV_Toolbar * pToolbar = (EV_Toolbar *) m_vecToolbars.getNthItem(ibar); const char * szTBName = (const char *) m_vecToolbarLayoutNames.getNthItem(ibar); EV_CocoaToolbar * pUTB = static_cast( pToolbar); UT_sint32 oldpos = pUTB->destroy(); // // Delete the old class // delete pToolbar; if(oldpos < 0) { return; } // // Build a new one. // pToolbar = _newToolbar(pFrame, szTBName, (const char *) m_szToolbarLabelSetName); static_cast(pToolbar)->rebuildToolbar(oldpos); m_vecToolbars.setNthItem(ibar, pToolbar, NULL); // // Refill the framedata pointers // pFrame->refillToolbarsInFrameData(); pFrame->repopulateCombos(); } bool XAP_CocoaFrameImpl::_close() { UT_DEBUGMSG (("XAP_CocoaFrame::close()\n")); [m_frameController close]; [[NSNotificationCenter defaultCenter] postNotificationName:XAP_FrameReleaseToolbar object:m_frameController]; return true; } bool XAP_CocoaFrameImpl::_raise() { UT_DEBUGMSG (("XAP_CocoaFrame::raise()\n")); [[m_frameController window] makeKeyAndOrderFront:m_frameController]; [[NSNotificationCenter defaultCenter] postNotificationName:XAP_FrameNeedToolbar object:m_frameController]; return true; } bool XAP_CocoaFrameImpl::_show() { UT_DEBUGMSG (("XAP_CocoaFrame::show()\n")); [[m_frameController window] makeKeyAndOrderFront:m_frameController]; [[NSNotificationCenter defaultCenter] postNotificationName:XAP_FrameNeedToolbar object:m_frameController]; XAP_CocoaTextView * textView = (XAP_CocoaTextView *) [m_frameController textView]; [textView hasBeenResized:nil]; return true; } UT_RGBColor XAP_CocoaFrameImpl::getColorSelBackground () const { /* this code is disabled as the NSColor returned is not RGB compatible. */ static UT_RGBColor * c = NULL; if (c == NULL) { c = new UT_RGBColor(); GR_CocoaGraphics::_utNSColorToRGBColor ([[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace], *c); } return *c; } bool XAP_CocoaFrameImpl::_updateTitle() { if (!XAP_FrameImpl::_updateTitle()) { // no relevant change, so skip it return false; } NSWindow * theWindow = [m_frameController window]; UT_ASSERT (theWindow); if (theWindow) { const char * szTitle = getFrame()->getNonDecoratedTitle(); const char * szFilename = getFrame()->getFilename(); [theWindow setTitle:[NSString stringWithUTF8String:szTitle]]; if (szFilename) [theWindow setRepresentedFilename:[NSString stringWithUTF8String:szFilename]]; [theWindow setDocumentEdited:(getFrame()->isDirty() ? YES : NO)]; } return true; } /*****************************************************************/ bool XAP_CocoaFrameImpl::_runModalContextMenu(AV_View * /* pView */, const char * szMenuName, UT_sint32 x, UT_sint32 y) { bool bResult = true; UT_ASSERT(!m_pCocoaPopup); m_pCocoaPopup = new EV_CocoaMenuPopup(m_pCocoaApp,szMenuName,m_szMenuLabelSetName); if (m_pCocoaPopup && m_pCocoaPopup->synthesizeMenuPopup()) { NSEvent *evt = [NSApp currentEvent]; [NSMenu popUpContextMenu:m_pCocoaPopup->getMenuHandle() withEvent:evt forView:[m_frameController getMainView]]; } XAP_Frame * pFrame = (XAP_Frame *)getFrame(); if (pFrame->getCurrentView()) { pFrame->getCurrentView()->focusChange( AV_FOCUS_HERE); } DELETEP(m_pCocoaPopup); return bResult; } void XAP_CocoaFrameImpl::setTimeOfLastEvent(NSTimeInterval timestamp) { m_pCocoaApp->setTimeOfLastEvent(timestamp); } EV_Toolbar * XAP_CocoaFrameImpl::_newToolbar(XAP_Frame *frame, const char *szLayout, const char *szLanguage) { return (new EV_CocoaToolbar(static_cast(XAP_App::getApp()), (AP_CocoaFrame *)frame, szLayout, szLanguage)); } void XAP_CocoaFrameImpl::_queue_resize() { UT_DEBUGMSG(("XAP_CocoaFrameImpl::queue_resize\n")); UT_ASSERT (UT_NOT_IMPLEMENTED); // gtk_widget_queue_resize(m_wTopLevelWindow); } EV_Menu* XAP_CocoaFrameImpl::_getMainMenu() { return m_pCocoaApp->getCocoaMenuBar(); } void XAP_CocoaFrameImpl::_setController (XAP_CocoaFrameController * ctrl) { if ((m_frameController) && (ctrl != m_frameController)){ [m_frameController release]; } m_frameController = ctrl; } void XAP_CocoaFrameImpl::setToolbarRect(const NSRect &r) { UT_uint32 frameCount = XAP_App::getApp()->getFrameCount(); UT_uint32 i; for (i = 0; i < frameCount; i++) { XAP_CocoaFrameImpl* impl = dynamic_cast(XAP_App::getApp()->getFrame(i)->getFrameImpl()); XAP_CocoaFrameController* ctrl = impl->_getController(); NSRect frame = [[ctrl window] frame]; if (NSIntersectsRect(frame, r)) { if (frame.origin.y + frame.size.height > r.origin.y) { UT_DEBUGMSG(("original frame is %f %f %f %f\n", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height)); frame.size.height = r.origin.y - frame.origin.y; [[ctrl window] setFrame:frame display:YES]; UT_DEBUGMSG(("resized frame is %f %f %f %f\n", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height)); } } } } /* Objective C section */ @implementation XAP_CocoaFrameController - (BOOL)windowShouldClose:(id)sender { UT_DEBUGMSG (("shouldCloseDocument\n")); UT_ASSERT (m_frame); XAP_App * pApp = m_frame->getFrame()->getApp(); UT_ASSERT(pApp); const EV_Menu_ActionSet * pMenuActionSet = pApp->getMenuActionSet(); UT_ASSERT(pMenuActionSet); const EV_EditMethodContainer * pEMC = pApp->getEditMethodContainer(); UT_ASSERT(pEMC); const EV_EditMethod * pEM = pEMC->findEditMethodByName("closeWindowX"); UT_ASSERT(pEM); if (pEM) { if (pEM->Fn(m_frame->getFrame()->getCurrentView(),NULL)) { // returning YES means close the window // but first let's warn the app controller not to assume our existence XAP_Frame * pFrame = m_frame->getFrame (); AV_View * pView = pFrame->getCurrentView(); XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate]; [pController unsetCurrentView:pView inFrame:pFrame]; return YES; } } // returning NO means do NOT close the window return NO; } - (void)keyDown:(NSEvent *)theEvent { xxx_UT_DEBUGMSG(("keyDown in window '%s'\n", [[[self window] title] UTF8String])); [m_textView interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; #if 0 XAP_Frame * pFrame = m_frame->getFrame(); // pFrame->setTimeOfLastEvent([theEvent timestamp]); AV_View * pView = pFrame->getCurrentView(); ev_CocoaKeyboard * pCocoaKeyboard = static_cast (pFrame->getKeyboard()); if (pView) pCocoaKeyboard->keyPressEvent(pView, theEvent); #endif } - (void)windowDidBecomeKey:(NSNotification *)aNotification { UT_DEBUGMSG(("windowDidBecomeKey: '%s'\n", [[[self window] title] UTF8String])); XAP_Frame * pFrame = m_frame->getFrame (); AV_View * pView = pFrame->getCurrentView(); XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate]; [pController setCurrentView:pView inFrame:pFrame]; [[NSNotificationCenter defaultCenter] postNotificationName:XAP_CocoaFrameImpl::XAP_FrameNeedToolbar object:self]; } - (void)windowDidExpose:(NSNotification *)aNotification { UT_DEBUGMSG(("windowDidExpose:\n")); // [[NSNotificationCenter defaultCenter] postNotificationName:XAP_CocoaFrameImpl::XAP_FrameNeedToolbar // object:self]; } - (void)windowDidResignKey:(NSNotification *)aNotification { UT_DEBUGMSG(("windowDidResignKey: '%s'\n", [[[self window] title] UTF8String])); XAP_CocoaAppController * pController = (XAP_CocoaAppController *) [NSApp delegate]; [pController setCurrentView:0 inFrame:0]; // [[NSNotificationCenter defaultCenter] postNotificationName:XAP_CocoaFrameImpl::XAP_FrameReleaseToolbar // object:self]; } /*! Returns an instance. */ + (XAP_CocoaFrameController*)createFrom:(XAP_CocoaFrameImpl *)frame { UT_DEBUGMSG (("Cocoa: createFrom:frame\n")); XAP_CocoaFrameController *obj = [[XAP_CocoaFrameController alloc] initWith:frame]; return [obj autorelease]; } - (id)initWith:(XAP_CocoaFrameImpl *)frame { UT_DEBUGMSG (("Cocoa: @XAP_CocoaFrameController initWith:frame\n")); m_frame = frame; [self initWithWindowNibName:frame->_getNibName()]; /* this one will make the call to [super init] */ [[self window] setAcceptsMouseMovedEvents:YES]; /* can't we set that from IB (FIXME) */ [[self window] makeFirstResponder:self]; return self; } - (NSView *)getMainView { return mainView; } - (XAP_CocoaNSStatusBar *)getStatusBar { return statusBar; } - (XAP_CocoaFrameImpl *)frameImpl { return m_frame; } - (void)setTextView:(NSView *)tv { m_textView = tv; } - (NSView *)textView { return m_textView; } - (NSArray*)getToolbars { NSMutableArray* array = [NSMutableArray array]; const UT_GenericVector & toolbars = m_frame->_getToolbars(); UT_uint32 count = toolbars.getItemCount(); for (UT_uint32 i = 0; i < count; i++) { const EV_CocoaToolbar* tlbr = static_cast(toolbars[i]); UT_ASSERT(tlbr); if (!tlbr->isHidden()) { [array addObject:tlbr->_getToolbarView()]; } } return array; } - (NSString *)getToolbarSummaryID { UT_UTF8String SummaryID; const UT_GenericVector & toolbars = m_frame->_getToolbars(); UT_uint32 count = toolbars.getItemCount(); for (UT_uint32 i = 0; i < count; i++) { const EV_CocoaToolbar * tlbr = static_cast(toolbars[i]); UT_ASSERT(tlbr); if (!tlbr->isHidden()) { SummaryID += "+"; } else { SummaryID += "-"; } } return [NSString stringWithUTF8String:(SummaryID.utf8_str())]; } @end