Просмотр исходного кода

Added an experimental magnifying glass for --opengl only.

Dalton Nell 9 лет назад
Родитель
Сommit
7f3edc8df3

+ 3
- 0
CMakeLists.txt Просмотреть файл

@@ -90,6 +90,7 @@ find_package( XExt      REQUIRED )
90 90
 find_package( OpenGL    REQUIRED )
91 91
 find_package( GLX       REQUIRED )
92 92
 find_package( XRender   REQUIRED )
93
+find_package( XRandr    REQUIRED )
93 94
 # This library is needed only for Ubuntu it seems, some platforms don't even
94 95
 # ship with it. I couldn't find a way to do a test compile to check if librt
95 96
 # was needed, so instead I just didn't mark it as REQUIRED.
@@ -102,6 +103,7 @@ set( CMAKE_CXX_FLAGS
102 103
 if ( RT_INCLUDE_DIR )
103 104
     include_directories( ${X11_INCLUDE_DIR}
104 105
                          ${XEXT_INCLUDE_DIR}
106
+                         ${XRANDR_INCLUDE_DIR}
105 107
                          ${OPENGL_INCLUDE_DIR}
106 108
                          ${GLX_INCLUDE_DIR}
107 109
                          ${XRENDER_INCLUDE_DIRS}
@@ -124,6 +126,7 @@ if ( RT_LIBRARY )
124 126
                            ${GLX_LIBRARIES}
125 127
                            ${XRENDER_LIBRARIES}
126 128
                            "${XEXT_LIBRARY}"
129
+                           "${XRANDR_LIBRARY}"
127 130
                            "${RT_LIBRARY}" )
128 131
 else()
129 132
     target_link_libraries( "${BIN_TARGET}"

+ 44
- 0
cmakemodules/FindGLX.cmake Просмотреть файл

@@ -0,0 +1,44 @@
1
+# Try to find GLX. Once done, this will define:
2
+#
3
+#   GLX_FOUND - variable which returns the result of the search
4
+#   GLX_INCLUDE_DIRS - list of include directories
5
+#   GLX_LIBRARIES - options for the linker
6
+
7
+#=============================================================================
8
+# Copyright 2012 Benjamin Eikel
9
+#
10
+# Distributed under the OSI-approved BSD License (the "License");
11
+# see accompanying file Copyright.txt for details.
12
+#
13
+# This software is distributed WITHOUT ANY WARRANTY; without even the
14
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+# See the License for more information.
16
+#=============================================================================
17
+# (To distribute this file outside of CMake, substitute the full
18
+#  License text for the above reference.)
19
+
20
+find_package(PkgConfig)
21
+pkg_check_modules(PC_GLX QUIET glx)
22
+
23
+find_path(GLX_INCLUDE_DIR
24
+    GL/glx.h
25
+    HINTS ${PC_GLX_INCLUDEDIR} ${PC_GLX_INCLUDE_DIRS}
26
+)
27
+find_library(GLX_LIBRARY
28
+    GL
29
+    HINTS ${PC_GLX_LIBDIR} ${PC_GLX_LIBRARY_DIRS}
30
+)
31
+
32
+set(GLX_INCLUDE_DIRS ${GLX_INCLUDE_DIR})
33
+set(GLX_LIBRARIES ${GLX_LIBRARY})
34
+
35
+include(FindPackageHandleStandardArgs)
36
+find_package_handle_standard_args(GLX DEFAULT_MSG
37
+    GLX_INCLUDE_DIR
38
+    GLX_LIBRARY
39
+)
40
+
41
+mark_as_advanced(
42
+    GLX_INCLUDE_DIR
43
+    GLX_LIBRARY
44
+)

+ 26
- 0
cmakemodules/FindXRandr.cmake Просмотреть файл

@@ -0,0 +1,26 @@
1
+# - Find XRandr
2
+# Find the XRandr libraries
3
+#
4
+#  This module defines the following variables:
5
+#     XRANDR_FOUND        - 1 if XRANDR_INCLUDE_DIR & XRANDR_LIBRARY are found, 0 otherwise
6
+#     XRANDR_INCLUDE_DIR  - where to find Xlib.h, etc.
7
+#     XRANDR_LIBRARY      - the X11 library
8
+#
9
+
10
+find_path( XRANDR_INCLUDE_DIR
11
+           NAMES X11/extensions/Xrandr.h
12
+           PATH_SUFFIXES X11/extensions
13
+           DOC "The XRandr include directory" )
14
+
15
+find_library( XRANDR_LIBRARY
16
+              NAMES Xrandr
17
+              PATHS /usr/lib /lib
18
+              DOC "The XRandr library" )
19
+
20
+if( XRANDR_INCLUDE_DIR AND XRANDR_LIBRARY )
21
+    set( XRANDR_FOUND 1 )
22
+else()
23
+    set( XRANDR_FOUND 0 )
24
+endif()
25
+
26
+mark_as_advanced( XRANDR_INCLUDE_DIR XRANDR_LIBRARY )

+ 47
- 0
cmakemodules/FindXRender.cmake Просмотреть файл

@@ -0,0 +1,47 @@
1
+# - Find XRender
2
+# Find the XRender libraries
3
+#
4
+# This module defines the following variables:
5
+#   XRENDER_FOUND - true if XRENDER_INCLUDE_DIR & XRENDER_LIBRARY are found
6
+#   XRENDER_LIBRARIES - Set when Xrender_LIBRARY is found
7
+#   XRENDER_INCLUDE_DIRS - Set when Xrender_INCLUDE_DIR is found
8
+#
9
+#   XRENDER_INCLUDE_DIR - where to find Xrender.h, etc.
10
+#   XRENDER_LIBRARY - the Xrender library
11
+#
12
+
13
+#=============================================================================
14
+# Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
15
+#
16
+# Licensed under the Apache License, Version 2.0 (the "License");
17
+# you may not use this file except in compliance with the License.
18
+# You may obtain a copy of the License at
19
+#
20
+#     http://www.apache.org/licenses/LICENSE-2.0
21
+#
22
+# Unless required by applicable law or agreed to in writing, software
23
+# distributed under the License is distributed on an "AS IS" BASIS,
24
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
+# See the License for the specific language governing permissions and
26
+# limitations under the License.
27
+#=============================================================================
28
+
29
+find_path(XRENDER_INCLUDE_DIR NAMES X11/extensions/Xrender.h
30
+          PATHS /opt/X11/include
31
+          DOC "The Xrender include directory")
32
+
33
+find_library(XRENDER_LIBRARY NAMES Xrender
34
+          PATHS /opt/X11/lib
35
+          DOC "The Xrender library")
36
+
37
+include(FindPackageHandleStandardArgs)
38
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xrender DEFAULT_MSG XRENDER_LIBRARY XRENDER_INCLUDE_DIR)
39
+
40
+if(XRENDER_FOUND)
41
+
42
+    set(XRENDER_LIBRARIES ${XRENDER_LIBRARY})
43
+    set(XRENDER_INCLUDE_DIRS ${XRENDER_INCLUDE_DIR})
44
+
45
+endif()
46
+
47
+mark_as_advanced(XRENDER_INCLUDE_DIR XRENDER_LIBRARY)

+ 71
- 1
src/cmdline.c Просмотреть файл

@@ -49,6 +49,9 @@ const char *gengetopt_args_info_help[] = {
49 49
   "      --max=INT                 Set the maximum output of width or height\n                                  values. Setting min and max to the same value\n                                  disables drag selections.  (default=`0')",
50 50
   "  -l, --highlight               Instead of outlining selections, slop\n                                  highlights it. This is only useful when\n                                  --color is set to a transparent color.\n                                  (default=off)",
51 51
   "      --opengl                  Enable hardware acceleration. Only works with\n                                  modern systems that are also running a\n                                  compositor.  (default=off)",
52
+  "      --magnify                 Display a magnifying glass when --opengl is\n                                  also enabled.  (default=off)",
53
+  "      --magstrength=FLOAT       Sets how many times the magnification window\n                                  size is multiplied.  (default=`4')",
54
+  "      --magpixels=INT           Sets how many pixels are displayed in the\n                                  magnification. The less pixels the bigger the\n                                  magnification.  (default=`64')",
52 55
   "  -f, --format=STRING           Set the output format string. Format specifiers\n                                  are %x, %y, %w, %h, %i, %g, and %c.\n                                  (default=`X=%x\\nY=%y\\nW=%w\\nH=%h\\nG=%g\\nID=%i\\nCancel=%c\\n')",
53 56
   "\nExamples\n    $ # Gray, thick, transparent border for maximum visiblity.\n    $ slop -b 20 -c 0.5,0.5,0.5,0.8\n\n    $ # Remove window decorations.\n    $ slop --nodecorations\n\n    $ # Disable window selections. Useful for selecting individual pixels.\n    $ slop -t 0\n\n    $ # Classic Windows XP selection.\n    $ slop -l -c 0.3,0.4,0.6,0.4\n\n    $ # Change output format to use safer parsing\n    $ slopoutput=$(slop -f \"%x %y %w %h\")\n    $ X=$(echo $slopoutput | awk '{print $1}')\n    $ Y=$(echo $slopoutput | awk '{print $2}')\n    $ W=$(echo $slopoutput | awk '{print $3}')\n    $ H=$(echo $slopoutput | awk '{print $4}')\n\nTips\n    * You can use the arrow keys to move the starting point of a\ndrag-selection, just in case you missed it by a few pixels.\n    * If you don't like a selection: you can cancel it by right-clicking\nregardless of which options are enabled or disabled for slop.\n    * If slop doesn't seem to select a window accurately, the problem could be\nbecause of decorations getting in the way. Try enabling the --nodecorations\nflag.\n",
54 57
     0
@@ -58,6 +61,7 @@ typedef enum {ARG_NO
58 61
   , ARG_FLAG
59 62
   , ARG_STRING
60 63
   , ARG_INT
64
+  , ARG_FLOAT
61 65
 } cmdline_parser_arg_type;
62 66
 
63 67
 static
@@ -90,6 +94,9 @@ void clear_given (struct gengetopt_args_info *args_info)
90 94
   args_info->max_given = 0 ;
91 95
   args_info->highlight_given = 0 ;
92 96
   args_info->opengl_given = 0 ;
97
+  args_info->magnify_given = 0 ;
98
+  args_info->magstrength_given = 0 ;
99
+  args_info->magpixels_given = 0 ;
93 100
   args_info->format_given = 0 ;
94 101
 }
95 102
 
@@ -117,6 +124,11 @@ void clear_args (struct gengetopt_args_info *args_info)
117 124
   args_info->max_orig = NULL;
118 125
   args_info->highlight_flag = 0;
119 126
   args_info->opengl_flag = 0;
127
+  args_info->magnify_flag = 0;
128
+  args_info->magstrength_arg = 4;
129
+  args_info->magstrength_orig = NULL;
130
+  args_info->magpixels_arg = 64;
131
+  args_info->magpixels_orig = NULL;
120 132
   args_info->format_arg = gengetopt_strdup ("X=%x\nY=%y\nW=%w\nH=%h\nG=%g\nID=%i\nCancel=%c\n");
121 133
   args_info->format_orig = NULL;
122 134
   
@@ -141,7 +153,10 @@ void init_args_info(struct gengetopt_args_info *args_info)
141 153
   args_info->max_help = gengetopt_args_info_help[12] ;
142 154
   args_info->highlight_help = gengetopt_args_info_help[13] ;
143 155
   args_info->opengl_help = gengetopt_args_info_help[14] ;
144
-  args_info->format_help = gengetopt_args_info_help[15] ;
156
+  args_info->magnify_help = gengetopt_args_info_help[15] ;
157
+  args_info->magstrength_help = gengetopt_args_info_help[16] ;
158
+  args_info->magpixels_help = gengetopt_args_info_help[17] ;
159
+  args_info->format_help = gengetopt_args_info_help[18] ;
145 160
   
146 161
 }
