/* -*- 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_CocoaCairoGraphics.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" #import "xap_FrameNSWindow.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"; /*****************************************************************/ XAP_CocoaFrameImpl::XAP_CocoaFrameImpl(XAP_Frame* frame) : XAP_FrameImpl (frame), m_dialogFactory(XAP_App::getApp(), frame), m_pCocoaPopup(NULL), m_frameController(nil) { // m_pView = NULL; // dirty hack to make sure the frame is compiled in as the class is only // referenced from a nib. XAP_FrameNSWindow *p = nil; if (0) { p = [[[XAP_FrameNSWindow alloc] init] autorelease]; } } // 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(XAP_App::getApp(), f->m_pFrame), m_pCocoaMenu(NULL), m_pCocoaPopup(NULL), m_frameController(nil) { m_pView = NULL; } */ XAP_CocoaFrameImpl::~XAP_CocoaFrameImpl(void) { // only delete the things we created... 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); } 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:XAP_App::getApp()->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; dynamic_cast(XAP_App::getApp())->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 (XAP_App::getApp()->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]; } } void XAP_CocoaFrameImpl::_rebuildMenus() { #if 0 // destroy old menu m_pUnixMenu->destroy(); DELETEP(m_pUnixMenu); // build new one. m_pUnixMenu = new EV_CocoaMenuBar(static_cast(XAP_App::getApp()), getFrame(), m_szMenuLayoutName, m_szMenuLabelSetName); UT_return_if_fail(m_pUnixMenu); bool bResult = m_pUnixMenu->rebuildMenuBar(); UT_ASSERT_HARMLESS(bResult); #endif UT_ASSERT(UT_NOT_IMPLEMENTED); } /*! * 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_CocoaCairoGraphics::_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(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) { dynamic_cast(XAP_App::getApp())->setTimeOfLastEvent(timestamp); } EV_Toolbar * XAP_CocoaFrameImpl::_newToolbar(XAP_Frame *frame, const char *szLayout, const char *szLanguage) { return (new EV_CocoaToolbar((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 dynamic_cast(XAP_App::getApp())->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_UNUSED(sender); UT_DEBUGMSG (("shouldCloseDocument\n")); UT_ASSERT (m_frame); XAP_App * pApp = XAP_App::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) { XAP_Frame * pFrame = m_frame->getFrame (); UT_ASSERT(pFrame); AV_View * pView = pFrame->getCurrentView(); UT_ASSERT(pView); 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_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_UNUSED(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_UNUSED(aNotification); UT_DEBUGMSG(("windowDidExpose:\n")); // [[NSNotificationCenter defaultCenter] postNotificationName:XAP_CocoaFrameImpl::XAP_FrameNeedToolbar // object:self]; } - (void)windowDidResignKey:(NSNotification *)aNotification { UT_UNUSED(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")); if(![self initWithWindowNibName:frame->_getNibName()]) { /* this one will make the call to [super init] */ return nil; } m_frame = frame; [[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