diff options
-rw-r--r-- | vcl/unx/gtk/window/gtkframe.cxx | 1491 |
1 files changed, 1491 insertions, 0 deletions
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx new file mode 100644 index 000000000000..8a649ad4d851 --- /dev/null +++ b/vcl/unx/gtk/window/gtkframe.cxx @@ -0,0 +1,1491 @@ +/************************************************************************* + * + * $RCSfile: gtkframe.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: obo $ $Date: 2004-02-20 08:54:05 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <plugins/gtk/gtkframe.hxx> +#include <plugins/gtk/gtkdata.hxx> +#include <plugins/gtk/gtkinst.hxx> +#include <keycodes.hxx> +#include <wmadaptor.hxx> +#include <salgdi.h> +#include <salbmp.h> + +#include <prex.h> +#include <X11/Xatom.h> +#include <postx.h> + +// Unfortunate: +#include <dlfcn.h> +#include <soicon.hxx> + +static USHORT GetModCode( guint state ) +{ + USHORT nCode = 0; + if( (state & GDK_SHIFT_MASK) ) + nCode |= KEY_SHIFT; + if( (state & GDK_CONTROL_MASK) ) + nCode |= KEY_MOD1; + if( (state & GDK_MOD1_MASK) ) + { + nCode |= KEY_MOD2; + if( (state & GDK_MOD1_MASK) ) + nCode |= KEY_CONTROLMOD; + } + if( (state & GDK_BUTTON1_MASK) ) + nCode |= MOUSE_LEFT; + if( (state & GDK_BUTTON2_MASK) ) + nCode |= MOUSE_MIDDLE; + if( (state & GDK_BUTTON3_MASK) ) + nCode |= MOUSE_RIGHT; + return nCode; +} + +static USHORT GetKeyCode( guint keyval ) +{ + USHORT nCode = 0; + if( keyval >= GDK_0 && keyval <= GDK_9 ) + nCode = KEY_0 + (keyval-GDK_0); + else if( keyval >= GDK_A && keyval <= GDK_Z ) + nCode = KEY_A + (keyval-GDK_A ); + else if( keyval >= GDK_a && keyval <= GDK_z ) + nCode = KEY_A + (keyval-GDK_a ); + else if( keyval >= GDK_F1 && keyval <= GDK_F26 ) + nCode = KEY_F1 + (keyval-GDK_F1); + + { + switch( keyval ) + { + case GDK_KP_Down: + case GDK_Down: nCode = KEY_DOWN; break; + case GDK_KP_Up: + case GDK_Up: nCode = KEY_UP; break; + case GDK_KP_Left: + case GDK_Left: nCode = KEY_LEFT; break; + case GDK_KP_Right: + case GDK_Right: nCode = KEY_RIGHT; break; + case GDK_KP_Home: + case GDK_Home: nCode = KEY_HOME; break; + case GDK_KP_End: + case GDK_End: nCode = KEY_END; break; + case GDK_KP_Page_Up: + case GDK_Page_Up: nCode = KEY_PAGEUP; break; + case GDK_KP_Page_Down: + case GDK_Page_Down: nCode = KEY_PAGEDOWN; break; + case GDK_KP_Enter: + case GDK_Return: nCode = KEY_RETURN; break; + case GDK_Escape: nCode = KEY_ESCAPE; break; + case GDK_ISO_Left_Tab: + case GDK_KP_Tab: + case GDK_Tab: nCode = KEY_TAB; break; + case GDK_BackSpace: nCode = KEY_BACKSPACE; break; + case GDK_KP_Space: + case GDK_space: nCode = KEY_SPACE; break; + case GDK_Insert: nCode = KEY_INSERT; break; + case GDK_Delete: nCode = KEY_DELETE; break; + case GDK_KP_Add: nCode = KEY_ADD; break; + case GDK_KP_Subtract: nCode = KEY_SUBTRACT; break; + case GDK_KP_Multiply: nCode = KEY_MULTIPLY; break; + case GDK_KP_Divide: nCode = KEY_DIVIDE; break; + case GDK_period: + case GDK_decimalpoint: nCode = KEY_POINT; break; + case GDK_comma: nCode = KEY_COMMA; break; + case GDK_less: nCode = KEY_LESS; break; + case GDK_greater: nCode = KEY_GREATER; break; + case GDK_equal: nCode = KEY_EQUAL; break; + case GDK_Find: nCode = KEY_FIND; break; + case GDK_Menu: nCode = KEY_MENU; break; + case GDK_Help: nCode = KEY_HELP; break; + case GDK_Undo: nCode = KEY_UNDO; break; + } + } + return nCode; +} + +GtkSalFrame::GraphicsHolder::~GraphicsHolder() +{ + delete pGraphics; +} + +GtkSalFrame::GtkSalFrame( SalFrame* pParent, ULONG nStyle ) +{ + getDisplay()->registerFrame( this ); + Init( pParent, nStyle ); +} + +GtkSalFrame::GtkSalFrame( SystemParentData* pSysData ) +{ + getDisplay()->registerFrame( this ); + Init( pSysData ); +} + +GtkSalFrame::~GtkSalFrame() +{ + getDisplay()->deregisterFrame( this ); + if( m_pIMContext ) + { + gtk_im_context_reset( m_pIMContext ); + gtk_im_context_set_client_window( m_pIMContext, NULL ); + g_object_unref( m_pIMContext ); + } + if( m_pFixedContainer ) + gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) ); + if( m_pWindow ) + gtk_widget_destroy( GTK_WIDGET(m_pWindow) ); +} + +void GtkSalFrame::InitCommon() +{ + // connect signals + g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this ); + g_signal_connect( G_OBJECT(m_pWindow), "button-press-event", G_CALLBACK(signalButton), this ); + g_signal_connect( G_OBJECT(m_pWindow), "button-release-event", G_CALLBACK(signalButton), this ); + g_signal_connect( G_OBJECT(m_pWindow), "expose-event", G_CALLBACK(signalExpose), this ); + g_signal_connect( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this ); + g_signal_connect( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this ); + g_signal_connect( G_OBJECT(m_pWindow), "map-event", G_CALLBACK(signalMap), this ); + g_signal_connect( G_OBJECT(m_pWindow), "unmap-event", G_CALLBACK(signalUnmap), this ); + g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this ); + g_signal_connect( G_OBJECT(m_pWindow), "motion-notify-event", G_CALLBACK(signalMotion), this ); + g_signal_connect( G_OBJECT(m_pWindow), "key-press-event", G_CALLBACK(signalKey), this ); + g_signal_connect( G_OBJECT(m_pWindow), "key-release-event", G_CALLBACK(signalKey), this ); + g_signal_connect( G_OBJECT(m_pWindow), "delete-event", G_CALLBACK(signalDelete), this ); + g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalState), this ); + g_signal_connect( G_OBJECT(m_pWindow), "scroll-event", G_CALLBACK(signalScroll), this ); + g_signal_connect( G_OBJECT(m_pWindow), "leave-notify-event", G_CALLBACK(signalCrossing), this ); + g_signal_connect( G_OBJECT(m_pWindow), "enter-notify-event", G_CALLBACK(signalCrossing), this ); + + // init members + m_pCurrentCursor = NULL; + m_nKeyModifiers = 0; + m_bSingleAltPress = false; + m_bResizeable = true; + m_bDefaultPos = true; + m_bDefaultSize = ( (m_nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! m_pParent ); + m_nState = GDK_WINDOW_STATE_WITHDRAWN; + m_bSendModChangeOnRelease = false; + m_pIMContext = NULL; + // delete graphics if InitCommon is called not from destructor + for( int i = 0; i < nMaxGraphics; i++ ) + { + m_aGraphics[i].bInUse = false; + delete m_aGraphics[i].pGraphics; + m_aGraphics[i].pGraphics = NULL; + } + + gtk_widget_set_app_paintable( GTK_WIDGET(m_pWindow), TRUE ); + gtk_widget_set_double_buffered( GTK_WIDGET(m_pWindow), FALSE ); + gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_pWindow), FALSE ); + + // realize the window, we need an XWindow id + gtk_widget_realize( GTK_WIDGET(m_pWindow) ); + + // add the fixed container child, + // fixed is needed since we have to position plugin windows + m_pFixedContainer = GTK_FIXED(gtk_fixed_new()); + gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) ); + gtk_widget_show( GTK_WIDGET(m_pFixedContainer) ); + + //system data + SalDisplay* pDisp = GetSalData()->GetDefDisp(); + m_aSystemData.pDisplay = pDisp->GetDisplay(); + m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(GTK_WIDGET(m_pWindow)->window); + m_aSystemData.pSalFrame = this; + m_aSystemData.pWidget = GTK_WIDGET(m_pWindow); + m_aSystemData.pVisual = pDisp->GetVisual()->GetVisual(); + m_aSystemData.nDepth = pDisp->GetVisual()->GetDepth(); + m_aSystemData.aColormap = pDisp->GetColormap().GetXColormap(); + m_aSystemData.pAppContext = NULL; + m_aSystemData.aShellWindow = m_aSystemData.aWindow; + m_aSystemData.pShellWidget = m_aSystemData.pWidget; + + gtk_widget_add_events( GTK_WIDGET(m_pWindow), + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK + ); + + // fake an initial geometry, gets updated via configure event or SetPosSize + maGeometry.nX = -1; + maGeometry.nY = -1; + maGeometry.nWidth = 600; + maGeometry.nHeight = 400; + if( m_pParent ) + { + // approximation + maGeometry.nTopDecoration = m_pParent->maGeometry.nTopDecoration; + maGeometry.nBottomDecoration = m_pParent->maGeometry.nBottomDecoration; + maGeometry.nLeftDecoration = m_pParent->maGeometry.nLeftDecoration; + maGeometry.nRightDecoration = m_pParent->maGeometry.nRightDecoration; + } + else + { + maGeometry.nTopDecoration = 0; + maGeometry.nBottomDecoration = 0; + maGeometry.nLeftDecoration = 0; + maGeometry.nRightDecoration = 0; + } +} + +void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle ) +{ + if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style + { + nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE; + nStyle &= ~SAL_FRAME_STYLE_FLOAT; + } + + m_pWindow = GTK_WINDOW( gtk_window_new( (nStyle & SAL_FRAME_STYLE_FLOAT) ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL ) ); + m_pParent = static_cast<GtkSalFrame*>(pParent); + m_nStyle = nStyle; + + if( m_pParent && m_pParent->m_pWindow ) + gtk_window_set_screen( m_pWindow, gtk_window_get_screen( m_pParent->m_pWindow ) ); + + InitCommon(); + + if( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ) + { + m_bResizeable = (nStyle & SAL_FRAME_STYLE_SIZEABLE) != 0; + gtk_window_set_resizable( m_pWindow, m_bResizeable ? TRUE : FALSE ); + gtk_window_set_gravity( m_pWindow, GDK_GRAVITY_STATIC ); + if( (nStyle & SAL_FRAME_STYLE_INTRO) ) + gtk_window_set_type_hint( m_pWindow, GDK_WINDOW_TYPE_HINT_SPLASHSCREEN ); + else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) ) + gtk_window_set_type_hint( m_pWindow, GDK_WINDOW_TYPE_HINT_UTILITY ); + if( ! (nStyle & (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE ) ) ) + gtk_window_set_decorated( m_pWindow, FALSE ); + if( m_pParent ) + gtk_window_set_transient_for( m_pWindow, m_pParent->m_pWindow ); + } +} + +void GtkSalFrame::Init( SystemParentData* pSysData ) +{ + m_pParent = NULL; + m_pWindow = GTK_WINDOW(gtk_plug_new((GdkNativeWindow)pSysData->aWindow)); + m_nStyle = SAL_FRAME_STYLE_CHILD; + InitCommon(); +} + +SalGraphics* GtkSalFrame::GetGraphics() +{ + if( m_pWindow ) + { + for( int i = 0; i < nMaxGraphics; i++ ) + { + if( ! m_aGraphics[i].bInUse ) + { + m_aGraphics[i].bInUse = true; + if( ! m_aGraphics[i].pGraphics ) + { + m_aGraphics[i].pGraphics = new X11SalGraphics(); + m_aGraphics[i].pGraphics->Init( this, GDK_WINDOW_XWINDOW(GTK_WIDGET(m_pWindow)->window) ); + } + return m_aGraphics[i].pGraphics; + } + } + } + + return NULL; +} + +void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics ) +{ + for( int i = 0; i < nMaxGraphics; i++ ) + { + if( m_aGraphics[i].pGraphics == pGraphics ) + { + m_aGraphics[i].bInUse = false; + break; + } + } +} + +BOOL GtkSalFrame::PostEvent( void* pData ) +{ + getDisplay()->SendInternalEvent( this, pData ); + return TRUE; +} + +void GtkSalFrame::SetTitle( const String& rTitle ) +{ + if( m_pWindow ) + gtk_window_set_title( m_pWindow, rtl::OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() ); +} + +void GtkSalFrame::SetIcon( USHORT nIcon ) +{ + GList *pPixbufs = NULL; + + // pl: evil ? don't be scared so easily :-) + { // Begin this unutterably evil; we need to pass a nice handle down + VCL_CUSTOM_ICON_FN *pCustomIcon = 0; + char *pSymbol = g_strdup_printf ("%s%d", VCL_CUSTOM_ICON_BASE, nIcon ); + void *pAppHdl = dlopen( NULL, RTLD_LAZY ); + if ( ( pCustomIcon = ( VCL_CUSTOM_ICON_FN* ) dlsym( pAppHdl, pSymbol ) ) ) + { + char **pIcons[4] = { NULL, NULL, NULL, NULL }; + pCustomIcon( pIcons[0], pIcons[1], pIcons[2], pIcons[3] ); + for( int i = 0; i < 4; i++) + { + if( pIcons[i] ) + { + GdkPixbuf *pPixbuf = gdk_pixbuf_new_from_xpm_data( (const char **) pIcons[i] ); + pPixbufs = g_list_prepend( pPixbufs, pPixbuf ); + } + } + } + g_free( pSymbol ); + dlclose( pAppHdl ); + } // End evilness + + gtk_window_set_icon_list( m_pWindow, pPixbufs ); + + g_list_foreach( pPixbufs, (GFunc) g_object_unref, NULL ); + g_list_free( pPixbufs ); +} + +void GtkSalFrame::SetMenu( SalMenu* pSalMenu ) +{ +} + +void GtkSalFrame::DrawMenuBar() +{ +} + +void GtkSalFrame::Center() +{ + long nX, nY; + + if( m_pParent ) + { + nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2; + nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2; + + } + else + { + long nScreenWidth, nScreenHeight; + long nScreenX = 0, nScreenY = 0; + + nScreenWidth = GetSalData()->GetDefDisp()->GetScreenSize().Width(); + nScreenHeight = GetSalData()->GetDefDisp()->GetScreenSize().Height(); + if( GetSalData()->GetDefDisp()->IsXinerama() ) + { + // get xinerama screen we are on + // if there is a parent, use its center for screen determination + // else use the pointer + GdkScreen* pScreen; + gint x, y; + GdkModifierType aMask; + gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask ); + + const std::vector< Rectangle >& rScreens = GetSalData()->GetDefDisp()->GetXineramaScreens(); + for( int i = 0; i < rScreens.size(); i++ ) + if( rScreens[i].IsInside( Point( x, y ) ) ) + { + nScreenX = rScreens[i].Left(); + nScreenY = rScreens[i].Top(); + nScreenWidth = rScreens[i].GetWidth(); + nScreenHeight = rScreens[i].GetHeight(); + break; + } + } + nX = nScreenX + (nScreenWidth - (long)maGeometry.nWidth)/2; + nY = nScreenY + (nScreenHeight - (long)maGeometry.nHeight)/2; + } + SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ); +} + +void GtkSalFrame::SetDefaultSize() +{ + const Size& rScreenSize( getDisplay()->GetScreenSize() ); + long w = rScreenSize.Width(); + long h = rScreenSize.Height(); + + // fill in holy default values brought to us by product management + if( rScreenSize.Width() >= 800 ) + w = 785; + if( rScreenSize.Width() >= 1024 ) + w = 920; + + if( rScreenSize.Height() >= 600 ) + h = 550; + if( rScreenSize.Height() >= 768 ) + h = 630; + if( rScreenSize.Height() >= 1024 ) + h = 875; + + SetPosSize( 0, 0, w, h, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT ); +} + +void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate ) +{ + if( m_pWindow ) + { + if( bVisible ) + { + if( m_bDefaultPos ) + Center(); + if( m_bDefaultSize ) + SetDefaultSize(); + gtk_widget_show( GTK_WIDGET(m_pWindow) ); + } + else + { + gtk_widget_hide( GTK_WIDGET(m_pWindow) ); + if( m_pIMContext ) + { + gtk_im_context_focus_out( m_pIMContext ); + gtk_im_context_reset( m_pIMContext ); + } + } + } +} + +void GtkSalFrame::Enable( BOOL bEnable ) +{ + // Not implemented by X11SalFrame either +} + +void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight ) +{ + if( m_pWindow ) + gtk_widget_set_size_request( GTK_WIDGET(m_pWindow), nWidth, nHeight ); +} + +void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags ) +{ + if( !m_pWindow ) + return; + + if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) && + (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen + ) + { +#if OSL_DEBUG_LEVEL > 1 + if( nWidth < 2 || nWidth > 2000 || nHeight < 2 || nHeight > 2000 ) + { + fprintf( stderr, "Discarding bad size: %d, %d\n", nWidth, nHeight ); + return; + } +#endif + m_bDefaultSize = false; + gtk_window_resize( m_pWindow, nWidth, nHeight ); + if( ! m_bResizeable ) + { + GdkGeometry aGeo; + aGeo.min_width = aGeo.max_width = nWidth; + aGeo.min_height = aGeo.max_height = nHeight; + gtk_window_set_geometry_hints + ( m_pWindow, NULL, &aGeo, + (GdkWindowHints) ( GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE ) ); + } + + maGeometry.nWidth = nWidth; + maGeometry.nHeight = nHeight; + } + else if( m_bDefaultSize ) + SetDefaultSize(); + + m_bDefaultSize = false; + + if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) + { +#if OSL_DEBUG_LEVEL > 1 + if( std::abs( nX ) > 2000 || std::abs( nY ) > 2000 ) + { + fprintf( stderr, "Discarding bad pos: %d, %d\n", nX, nY ); + return; + } +#endif + if( m_pParent ) + { + nX += m_pParent->maGeometry.nX; + nY += m_pParent->maGeometry.nY; + } + + // adjust position to avoid off screen windows + Size aScreenSize = GetSalData()->GetDefDisp()->GetScreenSize(); + if( nX < (long)maGeometry.nLeftDecoration ) + nX = maGeometry.nLeftDecoration; + if( nY < (long)maGeometry.nTopDecoration ) + nY = maGeometry.nTopDecoration; + if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() ) + nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration; + if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() ) + nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration; + + m_bDefaultPos = false; + gtk_window_move( m_pWindow, nX, nY ); + maGeometry.nX = nX; + maGeometry.nY = nY; + } + else if( m_bDefaultPos ) + Center(); + + m_bDefaultPos = false; +} + +void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight ) +{ + if( GTK_WIDGET_MAPPED( GTK_WIDGET(m_pWindow) ) ) + { + rWidth = maGeometry.nWidth; + rHeight = maGeometry.nHeight; + } + else + rWidth = rHeight = 0; +} + +void GtkSalFrame::GetWorkArea( Rectangle& rRect ) +{ + rRect = GetSalData()->GetDefDisp()->getWMAdaptor()->getWorkArea( 0 ); +} + +SalFrame* GtkSalFrame::GetParent() const +{ + return m_pParent; +} + +void GtkSalFrame::SetWindowState( const SalFrameState* pState ) +{ + if( ! m_pWindow || ! pState ) + return; + + if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) ) + { + USHORT nPosSizeFlags = 0; + long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0); + long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0); + long nWidth = pState->mnWidth; + long nHeight = pState->mnHeight; + if( pState->mnMask & SAL_FRAMESTATE_MASK_X ) + nPosSizeFlags |= SAL_FRAME_POSSIZE_X; + else + nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0); + if( pState->mnMask & SAL_FRAMESTATE_MASK_Y ) + nPosSizeFlags |= SAL_FRAME_POSSIZE_Y; + else + nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0); + if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH ) + nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH; + else + nWidth = maGeometry.nWidth; + if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT ) + nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT; + else + nHeight = maGeometry.nHeight; + SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags ); + } + if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE ) + { + if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED ) + gtk_window_maximize( m_pWindow ); + if( pState->mnState & SAL_FRAMESTATE_MINIMIZED ) + gtk_window_iconify( m_pWindow ); + } +} + +BOOL GtkSalFrame::GetWindowState( SalFrameState* pState ) +{ + pState->mnState = SAL_FRAMESTATE_NORMAL; + if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) || + (m_nState & GDK_WINDOW_STATE_WITHDRAWN) + ) + pState->mnState |= SAL_FRAMESTATE_MINIMIZED; + if( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) + pState->mnState |= SAL_FRAMESTATE_MAXIMIZED; + // rollup ? gtk 2.2 does not seem to support the shaded state + + pState->mnX = maGeometry.nX; + pState->mnY = maGeometry.nY; + pState->mnWidth = maGeometry.nWidth; + pState->mnHeight = maGeometry.nHeight; + pState->mnMask = + SAL_FRAMESTATE_MASK_X | + SAL_FRAMESTATE_MASK_Y | + SAL_FRAMESTATE_MASK_WIDTH | + SAL_FRAMESTATE_MASK_HEIGHT | + SAL_FRAMESTATE_MASK_STATE; + +#if OSL_DEBUG_LEVEL > 1 + if( std::abs( maGeometry.nX ) > 2000 || std::abs( maGeometry.nY ) > 2000 ) + { + fprintf( stderr, "bad pos in GetWindowState: %d, %d\n", maGeometry.nX, maGeometry.nY ); + abort(); + } + if( maGeometry.nWidth < 2 || maGeometry.nWidth > 2000 || maGeometry.nHeight < 2 || maGeometry.nHeight > 2000 ) + { + fprintf( stderr, "bad size in GetWindowState: %d, %d\n", maGeometry.nWidth, maGeometry.nHeight ); + abort(); + } +#endif + + return TRUE; +} + +void GtkSalFrame::ShowFullScreen( BOOL bFullScreen ) +{ + if( m_pWindow ) + { + if( bFullScreen ) + { + if( ! m_bResizeable ) + gtk_window_set_resizable( m_pWindow, TRUE ); + gtk_window_fullscreen( m_pWindow ); + } + else + { + gtk_window_unfullscreen( m_pWindow ); + if( ! m_bResizeable ) + gtk_window_set_resizable( m_pWindow, FALSE ); + } + } +} + +/* definitions from xautolock.c (pl15) */ +#define XAUTOLOCK_DISABLE 1 +#define XAUTOLOCK_ENABLE 2 + +void GtkSalFrame::setAutoLock( bool bLock ) +{ + GdkScreen *pScreen = gtk_window_get_screen( m_pWindow ); + GdkDisplay *pDisplay = gdk_screen_get_display( pScreen ); + GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen ); + + Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ), + "XAUTOLOCK_MESSAGE", False ); + + int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE; + + XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ), + GDK_WINDOW_XID( pRootWin ), + nAtom, XA_INTEGER, + 8, PropModeReplace, + (unsigned char*)&nMessage, + sizeof( nMessage ) ); +} + +void GtkSalFrame::StartPresentation( BOOL bStart ) +{ + Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() ); + + setAutoLock( !bStart ); + + int nTimeout, nInterval, bPreferBlanking, bAllowExposures; + + XGetScreenSaver( pDisplay, &nTimeout, &nInterval, + &bPreferBlanking, &bAllowExposures ); + if( bStart ) + { + if ( nTimeout ) + { + m_nSavedScreenSaverTimeout = nTimeout; + XResetScreenSaver( pDisplay ); + XSetScreenSaver( pDisplay, 0, nInterval, + bPreferBlanking, bAllowExposures ); + } + } + else + { + if( m_nSavedScreenSaverTimeout ) + XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout, + nInterval, bPreferBlanking, + bAllowExposures ); + m_nSavedScreenSaverTimeout = 0; + } +} + +void GtkSalFrame::SetAlwaysOnTop( BOOL bOnTop ) +{ +} + +void GtkSalFrame::ToTop( USHORT nFlags ) +{ + if( m_pWindow ) + gtk_window_present( m_pWindow ); +} + +void GtkSalFrame::SetPointer( PointerStyle ePointerStyle ) +{ + GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle ); + gdk_window_set_cursor( GTK_WIDGET( m_pWindow )->window, pCursor ); + m_pCurrentCursor = pCursor; +} + +void GtkSalFrame::grabPointer( BOOL bGrab ) +{ + int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK ); + GdkGrabStatus nStatus; + + if( bGrab ) + nStatus = gdk_pointer_grab + ( GTK_WIDGET( m_pWindow )->window, FALSE, + (GdkEventMask) nMask, NULL, m_pCurrentCursor, + GDK_CURRENT_TIME ); + else + { + // Two GdkDisplays may be open + g_assert(gdk_display_pointer_is_grabbed (getGdkDisplay())); + gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME); + } +} + +void GtkSalFrame::CaptureMouse( BOOL bCapture ) +{ + getDisplay()->CaptureMouse( bCapture ? this : NULL ); +} + +void GtkSalFrame::SetPointerPos( long nX, long nY ) +{ + GdkScreen *pScreen = gtk_window_get_screen ( m_pWindow ); + GdkDisplay *pDisplay = gdk_screen_get_display( pScreen ); + + /* #87921# when the application tries to center the mouse in the dialog the + * window isn't mapped already. So use coordinates relative to the root window. + */ + unsigned int nWindowLeft = maGeometry.nX + nX; + unsigned int nWindowTop = maGeometry.nY + nY; + + XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None, + GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ), + 0, 0, 0, 0, nWindowLeft, nWindowTop); +} + +void GtkSalFrame::Flush() +{ + GdkScreen *pScreen = gtk_window_get_screen ( m_pWindow ); + GdkDisplay *pDisplay = gdk_screen_get_display( pScreen ); +#ifdef HAVE_A_RECENT_GTK + gdk_display_flush( gdk_screen_get_display( pScreen ) ); +#else + XFlush (GDK_DISPLAY_XDISPLAY (pDisplay)); +#endif +} + +void GtkSalFrame::Sync() +{ + GdkScreen *pScreen = gtk_window_get_screen ( m_pWindow ); + gdk_display_sync( gdk_screen_get_display( pScreen ) ); +} + +String GtkSalFrame::GetSymbolKeyName( const String&, USHORT nKeyCode ) +{ + return getDisplay()->GetKeyName( nKeyCode ); +} + +String GtkSalFrame::GetKeyName( USHORT nKeyCode ) +{ + return getDisplay()->GetKeyName( nKeyCode ); +} + +GdkDisplay *GtkSalFrame::getGdkDisplay() +{ + GdkScreen *pScreen = gtk_window_get_screen( m_pWindow ); + if( pScreen ) + return gdk_screen_get_display( pScreen ); + else + return static_cast<GtkSalDisplay*>(GetSalData()->GetDefDisp())->GetGdkDisplay(); +} + +GtkSalDisplay *GtkSalFrame::getDisplay() +{ + return static_cast<GtkSalDisplay*>(GetSalData()->GetDefDisp()); +} + +ULONG GtkSalFrame::GetCurrentModButtons() +{ + GdkScreen* pScreen; + gint x, y; + GdkModifierType aMask; + gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask ); + return GetModCode( aMask ); +} + +void GtkSalFrame::SetInputContext( SalInputContext* pContext ) +{ + if( ! pContext ) + return; + + if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) ) + { + if( m_pIMContext ) + gtk_im_context_focus_out( m_pIMContext ); + return; + } + + // create a new im context + if( ! m_pIMContext ) + { + m_pIMContext = gtk_im_multicontext_new (); + g_signal_connect( m_pIMContext, "commit", + G_CALLBACK (signalIMCommit), this ); + g_signal_connect( m_pIMContext, "preedit_changed", + G_CALLBACK (signalIMPreeditChanged), this ); + g_signal_connect( m_pIMContext, "retrieve_surrounding", + G_CALLBACK (signalIMRetrieveSurrounding), this ); + g_signal_connect( m_pIMContext, "delete_surrounding", + G_CALLBACK (signalIMDeleteSurrounding), this ); + + gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET( m_pWindow )->window ); + } +} +void GtkSalFrame::EndExtTextInput( USHORT nFlags ) +{ + if( m_pIMContext ) + gtk_im_context_reset( m_pIMContext ); +} + +LanguageType GtkSalFrame::GetInputLanguage() +{ + return LANGUAGE_DONTKNOW; +} + +SalBitmap* GtkSalFrame::SnapShot() +{ + if( !m_pWindow ) + return NULL; + + X11SalBitmap *pBmp = new X11SalBitmap; + GdkWindow *pWin = GTK_WIDGET( m_pWindow )->window; + if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ), + GDK_WINDOW_XID( pWin ) ) ) + return pBmp; + else + delete pBmp; + + return NULL; +} + +static inline Color getColor( const GdkColor& rCol ) +{ + return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 ); +} + +void GtkSalFrame::UpdateSettings( AllSettings& rSettings ) +{ + if( ! m_pWindow ) + return; + + StyleSettings aStyleSet = rSettings.GetStyleSettings(); + + gtk_widget_ensure_style( GTK_WIDGET( m_pWindow ) ); + GtkStyle* pStyle = gtk_widget_get_style ( GTK_WIDGET( m_pWindow ) ); + + // text colors + Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] ); + aStyleSet.SetDialogTextColor( aTextColor ); + aStyleSet.SetMenuTextColor( aTextColor ); + aStyleSet.SetButtonTextColor( aTextColor ); + aStyleSet.SetRadioCheckTextColor( aTextColor ); + aStyleSet.SetGroupTextColor( aTextColor ); + aStyleSet.SetLabelTextColor( aTextColor ); + aStyleSet.SetInfoTextColor( aTextColor ); + aStyleSet.SetWindowTextColor( aTextColor ); + aStyleSet.SetFieldTextColor( aTextColor ); + + // background colors + Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] ); + Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] ); + aStyleSet.Set3DColors( aBackColor ); + aStyleSet.SetFaceColor( aBackColor ); + aStyleSet.SetDialogColor( aBackColor ); + aStyleSet.SetMenuColor( aBackColor ); + aStyleSet.SetMenuBarColor( aBackColor ); + aStyleSet.SetFieldColor( aBackFieldColor ); + aStyleSet.SetWindowColor( aBackFieldColor ); + // ancient wisdom tells us a mystic algorithm how to set checked color + if( aBackColor == COL_LIGHTGRAY ) + aStyleSet.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) ); + else + { + Color aColor2 = aStyleSet.GetLightColor(); + Color aCheck( (BYTE)(((USHORT)aBackColor.GetRed()+(USHORT)aColor2.GetRed())/2), + (BYTE)(((USHORT)aBackColor.GetGreen()+(USHORT)aColor2.GetGreen())/2), + (BYTE)(((USHORT)aBackColor.GetBlue()+(USHORT)aColor2.GetBlue())/2) + ); + aStyleSet.SetCheckedColor( aCheck ); + } + + // highlighting colors + Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] ); + Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] ); + aStyleSet.SetHighlightColor( aHighlightColor ); + aStyleSet.SetHighlightTextColor( aHighlightTextColor ); + aStyleSet.SetMenuHighlightColor( aHighlightColor ); + aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor ); + + // UI font + if( aStyleSet.GetUseSystemUIFonts() ) + { + ByteString aFamily = pango_font_description_get_family( pStyle->font_desc ); + int nPixelHeight = pango_font_description_get_size( pStyle->font_desc )/PANGO_SCALE; + PangoStyle eStyle = pango_font_description_get_style( pStyle->font_desc ); + PangoWeight eWeight = pango_font_description_get_weight( pStyle->font_desc ); + + long nDPIX, nDPIY; + long nDispDPIY = getDisplay()->GetResolution().B(); + getDisplay()->GetScreenFontResolution( nDPIX, nDPIY ); + int nHeight = nPixelHeight * nDispDPIY / nDPIY; + // allow for rounding in back conversion (at SetFont) + while( (nHeight * nDPIY / nDispDPIY) > nPixelHeight ) + nHeight--; + while( (nHeight * nDPIY / nDispDPIY) < nPixelHeight ) + nHeight++; + + Font aFont( String( aFamily, RTL_TEXTENCODING_UTF8 ), Size( 0, nHeight ) ); + if( eWeight >= PANGO_WEIGHT_BOLD ) + aFont.SetWeight( WEIGHT_BOLD ); + else if( PANGO_WEIGHT_LIGHT ) + aFont.SetWeight( WEIGHT_LIGHT ); + if( eStyle == PANGO_STYLE_OBLIQUE ) + aFont.SetItalic( ITALIC_OBLIQUE ); + else if( eStyle == PANGO_STYLE_ITALIC ) + aFont.SetItalic( ITALIC_NORMAL ); + + aStyleSet.SetAppFont( aFont ); + aStyleSet.SetHelpFont( aFont ); + aStyleSet.SetMenuFont( aFont ); + aStyleSet.SetToolFont( aFont ); + aStyleSet.SetLabelFont( aFont ); + aStyleSet.SetInfoFont( aFont ); + aStyleSet.SetRadioCheckFont( aFont ); + aStyleSet.SetPushButtonFont( aFont ); + aStyleSet.SetFieldFont( aFont ); + aStyleSet.SetIconFont( aFont ); + aStyleSet.SetGroupFont( aFont ); + } + +// FIXME: need some way of fetching toolbar icon size. +// aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL ); + + rSettings.SetStyleSettings( aStyleSet ); +} + +void GtkSalFrame::Beep( SoundType eType ) +{ + gdk_display_beep( getGdkDisplay() ); +} + +const SystemEnvData* GtkSalFrame::GetSystemData() const +{ + return &m_aSystemData; +} + +void GtkSalFrame::SetParent( SalFrame* pNewParent ) +{ + m_pParent = static_cast<GtkSalFrame*>(pNewParent); + gtk_window_set_transient_for( m_pWindow, m_pParent ? m_pParent->m_pWindow : NULL ); +} + +bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent ) +{ + gtk_widget_destroy( GTK_WIDGET(m_pWindow) ); + Init( pSysParent ); + return true; +} + +bool GtkSalFrame::Dispatch( const XEvent* pEvent ) +{ + bool bContinueDispatch = true; + + return bContinueDispatch; +} + +gboolean GtkSalFrame::signalButton( GtkWidget* pWidget, GdkEventButton* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + SalMouseEvent aEvent; + USHORT nEventType = 0; + switch( pEvent->type ) + { + case GDK_BUTTON_PRESS: + nEventType = SALEVENT_MOUSEBUTTONDOWN; + break; + case GDK_BUTTON_RELEASE: + nEventType = SALEVENT_MOUSEBUTTONUP; + break; + default: + return FALSE; + } + switch( pEvent->button ) + { + case 1: aEvent.mnButton = MOUSE_LEFT; break; + case 2: aEvent.mnButton = MOUSE_MIDDLE; break; + case 3: aEvent.mnButton = MOUSE_RIGHT; break; + default: return FALSE; break; + } + aEvent.mnTime = pEvent->time; + aEvent.mnX = (long)pEvent->x; + aEvent.mnY = (long)pEvent->y; + aEvent.mnCode = GetModCode( pEvent->state ); + + GTK_YIELD_GRAB(); + pThis->CallCallback( nEventType, &aEvent ); + + // let button events be dispatched to the correct window; + // the Xserver does an implicit XGrabPointer on ButtonPress + // but this is not what VCL wants + if( pEvent->type == GDK_BUTTON_PRESS && ! pThis->getDisplay()->GetCaptureFrame() ) + gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME ); + + return FALSE; +} + +gboolean GtkSalFrame::signalScroll( GtkWidget* pWidget, GdkEvent* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent; + + static ULONG nLines = 0; + if( ! nLines ) + { + char* pEnv = getenv( "SAL_WHEELLINES" ); + nLines = pEnv ? atoi( pEnv ) : 3; + if( nLines > 10 ) + nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL; + } + + bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT ); + SalWheelMouseEvent aEvent; + aEvent.mnTime = pSEvent->time; + aEvent.mnX = (ULONG)pSEvent->x; + aEvent.mnY = (ULONG)pSEvent->y; + aEvent.mnDelta = bNeg ? -120 : 120; + aEvent.mnNotchDelta = bNeg ? -1 : 1; + aEvent.mnScrollLines = nLines; + aEvent.mnCode = GetModCode( pSEvent->state ); + aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT); + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent ); + + return FALSE; +} + +gboolean GtkSalFrame::signalMotion( GtkWidget* pWidget, GdkEventMotion* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + SalMouseEvent aEvent; + aEvent.mnTime = pEvent->time; + aEvent.mnX = (long)pEvent->x; + aEvent.mnY = (long)pEvent->y; + aEvent.mnCode = GetModCode( pEvent->state ); + aEvent.mnButton = 0; + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent ); + + return TRUE; +} + +gboolean GtkSalFrame::signalCrossing( GtkWidget* pWidget, GdkEventCrossing* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + SalMouseEvent aEvent; + aEvent.mnTime = pEvent->time; + aEvent.mnX = (long)pEvent->x; + aEvent.mnY = (long)pEvent->y; + aEvent.mnCode = GetModCode( pEvent->state ); + aEvent.mnButton = 0; + + GTK_YIELD_GRAB(); + pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent ); + + return TRUE; +} + + +gboolean GtkSalFrame::signalExpose( GtkWidget* pWidget, GdkEventExpose* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + struct SalPaintEvent aEvent; + aEvent.mnBoundX = pEvent->area.x; + aEvent.mnBoundY = pEvent->area.y; + aEvent.mnBoundWidth = pEvent->area.width; + aEvent.mnBoundHeight = pEvent->area.height; + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_PAINT, &aEvent ); + + return FALSE; +} + +gboolean GtkSalFrame::signalFocus( GtkWidget* pWidget, GdkEventFocus* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + GTK_YIELD_GRAB(); + + if( !pEvent->in ) + { + pThis->m_nKeyModifiers = 0; + pThis->m_bSingleAltPress = false; + pThis->m_bSendModChangeOnRelease = false; + } + + if( pThis->m_pIMContext ) + { + if( pEvent->in ) + { + gtk_im_context_focus_in( pThis->m_pIMContext ); + gtk_im_context_reset( pThis->m_pIMContext ); + } + else + { + gtk_im_context_focus_out( pThis->m_pIMContext ); + pThis->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL ); + gtk_im_context_reset( pThis->m_pIMContext ); + } + } + + pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL ); + + return FALSE; +} + +gboolean GtkSalFrame::signalMap( GtkWidget* pWidget, GdkEvent* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_RESIZE, NULL ); + + return FALSE; +} + +gboolean GtkSalFrame::signalUnmap( GtkWidget* pWidget, GdkEvent* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_RESIZE, NULL ); + + return FALSE; +} + +gboolean GtkSalFrame::signalConfigure( GtkWidget* pWidget, GdkEventConfigure* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + bool bMoved = false, bSized = false; + if( pEvent->x != pThis->maGeometry.nX || pEvent->y != pThis->maGeometry.nY ) + bMoved = true; + if( pEvent->width != pThis->maGeometry.nWidth || pEvent->height != pThis->maGeometry.nHeight ) + bSized = true; + + pThis->maGeometry.nX = pEvent->x; + pThis->maGeometry.nY = pEvent->y; + pThis->maGeometry.nWidth = pEvent->width; + pThis->maGeometry.nHeight = pEvent->height; + + // update decoration hints + GdkRectangle aRect; + gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect ); + pThis->maGeometry.nTopDecoration = pEvent->y - aRect.y; + pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - pEvent->y - pEvent->height; + pThis->maGeometry.nLeftDecoration = pEvent->x - aRect.x; + pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - pEvent->x - pEvent->width; + + GTK_YIELD_GRAB(); + if( bMoved && bSized ) + pThis->CallCallback( SALEVENT_MOVERESIZE, NULL ); + else if( bMoved ) + pThis->CallCallback( SALEVENT_MOVE, NULL ); + else if( bSized ) + pThis->CallCallback( SALEVENT_RESIZE, NULL ); + + return FALSE; +} + +gboolean GtkSalFrame::signalKey( GtkWidget* pWidget, GdkEventKey* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + if( pThis->m_pIMContext ) + if( gtk_im_context_filter_keypress( pThis->m_pIMContext, pEvent ) ) + return TRUE; + + GTK_YIELD_GRAB(); + + // handle modifiers + if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R || + pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R || + pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R || + pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ) + { + SalKeyModEvent aModEvt; + + USHORT nModCode = GetModCode( pEvent->state ); + + aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events + if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers ) + pThis->m_bSendModChangeOnRelease = true; + + else if( pEvent->type == GDK_KEY_RELEASE && + pThis->m_bSendModChangeOnRelease ) + { + aModEvt.mnModKeyCode = pThis->m_nKeyModifiers; + pThis->m_nKeyModifiers = 0; + } + + USHORT nExtModMask = 0; + USHORT nModMask = 0; + // pressing just the ctrl key leads to a keysym of XK_Control but + // the event state does not contain ControlMask. In the release + // event its the other way round: it does contain the Control mask. + // The modifier mode therefore has to be adapted manually. + switch( pEvent->keyval ) + { + case GDK_Control_L: + nExtModMask = MODKEY_LMOD1; + nModMask = KEY_MOD1; + break; + case GDK_Control_R: + nExtModMask = MODKEY_RMOD1; + nModMask = KEY_MOD1; + break; + case GDK_Alt_L: + nExtModMask = MODKEY_LMOD2; + nModMask = KEY_MOD2 | (pEvent->type == GDK_KEY_RELEASE ? KEY_CONTROLMOD : 0); + break; + case GDK_Alt_R: + nExtModMask = MODKEY_RMOD2; + nModMask = KEY_MOD2 | (pEvent->type == GDK_KEY_RELEASE ? KEY_CONTROLMOD : 0); + break; + case GDK_Shift_L: + nExtModMask = MODKEY_LSHIFT; + nModMask = KEY_SHIFT; + break; + case GDK_Shift_R: + nExtModMask = MODKEY_RSHIFT; + nModMask = KEY_SHIFT; + break; + } + if( pEvent->type == GDK_KEY_RELEASE ) + { + nModCode &= ~nModMask; + pThis->m_nKeyModifiers &= ~nExtModMask; + } + else + { + nModCode |= nModMask; + pThis->m_nKeyModifiers |= nExtModMask; + } + + aModEvt.mnCode = nModCode; + aModEvt.mnTime = pEvent->time; + + pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt ); + + // emulate KEY_MENU + if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) && + ( nModCode & ~(KEY_CONTROLMOD|KEY_MOD2)) == 0 ) + { + if( pEvent->type == GDK_KEY_PRESS ) + pThis->m_bSingleAltPress = true; + + else if( pThis->m_bSingleAltPress ) + { + SalKeyEvent aKeyEvt; + + aKeyEvt.mnCode = KEY_MENU | nModCode; + aKeyEvt.mnRepeat = 0; + aKeyEvt.mnTime = pEvent->time; + aKeyEvt.mnCharCode = 0; + + // simulate KEY_MENU + pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt ); + pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt ); + pThis->m_bSingleAltPress = false; + } + } + else + pThis->m_bSingleAltPress = false; + } + else + { + SalKeyEvent aEvent; + + aEvent.mnTime = pEvent->time; + aEvent.mnCode = GetKeyCode( pEvent->keyval ) | GetModCode( pEvent->state ); + aEvent.mnCharCode = (USHORT)gdk_keyval_to_unicode( pEvent->keyval ); + aEvent.mnRepeat = 0; + pThis->CallCallback( pEvent->type == GDK_KEY_PRESS ? SALEVENT_KEYINPUT : SALEVENT_KEYUP, & aEvent ); + + pThis->m_bSendModChangeOnRelease = false; + pThis->m_bSingleAltPress = false; + } + + return TRUE; +} + +gboolean GtkSalFrame::signalDelete( GtkWidget* pWidget, GdkEvent* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_CLOSE, NULL ); + + return TRUE; +} + +void GtkSalFrame::signalStyleSet( GtkWidget* pWidget, GtkStyle* pPrevious, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + // signalStyleSet does NOT usually have the gdk lock + // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED + if( ! pThis->m_pParent ) + // don't call this for every window + // FIXME: should be called only once for a style change + pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED ); +} + +gboolean GtkSalFrame::signalState( GtkWidget* pWidget, GdkEvent* pEvent, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + pThis->m_nState = pEvent->window_state.new_window_state; + + return FALSE; +} + +void GtkSalFrame::signalIMCommit( GtkIMContext* pContext, gchar* pText, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + SalExtTextInputEvent aTextEvent; + + aTextEvent.mnTime = 0; + aTextEvent.mpTextAttr = 0; + aTextEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 ); + aTextEvent.mnCursorPos = aTextEvent.maText.Len(); + aTextEvent.mnCursorFlags = 0; + aTextEvent.mnDeltaStart = 0; + aTextEvent.mbOnlyCursor = False; + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent); + pThis->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL ); +} + +void GtkSalFrame::signalIMPreeditChanged( GtkIMContext* pContext, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + char* pText = NULL; + PangoAttrList* pAttribs = NULL; + gint nCursorPos = 0; + + gtk_im_context_get_preedit_string( pThis->m_pIMContext, + &pText, + &pAttribs, + &nCursorPos ); + SalExtTextInputEvent aTextEvent; + + aTextEvent.mnTime = 0; + aTextEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 ); + aTextEvent.mnCursorPos = nCursorPos; + aTextEvent.mnCursorFlags = 0; + aTextEvent.mnDeltaStart = 0; + aTextEvent.mbOnlyCursor = False; + + USHORT* pSalAttribs = new USHORT[ aTextEvent.maText.Len() ]; + // FIXME: more sophisticated attributes + for( int i = 0; i < aTextEvent.maText.Len(); ++i ) + pSalAttribs[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE; + + aTextEvent.mpTextAttr = pSalAttribs; + + g_free( pText ); + pango_attr_list_unref( pAttribs ); + + GTK_YIELD_GRAB(); + pThis->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent); + + delete [] pSalAttribs; +} + +void GtkSalFrame::signalIMPreeditStart( GtkIMContext* pContext, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; +} + +void GtkSalFrame::signalIMPreeditEnd( GtkIMContext* pContext, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; +} + +gboolean GtkSalFrame::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + return FALSE; +} + +gboolean GtkSalFrame::signalIMDeleteSurrounding( GtkIMContext* pContext, gint arg1, gint arg2, gpointer frame ) +{ + GtkSalFrame* pThis = (GtkSalFrame*)frame; + + return FALSE; +} |