merge the formfield patch from ooo-build
[ooovba.git] / vcl / unx / source / app / i18n_status.cxx
blobed09d267e4d21fb2d94149a754406cfb68dab6c5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: i18n_status.cxx,v $
10 * $Revision: 1.40 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #if OSL_DEBUG_LEVEL > 1
35 #include <stdio.h>
36 #endif
37 #include <sal/alloca.h>
39 #include <tools/prex.h>
40 #include <X11/Xlib.h>
41 #include <XIM.h>
42 #include <tools/postx.h>
44 #include <salunx.h>
46 #include <i18n_status.hxx>
47 #include <i18n_ic.hxx>
49 #include <vcl/wrkwin.hxx>
50 #include <vcl/fixed.hxx>
51 #include <vcl/menubtn.hxx>
52 #include <vcl/menu.hxx>
53 #include <vcl/svdata.hxx>
54 #include <vcl/svapp.hxx>
55 #include <saldisp.hxx>
56 #include <salframe.h>
57 #include <saldata.hxx>
58 #include <vcl/sysdata.hxx>
60 using namespace vcl;
61 using namespace rtl;
63 namespace vcl {
65 class StatusWindow : public WorkWindow
67 protected:
68 StatusWindow( WinBits nWinBits );
69 public:
70 virtual ~StatusWindow();
72 virtual void setPosition( SalFrame* );
73 virtual void setText( const String & ) = 0;
74 virtual String getText() const = 0;
75 virtual void show( bool bShow, I18NStatus::ShowReason eReason ) = 0;
76 virtual void toggle( bool bOn ) = 0;
81 StatusWindow::StatusWindow( WinBits nWinBits ) :
82 WorkWindow( NULL, nWinBits )
86 StatusWindow::~StatusWindow() {}
88 void StatusWindow::setPosition( SalFrame* )
92 // --------------------------------------------------------------------------
94 namespace vcl {
96 class XIMStatusWindow : public StatusWindow
98 FixedText m_aStatusText;
99 SalFrame* m_pLastParent;
100 Size m_aWindowSize;
101 bool m_bAnchoredAtRight;
102 // true if the right edge (instead of the left edge) should stay at a
103 // fixed position when re-sizing the window
105 // for delayed showing
106 bool m_bDelayedShow;
107 I18NStatus::ShowReason m_eDelayedReason;
108 ULONG m_nDelayedEvent;
109 // for toggling
110 bool m_bOn;
112 Point updatePosition();
113 void layout();
114 bool checkLastParent() const;
116 DECL_LINK( DelayedShowHdl, void* );
117 public:
118 XIMStatusWindow( bool bOn );
119 virtual ~XIMStatusWindow();
121 virtual void setPosition( SalFrame* );
122 virtual void setText( const String & );
123 virtual String getText() const;
124 virtual void show( bool bShow, I18NStatus::ShowReason eReason );
125 virtual void toggle( bool bOn );
127 // overload WorkWindow::DataChanged
128 virtual void DataChanged( const DataChangedEvent& rEvt );
133 XIMStatusWindow::XIMStatusWindow( bool bOn ) :
134 StatusWindow( WB_BORDER | WB_SYSTEMFLOATWIN | WB_TOOLTIPWIN ),
135 m_aStatusText( this, 0 ),
136 m_pLastParent( NULL ),
137 m_bAnchoredAtRight( false ),
138 m_bDelayedShow( false ),
139 m_eDelayedReason( I18NStatus::contextmap ),
140 m_nDelayedEvent( 0 ),
141 m_bOn( bOn )
143 layout();
146 XIMStatusWindow::~XIMStatusWindow()
148 if( m_nDelayedEvent )
149 Application::RemoveUserEvent( m_nDelayedEvent );
152 void XIMStatusWindow::toggle( bool bOn )
154 m_bOn = bOn;
155 show( bOn, I18NStatus::contextmap );
158 void XIMStatusWindow::layout()
160 m_aWindowSize.Width() = m_aStatusText.GetTextWidth( m_aStatusText.GetText() )+8;
161 Font aFont( m_aStatusText.GetFont() );
162 m_aWindowSize.Height() = aFont.GetHeight()+10;
163 m_aWindowSize = LogicToPixel( m_aWindowSize );
165 Size aControlSize( m_aWindowSize );
166 aControlSize.Width() -= 4;
167 aControlSize.Height() -= 4;
169 m_aStatusText.SetPosSizePixel( Point( 1, 1 ), aControlSize );
170 m_aStatusText.SetFont( aFont );
171 m_aStatusText.Show( TRUE );
173 if (m_bAnchoredAtRight && IsVisible())
175 SalFrame* pFrame = (SalFrame*)GetSystemData()->pSalFrame;
176 long nDelta = pFrame->maGeometry.nWidth - m_aWindowSize.Width();
177 pFrame->SetPosSize( pFrame->maGeometry.nX + nDelta,
178 pFrame->maGeometry.nY,
179 m_aWindowSize.Width(),
180 m_aWindowSize.Height(),
181 SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
183 else
184 SetOutputSizePixel( m_aWindowSize );
187 bool XIMStatusWindow::checkLastParent() const
189 if( m_pLastParent )
191 const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
192 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
194 if( *it == m_pLastParent )
195 return true;
198 return false;
201 void XIMStatusWindow::DataChanged( const DataChangedEvent& )
203 m_aStatusText.SetSettings( GetSettings() );
204 layout();
207 Point XIMStatusWindow::updatePosition()
209 Point aRet;
210 if( checkLastParent() )
212 const SystemEnvData* pParentEnvData = m_pLastParent->GetSystemData();
214 SalExtTextInputPosEvent aPosEvent;
215 m_pLastParent->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
216 int x, y;
217 XLIB_Window aChild;
218 XTranslateCoordinates( (Display*)pParentEnvData->pDisplay,
219 (XLIB_Window)pParentEnvData->aShellWindow,
220 GetX11SalData()->GetDisplay()->GetRootWindow( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ),
221 0, 0,
222 &x, &y,
223 &aChild );
225 // TODO: Currently, place the status window to the (physical) left of
226 // the cursor iff in vertical mode (assuming that the columns in
227 // vertical mode are always written from right to left, this causes the
228 // status window to keep out of the text already written). This
229 // heuristic would break if there is ever a vertical mode in which the
230 // columns are written from left to right. Also, more elaborate
231 // positioning for (both horizontal and vertical) left-to-right and
232 // right-to-left text would be possible.
233 bool bLeft = aPosEvent.mbVertical;
234 // true if status window is to the left of the cursor
236 int const nGap = 4; // between cursor and status window
237 if (aPosEvent.mbVertical)
239 aRet.X() = x + aPosEvent.mnX + (bLeft
240 ? -m_aWindowSize.Width() - nGap
241 : aPosEvent.mnHeight + nGap);
242 aRet.Y() = y + aPosEvent.mnY;
244 else
246 aRet.X() = x + aPosEvent.mnX + (bLeft ? -m_aWindowSize.Width() : 0);
247 aRet.Y() = y + aPosEvent.mnY+aPosEvent.mnHeight + nGap;
250 m_bAnchoredAtRight = bLeft;
252 return aRet;
255 void XIMStatusWindow::setPosition( SalFrame* pParent )
257 if( pParent )
259 if( pParent != m_pLastParent )
261 setText( String() );
262 m_pLastParent = pParent;
263 Show( FALSE, SHOW_NOACTIVATE );
265 if( IsVisible() )
267 const SystemEnvData* pEnvData = GetSystemData();
268 SalFrame* pStatusFrame = (SalFrame*)pEnvData->pSalFrame;
269 Point aPoint = updatePosition();
270 pStatusFrame->SetPosSize( aPoint.X(), aPoint.Y(), m_aWindowSize.Width(), m_aWindowSize.Height(), SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
275 IMPL_LINK( XIMStatusWindow, DelayedShowHdl, void*, EMPTYARG )
277 m_nDelayedEvent = 0;
278 const SystemEnvData* pData = GetSystemData();
279 SalFrame* pStatusFrame = (SalFrame*)pData->pSalFrame;
280 if( m_bDelayedShow )
282 Size aControlSize( m_aWindowSize.Width()-4, m_aWindowSize.Height()-4 );
283 m_aStatusText.SetPosSizePixel( Point( 1, 1 ), aControlSize );
284 Point aPoint = updatePosition();
285 pStatusFrame->SetPosSize( aPoint.X(), aPoint.Y(), m_aWindowSize.Width(), m_aWindowSize.Height(), SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
287 Show( m_bDelayedShow && m_bOn, SHOW_NOACTIVATE );
288 if( m_bDelayedShow )
290 XRaiseWindow( (Display*)pData->pDisplay,
291 (XLIB_Window)pData->aShellWindow );
293 return 0;
296 void XIMStatusWindow::show( bool bShow, I18NStatus::ShowReason eReason )
298 if( bShow && ! m_aStatusText.GetText().Len() )
299 bShow = false;
301 m_bDelayedShow = bShow;
302 m_eDelayedReason = eReason;
303 if( ! m_nDelayedEvent )
304 m_nDelayedEvent = Application::PostUserEvent( LINK( this, XIMStatusWindow, DelayedShowHdl ) );
307 void XIMStatusWindow::setText( const String& rText )
309 m_aStatusText.SetText( rText );
310 m_aWindowSize.Width() = m_aStatusText.GetTextWidth( rText )+8;
313 String XIMStatusWindow::getText() const
315 return m_aStatusText.GetText();
318 // --------------------------------------------------------------------------
320 namespace vcl {
322 class IIIMPStatusWindow : public StatusWindow
324 MenuButton m_aStatusBtn;
325 PopupMenu m_aMenu;
326 SalFrame* m_pResetFocus;
327 bool m_bShow;
328 bool m_bOn;
330 DECL_LINK( SelectHdl, MenuButton* );
332 void show();
334 public:
335 IIIMPStatusWindow( SalFrame* pParent, bool bOn ); // for initial position
336 virtual ~IIIMPStatusWindow();
338 virtual void setText( const String & );
339 virtual String getText() const;
340 virtual void show( bool bShow, I18NStatus::ShowReason eReason );
341 virtual void toggle( bool bOn );
342 void layout();
344 // overload Window focus handler
345 virtual void GetFocus();
346 // overload WorkWindow::DataChanged
347 virtual void DataChanged( const DataChangedEvent& rEvt );
352 IIIMPStatusWindow::IIIMPStatusWindow( SalFrame* pParent, bool bOn ) :
353 StatusWindow( WB_MOVEABLE ),
354 m_aStatusBtn( this, WB_BORDER ),
355 m_pResetFocus( pParent ),
356 m_bShow( true ),
357 m_bOn( bOn )
359 SetText( String( RTL_CONSTASCII_USTRINGPARAM( "IME Status" ) ) );
361 layout();
363 m_aStatusBtn.SetSelectHdl( LINK( this, IIIMPStatusWindow, SelectHdl ) );
364 m_aStatusBtn.SetPopupMenu( &m_aMenu );
365 m_aStatusBtn.Show( TRUE );
367 const ::std::vector< I18NStatus::ChoiceData >& rChoices( I18NStatus::get().getChoices() );
368 int i = 1;
369 for( ::std::vector< I18NStatus::ChoiceData >::const_iterator it = rChoices.begin(); it != rChoices.end(); ++it, i++ )
370 m_aMenu.InsertItem( i, it->aString );
372 if( pParent )
374 const SystemEnvData* pEnvData = GetSystemData();
376 const SalFrameGeometry& rGeom( pParent->GetUnmirroredGeometry() );
377 int nDistance = rGeom.nTopDecoration;
378 if( nDistance < 20 )
379 nDistance = 20;
380 XMoveWindow( (Display*)pEnvData->pDisplay,
381 (XLIB_Window)pEnvData->aShellWindow,
382 rGeom.nX,
383 rGeom.nY + rGeom.nHeight + nDistance
386 #if OSL_DEBUG_LEVEL > 1
387 else
388 fprintf( stderr, "Warning: could not reposition status window since no frame\n" );
389 #endif
390 EnableAlwaysOnTop( TRUE );
393 IIIMPStatusWindow::~IIIMPStatusWindow()
397 void IIIMPStatusWindow::layout()
399 Font aFont( m_aStatusBtn.GetFont() );
400 Size aSize( 15*aFont.GetHeight(), aFont.GetHeight()+14 );
401 aSize = m_aStatusBtn.LogicToPixel( aSize );
403 m_aStatusBtn.SetPosSizePixel( Point( 0, 0 ), aSize );
404 SetOutputSizePixel( aSize );
405 if( IsVisible() )
406 Invalidate();
409 void IIIMPStatusWindow::DataChanged( const DataChangedEvent& )
411 m_aStatusBtn.SetSettings( GetSettings() );
412 layout();
415 void IIIMPStatusWindow::setText( const String& rText )
417 m_aStatusBtn.SetText( rText );
420 String IIIMPStatusWindow::getText() const
422 return m_aStatusBtn.GetText();
425 void IIIMPStatusWindow::show( bool bShow, I18NStatus::ShowReason eReason )
427 // hide IIIMPStatusWindow only in presentations
428 if( ! bShow
429 && eReason != I18NStatus::presentation
431 return;
433 m_bShow = bShow;
434 show();
437 void IIIMPStatusWindow::toggle( bool bOn )
439 if (bOn != m_bOn)
441 m_bOn = bOn;
442 show();
446 void IIIMPStatusWindow::show()
448 if (m_bOn && m_bShow && !IsVisible())
449 m_pResetFocus = I18NStatus::get().getParent();
450 Show(m_bOn && m_bShow);
453 void IIIMPStatusWindow::GetFocus()
456 * this is here just to put the focus back to the application
457 * window at startup on clickToFocus WMs
459 WorkWindow::GetFocus();
460 if( m_pResetFocus )
463 * look if reset focus still exists
464 * since reset focus really is an internal hack there should
465 * not be a method to be called in SalFrame destructor
467 const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
468 std::list< SalFrame* >::const_iterator it;
469 for( it = rFrames.begin(); it != rFrames.end() && *it != m_pResetFocus; ++it )
471 if( it != rFrames.end() )
473 const SystemEnvData* pParentEnvData = m_pResetFocus->GetSystemData();
474 SalXLib* pXLib = GetX11SalData()->GetDisplay()->GetXLib();
475 pXLib->PushXErrorLevel( true );
476 XSetInputFocus( (Display*)pParentEnvData->pDisplay,
477 (XLIB_Window)pParentEnvData->aShellWindow,
478 RevertToNone,
479 CurrentTime
481 XSync( (Display*)pParentEnvData->pDisplay, False );
482 pXLib->PopXErrorLevel();
484 m_pResetFocus = NULL;
488 // --------------------------------------------------------------------------
490 IMPL_LINK( IIIMPStatusWindow, SelectHdl, MenuButton*, pBtn )
492 if( pBtn == & m_aStatusBtn )
494 const ::std::vector< I18NStatus::ChoiceData >& rChoices( I18NStatus::get().getChoices() );
495 unsigned int nIndex = m_aStatusBtn.GetCurItemId()-1;
496 if( nIndex < rChoices.size() )
498 XSetICValues( static_cast<X11SalFrame*>(I18NStatus::get().getParent())->getInputContext()->GetContext(),
499 XNUnicodeCharacterSubset,
500 rChoices[nIndex].pData,
501 NULL);
502 // FIXME: get rid of X11SalFrame
503 X11SalFrame* pParent = static_cast<X11SalFrame*>(I18NStatus::get().getParent());
504 if( pParent && pParent->isMapped() )
506 const SystemEnvData* pEnv = pParent->GetSystemData();
507 SalXLib* pXLib = GetX11SalData()->GetDisplay()->GetXLib();
508 pXLib->PushXErrorLevel( true );
509 XSetInputFocus( (Display*)pEnv->pDisplay,
510 (XLIB_Window)pEnv->aShellWindow,
511 RevertToNone,
512 CurrentTime
514 XSync( (Display*)pEnv->pDisplay, False );
515 pXLib->PopXErrorLevel();
519 return 0;
523 * I18NStatus
526 I18NStatus* I18NStatus::pInstance = NULL;
528 I18NStatus& I18NStatus::get()
530 if( ! pInstance )
531 pInstance = new I18NStatus();
532 return *pInstance;
535 // --------------------------------------------------------------------------
537 bool I18NStatus::exists()
539 return pInstance != NULL;
542 // --------------------------------------------------------------------------
544 void I18NStatus::free()
546 if( pInstance )
547 delete pInstance, pInstance = NULL;
550 // --------------------------------------------------------------------------
552 I18NStatus::I18NStatus() :
553 m_pParent( NULL ),
554 m_pStatusWindow( NULL )
558 // --------------------------------------------------------------------------
560 I18NStatus::~I18NStatus()
562 if( m_pStatusWindow )
563 delete m_pStatusWindow, m_pStatusWindow = NULL;
564 if( pInstance == this )
565 pInstance = NULL;
568 // --------------------------------------------------------------------------
570 void I18NStatus::setParent( SalFrame* pParent )
572 m_pParent = pParent;
573 if( ! m_pStatusWindow )
575 bool bIIIMPmode = m_aChoices.begin() != m_aChoices.end();
576 if( bIIIMPmode )
577 m_pStatusWindow = new IIIMPStatusWindow( pParent,
578 getStatusWindowMode() );
579 else
580 m_pStatusWindow = new XIMStatusWindow( getStatusWindowMode() );
581 setStatusText( m_aCurrentIM );
583 m_pStatusWindow->setPosition( m_pParent );
586 // --------------------------------------------------------------------------
588 void I18NStatus::show( bool bShow, ShowReason eReason )
590 if( m_pStatusWindow )
592 m_pStatusWindow->setPosition( m_pParent );
593 m_pStatusWindow->show( bShow, eReason );
597 // --------------------------------------------------------------------------
599 void I18NStatus::setStatusText( const String& rText )
601 if( m_pStatusWindow )
604 * #93614# convert fullwidth ASCII forms to ascii
606 int nChars = rText.Len()+1;
607 sal_Unicode* pBuffer = (sal_Unicode*)alloca( nChars*sizeof( sal_Unicode ) );
608 const sal_Unicode* pCopy = rText.GetBuffer();
609 for( int i = 0; i < nChars; i++ )
611 if( pCopy[i] >=0xff00 && pCopy[i] <= 0xff5f )
612 pBuffer[i] = (pCopy[i] & 0xff) + 0x20;
613 else
614 pBuffer[i] = pCopy[i];
616 String aText( pBuffer );
617 m_pStatusWindow->setText( aText );
618 m_pStatusWindow->setPosition( m_pParent );
620 bool bVisible = true;
621 if( m_pParent )
623 long w, h;
624 m_pParent->GetClientSize( w, h );
625 if( w == 0 || h == 0 )
627 bVisible = false;
631 m_pStatusWindow->show( bVisible, contextmap );
635 // --------------------------------------------------------------------------
637 void I18NStatus::changeIM( const String& rIM )
639 m_aCurrentIM = rIM;
642 // --------------------------------------------------------------------------
644 String I18NStatus::getStatusText() const
646 return m_pStatusWindow ? m_pStatusWindow->getText() : String();
649 // --------------------------------------------------------------------------
651 void I18NStatus::clearChoices()
653 m_aChoices.clear();
656 // --------------------------------------------------------------------------
658 void I18NStatus::addChoice( const String& rChoice, void* pData )
660 ChoiceData aData;
661 aData.pData = pData;
662 aData.aString = rChoice;
663 m_aChoices.push_back( aData );
666 // --------------------------------------------------------------------------
668 void I18NStatus::toTop() const
670 if( m_pStatusWindow )
672 const SystemEnvData* pData = m_pStatusWindow->GetSystemData();
673 XRaiseWindow( (Display*)pData->pDisplay,
674 (XLIB_Window)pData->aShellWindow );
678 // --------------------------------------------------------------------------
680 SalFrame* I18NStatus::getStatusFrame() const
682 SalFrame* pRet = NULL;
683 if( m_pStatusWindow )
685 const SystemEnvData* pData = m_pStatusWindow->GetSystemData();
686 pRet = (SalFrame*)pData->pSalFrame;
688 return pRet;
691 bool I18NStatus::canToggleStatusWindow() const
693 return true;
696 void I18NStatus::toggleStatusWindow()
698 if (m_pStatusWindow != 0)
699 m_pStatusWindow->toggle(getStatusWindowMode());
702 bool I18NStatus::getStatusWindowMode()
704 switch (ImplGetSVData()->maAppData.meShowImeStatusWindow)
706 default: // ImplSVAppData::ImeStatusWindowMode_UNKNOWN
707 return Application::GetShowImeStatusWindowDefault();
708 case ImplSVAppData::ImeStatusWindowMode_HIDE:
709 return false;
710 case ImplSVAppData::ImeStatusWindowMode_SHOW:
711 return true;
716 * X11ImeStatus
718 X11ImeStatus::~X11ImeStatus()
720 vcl::I18NStatus::free();
723 bool X11ImeStatus::canToggle()
725 return vcl::I18NStatus::get().canToggleStatusWindow();
728 void X11ImeStatus::toggle()
730 vcl::I18NStatus::get().toggleStatusWindow();
733 SalI18NImeStatus* X11SalInstance::CreateI18NImeStatus()
735 return new X11ImeStatus();