1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
#include "stdafx.h"
#include "Accelerators.h"
#include "Core/Runtime.h"
#include "Exception.h"
namespace gui {
#if defined(GUI_GTK)
static GcType staticType = {
GcType::tFixed,
null,
null,
sizeof(void *),
1,
{ 0 }
};
static void closureCallback(GtkAccelGroup *group, GObject *accel, guint keyval, GdkModifierType modifiers, void *data) {
Accelerators *me = *(Accelerators **)data;
me->dispatch(KeyChord(from_gtk(keyval), from_gtk(modifiers)));
}
static void closureDestroy(void *data, GClosure *c) {
// No need.
}
#endif
Accelerators::Accelerators() : gtkData(null), staticData(null) {
data = new (this) Map<KeyChord, Accel>();
#if defined(GUI_GTK)
gtkData = gtk_accel_group_new();
staticData = runtime::allocStaticRaw(engine(), &staticType);
*(Accelerators **)staticData = this;
#endif
}
Accelerators::~Accelerators() {
#if defined(GUI_GTK)
g_object_unref(gtkData);
#endif
}
void Accelerators::attach(Handle to) {
#if defined(GUI_GTK)
// Seems like gtk_window_add_accel_group takes ownership of the data (not clearly
// documented). Thus, we need to add a ref here.
g_object_ref(gtkData);
gtk_window_add_accel_group((GtkWindow *)to.widget(), (GtkAccelGroup *)gtkData);
#endif
}
void Accelerators::checkDuplicate(const KeyChord &chord) {
if (data->has(chord))
throw new (this) GuiError(TO_S(this, S("The key combination ") << chord << S(" is already used.")));
}
void Accelerators::add(KeyChord chord, Fn<void> *call) {
checkDuplicate(chord);
data->put(chord, Accel(call));
#if defined(GUI_GTK)
// Note: Does not seem like we can share closure between keys.
GClosure *closure = g_cclosure_new(G_CALLBACK(&closureCallback), staticData, &closureDestroy);
gtk_accel_group_connect((GtkAccelGroup *)gtkData, to_gtk(chord.key), to_gtk(chord.modifiers), (GtkAccelFlags)0, closure);
#endif
}
void Accelerators::add(KeyChord chord, Fn<void> *call, Handle item) {
checkDuplicate(chord);
data->put(chord, Accel(call));
#if defined(GUI_GTK)
guint key = to_gtk(chord.key);
GdkModifierType mods = to_gtk(chord.modifiers);
gtk_widget_add_accelerator(item.widget(), "activate", (GtkAccelGroup *)gtkData, key, mods, GTK_ACCEL_VISIBLE);
#endif
}
void Accelerators::remove(KeyChord chord) {
data->remove(chord);
#if defined(GUI_GTK)
gtk_accel_group_disconnect_key((GtkAccelGroup *)gtkData, to_gtk(chord.key), to_gtk(chord.modifiers));
#endif
}
Bool Accelerators::dispatch(KeyChord chord) {
Accel a = data->get(chord, Accel());
if (!a.any())
return false;
a.call->call();
return true;
}
}
|