Intercept X11 KeyPress event in GtkDrawingArea of GTK+3 on Linux - gtk

GTK+ version: 3.18.9
I created a drawing area (GtkWidget) with following code
content = gtk_drawing_area_new();
gtk_widget_set_can_focus(content, TRUE);
gtk_widget_add_events(content, GDK_ALL_EVENTS_MASK);
g_signal_connect(content, "draw", G_CALLBACK(&drawCallback), ctx);
gtk_widget_realize(content);
// Add a filter for interception
gdk_window_add_filter(content, gtk_widget_get_window(content),
OnXEvent, NULL);
Problem is that when I clicked the wideget, I got sequence of XEvents as follows:
LeaveNotify
FocusIn
EnterNotify
ButtonPress
FocusOut // Lost focus!
ButtonRelease
Above FocusOut indicated we lost focus right away after clicking.
It implies we can't receive any keyboard events since they are available only within focus.
Is this limitation of GTK? If not, is there any tools/methodlogy to find out which widget/widow trigger the FocusOut?
References:
gdk_window_add_filter

As of GTK+ version 3.18.9, it uses an extra X window for toplevel window and any keyboard events are captured by the window. Thus a filter need to be added as a global one, i.e.
gdk_window_add_filter(NULL, OnXEvent, NULL)
Note that the API was removed in this commit in GTK+ 4.x.

Related

Configure dwm (Linux) to peek when MODKEY is held

