diff --git a/doc/xschem_man/commands.html b/doc/xschem_man/commands.html index 934777d6..c189b512 100644 --- a/doc/xschem_man/commands.html +++ b/doc/xschem_man/commands.html @@ -122,6 +122,7 @@ LeftButton Double click Terminate Polygon placement - BackSpace Back to parent schematic - Delete Delete selected objects - Insert Insert element from library +- Print Scrn Grab screen area - Escape Abort, redraw, unselect ctrl Enter Confirm closing dialog boxes - Down Move down diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 96d3fcd1..b5c6e8f0 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -840,6 +840,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" Return various global variables used in the program
  • go_back
  •     Go up one level (pop) in hierarchy 
    +
  • grabscreen
  • +   grab root window 
  • hash_file file [skip_path_lines]
  •     Do a simple hash of 'file'
        'skip_path_lines' is an integer (default: 0) passed to hash_file() 
    @@ -860,13 +862,17 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" 'inst' can be an instance name or number
  • hilight_netname net
  •     Highlight net name 'net' 
    -
  • image [invert|white_transp|black_transp|transp_white|transp_black|write_back]
  • +   
  • image [invert|white_transp|black_transp|transp_white|transp_black|write_back|
  • +        blend_white|blend_black]
        Apply required changes to selected images
        invert: invert colors
        white_transp: transform white to transparent color (alpha=0) after invert.
        black_transp: transform black to transparent color (alpha=0) after invert.
        transp_white: transform white to transparent color (alpha=0) after invert.
    -   transp_black: transform black to transparent color (alpha=0) after invert.
    + transp_black: transform black to transparent color (alpha=0) after invert. + blend_white: blend with white background and remove alpha + blend_black: blend with black background and remove alpha + write_back: write resulting image back into `image_data` attribute
  • instance sym_name x y rot flip [prop] [n]
  •     Place a new instance of symbol 'sym_name' at position x,y,
        rotation and flip  set to 'rot', 'flip'
    diff --git a/src/callback.c b/src/callback.c
    index 33231466..c43601fb 100644
    --- a/src/callback.c
    +++ b/src/callback.c
    @@ -1736,6 +1736,130 @@ static void end_shape_point_edit()
          }
     }
     
    +#if defined(__unix__) && HAS_CAIRO==1
    +static int grabscreen(const char *winpath, int event, int mx, int my, KeySym key,
    +                 int button, int aux, int state)
    +{
    +  static int grab_state = 0;
    +  static int x1, y1, x2, y2;
    +  int rmx, rmy, wmx, wmy;
    +  unsigned int msq;
    +  Window rw, cw;
    +  XSetWindowAttributes winattr;
    +  XGCValues gcv;
    +  static GC gc = NULL;
    +  static Window clientwin = 0;
    +  static int first_motion = 1;
    +  static int displayh = 0, displayw = 0;
    +  static unsigned long white = 0;
    +
    +  if(grab_state == 0 && event == ButtonPress && button == Button1) {
    +    unsigned long gcvm = GCFunction | GCForeground;
    +
    +    white = WhitePixel(display, screen_number);
    +    displayh = DisplayHeight(display, screen_number);
    +    displayw = DisplayWidth(display, screen_number);
    +
    +    XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq);
    +    gcv.function = GXxor;
    +    gcv.foreground = white;
    +    gc = XCreateGC(display, rw, gcvm, &gcv);
    +
    +    winattr.override_redirect = True;
    +    clientwin = XCreateWindow(display, rw, 0, 0, displayw, displayh, 0, screendepth,
    +                InputOutput, visual, CWOverrideRedirect, &winattr);
    +    XMapRaised(display,clientwin);
    +
    +    x1 = rmx;
    +    y1 = rmy;
    +    dbg(1, "grabscreen(): got point1: %d %d\n", x1, y1);
    +    grab_state = 1;  
    +  }
    +
    +  if(grab_state == 1 && event == MotionNotify) {
    +    static int xx1, xx2, yy1, yy2;
    +    xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2;
    +    INT_RECTORDER(xx1, yy1, xx2, yy2);
    +    dbg(1, "Motion: %d %d %d %d\n", xx1, yy1, xx2, yy2);
    +    if(!first_motion) {
    +      XDrawRectangle(display, clientwin, gc, xx1 - 1, yy1 - 1, xx2 - xx1 + 2, yy2 - yy1 + 2);
    +    }
    +    first_motion = 0;
    +    XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq);
    +    x2 = xx2 = rmx;
    +    y2 = yy2 = rmy;
    +    xx1 = x1; yy1 = y1;
    +    INT_RECTORDER(xx1, yy1, xx2, yy2);
    +    XDrawRectangle(display, clientwin, gc, xx1 - 1, yy1 - 1, xx2 - xx1 + 2, yy2 - yy1 + 2);
    +  }
    +
    +  if(grab_state == 1 && event == ButtonRelease) {
    +    int grab_w = 0, grab_h = 0;
    +    cairo_surface_t *sfc = NULL, *subsfc = NULL;
    +    png_to_byte_closure_t closure;
    +    char *encoded_data = NULL;
    +    size_t olength;
    +    char *prop = NULL;
    +    grab_state = 0;
    +    first_motion = 1;
    +    xctx->ui_state &= ~GRABSCREEN;
    +    XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq);
    +    x2 = rmx;
    +    y2 = rmy;
    +    INT_RECTORDER(x1, y1, x2, y2);
    +    tcleval("grab release [xschem get current_win_path]");
    +    if(x2 - x1 > 10 && y2 -y1 > 10) {
    +      grab_w = (x2 - x1 + 1);
    +      grab_h = (y2 - y1 + 1);
    +      dbg(1, "grabscreen(): grab area: %d %d - %d %d\n", x1, y1, x2, y2);
    +      dbg(1, "grabscreen(): root w=%d, h=%d\n", displayw, displayh);
    +      sfc =  cairo_xlib_surface_create(display, rw, visual, displayw, displayh);
    +      if(!sfc || cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) {
    +        dbg(0, "grabscreen(): failure creating sfc\n");
    +        XFreeGC(display, gc);
    +        XDestroyWindow(display, clientwin);
    +        return 0;
    +      }
    +      dbg(1, "sfc: w=%d, h=%d\n", 
    +            cairo_xlib_surface_get_width(sfc),
    +            cairo_xlib_surface_get_height(sfc));
    +      subsfc = cairo_surface_create_for_rectangle(sfc, x1, y1, grab_w, grab_h);
    +      if(!subsfc || cairo_surface_status(subsfc) != CAIRO_STATUS_SUCCESS) {
    +        dbg(0, "grabscreen(): failure creating subsfc\n");
    +        cairo_surface_destroy(sfc);
    +        XFreeGC(display, gc);
    +        XDestroyWindow(display, clientwin);
    +        return 0;
    +      }
    +      closure.buffer = NULL;
    +      closure.size = 0;
    +      closure.pos = 0;
    +      cairo_surface_write_to_png_stream(subsfc, png_writer, &closure);
    +      cairo_surface_destroy(subsfc);
    +      cairo_surface_destroy(sfc);
    +      closure.size = closure.pos;
    +      dbg(1, "closure.size = %ld\n", closure.size);
    +      encoded_data = base64_encode((unsigned char *)closure.buffer, closure.size, &olength, 0);
    +      dbg(1, "olength = %ld\n", olength);
    +      my_free(_ALLOC_ID_, &closure.buffer);
    +      my_mstrcat(_ALLOC_ID_, &prop, "flags=image,unscaled\nalpha=0.8\nimage_data=", encoded_data, NULL);
    +      my_free(_ALLOC_ID_, &encoded_data);
    +      storeobject(-1, xctx->mousex_snap, xctx->mousey_snap, xctx->mousex_snap + grab_w, xctx->mousey_snap + grab_h,
    +                  xRECT, GRIDLAYER, SELECTED, prop);
    +      my_free(_ALLOC_ID_, &prop);
    +      xctx->need_reb_sel_arr=1;
    +      rebuild_selected_array();
    +      move_objects(START,0,0,0);
    +      xctx->ui_state |= START_SYMPIN;
    +    }
    +    XFreeGC(display, gc);
    +    XDestroyWindow(display, clientwin);
    +  }
    +  return 1;
    +}
    +#endif
    +
    +
     /* main window callback */
     /* mx and my are set to the mouse coord. relative to window  */
     /* winpath: set to .drw or sub windows .x1.drw, .x2.drw, ...  */
    @@ -1854,6 +1978,12 @@ int rstate; /* (reduced state, without ShiftMask) */
      }
     
      dbg(1, "key=%d EQUAL_MODMASK=%d, SET_MODMASK=%d\n", key, SET_MODMASK, EQUAL_MODMASK);
    +
    + #if defined(__unix__) && HAS_CAIRO==1
    + if(xctx->ui_state & GRABSCREEN) {
    +   grabscreen(winpath, event, mx, my, key, button, aux, state);
    + } else 
    + #endif
      switch(event)
      {
     
    @@ -2708,6 +2838,13 @@ int rstate; /* (reduced state, without ShiftMask) */
         }
         break;
        }
    +   #if defined(__unix__) && HAS_CAIRO==1
    +   if(key == XK_Print) {
    +     xctx->ui_state |= GRABSCREEN;
    +     tcleval("grab set -global [xschem get current_win_path]");
    +     break;
    +   }
    +   #endif
        if(key=='Q' && rstate == 0) /* edit attributes in editor */
        {
         if(xctx->semaphore >= 2) break;
    diff --git a/src/draw.c b/src/draw.c
    index 85cd3446..cd241517 100644
    --- a/src/draw.c
    +++ b/src/draw.c
    @@ -4049,7 +4049,7 @@ static cairo_surface_t *get_surface_from_file(const char *filename, const char *
         }
         filesize = (size_t)buf.st_size;
         if(filesize > 0) {
    -      fd = fopen(filename, "r");
    +      fd = fopen(filename, fopen_read_mode);
           if(fd) {
             size_t bytes_read;
             filedata = my_malloc(_ALLOC_ID_, filesize);
    diff --git a/src/keys.help b/src/keys.help
    index 77447c51..e0a1c3b8 100644
    --- a/src/keys.help
    +++ b/src/keys.help
    @@ -63,6 +63,7 @@ LeftButton Double click Terminate Polygon placement
     -          BackSpace    Back to parent schematic
     -          Delete       Delete selected objects
     -          Insert       Insert element from library
    +-          Print Scrn   Grab screen area
     -          Escape       Abort, redraw, unselect
     ctrl       Enter        Confirm closing dialog boxes
     -          Down         Move down
    diff --git a/src/scheduler.c b/src/scheduler.c
    index 8cbb8634..a49d3883 100644
    --- a/src/scheduler.c
    +++ b/src/scheduler.c
    @@ -1907,6 +1907,18 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           if((xctx->semaphore == 0)) go_back(1);
           Tcl_ResetResult(interp);
         }
    +
    +    /* grabscreen
    +     *   grab root window */
    +    else if(!strcmp(argv[1], "grabscreen"))
    +    {
    +      if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
    +      #if defined(__unix__) && HAS_CAIRO==1
    +      xctx->ui_state |= GRABSCREEN;
    +      tcleval("grab set -global [xschem get current_win_path]");
    +      #endif
    +      Tcl_ResetResult(interp);
    +    }
         else { cmd_found = 0;}
         break;
         case 'h': /*----------------------------------------------*/
    @@ -5397,7 +5409,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           else if(argc > 2 && atoi(argv[2]) == 2) {
             Tcl_ResetResult(interp);
           }
    -      else if(argc > 3 && atoi(argv[2]) == 3) {
    +      else if(argc > 2 && atoi(argv[2]) == 3) {
             Tcl_ResetResult(interp);
           }
         }
    diff --git a/src/xinit.c b/src/xinit.c
    index 739ab82c..4715c352 100644
    --- a/src/xinit.c
    +++ b/src/xinit.c
    @@ -2551,6 +2551,7 @@ int Tcl_AppInit(Tcl_Interp *inter)
          tcleval(name);
        }
      }
    + if(debug_var==-10) debug_var=0;
      /*                                */
      /*  EXECUTE xschem.tcl            */
      /*                                */
    @@ -2594,7 +2595,6 @@ int Tcl_AppInit(Tcl_Interp *inter)
      cadlayers=tclgetintvar("cadlayers");
      fix_broken_tiled_fill = tclgetboolvar("fix_broken_tiled_fill");
      fix_mouse_coord = tclgetboolvar("fix_mouse_coord");
    - if(debug_var==-10) debug_var=0;
      my_snprintf(tmp, S(tmp), "%.16g",CADGRID);
      tclvareval("set_ne cadgrid ", tmp, NULL);
      my_snprintf(tmp, S(tmp), "%.16g",CADSNAP);
    diff --git a/src/xschem.h b/src/xschem.h
    index 76ce8f0d..3ce176fe 100644
    --- a/src/xschem.h
    +++ b/src/xschem.h
    @@ -229,6 +229,7 @@ extern char win_temp_dir[PATH_MAX];
     #define START_SYMPIN 16384U
     #define GRAPHPAN 32768U     /* bit 15 */
     #define MENUSTART 65536U    /* bit 16 */
    +#define GRABSCREEN 131072   /* bit 17 */
     
     #define SELECTED 1U         /*  used in the .sel field for selected objs. */
     #define SELECTED1 2U        /*  first point selected... */
    @@ -349,6 +350,13 @@ extern char win_temp_dir[PATH_MAX];
       if(y2 < y1) {xxtmp = y1; y1 = y2; y2 = xxtmp;} \
     }
     
    +#define INT_RECTORDER(x1,y1,x2,y2) { \
    +  int xxtmp; \
    +  if(x2 < x1) {xxtmp = x1; x1 = x2; x2 = xxtmp;} \
    +  if(y2 < y1) {xxtmp = y1; y1 = y2; y2 = xxtmp;} \
    +}
    +
    +
     #define LINE_OUTSIDE(xa,ya,xb,yb,x1,y1,x2,y2) \
      (xa>=x2 || xb<=x1 ||  ( (ya=y2 || yb<=y1) : (yb>=y2 || ya<=y1) ) )
     
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index 0a67720c..4b920a10 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -7736,6 +7736,8 @@ proc build_widgets { {topwin {} } } {
       $topwin.menubar.tools.menu add command -label "Insert circle" -command "xschem circle" -accelerator Ctrl+Shift+C
       toolbar_add ToolInsertCircle "xschem circle" "Insert Circle" $topwin
       $topwin.menubar.tools.menu add command -label "Insert JPG/PNG image" -command "xschem add_image"
    +  $topwin.menubar.tools.menu add command -label "Grab screen area" -command "xschem grabscreen" \
    +    -accelerator {Print Scrn}
       $topwin.menubar.tools.menu add command -label "Search" -accelerator Ctrl+F -command  property_search
       toolbar_add ToolSearch property_search "Search" $topwin
       $topwin.menubar.tools.menu add command -label "Align to Grid" -accelerator Alt+U -command  "xschem align"