Allow use of context menu in text memos GTK
[xboard.git] / gtk / xoptions.c
index 79bce4b..0737c79 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * xoptions.c -- Move list window, part of X front end for XBoard
  *
- * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
+ * Copyright 2000, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
  * ------------------------------------------------------------------------
  *
  * GNU XBoard is free software: you can redistribute it and/or modify
@@ -48,11 +48,10 @@ extern char *getenv();
 #include <stdint.h>
 
 #include <cairo/cairo.h>
-#include <cairo/cairo-xlib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #ifdef OSXAPP
-#  include <gtkmacintegration-gtk2/gtkosxapplication.h>
+#  include <gtkmacintegration/gtkosxapplication.h>
 #endif
 
 #include "common.h"
@@ -244,6 +243,12 @@ SetWidgetLabel (Option *opt, char *buf)
 }
 
 void
+SetComboChoice (Option *opt, int n)
+{
+    gtk_combo_box_set_active(opt->handle, n);
+}
+
+void
 SetDialogTitle (DialogClass dlg, char *title)
 {
     gtk_window_set_title(GTK_WINDOW(shells[dlg]), title);
@@ -444,10 +449,24 @@ CreateMenuPopup (Option *opt, int n, int def)
 
            gtk_accelerator_parse(mb[i].accel, &accelerator_key, &accelerator_mods);
 #ifdef OSXAPP
-           if(accelerator_mods & GDK_CONTROL_MASK) {  // in OSX use Meta where Linux uses Ctrl
-               accelerator_mods &= ~GDK_CONTROL_MASK; // clear Ctrl flag
-               accelerator_mods |= GDK_META_MASK;     // set Meta flag
-           }
+          if(accelerator_mods & GDK_CONTROL_MASK &&
+             accelerator_key != 'v' &&          // don't use Cmd+V as this is a OS text edit command
+             accelerator_key != 'c' &&           // and Cmd+C
+             accelerator_key != 'x' &&          // and CMD+X
+             accelerator_key != 'a'           // and CMD+A
+             ) {  // in OSX use Meta (Cmd) where Linux uses Ctrl
+              accelerator_mods &= ~GDK_CONTROL_MASK; // clear Ctrl flag
+              accelerator_mods |= GDK_META_MASK;     // set Meta flag
+                 } else if (accelerator_mods & GDK_CONTROL_MASK &&
+                                        accelerator_key == 'v' ||
+                                        accelerator_key == 'c' ||
+                                        accelerator_key == 'x' ||
+                                        accelerator_key == 'a'
+                                        ) { // For these conflicting commands, lets make them alt-cmd
+                         accelerator_mods &= ~GDK_CONTROL_MASK; // clear Ctrl flag
+                         accelerator_mods |= GDK_META_MASK;
+                         accelerator_mods |= GDK_MOD1_MASK;
+                 } 
 #endif
            gtk_widget_add_accelerator (GTK_WIDGET(entry), "activate",GtkAccelerators,
                                        accelerator_key, accelerator_mods, GTK_ACCEL_VISIBLE);
@@ -530,11 +549,11 @@ HighlightText (Option *opt, int from, int to, Boolean highlight)
     if(!(opt->min & INIT)) {
        opt->min |= INIT; // each memo its own init flag!
        gtk_text_buffer_create_tag(opt->handle, "highlight", "background", "yellow", NULL);
-       gtk_text_buffer_create_tag(opt->handle, "normal", "background", "white", NULL);
     }
     gtk_text_buffer_get_iter_at_offset(opt->handle, &start, from);
     gtk_text_buffer_get_iter_at_offset(opt->handle, &end, to);
-    gtk_text_buffer_apply_tag_by_name(opt->handle, highlight ? "highlight" : "normal", &start, &end);
+    if(highlight) gtk_text_buffer_apply_tag_by_name(opt->handle, "highlight", &start, &end);
+    else gtk_text_buffer_remove_tag_by_name(opt->handle, "highlight", &start, &end);
 }
 
 static char **names;
@@ -664,10 +683,10 @@ MemoEvent(GtkWidget *widget, GdkEvent *event, gpointer gdata)
            }
            if(memo->value == 250 // kludge to recognize ICS Console and Chat panes
             && gtk_text_buffer_get_selection_bounds(memo->handle, NULL, NULL) ) {
-printf("*** selected\n");
                gtk_text_buffer_get_selection_bounds(memo->handle, &start, &end); // only return selected text
-               index = -1; // kludge to indicate omething was selected
+               index = -1; // kludge to indicate something was selected
            } else {
+               if(abs(button) == 3 && gtk_text_buffer_get_selection_bounds(memo->handle, NULL, NULL)) return FALSE; // normal context menu
 // GTK_TODO: is this really the most efficient way to get the character at the mouse cursor???
                gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_WIDGET, w, h, &x, &y);
                gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &start, x, y);
