Search code examples
cmouseovergtk3

How do I set the mouse cursor to cross hair over a GtkDrawingArea?


In GTK3, How do I set the mouse cursor to cross hair when hovering over a GtkWidget, in this case a GtkDrawingArea?


Solution

  • First of all, you must tell the GtkDrawingArea widget to use a backing window, in order to receive events:

    gtk_widget_set_has_window (GTK_WIDGET (darea), TRUE);
    

    Then you must tell it which events you wish to subscribe to; in this case, you want the crossing events, in order to receive notification of the pointer entering and leaving the widget:

    int crossing_mask = GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
    gtk_widget_add_events (GTK_WIDGET (darea), crossing_mask);
    

    At this point, you can connect to the GtkWidget::enter-notify-event and GtkWidget::leave-notify-event signals:

    g_signal_connect (darea, "enter-notify-event", G_CALLBACK (on_crossing), NULL);
    g_signal_connect (darea, "leave-notify-event", G_CALLBACK (on_crossing), NULL);
    

    You can use two separate signal handlers, if you want, but unless you're doing something complex in them, the code is going to be pretty much identical.

    The on_crossing() handler will look something like this:

    static gboolean
    on_crossing (GtkWidget *darea, GdkEventCrossing *event)
    {
      switch (gdk_event_get_event_type (event))
        {
        case GDK_ENTER_NOTIFY:
          // Do something on enter
          break;
    
        case GDK_LEAVE_NOTIFY:
          // Do something on leave
          break;
        }
    }
    

    Now you have specify the cursor to use depending on the event type. GTK+ uses the same cursor names as CSS does; you need to create a cursor instance using one of those names and then associate it to the GdkWindow used by the drawing area widget:

    // Get the display server connection
    GdkDisplay *display = gtk_widget_get_display (darea);
    GdkCursor *cursor;
    
    switch (gdk_event_get_event_type (event))
      {
      case GDK_ENTER_NOTIFY:
        cursor = gdk_cursor_new_from_name (display, "crosshair");
        break;
      case GDK_LEAVE_NOTIFY:
        cursor = gdk_cursor_new_from_name (display, "default");
        break;
      }
    
    // Assign the cursor to the window
    gdk_window_set_cursor (gtk_widget_get_window (darea), cursor);
    
    // Release the reference on the cursor
    g_object_unref (cursor);