Make sizing more robust (GTK)
authorH.G.Muller <hgm@hgm-xboard.(none)>
Wed, 23 Mar 2016 19:16:24 +0000 (20:16 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Tue, 29 Mar 2016 14:51:34 +0000 (16:51 +0200)
On sizing we now do not immediately replace the buffer canvas, but set
a flag in the Graph Option to indicate the canvas is invalid. Instead
of taking the canvas handle from a global variable (csBoardWindow) we
now obtain it in every drawing call from a function, which first tests
if the canvas is still valid. If it is not, we replace it by one of
the size specified in the Option (which was obtained from the window
size the moment the flag was set).
 The GraphExpose requests now bypass the general GraphEventProc, by
calling the drawing of the exposed area (which was relocated to a
separate function) directly. This avoids the overhead of checking for
resizing through requesting the window geometry.

dialogs.h
draw.c
gtk/xoptions.c

index fb9ea3d..4954423 100644 (file)
--- a/dialogs.h
+++ b/dialogs.h
@@ -77,6 +77,8 @@
 #define NO_OK          (1 << 1)
 #define NO_CANCEL      (1 << 2)
 
+#define REPLACE                (1 << 16)
+
 #define MODAL 1
 #define NONMODAL 0
 
diff --git a/draw.c b/draw.c
index 89f4851..6df1a13 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -131,9 +131,34 @@ void
 SwitchWindow (int main)
 {
     currBoard = (main ? &mainOptions[W_BOARD] : &dualOptions[3]);
-    csBoardWindow = DRAWABLE(currBoard);
+//    CsBoardWindow = DRAWABLE(currBoard);
 }
 
+
+static void
+NewCanvas (Option *graph)
+{
+       cairo_t *cr;
+       int w = graph->max, h = graph->value;
+       if(graph->choice) cairo_surface_destroy((cairo_surface_t *) graph->choice);
+       graph->choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+       // paint white, to prevent weirdness when people maximize window and drag pieces over space next to board
+       cr = cairo_create ((cairo_surface_t *) graph->choice);
+       cairo_rectangle (cr, 0, 0, w, h);
+       cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+       cairo_fill(cr);
+       cairo_destroy (cr);
+       graph->min &= ~REPLACE;
+}
+
+static cairo_surface_t *
+CsBoardWindow (Option *opt)
+{   // test before every draw event if we need to resize the canvas
+    if(opt->min & REPLACE) NewCanvas(opt);
+    return DRAWABLE(opt);
+}
+
+
 void
 SelectPieces(VariantClass v)
 {
@@ -486,7 +511,7 @@ void DrawSeekAxis( int x, int y, int xTo, int yTo )
     cairo_t *cr;
 
     /* get a cairo_t */
-    cr = cairo_create (csBoardWindow);
+    cr = cairo_create (CsBoardWindow(currBoard));
 
     cairo_move_to (cr, x, y);
     cairo_line_to(cr, xTo, yTo );
@@ -501,7 +526,7 @@ void DrawSeekAxis( int x, int y, int xTo, int yTo )
 
 void DrawSeekBackground( int left, int top, int right, int bottom )
 {
-    cairo_t *cr = cairo_create (csBoardWindow);
+    cairo_t *cr = cairo_create (CsBoardWindow(currBoard));
 
     cairo_rectangle (cr, left, top, right-left, bottom-top);
 
@@ -515,7 +540,7 @@ void DrawSeekBackground( int left, int top, int right, int bottom )
 
 void DrawSeekText(char *buf, int x, int y)
 {
-    cairo_t *cr = cairo_create (csBoardWindow);
+    cairo_t *cr = cairo_create (CsBoardWindow(currBoard));
 
     cairo_select_font_face (cr, "Sans",
                            CAIRO_FONT_SLANT_NORMAL,
@@ -534,7 +559,7 @@ void DrawSeekText(char *buf, int x, int y)
 
 void DrawSeekDot(int x, int y, int colorNr)
 {
-    cairo_t *cr = cairo_create (csBoardWindow);
+    cairo_t *cr = cairo_create (CsBoardWindow(currBoard));
     int square = colorNr & 0x80;
     colorNr &= 0x7F;
 
@@ -560,7 +585,8 @@ void DrawSeekDot(int x, int y, int colorNr)
 void
 InitDrawingHandle (Option *opt)
 {
-    csBoardWindow = DRAWABLE(opt);
+//    CsBoardWindow = DRAWABLE(opt);
+    currBoard = opt;
 }
 
 void
@@ -598,7 +624,7 @@ DrawGrid()
   cairo_t *cr;
 
   /* get a cairo_t */
-  cr = cairo_create (csBoardWindow);
+  cr = cairo_create (CsBoardWindow(currBoard));
 
   cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
   SetPen(cr, lineGap, "#000000", 0);
@@ -630,7 +656,7 @@ DrawBorder (int x, int y, int type, int odd)
        case 2: col = appData.premoveHighlightColor; break;
        default: col = "#808080"; break; // cannot happen
     }
-    cr = cairo_create(csBoardWindow);
+    cr = cairo_create(CsBoardWindow(currBoard));
     cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
     cairo_rectangle(cr, x+odd/2., y+odd/2., squareSize+lineGap, squareSize+lineGap);
     SetPen(cr, lineGap, col, 0);
@@ -665,7 +691,7 @@ DrawLogo (Option *opt, void *logo)
     int w, h;
 
     if(!opt) return;
-    cr = cairo_create(DRAWABLE(opt));
+    cr = cairo_create(CsBoardWindow(opt));
     cairo_rectangle (cr, 0, 0, opt->max, opt->value);
     cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.0);
     cairo_fill(cr); // paint background in case logo does not exist
@@ -759,7 +785,7 @@ DoDrawDot (cairo_surface_t *cs, int marker, int x, int y, int r)
 void
 DrawDot (int marker, int x, int y, int r)
 { // used for atomic captures; no need to draw on backup
-  DoDrawDot(csBoardWindow, marker, x, y, r);
+  DoDrawDot(CsBoardWindow(currBoard), marker, x, y, r);
   GraphExpose(currBoard, x-r, y-r, 2*r, 2*r);
 }
 
@@ -798,7 +824,7 @@ DrawText (char *string, int x, int y, int align)
        cairo_text_extents_t te;
        cairo_t *cr;
 
-       cr = cairo_create (csBoardWindow);
+       cr = cairo_create (CsBoardWindow(currBoard));
        cairo_select_font_face (cr, "Sans",
                    CAIRO_FONT_SLANT_NORMAL,
                    CAIRO_FONT_WEIGHT_BOLD);
@@ -857,10 +883,10 @@ DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, ch
     // piece, background, coordinate/count, marker dot
 
     if (piece == EmptySquare) {
-       BlankSquare(csBoardWindow, x, y, square_color, piece, 1);
+       BlankSquare(CsBoardWindow(currBoard), x, y, square_color, piece, 1);
     } else {
-       pngDrawPiece(csBoardWindow, piece, square_color, x, y);
-        if(appData.inscriptions[0]) InscribeKanji(csBoardWindow, piece, x, y);
+       pngDrawPiece(CsBoardWindow(currBoard), piece, square_color, x, y);
+        if(appData.inscriptions[0]) InscribeKanji(CsBoardWindow(currBoard), piece, x, y);
     }
 
     if(align) { // square carries inscription (coord or piece count)
@@ -869,7 +895,7 @@ DrawOneSquare (int x, int y, ChessSquare piece, int square_color, int marker, ch
     }
 
     if(marker) { // print fat marker dot, if requested
-       DoDrawDot(csBoardWindow, marker, x + squareSize/4, y+squareSize/4, squareSize/2);
+       DoDrawDot(CsBoardWindow(currBoard), marker, x + squareSize/4, y+squareSize/4, squareSize/2);
     }
 }
 
@@ -888,7 +914,7 @@ InitAnimState (AnimNr anr)
 {
     if(c_animBufs[anr]) cairo_surface_destroy (c_animBufs[anr]);
     if(c_animBufs[anr+2]) cairo_surface_destroy (c_animBufs[anr+2]);
-    c_animBufs[anr+4] = csBoardWindow;
+    c_animBufs[anr+4] = CsBoardWindow(currBoard);
     c_animBufs[anr+2] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
     c_animBufs[anr] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, squareSize, squareSize);
 }
@@ -928,13 +954,13 @@ void CopyRectangle (AnimNr anr, int srcBuf, int destBuf,
                 int srcX, int srcY, int width, int height, int destX, int destY)
 {
        cairo_t *cr;
-       c_animBufs[anr+4] = csBoardWindow;
+       c_animBufs[anr+4] = CsBoardWindow(currBoard);
        cr = cairo_create (c_animBufs[anr+destBuf]);
        cairo_set_source_surface (cr, c_animBufs[anr+srcBuf], destX - srcX, destY - srcY);
        cairo_rectangle (cr, destX, destY, width, height);
        cairo_fill (cr);
        cairo_destroy (cr);
-       if(c_animBufs[anr+destBuf] == csBoardWindow) // suspect that GTK needs this!
+       if(c_animBufs[anr+destBuf] == CsBoardWindow(currBoard)) // suspect that GTK needs this!
            GraphExpose(currBoard, destX, destY, width, height);
 }
 
@@ -970,7 +996,7 @@ DoDrawPolygon (cairo_surface_t *cs, Pnt arrow[], int nr)
 void
 DrawPolygon (Pnt arrow[], int nr)
 {
-    DoDrawPolygon(csBoardWindow, arrow, nr);
+    DoDrawPolygon(CsBoardWindow(currBoard), arrow, nr);
 //    if(!dual) DoDrawPolygon(csBoardBackup, arrow, nr);
 }
 
@@ -1008,7 +1034,7 @@ DrawSegment (int x, int y, int *lastX, int *lastY, int penType)
   static int curX, curY;
 
   if(penType != PEN_NONE) {
-    cairo_t *cr = cairo_create(DRAWABLE(disp));
+    cairo_t *cr = cairo_create(CsBoardWindow(disp));
     cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
     cairo_move_to (cr, curX, curY);
     cairo_line_to (cr, x,y);
@@ -1027,7 +1053,7 @@ DrawRectangle (int left, int top, int right, int bottom, int side, int style)
 {
   cairo_t *cr;
 
-  cr = cairo_create (DRAWABLE(disp));
+  cr = cairo_create (CsBoardWindow(disp));
   cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
   cairo_rectangle (cr, left, top, right-left, bottom-top);
   switch(side)
@@ -1054,7 +1080,7 @@ DrawEvalText (char *buf, int cbBuf, int y)
 {
     // the magic constants 8 and 5 should really be derived from the font size somehow
   cairo_text_extents_t extents;
-  cairo_t *cr = cairo_create(DRAWABLE(disp));
+  cairo_t *cr = cairo_create(CsBoardWindow(disp));
 
   /* GTK-TODO this has to go into the font-selection */
   cairo_select_font_face (cr, "Sans",
index f64bc7f..0424147 100644 (file)
@@ -912,6 +912,21 @@ ColorChanged (Widget w, XtPointer data, XEvent *event, Boolean *b)
 }
 #endif
 
+static void
+ExposeDraw (Option *graph, GdkEventExpose *eevent)
+{
+    int w = eevent->area.width;
+    cairo_t *cr;
+    if(eevent->area.x + w > graph->max) w--; // cut off fudge pixel
+    cr = gdk_cairo_create(((GtkWidget *) (graph->handle))->window);
+    cairo_set_source_surface(cr, (cairo_surface_t *) graph->choice, 0, 0);
+//cairo_set_source_rgb(cr, 1, 0, 0);
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+    cairo_rectangle(cr, eevent->area.x, eevent->area.y, w, eevent->area.height);
+    cairo_fill(cr);
+    cairo_destroy(cr);
+}
+
 static void
 GraphEventProc(GtkWidget *widget, GdkEvent *event, gpointer gdata)
 {   // handle expose and mouse events on Graph widget
@@ -924,7 +939,6 @@ GraphEventProc(GtkWidget *widget, GdkEvent *event, gpointer gdata)
     GdkEventMotion *mevent = (GdkEventMotion *) event;
     GdkEventScroll *sevent = (GdkEventScroll *) event;
     GtkAllocation a;
-    cairo_t *cr;
 
 //    if (!XtIsRealized(widget)) return;
 
@@ -957,26 +971,11 @@ GraphEventProc(GtkWidget *widget, GdkEvent *event, gpointer gdata)
                         // to give drawing routines opportunity to use it before first expose event
                         // (which are only processed when main gets to the event loop, so after all init!)
                         // so only change when size is no longer good
-               cairo_t *cr;
-               if(graph->choice) cairo_surface_destroy((cairo_surface_t *) graph->choice);
-               graph->choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
-               // paint white, to prevent weirdness when people maximize window and drag pieces over space next to board
-               cr = cairo_create ((cairo_surface_t *) graph->choice);
-               cairo_rectangle (cr, 0, 0, w, h);
-               cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
-               cairo_fill(cr);
-               cairo_destroy (cr);
+//             NewCanvas(graph);
+               graph->min |= REPLACE; // defer making new canvas
                break;
            }
-           w = eevent->area.width;
-           if(eevent->area.x + w > graph->max) w--; // cut off fudge pixel
-           cr = gdk_cairo_create(((GtkWidget *) (graph->handle))->window);
-           cairo_set_source_surface(cr, (cairo_surface_t *) graph->choice, 0, 0);
-//cairo_set_source_rgb(cr, 1, 0, 0);
-           cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
-           cairo_rectangle(cr, eevent->area.x, eevent->area.y, w, eevent->area.height);
-           cairo_fill(cr);
-           cairo_destroy(cr);
+           ExposeDraw(graph, eevent);
        default:
            return;
        case GDK_SCROLL:
@@ -1019,7 +1018,7 @@ GraphExpose (Option *opt, int x, int y, int w, int h)
   GdkEventExpose e;
   if(!opt->handle) return;
   e.area.x = x; e.area.y = y; e.area.width = w; e.area.height = h; e.count = -1; e.type = GDK_EXPOSE; // count = -1: kludge to suppress sizing
-  GraphEventProc(opt->handle, (GdkEvent *) &e, (gpointer) opt); // fake expose event
+  ExposeDraw(opt, &e); // fake expose event
 }
 
 void GenericCallback(GtkWidget *widget, gpointer gdata)
@@ -1486,7 +1485,7 @@ if(appData.debugMode) printf("n=%d, h=%d, w=%d\n",n,height,width);
                label = frame;
            }
             gtk_widget_set_size_request(label, option[i].max ? option[i].max : -1, -1);
-           if(option[i].target || dlgNr != ErrorDlg && option[i].name && !strchr(option[i].name, '\n')) { // allow user to specify event handler for button presses
+           if(option[i].target || dlgNr != ErrorDlg && option[i].name) { // allow user to specify event handler for button presses
                button = gtk_event_box_new();
                 gtk_container_add(GTK_CONTAINER(button), label);
                label = button;