1
/* ide-source-view-mode.c
3
* Copyright (C) 2015 Alexander Larsson <alexl@redhat.com>
4
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
#define G_LOG_DOMAIN "ide-source-view-mode"
22
#include <glib/gi18n.h>
24
#include "ide-debug.h"
25
#include "ide-source-view.h"
26
#include "ide-source-view-mode.h"
28
struct _IdeSourceViewMode
30
GtkWidget parent_instance;
36
IdeSourceViewModeType type;
39
G_DEFINE_TYPE (IdeSourceViewMode, ide_source_view_mode, GTK_TYPE_WIDGET)
47
static GParamSpec *gParamSpecs [LAST_PROP];
50
get_param (IdeSourceViewMode *self,
54
GtkStyleContext *context;
56
g_assert (IDE_IS_SOURCE_VIEW_MODE (self));
57
g_assert (param != NULL);
58
g_assert (value != NULL);
60
context = gtk_widget_get_style_context (GTK_WIDGET (self));
61
gtk_style_context_get_style_property (context, param, value);
65
get_boolean_param (IdeSourceViewMode *self,
71
g_value_init (&value, G_TYPE_BOOLEAN);
72
get_param (self, param, &value);
73
ret = g_value_get_boolean (&value);
74
g_value_unset (&value);
80
get_string_param (IdeSourceViewMode *self,
86
g_value_init (&value, G_TYPE_STRING);
87
get_param (self, param, &value);
88
ret = g_value_dup_string (&value);
89
g_value_unset (&value);
95
ide_source_view_mode_get_default_mode (IdeSourceViewMode *self)
98
* instead of switching back to "default" mode, use this mode instead
99
* if no other mode is specified.
101
return self->default_mode;
105
ide_source_view_mode_get_display_name (IdeSourceViewMode *self)
107
return self->display_name;
111
ide_source_view_mode_get_repeat_insert_with_count (IdeSourceViewMode *self)
114
* If count is 10, and you type -, you will get ----------
116
return get_boolean_param (self, "repeat-insert-with-count");
120
ide_source_view_mode_get_suppress_unbound (IdeSourceViewMode *self)
123
* unknown keypresses are swallowed. you probably want to use this
124
* with a transient mode.
126
return get_boolean_param (self, "suppress-unbound");
130
ide_source_view_mode_get_block_cursor (IdeSourceViewMode *self)
133
* fakes a block cursor by using overwrite mode in textview.
134
* you probably want to use this with "suppress-unbound".
136
return get_boolean_param (self, "block-cursor");
139
ide_source_view_mode_get_keep_mark_on_char (IdeSourceViewMode *self)
141
/* forces the source view to not let the cursor reach the end of the
142
* line (basically an iter over \n). this is useful for emulating vim
144
return get_boolean_param (self, "keep-mark-on-char");
148
ide_source_view_mode_finalize (GObject *object)
150
IdeSourceViewMode *self = IDE_SOURCE_VIEW_MODE (object);
152
g_clear_object (&self->view);
153
g_clear_pointer (&self->name, g_free);
154
g_clear_pointer (&self->default_mode, g_free);
155
g_clear_pointer (&self->display_name, g_free);
158
G_OBJECT_CLASS (ide_source_view_mode_parent_class)->finalize (object);
162
proxy_closure_marshal (GClosure *closure,
163
GValue *return_value,
164
guint n_param_values,
165
const GValue *param_values,
166
gpointer invocation_hint,
167
gpointer marshal_data)
170
IdeSourceViewMode *mode = IDE_SOURCE_VIEW_MODE (g_value_get_object (¶m_values[0]));
172
param_copy = g_memdup (param_values, sizeof (GValue) * n_param_values);
174
param_copy[0].data[0].v_pointer = mode->view;
175
g_signal_emitv (param_copy,
176
GPOINTER_TO_INT (closure->data),
183
proxy_all_action_signals (GType type)
190
signals = g_signal_list_ids (type, &n_signals);
191
for (i = 0; i < n_signals; i++)
193
g_signal_query (signals[i], &query);
195
if (query.signal_flags & G_SIGNAL_ACTION)
197
proxy = g_closure_new_simple (sizeof (GClosure), GINT_TO_POINTER (query.signal_id));
198
g_closure_set_meta_marshal (proxy, NULL, proxy_closure_marshal);
199
g_signal_newv (query.signal_name,
200
IDE_TYPE_SOURCE_VIEW_MODE,
201
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
206
(GType *)query.param_types);
212
ide_source_view_mode_get_name (IdeSourceViewMode *mode)
214
g_return_val_if_fail (IDE_IS_SOURCE_VIEW_MODE (mode), NULL);
220
ide_source_view_mode_get_property (GObject *object,
225
IdeSourceViewMode *mode = IDE_SOURCE_VIEW_MODE(object);
230
g_value_set_string (value, ide_source_view_mode_get_name (mode));
234
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
239
ide_source_view_mode_class_init (IdeSourceViewModeClass *klass)
241
GObjectClass *object_class = G_OBJECT_CLASS (klass);
242
GtkBindingSet *binding_set, *parent_binding_set;
245
object_class->finalize = ide_source_view_mode_finalize;
246
object_class->get_property = ide_source_view_mode_get_property;
248
gParamSpecs [PROP_NAME] =
249
g_param_spec_string ("name",
251
_("The name of the mode."),
253
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
255
g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
257
gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
258
g_param_spec_boolean ("suppress-unbound",
260
"Suppress Unbound Keypresses",
263
G_PARAM_STATIC_STRINGS)));
265
gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
266
g_param_spec_boolean ("block-cursor",
268
"Use fake block cursor by "
269
"using overwrite mode.",
272
G_PARAM_STATIC_STRINGS)));
274
gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
275
g_param_spec_boolean ("keep-mark-on-char",
277
"Don't allow the cursor to "
281
G_PARAM_STATIC_STRINGS)));
283
gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
284
g_param_spec_string ("display-name",
286
"Display name for mode",
289
G_PARAM_STATIC_STRINGS)));
291
gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
292
g_param_spec_string ("default-mode",
294
"Suggest a followup default mode",
297
G_PARAM_STATIC_STRINGS)));
299
gtk_widget_class_install_style_property (GTK_WIDGET_CLASS (klass),
300
g_param_spec_boolean ("repeat-insert-with-count",
301
"Repeat Insert with Count",
302
"Use the current count to "
303
"repeat the insertion.",
306
G_PARAM_STATIC_STRINGS)));
308
/* Proxy all action signals from source view */
309
type = IDE_TYPE_SOURCE_VIEW;
310
while (type != G_TYPE_INVALID && type != GTK_TYPE_WIDGET)
312
proxy_all_action_signals (type);
313
type = g_type_parent (type);
316
/* Add unbind all entries from parent classes (which is
317
really just the GtkWidget ones) so that we *only* add
318
stuff via modes. Any default ones are handled in the
319
normal fallback paths after mode elements are done. */
320
binding_set = gtk_binding_set_by_class (klass);
322
type = g_type_parent (IDE_TYPE_SOURCE_VIEW_MODE);
325
parent_binding_set = gtk_binding_set_find (g_type_name (type));
326
type = g_type_parent (type);
328
if (parent_binding_set)
330
GtkBindingEntry *entry = parent_binding_set->entries;
332
while (entry != NULL)
334
gtk_binding_entry_skip (binding_set, entry->keyval, entry->modifiers);
335
entry = entry->set_next;
342
ide_source_view_mode_init (IdeSourceViewMode *mode)
347
is_modifier_key (GdkEventKey *event)
349
static const guint modifier_keyvals[] = {
350
GDK_KEY_Shift_L, GDK_KEY_Shift_R, GDK_KEY_Shift_Lock,
351
GDK_KEY_Caps_Lock, GDK_KEY_ISO_Lock, GDK_KEY_Control_L,
352
GDK_KEY_Control_R, GDK_KEY_Meta_L, GDK_KEY_Meta_R,
353
GDK_KEY_Alt_L, GDK_KEY_Alt_R, GDK_KEY_Super_L, GDK_KEY_Super_R,
354
GDK_KEY_Hyper_L, GDK_KEY_Hyper_R, GDK_KEY_ISO_Level3_Shift,
355
GDK_KEY_ISO_Next_Group, GDK_KEY_ISO_Prev_Group,
356
GDK_KEY_ISO_First_Group, GDK_KEY_ISO_Last_Group,
357
GDK_KEY_Mode_switch, GDK_KEY_Num_Lock, GDK_KEY_Multi_key,
363
ac_val = modifier_keyvals;
366
if (event->keyval == *ac_val++)
374
toplevel_is_offscreen (GdkWindow *window)
377
* FIXME: This function is a workaround for a segfault in gdk_window_beep()
378
* with offscreen windows.
380
* https://bugzilla.gnome.org/show_bug.cgi?id=748341
384
window = gdk_window_get_parent (window))
388
type = gdk_window_get_window_type (window);
390
if (type == GDK_WINDOW_OFFSCREEN)
398
_ide_source_view_mode_do_event (IdeSourceViewMode *mode,
402
GtkStyleContext *context;
403
gboolean suppress_unbound;
406
g_return_val_if_fail (IDE_IS_SOURCE_VIEW_MODE (mode), FALSE);
407
g_return_val_if_fail (event, FALSE);
408
g_return_val_if_fail (remove, FALSE);
410
context = gtk_widget_get_style_context (GTK_WIDGET (mode));
412
suppress_unbound = ide_source_view_mode_get_suppress_unbound (mode);
414
g_object_ref (context);
415
gtk_style_context_save (context);
416
gtk_style_context_add_class (context, mode->name);
417
handled = gtk_bindings_activate_event (G_OBJECT (mode), event);
418
gtk_style_context_restore (context);
419
g_object_unref (context);
424
case IDE_SOURCE_VIEW_MODE_TYPE_TRANSIENT:
431
if (!is_modifier_key (event))
433
if (!toplevel_is_offscreen (event->window))
434
gtk_widget_error_bell (mode->view);
441
case IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT:
443
/* don't block possible accelerators, but supress others */
444
if (!handled && suppress_unbound && ((event->state & GDK_MODIFIER_MASK) == 0))
446
if (!is_modifier_key (event) && !toplevel_is_offscreen (event->window))
447
gdk_window_beep (event->window);
449
/* cancel any inflight macros */
450
g_signal_emit_by_name (mode->view, "end-macro");
457
case IDE_SOURCE_VIEW_MODE_TYPE_MODAL:
462
g_assert_not_reached ();
469
_ide_source_view_mode_new (GtkWidget *view,
471
IdeSourceViewModeType type)
473
IdeSourceViewMode *mode;
475
mode = g_object_new (IDE_TYPE_SOURCE_VIEW_MODE, NULL);
477
mode->view = g_object_ref (view);
478
mode->name = g_strdup (name);
481
if (mode->name != NULL)
483
GtkStyleContext *context;
485
context = gtk_widget_get_style_context (GTK_WIDGET (mode));
486
gtk_style_context_add_class (context, mode->name);
489
mode->default_mode = get_string_param (mode, "default-mode");
490
mode->display_name = get_string_param (mode, "display-name");
492
IDE_TRACE_MSG ("supress_unbound = %d", ide_source_view_mode_get_suppress_unbound (mode));
493
IDE_TRACE_MSG ("block_cursor = %d", ide_source_view_mode_get_block_cursor (mode));
494
IDE_TRACE_MSG ("type = %d", (int)mode->type);
495
IDE_TRACE_MSG ("default_mode = %s", mode->default_mode ?: "(null)");
496
IDE_TRACE_MSG ("display_name = %s", mode->display_name ?: "(null)");
498
return g_object_ref_sink (mode);
501
IdeSourceViewModeType
502
ide_source_view_mode_get_mode_type (IdeSourceViewMode *self)
504
g_return_val_if_fail (IDE_IS_SOURCE_VIEW_MODE (self), 0);