]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/gtkwin.c
Enable xterm mouse reporting of wheel actions in GTK.
[PuTTY.git] / unix / gtkwin.c
index 29ac22844e6a40bbc24b9a88fb9c77d84703b081..19ada0b8d5a045151510734ca5b65c04a2e80721 100644 (file)
@@ -94,6 +94,7 @@ struct gui_data {
     int mouseptr_visible;
     int busy_status;
     guint toplevel_callback_idle_id;
+    int idle_fn_scheduled, quit_fn_scheduled;
     int alt_keycode;
     int alt_digits;
     char *wintitle;
@@ -1233,26 +1234,32 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
                         GdkEventType type, guint ebutton, guint state,
                         gdouble ex, gdouble ey)
 {
-    int shift, ctrl, alt, x, y, button, act;
+    int shift, ctrl, alt, x, y, button, act, raw_mouse_mode;
 
     /* Remember the timestamp. */
     inst->input_event_time = timestamp;
 
     show_mouseptr(inst, 1);
 
-    if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
-       term_scroll(inst->term, 0, -5);
-       return TRUE;
-    }
-    if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
-       term_scroll(inst->term, 0, +5);
-       return TRUE;
-    }
-
     shift = state & GDK_SHIFT_MASK;
     ctrl = state & GDK_CONTROL_MASK;
     alt = state & GDK_MOD1_MASK;
 
+    raw_mouse_mode =
+        send_raw_mouse && !(shift && conf_get_int(inst->conf,
+                                                  CONF_mouse_override));
+
+    if (!raw_mouse_mode) {
+        if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
+            term_scroll(inst->term, 0, -5);
+            return TRUE;
+        }
+        if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
+            term_scroll(inst->term, 0, +5);
+            return TRUE;
+        }
+    }
+
     if (ebutton == 3 && ctrl) {
        gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,
                       ebutton, timestamp);
@@ -1265,6 +1272,10 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
        button = MBT_MIDDLE;
     else if (ebutton == 3)
        button = MBT_RIGHT;
+    else if (ebutton == 4)
+       button = MBT_WHEEL_UP;
+    else if (ebutton == 5)
+       button = MBT_WHEEL_DOWN;
     else
        return FALSE;                  /* don't even know what button! */
 
@@ -1276,9 +1287,7 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
       default: return FALSE;          /* don't know this event type */
     }
 
-    if (send_raw_mouse && !(shift && conf_get_int(inst->conf,
-                                                 CONF_mouse_override)) &&
-       act != MA_CLICK && act != MA_RELEASE)
+    if (raw_mouse_mode && act != MA_CLICK && act != MA_RELEASE)
        return TRUE;                   /* we ignore these in raw mouse mode */
 
     x = (ex - inst->window_border) / inst->font_width;
@@ -1403,6 +1412,8 @@ static gint quit_toplevel_callback_func(gpointer data)
 
     notify_toplevel_callback(inst);
 
+    inst->quit_fn_scheduled = FALSE;
+
     return 0;
 }
 
@@ -1414,15 +1425,36 @@ static gint idle_toplevel_callback_func(gpointer data)
         /*
          * We don't run the callbacks if we're in the middle of a
          * subsidiary gtk_main. Instead, ask for a callback when we
-         * get back out of the subsidiary main loop, so we can
-         * reschedule ourself then.
+         * get back out of the subsidiary main loop (if we haven't
+         * already arranged one), so we can reschedule ourself then.
+         */
+        if (!inst->quit_fn_scheduled) {
+            gtk_quit_add(2, quit_toplevel_callback_func, inst);
+            inst->quit_fn_scheduled = TRUE;
+        }
+        /*
+         * And unschedule this idle function, since we've now done
+         * everything we can until the innermost gtk_main has quit and
+         * can reschedule us with a chance of actually taking action.
          */
-        gtk_quit_add(2, quit_toplevel_callback_func, inst);
+        if (inst->idle_fn_scheduled) { /* double-check, just in case */
+            gtk_idle_remove(inst->toplevel_callback_idle_id);
+            inst->idle_fn_scheduled = FALSE;
+        }
     } else {
         run_toplevel_callbacks();
     }
 
-    gtk_idle_remove(inst->toplevel_callback_idle_id);
+    /*
+     * If we've emptied our toplevel callback queue, unschedule
+     * ourself. Otherwise, leave ourselves pending so we'll be called
+     * again to deal with more callbacks after another round of the
+     * event loop.
+     */
+    if (!toplevel_callback_pending() && inst->idle_fn_scheduled) {
+        gtk_idle_remove(inst->toplevel_callback_idle_id);
+        inst->idle_fn_scheduled = FALSE;
+    }
 
     return TRUE;
 }
@@ -1431,8 +1463,11 @@ static void notify_toplevel_callback(void *frontend)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
 
-    inst->toplevel_callback_idle_id =
-        gtk_idle_add(idle_toplevel_callback_func, inst);
+    if (!inst->idle_fn_scheduled) {
+        inst->toplevel_callback_idle_id =
+            gtk_idle_add(idle_toplevel_callback_func, inst);
+        inst->idle_fn_scheduled = TRUE;
+    }
 }
 
 static gint timer_trigger(gpointer data)
@@ -2900,7 +2935,7 @@ char *setup_fonts_ucs(struct gui_data *inst)
             for (i = 0; i < 2; i++)
                 if (fonts[i])
                     unifont_destroy(fonts[i]);
-            return dupprintf("%s: unable to load wide font \"%s\"", fs->name);
+            return dupprintf("unable to load wide font \"%s\"", fs->name);
        }
     } else {
        fonts[2] = NULL;
@@ -2916,8 +2951,7 @@ char *setup_fonts_ucs(struct gui_data *inst)
             for (i = 0; i < 3; i++)
                 if (fonts[i])
                     unifont_destroy(fonts[i]);
-           return dupprintf("%s: unable to load wide bold font \"%s\"",
-                             fs->name);
+           return dupprintf("unable to load wide bold font \"%s\"", fs->name);
        }
     }
 
@@ -3604,6 +3638,8 @@ int pt_main(int argc, char **argv)
     inst->busy_status = BUSY_NOT;
     inst->conf = conf_new();
     inst->wintitle = inst->icontitle = NULL;
+    inst->quit_fn_scheduled = FALSE;
+    inst->idle_fn_scheduled = FALSE;
 
     /* defer any child exit handling until we're ready to deal with
      * it */