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
18 darktable is free software: you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation, either version 3 of the License, or
21 (at your option) any later version.
22
23 darktable is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with darktable. If not, see <http://www.gnu.org/licenses/>.
30*/
31#include <gdk/gdkkeysyms.h>
32#include <gtk/gtk.h>
33#ifdef GDK_WINDOWING_WAYLAND
34#include <gdk/gdkwayland.h>
35#endif
36
37#include "system/dtpthread.h"
38
39G_BEGIN_DECLS
40
41#define DT_ACCELS_WIDGET_SHORTCUT_KEY "dt-accel-shortcut"
42#define DT_ACCELS_WIDGET_TOOLTIP_DISABLED_KEY "dt-accel-tooltip-disabled"
43
119#ifndef DT_WIDGETS_ACCELERATORS_H
120#define DT_WIDGETS_ACCELERATORS_H
121
122/* Ansel's accelerator system is fully custom (see dt_accels_dispatch()) and never
123 * goes through GTK's own accelerator string parser, so it gets none of the
124 * "<Primary>" -> Ctrl/Cmd translation that convention normally provides for free.
125 * Each default shortcut that is meant to follow the OS's own accelerator
126 * convention (most menu/window-level shortcuts) must be registered with
127 * DT_PRIMARY_MASK instead of GDK_CONTROL_MASK. A shortcut that must remain the
128 * literal Ctrl key even on macOS should keep GDK_CONTROL_MASK explicitly.
129 * On the Quartz GDK backend a physical Cmd keypress is reported through
130 * GDK_MOD2_MASK (see _accels_keys_decode() in accelerators.c for the matching
131 * GDK_META_MASK duplicate it has to filter out on that same backend). */
132#ifdef GDK_WINDOWING_QUARTZ
133#define DT_PRIMARY_MASK GDK_MOD2_MASK
134#else
135#define DT_PRIMARY_MASK GDK_CONTROL_MASK
136#endif
137
138typedef struct dt_accels_t
139{
141 GtkAccelGroup *global_accels; // used, aka init it and free it
142 GtkAccelGroup *darkroom_accels; // darkroom-specific accels
143 GtkAccelGroup *lighttable_accels; // lighttable-specific accels
144 GtkAccelGroup *map_accels; // map-specific accels
145 GtkAccelGroup *print_accels; // print-specific accels
146 GtkAccelGroup *slideshow_accels; // slideshow-specific accels
147
148 // reference to the above group currently loaded in the main window. don't init,
149 // don't free, only update
150 GtkAccelGroup *active_group;
151
152 GHashTable *acceleratables; // Key/value list of path/dt_shortcut_t
153 gint reset; // ref counter of how many parts disconnected accels
154 GdkKeymap *keymap; // default screen keymap to decode key values
155 GdkModifierType default_mod_mask; // set of modifier masks relevant only to key strokes
156
157 // TRUE if we didn't find a keyboardrc config file at startup and we need to init a new one
158 gboolean init;
159
160 // between key_pressed and key_release events, this stores the active key strokes
161 GtkAccelKey active_key;
162
163 // Temporarily disable accelerators
165
166 GtkAccelFlags flags;
167
168 dt_pthread_mutex_t lock;
169
170 // Views can register a global callback to handle scroll events
171 // for example while keystrokes are on.
172 struct scroll
173 {
174 gboolean (*callback)(GdkEventScroll event, void *data);
175 void *data;
176 } scroll;
178
180{
181 DT_SHORTCUT_UNSET = 0, // shortcut non-inited
182 DT_SHORTCUT_DEFAULT = 1, // shortcut inited with compile-time defaults
183 DT_SHORTCUT_USER = 2 // shortcut changed by user config
185
186typedef struct dt_shortcut_t
187{
188 GtkWidget *widget; // link to the widget being accelerated. Can be NULL.
189 GList *closure; // GList of GClosures, aka callback + data being accelerated. Always non-NULL once
190 // built through dt_accels_new_{widget,action,virtual}_shortcut(): accel groups are
191 // never attached to a GtkWindow (see dt_accels_dispatch), so the internal dispatcher
192 // is the only path that can activate a shortcut, and it always goes through this closure.
193 char *path; // global path for that accel
194 const char *signal; // widget signal to be wired to that accel
195 GtkAccelGroup *accel_group; // the accel_group to which this shortcut belongs
196 guint key; // default key
197 GdkModifierType mods; // default modifier
199 gboolean locked; // if shortcut can't be changed by user
200 gboolean virtual_shortcut; // if shortcut is mapped to a key-pressed event handler instead of a global action callback
201 const char *description; // user-legible description of the action
202 dt_accels_t *accels; // back-reference for convenience
204
205
206dt_accels_t *dt_accels_init(char *config_file, GtkAccelFlags flags);
207void dt_accels_cleanup(dt_accels_t *accels);
208
209
210gchar *dt_accels_build_path(const gchar *scope, const gchar *feature);
211
219
220
227
228
237void dt_accels_connect_active_group(dt_accels_t *accels, const gchar *group);
238
245
246
259void dt_accels_new_virtual_shortcut(dt_accels_t *accels, GtkAccelGroup *accel_group, const gchar *accel_path,
260 GtkWidget *widget,
261 guint key_val, GdkModifierType accel_mods);
262
263
265 gboolean (*action_callback)(GtkAccelGroup *group,
266 GObject *acceleratable, guint keyval,
267 GdkModifierType mods, gpointer user_data),
268 gpointer data, GtkAccelGroup *accel_group, const gchar *action_scope,
269 const gchar *action_name);
270
284void dt_accels_new_widget_shortcut(dt_accels_t *accels, GtkWidget *widget, const gchar *signal,
285 GtkAccelGroup *accel_group, const gchar *accel_path, guint key_val,
286 GdkModifierType accel_mods, const gboolean lock);
287
288
321 gboolean (*action_callback)(GtkAccelGroup *group, GObject *acceleratable,
322 guint keyval, GdkModifierType mods,
323 gpointer user_data),
324 gpointer data, GtkWidget *target_widget, GtkAccelGroup *accel_group,
325 const gchar *action_scope, const gchar *action_name, guint key_val,
326 GdkModifierType accel_mods, const gboolean lock, const char *description);
327
328
337gboolean dt_accels_dispatch(GtkWidget *w, GdkEvent *event, gpointer user_data);
338
347void dt_accels_attach_scroll_handler(dt_accels_t *accels, gboolean (*callback)(GdkEventScroll event, void *data),
348 void *data);
349
351
352
353// Temporarily enable/disable keyboard accels, for example during GtkEntry typing.
354// Connect it from Gtk focus in/out event handlers
355static inline void dt_accels_disable(dt_accels_t *accels, gboolean state)
356{
357 accels->disable_accels = state;
358}
359
383void dt_accels_remove_accel(dt_accels_t *accels, const char *path, gpointer data);
384
391void dt_accels_remove_shortcut(dt_accels_t *accels, const char *path);
392
399void dt_accels_window(dt_accels_t *accels, GtkWindow *main_window);
400
401void dt_accels_search(dt_accels_t *accels, GtkWindow *main_window, GtkWidget *anchor);
402
403/* ------------------------------------------------------------------------------------------
404 * Host hooks
405 *
406 * The shortcut system is otherwise self-contained GTK: a key arrives, a path is matched, a
407 * closure fires. These four are the only things it cannot answer by itself, so the host
408 * supplies them instead of the module reaching for application globals.
409 *
410 * All are optional. Unregistered, each degrades to a sensible inert default.
411 * ------------------------------------------------------------------------------------------ */
412
416
425
430
435
439typedef gchar *(*dt_accels_recent_get_handler_t)(int index);
440typedef void (*dt_accels_recent_set_handler_t)(int index, const char *value);
443
444/* Shorthand for a darkroom-scoped action shortcut, resolved through this module's own
445 * instance rather than through the application's GUI struct. */
446#define dt_accels_new_darkroom_action(a, b, w, c, d, e, f, g) \
447 dt_accels_new_action_shortcut(dt_accels_get_global(), a, b, w, \
448 dt_accels_get_global()->darkroom_accels, c, d, e, f, FALSE, g)
449
450G_END_DECLS
451
452#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)
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