/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
*/
sal_uInt16 GtkSalFrame::GetKeyModCode( guint state )
{
sal_uInt16 nCode = 0; if( state & GDK_SHIFT_MASK )
nCode |= KEY_SHIFT; if( state & GDK_CONTROL_MASK )
nCode |= KEY_MOD1; if (state & GDK_ALT_MASK)
nCode |= KEY_MOD2; if( state & GDK_SUPER_MASK )
nCode |= KEY_MOD3; return nCode;
}
sal_uInt16 GtkSalFrame::GetMouseModCode( guint state )
{
sal_uInt16 nCode = GetKeyModCode( state ); 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;
}
// KEY_F26 is the last function key known to keycodes.hxx staticbool IsFunctionKeyVal(guint keyval)
{ return keyval >= GDK_KEY_F1 && keyval <= GDK_KEY_F26;
}
sal_uInt16 GtkSalFrame::GetKeyCode(guint keyval)
{
sal_uInt16 nCode = 0; if( keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9 )
nCode = KEY_0 + (keyval-GDK_KEY_0); elseif( keyval >= GDK_KEY_KP_0 && keyval <= GDK_KEY_KP_9 )
nCode = KEY_0 + (keyval-GDK_KEY_KP_0); elseif( keyval >= GDK_KEY_A && keyval <= GDK_KEY_Z )
nCode = KEY_A + (keyval-GDK_KEY_A ); elseif( keyval >= GDK_KEY_a && keyval <= GDK_KEY_z )
nCode = KEY_A + (keyval-GDK_KEY_a ); elseif (IsFunctionKeyVal(keyval))
{ switch( keyval )
{ // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx // although GDK_KEY_F1 ... GDK_KEY_L10 are known to // gdk/gdkkeysyms.h, they are unlikely to be generated // except possibly by Solaris systems // this whole section needs review case GDK_KEY_L2:
nCode = KEY_F12; break; case GDK_KEY_L3: nCode = KEY_PROPERTIES; break; case GDK_KEY_L4: nCode = KEY_UNDO; break; case GDK_KEY_L6: nCode = KEY_COPY; break; // KEY_F16 case GDK_KEY_L8: nCode = KEY_PASTE; break; // KEY_F18 case GDK_KEY_L10: nCode = KEY_CUT; break; // KEY_F20 default:
nCode = KEY_F1 + (keyval-GDK_KEY_F1); break;
}
} else
{ switch( keyval )
{ case GDK_KEY_KP_Down: case GDK_KEY_Down: nCode = KEY_DOWN; break; case GDK_KEY_KP_Up: case GDK_KEY_Up: nCode = KEY_UP; break; case GDK_KEY_KP_Left: case GDK_KEY_Left: nCode = KEY_LEFT; break; case GDK_KEY_KP_Right: case GDK_KEY_Right: nCode = KEY_RIGHT; break; case GDK_KEY_KP_Begin: case GDK_KEY_KP_Home: case GDK_KEY_Begin: case GDK_KEY_Home: nCode = KEY_HOME; break; case GDK_KEY_KP_End: case GDK_KEY_End: nCode = KEY_END; break; case GDK_KEY_KP_Page_Up: case GDK_KEY_Page_Up: nCode = KEY_PAGEUP; break; case GDK_KEY_KP_Page_Down: case GDK_KEY_Page_Down: nCode = KEY_PAGEDOWN; break; case GDK_KEY_KP_Enter: case GDK_KEY_Return: nCode = KEY_RETURN; break; case GDK_KEY_Escape: nCode = KEY_ESCAPE; break; case GDK_KEY_ISO_Left_Tab: case GDK_KEY_KP_Tab: case GDK_KEY_Tab: nCode = KEY_TAB; break; case GDK_KEY_BackSpace: nCode = KEY_BACKSPACE; break; case GDK_KEY_KP_Space: case GDK_KEY_space: nCode = KEY_SPACE; break; case GDK_KEY_KP_Insert: case GDK_KEY_Insert: nCode = KEY_INSERT; break; case GDK_KEY_KP_Delete: case GDK_KEY_Delete: nCode = KEY_DELETE; break; case GDK_KEY_plus: case GDK_KEY_KP_Add: nCode = KEY_ADD; break; case GDK_KEY_minus: case GDK_KEY_KP_Subtract: nCode = KEY_SUBTRACT; break; case GDK_KEY_asterisk: case GDK_KEY_KP_Multiply: nCode = KEY_MULTIPLY; break; case GDK_KEY_slash: case GDK_KEY_KP_Divide: nCode = KEY_DIVIDE; break; case GDK_KEY_period: nCode = KEY_POINT; break; case GDK_KEY_decimalpoint: nCode = KEY_POINT; break; case GDK_KEY_comma: nCode = KEY_COMMA; break; case GDK_KEY_less: nCode = KEY_LESS; break; case GDK_KEY_greater: nCode = KEY_GREATER; break; case GDK_KEY_KP_Equal: case GDK_KEY_equal: nCode = KEY_EQUAL; break; case GDK_KEY_Find: nCode = KEY_FIND; break; case GDK_KEY_Menu: nCode = KEY_CONTEXTMENU;break; case GDK_KEY_Help: nCode = KEY_HELP; break; case GDK_KEY_Undo: nCode = KEY_UNDO; break; case GDK_KEY_Redo: nCode = KEY_REPEAT; break; // on a sun keyboard this actually is usually SunXK_Stop = 0x0000FF69 (XK_Cancel), // but VCL doesn't have a key definition for that case GDK_KEY_Cancel: nCode = KEY_F11; break; case GDK_KEY_KP_Decimal: case GDK_KEY_KP_Separator: nCode = KEY_DECIMAL; break; case GDK_KEY_asciitilde: nCode = KEY_TILDE; break; case GDK_KEY_leftsinglequotemark: case GDK_KEY_quoteleft: nCode = KEY_QUOTELEFT; break; case GDK_KEY_bracketleft: nCode = KEY_BRACKETLEFT; break; case GDK_KEY_bracketright: nCode = KEY_BRACKETRIGHT; break; case GDK_KEY_semicolon: nCode = KEY_SEMICOLON; break; case GDK_KEY_quoteright: nCode = KEY_QUOTERIGHT; break; case GDK_KEY_braceright: nCode = KEY_RIGHTCURLYBRACKET; break; case GDK_KEY_numbersign: nCode = KEY_NUMBERSIGN; break; case GDK_KEY_Forward: nCode = KEY_XF86FORWARD; break; case GDK_KEY_Back: nCode = KEY_XF86BACK; break; case GDK_KEY_colon: nCode = KEY_COLON; break; // some special cases, also see saldisp.cxx // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000 // These can be found in ap_keysym.h case 0x1000FF02: // apXK_Copy
nCode = KEY_COPY; break; case 0x1000FF03: // apXK_Cut
nCode = KEY_CUT; break; case 0x1000FF04: // apXK_Paste
nCode = KEY_PASTE; break; case 0x1000FF14: // apXK_Repeat
nCode = KEY_REPEAT; break; // Exit, Save // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000 // These can be found in DECkeysym.h case 0x1000FF00:
nCode = KEY_DELETE; break; // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000 // These can be found in HPkeysym.h case 0x1000FF73: // hpXK_DeleteChar
nCode = KEY_DELETE; break; case 0x1000FF74: // hpXK_BackTab case 0x1000FF75: // hpXK_KP_BackTab
nCode = KEY_TAB; break; // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - - // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004 // These also can be found in HPkeysym.h case 0x1004FF02: // osfXK_Copy
nCode = KEY_COPY; break; case 0x1004FF03: // osfXK_Cut
nCode = KEY_CUT; break; case 0x1004FF04: // osfXK_Paste
nCode = KEY_PASTE; break; case 0x1004FF07: // osfXK_BackTab
nCode = KEY_TAB; break; case 0x1004FF08: // osfXK_BackSpace
nCode = KEY_BACKSPACE; break; case 0x1004FF1B: // osfXK_Escape
nCode = KEY_ESCAPE; break; // Up, Down, Left, Right, PageUp, PageDown // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - - // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007 // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - - // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005 // These can be found in Sunkeysym.h case 0x1005FF10: // SunXK_F36
nCode = KEY_F11; break; case 0x1005FF11: // SunXK_F37
nCode = KEY_F12; break; case 0x1005FF70: // SunXK_Props
nCode = KEY_PROPERTIES; break; case 0x1005FF71: // SunXK_Front
nCode = KEY_FRONT; break; case 0x1005FF72: // SunXK_Copy
nCode = KEY_COPY; break; case 0x1005FF73: // SunXK_Open
nCode = KEY_OPEN; break; case 0x1005FF74: // SunXK_Paste
nCode = KEY_PASTE; break; case 0x1005FF75: // SunXK_Cut
nCode = KEY_CUT; break; // - - - - - - - - - - - - - X F 8 6 - - - - - - - - - - - - - 0x1008 // These can be found in XF86keysym.h // but more importantly they are also available GTK/Gdk version 3 // and hence are already provided in gdk/gdkkeysyms.h, and hence // in gdk/gdk.h case GDK_KEY_Copy: nCode = KEY_COPY; break; // 0x1008ff57 case GDK_KEY_Cut: nCode = KEY_CUT; break; // 0x1008ff58 case GDK_KEY_Open: nCode = KEY_OPEN; break; // 0x1008ff6b case GDK_KEY_Paste: nCode = KEY_PASTE; break; // 0x1008ff6d
}
}
if (pKeyDebug && *pKeyDebug == '1')
{ if (bDown)
{ // shift-zero forces a re-draw and event is swallowed if (keyval == GDK_KEY_0)
{
SAL_INFO("vcl.gtk3", "force widget_queue_draw.");
gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea)); returnfalse;
} elseif (keyval == GDK_KEY_1)
{
SAL_INFO("vcl.gtk3", "force repaint all.");
TriggerPaintEvent(); returnfalse;
} elseif (keyval == GDK_KEY_2)
{
dumpframes = !dumpframes;
SAL_INFO("vcl.gtk3", "toggle dump frames to " << dumpframes); returnfalse;
}
}
} #endif
/* * #i42122# translate all keys with Ctrl and/or Alt to group 0 else * shortcuts (e.g. Ctrl-o) will not work but be inserted by the * application * * #i52338# do this for all keys that the independent part has no key code * for * * fdo#41169 rather than use group 0, detect if there is a group which can * be used to input Latin text and use that if possible
*/
aEvent.mnCode = GetKeyCode( keyval ); #if !GTK_CHECK_VERSION(4, 0, 0) if( aEvent.mnCode == 0 )
{
gint best_group = SAL_MAX_INT32;
// Try and find Latin layout
GdkKeymap* keymap = gdk_keymap_get_default();
GdkKeymapKey *keys;
gint n_keys; if (gdk_keymap_get_entries_for_keyval(keymap, GDK_KEY_A, &keys, &n_keys))
{ // Find the lowest group that supports Latin layout for (gint i = 0; i < n_keys; ++i)
{ if (keys[i].level != 0 && keys[i].level != 1) continue;
best_group = std::min(best_group, keys[i].group); if (best_group == 0) break;
}
g_free(keys);
}
//Unavailable, go with original group then I suppose if (best_group == SAL_MAX_INT32)
best_group = group;
bool bStopProcessingKey; if (bDown)
{ // tdf#152404 Commit uncommitted text before dispatching key shortcuts. In // certain cases such as pressing Control-Alt-C in a Writer document while // there is uncommitted text will call GtkSalFrame::EndExtTextInput() which // will dispatch a SalEvent::EndExtTextInput event. Writer's handler for that // event will delete the uncommitted text and then insert the committed text // but LibreOffice will crash when deleting the uncommitted text because // deletion of the text also removes and deletes the newly inserted comment. if (m_pIMHandler && !m_pIMHandler->m_aInputEvent.maText.isEmpty() && (aEvent.mnCode & (KEY_MOD1 | KEY_MOD2)))
m_pIMHandler->doCallEndExtTextInput();
// Create menu model and action group attached to this frame.
GMenuModel* pMenuModel = G_MENU_MODEL( g_lo_menu_new() );
GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new());
// This is called when the registrar becomes unavailable. It shows the menubar. void on_registrar_unavailable( GDBusConnection * /*connection*/, const gchar * /*name*/,
gpointer user_data )
{
SolarMutexGuard aGuard;
void GtkSalFrame::EnsureAppMenuWatch()
{ if ( m_nWatcherId ) return;
// Get a DBus session connection.
EnsureSessionBus(); if (!pSessionBus) return;
// Publish the menu only if AppMenu registrar is available.
m_nWatcherId = g_bus_watch_name_on_connection( pSessionBus, "com.canonical.AppMenu.Registrar",
G_BUS_NAME_WATCHER_FLAGS_NONE,
on_registrar_available,
on_registrar_unavailable, this,
nullptr );
}
#if !GTK_CHECK_VERSION(4,0,0) // tdf#124694 GtkFixed takes the max size of all its children as its // preferred size, causing it to not clip its child, but grow instead.
/* * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to * utilize GAIL for the toplevel window and toolkit implementation incl. * key event listener support ..
*/
GType
ooo_fixed_get_type()
{ static GType type = 0;
if (!type) { staticconst GTypeInfo tinfo =
{ sizeof (GtkFixedClass),
nullptr, /* base init */
nullptr, /* base finalize */
ooo_fixed_class_init, /* class init */
nullptr, /* class finalize */
nullptr, /* class data */ sizeof (GtkFixed), /* instance size */
0, /* nb preallocs */
nullptr, /* instance init */
nullptr /* value table */
};
type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
&tinfo, GTypeFlags(0));
}
#if GTK_CHECK_VERSION(4,0,0)
m_nSettingChangedSignalId = g_signal_connect(G_OBJECT(gtk_widget_get_display(pEventWidget)), "setting-changed", G_CALLBACK(signalStyleUpdated), this); #else // use pEventWidget instead of m_pWindow to avoid infinite event loop under Linux Mint Mate 18.3
g_signal_connect(G_OBJECT(pEventWidget), "style-updated", G_CALLBACK(signalStyleUpdated), this); #endif
gtk_widget_set_has_tooltip(pEventWidget, true); // connect signals
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "query-tooltip", G_CALLBACK(signalTooltipQuery), this )); #if !GTK_CHECK_VERSION(4,0,0)
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-press-event", G_CALLBACK(signalButton), this ));
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "button-release-event", G_CALLBACK(signalButton), this ));
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "motion-notify-event", G_CALLBACK(signalMotion), this ));
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "leave-notify-event", G_CALLBACK(signalCrossing), this ));
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "enter-notify-event", G_CALLBACK(signalCrossing), this ));
m_aMouseSignalIds.push_back(g_signal_connect( G_OBJECT(pEventWidget), "scroll-event", G_CALLBACK(signalScroll), this )); #else
GtkGesture *pClick = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(pClick), 0); // use GTK_PHASE_TARGET instead of default GTK_PHASE_BUBBLE because I don't // want click events in gtk widgets inside the overlay, e.g. the font size // combobox GtkEntry in the toolbar, to be propagated down to this widget
gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(pClick), GTK_PHASE_TARGET);
gtk_widget_add_controller(pEventWidget, GTK_EVENT_CONTROLLER(pClick));
g_signal_connect(pClick, "pressed", G_CALLBACK(gesturePressed), this);
g_signal_connect(pClick, "released", G_CALLBACK(gestureReleased), this);
#if !GTK_CHECK_VERSION(4,0,0)
g_signal_connect_after( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this );
g_signal_connect_after( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this ); if (GTK_IS_WINDOW(m_pWindow)) // i.e. not if it's a GtkEventBox which doesn't have the signal
m_nSetFocusSignalId = g_signal_connect( G_OBJECT(m_pWindow), "set-focus", G_CALLBACK(signalSetFocus), this ); #else
GtkEventController* pFocusController = gtk_event_controller_focus_new();
g_signal_connect(pFocusController, "enter", G_CALLBACK(signalFocusEnter), this);
g_signal_connect(pFocusController, "leave", G_CALLBACK(signalFocusLeave), this);
gtk_widget_set_focusable(pEventWidget, true);
gtk_widget_add_controller(pEventWidget, pFocusController); if (GTK_IS_WINDOW(m_pWindow)) // i.e. not if it's a GtkEventBox which doesn't have the property (presumably?)
m_nSetFocusSignalId = g_signal_connect( G_OBJECT(m_pWindow), "notify::focus-widget", G_CALLBACK(signalSetFocus), this ); #endif #if !GTK_CHECK_VERSION(4,0,0)
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), "delete-event", G_CALLBACK(signalDelete), this ); #else
g_signal_connect( G_OBJECT(m_pWindow), "map", G_CALLBACK(signalMap), this );
g_signal_connect( G_OBJECT(m_pWindow), "unmap", G_CALLBACK(signalUnmap), this ); if (GTK_IS_WINDOW(m_pWindow))
g_signal_connect( G_OBJECT(m_pWindow), "close-request", G_CALLBACK(signalDelete), this ); #endif #if !GTK_CHECK_VERSION(4,0,0)
g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this ); #endif
void GtkSalFrame::DisallowCycleFocusOut()
{ if (!m_nSetFocusSignalId) return; // don't enable/disable can-focus as control enters and leaves // embedded native gtk widgets
g_signal_handler_disconnect(G_OBJECT(m_pWindow), m_nSetFocusSignalId);
m_nSetFocusSignalId = 0;
#if !GTK_CHECK_VERSION(4, 0, 0) // gtk3: set container without can-focus and focus will tab between // the native embedded widgets using the default gtk handling for // that // gtk4: no need because the native widgets are the only // thing in the overlay and the drawing widget is underneath so // the natural focus cycle is sufficient
gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), false); #endif
}
void GtkSalFrame::AllowCycleFocusOut()
{ if (m_nSetFocusSignalId) return; #if !GTK_CHECK_VERSION(4,0,0) // enable/disable can-focus as control enters and leaves // embedded native gtk widgets
m_nSetFocusSignalId = g_signal_connect(G_OBJECT(m_pWindow), "set-focus", G_CALLBACK(signalSetFocus), this); #else
m_nSetFocusSignalId = g_signal_connect(G_OBJECT(m_pWindow), "notify::focus-widget", G_CALLBACK(signalSetFocus), this); #endif
#if !GTK_CHECK_VERSION(4, 0, 0) // set container without can-focus and focus will tab between // the native embedded widgets using the default gtk handling for // that // gtk4: no need because the native widgets are the only // thing in the overlay and the drawing widget is underneath so // the natural focus cycle is sufficient
gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), true); #endif
}
session_client_response(client_proxy);
} elseif (g_str_equal (signal_name, "CancelEndSession"))
{ // restore back to uninhibited (to set again if queried), so frames // that go away before the next logout don't affect that logout
pThis->SessionManagerInhibit(false, APPLICATION_INHIBIT_LOGOUT, VclResId(STR_UNSAVED_DOCUMENTS),
gtk_window_get_icon_name(GTK_WINDOW(pThis->getWindow())));
} elseif (g_str_equal (signal_name, "EndSession"))
{
session_client_response(client_proxy);
clear_modify_and_terminate();
} elseif (g_str_equal (signal_name, "Stop"))
{
clear_modify_and_terminate();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.