147 162
 
@@ -236,6 +251,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info)
236 251
   free_string_field (&(args_info->color_orig));
237 252
   free_string_field (&(args_info->min_orig));
238 253
   free_string_field (&(args_info->max_orig));
254
+  free_string_field (&(args_info->magstrength_orig));
255
+  free_string_field (&(args_info->magpixels_orig));
239 256
   free_string_field (&(args_info->format_arg));
240 257
   free_string_field (&(args_info->format_orig));
241 258
   
@@ -296,6 +313,12 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
296 313
     write_into_file(outfile, "highlight", 0, 0 );
297 314
   if (args_info->opengl_given)
298 315
     write_into_file(outfile, "opengl", 0, 0 );
316
+  if (args_info->magnify_given)
317
+    write_into_file(outfile, "magnify", 0, 0 );
318
+  if (args_info->magstrength_given)
319
+    write_into_file(outfile, "magstrength", args_info->magstrength_orig, 0);
320
+  if (args_info->magpixels_given)
321
+    write_into_file(outfile, "magpixels", args_info->magpixels_orig, 0);
299 322
   if (args_info->format_given)
300 323
     write_into_file(outfile, "format", args_info->format_orig, 0);
301 324
   
@@ -470,6 +493,9 @@ int update_arg(void *field, char **orig_field,
470 493
   case ARG_INT:
471 494
     if (val) *((int *)field) = strtol (val, &stop_char, 0);
472 495
     break;
496
+  case ARG_FLOAT:
497
+    if (val) *((float *)field) = (float)strtod (val, &stop_char);
498
+    break;
473 499
   case ARG_STRING:
474 500
     if (val) {
475 501
       string_field = (char **)field;
@@ -485,6 +511,7 @@ int update_arg(void *field, char **orig_field,
485 511
   /* check numeric conversion */
486 512
   switch(arg_type) {
487 513
   case ARG_INT:
514
+  case ARG_FLOAT:
488 515
     if (val && !(stop_char && *stop_char == '\0')) {
489 516
       fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val);
490 517
       return 1; /* failure */
@@ -566,6 +593,9 @@ cmdline_parser_internal (
566 593
         { "max",	1, NULL, 0 },
567 594
         { "highlight",	0, NULL, 'l' },
568 595
         { "opengl",	0, NULL, 0 },
596
+        { "magnify",	0, NULL, 0 },
597
+        { "magstrength",	1, NULL, 0 },
598
+        { "magpixels",	1, NULL, 0 },
569 599
         { "format",	1, NULL, 'f' },
570 600
         { 0,  0, 0, 0 }
571 601
       };
@@ -745,6 +775,46 @@ cmdline_parser_internal (
745 775
                 additional_error))
746 776
               goto failure;
747 777
           
778
+          }
779
+          /* Display a magnifying glass when --opengl is also enabled..  */
780
+          else if (strcmp (long_options[option_index].name, "magnify") == 0)
781
+          {
782
+          
783
+          
784
+            if (update_arg((void *)&(args_info->magnify_flag), 0, &(args_info->magnify_given),
785
+                &(local_args_info.magnify_given), optarg, 0, 0, ARG_FLAG,
786
+                check_ambiguity, override, 1, 0, "magnify", '-',
787
+                additional_error))
788
+              goto failure;
789
+          
790
+          }
791
+          /* Sets how many times the magnification window size is multiplied..  */
792
+          else if (strcmp (long_options[option_index].name, "magstrength") == 0)
793
+          {
794
+          
795
+          
796
+            if (update_arg( (void *)&(args_info->magstrength_arg), 
797
+                 &(args_info->magstrength_orig), &(args_info->magstrength_given),
798
+                &(local_args_info.magstrength_given), optarg, 0, "4", ARG_FLOAT,
799
+                check_ambiguity, override, 0, 0,
800
+                "magstrength", '-',
801
+                additional_error))
802
+              goto failure;
803
+          
804
+          }
805
+          /* Sets how many pixels are displayed in the magnification. The less pixels the bigger the magnification..  */
806
+          else if (strcmp (long_options[option_index].name, "magpixels") == 0)
807
+          {
808
+          
809
+          
810
+            if (update_arg( (void *)&(args_info->magpixels_arg), 
811
+                 &(args_info->magpixels_orig), &(args_info->magpixels_given),
812
+                &(local_args_info.magpixels_given), optarg, 0, "64", ARG_INT,
813
+                check_ambiguity, override, 0, 0,
814
+                "magpixels", '-',
815
+                additional_error))
816
+              goto failure;
817
+          
748 818
           }
749 819
           
750 820
           break;

+ 11
- 0
src/cmdline.in Просмотреть файл

@@ -71,6 +71,14 @@ struct gengetopt_args_info
71 71
   const char *highlight_help; /**< @brief Instead of outlining selections, slop highlights it. This is only useful when --color is set to a transparent color. help description.  */
72 72
   int opengl_flag;	/**< @brief Enable hardware acceleration. Only works with modern systems that are also running a compositor. (default=off).  */
73 73
   const char *opengl_help; /**< @brief Enable hardware acceleration. Only works with modern systems that are also running a compositor. help description.  */
74
+  int magnify_flag;	/**< @brief Display a magnifying glass when --opengl is also enabled. (default=off).  */
75
+  const char *magnify_help; /**< @brief Display a magnifying glass when --opengl is also enabled. help description.  */
76
+  float magstrength_arg;	/**< @brief Sets how many times the magnification window size is multiplied. (default='4').  */
77
+  char * magstrength_orig;	/**< @brief Sets how many times the magnification window size is multiplied. original value given at command line.  */
78
+  const char *magstrength_help; /**< @brief Sets how many times the magnification window size is multiplied. help description.  */
79
+  int magpixels_arg;	/**< @brief Sets how many pixels are displayed in the magnification. The less pixels the bigger the magnification. (default='64').  */
80
+  char * magpixels_orig;	/**< @brief Sets how many pixels are displayed in the magnification. The less pixels the bigger the magnification. original value given at command line.  */
81
+  const char *magpixels_help; /**< @brief Sets how many pixels are displayed in the magnification. The less pixels the bigger the magnification. help description.  */
74 82
   char * format_arg;	/**< @brief Set the output format string. Format specifiers are %x, %y, %w, %h, %i, %g, and %c. (default='REPLACEME').  */
75 83
   char * format_orig;	/**< @brief Set the output format string. Format specifiers are %x, %y, %w, %h, %i, %g, and %c. original value given at command line.  */
76 84
   const char *format_help; /**< @brief Set the output format string. Format specifiers are %x, %y, %w, %h, %i, %g, and %c. help description.  */
@@ -89,6 +97,9 @@ struct gengetopt_args_info
89 97
   unsigned int max_given ;	/**< @brief Whether max was given.  */
90 98
   unsigned int highlight_given ;	/**< @brief Whether highlight was given.  */
91 99
   unsigned int opengl_given ;	/**< @brief Whether opengl was given.  */
100
+  unsigned int magnify_given ;	/**< @brief Whether magnify was given.  */
101
+  unsigned int magstrength_given ;	/**< @brief Whether magstrength was given.  */
102
+  unsigned int magpixels_given ;	/**< @brief Whether magpixels was given.  */
92 103
   unsigned int format_given ;	/**< @brief Whether format was given.  */
93 104
 
94 105
 } ;

+ 237
- 4
src/glselectrectangle.cpp Просмотреть файл

@@ -41,6 +41,187 @@ slop::GLSelectRectangle::~GLSelectRectangle() {
41 41
     usleep( 10000 );
42 42
 }
43 43
 
44
+void slop::GLSelectRectangle::constrainWithinMonitor( int* x, int* y, int* w, int* h ) {
45
+    m_offsetx = 0;
46
+    m_offsety = 0;
47
+    m_offsetw = 0;
48
+    m_offseth = 0;
49
+    for ( unsigned int i=0;i<m_monitors.size();i++ ) {
50
+        XRRCrtcInfo* monitor = m_monitors[ i ];
51
+        if ( !((int)xengine->m_mousex >= (int)monitor->x && (int)xengine->m_mousey >= (int)monitor->y &&
52
+               (int)xengine->m_mousex <= (int)(monitor->x+monitor->width) && (int)xengine->m_mousey <= (int)(monitor->y+monitor->height) ) ) {
53
+            continue;
54
+        }
55
+        if ( (int)*x < (int)monitor->x ) {
56
+            m_offsetx = monitor->x-*x;
57
+            *w += *x-monitor->x;
58
+            *x = monitor->x;
59
+        }
60
+        if ( (int)(*x+*w) >= (int)(monitor->x+monitor->width) ) {
61
+            m_offsetw = (monitor->width-1-(*x-monitor->x+*w));
62
+            *w = monitor->width-1-(*x-monitor->x);
63
+        }
64
+        if ( (int)*y < (int)monitor->y ) {
65
+            m_offsety = monitor->y-*y;
66
+            *h += *y-monitor->y;
67
+            *y = monitor->y;
68
+        }
69
+        if ( (int)(*y+*h) >= (int)(monitor->y+monitor->height) ) {
70
+            m_offseth = (monitor->height-1-(*y-monitor->y+*h));
71
+            *h = monitor->height-1-(*y-monitor->y);
72
+        }
73
+        break;
74
+    }
75
+    m_offsetx *= m_glassSize;
76
+    m_offsety *= m_glassSize;
77
+    m_offsetw *= m_glassSize;
78
+    m_offseth *= m_glassSize;
79
+}
80
+
81
+void slop::GLSelectRectangle::setMagnifySettings( bool on, float magstrength, unsigned int pixels ) {
82
+    m_glassSize = magstrength;
83
+    m_glassPixels = pixels;
84
+    m_glassEnabled = on;
85
+    m_glassx = xengine->m_mousex;
86
+    m_glassy = xengine->m_mousey;
87
+    m_realglassx = xengine->m_mousex;
88
+    m_realglassy = xengine->m_mousey;
89
+}
90
+
91
+void slop::GLSelectRectangle::pushOut( int* x, int* y, int w, int h, int rx, int ry, int rw, int rh ) {
92
+    // AABB to test for collision
93
+    if (!(
94
+          *x < rx + rw &&
95
+          *x + w > rx &&
96
+          *y < ry + rh &&
97
+          h + *y > ry
98
+       )) {
99
+        // No collision, so we do nothing.
100
+        return;
101
+    }
102
+    // Otherwise we find an optimal angle to push ourselves out at.
103
+    int centerx = rx+rw/2;
104
+    int centery = ry+rh/2;
105
+    float ang = -atan2( (float)(*y+(float)h/2.f)-(float)centery, (float)(*x+(float)w/2.f)-(float)centerx );
106
+    float pi = 3.1415926535897;
107
+    float upright = pi/2 - atan( (2.f*float(rx+rw)-2.f*(float)centerx)/(float)rh );
108
+    float upleft = pi/2 - atan( (2.f*(float)rx-2.f*(float)centerx)/(float)rh );
109
+    float downright = -upright;
110
+    float downleft = -upleft;
111
+    if ( ang >= upright && ang <= upleft ) {
112
+        *x = centerx + ((rh*cos(ang))/(2*sin(ang))) - w/2;
113
+        *y = centery - rh/2 - h;
114
+    } else if ( ang <= downright && ang >= downleft) {
115
+        *x = centerx - ((rh*cos(ang))/(2*sin(ang))) - w/2;
116
+        *y = centery + rh/2;
117
+    } else if ( ang < downleft || ang > upleft ) {
118
+        *x = centerx - rw/2 - w;
119
+        *y = centery + (rw*sin(ang))/(2*cos(ang)) - h/2;
120
+    } else {
121
+        *x = centerx + rw/2;
122
+        *y = centery - (rw*sin(ang))/(2*cos(ang)) - h/2;
123
+    }
124
+}
125
+
126
+void slop::GLSelectRectangle::pushIn( int* x, int* y, int w, int h, int rx, int ry, int rw, int rh ) {
127
+    if ( *x > rx && *y > ry &&
128
+         *x+w < rx+rw && *y+h < ry+rh ) {
129
+        // We're already fully contained...
130
+        return;
131
+    }
132
+    // Otherwise we find an optimal angle to push ourselves in at.
133
+    int centerx = rx+rw/2;
134
+    int centery = ry+rh/2;
135
+    float ang = -atan2( (float)(*y+(float)h/2.f)-(float)centery, (float)(*x+(float)w/2.f)-(float)centerx );
136
+    float pi = 3.1415926535897;
137
+    float upright = pi/2 - atan( (2.f*float(rx+rw)-2.f*(float)centerx)/(float)rh );
138
+    float upleft = pi/2 - atan( (2.f*(float)rx-2.f*(float)centerx)/(float)rh );
139
+    float downright = -upright;
140
+    float downleft = -upleft;
141
+    if ( ang >= upright && ang <= upleft ) {
142
+        *x = centerx + ((rh*cos(ang))/(2*sin(ang))) - w/2;
143
+        *y = centery - rh/2;
144
+    } else if ( ang <= downright && ang >= downleft) {
145
+        *x = centerx - ((rh*cos(ang))/(2*sin(ang))) - w/2;
146
+        *y = centery + rh/2 - h;
147
+    } else if ( ang < downleft || ang > upleft ) {
148
+        *x = centerx - rw/2;
149
+        *y = centery + (rw*sin(ang))/(2*cos(ang)) - h/2;
150
+    } else {
151
+        *x = centerx + rw/2 - w;
152
+        *y = centery - (rw*sin(ang))/(2*cos(ang)) - h/2;
153
+    }
154
+    if ( !(*x > rx && *y > ry &&
155
+         *x+w < rx+rw && *y+h < ry+rh) ) {
156
+        if ( *x+w > rx+rw ) {
157
+            *x -= w/2;
158
+        }
159
+        if ( *x < rx ) {
160
+            *x += w/2;
161
+        }
162
+        if ( *y+h > ry+rh ) {
163
+            *y -= h/2;
164
+        }
165
+        if ( *y < ry ) {
166
+            *y += h/2;
167
+        }
168
+    }
169
+}
170
+
171
+void slop::GLSelectRectangle::findOptimalGlassPosition() {
172
+    // Try to move the glass next to the mouse.
173
+    m_glassx = xengine->m_mousex+m_glassPixels/2+5-m_glassBorder;
174
+    m_glassy = xengine->m_mousey+m_glassPixels/2+5-m_glassBorder;
175
+    XRectangle view, selection, combined;
176
+    view.x = xengine->m_mousex-(m_glassPixels+1+m_glassBorder)/2;
177
+    view.y = xengine->m_mousey-(m_glassPixels+1+m_glassBorder)/2;
178
+    view.width = m_glassPixels+1;
179
+    view.height = m_glassPixels+1;
180
+    selection.x = m_x-m_border;
181
+    selection.y = m_y-m_border;
182
+    selection.width = m_width+m_border*2;
183
+    selection.height = m_height+m_border*2;
184
+    combined.x = std::min( selection.x, view.x );
185
+    combined.y = std::min( selection.y, view.y );
186
+    combined.width = selection.width + std::max( selection.x-view.x, (view.x+view.width)-(selection.x+selection.width) );
187
+    combined.height = selection.height + std::max( selection.y-view.y, (view.y+view.height)-(selection.y+selection.height) );
188
+    for ( unsigned int i=0;i<m_monitors.size();i++ ) {
189
+        XRRCrtcInfo* monitor = m_monitors[ i ];
190
+        // Push the glass inside the monitor the mouse is on.
191
+        if ( (int)xengine->m_mousex >= (int)monitor->x && (int)xengine->m_mousex <= (int)(monitor->x + monitor->width) &&
192
+             (int)xengine->m_mousey >= (int)monitor->y && (int)xengine->m_mousey <= (int)(monitor->y + monitor->height) ) {
193
+            pushIn( &m_glassx, &m_glassy, m_glassPixels*m_glassSize+m_glassBorder*2, m_glassPixels*m_glassSize+m_glassBorder*2, monitor->x, monitor->y, monitor->width, monitor->height );
194
+            break;
195
+        }
196
+    }
197
+    // Push the glass outside of the selection, but only if we are left clicking, and always keep it out of the "shot"
198
+    if ( xengine->getCursor() != slop::Left ) {
199
+        pushOut( &m_glassx, &m_glassy, m_glassPixels*m_glassSize+m_glassBorder*2, m_glassPixels*m_glassSize+m_glassBorder*2, combined.x, combined.y, combined.width, combined.height );
200
+    } else {
201
+        pushOut( &m_glassx, &m_glassy, m_glassPixels*m_glassSize+m_glassBorder*2, m_glassPixels*m_glassSize+m_glassBorder*2, view.x, view.y, view.width, view.height );
202
+    }
203
+    m_glassx += m_glassBorder;
204
+    m_glassy += m_glassBorder;
205
+}
206
+
207
+void slop::GLSelectRectangle::generateMagnifyingGlass() {
208
+    int x = xengine->m_mousex-m_glassPixels/2;
209
+    int y = xengine->m_mousey-m_glassPixels/2;
210
+    int w = m_glassPixels;
211
+    int h = m_glassPixels;
212
+    constrainWithinMonitor( &x, &y, &w, &h );
213
+    XImage* image = XGetImage( xengine->m_display, xengine->m_root, x, y, w, h, 0xffffffff, ZPixmap );
214
+    glEnable(GL_TEXTURE_2D);
215
+    glGenTextures(1, &m_texid);
216
+    glBindTexture(GL_TEXTURE_2D, m_texid);
217
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
218
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
219
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
220
+    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(&(image->data[0])));
221
+    XDestroyImage( image );
222
+    glDisable(GL_TEXTURE_2D);
223
+}
224
+
44 225
 slop::GLSelectRectangle::GLSelectRectangle( int sx, int sy, int ex, int ey, int border, bool highlight, float r, float g, float b, float a ) {
45 226
     m_x = std::min( sx, ex );
46 227
     m_y = std::min( sy, ey );
@@ -53,6 +234,14 @@ slop::GLSelectRectangle::GLSelectRectangle( int sx, int sy, int ex, int ey, int
53 234
     m_border = border;
54 235
     m_window = None;
55 236
     m_highlight = highlight;
237
+    m_glassPixels = 64;
238
+    m_glassx = xengine->m_mousex;
239
+    m_glassy = xengine->m_mousey;
240
+    m_realglassx = xengine->m_mousex;
241
+    m_realglassy = xengine->m_mousey;
242
+    m_glassSize = 4;
243
+    m_glassBorder = 1;
244
+    m_monitors = xengine->getCRTCS();
56 245
 
57 246
     // If we don't have a border, we don't exist, so just die.
58 247
     if ( m_border == 0 ) {
@@ -178,7 +367,9 @@ void slop::GLSelectRectangle::setGeo( int sx, int sy, int ex, int ey ) {
178 367
     m_y = y;
179 368
     m_width = w;
180 369
     m_height = h;
181
-    glDrawBuffer( GL_BACK );
370
+}
371
+
372
+void slop::GLSelectRectangle::update( double dt ) {
182 373
     glViewport( 0, 0, xengine->getWidth(), xengine->getHeight() );
183 374
 
184 375
     glClearColor( 0, 0, 0, 0 );
@@ -191,14 +382,56 @@ void slop::GLSelectRectangle::setGeo( int sx, int sy, int ex, int ey ) {
191 382
     glMatrixMode( GL_MODELVIEW );
192 383
     glLoadIdentity();
193 384
 
194
-    glEnable( GL_BLEND );
195
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
196
-
197 385
     glColor4f( m_r, m_g, m_b, m_a );
198 386
     glRecti( m_x-m_border, m_y, m_x+m_width+m_border, m_y-m_border );
199 387
     glRecti( m_x-m_border, m_y+m_height, m_x+m_width+m_border, m_y+m_height+m_border );
200 388
     glRecti( m_x-m_border, m_y, m_x, m_y+m_height );
201 389
     glRecti( m_x+m_width, m_y, m_x+m_width+m_border, m_y+m_height );
202 390
 
391
+    if ( m_glassEnabled ) {
392
+        generateMagnifyingGlass();
393
+        findOptimalGlassPosition();
394
+
395
+        // Takes .1 second to reach the real position. Used for easing.
396
+        m_realglassx -= float(m_realglassx - (float)m_glassx) * dt * 10;
397
+        m_realglassy -= float(m_realglassy - (float)m_glassy) * dt * 10;
398
+
399
+        // Black outline...
400
+
401
+        glColor4f( 0, 0, 0, 1 );
402
+        glBegin( GL_QUADS );
403
+        glTexCoord2f(0.0, 1.0); glVertex3f( m_realglassx+m_offsetx-m_glassBorder,                               m_realglassy+(m_glassSize*m_glassPixels)+m_offseth+m_glassBorder, 0.0);
404
+        glTexCoord2f(1.0, 1.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw+m_glassBorder,   m_realglassy+(m_glassSize*m_glassPixels)+m_offseth+1, 0.0);
405
+        glTexCoord2f(1.0, 0.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw+m_glassBorder,   m_realglassy+m_offsety-m_glassBorder, 0.0);
406
+        glTexCoord2f(0.0, 0.0); glVertex3f( m_realglassx+m_offsetx-m_glassBorder,                               m_realglassy+m_offsety-m_glassBorder, 0.0);
407
+        glEnd();
408
+
409
+        glEnable( GL_TEXTURE_2D );
410
+        glBindTexture( GL_TEXTURE_2D, m_texid );
411
+        glColor4f( 1, 1, 1, 1 );
412
+        glBegin( GL_QUADS );
413
+        glTexCoord2f(0.0, 1.0); glVertex3f( m_realglassx+m_offsetx,                             m_realglassy+(m_glassSize*m_glassPixels)+m_offseth, 0.0);
414
+        glTexCoord2f(1.0, 1.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth, 0.0);
415
+        glTexCoord2f(1.0, 0.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw, m_realglassy+m_offsety, 0.0);
416
+        glTexCoord2f(0.0, 0.0); glVertex3f( m_realglassx+m_offsetx,                             m_realglassy+m_offsety, 0.0);
417
+        glEnd();
418
+        glDisable( GL_TEXTURE_2D );
419
+
420
+        glLogicOp(GL_INVERT);
421
+        glEnable(GL_COLOR_LOGIC_OP);
422
+        glLineWidth( 2 );
423
+        glColor4f( 0, 0, 0, 1 );
424
+        glBegin( GL_LINES );
425
+        float cx = m_realglassx+(m_glassSize*m_glassPixels)/2;
426
+        float cy = m_realglassy+(m_glassSize*m_glassPixels)/2;
427
+        glVertex3f( cx-5, cy, 0 );
428
+        glVertex3f( cx+5, cy, 0 );
429
+        glVertex3f( cx, cy-5, 0 );
430
+        glVertex3f( cx, cy+5, 0 );
431
+        glEnd();
432
+        glLogicOp(GL_NOOP);
433
+        glDisable(GL_COLOR_LOGIC_OP);
434
+    }
435
+
203 436
     glXSwapBuffers( xengine->m_display, m_glxWindow );
204 437
 }

+ 21
- 0
src/glselectrectangle.hpp Просмотреть файл

@@ -47,6 +47,13 @@ public:
47 47
                         GLSelectRectangle( int sx, int sy, int ex, int ey, int border, bool highlight, float r, float g, float b, float a );
48 48
                         ~GLSelectRectangle();
49 49
     void                setGeo( int x, int y, int w, int h );
50
+    void                update( double dt );
51
+    void                generateMagnifyingGlass();
52
+    void                setMagnifySettings( bool on, float magstrength, unsigned int pixels );
53
+    void                pushIn( int* x, int* y, int w, int h, int rx, int ry, int rw, int rh );
54
+    void                pushOut( int* x, int* y, int w, int h, int rx, int ry, int rw, int rh );
55
+    void                findOptimalGlassPosition();
56
+    void                constrainWithinMonitor( int* x, int* y, int* w, int* h );
50 57
     float               m_r;
51 58
     float               m_g;
52 59
     float               m_b;
@@ -57,6 +64,20 @@ public:
57 64
     GLXContext          m_renderContext;
58 65
     GLXWindow           m_glxWindow;
59 66
     Colormap            m_cmap;
67
+    unsigned int        m_texid;
68
+    int                 m_offsetx;
69
+    int                 m_offsety;
70
+    int                 m_offsetw;
71
+    int                 m_offseth;
72
+    unsigned int        m_glassPixels;
73
+    float               m_glassSize;
74
+    int                 m_glassBorder;
75
+    float               m_realglassx;
76
+    float               m_realglassy;
77
+    int                 m_glassx;
78
+    int                 m_glassy;
79
+    bool                m_glassEnabled;
80
+    std::vector<XRRCrtcInfo*> m_monitors;
60 81
 };
61 82
 
62 83
 }

+ 22
- 2
src/main.cpp Просмотреть файл

@@ -266,6 +266,13 @@ int app( int argc, char** argv ) {
266 266
         pressedTime[ i ] = 0;
267 267
     }
268 268
     std::string format = options.format_arg;
269
+    bool magenabled = options.magnify_flag;
270
+    float magstrength = options.magstrength_arg;
271
+    if ( options.magpixels_arg < 0 ) {
272
+        fprintf( stderr, "Error: --magpixels < 0, it's an unsigned integer you twat. Stop trying to underflow me!\n" );
273
+        return EXIT_FAILURE;
274
+    }
275
+    unsigned int magpixels = (unsigned int)options.magpixels_arg;
269 276
     cmdline_parser_free( &options );
270 277
 
271 278
     // First we set up the x interface and grab the mouse,
@@ -292,13 +299,17 @@ int app( int argc, char** argv ) {
292 299
         }
293 300
     }
294 301
     current_utc_time( &start );
302
+    double deltatime = 0;
303
+    double curtime = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
295 304
     while ( running ) {
296 305
         current_utc_time( &time );
297 306
         // "ticking" the xengine makes it process all queued events.
298 307
         xengine->tick();
299 308
         // If the user presses any key on the keyboard, exit the application.
300 309
         // Make sure at least gracetime has passed before allowing canceling
301
-        double curtime = double( time.tv_sec*1000000000L + time.tv_nsec )/1000000000.f;
310
+        double newtime = double( time.tv_sec*1000000000L + time.tv_nsec )/1000000000.f;
311
+        deltatime = newtime-curtime;
312
+        curtime = newtime;
302 313
         double starttime = double( start.tv_sec*1000000000L + start.tv_nsec )/1000000000.f;
303 314
         if ( curtime - starttime > gracetime ) {
304 315
             if ( keyRepeat( XK_Up, curtime, 0.5, &pressedTime[ 0 ], &pressedMemory[ 0 ] ) ) {
@@ -356,6 +367,8 @@ int app( int argc, char** argv ) {
356 367
                                                                      borderSize,
357 368
                                                                      highlight,
358 369
                                                                      r, g, b, a );
370
+                            // Haha why is this so hard to cast?
371
+                            ((slop::GLSelectRectangle*)(selection))->setMagnifySettings( magenabled, magstrength, magpixels );
359 372
                         } else {
360 373
                             selection = new slop::XSelectRectangle( t.m_x, t.m_y,
361 374
                                                                     t.m_x + t.m_width,
@@ -371,6 +384,9 @@ int app( int argc, char** argv ) {
371 384
                     // Since WindowRectangle can select different windows depending on click location...
372 385
                     window = t.getWindow();
373 386
                 }
387
+                if ( selection ) {
388
+                    selection->update( deltatime );
389
+                }
374 390
                 // If the user clicked we move on to the next state.
375 391
                 if ( xengine->mouseDown( 1 ) ) {
376 392
                     state++;
@@ -408,6 +424,8 @@ int app( int argc, char** argv ) {
408 424
                                                                  borderSize,
409 425
                                                                  highlight,
410 426
                                                                  r, g, b, a );
427
+                        // Haha why is this so hard to cast?
428
+                        ((slop::GLSelectRectangle*)(selection))->setMagnifySettings( magenabled, magstrength, magpixels );
411 429
                     } else {
412 430
                         selection = new slop::XSelectRectangle( sx, sy,
413 431
                                                                 ex, ey,
@@ -429,6 +447,7 @@ int app( int argc, char** argv ) {
429 447
                 if ( ( std::abs( w ) < tolerance && std::abs( h ) < tolerance ) ) {
430 448
                     // We make sure the selection rectangle stays on the window we had selected
431 449
                     selection->setGeo( xmem, ymem, xmem + wmem, ymem + hmem );
450
+                    selection->update( deltatime );
432 451
                     xengine->setCursor( slop::Left );
433 452
                     // Make sure
434 453
                     window = windowmemory;
@@ -455,7 +474,8 @@ int app( int argc, char** argv ) {
455 474
                 int sx, sy, ex, ey;
456 475
                 constrain( cx, cy, xengine->m_mousex, xengine->m_mousey, padding, minimumsize, maximumsize, &sx, &sy, &ex, &ey );
457 476
                 // Set the selection rectangle's dimensions to mouse movement.
458
-                selection->setGeo( sx + xoffset, sy + yoffset, ex, ey );
477
+                selection->setGeo( sx + xoffset, sy + yoffset, ex-1, ey-1 );
478
+                selection->update( deltatime );
459 479
                 break;
460 480
             }
461 481
             case 3: {

+ 14
- 0
src/options.ggo Просмотреть файл

@@ -64,6 +64,20 @@ option "opengl" - "Enable hardware acceleration. Only works with modern systems
64 64
     flag
65 65
     off
66 66
 
67
+option "magnify" - "Display a magnifying glass when --opengl is also enabled."
68
+    flag
69
+    off
70
+
71
+option "magstrength" - "Sets how many times the magnification window size is multiplied."
72
+    float
73
+    default="4"
74
+    optional
75
+
76
+option "magpixels" - "Sets how many pixels are displayed in the magnification. The less pixels the bigger the magnification."
77
+    int
78
+    default="64"
79
+    optional
80
+
67 81
 option "format" f "Set the output format string. Format specifiers are %x, %y, %w, %h, %i, %g, and %c."
68 82
     string
69 83
     default="REPLACEME"

+ 3
- 0
src/selectrectangle.cpp Просмотреть файл

@@ -28,6 +28,9 @@ bool slop::isSelectRectangleSupported() {
28 28
 slop::SelectRectangle::~SelectRectangle() {
29 29
 }
30 30
 
31
+void slop::SelectRectangle::update( double dt ) {
32
+}
33
+
31 34
 void slop::SelectRectangle::setGeo( int sx, int sy, int ex, int ey ) {
32 35
     fprintf( stderr, "Tried to use a class function that's meant to be overridden!\n");
33 36
 }

+ 1
- 0
src/selectrectangle.hpp Просмотреть файл

@@ -42,6 +42,7 @@ class SelectRectangle {
42 42
 public:
43 43
     virtual ~SelectRectangle();
44 44
     virtual void    setGeo( int x, int y, int w, int h );
45
+    virtual void    update( double dt );
45 46
     Window          m_window;
46 47
     int             m_x;
47 48
     int             m_y;

+ 25
- 3
src/x.cpp Просмотреть файл

@@ -104,12 +104,25 @@ int slop::XEngine::init( std::string display ) {
104 104
     //m_root      = RootWindow     ( m_display, XScreenNumberOfScreen( m_screen ) );
105 105
     m_root      = DefaultRootWindow( m_display );
106 106
 
107
+    m_res = XRRGetScreenResourcesCurrent( m_display, m_root);
108
+
107 109
     m_good = true;
108 110
     XSetErrorHandler( slop::XEngineErrorHandler );
109 111
     selectAllInputs( m_root, EnterWindowMask );
110 112
     return EXIT_SUCCESS;
111 113
 }
112 114
 
115
+std::vector<XRRCrtcInfo*> slop::XEngine::getCRTCS() {
116
+    std::vector<XRRCrtcInfo*> monitors;
117
+    if ( !m_res ) {
118
+        return monitors;
119
+    }
120
+    for ( int i=0;i<m_res->ncrtc;i++ ) {
121
+        monitors.push_back( XRRGetCrtcInfo( m_display, m_res, m_res->crtcs[ i ] ) );
122
+    }
123
+    return monitors;
124
+}
125
+
113 126
 bool slop::XEngine::keyPressed( KeySym key ) {
114 127
     KeyCode keycode = XKeysymToKeycode( m_display, key );
115 128
     if ( keycode != 0 ) {
@@ -183,7 +196,7 @@ int slop::XEngine::grabCursor( slop::CursorType type, double waittime ) {
183 196
     if ( !m_good ) {
184 197
         return EXIT_FAILURE;
185 198
     }
186
-    int xfontcursor = getCursor( type );
199
+    int xfontcursor = makeCursor( type );
187 200
     int err = XGrabPointer( m_display, m_root, True,
188 201
                             PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask,
189 202
                             GrabModeAsync, GrabModeAsync, None, xfontcursor, CurrentTime );
@@ -290,7 +303,7 @@ void slop::XEngine::tick() {
290 303
 }
291 304
 
292 305
 // This converts an enum into a preallocated cursor, the cursor will automatically deallocate itself on ~XEngine
293
-Cursor slop::XEngine::getCursor( slop::CursorType type ) {
306
+Cursor slop::XEngine::makeCursor( slop::CursorType type ) {
294 307
     int xfontcursor;
295 308
     switch ( type ) {
296 309
         default:
@@ -316,12 +329,21 @@ Cursor slop::XEngine::getCursor( slop::CursorType type ) {
316 329
     return newcursor;
317 330
 }
318 331
 
332
+slop::CursorType slop::XEngine::getCursor() {
333
+    if ( m_currentCursor ) {
334
+        return m_currentCursor;
335
+    } else {
336
+        return slop::Left;
337
+    }
338
+}
339
+
319 340
 // Swaps out the current cursor, bewary that XChangeActivePointerGrab also resets masks, so if you change the mouse masks on grab you need to change them here too.
320 341
 void slop::XEngine::setCursor( slop::CursorType type ) {
321 342
     if ( !m_good ) {
322 343
         return;
323 344
     }
324
-    Cursor xfontcursor = getCursor( type );
345
+    m_currentCursor = type;
346
+    Cursor xfontcursor = makeCursor( type );
325 347
     XChangeActivePointerGrab( m_display,
326 348
                               PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
327 349
                               xfontcursor, CurrentTime );

+ 7
- 1
src/x.hpp Просмотреть файл

@@ -26,6 +26,7 @@
26 26
 #include <X11/Xlib.h>
27 27
 #include <X11/cursorfont.h>
28 28
 #include <X11/extensions/shape.h>
29
+#include <X11/extensions/Xrandr.h>
29 30
 
30 31
 #include <stdlib.h>
31 32
 #include <cstring>
@@ -77,9 +78,12 @@ public:
77 78
     int                 releaseCursor();
78 79
     int                 releaseKeyboard();
79 80
     void                setCursor( slop::CursorType type );
81
+    slop::CursorType    getCursor();
80 82
     void                drawRect( int x, int y, unsigned int w, unsigned int h );
81 83
     unsigned int        getWidth();
82 84
     unsigned int        getHeight();
85
+    std::vector<XRRCrtcInfo*>        getCRTCS();
86
+    void                freeCRTCS( std::vector<XRRCrtcInfo*> monitors );
83 87
     int                 m_mousex;
84 88
     int                 m_mousey;
85 89
     Display*            m_display;
@@ -91,10 +95,12 @@ public:
91 95
     std::vector<bool>   m_mouse;
92 96
     bool                mouseDown( unsigned int button );
93 97
     bool                m_keypressed;
98
+    XRRScreenResources* m_res;
94 99
 private:
100
+    slop::CursorType    m_currentCursor;
95 101
     bool                m_good;
96 102
     std::vector<Cursor> m_cursors;
97
-    Cursor              getCursor( slop::CursorType type );
103
+    Cursor              makeCursor( slop::CursorType type );
98 104
     void                selectAllInputs( Window win, long event_mask);
99 105
 };
100 106