@@ -680,7 +699,7 @@ printf("*** selected\n");
            }
            /* get text from textbuffer */
            val = gtk_text_buffer_get_text (memo->handle, &start, &end, FALSE);
-           break;
+           if(strlen(val) != index) break; // if we clicked behind all text, fall through to do default action
        default:
            return FALSE; // should not happen
     }
@@ -826,6 +845,16 @@ gboolean GenericPopDown(w, resptype, gdata)
     return TRUE;
 }
 
+gboolean PopDownProxy(w, gdata)
+     GtkWidget *w;
+     gpointer  gdata;
+{
+    GtkResponseType resp = GTK_RESPONSE_ACCEPT;
+    int dlg = (intptr_t) gdata;
+    if(dlg >= 3000) dlg -= 3000, resp = GTK_RESPONSE_REJECT;
+    return GenericPopDown(gtk_widget_get_toplevel(w), resp, (gpointer)(intptr_t)dlg);
+}
+
 int AppendText(Option *opt, char *s)
 {
     char *v;
@@ -1293,7 +1322,7 @@ if(appData.debugMode) printf("n=%d, h=%d, w=%d\n",n,height,width);
             top = breakType = 0; expandable = FALSE;
         }
         if(!SameRow(&option[i])) {
-           if(SameRow(&option[i+1])) {
+           if(SameRow(&option[i+1]) || topLevel && option[i].type == Button && option[i+1].type == EndMark && option[i+1].min & SAME_ROW) {
                GtkAttachOptions x = GTK_FILL;
                // make sure hbox is always available when we have more options on same row
                 hbox = gtk_hbox_new (option[i].type == Button && option[i].textValue || option[i].type == Graph, 0);
@@ -1451,10 +1480,12 @@ if(appData.debugMode) printf("n=%d, h=%d, w=%d\n",n,height,width);
             /* set button color on new variant dialog */
             if(option[i].textValue) {
                 static char *b = "Bold";
+                char *v, *p = NULL, n = option[i].value;
+                if(n >= 0) v = VariantName(n), p = strstr(first.variants, v);
                 gdk_color_parse( option[i].textValue, &color );
                 gtk_widget_modify_bg ( GTK_WIDGET(button), GTK_STATE_NORMAL, &color );
                 gtk_widget_set_sensitive(button, option[i].value >= 0 && (appData.noChessProgram
-                                        || strstr(first.variants, VariantName(option[i].value))));
+                                        || p && (!*v || strlen(p) == strlen(v) || p[strlen(v)] == ',')));
                 if(engineVariant[100] ? !strcmp(engineVariant+100, option[i].name) : 
                    gameInfo.variant ? option[i].value == gameInfo.variant : !strcmp(option[i].name, "Normal"))
                     SetWidgetFont(gtk_bin_get_child(GTK_BIN(button)), &b);
@@ -1635,6 +1666,21 @@ if(appData.debugMode) printf("n=%d, h=%d, w=%d\n",n,height,width);
        }
     }
 
+    if(topLevel && !(option[i].min & NO_OK)) { // buttons requested in top-level window
+        button = gtk_button_new_with_label (_("OK"));
+        g_signal_connect (button, "clicked", G_CALLBACK (PopDownProxy), (gpointer)(intptr_t) dlgNr);
+        if(!(option[i].min & NO_CANCEL)) {
+            GtkWidget *button2 = gtk_button_new_with_label (_("Cancel"));
+            g_signal_connect (button2, "clicked", G_CALLBACK (PopDownProxy), (gpointer)(intptr_t) dlgNr + 3000);
+            if(!hbox) {
+                hbox = gtk_hbox_new (False, 0);
+                gtk_table_attach(GTK_TABLE(table), hbox, left, left+r, top+1, top+2, GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 1);
+            }
+            Pack(hbox, table, button, left, left+1, top+1, 0);
+            Pack(hbox, table, button2, left, left+1, top+1, 0);
+        } else Pack(hbox, table, button, left, left+1, ++top, 0);
+    }
+
     gtk_table_resize(GTK_TABLE(table), top+1, r);
     if(dlgNr == BoardWindow && appData.fixedSize) { // inhibit sizing
        GtkWidget *h = gtk_hbox_new(FALSE, 0);