Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
accelerators.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2013 Jérémy Rosen.
4 Copyright (C) 2011 Robert Bieber.
5 Copyright (C) 2012 Richard Wonka.
6 Copyright (C) 2012, 2014, 2016-2017 Tobias Ellinghaus.
7 Copyright (C) 2016 Roman Lebedev.
8 Copyright (C) 2019-2020 Aldric Renaudin.
9 Copyright (C) 2020 Chris Elston.
10 Copyright (C) 2020-2022 Diederik Ter Rahe.
11 Copyright (C) 2020 Heiko Bauke.
12 Copyright (C) 2020 Hubert Kowalski.
13 Copyright (C) 2020-2021 Pascal Obry.
14 Copyright (C) 2021 Bill Ferguson.
15 Copyright (C) 2022 Martin Bařinka.
16 Copyright (C) 2023, 2025 Aurélien PIERRE.
17 Copyright (C) 2026 Guillaume Stutin.
18
19 darktable is free software: you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation, either version 3 of the License, or
22 (at your option) any later version.
23
24 darktable is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with darktable. If not, see <http://www.gnu.org/licenses/>.
31*/
32#include <gdk/gdkkeysyms.h>
33#include <gtk/gtk.h>
34#ifdef GDK_WINDOWING_WAYLAND
35#include <gdk/gdkwayland.h>
36#endif
37
38#include "system/dtpthread.h"
39
40G_BEGIN_DECLS
41
42#define DT_ACCELS_WIDGET_SHORTCUT_KEY "dt-accel-shortcut"
43#define DT_ACCELS_WIDGET_TOOLTIP_DISABLED_KEY "dt-accel-tooltip-disabled"
44
120#ifndef DT_WIDGETS_ACCELERATORS_H
121#define DT_WIDGETS_ACCELERATORS_H
122
123/* Ansel's accelerator system is fully custom (see dt_accels_dispatch()) and never
124 * goes through GTK's own accelerator string parser, so it gets none of the
125 * "<Primary>" -> Ctrl/Cmd translation that convention normally provides for free.
126 * Each default shortcut that is meant to follow the OS's own accelerator
127 * convention (most menu/window-level shortcuts) must be registered with
128 * DT_PRIMARY_MASK instead of GDK_CONTROL_MASK. A shortcut that must remain the
129 * literal Ctrl key even on macOS should keep GDK_CONTROL_MASK explicitly.
130 * On the Quartz GDK backend a physical Cmd keypress is reported through
131 * GDK_MOD2_MASK (see _accels_keys_decode() in accelerators.c for the matching
132 * GDK_META_MASK duplicate it has to filter out on that same backend). */
133#ifdef GDK_WINDOWING_QUARTZ
134#define DT_PRIMARY_MASK GDK_MOD2_MASK
135#else
136#define DT_PRIMARY_MASK GDK_CONTROL_MASK
137#endif
138
139typedef struct dt_accels_t
140{
142 GtkAccelGroup *global_accels; // used, aka init it and free it
143 GtkAccelGroup *darkroom_accels; // darkroom-specific accels
144 GtkAccelGroup *lighttable_accels; // lighttable-specific accels
145 GtkAccelGroup *map_accels; // map-specific accels
146 GtkAccelGroup *print_accels; // print-specific accels
147 GtkAccelGroup *slideshow_accels; // slideshow-specific accels
148
149 // reference to the above group currently loaded in the main window. don't init,
150 // don't free, only update
151 GtkAccelGroup *active_group;
152
153 GHashTable *acceleratables; // Key/value list of path/dt_shortcut_t
154 gint reset; // ref counter of how many parts disconnected accels
155 GdkKeymap *keymap; // default screen keymap to decode key values
156 GdkModifierType default_mod_mask; // set of modifier masks relevant only to key strokes
157
158 // TRUE if we didn't find a keyboardrc config file at startup and we need to init a new one
159 gboolean init;
160
161 // between key_pressed and key_release events, this stores the active key strokes;
162 // cleared when the main window gains or loses the focus (see dt_accels_dispatch)
163 GtkAccelKey active_key;
164
165 // Temporarily disable accelerators
167
168 GtkAccelFlags flags;
169
170 dt_pthread_mutex_t lock;
171
172 // Views can register a global callback to handle scroll events
173 // for example while keystrokes are on.
174 struct scroll
175 {
176 gboolean (*callback)(GdkEventScroll event, void *data);
177 void *data;
178 } scroll;
180
182{
183 DT_SHORTCUT_UNSET = 0, // shortcut non-inited
184 DT_SHORTCUT_DEFAULT = 1, // shortcut inited with compile-time defaults
185 DT_SHORTCUT_USER = 2 // shortcut changed by user config
187
188typedef struct dt_shortcut_t
189{
190 GtkWidget *widget; // link to the widget being accelerated. Can be NULL.
191 GList *closure; // GList of GClosures, aka callback + data being accelerated. Always non-NULL once
192 // built through dt_accels_new_{widget,action,virtual}_shortcut(): accel groups are
193 // never attached to a GtkWindow (see dt_accels_dispatch), so the internal dispatcher
194 // is the only path that can activate a shortcut, and it always goes through this closure.
195 char *path; // global path for that accel
196 const char *signal; // widget signal to be wired to that accel
197 GtkAccelGroup *accel_group; // the accel_group to which this shortcut belongs
198 guint key; // default key
199 GdkModifierType mods; // default modifier
201 gboolean locked; // if shortcut can't be changed by user
202 gboolean virtual_shortcut; // if shortcut is mapped to a key-pressed event handler instead of a global action callback
203 const char *description; // user-legible description of the action
204 dt_accels_t *accels; // back-reference for convenience
206
207
208dt_accels_t *dt_accels_init(char *config_file, GtkAccelFlags flags);
209void dt_accels_cleanup(dt_accels_t *accels);
210
211
223gchar *dt_accels_build_path(const gchar *scope, const gchar *feature);
224
232
233
240
241
250void dt_accels_connect_active_group(dt_accels_t *accels, const gchar *group);
251
258
259
272void dt_accels_new_virtual_shortcut(dt_accels_t *accels, GtkAccelGroup *accel_group, const gchar *accel_path,
273 GtkWidget *widget,
274 guint key_val, GdkModifierType accel_mods);
275
276
278 gboolean (*action_callback)(GtkAccelGroup *group,
279 GObject *acceleratable, guint keyval,
280 GdkModifierType mods, gpointer user_data),
281 gpointer data, GtkAccelGroup *accel_group, const gchar *action_scope,
282 const gchar *action_name);
283
297void dt_accels_new_widget_shortcut(dt_accels_t *accels, GtkWidget *widget, const gchar *signal,
298 GtkAccelGroup *accel_group, const gchar *accel_path, guint key_val,
299 GdkModifierType accel_mods, const gboolean lock);
300
301
334 gboolean (*action_callback)(GtkAccelGroup *group, GObject *acceleratable,
335 guint keyval, GdkModifierType mods,
336 gpointer user_data),
337 gpointer data, GtkWidget *target_widget, GtkAccelGroup *accel_group,
338 const gchar *action_scope, const gchar *action_name, guint key_val,
339 GdkModifierType accel_mods, const gboolean lock, const char *description);
340
341
350gboolean dt_accels_dispatch(GtkWidget *w, GdkEvent *event, gpointer user_data);
351
360void dt_accels_attach_scroll_handler(dt_accels_t *accels, gboolean (*callback)(GdkEventScroll event, void *data),
361 void *data);
362
364
365
366// Temporarily enable/disable keyboard accels, for example during GtkEntry typing.
367// Connect it from Gtk focus in/out event handlers
368static inline void dt_accels_disable(dt_accels_t *accels, gboolean state)
369{
370 accels->disable_accels = state;
371}
372
396void dt_accels_remove_accel(dt_accels_t *accels, const char *path, gpointer data);
397
404void dt_accels_remove_shortcut(dt_accels_t *accels, const char *path);
405
412void dt_accels_window(dt_accels_t *accels, GtkWindow *main_window);
413
414void dt_accels_search(dt_accels_t *accels, GtkWindow *main_window, GtkWidget *anchor);
415
416/* ------------------------------------------------------------------------------------------
417 * Host hooks
418 *
419 * The shortcut system is otherwise self-contained GTK: a key arrives, a path is matched, a
420 * closure fires. These four are the only things it cannot answer by itself, so the host
421 * supplies them instead of the module reaching for application globals.
422 *
423 * All are optional. Unregistered, each degrades to a sensible inert default.
424 * ------------------------------------------------------------------------------------------ */
425
429
438
443
448
452typedef gchar *(*dt_accels_recent_get_handler_t)(int index);
453typedef void (*dt_accels_recent_set_handler_t)(int index, const char *value);
456
457/* Shorthand for a darkroom-scoped action shortcut, resolved through this module's own
458 * instance rather than through the application's GUI struct. */
459#define dt_accels_new_darkroom_action(a, b, w, c, d, e, f, g) \
460 dt_accels_new_action_shortcut(dt_accels_get_global(), a, b, w, \
461 dt_accels_get_global()->darkroom_accels, c, d, e, f, FALSE, g)
462
463G_END_DECLS
464
465#endif // DT_WIDGETS_ACCELERATORS_H
void dt_accels_connect_accels(dt_accels_t *accels)
Actually enable accelerators after having loaded user config.
void(* dt_accels_recent_set_handler_t)(int index, const char *value)
void dt_accels_set_top_offset_handler(dt_accels_top_offset_handler_t handler)
static void dt_accels_disable(dt_accels_t *accels, gboolean state)
void(* dt_accels_refocus_handler_t)(void)
void dt_accels_connect_active_group(dt_accels_t *accels, const gchar *group)
Connect the contextual active accels group to the window. Views can declare their own set of contextu...
void dt_accels_disconnect_active_group(dt_accels_t *accels)
Disconnect the contextual active accels group from the window.
gboolean dt_accels_dispatch(GtkWidget *w, GdkEvent *event, gpointer user_data)
Force our listener for all key strokes to bypass reserved Gtk keys.
void dt_accels_remove_shortcut(dt_accels_t *accels, const char *path)
Remove the shortcut object identified by path and all its accels.
dt_accels_t * dt_accels_init(char *config_file, GtkAccelFlags flags)
void dt_accels_set_refocus_handler(dt_accels_refocus_handler_t handler)
dt_accels_t * dt_accels_get_global(void)
void dt_accels_cleanup(dt_accels_t *accels)
dt_shortcut_type_t
@ DT_SHORTCUT_UNSET
@ DT_SHORTCUT_USER
@ DT_SHORTCUT_DEFAULT
void dt_accels_search(dt_accels_t *accels, GtkWindow *main_window, GtkWidget *anchor)
gchar *(* dt_accels_recent_get_handler_t)(int index)
void dt_accels_window(dt_accels_t *accels, GtkWindow *main_window)
Show the modal dialog listing all available keyboard shortcuts and letting user to set them.
void dt_accels_new_virtual_shortcut(dt_accels_t *accels, GtkAccelGroup *accel_group, const gchar *accel_path, GtkWidget *widget, guint key_val, GdkModifierType accel_mods)
Add a new virtual shortcut. Virtual shortcuts are immutable, read-only and don't trigger any action....
void dt_accels_set_recent_handlers(dt_accels_recent_get_handler_t get, dt_accels_recent_set_handler_t set)
void dt_accels_set_global(dt_accels_t *accels)
void dt_accels_new_virtual_instance_shortcut(dt_accels_t *accels, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gpointer data, GtkAccelGroup *accel_group, const gchar *action_scope, const gchar *action_name)
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
Build the accel path of feature under scope.
gint(* dt_accels_top_offset_handler_t)(void)
void dt_accels_new_action_shortcut(dt_accels_t *accels, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gpointer data, GtkWidget *target_widget, GtkAccelGroup *accel_group, const gchar *action_scope, const gchar *action_name, guint key_val, GdkModifierType accel_mods, const gboolean lock, const char *description)
Register a new shortcut for a generic action, setting up its path, default keys and accel group....
void dt_accels_remove_accel(dt_accels_t *accels, const char *path, gpointer data)
Recursively remove all accels for all shortcuts containing path. This is unneeded for accels attached...
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
void dt_accels_load_user_config(dt_accels_t *accels)
Loads keyboardrc.lang from config dir. This needs to run after we inited the accel map from widgets c...
void dt_accels_new_widget_shortcut(dt_accels_t *accels, GtkWidget *widget, const gchar *signal, GtkAccelGroup *accel_group, const gchar *accel_path, guint key_val, GdkModifierType accel_mods, const gboolean lock)
Register a new shortcut for a widget, setting up its path, default keys and accel group....
void dt_accels_attach_scroll_handler(dt_accels_t *accels, gboolean(*callback)(GdkEventScroll event, void *data), void *data)
Attach a new global scroll event callback. So far this is used in darkroom to redirect scroll events ...
void dt_accels_detach_scroll_handler(dt_accels_t *accels)
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:168
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
const float uint32_t state[4]
gboolean(* callback)(GdkEventScroll event, void *data)
GtkAccelFlags flags
gboolean disable_accels
GdkKeymap * keymap
gboolean init
GtkAccelGroup * slideshow_accels
GtkAccelKey active_key
GtkAccelGroup * map_accels
GtkAccelGroup * global_accels
GtkAccelGroup * print_accels
GtkAccelGroup * lighttable_accels
GdkModifierType default_mod_mask
char * config_file
dt_pthread_mutex_t lock
GHashTable * acceleratables
GtkAccelGroup * active_group
GtkAccelGroup * darkroom_accels
GdkModifierType mods
GtkAccelGroup * accel_group
gboolean locked
dt_shortcut_type_t type
dt_accels_t * accels
GtkWidget * widget
gboolean virtual_shortcut
const char * signal
const char * description
dt_pthread_mutex_t lock
Definition supervisor.c:123