I just installed dwm on Arch and am loving it. However, I found that I have no use for the status bar except when I'm switching tags, so I thought a useful feature would be to only display it while MODKEY is pressed.
I know that MODKEY+b toggles the bar, but I'd like to be able to peek at it while MODKEY's being held down. I'd also prefer that this doesn't consume the event, so I'll still be able to chain additional keys onto the sequence.
The only thing I found online about this was a post from Lokichaos (https://warosu.org/g/thread/24122078):
I split the difference with "peek" behavior. When I hold down Mod4 (my main dwm modkey) it shows the bar (but does not reserve space for it). The bar also auto-shows when there is an urgent client waiting (so I can see the highlighted tag). [...]
Is there any way I could implement this with my config.h file, or would I need to get into the nitty-gritty dwm.c? Any ideas as to how this could be done in an organized fashion so that I could bind other actions to key presses and releases?
Thanks for your help!
--EDIT--
This patch allows you to listen to release events, (they even show you how to toggle the bar with pressing/releasing MODKEY+b), but I'm only able to listen to presses and releases on non-mod keys. Again, my goal is to have the bar display when I press MODKEY, and disappear again when I release it.
Here are the three things I've tried in config.h:
type modifier key function argument
{ KeyRelease,MODKEY, 0, togglebar, {0} },
{ KeyRelease,MODKEY, NULL, togglebar, {0} },
{ KeyRelease,MODKEY, XK_Super_L, togglebar, {0} },
...to no avail.
You may try holdbar patch to serve your purpose. I am using this and it is working seamlessly without any errors.
Note that after using this, togglebar will not work any more and bar will be always hidden. Also you cannot map HOLDKEY to simply MODKEY as it takes keysym bindings. You can get them by running xev and pressing the required key. It's keysym value in hexadecimal will be displayed. I use the Super (Windows) key and it's keysym value is 0xffeb. I have applied the same patch. If you want to see, you can view it on Github.

Multitouch GTK3 Example

From what I understand, multitouch support was added to GTK+ as of version 3.4. What I'm not clear on is whether this applies just to touch screens like phones/tablets or whether it extends to Apple style touch pads (the way Ubuntu/Unity and OS X use multitouch gestures on the touchpad).
I've also had a hard time finding examples of how to implement gestures and how to track multitouch events.
Are there any good examples of how to implement multitouch with GTK (or something related like Clutter)?
I also couldn't find examples so here is my knowledge about it:
Mouse events (introduction):
When using mouse Gdk propagates events GDK_BUTTON_PRESS, GDK_BUTTON_RELEASE (and a few other). That gets translated into GtkWidget signals like button-press-event and then into higher level ones like GtkButton's clicked if applicable. Connecting a callback to the button-press-event signal allows access to GdkEventButton structure. Using clicked however frees you from keeping track whether it was a click (press & release) or only a release (during kinetic scrolling for instance).
Touch events:
Touch works a little bit different. There are 4 touch events:
GDK_TOUCH_BEGIN
A new touch event sequence has just started. This event type was added
in 3.4.
GDK_TOUCH_UPDATE
A touch event sequence has been updated. This event type was added in
3.4.
GDK_TOUCH_END
A touch event sequence has finished. This event type was added in 3.4.
GDK_TOUCH_CANCEL
A touch event sequence has been canceled. This event type was added in
3.4.
and GdkEventTouch structure uses GdkEventSequence for differentiating between fingers. It seems to me that it is simply a value (couldn't find definition in the sources) but I may be mistaken here. GtkWidget has touch-event signal similar to button-press-event etc that also gets translated into events like clicked.
Sample code (using gtkmm but core aspects are the same):
#include <gtkmm.h>
#include <iostream>
int main()
{
auto app = Gtk::Application::create();
Gtk::Window window;
window.set_default_size(1024, 768);
app->signal_startup().connect([&]
{
app->add_window(window);
});
window.show();
//code works for me without adding events mask but let's be thorough
window.add_events(Gdk::TOUCH_MASK);
window.signal_touch_event().connect([&](GdkEventTouch* event)->bool
{
std::cout<<"TOUCH EVENT: ";
switch(event->type)
{
case GDK_TOUCH_BEGIN:
std::cout<<"begin ";
break;
case GDK_TOUCH_UPDATE:
std::cout<<"update ";
break;
case GDK_TOUCH_END:
std::cout<<"end ";
break;
case GDK_TOUCH_CANCEL:
std::cout<<"cancel ";
break;
default:
std::cout<<"something else ";
}
std::cout<<event->sequence<<" "
<<gdk_event_get_event_sequence((GdkEvent*)event)<<" "
<<std::endl;
return GDK_EVENT_PROPAGATE;
});
window.signal_event().connect([&](GdkEvent* event)->bool
{
std::cout<<"EVENT: "<<event->type<<std::endl;
return GDK_EVENT_PROPAGATE;
});
app->run();
return 0;
}
Touchpad events:
There are also touchpad & pad events and structures but it seems that there is no explicit handling of these on Gtk level. It has to be done in callback for event signal with checking GdkEventType and casting it into appropriate structures.

GTK+ (2.0) - signal "clicked" on GtkEntry?

I'm testing some signals with GTK+ 2.0. I'm looking for a way to get a signal emitted when I click on a GtkEntry.
if (widgets_info[i].action & IG_INPUT)
{
widget->frame[i] = gtk_entry_new_with_max_length(MAX_INPUT_LENGTH);
gtk_entry_set_text(widget->frame[i], widgets_info[i].text);
catch_signal(widget->frame[i], MY_SIGNAL, &change_entry, widget);
}
I have a pre-selected text in my entry (widgets_info[i].text) and i want this text to disappear if the user click on my GtkEntry.
Does someone know what is this signal?
(Sorry for my English)
Try focus-in-event, note that you must enable focus-tracking as described in the documentation.
The button-press-event signal should do what you need:
http://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-button-press-event
However, in GTK+ 3, GtkEntry now supports this idea of placeholder text, so you don't need to implement it yourself:
http://developer.gnome.org/gtk3/stable/GtkEntry.html#gtk-entry-set-placeholder-text

Simulate mouse on Mac

I have a virtual trackpad on my iPhone and to move my mouse I'm using :
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, CGPointMake(((float)aD.msg)+location.x, ((float)aD.msg2)+location.y));
It's working well but this not a real mouse because when I put my mouse on my hidden dock, this one doesn't display it self. I don't understand why.
More over I tried to simulate mouse click with :
case MOUSECLICK:
[self postMouseEventWithButton:0 withType:kCGEventLeftMouseDown andPoint:CGEventGetLocation(CGEventCreate(NULL))];
[self postMouseEventWithButton:0 withType:kCGEventLeftMouseUp andPoint:CGEventGetLocation(CGEventCreate(NULL))];
// *********************
-(void)postMouseEventWithButton:(CGMouseButton)b withType:(CGEventType)t andPoint:(CGPoint)p
{
CGEventRef theEvent = CGEventCreateMouseEvent(NULL, t, p, b);
CGEventSetType(theEvent, t);
CGEventPost(kCGHIDEventTap, theEvent);
CFRelease(theEvent);
}
Is it the good method? Thanks for your help !
CGDisplayMoveCursorToPoint() only moves the image of the cursor, it does not generate any events. You should create and post mouse events of type kCGEventMouseMoved to simulate moving the mouse. Your own method would do it:
[self postMouseEventWithButton:0 withType:kCGEventMouseMoved andPoint:point];
For clicks, you are already doing it the right way, I think. One thing you should also do is set the click count properly on both the mouse down and mouse up events, like so:
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 1);
... because some applications need it.
(See also Simulating mouse clicks on Mac OS X does not work for some applications)
If your code doesn't work, I'm not sure why; it looks OK to me. Try posting to kCGSessionEventTap instead of kCGHIDEventTap and see if it helps. Also, you don't need the CGEventSetType() call since the type is already set in the creation call.

