1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: i18n_status.cxx,v $
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
37 #include <sal/alloca.h>
39 #include <tools/prex.h>
42 #include <tools/postx.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>
57 #include <saldata.hxx>
58 #include <vcl/sysdata.hxx>
65 class StatusWindow
: public WorkWindow
68 StatusWindow( WinBits nWinBits
);
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 // --------------------------------------------------------------------------
96 class XIMStatusWindow
: public StatusWindow
98 FixedText m_aStatusText
;
99 SalFrame
* m_pLastParent
;
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
107 I18NStatus::ShowReason m_eDelayedReason
;
108 ULONG m_nDelayedEvent
;
112 Point
updatePosition();
114 bool checkLastParent() const;
116 DECL_LINK( DelayedShowHdl
, void* );
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 ),
146 XIMStatusWindow::~XIMStatusWindow()
148 if( m_nDelayedEvent
)
149 Application::RemoveUserEvent( m_nDelayedEvent
);
152 void XIMStatusWindow::toggle( bool 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
);
184 SetOutputSizePixel( m_aWindowSize
);
187 bool XIMStatusWindow::checkLastParent() const
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
)
201 void XIMStatusWindow::DataChanged( const DataChangedEvent
& )
203 m_aStatusText
.SetSettings( GetSettings() );
207 Point
XIMStatusWindow::updatePosition()
210 if( checkLastParent() )
212 const SystemEnvData
* pParentEnvData
= m_pLastParent
->GetSystemData();
214 SalExtTextInputPosEvent aPosEvent
;
215 m_pLastParent
->CallCallback( SALEVENT_EXTTEXTINPUTPOS
, (void*)&aPosEvent
);
218 XTranslateCoordinates( (Display
*)pParentEnvData
->pDisplay
,
219 (XLIB_Window
)pParentEnvData
->aShellWindow
,
220 GetX11SalData()->GetDisplay()->GetRootWindow( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ),
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
;
246 aRet
.X() = x
+ aPosEvent
.mnX
+ (bLeft
? -m_aWindowSize
.Width() : 0);
247 aRet
.Y() = y
+ aPosEvent
.mnY
+aPosEvent
.mnHeight
+ nGap
;
250 m_bAnchoredAtRight
= bLeft
;
255 void XIMStatusWindow::setPosition( SalFrame
* pParent
)
259 if( pParent
!= m_pLastParent
)
262 m_pLastParent
= pParent
;
263 Show( FALSE
, SHOW_NOACTIVATE
);
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
)
278 const SystemEnvData
* pData
= GetSystemData();
279 SalFrame
* pStatusFrame
= (SalFrame
*)pData
->pSalFrame
;
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
);
290 XRaiseWindow( (Display
*)pData
->pDisplay
,
291 (XLIB_Window
)pData
->aShellWindow
);
296 void XIMStatusWindow::show( bool bShow
, I18NStatus::ShowReason eReason
)
298 if( bShow
&& ! m_aStatusText
.GetText().Len() )
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 // --------------------------------------------------------------------------
322 class IIIMPStatusWindow
: public StatusWindow
324 MenuButton m_aStatusBtn
;
326 SalFrame
* m_pResetFocus
;
330 DECL_LINK( SelectHdl
, MenuButton
* );
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
);
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
),
359 SetText( String( RTL_CONSTASCII_USTRINGPARAM( "IME Status" ) ) );
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() );
369 for( ::std::vector
< I18NStatus::ChoiceData
>::const_iterator it
= rChoices
.begin(); it
!= rChoices
.end(); ++it
, i
++ )
370 m_aMenu
.InsertItem( i
, it
->aString
);
374 const SystemEnvData
* pEnvData
= GetSystemData();
376 const SalFrameGeometry
& rGeom( pParent
->GetUnmirroredGeometry() );
377 int nDistance
= rGeom
.nTopDecoration
;
380 XMoveWindow( (Display
*)pEnvData
->pDisplay
,
381 (XLIB_Window
)pEnvData
->aShellWindow
,
383 rGeom
.nY
+ rGeom
.nHeight
+ nDistance
386 #if OSL_DEBUG_LEVEL > 1
388 fprintf( stderr
, "Warning: could not reposition status window since no frame\n" );
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
);
409 void IIIMPStatusWindow::DataChanged( const DataChangedEvent
& )
411 m_aStatusBtn
.SetSettings( GetSettings() );
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
429 && eReason
!= I18NStatus::presentation
437 void IIIMPStatusWindow::toggle( bool bOn
)
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();
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
,
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
,
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
,
514 XSync( (Display
*)pEnv
->pDisplay
, False
);
515 pXLib
->PopXErrorLevel();
526 I18NStatus
* I18NStatus::pInstance
= NULL
;
528 I18NStatus
& I18NStatus::get()
531 pInstance
= new I18NStatus();
535 // --------------------------------------------------------------------------
537 bool I18NStatus::exists()
539 return pInstance
!= NULL
;
542 // --------------------------------------------------------------------------
544 void I18NStatus::free()
547 delete pInstance
, pInstance
= NULL
;
550 // --------------------------------------------------------------------------
552 I18NStatus::I18NStatus() :
554 m_pStatusWindow( NULL
)
558 // --------------------------------------------------------------------------
560 I18NStatus::~I18NStatus()
562 if( m_pStatusWindow
)
563 delete m_pStatusWindow
, m_pStatusWindow
= NULL
;
564 if( pInstance
== this )
568 // --------------------------------------------------------------------------
570 void I18NStatus::setParent( SalFrame
* pParent
)
573 if( ! m_pStatusWindow
)
575 bool bIIIMPmode
= m_aChoices
.begin() != m_aChoices
.end();
577 m_pStatusWindow
= new IIIMPStatusWindow( pParent
,
578 getStatusWindowMode() );
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;
614 pBuffer
[i
] = pCopy
[i
];
616 String
aText( pBuffer
);
617 m_pStatusWindow
->setText( aText
);
618 m_pStatusWindow
->setPosition( m_pParent
);
620 bool bVisible
= true;
624 m_pParent
->GetClientSize( w
, h
);
625 if( w
== 0 || h
== 0 )
631 m_pStatusWindow
->show( bVisible
, contextmap
);
635 // --------------------------------------------------------------------------
637 void I18NStatus::changeIM( const String
& rIM
)
642 // --------------------------------------------------------------------------
644 String
I18NStatus::getStatusText() const
646 return m_pStatusWindow
? m_pStatusWindow
->getText() : String();
649 // --------------------------------------------------------------------------
651 void I18NStatus::clearChoices()
656 // --------------------------------------------------------------------------
658 void I18NStatus::addChoice( const String
& rChoice
, void* 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
;
691 bool I18NStatus::canToggleStatusWindow() const
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
:
710 case ImplSVAppData::ImeStatusWindowMode_SHOW
:
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();