├── .gitignore ├── README.md ├── Makefile.am ├── configure.ac ├── LICENSE ├── INSTALL.md ├── doc ├── xininfo.markdown └── xininfo.1 ├── data └── uncrustify.cfg └── source └── xininfo.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.swp 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | doc/xininfo.markdown -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Specify automake version. 2 | AUTOMAKE_OPTIONS = 1.11.3 3 | 4 | ## 5 | # Rofi the program 6 | ## 7 | bin_PROGRAMS=xininfo 8 | 9 | LIBS=\ 10 | @xcb_LIBS@ 11 | 12 | AM_CFLAGS=\ 13 | @EXTRA_CFLAGS@\ 14 | @xcb_CFLAGS@\ 15 | -DMANPAGE_PATH="\"$(mandir)/\""\ 16 | -I$(top_builddir)/\ 17 | -Werror=missing-prototypes 18 | 19 | EXTRA_DIST=\ 20 | doc/xininfo.markdown 21 | 22 | xininfo_SOURCES=\ 23 | source/xininfo.c 24 | 25 | dist_man1_MANS=\ 26 | doc/xininfo.1 27 | 28 | .PHONY: indent 29 | indent: $(xininfo_SOURCES) 30 | uncrustify -c $(top_srcdir)/data/uncrustify.cfg --replace $^ 31 | 32 | .PHONY: update-manpage 33 | update-manpage: 34 | ronn --roff --pipe $(top_srcdir)/doc/xininfo.markdown > $(top_srcdir)/doc/xininfo.1 35 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([xininfo], [0.15.5], [qball@gmpclient.org]) 2 | 3 | AC_CONFIG_SRCDIR([source/xininfo.c]) 4 | AC_CONFIG_HEADER([config.h]) 5 | 6 | ## 7 | # Setup automake to be silent and in foreign mode. 8 | ## 9 | AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects dist-xz]) 10 | AM_SILENT_RULES([yes]) 11 | 12 | ## 13 | # Check for compiler 14 | ## 15 | AC_PROG_CC([clang gcc cc]) 16 | AC_PROG_CC_C99 17 | AM_PROG_CC_C_O 18 | 19 | AC_USE_SYSTEM_EXTENSIONS 20 | 21 | ## 22 | # Check dependencies 23 | ## 24 | AC_CHECK_FUNC([atexit],, AC_MSG_ERROR("Could not find atexit in c library")) 25 | PKG_PROG_PKG_CONFIG 26 | 27 | PKG_CHECK_MODULES([xcb], [ xcb-aux xcb-randr xcb-xinerama xcb-dpms xcb-ewmh xcb-screensaver ]) 28 | 29 | AC_SUBST([EXTRA_CFLAGS], ["-Wall -Wextra -Wparentheses -Winline -pedantic"]) 30 | 31 | AC_CONFIG_FILES([Makefile ]) 32 | AC_OUTPUT 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT/X11 License 2 | Copyright (c) 2014 Qball Cow 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installation guide 2 | 3 | ## DEPENDENCY 4 | 5 | ### For building: 6 | 7 | * C compiler that supports the c99 standard. (gcc or clang) 8 | * make 9 | * autoconf 10 | * automake (1.11.3 or up) 11 | * pkg-config 12 | * Developer packages of the external libraries 13 | 14 | ### External libraries 15 | 16 | * libglib2.0 >= 2.40 17 | * libxcb (sometimes split, you need libxcb, libxcb-xkb and libxcb-randr libxcb-xinerama) 18 | * xcb-util 19 | * xcb-util-wm (sometimes split as libxcb-ewmh and libxcb-icccm libxcb-dpms libxcb-screensaver) 20 | * xcb-util-xrm [new module, can be found here](https://github.com/Airblader/xcb-util-xrm/) 21 | 22 | On debian based systems, the developer packages are in the form of: `-dev` on rpm based 23 | `-devel`. 24 | 25 | ## Install from a release 26 | 27 | Check dependencies and configure build system: 28 | 29 | ``` 30 | ./configure 31 | ``` 32 | 33 | Build xininfo: 34 | 35 | ``` 36 | make 37 | ``` 38 | 39 | The actual install, execute as root (if needed): 40 | 41 | ``` 42 | make install 43 | ``` 44 | 45 | 46 | ## Install a checkout from git 47 | 48 | The GitHub Pages version of these directions may be out of date. Please use 49 | [INSTALL.md from the online repo][master-install] or your local repository. 50 | 51 | [master-install]: https://github.com/DaveDavenport/xininfo/blob/master/INSTALL.md#install-a-checkout-from-git 52 | 53 | Generate build system: 54 | 55 | ``` 56 | autoreconf -i 57 | ``` 58 | 59 | Create a build directory: 60 | 61 | ``` 62 | mkdir build 63 | ``` 64 | 65 | Enter build directory: 66 | 67 | ``` 68 | cd build 69 | ``` 70 | 71 | Check dependencies and configure build system: 72 | 73 | ``` 74 | ../configure 75 | ``` 76 | 77 | Build xininfo: 78 | 79 | ``` 80 | make 81 | ``` 82 | 83 | The actual install, execute as root (if needed): 84 | 85 | ``` 86 | make install 87 | ``` 88 | 89 | 90 | ## Options for configure 91 | 92 | When you run the configure step there are several you can configure. (To see the full list type 93 | `./configure --help` ). 94 | 95 | The most useful one to set the installation prefix: 96 | 97 | ``` 98 | ./configure --prefix= 99 | ``` 100 | 101 | f.e. 102 | 103 | ``` 104 | ./configure --prefix=/usr/ 105 | ``` 106 | 107 | ### Install locally 108 | 109 | or to install locally: 110 | 111 | ``` 112 | ./configure --prefix=${HOME}/.local/ 113 | ``` 114 | 115 | 116 | ## Options for make 117 | 118 | When you run make you can tweak the build process a little. 119 | 120 | ### Verbose output 121 | 122 | Show the commands called: 123 | 124 | ``` 125 | make V=1 126 | ``` 127 | 128 | ### Debug build 129 | 130 | Compile with debug symbols and no optimization 131 | 132 | ``` 133 | make CFLAGS="-O0 -g3" clean xininfo 134 | ``` 135 | -------------------------------------------------------------------------------- /doc/xininfo.markdown: -------------------------------------------------------------------------------- 1 | # XININFO 1 xininfo 2 | 3 | ## NAME 4 | 5 | xininfo - a tool to query the layout and size of each configured monitor. 6 | 7 | ## SYNOPSIS 8 | 9 | **xininfo** 10 | [ -monitor *id*] 11 | [ -active-mon] 12 | [ -mon-size] 13 | [ -mon-width ] 14 | [ -max-mon-width ] 15 | [ -mon-height ] 16 | [ -max-mon-height ] 17 | [ -mon-x ] 18 | [ -mon-y ] 19 | [ -mon-pos ] 20 | [ -num-mon ] 21 | [ -dpms ] 22 | [ -dpms-state ] 23 | [ -screensaver ] 24 | [ -screensaver-state ] 25 | [ -print ] 26 | [ -name ] 27 | [ -modes ] 28 | [ -h ] 29 | 30 | 31 | 32 | ## DESCRIPTION 33 | 34 | **xininfo** is an X11 utility to query the current layout and size of each configured monitor. It is 35 | designed to be used by scripts. 36 | 37 | ## License 38 | 39 | MIT/X11 40 | 41 | ## USAGE 42 | 43 | **xininfo** accepts the following commands. Multiple commands can be concatenated. 44 | All information returned is in number of pixels. 45 | 46 | `-monitor` *id* 47 | 48 | Set queried monitor to *id*. By default it uses the active monitor. 49 | 50 | `-active-mon` 51 | 52 | Query the *id* of the active monitor. 53 | 54 | **Prints**: *id* 55 | 56 | `-mon-size` 57 | 58 | Get the size of the monitor. 59 | 60 | **Prints**: *width* *height* 61 | 62 | `-mon-width` 63 | 64 | Get the width of the monitor: 65 | 66 | **Prints**: *width* 67 | 68 | `-max-mon-width` 69 | 70 | Query width of the monitor with the most horizontal pixels 71 | 72 | **Prints**: *width* 73 | 74 | `-mon-height` 75 | 76 | Get the height of the monitor: 77 | 78 | **Prints**: *height* 79 | 80 | `-max-mon-height` 81 | 82 | Query height of the monitor with the most vertical pixels 83 | 84 | **Prints**: *width* 85 | 86 | `-mon-x` 87 | 88 | Get the x position of the monitor: 89 | 90 | **Prints**: *x* 91 | 92 | `-mon-y` 93 | 94 | Get the y position of the monitor: 95 | 96 | **Prints**: *y* 97 | 98 | `-mon-pos` 99 | 100 | Get the position of the monitor: 101 | 102 | **Prints**: *x* *y* 103 | 104 | `-num-mon` 105 | 106 | Queries the number of configured monitors. 107 | 108 | **Prints**: *#monitors* 109 | 110 | `-dpms` 111 | 112 | Prints the current dpms state human readable. 113 | 114 | `-dpms-state` 115 | 116 | Prints the current dpms state easy parsable. 117 | 118 | `-screensaver` 119 | 120 | Prints the current screensaver state human readable. 121 | 122 | `-screensaver-state` 123 | 124 | Prints the current screensaver state easy parsable. 125 | 126 | 127 | `-print` 128 | 129 | Print out all information in a human readable format. 130 | 131 | `-name` 132 | 133 | Print the xrandr name of the monitor. 134 | 135 | `-modes` 136 | 137 | Print the supported modes (resolution and refresh rate) for the selected monitor. 138 | 139 | `-h` 140 | 141 | Show the manpage of **xininfo** 142 | 143 | 144 | ## AUTHOR 145 | 146 | Qball Cow 147 | -------------------------------------------------------------------------------- /doc/xininfo.1: -------------------------------------------------------------------------------- 1 | .\" generated with Ronn/v0.7.3 2 | .\" http://github.com/rtomayko/ronn/tree/0.7.3 3 | . 4 | .TH "XININFO" "" "2016-11-09" "" "" 5 | . 6 | .SH "NAME" 7 | xininfo \- a tool to query the layout and size of each configured monitor\. 8 | . 9 | .SH "SYNOPSIS" 10 | \fBxininfo\fR [ \-monitor \fIid\fR] [ \-active\-mon] [ \-mon\-size] [ \-mon\-width ] [ \-max\-mon\-width ] [ \-mon\-height ] [ \-max\-mon\-height ] [ \-mon\-x ] [ \-mon\-y ] [ \-mon\-pos ] [ \-num\-mon ] [ \-dpms ] [ \-dpms\-state ] [ \-screensaver ] [ \-screensaver\-state ] [ \-print ] [ \-name ] [ \-modes ] [ \-h ] 11 | . 12 | .SH "DESCRIPTION" 13 | \fBxininfo\fR is an X11 utility to query the current layout and size of each configured monitor\. It is designed to be used by scripts\. 14 | . 15 | .SH "License" 16 | MIT/X11 17 | . 18 | .SH "USAGE" 19 | \fBxininfo\fR accepts the following commands\. Multiple commands can be concatenated\. All information returned is in number of pixels\. 20 | . 21 | .P 22 | \fB\-monitor\fR \fIid\fR 23 | . 24 | .P 25 | Set queried monitor to \fIid\fR\. By default it uses the active monitor\. 26 | . 27 | .P 28 | \fB\-active\-mon\fR 29 | . 30 | .P 31 | Query the \fIid\fR of the active monitor\. 32 | . 33 | .P 34 | \fBPrints\fR: \fIid\fR 35 | . 36 | .P 37 | \fB\-mon\-size\fR 38 | . 39 | .P 40 | Get the size of the monitor\. 41 | . 42 | .P 43 | \fBPrints\fR: \fIwidth\fR \fIheight\fR 44 | . 45 | .P 46 | \fB\-mon\-width\fR 47 | . 48 | .P 49 | Get the width of the monitor: 50 | . 51 | .P 52 | \fBPrints\fR: \fIwidth\fR 53 | . 54 | .P 55 | \fB\-max\-mon\-width\fR 56 | . 57 | .P 58 | Query width of the monitor with the most horizontal pixels 59 | . 60 | .P 61 | \fBPrints\fR: \fIwidth\fR 62 | . 63 | .P 64 | \fB\-mon\-height\fR 65 | . 66 | .P 67 | Get the height of the monitor: 68 | . 69 | .P 70 | \fBPrints\fR: \fIheight\fR 71 | . 72 | .P 73 | \fB\-max\-mon\-height\fR 74 | . 75 | .P 76 | Query height of the monitor with the most vertical pixels 77 | . 78 | .P 79 | \fBPrints\fR: \fIwidth\fR 80 | . 81 | .P 82 | \fB\-mon\-x\fR 83 | . 84 | .P 85 | Get the x position of the monitor: 86 | . 87 | .P 88 | \fBPrints\fR: \fIx\fR 89 | . 90 | .P 91 | \fB\-mon\-y\fR 92 | . 93 | .P 94 | Get the y position of the monitor: 95 | . 96 | .P 97 | \fBPrints\fR: \fIy\fR 98 | . 99 | .P 100 | \fB\-mon\-pos\fR 101 | . 102 | .P 103 | Get the position of the monitor: 104 | . 105 | .P 106 | \fBPrints\fR: \fIx\fR \fIy\fR 107 | . 108 | .P 109 | \fB\-num\-mon\fR 110 | . 111 | .P 112 | Queries the number of configured monitors\. 113 | . 114 | .P 115 | \fBPrints\fR: \fI#monitors\fR 116 | . 117 | .P 118 | \fB\-dpms\fR 119 | . 120 | .P 121 | Prints the current dpms state human readable\. 122 | . 123 | .P 124 | \fB\-dpms\-state\fR 125 | . 126 | .P 127 | Prints the current dpms state easy parsable\. 128 | . 129 | .P 130 | \fB\-screensaver\fR 131 | . 132 | .P 133 | Prints the current screensaver state human readable\. 134 | . 135 | .P 136 | \fB\-screensaver\-state\fR 137 | . 138 | .P 139 | Prints the current screensaver state easy parsable\. 140 | . 141 | .P 142 | \fB\-print\fR 143 | . 144 | .P 145 | Print out all information in a human readable format\. 146 | . 147 | .P 148 | \fB\-name\fR 149 | . 150 | .P 151 | Print the xrandr name of the monitor\. 152 | . 153 | .P 154 | \fB\-modes\fR 155 | . 156 | .P 157 | Print the supported modes (resolution and refresh rate) for the selected monitor\. 158 | . 159 | .P 160 | \fB\-h\fR 161 | . 162 | .P 163 | Show the manpage of \fBxininfo\fR 164 | . 165 | .SH "AUTHOR" 166 | Qball Cow \fIqball@gmpclient\.org\fR 167 | -------------------------------------------------------------------------------- /data/uncrustify.cfg: -------------------------------------------------------------------------------- 1 | # 2 | # My favorite format 3 | # 4 | code_width = 240 5 | nl_max = 2 6 | ls_func_split_full = True 7 | indent_with_tabs = 0 # 1=indent to level only, 2=indent with tabs 8 | input_tab_size = 8 # original tab size 9 | output_tab_size = 4 # new tab size 10 | indent_columns = output_tab_size 11 | indent_label = 2 # pos: absolute col, neg: relative column 12 | indent_align_string = False # align broken strings 13 | indent_brace = 0 14 | 15 | nl_enum_brace = add # "enum {" vs "enum \n {" 16 | nl_union_brace = add # "union {" vs "union \n {" 17 | nl_struct_brace = add # "struct {" vs "struct \n {" 18 | nl_do_brace = remove # "do {" vs "do \n {" 19 | nl_if_brace = remove # "if () {" vs "if () \n {" 20 | nl_for_brace = remove # "for () {" vs "for () \n {" 21 | nl_else_brace = remove # "else {" vs "else \n {" 22 | nl_while_brace = remove # "while () {" vs "while () \n {" 23 | nl_switch_brace = add # "switch () {" vs "switch () \n {" 24 | # nl_func_var_def_blk = 1 25 | # nl_before_case = 1 26 | nl_fcall_brace = add # "foo() {" vs "foo()\n{" 27 | nl_fdef_brace = add # "int foo() {" vs "int foo()\n{" 28 | # nl_after_return = TRUE 29 | nl_brace_while = remove 30 | nl_brace_else = add 31 | nl_squeeze_ifdef = FALSE 32 | 33 | mod_paren_on_return = remove # "return 1;" vs "return (1);" 34 | mod_full_brace_if = add # "if (a) a--;" vs "if (a) { a--; }" 35 | mod_full_brace_for = add # "for () a--;" vs "for () { a--; }" 36 | mod_full_brace_do = add # "do a--; while ();" vs "do { a--; } while ();" 37 | mod_full_brace_while = add # "while (a) a--;" vs "while (a) { a--; }" 38 | 39 | sp_before_semi = remove 40 | sp_paren_paren = add # space between (( and )) 41 | sp_return_paren = add # "return (1);" vs "return(1);" 42 | sp_sizeof_paren = add # "sizeof (int)" vs "sizeof(int)" 43 | sp_before_sparen = add # "if (" vs "if(" 44 | sp_after_sparen = force # "if () {" vs "if (){" 45 | sp_after_cast = add # "(int) a" vs "(int)a" 46 | sp_inside_braces = add # "{ 1 }" vs "{1}" 47 | sp_inside_braces_struct = force # "{ 1 }" vs "{1}" 48 | sp_inside_braces_enum = force # "{ 1 }" vs "{1}" 49 | sp_inside_paren = add 50 | sp_inside_fparen = add 51 | sp_inside_sparen = add 52 | #sp_type_func = ignore 53 | sp_assign = force 54 | sp_arith = force 55 | sp_bool = force 56 | sp_compare = force 57 | sp_assign = force 58 | sp_after_comma = force 59 | sp_func_def_paren = add # "int foo (){" vs "int foo(){" 60 | sp_func_call_paren = add # "foo (" vs "foo(" 61 | sp_func_proto_paren = add # "int foo ();" vs "int foo();" 62 | 63 | align_with_tabs = FALSE # use tabs to align 64 | align_on_tabstop = FALSE # align on tabstops 65 | align_enum_equ_span = 4 66 | align_nl_cont = TRUE 67 | align_var_def_span = 2 68 | align_var_def_inline = TRUE 69 | align_var_def_star_style = 1 70 | align_var_def_colon = TRUE 71 | align_assign_span = 1 72 | align_struct_init_span = 3 73 | align_var_struct_span = 3 74 | align_right_cmt_span = 3 75 | align_pp_define_span = 3 76 | align_pp_define_gap = 4 77 | align_number_left = TRUE 78 | align_typedef_span = 5 79 | align_typedef_gap = 3 80 | 81 | # cmt_star_cont = TRUE 82 | 83 | eat_blanks_before_close_brace = TRUE 84 | eat_blanks_after_open_brace = TRUE 85 | 86 | -------------------------------------------------------------------------------- /source/xininfo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * xininfo 3 | * 4 | * MIT/X11 License 5 | * Copyright (c) 2014-2015 Qball Cow 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining 8 | * a copy of this software and associated documentation files (the 9 | * "Software"), to deal in the Software without restriction, including 10 | * without limitation the rights to use, copy, modify, merge, publish, 11 | * distribute, sublicense, and/or sell copies of the Software, and to 12 | * permit persons to whom the Software is furnished to do so, subject to 13 | * the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | * 26 | */ 27 | 28 | #define _GNU_SOURCE 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #define MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) 48 | #define MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) ) 49 | #define INTERSECT( x, y, x1, y1, w1, h1 ) ( ( ( ( x ) >= ( x1 ) ) && ( ( x ) < ( x1 + w1 ) ) ) && ( ( ( y ) >= ( y1 ) ) && ( ( y ) < ( y1 + h1 ) ) ) ) 50 | 51 | #define TRUE 1 52 | #define FALSE 0 53 | 54 | xcb_connection_t *connection = NULL; 55 | xcb_screen_t *screen = NULL; 56 | xcb_ewmh_connection_t ewmh; 57 | int screen_nbr = 0; 58 | int show_all = FALSE; 59 | 60 | typedef struct 61 | { 62 | int w, h; 63 | double rate; 64 | } MMB_Mode; 65 | // Monitor layout stuff. 66 | typedef struct 67 | { 68 | int enabled; 69 | int x, y; 70 | int w, h; 71 | char *name; 72 | int primary; 73 | MMB_Mode *modes; 74 | int modes_len; 75 | } MMB_Rectangle; 76 | 77 | typedef struct 78 | { 79 | // Size of the total screen area. 80 | MMB_Rectangle base; 81 | 82 | // Number of monitors. 83 | int num_monitors; 84 | // List of monitors; 85 | MMB_Rectangle **monitors; 86 | 87 | // Mouse position 88 | MMB_Rectangle active_monitor; 89 | } MMB_Screen; 90 | 91 | // find active_monitor pointer location 92 | void x11_build_monitor_layout ( MMB_Screen *mmc ); 93 | 94 | static int pointer_get ( MMB_Screen *screen, xcb_window_t root ) 95 | { 96 | xcb_query_pointer_cookie_t c = xcb_query_pointer ( connection, root ); 97 | xcb_query_pointer_reply_t *r = xcb_query_pointer_reply ( connection, c, NULL ); 98 | if ( r ) { 99 | screen->active_monitor.x = r->root_x; 100 | screen->active_monitor.y = r->root_y; 101 | free ( r ); 102 | return TRUE; 103 | } 104 | 105 | return FALSE; 106 | } 107 | static int mmb_screen_get_current_desktop ( MMB_Screen *screen ) 108 | { 109 | unsigned int current_desktop = 0; 110 | xcb_get_property_cookie_t gcdc; 111 | gcdc = xcb_ewmh_get_current_desktop ( &ewmh, screen_nbr ); 112 | if ( xcb_ewmh_get_current_desktop_reply ( &ewmh, gcdc, ¤t_desktop, NULL ) ) { 113 | xcb_get_property_cookie_t c = xcb_ewmh_get_desktop_viewport ( &ewmh, screen_nbr ); 114 | xcb_ewmh_get_desktop_viewport_reply_t vp; 115 | if ( xcb_ewmh_get_desktop_viewport_reply ( &ewmh, c, &vp, NULL ) ) { 116 | if ( current_desktop < vp.desktop_viewport_len ) { 117 | screen->active_monitor.x = vp.desktop_viewport[current_desktop].x; 118 | screen->active_monitor.y = vp.desktop_viewport[current_desktop].y; 119 | xcb_ewmh_get_desktop_viewport_reply_wipe ( &vp ); 120 | return TRUE; 121 | } 122 | xcb_ewmh_get_desktop_viewport_reply_wipe ( &vp ); 123 | } 124 | } 125 | return FALSE; 126 | } 127 | 128 | /** 129 | * @param display An X11 Display 130 | * 131 | * Create MMB_Screen that holds the monitor layout of display. 132 | * 133 | * @returns filled in MMB_Screen 134 | */ 135 | static MMB_Screen *mmb_screen_create ( int screen_nbr ) 136 | { 137 | // Create empty structure. 138 | MMB_Screen *retv = malloc ( sizeof ( *retv ) ); 139 | memset ( retv, 0, sizeof ( *retv ) ); 140 | 141 | screen = xcb_aux_get_screen ( connection, screen_nbr ); 142 | retv->base.w = screen->width_in_pixels; 143 | retv->base.h = screen->height_in_pixels; 144 | 145 | x11_build_monitor_layout ( retv ); 146 | // monitor_active 147 | if ( !mmb_screen_get_current_desktop ( retv ) ) { 148 | if ( pointer_get ( retv, screen->root ) ) { 149 | fprintf ( stderr, "Failed to find monitor\n" ); 150 | } 151 | } 152 | 153 | return retv; 154 | } 155 | /** 156 | * Create monitor based on output id 157 | */ 158 | static MMB_Rectangle * x11_get_monitor_from_output ( xcb_randr_output_t out, xcb_randr_mode_info_t *modes, int modes_len ) 159 | { 160 | xcb_randr_get_output_info_reply_t *op_reply; 161 | xcb_randr_get_crtc_info_reply_t *crtc_reply; 162 | xcb_randr_get_output_info_cookie_t it = xcb_randr_get_output_info ( connection, out, XCB_CURRENT_TIME ); 163 | op_reply = xcb_randr_get_output_info_reply ( connection, it, NULL ); 164 | 165 | if ( op_reply->num_modes == 0 ) { 166 | // No monitor attached. 167 | free ( op_reply ); 168 | return NULL; 169 | } 170 | MMB_Rectangle *retv = malloc ( sizeof ( MMB_Rectangle ) ); 171 | memset ( retv, '\0', sizeof ( MMB_Rectangle ) ); 172 | if ( op_reply->crtc != XCB_NONE ) { 173 | xcb_randr_get_crtc_info_cookie_t ct = xcb_randr_get_crtc_info ( connection, op_reply->crtc, XCB_CURRENT_TIME ); 174 | crtc_reply = xcb_randr_get_crtc_info_reply ( connection, ct, NULL ); 175 | if ( crtc_reply ) { 176 | retv->enabled = TRUE; 177 | retv->x = crtc_reply->x; 178 | retv->y = crtc_reply->y; 179 | retv->w = crtc_reply->width; 180 | retv->h = crtc_reply->height; 181 | free ( crtc_reply ); 182 | } 183 | } 184 | 185 | retv->modes_len = op_reply->num_modes; 186 | retv->modes = malloc ( sizeof ( MMB_Mode ) * op_reply->num_modes ); 187 | xcb_randr_mode_t *modesr = xcb_randr_get_output_info_modes ( op_reply ); 188 | for ( int i = 0; i < op_reply->num_modes; i++ ) { 189 | for ( int j = 0; j < modes_len; j++ ) { 190 | if ( modesr[i] == modes[j].id ) { 191 | retv->modes[i].w = modes[j].width; 192 | retv->modes[i].h = modes[j].height; 193 | retv->modes[i].rate = modes[j].dot_clock / (double) ( modes[j].htotal * modes[j].vtotal ); 194 | } 195 | } 196 | } 197 | 198 | char *tname = (char *) xcb_randr_get_output_info_name ( op_reply ); 199 | int tname_len = xcb_randr_get_output_info_name_length ( op_reply ); 200 | 201 | retv->name = malloc ( ( tname_len + 1 ) * sizeof ( char ) ); 202 | memcpy ( retv->name, tname, tname_len ); 203 | retv->name[tname_len] = '\0'; 204 | free ( op_reply ); 205 | return retv; 206 | } 207 | 208 | static void x11_build_monitor_layout_xinerama ( MMB_Screen *mmc ) 209 | { 210 | xcb_xinerama_query_screens_cookie_t screens_cookie = xcb_xinerama_query_screens_unchecked ( connection ); 211 | 212 | xcb_xinerama_query_screens_reply_t *screens_reply = xcb_xinerama_query_screens_reply ( connection, 213 | screens_cookie, 214 | NULL 215 | ); 216 | 217 | xcb_xinerama_screen_info_iterator_t screens_iterator = xcb_xinerama_query_screens_screen_info_iterator ( 218 | screens_reply 219 | ); 220 | 221 | for (; screens_iterator.rem > 0; xcb_xinerama_screen_info_next ( &screens_iterator ) ) { 222 | mmc->monitors = realloc ( mmc->monitors, sizeof ( MMB_Rectangle* ) * ( mmc->num_monitors + 1 ) ); 223 | MMB_Rectangle *w = malloc ( sizeof ( MMB_Rectangle ) ); 224 | memset ( w, '\0', sizeof ( MMB_Rectangle ) ); 225 | w->x = screens_iterator.data->x_org; 226 | w->y = screens_iterator.data->y_org; 227 | w->w = screens_iterator.data->width; 228 | w->h = screens_iterator.data->height; 229 | mmc->monitors[mmc->num_monitors] = w; 230 | mmc->num_monitors++; 231 | } 232 | 233 | free ( screens_reply ); 234 | } 235 | static int x11_is_extension_present ( const char *extension ) 236 | { 237 | xcb_query_extension_cookie_t randr_cookie = xcb_query_extension ( connection, strlen ( extension ), extension ); 238 | xcb_query_extension_reply_t *randr_reply = xcb_query_extension_reply ( connection, randr_cookie, NULL ); 239 | int present = randr_reply->present; 240 | free ( randr_reply ); 241 | return present; 242 | } 243 | 244 | void x11_build_monitor_layout ( MMB_Screen *mmc ) 245 | { 246 | // If RANDR is not available, try Xinerama 247 | if ( !x11_is_extension_present ( "RANDR" ) ) { 248 | // Check if xinerama is available. 249 | if ( x11_is_extension_present ( "XINERAMA" ) ) { 250 | x11_build_monitor_layout_xinerama ( mmc ); 251 | return; 252 | } 253 | fprintf ( stderr, "No RANDR or Xinerama available for getting monitor layout." ); 254 | return; 255 | } 256 | 257 | xcb_randr_get_screen_resources_current_reply_t *res_reply; 258 | xcb_randr_get_screen_resources_current_cookie_t src; 259 | src = xcb_randr_get_screen_resources_current ( connection, screen->root ); 260 | res_reply = xcb_randr_get_screen_resources_current_reply ( connection, src, NULL ); 261 | if ( !res_reply ) { 262 | return; //just report error 263 | } 264 | int mon_num = xcb_randr_get_screen_resources_current_outputs_length ( res_reply ); 265 | xcb_randr_output_t *ops = xcb_randr_get_screen_resources_current_outputs ( res_reply ); 266 | xcb_randr_mode_info_t *modes = xcb_randr_get_screen_resources_current_modes ( res_reply ); 267 | int modes_len = xcb_randr_get_screen_resources_current_modes_length ( res_reply ); 268 | 269 | // Get primary. 270 | xcb_randr_get_output_primary_cookie_t pc = xcb_randr_get_output_primary ( connection, screen->root ); 271 | xcb_randr_get_output_primary_reply_t *pc_rep = xcb_randr_get_output_primary_reply ( connection, pc, NULL ); 272 | 273 | for ( int i = mon_num - 1; i >= 0; i-- ) { 274 | MMB_Rectangle *w = x11_get_monitor_from_output ( ops[i], modes, modes_len ); 275 | if ( w ) { 276 | mmc->monitors = realloc ( mmc->monitors, ( mmc->num_monitors + 1 ) * sizeof ( MMB_Rectangle* ) ); 277 | mmc->monitors[mmc->num_monitors] = w; 278 | if ( pc_rep && pc_rep->output == ops[i] ) { 279 | w->primary = TRUE; 280 | } 281 | mmc->num_monitors++; 282 | } 283 | } 284 | // If exists, free primary output reply. 285 | if ( pc_rep ) { 286 | free ( pc_rep ); 287 | } 288 | free ( res_reply ); 289 | } 290 | 291 | /** 292 | * @param screen a Pointer to the MMB_Screen pointer to free. 293 | * 294 | * Free MMB_Screen object and set pointer to NULL. 295 | */ 296 | static void mmb_screen_free ( MMB_Screen **screen ) 297 | { 298 | if ( screen == NULL || *screen == NULL ) { 299 | return; 300 | } 301 | 302 | if ( ( *screen )->active_monitor.name ) { 303 | free ( ( *screen )->active_monitor.name ); 304 | } 305 | 306 | for ( int i = 0; i < ( *screen )->num_monitors; i++ ) { 307 | if ( ( *screen )->monitors[i]->name ) { 308 | free ( ( *screen )->monitors[i]->name ); 309 | if ( ( *screen )->monitors[i]->modes_len > 0 ) { 310 | free ( ( *screen )->monitors[i]->modes ); 311 | } 312 | free ( ( *screen )->monitors[i] ); 313 | } 314 | } 315 | 316 | if ( ( *screen )->monitors != NULL ) { 317 | free ( ( *screen )->monitors ); 318 | } 319 | 320 | free ( *screen ); 321 | screen = NULL; 322 | } 323 | 324 | static int mmb_screen_get_active_monitor ( MMB_Screen *screen ) 325 | { 326 | for ( int i = 0; i < screen->num_monitors; i++ ) { 327 | if ( INTERSECT ( screen->active_monitor.x, screen->active_monitor.y, 328 | screen->monitors[i]->x, 329 | screen->monitors[i]->y, 330 | screen->monitors[i]->w, 331 | screen->monitors[i]->h ) ) { 332 | return i; 333 | } 334 | } 335 | 336 | return 0; 337 | } 338 | 339 | static void mmb_screen_print ( MMB_Screen *screen ) 340 | { 341 | printf ( "Total size: %d %d\n", screen->base.w, screen->base.h ); 342 | printf ( "Num. monitors: %d\n", screen->num_monitors ); 343 | 344 | for ( int i = 0; i < screen->num_monitors; i++ ) { 345 | printf ( " %01d: %d %d -> %d %d (%s) %s\n", 346 | i, 347 | screen->monitors[i]->x, 348 | screen->monitors[i]->y, 349 | screen->monitors[i]->w, 350 | screen->monitors[i]->h, 351 | screen->monitors[i]->name, 352 | screen->monitors[i]->enabled ? "" : "(disabled)" 353 | ); 354 | } 355 | 356 | int active_monitor = mmb_screen_get_active_monitor ( screen ); 357 | printf ( "Active mon: %d\n", active_monitor ); 358 | printf ( " %d-%d\n", screen->active_monitor.x, screen->active_monitor.y ); 359 | } 360 | 361 | static void screensaver ( char **argv ) 362 | { 363 | (void) ( argv ); 364 | if ( !x11_is_extension_present ( "MIT-SCREEN-SAVER" ) ) { 365 | printf ( "unavailable\n" ); 366 | return; 367 | } 368 | xcb_screensaver_query_info_cookie_t c = xcb_screensaver_query_info ( connection, screen->root ); 369 | xcb_screensaver_query_info_reply_t *r = xcb_screensaver_query_info_reply ( connection, c, NULL ); 370 | if ( r ) { 371 | switch ( r->state ) 372 | { 373 | case XCB_SCREENSAVER_STATE_OFF: 374 | printf ( "off\n" ); 375 | break; 376 | case XCB_SCREENSAVER_STATE_ON: 377 | printf ( "on\n" ); 378 | break; 379 | case XCB_SCREENSAVER_STATE_CYCLE: 380 | printf ( "cycle\n" ); 381 | break; 382 | default: 383 | printf ( "disabled\n" ); 384 | break; 385 | } 386 | free ( r ); 387 | } 388 | else{ 389 | printf ( "n\\a\n" ); 390 | } 391 | } 392 | static void screensaver_print ( char **argv ) 393 | { 394 | (void) ( argv ); 395 | printf ( "screensaver: " ); 396 | screensaver ( NULL ); 397 | } 398 | 399 | static void dpms_state ( char **argv ) 400 | { 401 | (void ) ( argv ); 402 | xcb_dpms_capable_cookie_t c = xcb_dpms_capable ( connection ); 403 | xcb_dpms_capable_reply_t *r = xcb_dpms_capable_reply ( connection, c, NULL ); 404 | 405 | if ( r && r->capable == 0 ) { 406 | printf ( "incapable\n" ); 407 | free ( r ); 408 | return; 409 | } 410 | free ( r ); 411 | xcb_dpms_info_cookie_t ic = xcb_dpms_info ( connection ); 412 | xcb_dpms_info_reply_t *ir = xcb_dpms_info_reply ( connection, ic, NULL ); 413 | if ( ir ) { 414 | if ( ir->state ) { 415 | switch ( ir->power_level ) 416 | { 417 | case XCB_DPMS_DPMS_MODE_ON: 418 | printf ( "on\n" ); 419 | break; 420 | case XCB_DPMS_DPMS_MODE_STANDBY: 421 | printf ( "standby\n" ); 422 | break; 423 | case XCB_DPMS_DPMS_MODE_SUSPEND: 424 | printf ( "suspend\n" ); 425 | break; 426 | case XCB_DPMS_DPMS_MODE_OFF: 427 | printf ( "off\n" ); 428 | break; 429 | default: 430 | break; 431 | } 432 | } 433 | else { 434 | printf ( "disabled\n" ); 435 | } 436 | 437 | free ( ir ); 438 | } 439 | } 440 | 441 | static void dpms_print ( char ** argv ) 442 | { 443 | (void ) ( argv ); 444 | xcb_dpms_capable_cookie_t c = xcb_dpms_capable ( connection ); 445 | xcb_dpms_capable_reply_t *r = xcb_dpms_capable_reply ( connection, c, NULL ); 446 | 447 | if ( r && r->capable == 0 ) { 448 | printf ( "dpms: incapable\n" ); 449 | free ( r ); 450 | return; 451 | } 452 | free ( r ); 453 | xcb_dpms_info_cookie_t ic = xcb_dpms_info ( connection ); 454 | xcb_dpms_info_reply_t *ir = xcb_dpms_info_reply ( connection, ic, NULL ); 455 | if ( ir ) { 456 | if ( ir->state ) { 457 | printf ( "dpms: capable\nstate: " ); 458 | switch ( ir->power_level ) 459 | { 460 | case XCB_DPMS_DPMS_MODE_ON: 461 | printf ( "on\n" ); 462 | break; 463 | case XCB_DPMS_DPMS_MODE_STANDBY: 464 | printf ( "standby\n" ); 465 | break; 466 | case XCB_DPMS_DPMS_MODE_SUSPEND: 467 | printf ( "suspend\n" ); 468 | break; 469 | case XCB_DPMS_DPMS_MODE_OFF: 470 | printf ( "off\n" ); 471 | break; 472 | default: 473 | break; 474 | } 475 | } 476 | else { 477 | printf ( "dpms: disabled\n" ); 478 | } 479 | 480 | free ( ir ); 481 | } 482 | } 483 | 484 | static int monitor_pos = 0; 485 | static MMB_Screen *mmb_screen = NULL; 486 | static MMB_Rectangle *selected_mon = NULL; 487 | 488 | static void set_monitor ( char **argv ) 489 | { 490 | monitor_pos = atoi ( argv[1] ); 491 | 492 | if ( !( monitor_pos >= 0 && monitor_pos < mmb_screen->num_monitors ) ) { 493 | fprintf ( stderr, "Invalid monitor: %d (0 <= %d < %d failed)\n", 494 | monitor_pos, 495 | monitor_pos, 496 | mmb_screen->num_monitors ); 497 | // Cleanup 498 | exit ( EXIT_FAILURE ); 499 | } 500 | selected_mon = mmb_screen->monitors[monitor_pos]; 501 | } 502 | static void print_active_mon ( char **argv ) 503 | { 504 | (void ) ( argv ); 505 | int active_mon = mmb_screen_get_active_monitor ( mmb_screen ); 506 | printf ( "%d\n", active_mon ); 507 | } 508 | static void print_mon_size ( char **argv ) 509 | { 510 | (void ) ( argv ); 511 | printf ( "%i %i\n", selected_mon->w, selected_mon->h ); 512 | } 513 | static void print_mon_width ( char **argv ) 514 | { 515 | (void ) ( argv ); 516 | printf ( "%d\n", selected_mon->w ); 517 | } 518 | static void print_mon_height ( char **argv ) 519 | { 520 | (void ) ( argv ); 521 | printf ( "%d\n", selected_mon->h ); 522 | } 523 | static void print_mon_x ( char **argv ) 524 | { 525 | (void ) ( argv ); 526 | printf ( "%d\n", selected_mon->x ); 527 | } 528 | static void print_mon_y ( char **argv ) 529 | { 530 | (void ) ( argv ); 531 | printf ( "%d\n", selected_mon->y ); 532 | } 533 | 534 | static void print_mon_pos ( char **argv ) 535 | { 536 | (void ) ( argv ); 537 | printf ( "%i %i\n", selected_mon->x, selected_mon->y ); 538 | } 539 | static void print_max_mon_width ( char **argv ) 540 | { 541 | (void ) ( argv ); 542 | int maxw = 0; 543 | 544 | for ( int i = 0; i < mmb_screen->num_monitors; i++ ) { 545 | maxw = MAX ( maxw, mmb_screen->monitors[i]->w ); 546 | } 547 | 548 | printf ( "%i\n", maxw ); 549 | } 550 | static void print_max_mon_height ( char **argv ) 551 | { 552 | (void ) ( argv ); 553 | int maxh = 0; 554 | 555 | for ( int i = 0; i < mmb_screen->num_monitors; i++ ) { 556 | maxh = MAX ( maxh, mmb_screen->monitors[i]->h ); 557 | } 558 | 559 | printf ( "%i\n", maxh ); 560 | } 561 | static void print_mon_name ( char **argv ) 562 | { 563 | (void ) ( argv ); 564 | if ( mmb_screen->monitors[monitor_pos]->name ) { 565 | printf ( "%s\n", mmb_screen->monitors[monitor_pos]->name ); 566 | } 567 | else { 568 | printf ( "unknown\n" ); 569 | } 570 | } 571 | static void print_num_mon ( char **argv ) 572 | { 573 | (void ) ( argv ); 574 | printf ( "%u\n", mmb_screen->num_monitors ); 575 | } 576 | static void print ( char **argv ) 577 | { 578 | (void ) ( argv ); 579 | mmb_screen_print ( mmb_screen ); 580 | } 581 | 582 | static void print_mon_modes ( char ** argv ) 583 | { 584 | (void ) ( argv ); 585 | for ( int i = 0; i < selected_mon->modes_len; i++ ) { 586 | printf ( "%d %d @ %.2f\n", selected_mon->modes[i].w, selected_mon->modes[i].h, selected_mon->modes[i].rate ); 587 | } 588 | } 589 | static void print_help ( char ** ); 590 | typedef struct _CmdOptions 591 | { 592 | const char *handle; 593 | const int n_args; 594 | void ( *callback )( char **start ); 595 | const char *description; 596 | } CmdOptions; 597 | 598 | static const CmdOptions options[] = { 599 | { 600 | .handle = "-monitor", 601 | .n_args = 1, 602 | .callback = set_monitor, 603 | .description = "Select monitor by id. By default it uses the active monitor as indicated by the window manager." 604 | }, 605 | { 606 | .handle = "-active-mon", 607 | .n_args = 0, 608 | .callback = print_active_mon, 609 | .description = "Print the monitor id indicated by the window manager to hold the focus." 610 | }, 611 | { 612 | .handle = "-mon-size", 613 | .n_args = 0, 614 | .callback = print_mon_size, 615 | .description = "Get the size of the selected monitor." 616 | }, 617 | { 618 | .handle = "-mon-width", 619 | .n_args = 0, 620 | .callback = print_mon_width, 621 | .description = "Get the width of the selected monitor." 622 | }, 623 | { 624 | .handle = "-max-mon-width", 625 | .n_args = 0, 626 | .callback = print_max_mon_width, 627 | .description = "Get largest monitor width." 628 | }, 629 | { 630 | .handle = "-max-mon-height", 631 | .n_args = 0, 632 | .callback = print_max_mon_height, 633 | .description = "Get the largest monitor height." 634 | }, 635 | { 636 | .handle = "-mon-height", 637 | .n_args = 0, 638 | .callback = print_mon_height, 639 | .description = "Get the selected monitor height." 640 | }, 641 | { 642 | .handle = "-mon-x", 643 | .n_args = 0, 644 | .callback = print_mon_x, 645 | .description = "Get the selected monitor horizontal (x) position." 646 | }, 647 | { 648 | .handle = "-mon-y", 649 | .n_args = 0, 650 | .callback = print_mon_y, 651 | .description = "Get the selected monitor vertical (y) position." 652 | }, 653 | { 654 | .handle = "-mon-pos", 655 | .n_args = 0, 656 | .callback = print_mon_pos, 657 | .description = "Get the selected monitor position (x y)." 658 | }, 659 | { 660 | .handle = "-num-mon", 661 | .n_args = 0, 662 | .callback = print_num_mon, 663 | .description = "Get the number of enabled monitors." 664 | }, 665 | { 666 | .handle = "-dpms", 667 | .n_args = 0, 668 | .callback = dpms_print, 669 | .description = "Get the dpms state." 670 | }, 671 | { 672 | .handle = "-dpms-state", 673 | .n_args = 0, 674 | .callback = dpms_state, 675 | .description = "Get the dpms state (parsable)." 676 | }, 677 | { 678 | .handle = "-screensaver", 679 | .n_args = 0, 680 | .callback = screensaver_print, 681 | .description = "Get the screensaver state." 682 | }, 683 | { 684 | .handle = "-screensaver-state", 685 | .n_args = 0, 686 | .callback = screensaver, 687 | .description = "Get the screensaver state (parsable)" 688 | }, 689 | { 690 | .handle = "-print", 691 | .n_args = 0, 692 | .callback = print, 693 | .description = "Print monitor(s) layout." 694 | }, 695 | { 696 | .handle = "-name", 697 | .n_args = 0, 698 | .callback = print_mon_name, 699 | .description = "Print monitor name." 700 | }, 701 | { 702 | .handle = "-modes", 703 | .n_args = 0, 704 | .callback = print_mon_modes, 705 | .description = "Print monitors supported modes." 706 | }, 707 | 708 | { 709 | .handle = "-h", 710 | .n_args = 0, 711 | .callback = print_help, 712 | .description = "Print this help message." 713 | }, 714 | }; 715 | const unsigned int num_options = sizeof ( options ) / sizeof ( CmdOptions ); 716 | 717 | static void print_help ( char **argv ) 718 | { 719 | (void ) ( argv ); 720 | printf ( "xinfino usage:\n" ); 721 | printf ( " xininfo [-option ....]\n" ); 722 | printf ( "\n" ); 723 | printf ( "Command line options:\n" ); 724 | for ( unsigned int i = 0; i < num_options; i++ ) { 725 | printf ( " %*s %s - %s\n", 20, options[i].handle, options[i].n_args > 0 ? "{arguments}" : " ", options[i].description ); 726 | } 727 | printf ( "\n" ); 728 | printf ( "These arguments can be chained, e.g. xininfo -monitor 1 -mon-size -monitor 2 -mon-size.\n" ); 729 | printf ( "Will print first the size of monitor 1 then monitor 2.\n" ); 730 | } 731 | /** 732 | * Function to handle arguments. 733 | */ 734 | static int handle_arg ( int argc, char **argv ) 735 | { 736 | for ( unsigned int i = 0; i < num_options; i++ ) { 737 | if ( strcmp ( options[i].handle, argv[0] ) == 0 ) { 738 | if ( argc > options[i].n_args ) { 739 | options[i].callback ( argv ); 740 | return options[i].n_args; 741 | } 742 | else { 743 | fprintf ( stderr, "Option: %s requires %d arguments.\n", options[i].handle, options[i].n_args ); 744 | exit ( EXIT_FAILURE ); 745 | } 746 | } 747 | } 748 | fprintf ( stderr, "Commandline option: '%s' not found.\n", argv[0] ); 749 | return 0; 750 | } 751 | 752 | static void cleanup ( void ) 753 | { 754 | // Cleanup 755 | mmb_screen_free ( &mmb_screen ); 756 | xcb_ewmh_connection_wipe ( &( ewmh ) ); 757 | xcb_disconnect ( connection ); 758 | } 759 | 760 | int main ( int argc, char **argv ) 761 | { 762 | atexit ( cleanup ); 763 | 764 | // Get DISPLAY 765 | const char *display_str = getenv ( "DISPLAY" ); 766 | connection = xcb_connect ( display_str, &screen_nbr ); 767 | if ( xcb_connection_has_error ( connection ) ) { 768 | fprintf ( stderr, "Failed to open display: %s", display_str ); 769 | return EXIT_FAILURE; 770 | } 771 | xcb_intern_atom_cookie_t *ac = xcb_ewmh_init_atoms ( connection, &ewmh ); 772 | xcb_generic_error_t *errors = NULL; 773 | xcb_ewmh_init_atoms_replies ( &ewmh, ac, &errors ); 774 | if ( errors ) { 775 | fprintf ( stderr, "Failed to create EWMH atoms\n" ); 776 | free ( errors ); 777 | } 778 | 779 | // Get monitor layout. (xinerama aware) 780 | mmb_screen = mmb_screen_create ( screen_nbr ); 781 | 782 | if ( mmb_screen->num_monitors == 0 ) { 783 | fprintf ( stderr, "No monitor found.\n" ); 784 | return EXIT_FAILURE; 785 | } 786 | 787 | monitor_pos = mmb_screen_get_active_monitor ( mmb_screen ); 788 | selected_mon = mmb_screen->monitors[monitor_pos]; 789 | 790 | for ( int ac = 1; ac < argc; ac++ ) { 791 | // 792 | ac += handle_arg ( argc - ac, &argv[ac] ); 793 | } 794 | return EXIT_SUCCESS; 795 | } 796 | --------------------------------------------------------------------------------