Gtkmm - "Gdk::Window::pointer_grab" troubles

I am programming an FPS (First Person Shooter) game using "Gtkmm" as a window manager and I would like to do the "mouse-look". Therefore, I have to "grab" the mouse pointer to redirect all the mouse motion events to my application window.
There seems to be three overloaded functions to do that job and I have chosen the simplest one for the beginning:
Gdk::GrabStatus Gdk::Window::pointer_grab(bool owner_events, Gdk::EventMask event_mask, guint32 timestamp)
I have tried to put this function to my application but I have had "bad results" so far - it doesn't do what I want it to, it behaves "differently" on "Windows" than on "Linux", etc...
So I will write down what I have done so far, but first, what is my target: "I want to have my application in a window and want to be able to do the mouse-look with a mouse even when I leave the window with the mouse pointer".
So let's get to the function parameters:
-->bool owner_events: when I set it to "true", I got events only when I was inside the window, but (worse) when I set it to "false", I didn't get any events - so I set it to true (the better option :-) )
-->Gdk::EventMask event_mask: there should be those events which I want to catch. For now, I am interested only in mouse motion events, so I put there only "Gdk::POINTER_MOTION_MASK"
-->guint32 timestamp: this I also don't understand but when I put there pure "0", the grab status was OK, thus "GRAB_SUCCESS" (when I tried to set it to 1, 2 or whatever other number, it returned "GRAB_INVALID_TIME" as a grab status) - so I set it to "0"
And now when I run it on Linux, it although grabs the pointer and when I click somewhere outside the window, it doesn't react (thus my window stays always at the top, which is what "I want"), but the problem is that, that the application doesn't catch any events or catches it only when I am inside the window (when I set owner_events to true).
And on Windows it is yet worse: when I click somewhere outside the window, it switches me to the area where I clicked - so this is the same as "without grabbing".
Could someone tell me, what I am doing wrong, or give me a little example on using grabbing in Gtkmm?
For the event_mask, you should include Gdk::ENTER_NOTIFY_MASK and Gdk::BUTTON_RELEASE_MASK so you can ungrab the point when it either reenters the window or when the button is released.
For timestamp, either pass the GdkEvent...::time member, or Gdk::CURRENT_TIME.