2011-10-22 06:48:13 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* 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
|
2012-02-27 13:01:10 +00:00
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
2011-10-22 06:48:13 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
|
|
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
|
|
|
* files for a list of changes. These files are distributed with
|
|
|
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <locale.h>
|
2011-12-30 09:20:22 +00:00
|
|
|
|
#include <stdlib.h>
|
2011-10-22 06:48:13 +00:00
|
|
|
|
|
|
|
|
|
#include "gdk/gdk.h"
|
|
|
|
|
|
|
|
|
|
#include "gtkprivate.h"
|
2013-03-24 08:16:20 +00:00
|
|
|
|
#include "gtkresources.h"
|
2011-10-22 06:48:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined G_OS_WIN32 && !(defined GDK_WINDOWING_QUARTZ && defined QUARTZ_RELOCATION)
|
|
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
|
_gtk_get_datadir (void)
|
|
|
|
|
{
|
|
|
|
|
return GTK_DATADIR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
|
_gtk_get_libdir (void)
|
|
|
|
|
{
|
|
|
|
|
return GTK_LIBDIR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
|
_gtk_get_sysconfdir (void)
|
|
|
|
|
{
|
|
|
|
|
return GTK_SYSCONFDIR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
|
_gtk_get_localedir (void)
|
|
|
|
|
{
|
|
|
|
|
return GTK_LOCALEDIR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
|
_gtk_get_data_prefix (void)
|
|
|
|
|
{
|
|
|
|
|
return GTK_DATA_PREFIX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* _gtk_get_lc_ctype:
|
|
|
|
|
*
|
|
|
|
|
* Return the Unix-style locale string for the language currently in
|
|
|
|
|
* effect. On Unix systems, this is the return value from
|
2014-02-04 23:21:13 +00:00
|
|
|
|
* `setlocale(LC_CTYPE, NULL)`, and the user can
|
2011-10-22 06:48:13 +00:00
|
|
|
|
* affect this through the environment variables LC_ALL, LC_CTYPE or
|
|
|
|
|
* LANG (checked in that order). The locale strings typically is in
|
|
|
|
|
* the form lang_COUNTRY, where lang is an ISO-639 language code, and
|
|
|
|
|
* COUNTRY is an ISO-3166 country code. For instance, sv_FI for
|
|
|
|
|
* Swedish as written in Finland or pt_BR for Portuguese as written in
|
|
|
|
|
* Brazil.
|
|
|
|
|
*
|
2014-02-07 18:32:47 +00:00
|
|
|
|
* On Windows, the C library doesn’t use any such environment
|
|
|
|
|
* variables, and setting them won’t affect the behaviour of functions
|
2011-10-22 06:48:13 +00:00
|
|
|
|
* like ctime(). The user sets the locale through the Regional Options
|
|
|
|
|
* in the Control Panel. The C library (in the setlocale() function)
|
|
|
|
|
* does not use country and language codes, but country and language
|
|
|
|
|
* names spelled out in English.
|
|
|
|
|
* However, this function does check the above environment
|
|
|
|
|
* variables, and does return a Unix-style locale string based on
|
2014-02-07 18:01:26 +00:00
|
|
|
|
* either said environment variables or the thread’s current locale.
|
2011-10-22 06:48:13 +00:00
|
|
|
|
*
|
2014-02-19 23:49:43 +00:00
|
|
|
|
* Returns: a dynamically allocated string, free with g_free().
|
2011-10-22 06:48:13 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
|
_gtk_get_lc_ctype (void)
|
|
|
|
|
{
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
/* Somebody might try to set the locale for this process using the
|
|
|
|
|
* LANG or LC_ environment variables. The Microsoft C library
|
|
|
|
|
* doesn't know anything about them. You set the locale in the
|
|
|
|
|
* Control Panel. Setting these env vars won't have any affect on
|
|
|
|
|
* locale-dependent C library functions like ctime(). But just for
|
|
|
|
|
* kicks, do obey LC_ALL, LC_CTYPE and LANG in GTK. (This also makes
|
|
|
|
|
* it easier to test GTK and Pango in various default languages, you
|
|
|
|
|
* don't have to clickety-click in the Control Panel, you can simply
|
|
|
|
|
* start the program with LC_ALL=something on the command line.)
|
|
|
|
|
*/
|
|
|
|
|
gchar *p;
|
|
|
|
|
|
|
|
|
|
p = getenv ("LC_ALL");
|
|
|
|
|
if (p != NULL)
|
|
|
|
|
return g_strdup (p);
|
|
|
|
|
|
|
|
|
|
p = getenv ("LC_CTYPE");
|
|
|
|
|
if (p != NULL)
|
|
|
|
|
return g_strdup (p);
|
|
|
|
|
|
|
|
|
|
p = getenv ("LANG");
|
|
|
|
|
if (p != NULL)
|
|
|
|
|
return g_strdup (p);
|
|
|
|
|
|
|
|
|
|
return g_win32_getlocale ();
|
|
|
|
|
#else
|
|
|
|
|
return g_strdup (setlocale (LC_CTYPE, NULL));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
|
|
|
|
|
GValue *return_accu,
|
|
|
|
|
const GValue *handler_return,
|
|
|
|
|
gpointer dummy)
|
|
|
|
|
{
|
|
|
|
|
gboolean continue_emission;
|
|
|
|
|
gboolean signal_handled;
|
|
|
|
|
|
|
|
|
|
signal_handled = g_value_get_boolean (handler_return);
|
|
|
|
|
g_value_set_boolean (return_accu, signal_handled);
|
|
|
|
|
continue_emission = !signal_handled;
|
|
|
|
|
|
|
|
|
|
return continue_emission;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_gtk_single_string_accumulator (GSignalInvocationHint *ihint,
|
|
|
|
|
GValue *return_accu,
|
|
|
|
|
const GValue *handler_return,
|
|
|
|
|
gpointer dummy)
|
|
|
|
|
{
|
|
|
|
|
gboolean continue_emission;
|
|
|
|
|
const gchar *str;
|
|
|
|
|
|
|
|
|
|
str = g_value_get_string (handler_return);
|
|
|
|
|
g_value_set_string (return_accu, str);
|
|
|
|
|
continue_emission = str == NULL;
|
|
|
|
|
|
|
|
|
|
return continue_emission;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdkModifierType
|
|
|
|
|
_gtk_replace_virtual_modifiers (GdkKeymap *keymap,
|
|
|
|
|
GdkModifierType modifiers)
|
|
|
|
|
{
|
|
|
|
|
GdkModifierType result = 0;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_KEYMAP (keymap), 0);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) /* SHIFT...MOD5 */
|
|
|
|
|
{
|
|
|
|
|
GdkModifierType real = 1 << i;
|
|
|
|
|
|
|
|
|
|
if (modifiers & real)
|
|
|
|
|
{
|
|
|
|
|
GdkModifierType virtual = real;
|
|
|
|
|
|
|
|
|
|
gdk_keymap_add_virtual_modifiers (keymap, &virtual);
|
|
|
|
|
|
|
|
|
|
if (virtual == real)
|
|
|
|
|
result |= virtual;
|
|
|
|
|
else
|
|
|
|
|
result |= virtual & ~real;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdkModifierType
|
|
|
|
|
_gtk_get_primary_accel_mod (void)
|
|
|
|
|
{
|
|
|
|
|
static GdkModifierType primary = 0;
|
|
|
|
|
|
|
|
|
|
if (! primary)
|
|
|
|
|
{
|
|
|
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
|
|
primary = gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
|
|
|
|
|
GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
|
|
|
|
|
primary = _gtk_replace_virtual_modifiers (gdk_keymap_get_for_display (display),
|
|
|
|
|
primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return primary;
|
|
|
|
|
}
|
2011-11-18 11:25:03 +00:00
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_gtk_translate_keyboard_accel_state (GdkKeymap *keymap,
|
|
|
|
|
guint hardware_keycode,
|
|
|
|
|
GdkModifierType state,
|
|
|
|
|
GdkModifierType accel_mask,
|
|
|
|
|
gint group,
|
|
|
|
|
guint *keyval,
|
|
|
|
|
gint *effective_group,
|
|
|
|
|
gint *level,
|
|
|
|
|
GdkModifierType *consumed_modifiers)
|
|
|
|
|
{
|
2011-11-18 14:14:31 +00:00
|
|
|
|
GdkModifierType shift_group_mask;
|
2011-11-18 11:25:03 +00:00
|
|
|
|
gboolean group_mask_disabled = FALSE;
|
|
|
|
|
gboolean retval;
|
|
|
|
|
|
|
|
|
|
/* if the group-toggling modifier is part of the accel mod mask, and
|
|
|
|
|
* it is active, disable it for matching
|
|
|
|
|
*/
|
2011-11-18 14:14:31 +00:00
|
|
|
|
shift_group_mask = gdk_keymap_get_modifier_mask (keymap,
|
|
|
|
|
GDK_MODIFIER_INTENT_SHIFT_GROUP);
|
|
|
|
|
if (accel_mask & state & shift_group_mask)
|
2011-11-18 11:25:03 +00:00
|
|
|
|
{
|
2011-11-18 14:14:31 +00:00
|
|
|
|
state &= ~shift_group_mask;
|
2011-11-18 11:25:03 +00:00
|
|
|
|
group = 0;
|
|
|
|
|
group_mask_disabled = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retval = gdk_keymap_translate_keyboard_state (keymap,
|
|
|
|
|
hardware_keycode, state, group,
|
|
|
|
|
keyval,
|
|
|
|
|
effective_group, level,
|
|
|
|
|
consumed_modifiers);
|
|
|
|
|
|
|
|
|
|
/* add back the group mask, we want to match against the modifier,
|
|
|
|
|
* but not against the keyval from its group
|
|
|
|
|
*/
|
|
|
|
|
if (group_mask_disabled)
|
|
|
|
|
{
|
|
|
|
|
if (effective_group)
|
|
|
|
|
*effective_group = 1;
|
|
|
|
|
|
|
|
|
|
if (consumed_modifiers)
|
2011-11-18 14:14:31 +00:00
|
|
|
|
*consumed_modifiers &= ~shift_group_mask;
|
2011-11-18 11:25:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
2013-03-24 08:16:20 +00:00
|
|
|
|
|
|
|
|
|
static gpointer
|
|
|
|
|
register_resources (gpointer data)
|
|
|
|
|
{
|
|
|
|
|
_gtk_register_resource ();
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_gtk_ensure_resources (void)
|
|
|
|
|
{
|
|
|
|
|
static GOnce register_resources_once = G_ONCE_INIT;
|
|
|
|
|
|
|
|
|
|
g_once (®ister_resources_once, register_resources, NULL);
|
|
|
|
|
}
|
2016-07-05 00:29:59 +00:00
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
gtk_should_use_portal (void)
|
|
|
|
|
{
|
|
|
|
|
static const char *use_portal = NULL;
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY (use_portal == NULL))
|
|
|
|
|
{
|
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
|
|
path = g_build_filename (g_get_user_runtime_dir (), "flatpak-info", NULL);
|
|
|
|
|
if (g_file_test (path, G_FILE_TEST_EXISTS))
|
|
|
|
|
use_portal = "1";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
use_portal = g_getenv ("GTK_USE_PORTAL");
|
|
|
|
|
if (!use_portal)
|
|
|
|
|
use_portal = "";
|
|
|
|
|
}
|
|
|
|
|
g_free (path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return use_portal[0] == '1';
|
|
|
|
|
}
|
2018-08-30 17:05:55 +00:00
|
|
|
|
|
2020-03-23 13:56:43 +00:00
|
|
|
|
/*
|
|
|
|
|
* gtk_get_portal_interface_version:
|
|
|
|
|
* @connection: a session #GDBusConnection
|
|
|
|
|
* @interface_name: the interface name for the portal interface
|
|
|
|
|
* we're interested in.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the version number of the portal, or 0 on error.
|
|
|
|
|
*/
|
|
|
|
|
guint
|
|
|
|
|
gtk_get_portal_interface_version (GDBusConnection *connection,
|
|
|
|
|
const char *interface_name)
|
|
|
|
|
{
|
2020-03-30 15:50:50 +00:00
|
|
|
|
GDBusProxy *proxy = NULL;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
GVariant *ret = NULL;
|
|
|
|
|
char *owner = NULL;
|
2020-03-23 13:56:43 +00:00
|
|
|
|
guint version = 0;
|
|
|
|
|
|
|
|
|
|
proxy = g_dbus_proxy_new_sync (connection,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
"org.freedesktop.portal.Desktop",
|
|
|
|
|
"/org/freedesktop/portal/desktop",
|
|
|
|
|
interface_name,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
if (!proxy)
|
|
|
|
|
{
|
|
|
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
|
|
|
g_warning ("Could not query portal version on interface '%s': %s",
|
|
|
|
|
interface_name, error->message);
|
2020-03-30 15:50:50 +00:00
|
|
|
|
goto out;
|
2020-03-23 13:56:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
owner = g_dbus_proxy_get_name_owner (proxy);
|
|
|
|
|
if (owner == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_debug ("%s not provided by any service", interface_name);
|
2020-03-30 15:50:50 +00:00
|
|
|
|
goto out;
|
2020-03-23 13:56:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = g_dbus_proxy_get_cached_property (proxy, "version");
|
|
|
|
|
if (ret)
|
|
|
|
|
version = g_variant_get_uint32 (ret);
|
|
|
|
|
|
|
|
|
|
g_debug ("Got version %u for portal interface '%s'",
|
|
|
|
|
version, interface_name);
|
|
|
|
|
|
2020-03-30 15:50:50 +00:00
|
|
|
|
out:
|
|
|
|
|
g_clear_object (&proxy);
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
g_clear_pointer (&ret, g_variant_unref);
|
|
|
|
|
g_clear_pointer (&owner, g_free);
|
|
|
|
|
|
2020-03-23 13:56:43 +00:00
|
|
|
|
return version;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-30 17:05:55 +00:00
|
|
|
|
static char *
|
|
|
|
|
get_portal_path (GDBusConnection *connection,
|
|
|
|
|
const char *kind,
|
|
|
|
|
char **token)
|
|
|
|
|
{
|
|
|
|
|
char *sender;
|
|
|
|
|
int i;
|
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
|
|
*token = g_strdup_printf ("gtk%d", g_random_int_range (0, G_MAXINT));
|
|
|
|
|
sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1);
|
|
|
|
|
for (i = 0; sender[i]; i++)
|
|
|
|
|
if (sender[i] == '.')
|
|
|
|
|
sender[i] = '_';
|
|
|
|
|
|
2018-09-05 23:54:32 +00:00
|
|
|
|
path = g_strconcat ("/org/freedesktop/portal/desktop", "/", kind, "/", sender, "/", *token, NULL);
|
2018-08-30 17:05:55 +00:00
|
|
|
|
|
|
|
|
|
g_free (sender);
|
|
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
gtk_get_portal_request_path (GDBusConnection *connection,
|
|
|
|
|
char **token)
|
|
|
|
|
{
|
|
|
|
|
return get_portal_path (connection, "request", token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
gtk_get_portal_session_path (GDBusConnection *connection,
|
|
|
|
|
char **token)
|
|
|
|
|
{
|
|
|
|
|
return get_portal_path (connection, "session", token);
|
|
|
|
|
}
|