diff --git a/uppsrc/CtrlCore/GtkApp.cpp b/uppsrc/CtrlCore/GtkApp.cpp index 94ce7c499..da09dbba7 100644 --- a/uppsrc/CtrlCore/GtkApp.cpp +++ b/uppsrc/CtrlCore/GtkApp.cpp @@ -30,6 +30,7 @@ void InitGtkApp(int argc, char **argv, const char **envptr) Ctrl::ReSkin(); g_timeout_add(20, (GSourceFunc) Ctrl::TimeHandler, NULL); InstallPanicMessageBox(Ctrl::PanicMsgBox); + gdk_window_add_filter(NULL, Ctrl::RootKeyFilter, NULL); } END_UPP_NAMESPACE diff --git a/uppsrc/CtrlCore/GtkCtrl.h b/uppsrc/CtrlCore/GtkCtrl.h index 21c709b96..990a43db9 100644 --- a/uppsrc/CtrlCore/GtkCtrl.h +++ b/uppsrc/CtrlCore/GtkCtrl.h @@ -156,7 +156,11 @@ public: // really private: static Gclipboard& gclipboard(); static Gclipboard& gselection(); static String RenderPrimarySelection(const Value& fmt); - + + static Vector hotkey; + static Vector keyhot; + static Vector modhot; + public: static void EndSession() {} static bool IsEndSession() { return false; } @@ -169,4 +173,7 @@ public: GdkWindow *gdk() const { return top ? top->window->window : NULL; } GtkWindow *gtk() const { return top ? (GtkWindow *)top->window : NULL; } + + static GdkFilterReturn RootKeyFilter(GdkXEvent *xevent, GdkEvent *event, gpointer data); + //$ }; diff --git a/uppsrc/CtrlCore/GtkEvent.cpp b/uppsrc/CtrlCore/GtkEvent.cpp index 6dfa09a16..93e4e7e19 100644 --- a/uppsrc/CtrlCore/GtkEvent.cpp +++ b/uppsrc/CtrlCore/GtkEvent.cpp @@ -446,7 +446,20 @@ void Ctrl::Proc() kv |= K_CTRL; if(GetAlt() && kv != K_ALT_KEY) kv |= K_ALT; - LLOG(GetKeyDesc(kv) << ", pressed: " << pressed << ", count: " << CurrentEvent.count); + DLOG(GetKeyDesc(kv) << ", pressed: " << pressed << ", count: " << CurrentEvent.count); +#ifdef GDK_WINDOWING_X11 + DDUMP(FormatIntHex(kv)); + if(pressed) + for(int i = 0; i < hotkey.GetCount(); i++) { + DDUMP(FormatIntHex(keyhot[i])); + DDUMP((bool)hotkey[i]); + if(hotkey[i] && keyhot[i] == kv) { + DLOG("CALL!"); + hotkey[i](); + return; + } + } +#endif DispatchKey(!pressed * K_KEYUP + kv, CurrentEvent.count); } break; diff --git a/uppsrc/CtrlCore/GtkWnd.cpp b/uppsrc/CtrlCore/GtkWnd.cpp index 2f8d26e76..7b746b7c5 100644 --- a/uppsrc/CtrlCore/GtkWnd.cpp +++ b/uppsrc/CtrlCore/GtkWnd.cpp @@ -6,6 +6,10 @@ NAMESPACE_UPP #define LLOG(x) // DLOG(rmsecs() << ' ' << x) +Vector Ctrl::hotkey; +Vector Ctrl::keyhot; +Vector Ctrl::modhot; + Vector Ctrl::wins; int Ctrl::WndCaretTime; @@ -110,36 +114,21 @@ Ctrl *Ctrl::GetActiveCtrl() // Vector Ctrl::hotkey; +#ifndef GDK_WINDOWING_X11 + +// There is no generic support in GTK for HotKey + int Ctrl::RegisterSystemHotKey(dword key, Callback cb) { -/* ASSERT(key >= K_DELTA); - int q = hotkey.GetCount(); - for(int i = 0; i < hotkey.GetCount(); i++) - if(!hotkey[i]) { - q = i; - break; - } - hotkey.At(q) = cb; - dword mod = 0; - if(key & K_ALT) - mod |= MOD_ALT; - if(key & K_SHIFT) - mod |= MOD_SHIFT; - if(key & K_CTRL) - mod |= MOD_CONTROL; - - return RegisterHotKey(NULL, q, mod, key & 0xffff) ? q : -1;*/ return -1; } void Ctrl::UnregisterSystemHotKey(int id) { -/* if(id >= 0 && id < hotkey.GetCount()) { - UnregisterHotKey(NULL, id); - hotkey[id].Clear(); - }*/ } +#endif + void Ctrl::AnimateCaret() { GuiLock __; diff --git a/uppsrc/CtrlCore/GtkX11Util.cpp b/uppsrc/CtrlCore/GtkX11Util.cpp index caad91c03..b6c7555aa 100644 --- a/uppsrc/CtrlCore/GtkX11Util.cpp +++ b/uppsrc/CtrlCore/GtkX11Util.cpp @@ -23,6 +23,11 @@ XDisplay *Xdisplay() return GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); } +Window Xroot() +{ + return GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(gdk_screen_get_default())); +} + String GetProperty(Window w, Atom property, Atom rtype) { GuiLock __; @@ -88,6 +93,76 @@ Vector GetPropertyInts(GdkWindow *w, const char *property) return result; } +dword X11mods(dword key) +{ + dword mod = 0; + if(key & K_ALT) + mod |= Mod1Mask; + if(key & K_SHIFT) + mod |= ShiftMask; + if(key & K_CTRL) + mod |= ControlMask; + return mod; +} + +int Ctrl::RegisterSystemHotKey(dword key, Callback cb) +{ + GuiLock __; + DDUMP(FormatIntHex(key)); + ASSERT(key >= K_DELTA); + gdk_error_trap_push(); + KeyCode k = XKeysymToKeycode(Xdisplay(), key & 0xffff); + dword mod = X11mods(key); + bool r = false; + for(dword nlock = 0; nlock < 2; nlock++) + for(dword clock = 0; clock < 2; clock++) + for(dword slock = 0; slock < 2; slock++) + r = XGrabKey(Xdisplay(), k, + mod | (nlock * Mod2Mask) | (clock * LockMask) | (slock * Mod3Mask), + Xroot(), true, GrabModeAsync, GrabModeAsync) || r; + gdk_error_trap_pop(); + if(!r) return -1; + int q = hotkey.GetCount(); + for(int i = 0; i < hotkey.GetCount(); i++) + if(!hotkey[i]) { + q = i; + break; + } + hotkey.At(q) = cb; + keyhot.At(q) = k; + modhot.At(q) = mod; + return q; +} + +void Ctrl::UnregisterSystemHotKey(int id) +{ + GuiLock __; + if(id >= 0 && id < hotkey.GetCount() && hotkey[id]) { + gdk_error_trap_push(); + for(dword nlock = 0; nlock < 2; nlock++) + for(dword clock = 0; clock < 2; clock++) + for(dword slock = 0; slock < 2; slock++) + XUngrabKey(Xdisplay(), keyhot[id], + modhot[id] | (nlock * Mod2Mask) | (clock * LockMask) | (slock * Mod3Mask), + Xroot()); + gdk_error_trap_pop(); + hotkey[id].Clear(); + } +} + +GdkFilterReturn Ctrl::RootKeyFilter(GdkXEvent *xevent, GdkEvent *Xevent, gpointer data) +{ + XEvent *event = (XEvent *)xevent; + if(event->type == KeyPress) + for(int i = 0; i < hotkey.GetCount(); i++) + if(hotkey[i] && keyhot[i] == event->xkey.keycode && + modhot[i] == (event->xkey.state & (Mod1Mask|ShiftMask|ControlMask))) { + hotkey[i](); + return GDK_FILTER_REMOVE; + } + return GDK_FILTER_CONTINUE; +} + END_UPP_NAMESPACE #endif \ No newline at end of file